aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitmodules2
m---------fpga-src0
-rw-r--r--host/CMakeLists.txt16
-rw-r--r--host/apps/omap_debug/.gitignore20
-rw-r--r--host/apps/omap_debug/Makefile33
-rwxr-xr-xhost/apps/omap_debug/set_debug_pins.py35
-rw-r--r--host/apps/omap_debug/test.c34
-rw-r--r--host/apps/omap_debug/u1e-read-stream.c21
-rw-r--r--host/apps/omap_debug/usrp-e-button.c56
-rw-r--r--host/apps/omap_debug/usrp-e-ctl.c48
-rw-r--r--host/apps/omap_debug/usrp-e-debug-pins.c77
-rw-r--r--host/apps/omap_debug/usrp-e-i2c.c87
-rw-r--r--host/apps/omap_debug/usrp-e-lb-test.c58
-rw-r--r--host/apps/omap_debug/usrp-e-led.c35
-rw-r--r--host/apps/omap_debug/usrp-e-ram.c25
-rw-r--r--host/apps/omap_debug/usrp-e-read.c18
-rw-r--r--host/apps/omap_debug/usrp-e-spi.c54
-rw-r--r--host/apps/omap_debug/usrp-e-uart-rx.c53
-rw-r--r--host/apps/omap_debug/usrp-e-uart.c48
-rw-r--r--host/apps/omap_debug/usrp-e-write.c21
-rw-r--r--host/apps/omap_debug/usrp_e.h60
-rw-r--r--host/cmake/Toolchains/mingw_cross.cmake69
-rw-r--r--host/docs/dboards.dox4
-rw-r--r--host/docs/uhd.dox1
-rw-r--r--host/docs/usrp_b200.dox31
-rw-r--r--host/docs/usrp_e3x0.dox4
-rw-r--r--host/docs/vrt_chdr.dox83
-rw-r--r--host/examples/CMakeLists.txt3
-rw-r--r--host/examples/benchmark_rate.cpp65
-rw-r--r--host/examples/fpgpio.cpp418
-rw-r--r--host/examples/gpio.cpp462
-rw-r--r--host/examples/rx_samples_to_file.cpp200
-rw-r--r--host/examples/rx_timed_samples.cpp1
-rw-r--r--host/examples/test_pps_input.cpp5
-rw-r--r--host/examples/transport_hammer.cpp280
-rw-r--r--host/examples/tx_bursts.cpp1
-rw-r--r--host/examples/tx_waveforms.cpp49
-rw-r--r--host/examples/txrx_loopback_to_file.cpp47
-rw-r--r--host/examples/wavetable.hpp66
-rw-r--r--host/include/uhd/config.hpp9
-rw-r--r--host/include/uhd/convert.hpp3
-rw-r--r--host/include/uhd/transport/CMakeLists.txt4
-rw-r--r--host/include/uhd/transport/chdr.hpp113
-rw-r--r--host/include/uhd/transport/nirio/nirio_driver_iface.h4
-rw-r--r--host/include/uhd/transport/nirio/nirio_fifo.h4
-rw-r--r--host/include/uhd/transport/usb_device_handle.hpp3
-rw-r--r--host/include/uhd/transport/vrt_if_packet.hpp76
-rw-r--r--host/include/uhd/types/CMakeLists.txt2
-rw-r--r--host/include/uhd/types/dict.hpp19
-rw-r--r--host/include/uhd/types/dict.ipp14
-rw-r--r--host/include/uhd/types/direction.hpp2
-rw-r--r--host/include/uhd/types/filters.hpp286
-rw-r--r--host/include/uhd/types/sid.hpp238
-rw-r--r--host/include/uhd/usrp/multi_usrp.hpp114
-rw-r--r--host/include/uhd/utils/math.hpp12
-rw-r--r--host/lib/convert/convert_impl.cpp32
-rw-r--r--host/lib/transport/CMakeLists.txt1
-rw-r--r--host/lib/transport/chdr.cpp182
-rw-r--r--host/lib/transport/libusb1_base.cpp20
-rw-r--r--host/lib/transport/nirio/rpc/rpc_client.cpp2
-rw-r--r--host/lib/transport/super_recv_packet_handler.hpp2
-rw-r--r--host/lib/types/CMakeLists.txt2
-rw-r--r--host/lib/types/filters.cpp74
-rw-r--r--host/lib/types/sid.cpp153
-rw-r--r--host/lib/usrp/b200/b200_iface.hpp3
-rw-r--r--host/lib/usrp/b200/b200_impl.cpp176
-rw-r--r--host/lib/usrp/b200/b200_impl.hpp62
-rw-r--r--host/lib/usrp/b200/b200_io_impl.cpp156
-rw-r--r--host/lib/usrp/b200/b200_regs.hpp2
-rw-r--r--host/lib/usrp/common/ad9361_ctrl.cpp78
-rw-r--r--host/lib/usrp/common/ad9361_ctrl.hpp51
-rw-r--r--host/lib/usrp/common/ad9361_driver/ad9361_device.cpp981
-rw-r--r--host/lib/usrp/common/ad9361_driver/ad9361_device.h121
-rw-r--r--host/lib/usrp/common/ad9361_driver/ad9361_gain_tables.h162
-rw-r--r--host/lib/usrp/common/ad9361_driver/ad9361_synth_lut.h28
-rw-r--r--host/lib/usrp/cores/gpio_core_200.hpp26
-rw-r--r--host/lib/usrp/e300/e300_impl.cpp48
-rw-r--r--host/lib/usrp/e300/e300_impl.hpp6
-rw-r--r--host/lib/usrp/e300/e300_network.cpp21
-rw-r--r--host/lib/usrp/e300/e300_remote_codec_ctrl.cpp110
-rw-r--r--host/lib/usrp/e300/e300_remote_codec_ctrl.hpp13
-rw-r--r--host/lib/usrp/multi_usrp.cpp190
-rw-r--r--host/lib/usrp/x300/x300_impl.cpp85
-rw-r--r--host/lib/usrp/x300/x300_impl.hpp6
-rw-r--r--host/lib/usrp/x300/x300_io_impl.cpp52
-rw-r--r--host/lib/usrp/x300/x300_regs.hpp140
-rw-r--r--host/lib/utils/platform.cpp4
-rw-r--r--host/tests/CMakeLists.txt13
-rw-r--r--host/tests/addr_test.cpp7
-rw-r--r--host/tests/chdr_test.cpp141
-rw-r--r--host/tests/dict_test.cpp25
-rw-r--r--host/tests/fp_compare_delta_test.cpp6
-rw-r--r--host/tests/math_test.cpp29
-rw-r--r--host/tests/sid_t_test.cpp158
-rw-r--r--host/tests/time_spec_test.cpp4
-rw-r--r--host/utils/b2xx_fx3_utils.cpp86
-rw-r--r--tools/uhd_txrx_debug_prints/uhd_txrx_debug_prints_README.md17
-rwxr-xr-xtools/uhd_txrx_debug_prints/uhd_txrx_debug_prints_graph.py415
98 files changed, 5197 insertions, 2186 deletions
diff --git a/.gitmodules b/.gitmodules
index 473a21289..c85c089b3 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,4 +1,4 @@
[submodule "fpga-src"]
path = fpga-src
url = https://github.com/EttusResearch/fpga.git
- branch = maint
+ branch = master
diff --git a/fpga-src b/fpga-src
-Subproject fc192fbc2037076075f2eee09cc632447252b53
+Subproject 78c9077afe5ff35c5528689dcb2b0debbd57c41
diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt
index 67b2446dd..2666aa1d3 100644
--- a/host/CMakeLists.txt
+++ b/host/CMakeLists.txt
@@ -166,6 +166,22 @@ IF(MSVC)
ADD_DEFINITIONS(/MP) #multi-threaded build
ENDIF(MSVC)
+IF(MINGW)
+ #Avoid depending on MinGW runtime DLLs
+ CHECK_CXX_COMPILER_FLAG(-static-libgcc HAVE_STATIC_LIBGCC_FLAG)
+ IF(HAVE_STATIC_LIBGCC_FLAG)
+ SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc")
+ SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -static-libgcc")
+ SET(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -static-libgcc")
+ ENDIF()
+ CHECK_CXX_COMPILER_FLAG(-static-libstdc++ HAVE_STATIC_LIBSTDCXX_FLAG)
+ IF(HAVE_STATIC_LIBSTDCXX_FLAG)
+ SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libstdc++")
+ SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -static-libstdc++")
+ SET(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -static-libstdc++")
+ ENDIF()
+ENDIF()
+
IF(CYGWIN)
ADD_DEFINITIONS(-D__USE_W32_SOCKETS) #boost asio says we need this
ENDIF(CYGWIN)
diff --git a/host/apps/omap_debug/.gitignore b/host/apps/omap_debug/.gitignore
deleted file mode 100644
index 008a23138..000000000
--- a/host/apps/omap_debug/.gitignore
+++ /dev/null
@@ -1,20 +0,0 @@
-.gitignore
-clkgen-config
-fpga-downloader
-usrp-e-button
-usrp-e-crc-rw
-usrp-e-ctl
-usrp-e-debug-pins
-usrp-e-fpga-rw
-usrp-e-gpio
-usrp-e-i2c
-usrp-e-lb-test
-usrp-e-led
-usrp-e-loopback
-usrp-e-random-loopback
-usrp-e-rw
-usrp-e-spi
-usrp-e-timed
-usrp-e-uart
-usrp-e-uart-rx
-usrp-e-mm-loopback
diff --git a/host/apps/omap_debug/Makefile b/host/apps/omap_debug/Makefile
deleted file mode 100644
index f8b9f2bd9..000000000
--- a/host/apps/omap_debug/Makefile
+++ /dev/null
@@ -1,33 +0,0 @@
-CFLAGS=-Wall -I../../lib/usrp/usrp_e/ -march=armv7-a -mtune=cortex-a8 -mfpu=neon -O3
-CXXFLAGS=-Wall -I../../lib/usrp/usrp_e/ -march=armv7-a -mtune=cortex-a8 -mfpu=neon -O3
-
-all : usrp-e-spi usrp-e-i2c usrp-e-uart usrp-e-led usrp-e-ctl usrp-e-button usrp-e-uart-rx usrp-e-gpio usrp-e-debug-pins
-
-usrp-e-spi : usrp-e-spi.c
-
-usrp-e-i2c : usrp-e-i2c.c
-
-usrp-e-uart : usrp-e-uart.c
-
-usrp-e-uart-rx : usrp-e-uart-rx.c
-
-usrp-e-led : usrp-e-led.c
-
-usrp-e-ctl : usrp-e-ctl.c
-
-usrp-e-button : usrp-e-button.c
-
-usrp-e-gpio : usrp-e-gpio.c
-
-usrp-e-debug-pins : usrp-e-debug-pins.c
-clean :
- rm -f usrp-e-spi
- rm -f usrp-e-i2c
- rm -f usrp-e-uart
- rm -f usrp-e-uart-rx
- rm -f usrp-e-led
- rm -f usrp-e-ctl
- rm -f usrp-e-button
- rm -f usrp-e-gpio
- rm -f usrp-e-debug-pins
- rm -f usrp-e-lb-test
diff --git a/host/apps/omap_debug/set_debug_pins.py b/host/apps/omap_debug/set_debug_pins.py
deleted file mode 100755
index 0f9ecd7b9..000000000
--- a/host/apps/omap_debug/set_debug_pins.py
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/usr/bin/python
-
-import os
-
-# Memory Map
-misc_base = 0
-uart_base = 1
-spi_base = 2
-i2c_base = 3
-gpio_base = 4 * 128
-settings_base = 5
-
-# GPIO offset
-gpio_pins = 0
-gpio_ddr = 4
-gpio_ctrl_lo = 8
-gpio_ctrl_hi = 12
-
-def set_reg(reg, val):
- os.system("./usrp1-e-ctl w %d 1 %d" % (reg,val))
-
-def get_reg(reg):
- fin,fout = os.popen4("./usrp1-e-ctl r %d 1" % (reg,))
- print fout.read()
-
-# Set DDRs to output
-set_reg(gpio_base+gpio_ddr, 0xFFFF)
-set_reg(gpio_base+gpio_ddr+2, 0xFFFF)
-
-# Set CTRL to Debug #0 ( A is for debug 0, F is for debug 1 )
-set_reg(gpio_base+gpio_ctrl_lo, 0xAAAA)
-set_reg(gpio_base+gpio_ctrl_lo+2, 0xAAAA)
-set_reg(gpio_base+gpio_ctrl_hi, 0xAAAA)
-set_reg(gpio_base+gpio_ctrl_hi+2, 0xAAAA)
-
diff --git a/host/apps/omap_debug/test.c b/host/apps/omap_debug/test.c
deleted file mode 100644
index 36f4d700a..000000000
--- a/host/apps/omap_debug/test.c
+++ /dev/null
@@ -1,34 +0,0 @@
-#include <stdio.h>
-
-void
-main()
-{
- int x;
- char *y;
- long long z;
-
- x = 0x01020304;
- z = 0x0102030405060708LL;
-
- printf("%x\n",x);
- y = (char *)&x;
- printf("%x\n",y[0]);
- printf("%x\n",y[1]);
- printf("%x\n",y[2]);
- printf("%x\n",y[3]);
-
- printf("Printing z ...\n");
- printf("%llx\n",z);
- printf("Printing z done\n");
-
- y = (char *)&z;
- printf("%x\n",y[0]);
- printf("%x\n",y[1]);
- printf("%x\n",y[2]);
- printf("%x\n",y[3]);
- printf("%x\n",y[4]);
- printf("%x\n",y[5]);
- printf("%x\n",y[6]);
- printf("%x\n",y[7]);
-}
-
diff --git a/host/apps/omap_debug/u1e-read-stream.c b/host/apps/omap_debug/u1e-read-stream.c
deleted file mode 100644
index 4e4c21d9e..000000000
--- a/host/apps/omap_debug/u1e-read-stream.c
+++ /dev/null
@@ -1,21 +0,0 @@
-#include <stdio.h>
-#include <sys/types.h>
-#include <fcntl.h>
-
-int main(int rgc, char *argv[])
-{
- int fp, cnt, n;
- short buf[1024];
-
- n = 0;
-
- fp = open("/dev/usrp1_e0", O_RDONLY);
- printf("fp = %d\n", fp);
-
- do {
- cnt = read(fp, buf, 2048);
- n++;
-// printf("Bytes read - %d\n", cnt);
- } while(n < 10*512);
- printf("Data - %hX\n", buf[0]);
-}
diff --git a/host/apps/omap_debug/usrp-e-button.c b/host/apps/omap_debug/usrp-e-button.c
deleted file mode 100644
index f13291491..000000000
--- a/host/apps/omap_debug/usrp-e-button.c
+++ /dev/null
@@ -1,56 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <unistd.h>
-
-#include "usrp_e.h"
-#include "usrp_e_regs.hpp"
-
-// Usage: usrp_e_uart <string>
-
-#define PB1 (1<<8)
-#define PB2 (1<<9)
-#define PB3 (1<<10)
-#define P1 (0)
-#define P2 (0xFF)
-#define P3 (0xAA)
-#define P4 (0x55)
-
-int main(int argc, char *argv[])
-{
- int fp, ret;
- struct usrp_e_ctl16 d;
- int pb1=0, pb2=0, pb3=0, p1=0, p2=0, p3=0, p4=0;
-
- fp = open("/dev/usrp_e0", O_RDWR);
- printf("fp = %d\n", fp);
-
- d.offset = UE_REG_MISC_SW;
- d.count = 1;
-
- do {
- ret = ioctl(fp, USRP_E_READ_CTL16, &d);
- if (d.buf[0] & PB1) {
- pb1 = 1;
- printf("Pushbutton 1 hit\n");
- }
-
- if (d.buf[0] & PB2) {
- pb2 = 1;
- printf("Pushbutton 2 hit\n");
- }
-
- if (d.buf[0] & PB3) {
- pb3 = 1;
- printf("Pushbutton 3 hit\n");
- }
-
- sleep(1);
-
- } while (!(pb1 && pb2 && pb3));
-
- return 0;
-}
diff --git a/host/apps/omap_debug/usrp-e-ctl.c b/host/apps/omap_debug/usrp-e-ctl.c
deleted file mode 100644
index 69c48ee6f..000000000
--- a/host/apps/omap_debug/usrp-e-ctl.c
+++ /dev/null
@@ -1,48 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-
-#include "usrp_e.h"
-
-// Usage: usrp_e_ctl w|r offset number_of_values val1 val2 ....
-
-int main(int argc, char *argv[])
-{
- int fp, i, cnt, ret;
- struct usrp_e_ctl16 ctl_data;
-
- if (argc < 4) {
- printf("Usage: usrp_e_ctl w|r offset number_of_values val1 val2 ....\n");
- exit(-1);
- }
-
- cnt = atoi(argv[3]);
-
- ctl_data.offset = atoi(argv[2]);
- ctl_data.count = cnt;
-
- fp = open("/dev/usrp_e0", O_RDWR);
- printf("fp = %d\n", fp);
-
- if (*argv[1] == 'w') {
- for (i=0; i<cnt; i++)
- ctl_data.buf[i] = atoi(argv[4+i]);
-
- ret = ioctl(fp, USRP_E_WRITE_CTL16, &ctl_data);
- printf("Return value from write ioctl = %d\n", ret);
- }
-
- if (*argv[1] == 'r') {
- ret = ioctl(fp, USRP_E_READ_CTL16, &ctl_data);
- printf("Return value from write ioctl = %d\n", ret);
-
- for (i=0; i<ctl_data.count; i++) {
- if (!(i%8))
- printf("\nData at %4d :", i);
- printf(" %5d", ctl_data.buf[i]);
- }
- printf("\n");
- }
-}
diff --git a/host/apps/omap_debug/usrp-e-debug-pins.c b/host/apps/omap_debug/usrp-e-debug-pins.c
deleted file mode 100644
index d18bbf990..000000000
--- a/host/apps/omap_debug/usrp-e-debug-pins.c
+++ /dev/null
@@ -1,77 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <string.h>
-#include <sys/ioctl.h>
-
-#include "usrp_e.h"
-#include "usrp_e_regs.hpp"
-
-// Usage: usrp_e_gpio <string>
-
-static int fp;
-
-static int read_reg(__u16 reg)
-{
- int ret;
- struct usrp_e_ctl16 d;
-
- d.offset = reg;
- d.count = 1;
- ret = ioctl(fp, USRP_E_READ_CTL16, &d);
- return d.buf[0];
-}
-
-static void write_reg(__u16 reg, __u16 val)
-{
- int ret;
- struct usrp_e_ctl16 d;
-
- d.offset = reg;
- d.count = 1;
- d.buf[0] = val;
- ret = ioctl(fp, USRP_E_WRITE_CTL16, &d);
-}
-
-int main(int argc, char *argv[])
-{
- int test;
-
- test = 0;
- if (argc < 2) {
- printf("%s 0|1|off\n", argv[0]);
- }
-
- fp = open("/dev/usrp_e0", O_RDWR);
- printf("fp = %d\n", fp);
- if (fp < 0) {
- perror("Open failed");
- return -1;
- }
-
- if (strcmp(argv[1], "0") == 0) {
- printf("Selected 0 based on %s\n", argv[1]);
- write_reg(UE_REG_GPIO_TX_DDR, 0xFFFF);
- write_reg(UE_REG_GPIO_RX_DDR, 0xFFFF);
- write_reg(UE_REG_GPIO_TX_SEL, 0x0);
- write_reg(UE_REG_GPIO_RX_SEL, 0x0);
- write_reg(UE_REG_GPIO_TX_DBG, 0xFFFF);
- write_reg(UE_REG_GPIO_RX_DBG, 0xFFFF);
- } else if (strcmp(argv[1], "1") == 0) {
- printf("Selected 1 based on %s\n", argv[1]);
- write_reg(UE_REG_GPIO_TX_DDR, 0xFFFF);
- write_reg(UE_REG_GPIO_RX_DDR, 0xFFFF);
- write_reg(UE_REG_GPIO_TX_SEL, 0xFFFF);
- write_reg(UE_REG_GPIO_RX_SEL, 0xFFFF);
- write_reg(UE_REG_GPIO_TX_DBG, 0xFFFF);
- write_reg(UE_REG_GPIO_RX_DBG, 0xFFFF);
- } else {
- printf("Selected off based on %s\n", argv[1]);
- write_reg(UE_REG_GPIO_TX_DDR, 0x0);
- write_reg(UE_REG_GPIO_RX_DDR, 0x0);
- }
-
- return 0;
-}
diff --git a/host/apps/omap_debug/usrp-e-i2c.c b/host/apps/omap_debug/usrp-e-i2c.c
deleted file mode 100644
index da8709ae1..000000000
--- a/host/apps/omap_debug/usrp-e-i2c.c
+++ /dev/null
@@ -1,87 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-
-#include "usrp_e.h"
-
-// Usage: usrp_e_i2c w address data0 data1 data 2 ....
-// Usage: usrp_e_i2c r address count
-
-int main(int argc, char *argv[])
-{
- int fp, ret, i, tmp;
- struct usrp_e_i2c *i2c_msg;
- int direction, address, count;
-
- if (argc < 3) {
- printf("Usage: usrp-e-i2c w address data0 data1 data2 ...\n");
- printf("Usage: usrp-e-i2c r address count\n");
- printf("All addresses and data in hex.\n");
- exit(-1);
- }
-
- if (strcmp(argv[1], "r") == 0) {
- direction = 0;
- } else if (strcmp(argv[1], "w") == 0) {
- direction = 1;
- } else {
- return -1;
- }
-
- sscanf(argv[2], "%X", &address);
- printf("Address = %X\n", address);
-
- fp = open("/dev/usrp_e0", O_RDWR);
- printf("fp = %d\n", fp);
- if (fp < 0) {
- perror("Open failed");
- return -1;
- }
-
-// sleep(1);
-
- if (direction) {
- count = argc - 3;
- } else {
- sscanf(argv[3], "%X", &count);
- }
- printf("Count = %X\n", count);
-
- i2c_msg = malloc(sizeof(i2c_msg) + count * sizeof(char));
-
- i2c_msg->addr = address;
- i2c_msg->len = count;
-
- for (i = 0; i < count; i++) {
- i2c_msg->data[i] = i;
- }
-
- if (direction) {
- // Write
-
- for (i=0; i<count; i++) {
- sscanf(argv[3+i], "%X", &tmp);
- i2c_msg->data[i] = tmp;
- }
-
- ret = ioctl(fp, USRP_E_I2C_WRITE, i2c_msg);
- printf("Return value from i2c_write ioctl: %d\n", ret);
- } else {
- // Read
-
- ret = ioctl(fp, USRP_E_I2C_READ, i2c_msg);
- printf("Return value from i2c_read ioctl: %d\n", ret);
-
- printf("Ioctl: %d Data read :", ret);
- for (i=0; i<count; i++) {
- printf(" %X", i2c_msg->data[i]);
- }
- printf("\n");
-
- }
- return 0;
-}
diff --git a/host/apps/omap_debug/usrp-e-lb-test.c b/host/apps/omap_debug/usrp-e-lb-test.c
deleted file mode 100644
index 68848064e..000000000
--- a/host/apps/omap_debug/usrp-e-lb-test.c
+++ /dev/null
@@ -1,58 +0,0 @@
-#include <stdio.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <stddef.h>
-#include "usrp_e.h"
-
-// max length #define PKT_DATA_LENGTH 1016
-
-int main(int argc, char *argv[])
-{
- struct usrp_transfer_frame *tx_data, *rx_data;
- int i, fp, packet_data_length, cnt;
- struct usrp_e_ctl16 d;
-
- if (argc < 2) {
- printf("%s data_size (in bytes < 2040)\n", argv[0]);
- return -1;
- }
-
- packet_data_length = atoi(argv[1]);
-
- fp = open("/dev/usrp_e0", O_RDWR);
-
- d.offset = 14;
- d.count = 1;
- d.buf[0] = (1 << 13);
- ioctl(fp, USRP_E_WRITE_CTL16, &d);
-
- tx_data = malloc(2048);
- rx_data = malloc(2048);
-
- tx_data->status = 0;
- tx_data->len = sizeof(struct usrp_transfer_frame) + packet_data_length;
-
- while (1) {
-
- for (i = 0; i < packet_data_length; i++) {
- tx_data->buf[i] = random() >> 24;
-
- }
-
- cnt = write(fp, tx_data, 2048);
- cnt = read(fp, rx_data, 2048);
-
- if (tx_data->len != rx_data->len)
- printf("Bad frame length sent %d, read %d\n", tx_data->len, rx_data->len);
-
- for (i = 0; i < packet_data_length; i++) {
- if (tx_data->buf[i] != rx_data->buf[i])
- printf("Bad data at %d, sent %d, received %d\n", i, tx_data->buf[i], rx_data->buf[i]);
- }
- printf("---------------------------------------------------\n");
- sleep(1);
- }
-}
diff --git a/host/apps/omap_debug/usrp-e-led.c b/host/apps/omap_debug/usrp-e-led.c
deleted file mode 100644
index d1b6c8996..000000000
--- a/host/apps/omap_debug/usrp-e-led.c
+++ /dev/null
@@ -1,35 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <unistd.h>
-
-#include "usrp_e.h"
-#include "usrp_e_regs.hpp"
-
-// Usage: usrp_e_uart <string>
-
-
-int main(int argc, char *argv[])
-{
- int fp, i, ret;
- struct usrp_e_ctl16 d;
-
- fp = open("/dev/usrp_e0", O_RDWR);
- printf("fp = %d\n", fp);
-
- d.offset = UE_REG_MISC_BASE;
- d.count = 1;
-
- while (1) {
- for (i=0; i<8; i++) {
- d.buf[0] = i;
- ret = ioctl(fp, USRP_E_WRITE_CTL16, &d);
- sleep(1);
- }
- }
-
- return 0;
-}
diff --git a/host/apps/omap_debug/usrp-e-ram.c b/host/apps/omap_debug/usrp-e-ram.c
deleted file mode 100644
index d548f7ccd..000000000
--- a/host/apps/omap_debug/usrp-e-ram.c
+++ /dev/null
@@ -1,25 +0,0 @@
-#include <stdio.h>
-#include <sys/types.h>
-#include <fcntl.h>
-
-int main(int rgc, char *argv[])
-{
- int fp, i, cnt;
- unsigned short buf[1024];
- unsigned short buf_rb[1024];
-
- fp = open("/dev/usrp1_e0", O_RDWR);
- printf("fp = %d\n", fp);
-
- for (i=0; i<1024; i++)
- buf[i] = i*256;
- write(fp, buf, 2048);
- read(fp, buf_rb, 2048);
-
- printf("Read back %hX %hX\n", buf_rb[0], buf_rb[1]);
-
- for (i=0; i<1024; i++) {
- if (buf[i] != buf_rb[i])
- printf("Read - %hX, expected - %hX\n", buf_rb[i], buf[i]);
- }
-}
diff --git a/host/apps/omap_debug/usrp-e-read.c b/host/apps/omap_debug/usrp-e-read.c
deleted file mode 100644
index c28f018d5..000000000
--- a/host/apps/omap_debug/usrp-e-read.c
+++ /dev/null
@@ -1,18 +0,0 @@
-#include <stdio.h>
-#include <sys/types.h>
-#include <fcntl.h>
-
-int main(int rgc, char *argv[])
-{
- int fp, cnt;
- short buf[1024];
-
- fp = open("/dev/usrp1_e0", O_RDONLY);
- printf("fp = %d\n", fp);
-
- do {
- cnt = read(fp, buf, 2048);
-// printf("Bytes read - %d\n", cnt);
- } while(1);
- printf("Data - %hX\n", buf[0]);
-}
diff --git a/host/apps/omap_debug/usrp-e-spi.c b/host/apps/omap_debug/usrp-e-spi.c
deleted file mode 100644
index c353c409b..000000000
--- a/host/apps/omap_debug/usrp-e-spi.c
+++ /dev/null
@@ -1,54 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-
-#include "usrp_e.h"
-
-// Usage: usrp_e_spi w|rb slave data
-
-int main(int argc, char *argv[])
-{
- int fp, slave, length, ret;
- unsigned int data;
- struct usrp_e_spi spi_dat;
-
- if (argc < 5) {
- printf("Usage: usrp_e_spi w|rb slave transfer_length data\n");
- exit(-1);
- }
-
- slave = atoi(argv[2]);
- length = atoi(argv[3]);
- data = atoll(argv[4]);
-
- printf("Data = %X\n", data);
-
- fp = open("/dev/usrp_e0", O_RDWR);
- printf("fp = %d\n", fp);
- if (fp < 0) {
- perror("Open failed");
- return -1;
- }
-
-// sleep(1);
-
-
- spi_dat.slave = slave;
- spi_dat.data = data;
- spi_dat.length = length;
- spi_dat.flags = UE_SPI_PUSH_FALL | UE_SPI_LATCH_RISE;
-
- if (*argv[1] == 'r') {
- spi_dat.readback = 1;
- ret = ioctl(fp, USRP_E_SPI, &spi_dat);
- printf("Ioctl returns: %d, Data returned = %d\n", ret, spi_dat.data);
- } else {
- spi_dat.readback = 0;
- ioctl(fp, USRP_E_SPI, &spi_dat);
- }
-
- return 0;
-}
diff --git a/host/apps/omap_debug/usrp-e-uart-rx.c b/host/apps/omap_debug/usrp-e-uart-rx.c
deleted file mode 100644
index 24b417980..000000000
--- a/host/apps/omap_debug/usrp-e-uart-rx.c
+++ /dev/null
@@ -1,53 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <string.h>
-#include <sys/ioctl.h>
-
-#include "usrp_e.h"
-#include "usrp_e_regs.hpp"
-
-// Usage: usrp_e_uart <string>
-
-
-int main(int argc, char *argv[])
-{
- int fp, ret;
- struct usrp_e_ctl16 d;
- __u16 clkdiv;
-
- if (argc == 0) {
- printf("Usage: usrp-e-uart-rx <opt clkdiv>\n");
- printf("clkdiv = 278 is 230.4k \n");
- printf("clkdiv = 556 is 115.2k \n");
- exit(-1);
- }
-
- fp = open("/dev/usrp_e0", O_RDWR);
- printf("fp = %d\n", fp);
-
- if (argc == 2) {
- clkdiv = atoi(argv[1]);
- d.offset = UE_REG_UART_CLKDIV;
- d.count = 1;
- d.buf[0] = clkdiv;
- ret = ioctl(fp, USRP_E_WRITE_CTL16, &d);
- }
-
- while(1) {
- d.offset = UE_REG_UART_RXLEVEL;
- d.count = 1;
- ret = ioctl(fp, USRP_E_READ_CTL16, &d);
-
- if (d.buf[0] > 0) {
- d.offset = UE_REG_UART_RXCHAR;
- d.count = 1;
- ret = ioctl(fp, USRP_E_READ_CTL16, &d);
- printf("%c", d.buf[0]);
- fflush(stdout);
- }
- }
-
- return 0;
-}
diff --git a/host/apps/omap_debug/usrp-e-uart.c b/host/apps/omap_debug/usrp-e-uart.c
deleted file mode 100644
index 2956c407f..000000000
--- a/host/apps/omap_debug/usrp-e-uart.c
+++ /dev/null
@@ -1,48 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <string.h>
-#include <sys/ioctl.h>
-
-#include "usrp_e.h"
-#include "usrp_e_regs.hpp"
-
-// Usage: usrp_e_uart <string>
-
-
-int main(int argc, char *argv[])
-{
- int fp, i, ret;
- struct usrp_e_ctl16 d;
- char *str = argv[1];
- __u16 clkdiv;
-
- if (argc < 2) {
- printf("Usage: usrp_e_uart <string> <opt clkdiv>\n");
- printf("clkdiv = 278 is 230.4k \n");
- printf("clkdiv = 556 is 115.2k \n");
- exit(-1);
- }
-
- fp = open("/dev/usrp_e0", O_RDWR);
- printf("fp = %d\n", fp);
-
- if (argc == 3) {
- clkdiv = atoi(argv[2]);
- d.offset = UE_REG_UART_CLKDIV;
- d.count = 1;
- d.buf[0] = clkdiv;
- ret = ioctl(fp, USRP_E_WRITE_CTL16, &d);
- }
-
- for (i=0; i<strlen(str); i++) {
- d.offset = UE_REG_UART_TXCHAR;
- d.count = 1;
- d.buf[0] = str[i];
- ret = ioctl(fp, USRP_E_WRITE_CTL16, &d);
- printf("Wrote %X, to %X, ret = %d\n", d.buf[0], d.offset, ret);
- }
-
- return 0;
-}
diff --git a/host/apps/omap_debug/usrp-e-write.c b/host/apps/omap_debug/usrp-e-write.c
deleted file mode 100644
index 903c0071f..000000000
--- a/host/apps/omap_debug/usrp-e-write.c
+++ /dev/null
@@ -1,21 +0,0 @@
-#include <stdio.h>
-#include <sys/types.h>
-#include <fcntl.h>
-
-int main(int rgc, char *argv[])
-{
- int fp, i, cnt;
- short buf[1024];
-
- fp = open("/dev/usrp1_e0", O_WRONLY);
- printf("fp = %d\n", fp);
-
- for (i=0; i<1024; i++) {
- buf[i] = i;
- }
-
-// do {
- cnt = write(fp, buf, 2048);
- printf("Bytes written - %d\n", cnt);
-// } while (1);
-}
diff --git a/host/apps/omap_debug/usrp_e.h b/host/apps/omap_debug/usrp_e.h
deleted file mode 100644
index 2c4aa2ac1..000000000
--- a/host/apps/omap_debug/usrp_e.h
+++ /dev/null
@@ -1,60 +0,0 @@
-
-/*
- * Copyright (C) 2010 Ettus Research, LLC
- *
- * Written by Philip Balister <philip@opensdr.com>
- *
- * 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 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __USRP_E_H
-#define __USRP_E_H
-
-#include <linux/types.h>
-#include <linux/ioctl.h>
-
-struct usrp_e_ctl16 {
- __u32 offset;
- __u32 count;
- __u16 buf[20];
-};
-
-struct usrp_e_ctl32 {
- __u32 offset;
- __u32 count;
- __u32 buf[10];
-};
-
-#define USRP_E_IOC_MAGIC 'u'
-#define USRP_E_WRITE_CTL16 _IOW(USRP_E_IOC_MAGIC, 0x20, struct usrp_e_ctl16)
-#define USRP_E_READ_CTL16 _IOWR(USRP_E_IOC_MAGIC, 0x21, struct usrp_e_ctl16)
-#define USRP_E_WRITE_CTL32 _IOW(USRP_E_IOC_MAGIC, 0x22, struct usrp_e_ctl32)
-#define USRP_E_READ_CTL32 _IOWR(USRP_E_IOC_MAGIC, 0x23, struct usrp_e_ctl32)
-#define USRP_E_GET_RB_INFO _IOR(USRP_E_IOC_MAGIC, 0x27, struct usrp_e_ring_buffer_size_t)
-#define USRP_E_GET_COMPAT_NUMBER _IO(USRP_E_IOC_MAGIC, 0x28)
-
-#define USRP_E_COMPAT_NUMBER 2
-
-/* Flag defines */
-#define RB_USER (1<<0)
-#define RB_KERNEL (1<<1)
-#define RB_OVERRUN (1<<2)
-#define RB_DMA_ACTIVE (1<<3)
-#define RB_USER_PROCESS (1<<4)
-
-struct ring_buffer_info {
- int flags;
- int len;
-};
-
-struct usrp_e_ring_buffer_size_t {
- int num_pages_rx_flags;
- int num_rx_frames;
- int num_pages_tx_flags;
- int num_tx_frames;
-};
-
-#endif
diff --git a/host/cmake/Toolchains/mingw_cross.cmake b/host/cmake/Toolchains/mingw_cross.cmake
new file mode 100644
index 000000000..7c5adb002
--- /dev/null
+++ b/host/cmake/Toolchains/mingw_cross.cmake
@@ -0,0 +1,69 @@
+# Use this command:
+#
+# cmake -DCMAKE_TOOLCHAIN_FILE=cmake/Toolchain-mingw.cmake .
+#
+# or for out of source:
+#
+# cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-mingw.cmake ..
+#
+# You will need at least CMake 2.6.0.
+#
+# Adjust the following paths to suit your environment.
+#
+# This file was based on http://www.cmake.org/Wiki/CmakeMingw
+
+# the name of the target operating system
+set(CMAKE_SYSTEM_NAME Windows)
+
+# Assume the target architecture.
+# XXX for some reason the value set here gets cleared before we reach the
+# main CMakeLists.txt; see that file for a workaround.
+# set(CMAKE_SYSTEM_PROCESSOR i686)
+
+# Which compilers to use for C and C++, and location of target
+# environment.
+if(EXISTS /usr/i586-mingw32msvc)
+ # First look in standard location as used by Debian/Ubuntu/etc.
+ set(CMAKE_C_COMPILER i586-mingw32msvc-gcc)
+ set(CMAKE_CXX_COMPILER i586-mingw32msvc-g++)
+ set(CMAKE_RC_COMPILER i586-mingw32msvc-windres)
+ set(CMAKE_FIND_ROOT_PATH /usr/i586-mingw32msvc)
+elseif(EXISTS /usr/i686-w64-mingw32)
+ # First look in standard location as used by Debian/Ubuntu/etc.
+ set(CMAKE_C_COMPILER i686-w64-mingw32-gcc)
+ set(CMAKE_CXX_COMPILER i686-w64-mingw32-g++)
+ set(CMAKE_RC_COMPILER i686-w64-mingw32-windres)
+ set(CMAKE_AR:FILEPATH /usr/bin/i686-w64-mingw32-ar)
+elseif(EXISTS /opt/mingw)
+ # You can get a MinGW environment using the script at <http://mxe.cc>.
+ # It downloads and builds MinGW and most of the dependencies for you.
+ # You can use the toolchain file generated by MXE called `mxe-conf.cmake'
+ # or you can use this file by adjusting the above and following paths.
+ set(CMAKE_C_COMPILER /opt/mingw/usr/bin/i686-pc-mingw32-gcc)
+ set(CMAKE_CXX_COMPILER /opt/mingw/usr/bin/i686-pc-mingw32-g++)
+ set(CMAKE_RC_COMPILER /opt/mingw/usr/bin/i686-pc-mingw32-windres)
+ set(CMAKE_FIND_ROOT_PATH /opt/mingw/usr/i686-pc-mingw32)
+else()
+ # Else fill in local path which the user will likely adjust.
+ # This is the location assumed by <http://www.libsdl.org/extras/win32/cross/>
+ set(CMAKE_C_COMPILER /usr/local/cross-tools/bin/i386-mingw32-gcc)
+ set(CMAKE_CXX_COMPILER /usr/local/cross-tools/bin/i386-mingw32-g++)
+ set(CMAKE_RC_COMPILER /usr/local/cross-tools/bin/i386-mingw32-windres)
+ set(CMAKE_FIND_ROOT_PATH /usr/local/cross-tools)
+endif()
+
+# Adjust the default behaviour of the FIND_XXX() commands:
+# search headers and libraries in the target environment, search
+# programs in the host environment
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+
+# Tell pkg-config not to look at the target environment's .pc files.
+# Setting PKG_CONFIG_LIBDIR sets the default search directory, but we have to
+# set PKG_CONFIG_PATH as well to prevent pkg-config falling back to the host's
+# path.
+set(ENV{PKG_CONFIG_LIBDIR} ${CMAKE_FIND_ROOT_PATH}/lib/pkgconfig)
+set(ENV{PKG_CONFIG_PATH} ${CMAKE_FIND_ROOT_PATH}/lib/pkgconfig)
+
+set(ENV{MINGDIR} ${CMAKE_FIND_ROOT_PATH})
diff --git a/host/docs/dboards.dox b/host/docs/dboards.dox
index 3d6866a42..812a3a09e 100644
--- a/host/docs/dboards.dox
+++ b/host/docs/dboards.dox
@@ -372,6 +372,10 @@ Sensors:
- **rssi**: float for measured RSSI in dBm
- **temperature**: float for measured temperature in degC
+\subsection dboards_e300 E310 MIMO XCVR board
+
+Please refer to \ref e3x0_dboard_e310.
+
\subsection dboards_dbsrxmod DBSRX - Modifying for other boards that USRP1
Due to different clocking capabilities, the DBSRX will require
diff --git a/host/docs/uhd.dox b/host/docs/uhd.dox
index 949c710b1..fcd0a25b0 100644
--- a/host/docs/uhd.dox
+++ b/host/docs/uhd.dox
@@ -12,6 +12,7 @@ Some additional pages on developing UHD are also available here:
\li \subpage page_coding
\li \subpage page_converters
\li \subpage page_stream
+\li \subpage page_rtp
*/
// vim:ft=doxygen:
diff --git a/host/docs/usrp_b200.dox b/host/docs/usrp_b200.dox
index 6ee2f3445..9d3550b98 100644
--- a/host/docs/usrp_b200.dox
+++ b/host/docs/usrp_b200.dox
@@ -36,15 +36,40 @@ images:
The master clock rate feeds the RF frontends and the DSP chains. Users
may select non-default clock rates to acheive integer decimations or
-interpolations in the DSP chains. The default master clock rate defaults
-to 32 MHz, but can be set to any rate between 5 MHz and 61.44 MHz.
+interpolations in the DSP chains. The clock rate can be set to any value
+between 5 MHz and 61.44 MHz (or 30.72 MHz for dual-channel mode).
+Note that rates above 56 MHz are possible, but not recommended.
The user can set the master clock rate through the usrp API call
uhd::usrp::multi_usrp::set_master_clock_rate(), or the clock rate can be set through the
-device arguments, which many applications take: :
+device arguments, which many applications take:
uhd_usrp_probe --args="master_clock_rate=52e6"
+The property to control the master clock rate is a double value, called `tick_rate`.
+
+\subsection b200_auto_mcr Automatic Clock Rate Setting
+
+The default clock rate setting is to automatically set a clock rate
+depending on the requested sampling rate. The automatic clock rate selection
+is disabled when either `master_clock_rate` is given in the device initialization
+arguments, or when uhd::usrp::multi_usrp::set_master_clock_rate() is called.
+
+Note that the master clock rate must be an integer multiple of the sampling
+rate. If a master clock rate is chosen for which this condition does not
+hold, a warning will be displayed and a different sampling rate is used internally.
+
+Nevertheless, there are multiple valid values for the master clock rate
+for most sampling rates. The auto clock rate selection attempts to use
+the largest possible clock rate as to enable as many half-band filters
+as possible. Expert users might have cases where a more fine-grained
+control over the resampling stages is required, in which case manually
+selecting a master clock rate might be more suitable than the automatic
+rate.
+
+The property to dis- or enable the auto tick rate is a boolean value,
+`auto_tick_rate`.
+
\section b200_fe RF Frontend Notes
The B200 features an integrated RF frontend.
diff --git a/host/docs/usrp_e3x0.dox b/host/docs/usrp_e3x0.dox
index 38bf8d926..b55fa1054 100644
--- a/host/docs/usrp_e3x0.dox
+++ b/host/docs/usrp_e3x0.dox
@@ -191,7 +191,7 @@ builds)
$ bitbake gnuradio-dev-image
\endcode
-When this completes, the files needed to create the sd card are in
+When this completes, the files needed to create the SD card are in
`tmp-glibc/deploy/images/ettus-e300`
-# Build the toolchain.
@@ -537,7 +537,7 @@ usrp->set_rx_subdev_spec("A:A A:B");
The following sensors are available for the USRP-E Series motherboards;
they can be queried through the API.
-- **fe_locked** - rx / tx frontend pll locked
+- **fe_locked** - rx / tx frontend PLL locked
- **temp** - processor temperature value
- **gps_time** and **gps_locked** sensors are added when the GPS is found
diff --git a/host/docs/vrt_chdr.dox b/host/docs/vrt_chdr.dox
new file mode 100644
index 000000000..8ab177b21
--- /dev/null
+++ b/host/docs/vrt_chdr.dox
@@ -0,0 +1,83 @@
+/*! \page page_rtp Radio Transport Protocols
+
+\tableofcontents
+
+Radio transport protocols are used to exchange samples (or other items) between host and devices.
+If one were to sniff Ethernet traffic between a USRP and a PC, the packets would conform to a
+radio transport protocol.
+
+For USRP devices, two radio transport protocols are relevent: VRT (the VITA Radio Transport protocol)
+and CVITA (compressed VITA), also known as CHDR. Generation-3 devices and the B200 use CHDR, the rest
+use VRT.
+
+\section rtp_vrt VRT
+
+VRT is an open protocol defined by the VITA-49 standard. It was designed for interoperability,
+and to allow different device types to work with different software stacks.
+
+VRT is a very verbose standard, and only a subset is implemented in UHD/USRPs.
+The full standard is available from the VITA website: http://www.vita.com .
+
+
+\section rtp_chdr CVITA (CHDR)
+
+For the third generation of Ettus devices, a new type transport protocol was designed.
+It reduces the complexity of the original standard and uses a fixed-length 64-Bit header
+for everything except the timestamp. Because this is a "compressed" form of VITA, it
+was dubbed "Compressed VITA" (CVITA). The compressed header is called CHDR, which is why
+the protocol is often called CHDR itself (pronounced like the cheese "cheddar").
+
+By compressing all information into a 64-bit line, the header can efficiently be parsed
+in newer FPGAs, where the common streaming protocol is 64-Bit AXI. The first line in a
+packet already provides all necessary information to proceed.
+
+Some CHDR-specific functions can be found in: uhd::transport::vrt::chdr.
+
+The form of a CVITA packet is the following:
+
+Address (Bytes) | Length (Bytes) | Payload
+----------------|----------------|----------------------------
+0 | 8 | Compressed Header (CHDR)
+8 | 8 | Fractional Time (Optional!)
+8/16 | - | Data
+
+If there is no timestamp present, the data starts at address 8, otherwise, it starts at 16.
+
+The 64 Bits in the compressed header have the following meaning:
+
+Bits | Meaning
+-------|--------------------------------------------------
+63:62 | Packet Type
+61 | Has fractional time stamp (1: Yes)
+60 | End-of-burst or error flag
+59:48 | 12-bit sequence number
+47:32 | Total packet length in Bytes
+31:0 | Stream ID (SID)
+
+
+The packet type is determined mainly by the first two bits, although
+the EOB or error flag are also taken into consideration:
+
+Bit 63 | Bit 62 | Bit 60 | Packet Type
+-------|--------|--------|--------------
+0 | 0 | 0 | Data
+0 | 0 | 1 | Data (End-of-burst)
+0 | 1 | 0 | Flow Control
+1 | 0 | 0 | Command Packet
+1 | 1 | 0 | Command Response
+1 | 1 | 1 | Command Response (Error)
+
+\section vrt_tools Tools
+
+For CHDR, we provide a Wireshark dissector under tools/chdr_dissector. It can be used
+for Ethernet links as well as USB (e.g., for the B210).
+
+\section vrt_code Code
+
+Relevent code sections for the radio transport layer are:
+* uhd::transport::vrt - Namespace for radio transport protocol related functions and definitions
+* uhd::transport::vrt::chdr - Sub-namespace specifically for CVITA/CHDR
+* uhd::sid_t - Datatype to represent SIDs
+
+*/
+// vim:ft=doxygen:
diff --git a/host/examples/CMakeLists.txt b/host/examples/CMakeLists.txt
index 1e6f2f013..92947d86c 100644
--- a/host/examples/CMakeLists.txt
+++ b/host/examples/CMakeLists.txt
@@ -29,14 +29,13 @@ SET(example_sources
test_messages.cpp
test_pps_input.cpp
test_timed_commands.cpp
- transport_hammer.cpp
tx_bursts.cpp
tx_samples_from_file.cpp
tx_timed_samples.cpp
tx_waveforms.cpp
txrx_loopback_to_file.cpp
latency_test.cpp
- fpgpio.cpp
+ gpio.cpp
)
IF(ENABLE_OCTOCLOCK)
diff --git a/host/examples/benchmark_rate.cpp b/host/examples/benchmark_rate.cpp
index 03d8f3477..7ff8b9939 100644
--- a/host/examples/benchmark_rate.cpp
+++ b/host/examples/benchmark_rate.cpp
@@ -43,7 +43,12 @@ unsigned long long num_seq_errors = 0;
/***********************************************************************
* Benchmark RX Rate
**********************************************************************/
-void benchmark_rx_rate(uhd::usrp::multi_usrp::sptr usrp, const std::string &rx_cpu, uhd::rx_streamer::sptr rx_stream){
+void benchmark_rx_rate(
+ uhd::usrp::multi_usrp::sptr usrp,
+ const std::string &rx_cpu,
+ uhd::rx_streamer::sptr rx_stream,
+ bool random_nsamps
+) {
uhd::set_thread_priority_safe();
//print pre-test summary
@@ -68,15 +73,19 @@ void benchmark_rx_rate(uhd::usrp::multi_usrp::sptr usrp, const std::string &rx_c
rx_stream->issue_stream_cmd(cmd);
while (not boost::this_thread::interruption_requested()){
+ if (random_nsamps) {
+ cmd.num_samps = rand() % max_samps_per_packet;
+ rx_stream->issue_stream_cmd(cmd);
+ }
try {
- num_rx_samps += rx_stream->recv(buffs, max_samps_per_packet, md)*rx_stream->get_num_channels();
+ num_rx_samps += rx_stream->recv(buffs, max_samps_per_packet, md)*rx_stream->get_num_channels();
}
catch (...) {
- /* apparently, the boost thread interruption can sometimes result in
- throwing exceptions not of type boost::exception, this catch allows
- this thread to still attempt to issue the STREAM_MODE_STOP_CONTINUOUS
- */
- break;
+ /* apparently, the boost thread interruption can sometimes result in
+ throwing exceptions not of type boost::exception, this catch allows
+ this thread to still attempt to issue the STREAM_MODE_STOP_CONTINUOUS
+ */
+ break;
}
//handle the error codes
@@ -109,7 +118,12 @@ void benchmark_rx_rate(uhd::usrp::multi_usrp::sptr usrp, const std::string &rx_c
/***********************************************************************
* Benchmark TX Rate
**********************************************************************/
-void benchmark_tx_rate(uhd::usrp::multi_usrp::sptr usrp, const std::string &tx_cpu, uhd::tx_streamer::sptr tx_stream){
+void benchmark_tx_rate(
+ uhd::usrp::multi_usrp::sptr usrp,
+ const std::string &tx_cpu,
+ uhd::tx_streamer::sptr tx_stream,
+ bool random_nsamps=false
+) {
uhd::set_thread_priority_safe();
//print pre-test summary
@@ -127,9 +141,25 @@ void benchmark_tx_rate(uhd::usrp::multi_usrp::sptr usrp, const std::string &tx_c
buffs.push_back(&buff.front()); //same buffer for each channel
md.has_time_spec = (buffs.size() != 1);
- while (not boost::this_thread::interruption_requested()){
- num_tx_samps += tx_stream->send(buffs, max_samps_per_packet, md)*tx_stream->get_num_channels();;
- md.has_time_spec = false;
+ if (random_nsamps) {
+ std::srand( time(NULL) );
+ while(not boost::this_thread::interruption_requested()){
+ size_t total_num_samps = rand() % max_samps_per_packet;
+ size_t num_acc_samps = 0;
+ const float timeout = 1;
+
+ usrp->set_time_now(uhd::time_spec_t(0.0));
+ while(num_acc_samps < total_num_samps){
+ //send a single packet
+ num_tx_samps += tx_stream->send(buffs, max_samps_per_packet, md, timeout)*tx_stream->get_num_channels();
+ num_acc_samps += std::min(total_num_samps-num_acc_samps, tx_stream->get_max_num_samps());
+ }
+ }
+ } else {
+ while (not boost::this_thread::interruption_requested()){
+ num_tx_samps += tx_stream->send(buffs, max_samps_per_packet, md)*tx_stream->get_num_channels();
+ md.has_time_spec = false;
+ }
}
//send a mini EOB packet
@@ -182,6 +212,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
std::string rx_cpu, tx_cpu;
std::string mode;
std::string channel_list;
+ bool random_nsamps = false;
//setup the program options
po::options_description desc("Allowed options");
@@ -196,6 +227,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
("rx_cpu", po::value<std::string>(&rx_cpu)->default_value("fc32"), "specify the host/cpu sample mode for RX")
("tx_cpu", po::value<std::string>(&tx_cpu)->default_value("fc32"), "specify the host/cpu sample mode for TX")
("mode", po::value<std::string>(&mode)->default_value("none"), "multi-channel sync mode option: none, mimo")
+ ("random", "Run with random values of samples in send() and recv() to stress-test the I/O.")
("channels", po::value<std::string>(&channel_list)->default_value("0"), "which channel(s) to use (specify \"0\", \"1\", \"0,1\", etc)")
;
po::variables_map vm;
@@ -213,6 +245,12 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
return ~0;
}
+ // Random number of samples?
+ if (vm.count("random")) {
+ std::cout << "Using random number of samples in send() and recv() calls." << std::endl;
+ random_nsamps = true;
+ }
+
//create a usrp device
std::cout << std::endl;
uhd::device_addrs_t device_addrs = uhd::device::find(args, uhd::device::USRP);
@@ -251,7 +289,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
uhd::stream_args_t stream_args(rx_cpu, rx_otw);
stream_args.channels = channel_nums;
uhd::rx_streamer::sptr rx_stream = usrp->get_rx_stream(stream_args);
- thread_group.create_thread(boost::bind(&benchmark_rx_rate, usrp, rx_cpu, rx_stream));
+ thread_group.create_thread(boost::bind(&benchmark_rx_rate, usrp, rx_cpu, rx_stream, random_nsamps));
}
//spawn the transmit test thread
@@ -261,7 +299,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
uhd::stream_args_t stream_args(tx_cpu, tx_otw);
stream_args.channels = channel_nums;
uhd::tx_streamer::sptr tx_stream = usrp->get_tx_stream(stream_args);
- thread_group.create_thread(boost::bind(&benchmark_tx_rate, usrp, tx_cpu, tx_stream));
+ thread_group.create_thread(boost::bind(&benchmark_tx_rate, usrp, tx_cpu, tx_stream, random_nsamps));
thread_group.create_thread(boost::bind(&benchmark_tx_rate_async_helper, tx_stream));
}
@@ -287,6 +325,5 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
//finished
std::cout << std::endl << "Done!" << std::endl << std::endl;
-
return EXIT_SUCCESS;
}
diff --git a/host/examples/fpgpio.cpp b/host/examples/fpgpio.cpp
deleted file mode 100644
index c57893669..000000000
--- a/host/examples/fpgpio.cpp
+++ /dev/null
@@ -1,418 +0,0 @@
-//
-// Copyright 2014 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/>.
-//
-
-// Example for front panel GPIO.
-// Bits are set as follows:
-// FPGPIO[0] = ATR output 1 at idle
-// FPGPIO[1] = ATR output 1 during RX
-// FPGPIO[2] = ATR output 1 during TX
-// FPGPIO[3] = ATR output 1 during full duplex
-// FPGPIO[4] = output
-// FPGPIO[5] = input
-// FPGPIO[6] = input (X series only)
-// FPGPIO[7] = input (X series only)
-// FPGPIO[8] = input (X series only)
-// FPGPIO[9] = input (X series only)
-// FPGPIO[10] = input (X series only)
-// The example cycles through idle, TX, RX, and full duplex, spending 2 seconds for each.
-// Outputs can be physically looped back to inputs for verification testing.
-
-#include <uhd/utils/thread_priority.hpp>
-#include <uhd/utils/safe_main.hpp>
-#include <uhd/usrp/multi_usrp.hpp>
-#include <uhd/convert.hpp>
-#include <boost/program_options.hpp>
-#include <boost/format.hpp>
-#include <boost/cstdint.hpp>
-#include <boost/thread.hpp>
-#include <csignal>
-#include <iostream>
-
-static const std::string FPGPIO_DEFAULT_CPU_FORMAT = "fc32";
-static const std::string FPGPIO_DEFAULT_OTW_FORMAT = "sc16";
-static const double FPGPIO_DEFAULT_RX_RATE = 500e3;
-static const double FPGPIO_DEFAULT_TX_RATE = 500e3;
-static const double FPGPIO_DEFAULT_DWELL_TIME = 2.0;
-static const std::string FPGPIO_DEFAULT_GPIO = "FP0";
-static const size_t FPGPIO_DEFAULT_NUM_BITS = 11;
-
-static UHD_INLINE boost::uint32_t FPGPIO_BIT(const size_t x)
-{
- return (1 << x);
-}
-
-namespace po = boost::program_options;
-
-static bool stop_signal_called = false;
-void sig_int_handler(int){stop_signal_called = true;}
-
-std::string to_bit_string(boost::uint32_t val, const size_t num_bits)
-{
- std::string out;
- for (int i = num_bits - 1; i >= 0; i--)
- {
- std::string bit = ((val >> i) & 1) ? "1" : "0";
- out += " ";
- out += bit;
- }
- return out;
-}
-
-void output_reg_values(
- const std::string bank,
- const uhd::usrp::multi_usrp::sptr &usrp,
- const size_t num_bits)
-{
- std::cout << (boost::format("Bit "));
- for (int i = num_bits - 1; i >= 0; i--)
- std::cout << (boost::format(" %s%d") % (i < 10 ? " " : "") % i);
- std::cout << std::endl;
- std::cout << "CTRL: " << to_bit_string(
- boost::uint32_t(usrp->get_gpio_attr(bank, std::string("CTRL"))),
- num_bits)
- << std::endl;
-
- std::cout << "DDR: " << to_bit_string(
- boost::uint32_t(usrp->get_gpio_attr(bank, std::string("DDR"))),
- num_bits)
- << std::endl;
-
- std::cout << "ATR_0X: " << to_bit_string(
- boost::uint32_t(usrp->get_gpio_attr(bank, std::string("ATR_0X"))),
- num_bits)
- << std::endl;
-
- std::cout << "ATR_RX: " << to_bit_string(
- boost::uint32_t(usrp->get_gpio_attr(bank, std::string("ATR_RX"))),
- num_bits)
- << std::endl;
-
- std::cout << "ATR_TX: " << to_bit_string(
- boost::uint32_t(usrp->get_gpio_attr(bank, std::string("ATR_TX"))),
- num_bits)
- << std::endl;
-
- std::cout << "ATR_XX: " << to_bit_string(
- boost::uint32_t(usrp->get_gpio_attr(bank, std::string("ATR_XX"))),
- num_bits)
- << std::endl;
-
- std::cout << "OUT: " << to_bit_string(
- boost::uint32_t(usrp->get_gpio_attr(bank, std::string("OUT"))),
- num_bits)
- << std::endl;
-
- std::cout << "READBACK: " << to_bit_string(
- boost::uint32_t(usrp->get_gpio_attr(bank, std::string("READBACK"))),
- num_bits)
- << std::endl;
-}
-
-int UHD_SAFE_MAIN(int argc, char *argv[])
-{
- uhd::set_thread_priority_safe();
-
- //variables to be set by po
- std::string args;
- std::string cpu, otw;
- double rx_rate, tx_rate, dwell;
- std::string fpgpio;
- size_t num_bits;
-
- //setup the program options
- po::options_description desc("Allowed options");
- desc.add_options()
- ("help", "help message")
- ("args", po::value<std::string>(&args)->default_value(""), "multi uhd device address args")
- ("repeat", "repeat loop until Ctrl-C is pressed")
- ("cpu", po::value<std::string>(&cpu)->default_value(FPGPIO_DEFAULT_CPU_FORMAT), "cpu data format")
- ("otw", po::value<std::string>(&otw)->default_value(FPGPIO_DEFAULT_OTW_FORMAT), "over the wire data format")
- ("rx_rate", po::value<double>(&rx_rate)->default_value(FPGPIO_DEFAULT_RX_RATE), "rx sample rate")
- ("tx_rate", po::value<double>(&tx_rate)->default_value(FPGPIO_DEFAULT_TX_RATE), "tx sample rate")
- ("dwell", po::value<double>(&dwell)->default_value(FPGPIO_DEFAULT_DWELL_TIME), "dwell time in seconds for each test case")
- ("gpio", po::value<std::string>(&fpgpio)->default_value(FPGPIO_DEFAULT_GPIO), "name of gpio bank")
- ("bits", po::value<size_t>(&num_bits)->default_value(FPGPIO_DEFAULT_NUM_BITS), "number of bits in gpio bank")
- ;
- po::variables_map vm;
- po::store(po::parse_command_line(argc, argv, desc), vm);
- po::notify(vm);
-
- //print the help message
- if (vm.count("help")){
- std::cout << boost::format("Front Panel GPIO %s") % desc << std::endl;
- return ~0;
- }
-
- //create a usrp device
- std::cout << std::endl;
- std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl;
- uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args);
- std::cout << boost::format("Using Device: %s") % usrp->get_pp_string() << std::endl;
-
- //print out initial unconfigured state of FP GPIO
- std::cout << "Unconfigured GPIO values:" << std::endl;
- output_reg_values(fpgpio, usrp, num_bits);
-
- //configure GPIO registers
- boost::uint32_t ctrl = 0; // default all as manual
- boost::uint32_t ddr = 0; // default all as input
- boost::uint32_t atr_idle = 0;
- boost::uint32_t atr_rx = 0;
- boost::uint32_t atr_tx = 0;
- boost::uint32_t atr_duplex = 0;
- boost::uint32_t mask = 0x7ff;
-
- //set up FPGPIO outputs:
- //FPGPIO[0] = ATR output 1 at idle
- ctrl |= FPGPIO_BIT(0);
- atr_idle |= FPGPIO_BIT(0);
- ddr |= FPGPIO_BIT(0);
-
- //FPGPIO[1] = ATR output 1 during RX
- ctrl |= FPGPIO_BIT(1);
- ddr |= FPGPIO_BIT(1);
- atr_rx |= FPGPIO_BIT(1);
-
- //FPGPIO[2] = ATR output 1 during TX
- ctrl |= FPGPIO_BIT(2);
- ddr |= FPGPIO_BIT(2);
- atr_tx |= FPGPIO_BIT(2);
-
- //FPGPIO[3] = ATR output 1 during full duplex
- ctrl |= FPGPIO_BIT(3);
- ddr |= FPGPIO_BIT(3);
- atr_duplex |= FPGPIO_BIT(3);
-
- //FPGPIO[4] = output
- ddr |= FPGPIO_BIT(4);
-
- //set data direction register (DDR)
- usrp->set_gpio_attr(fpgpio, std::string("DDR"), ddr, mask);
-
- //set ATR registers
- usrp->set_gpio_attr(fpgpio, std::string("ATR_0X"), atr_idle, mask);
- usrp->set_gpio_attr(fpgpio, std::string("ATR_RX"), atr_rx, mask);
- usrp->set_gpio_attr(fpgpio, std::string("ATR_TX"), atr_tx, mask);
- usrp->set_gpio_attr(fpgpio, std::string("ATR_XX"), atr_duplex, mask);
-
- //set control register
- usrp->set_gpio_attr(fpgpio, std::string("CTRL"), ctrl, mask);
-
- //print out initial state of FP GPIO
- std::cout << "\nConfigured GPIO values:" << std::endl;
- output_reg_values(fpgpio, usrp, num_bits);
- std::cout << std::endl;
-
- //set up streams
- uhd::stream_args_t rx_args(cpu, otw);
- uhd::stream_args_t tx_args(cpu, otw);
- uhd::rx_streamer::sptr rx_stream = usrp->get_rx_stream(rx_args);
- uhd::tx_streamer::sptr tx_stream = usrp->get_tx_stream(tx_args);
- uhd::stream_cmd_t rx_cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
- rx_cmd.stream_now = true;
- usrp->set_rx_rate(rx_rate);
- usrp->set_tx_rate(tx_rate);
-
- //set up buffers for tx and rx
- const size_t max_samps_per_packet = rx_stream->get_max_num_samps();
- const size_t nsamps_per_buff = max_samps_per_packet;
- std::vector<char> rx_buff(max_samps_per_packet*uhd::convert::get_bytes_per_item(cpu));
- std::vector<char> tx_buff(max_samps_per_packet*uhd::convert::get_bytes_per_item(cpu));
- std::vector<void *> rx_buffs, tx_buffs;
- for (size_t ch = 0; ch < rx_stream->get_num_channels(); ch++)
- rx_buffs.push_back(&rx_buff.front()); //same buffer for each channel
- for (size_t ch = 0; ch < tx_stream->get_num_channels(); ch++)
- tx_buffs.push_back(&tx_buff.front()); //same buffer for each channel
-
- uhd::rx_metadata_t rx_md;
- uhd::tx_metadata_t tx_md;
- tx_md.has_time_spec = false;
- tx_md.start_of_burst = true;
- uhd::time_spec_t stop_time;
- double timeout = 0.01;
- uhd::time_spec_t dwell_time(dwell);
- int loop = 0;
- boost::uint32_t rb, expected;
-
- //register singal handler
- std::signal(SIGINT, &sig_int_handler);
-
- //Test the mask - only need to test once with no dwell time
- std::cout << "\nTesting mask..." << std::flush;
- //send a value of all 1's to the DDR with a mask for only bit 10
- usrp->set_gpio_attr(fpgpio, std::string("DDR"), ~0, FPGPIO_BIT(10));
- //bit 10 should now be 1, but all the other bits should be unchanged
- rb = usrp->get_gpio_attr(fpgpio, std::string("DDR")) & mask;
- expected = ddr | FPGPIO_BIT(10);
- if (rb == expected)
- std::cout << "pass" << std::endl;
- else
- std::cout << "fail" << std::endl;
- std::cout << std::endl;
- output_reg_values(fpgpio, usrp, num_bits);
- usrp->set_gpio_attr(fpgpio, std::string("DDR"), ddr, mask);
-
- while (not stop_signal_called)
- {
- int failures = 0;
-
- if (vm.count("repeat"))
- std::cout << "Press Ctrl + C to quit..." << std::endl;
-
- // test user controlled GPIO and ATR idle by setting bit 4 high for 1 second
- std::cout << "\nTesting user controlled GPIO and ATR idle output..." << std::flush;
- usrp->set_gpio_attr(fpgpio, "OUT", 1 << 4, 1 << 4);
- stop_time = usrp->get_time_now() + dwell_time;
- while (not stop_signal_called and usrp->get_time_now() < stop_time)
- {
- boost::this_thread::sleep(boost::posix_time::milliseconds(100));
- }
- rb = usrp->get_gpio_attr(fpgpio, "READBACK");
- expected = FPGPIO_BIT(4) | FPGPIO_BIT(0);
- if ((rb & expected) != expected)
- {
- ++failures;
- std::cout << "fail" << std::endl;
- if ((rb & FPGPIO_BIT(0)) == 0)
- std::cout << "Bit 0 should be set, but is not" << std::endl;
- if ((rb & FPGPIO_BIT(4)) == 0)
- std::cout << "Bit 4 should be set, but is not" << std::endl;
- } else {
- std::cout << "pass" << std::endl;
- }
- std::cout << std::endl;
- output_reg_values(fpgpio, usrp, num_bits);
- usrp->set_gpio_attr(fpgpio, "OUT", 0, FPGPIO_BIT(4));
- if (stop_signal_called)
- break;
-
- // test ATR RX by receiving for 1 second
- std::cout << "\nTesting ATR RX output..." << std::flush;
- rx_cmd.stream_mode = uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS;
- rx_stream->issue_stream_cmd(rx_cmd);
- stop_time = usrp->get_time_now() + dwell_time;
- while (not stop_signal_called and usrp->get_time_now() < stop_time)
- {
- try {
- rx_stream->recv(rx_buffs, nsamps_per_buff, rx_md, timeout);
- } catch(...){}
- }
- rb = usrp->get_gpio_attr(fpgpio, "READBACK");
- expected = FPGPIO_BIT(1);
- if ((rb & expected) != expected)
- {
- ++failures;
- std::cout << "fail" << std::endl;
- std::cout << "Bit 1 should be set, but is not" << std::endl;
- } else {
- std::cout << "pass" << std::endl;
- }
- std::cout << std::endl;
- output_reg_values(fpgpio, usrp, num_bits);
- rx_stream->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
- //clear out any data left in the rx stream
- try {
- rx_stream->recv(rx_buffs, nsamps_per_buff, rx_md, timeout);
- } catch(...){}
- if (stop_signal_called)
- break;
-
- // test ATR TX by transmitting for 1 second
- std::cout << "\nTesting ATR TX output..." << std::flush;
- stop_time = usrp->get_time_now() + dwell_time;
- tx_md.start_of_burst = true;
- tx_md.end_of_burst = false;
- while (not stop_signal_called and usrp->get_time_now() < stop_time)
- {
- try {
- tx_stream->send(tx_buffs, nsamps_per_buff, tx_md, timeout);
- tx_md.start_of_burst = false;
- } catch(...){}
- }
- rb = usrp->get_gpio_attr(fpgpio, "READBACK");
- expected = FPGPIO_BIT(2);
- if ((rb & expected) != expected)
- {
- ++failures;
- std::cout << "fail" << std::endl;
- std::cout << "Bit 2 should be set, but is not" << std::endl;
- } else {
- std::cout << "pass" << std::endl;
- }
- std::cout << std::endl;
- output_reg_values(fpgpio, usrp, num_bits);
- tx_md.end_of_burst = true;
- try {
- tx_stream->send(tx_buffs, nsamps_per_buff, tx_md, timeout);
- } catch(...){}
- if (stop_signal_called)
- break;
-
- // test ATR RX by transmitting and receiving for 1 second
- std::cout << "\nTesting ATR full duplex output..." << std::flush;
- rx_cmd.stream_mode = uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS;
- rx_stream->issue_stream_cmd(rx_cmd);
- tx_md.start_of_burst = true;
- tx_md.end_of_burst = false;
- stop_time = usrp->get_time_now() + dwell_time;
- while (not stop_signal_called and usrp->get_time_now() < stop_time)
- {
- try {
- tx_stream->send(rx_buffs, nsamps_per_buff, tx_md, timeout);
- tx_md.start_of_burst = false;
- rx_stream->recv(tx_buffs, nsamps_per_buff, rx_md, timeout);
- } catch(...){}
- }
- rb = usrp->get_gpio_attr(fpgpio, "READBACK");
- expected = FPGPIO_BIT(3);
- if ((rb & expected) != expected)
- {
- ++failures;
- std::cout << "fail" << std::endl;
- std::cout << "Bit 3 should be set, but is not" << std::endl;
- } else {
- std::cout << "pass" << std::endl;
- }
- std::cout << std::endl;
- output_reg_values(fpgpio, usrp, num_bits);
- rx_stream->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
- tx_md.end_of_burst = true;
- try {
- tx_stream->send(tx_buffs, nsamps_per_buff, tx_md, timeout);
- } catch(...){}
- //clear out any data left in the rx stream
- try {
- rx_stream->recv(rx_buffs, nsamps_per_buff, rx_md, timeout);
- } catch(...){}
-
- std::cout << std::endl;
- if (failures)
- std::cout << failures << " tests failed" << std::endl;
- else
- std::cout << "All tests passed!" << std::endl;
-
- if (!vm.count("repeat"))
- break;
-
- std::cout << (boost::format("\nLoop %d completed") % ++loop) << std::endl;
- }
-
- //finished
- std::cout << std::endl << "Done!" << std::endl << std::endl;
-
- return EXIT_SUCCESS;
-}
diff --git a/host/examples/gpio.cpp b/host/examples/gpio.cpp
new file mode 100644
index 000000000..b0d15f35a
--- /dev/null
+++ b/host/examples/gpio.cpp
@@ -0,0 +1,462 @@
+//
+// Copyright 2014-15 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/>.
+//
+
+// Example for GPIO testing and bit banging.
+//
+// This example was originally designed to test the 11 bit wide front panel
+// GPIO on the X300 series and has since been adapted to work with any GPIO
+// bank on any USRP and provide optional bit banging. Please excuse the
+// clutter. Also, there is no current way to detect the width of the
+// specified GPIO bank, so the user must specify the width with the --bits
+// flag if more than 11 bits.
+//
+// GPIO Testing:
+// For testing, GPIO bits are set as follows:
+// GPIO[0] = ATR output 1 at idle
+// GPIO[1] = ATR output 1 during RX
+// GPIO[2] = ATR output 1 during TX
+// GPIO[3] = ATR output 1 during full duplex
+// GPIO[4] = output
+// GPIO[n:5] = input (all other pins)
+// The testing cycles through idle, TX, RX, and full duplex, dwelling on each
+// test case (default 2 seconds), and then comparing the readback register with
+// the expected values of the outputs for verification. The values of all GPIO
+// registers are displayed at the end of each test case. Outputs can be
+// physically looped back to inputs to manually verify the inputs.
+//
+// GPIO Bit Banging:
+// GPIO banks have the standard registers of DDR for data direction and OUT
+// for output values. Users can bit bang the GPIO bits by using this example
+// with the --bitbang flag and specifying the --ddr and --out flags to set the
+// values of the corresponding registers. The READBACK register is
+// continuously read for the duration of the dwell time (default 2 seconds) so
+// users can monitor changes on the inputs.
+//
+// Automatic Transmit/Receive (ATR):
+// In addition to the standard DDR and OUT registers, the GPIO banks also
+// have ATR (Automatic Transmit/Receive) control registers that allow the
+// GPIO pins to be automatically set to specific values when the USRP is
+// idle, transmitting, receiving, or operating in full duplex mode. The
+// description of these registers is below:
+// CTRL - Control (0=manual, 1=ATR)
+// ATR_0X - Values to be set when idle
+// ATR_RX - Output values to be set when receiving
+// ATR_TX - Output values to be set when transmitting
+// ATR_XX - Output values to be set when operating in full duplex
+// This code below contains examples of setting all these registers. On
+// devices with multiple radios, the ATR for the front panel GPIO is driven
+// by the state of the first radio (0 or A).
+//
+// The UHD API
+// The multi_usrp::set_gpio_attr() method is the UHD API for configuring and
+// controlling the GPIO banks. The parameters to the method are:
+// bank - the name of the GPIO bank (typically "FP0" for front panel GPIO,
+// "TX<n>" for TX daughter card GPIO, or
+// "RX<n>" for RX daughter card GPIO)
+// attr - attribute (register) to change ("DDR", "OUT", "CTRL", "ATR_0X",
+// "ATR_RX", "ATR_TX", "ATR_XX")
+// value - the value to be set
+// mask - a mask indicating which bits in the specified attribute register are
+// to be changed (default is all bits).
+
+#include <uhd/utils/thread_priority.hpp>
+#include <uhd/utils/safe_main.hpp>
+#include <uhd/usrp/multi_usrp.hpp>
+#include <uhd/convert.hpp>
+#include <boost/assign.hpp>
+#include <boost/program_options.hpp>
+#include <boost/format.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/thread.hpp>
+#include <csignal>
+#include <iostream>
+#include <stdlib.h>
+
+static const std::string GPIO_DEFAULT_CPU_FORMAT = "fc32";
+static const std::string GPIO_DEFAULT_OTW_FORMAT = "sc16";
+static const double GPIO_DEFAULT_RX_RATE = 500e3;
+static const double GPIO_DEFAULT_TX_RATE = 500e3;
+static const double GPIO_DEFAULT_DWELL_TIME = 2.0;
+static const std::string GPIO_DEFAULT_GPIO = "FP0";
+static const size_t GPIO_DEFAULT_NUM_BITS = 11;
+static const std::string GPIO_DEFAULT_CTRL = "0x0"; // all as user controlled
+static const std::string GPIO_DEFAULT_DDR = "0x0"; // all as inputs
+static const std::string GPIO_DEFAULT_OUT = "0x0";
+
+static UHD_INLINE boost::uint32_t GPIO_BIT(const size_t x)
+{
+ return (1 << x);
+}
+
+namespace po = boost::program_options;
+
+static bool stop_signal_called = false;
+void sig_int_handler(int){stop_signal_called = true;}
+
+std::string to_bit_string(boost::uint32_t val, const size_t num_bits)
+{
+ std::string out;
+ for (int i = num_bits - 1; i >= 0; i--)
+ {
+ std::string bit = ((val >> i) & 1) ? "1" : "0";
+ out += " ";
+ out += bit;
+ }
+ return out;
+}
+
+void output_reg_values(
+ const std::string bank,
+ const uhd::usrp::multi_usrp::sptr &usrp,
+ const size_t num_bits)
+{
+ std::vector<std::string> attrs = boost::assign::list_of("CTRL")("DDR")("ATR_0X")("ATR_RX")("ATR_TX")("ATR_XX")("OUT")("READBACK");
+ std::cout << (boost::format("%10s ") % "Bit");
+ for (int i = num_bits - 1; i >= 0; i--)
+ std::cout << (boost::format(" %2d") % i);
+ std::cout << std::endl;
+ BOOST_FOREACH(std::string &attr, attrs)
+ {
+ std::cout << (boost::format("%10s:%s")
+ % attr % to_bit_string(boost::uint32_t(usrp->get_gpio_attr(bank, attr)), num_bits))
+ << std::endl;
+ }
+}
+
+int UHD_SAFE_MAIN(int argc, char *argv[])
+{
+ uhd::set_thread_priority_safe();
+
+ //variables to be set by po
+ std::string args;
+ std::string cpu, otw;
+ double rx_rate, tx_rate, dwell;
+ std::string gpio;
+ size_t num_bits;
+ std::string ctrl_str;
+ std::string ddr_str;
+ std::string out_str;
+
+ //setup the program options
+ po::options_description desc("Allowed options");
+ desc.add_options()
+ ("help", "help message")
+ ("args", po::value<std::string>(&args)->default_value(""), "multi uhd device address args")
+ ("repeat", "repeat loop until Ctrl-C is pressed")
+ ("cpu", po::value<std::string>(&cpu)->default_value(GPIO_DEFAULT_CPU_FORMAT), "cpu data format")
+ ("otw", po::value<std::string>(&otw)->default_value(GPIO_DEFAULT_OTW_FORMAT), "over the wire data format")
+ ("rx_rate", po::value<double>(&rx_rate)->default_value(GPIO_DEFAULT_RX_RATE), "rx sample rate")
+ ("tx_rate", po::value<double>(&tx_rate)->default_value(GPIO_DEFAULT_TX_RATE), "tx sample rate")
+ ("dwell", po::value<double>(&dwell)->default_value(GPIO_DEFAULT_DWELL_TIME), "dwell time in seconds for each test case")
+ ("bank", po::value<std::string>(&gpio)->default_value(GPIO_DEFAULT_GPIO), "name of gpio bank")
+ ("bits", po::value<size_t>(&num_bits)->default_value(GPIO_DEFAULT_NUM_BITS), "number of bits in gpio bank")
+ ("bitbang", "single test case where user sets values for CTRL, DDR, and OUT registers")
+ ("ddr", po::value<std::string>(&ddr_str)->default_value(GPIO_DEFAULT_DDR), "GPIO DDR reg value")
+ ("out", po::value<std::string>(&out_str)->default_value(GPIO_DEFAULT_OUT), "GPIO OUT reg value")
+ ;
+ po::variables_map vm;
+ po::store(po::parse_command_line(argc, argv, desc), vm);
+ po::notify(vm);
+
+ //print the help message
+ if (vm.count("help")){
+ std::cout << boost::format("gpio %s") % desc << std::endl;
+ return ~0;
+ }
+
+ //create a usrp device
+ std::cout << std::endl;
+ std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl;
+ uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args);
+ std::cout << boost::format("Using Device: %s") % usrp->get_pp_string() << std::endl;
+
+ //print out initial unconfigured state of FP GPIO
+ std::cout << "Initial GPIO values:" << std::endl;
+ output_reg_values(gpio, usrp, num_bits);
+
+ //configure GPIO registers
+ boost::uint32_t ddr = strtoul(ddr_str.c_str(), NULL, 0);
+ boost::uint32_t out = strtoul(out_str.c_str(), NULL, 0);
+ boost::uint32_t ctrl = 0;
+ boost::uint32_t atr_idle = 0;
+ boost::uint32_t atr_rx = 0;
+ boost::uint32_t atr_tx = 0;
+ boost::uint32_t atr_duplex = 0;
+ boost::uint32_t mask = (1 << num_bits) - 1;
+
+ if (!vm.count("bitbang"))
+ {
+ //set up GPIO outputs:
+ //GPIO[0] = ATR output 1 at idle
+ ctrl |= GPIO_BIT(0);
+ atr_idle |= GPIO_BIT(0);
+ ddr |= GPIO_BIT(0);
+
+ //GPIO[1] = ATR output 1 during RX
+ ctrl |= GPIO_BIT(1);
+ ddr |= GPIO_BIT(1);
+ atr_rx |= GPIO_BIT(1);
+
+ //GPIO[2] = ATR output 1 during TX
+ ctrl |= GPIO_BIT(2);
+ ddr |= GPIO_BIT(2);
+ atr_tx |= GPIO_BIT(2);
+
+ //GPIO[3] = ATR output 1 during full duplex
+ ctrl |= GPIO_BIT(3);
+ ddr |= GPIO_BIT(3);
+ atr_duplex |= GPIO_BIT(3);
+
+ //GPIO[4] = output
+ ddr |= GPIO_BIT(4);
+ }
+
+ //set data direction register (DDR)
+ usrp->set_gpio_attr(gpio, "DDR", ddr, mask);
+
+ //set output values (OUT)
+ usrp->set_gpio_attr(gpio, "OUT", out, mask);
+
+ //set ATR registers
+ usrp->set_gpio_attr(gpio, "ATR_0X", atr_idle, mask);
+ usrp->set_gpio_attr(gpio, "ATR_RX", atr_rx, mask);
+ usrp->set_gpio_attr(gpio, "ATR_TX", atr_tx, mask);
+ usrp->set_gpio_attr(gpio, "ATR_XX", atr_duplex, mask);
+
+ //set control register
+ usrp->set_gpio_attr(gpio, "CTRL", ctrl, mask);
+
+ //print out initial state of FP GPIO
+ std::cout << "\nConfigured GPIO values:" << std::endl;
+ output_reg_values(gpio, usrp, num_bits);
+ std::cout << std::endl;
+
+ //set up streams
+ uhd::stream_args_t rx_args(cpu, otw);
+ uhd::stream_args_t tx_args(cpu, otw);
+ uhd::rx_streamer::sptr rx_stream = usrp->get_rx_stream(rx_args);
+ uhd::tx_streamer::sptr tx_stream = usrp->get_tx_stream(tx_args);
+ uhd::stream_cmd_t rx_cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
+ rx_cmd.stream_now = true;
+ usrp->set_rx_rate(rx_rate);
+ usrp->set_tx_rate(tx_rate);
+
+ //set up buffers for tx and rx
+ const size_t max_samps_per_packet = rx_stream->get_max_num_samps();
+ const size_t nsamps_per_buff = max_samps_per_packet;
+ std::vector<char> rx_buff(max_samps_per_packet*uhd::convert::get_bytes_per_item(cpu));
+ std::vector<char> tx_buff(max_samps_per_packet*uhd::convert::get_bytes_per_item(cpu));
+ std::vector<void *> rx_buffs, tx_buffs;
+ for (size_t ch = 0; ch < rx_stream->get_num_channels(); ch++)
+ rx_buffs.push_back(&rx_buff.front()); //same buffer for each channel
+ for (size_t ch = 0; ch < tx_stream->get_num_channels(); ch++)
+ tx_buffs.push_back(&tx_buff.front()); //same buffer for each channel
+
+ uhd::rx_metadata_t rx_md;
+ uhd::tx_metadata_t tx_md;
+ tx_md.has_time_spec = false;
+ tx_md.start_of_burst = true;
+ uhd::time_spec_t stop_time;
+ double timeout = 0.01;
+ uhd::time_spec_t dwell_time(dwell);
+ int loop = 0;
+ boost::uint32_t rb, expected;
+
+ //register signal handler
+ std::signal(SIGINT, &sig_int_handler);
+
+ if (!vm.count("bitbang"))
+ {
+ // Test the mask parameter of the multi_usrp::set_gpio_attr API
+ // We only need to test once with no dwell time
+ std::cout << "\nTesting mask..." << std::flush;
+ //send a value of all 1's to the DDR with a mask for only upper most bit
+ usrp->set_gpio_attr(gpio, "DDR", ~0, GPIO_BIT(num_bits - 1));
+ //upper most bit should now be 1, but all the other bits should be unchanged
+ rb = usrp->get_gpio_attr(gpio, "DDR") & mask;
+ expected = ddr | GPIO_BIT(num_bits - 1);
+ if (rb == expected)
+ std::cout << "pass:" << std::endl;
+ else
+ std::cout << "fail:" << std::endl;
+ output_reg_values(gpio, usrp, num_bits);
+ //restore DDR value
+ usrp->set_gpio_attr(gpio, "DDR", ddr, mask);
+ }
+
+ while (not stop_signal_called)
+ {
+ int failures = 0;
+
+ if (vm.count("repeat"))
+ std::cout << "Press Ctrl + C to quit..." << std::endl;
+
+ if (vm.count("bitbang"))
+ {
+ // dwell and continuously read back GPIO values
+ stop_time = usrp->get_time_now() + dwell_time;
+ while (not stop_signal_called and usrp->get_time_now() < stop_time)
+ {
+ rb = usrp->get_gpio_attr(gpio, "READBACK");
+ std::cout << "\rREADBACK: " << to_bit_string(rb, num_bits);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(10));
+ }
+ std::cout << std::endl;
+ }
+ else
+ {
+ // test user controlled GPIO and ATR idle by setting bit 4 high for 1 second
+ std::cout << "\nTesting user controlled GPIO and ATR idle output..." << std::flush;
+ usrp->set_gpio_attr(gpio, "OUT", 1 << 4, 1 << 4);
+ stop_time = usrp->get_time_now() + dwell_time;
+ while (not stop_signal_called and usrp->get_time_now() < stop_time)
+ {
+ boost::this_thread::sleep(boost::posix_time::milliseconds(100));
+ }
+ rb = usrp->get_gpio_attr(gpio, "READBACK");
+ expected = GPIO_BIT(4) | GPIO_BIT(0);
+ if ((rb & expected) != expected)
+ {
+ ++failures;
+ std::cout << "fail:" << std::endl;
+ if ((rb & GPIO_BIT(0)) == 0)
+ std::cout << "Bit 0 should be set, but is not" << std::endl;
+ if ((rb & GPIO_BIT(4)) == 0)
+ std::cout << "Bit 4 should be set, but is not" << std::endl;
+ } else {
+ std::cout << "pass:" << std::endl;
+ }
+ output_reg_values(gpio, usrp, num_bits);
+ usrp->set_gpio_attr(gpio, "OUT", 0, GPIO_BIT(4));
+ if (stop_signal_called)
+ break;
+
+ // test ATR RX by receiving for 1 second
+ std::cout << "\nTesting ATR RX output..." << std::flush;
+ rx_cmd.stream_mode = uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS;
+ rx_stream->issue_stream_cmd(rx_cmd);
+ stop_time = usrp->get_time_now() + dwell_time;
+ while (not stop_signal_called and usrp->get_time_now() < stop_time)
+ {
+ try {
+ rx_stream->recv(rx_buffs, nsamps_per_buff, rx_md, timeout);
+ } catch(...){}
+ }
+ rb = usrp->get_gpio_attr(gpio, "READBACK");
+ expected = GPIO_BIT(1);
+ if ((rb & expected) != expected)
+ {
+ ++failures;
+ std::cout << "fail:" << std::endl;
+ std::cout << "Bit 1 should be set, but is not" << std::endl;
+ } else {
+ std::cout << "pass:" << std::endl;
+ }
+ output_reg_values(gpio, usrp, num_bits);
+ rx_stream->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
+ //clear out any data left in the rx stream
+ try {
+ rx_stream->recv(rx_buffs, nsamps_per_buff, rx_md, timeout);
+ } catch(...){}
+ if (stop_signal_called)
+ break;
+
+ // test ATR TX by transmitting for 1 second
+ std::cout << "\nTesting ATR TX output..." << std::flush;
+ stop_time = usrp->get_time_now() + dwell_time;
+ tx_md.start_of_burst = true;
+ tx_md.end_of_burst = false;
+ while (not stop_signal_called and usrp->get_time_now() < stop_time)
+ {
+ try {
+ tx_stream->send(tx_buffs, nsamps_per_buff, tx_md, timeout);
+ tx_md.start_of_burst = false;
+ } catch(...){}
+ }
+ rb = usrp->get_gpio_attr(gpio, "READBACK");
+ expected = GPIO_BIT(2);
+ if ((rb & expected) != expected)
+ {
+ ++failures;
+ std::cout << "fail:" << std::endl;
+ std::cout << "Bit 2 should be set, but is not" << std::endl;
+ } else {
+ std::cout << "pass:" << std::endl;
+ }
+ output_reg_values(gpio, usrp, num_bits);
+ tx_md.end_of_burst = true;
+ try {
+ tx_stream->send(tx_buffs, nsamps_per_buff, tx_md, timeout);
+ } catch(...){}
+ if (stop_signal_called)
+ break;
+
+ // test ATR RX by transmitting and receiving for 1 second
+ std::cout << "\nTesting ATR full duplex output..." << std::flush;
+ rx_cmd.stream_mode = uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS;
+ rx_stream->issue_stream_cmd(rx_cmd);
+ tx_md.start_of_burst = true;
+ tx_md.end_of_burst = false;
+ stop_time = usrp->get_time_now() + dwell_time;
+ while (not stop_signal_called and usrp->get_time_now() < stop_time)
+ {
+ try {
+ tx_stream->send(rx_buffs, nsamps_per_buff, tx_md, timeout);
+ tx_md.start_of_burst = false;
+ rx_stream->recv(tx_buffs, nsamps_per_buff, rx_md, timeout);
+ } catch(...){}
+ }
+ rb = usrp->get_gpio_attr(gpio, "READBACK");
+ expected = GPIO_BIT(3);
+ if ((rb & expected) != expected)
+ {
+ ++failures;
+ std::cout << "fail:" << std::endl;
+ std::cout << "Bit 3 should be set, but is not" << std::endl;
+ } else {
+ std::cout << "pass:" << std::endl;
+ }
+ output_reg_values(gpio, usrp, num_bits);
+ rx_stream->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
+ tx_md.end_of_burst = true;
+ try {
+ tx_stream->send(tx_buffs, nsamps_per_buff, tx_md, timeout);
+ } catch(...){}
+ //clear out any data left in the rx stream
+ try {
+ rx_stream->recv(rx_buffs, nsamps_per_buff, rx_md, timeout);
+ } catch(...){}
+
+ std::cout << std::endl;
+ if (failures)
+ std::cout << failures << " tests failed" << std::endl;
+ else
+ std::cout << "All tests passed!" << std::endl;
+ }
+
+ if (!vm.count("repeat"))
+ break;
+
+ if (not stop_signal_called)
+ std::cout << (boost::format("\nLoop %d completed") % ++loop) << std::endl;
+ }
+
+ //finished
+ std::cout << std::endl << "Done!" << std::endl << std::endl;
+
+ return EXIT_SUCCESS;
+}
diff --git a/host/examples/rx_samples_to_file.cpp b/host/examples/rx_samples_to_file.cpp
index 80b72de9c..934dce586 100644
--- a/host/examples/rx_samples_to_file.cpp
+++ b/host/examples/rx_samples_to_file.cpp
@@ -56,7 +56,7 @@ template<typename samp_type> void recv_to_file(
std::vector<samp_type> buff(samps_per_buff);
std::ofstream outfile;
if (not null)
- outfile.open(file.c_str(), std::ofstream::binary);
+ outfile.open(file.c_str(), std::ofstream::binary);
bool overflow_message = true;
//setup streaming
@@ -78,8 +78,8 @@ template<typename samp_type> void recv_to_file(
typedef std::map<size_t,size_t> SizeMap;
SizeMap mapSizes;
- while(not stop_signal_called and (num_requested_samples != num_total_samps or num_requested_samples == 0)){
- boost::system_time now = boost::get_system_time();
+ while(not stop_signal_called and (num_requested_samples != num_total_samps or num_requested_samples == 0)) {
+ boost::system_time now = boost::get_system_time();
size_t num_rx_samps = rx_stream->recv(&buff.front(), buff.size(), md, 3.0, enable_size_map);
@@ -88,7 +88,7 @@ template<typename samp_type> void recv_to_file(
break;
}
if (md.error_code == uhd::rx_metadata_t::ERROR_CODE_OVERFLOW){
- if (overflow_message){
+ if (overflow_message) {
overflow_message = false;
std::cerr << boost::format(
"Got an overflow indication. Please consider the following:\n"
@@ -110,99 +110,99 @@ template<typename samp_type> void recv_to_file(
throw std::runtime_error(error);
}
- if (enable_size_map){
- SizeMap::iterator it = mapSizes.find(num_rx_samps);
- if (it == mapSizes.end())
- mapSizes[num_rx_samps] = 0;
- mapSizes[num_rx_samps] += 1;
- }
+ if (enable_size_map) {
+ SizeMap::iterator it = mapSizes.find(num_rx_samps);
+ if (it == mapSizes.end())
+ mapSizes[num_rx_samps] = 0;
+ mapSizes[num_rx_samps] += 1;
+ }
num_total_samps += num_rx_samps;
- if (outfile.is_open())
- outfile.write((const char*)&buff.front(), num_rx_samps*sizeof(samp_type));
-
- if (bw_summary){
- last_update_samps += num_rx_samps;
- boost::posix_time::time_duration update_diff = now - last_update;
- if (update_diff.ticks() > boost::posix_time::time_duration::ticks_per_second()) {
- double t = (double)update_diff.ticks() / (double)boost::posix_time::time_duration::ticks_per_second();
- double r = (double)last_update_samps / t;
- std::cout << boost::format("\t%f Msps") % (r/1e6) << std::endl;
- last_update_samps = 0;
- last_update = now;
- }
- }
+ if (outfile.is_open())
+ outfile.write((const char*)&buff.front(), num_rx_samps*sizeof(samp_type));
+
+ if (bw_summary) {
+ last_update_samps += num_rx_samps;
+ boost::posix_time::time_duration update_diff = now - last_update;
+ if (update_diff.ticks() > boost::posix_time::time_duration::ticks_per_second()) {
+ double t = (double)update_diff.ticks() / (double)boost::posix_time::time_duration::ticks_per_second();
+ double r = (double)last_update_samps / t;
+ std::cout << boost::format("\t%f Msps") % (r/1e6) << std::endl;
+ last_update_samps = 0;
+ last_update = now;
+ }
+ }
ticks_diff = now - start;
- if (ticks_requested > 0){
- if ((unsigned long long)ticks_diff.ticks() > ticks_requested)
- break;
- }
+ if (ticks_requested > 0){
+ if ((unsigned long long)ticks_diff.ticks() > ticks_requested)
+ break;
+ }
}
stream_cmd.stream_mode = uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS;
rx_stream->issue_stream_cmd(stream_cmd);
if (outfile.is_open())
- outfile.close();
-
- if (stats){
- std::cout << std::endl;
-
- double t = (double)ticks_diff.ticks() / (double)boost::posix_time::time_duration::ticks_per_second();
- std::cout << boost::format("Received %d samples in %f seconds") % num_total_samps % t << std::endl;
- double r = (double)num_total_samps / t;
- std::cout << boost::format("%f Msps") % (r/1e6) << std::endl;
-
- if (enable_size_map) {
- std::cout << std::endl;
- std::cout << "Packet size map (bytes: count)" << std::endl;
- for (SizeMap::iterator it = mapSizes.begin(); it != mapSizes.end(); it++)
- std::cout << it->first << ":\t" << it->second << std::endl;
- }
- }
+ outfile.close();
+
+ if (stats) {
+ std::cout << std::endl;
+
+ double t = (double)ticks_diff.ticks() / (double)boost::posix_time::time_duration::ticks_per_second();
+ std::cout << boost::format("Received %d samples in %f seconds") % num_total_samps % t << std::endl;
+ double r = (double)num_total_samps / t;
+ std::cout << boost::format("%f Msps") % (r/1e6) << std::endl;
+
+ if (enable_size_map) {
+ std::cout << std::endl;
+ std::cout << "Packet size map (bytes: count)" << std::endl;
+ for (SizeMap::iterator it = mapSizes.begin(); it != mapSizes.end(); it++)
+ std::cout << it->first << ":\t" << it->second << std::endl;
+ }
+ }
}
typedef boost::function<uhd::sensor_value_t (const std::string&)> get_sensor_fn_t;
bool check_locked_sensor(std::vector<std::string> sensor_names, const char* sensor_name, get_sensor_fn_t get_sensor_fn, double setup_time){
- if (std::find(sensor_names.begin(), sensor_names.end(), sensor_name) == sensor_names.end())
- return false;
-
- boost::system_time start = boost::get_system_time();
- boost::system_time first_lock_time;
-
- std::cout << boost::format("Waiting for \"%s\": ") % sensor_name;
- std::cout.flush();
-
- while (true){
- if ((not first_lock_time.is_not_a_date_time()) and
- (boost::get_system_time() > (first_lock_time + boost::posix_time::seconds(setup_time))))
- {
- std::cout << " locked." << std::endl;
- break;
- }
- if (get_sensor_fn(sensor_name).to_bool()){
- if (first_lock_time.is_not_a_date_time())
- first_lock_time = boost::get_system_time();
- std::cout << "+";
- std::cout.flush();
- }
- else{
- first_lock_time = boost::system_time(); //reset to 'not a date time'
-
- if (boost::get_system_time() > (start + boost::posix_time::seconds(setup_time))){
- std::cout << std::endl;
- throw std::runtime_error(str(boost::format("timed out waiting for consecutive locks on sensor \"%s\"") % sensor_name));
- }
- std::cout << "_";
- std::cout.flush();
- }
- boost::this_thread::sleep(boost::posix_time::milliseconds(100));
- }
- std::cout << std::endl;
- return true;
+ if (std::find(sensor_names.begin(), sensor_names.end(), sensor_name) == sensor_names.end())
+ return false;
+
+ boost::system_time start = boost::get_system_time();
+ boost::system_time first_lock_time;
+
+ std::cout << boost::format("Waiting for \"%s\": ") % sensor_name;
+ std::cout.flush();
+
+ while (true) {
+ if ((not first_lock_time.is_not_a_date_time()) and
+ (boost::get_system_time() > (first_lock_time + boost::posix_time::seconds(setup_time))))
+ {
+ std::cout << " locked." << std::endl;
+ break;
+ }
+ if (get_sensor_fn(sensor_name).to_bool()){
+ if (first_lock_time.is_not_a_date_time())
+ first_lock_time = boost::get_system_time();
+ std::cout << "+";
+ std::cout.flush();
+ }
+ else {
+ first_lock_time = boost::system_time(); //reset to 'not a date time'
+
+ if (boost::get_system_time() > (start + boost::posix_time::seconds(setup_time))){
+ std::cout << std::endl;
+ throw std::runtime_error(str(boost::format("timed out waiting for consecutive locks on sensor \"%s\"") % sensor_name));
+ }
+ std::cout << "_";
+ std::cout.flush();
+ }
+ boost::this_thread::sleep(boost::posix_time::milliseconds(100));
+ }
+ std::cout << std::endl;
+ return true;
}
int UHD_SAFE_MAIN(int argc, char *argv[]){
@@ -246,8 +246,12 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
po::notify(vm);
//print the help message
- if (vm.count("help")){
+ if (vm.count("help")) {
std::cout << boost::format("UHD RX samples to file %s") % desc << std::endl;
+ std::cout
+ << std::endl
+ << "This application streams data from a single channel of a USRP device to a file.\n"
+ << std::endl;
return ~0;
}
@@ -258,7 +262,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
bool continue_on_bad_packet = vm.count("continue") > 0;
if (enable_size_map)
- std::cout << "Packet size tracking enabled - will only recv one packet at a time!" << std::endl;
+ std::cout << "Packet size tracking enabled - will only recv one packet at a time!" << std::endl;
//create a usrp device
std::cout << std::endl;
@@ -283,23 +287,23 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
std::cout << boost::format("Actual RX Rate: %f Msps...") % (usrp->get_rx_rate()/1e6) << std::endl << std::endl;
//set the center frequency
- if (vm.count("freq")){ //with default of 0.0 this will always be true
- std::cout << boost::format("Setting RX Freq: %f MHz...") % (freq/1e6) << std::endl;
+ if (vm.count("freq")) { //with default of 0.0 this will always be true
+ std::cout << boost::format("Setting RX Freq: %f MHz...") % (freq/1e6) << std::endl;
uhd::tune_request_t tune_request(freq);
if(vm.count("int-n")) tune_request.args = uhd::device_addr_t("mode_n=integer");
- usrp->set_rx_freq(tune_request);
- std::cout << boost::format("Actual RX Freq: %f MHz...") % (usrp->get_rx_freq()/1e6) << std::endl << std::endl;
- }
+ usrp->set_rx_freq(tune_request);
+ std::cout << boost::format("Actual RX Freq: %f MHz...") % (usrp->get_rx_freq()/1e6) << std::endl << std::endl;
+ }
//set the rf gain
- if (vm.count("gain")){
+ if (vm.count("gain")) {
std::cout << boost::format("Setting RX Gain: %f dB...") % gain << std::endl;
usrp->set_rx_gain(gain);
std::cout << boost::format("Actual RX Gain: %f dB...") % usrp->get_rx_gain() << std::endl << std::endl;
}
- //set the analog frontend filter bandwidth
- if (vm.count("bw")){
+ //set the IF filter bandwidth
+ if (vm.count("bw")) {
std::cout << boost::format("Setting RX Bandwidth: %f MHz...") % (bw/1e6) << std::endl;
usrp->set_rx_bandwidth(bw);
std::cout << boost::format("Actual RX Bandwidth: %f MHz...") % (usrp->get_rx_bandwidth()/1e6) << std::endl << std::endl;
@@ -312,12 +316,12 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
//check Ref and LO Lock detect
if (not vm.count("skip-lo")){
- check_locked_sensor(usrp->get_rx_sensor_names(0), "lo_locked", boost::bind(&uhd::usrp::multi_usrp::get_rx_sensor, usrp, _1, 0), setup_time);
- if (ref == "mimo")
- check_locked_sensor(usrp->get_mboard_sensor_names(0), "mimo_locked", boost::bind(&uhd::usrp::multi_usrp::get_mboard_sensor, usrp, _1, 0), setup_time);
- if (ref == "external")
- check_locked_sensor(usrp->get_mboard_sensor_names(0), "ref_locked", boost::bind(&uhd::usrp::multi_usrp::get_mboard_sensor, usrp, _1, 0), setup_time);
- }
+ check_locked_sensor(usrp->get_rx_sensor_names(0), "lo_locked", boost::bind(&uhd::usrp::multi_usrp::get_rx_sensor, usrp, _1, 0), setup_time);
+ if (ref == "mimo")
+ check_locked_sensor(usrp->get_mboard_sensor_names(0), "mimo_locked", boost::bind(&uhd::usrp::multi_usrp::get_mboard_sensor, usrp, _1, 0), setup_time);
+ if (ref == "external")
+ check_locked_sensor(usrp->get_mboard_sensor_names(0), "ref_locked", boost::bind(&uhd::usrp::multi_usrp::get_mboard_sensor, usrp, _1, 0), setup_time);
+ }
if (total_num_samps == 0){
std::signal(SIGINT, &sig_int_handler);
@@ -325,7 +329,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
}
#define recv_to_file_args(format) \
- (usrp, format, wirefmt, file, spb, total_num_samps, total_time, bw_summary, stats, null, enable_size_map, continue_on_bad_packet)
+ (usrp, format, wirefmt, file, spb, total_num_samps, total_time, bw_summary, stats, null, enable_size_map, continue_on_bad_packet)
//recv to file
if (type == "double") recv_to_file<std::complex<double> >recv_to_file_args("fc64");
else if (type == "float") recv_to_file<std::complex<float> >recv_to_file_args("fc32");
diff --git a/host/examples/rx_timed_samples.cpp b/host/examples/rx_timed_samples.cpp
index 30535907f..20abd92fe 100644
--- a/host/examples/rx_timed_samples.cpp
+++ b/host/examples/rx_timed_samples.cpp
@@ -48,7 +48,6 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
("rate", po::value<double>(&rate)->default_value(100e6/16), "rate of incoming samples")
("dilv", "specify to disable inner-loop verbose")
("channels", po::value<std::string>(&channel_list)->default_value("0"), "which channel(s) to use (specify \"0\", \"1\", \"0,1\", etc)")
-
;
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
diff --git a/host/examples/test_pps_input.cpp b/host/examples/test_pps_input.cpp
index 889c98a45..3e6c4ba9d 100644
--- a/host/examples/test_pps_input.cpp
+++ b/host/examples/test_pps_input.cpp
@@ -47,6 +47,11 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
//print the help message
if (vm.count("help")){
std::cout << boost::format("UHD Test PPS Input %s") % desc << std::endl;
+ std::cout
+ << std::endl
+ << "Tests if the PPS input signal is working. Will throw an error if not."
+ << std::endl
+ << std::endl;
return ~0;
}
diff --git a/host/examples/transport_hammer.cpp b/host/examples/transport_hammer.cpp
deleted file mode 100644
index 32e344e3e..000000000
--- a/host/examples/transport_hammer.cpp
+++ /dev/null
@@ -1,280 +0,0 @@
-//
-// Copyright 2012 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-//
-
-#include <uhd/utils/thread_priority.hpp>
-#include <uhd/convert.hpp>
-#include <uhd/utils/safe_main.hpp>
-#include <uhd/usrp/multi_usrp.hpp>
-#include <boost/program_options.hpp>
-#include <boost/format.hpp>
-#include <boost/thread/thread.hpp>
-#include <boost/math/special_functions/round.hpp>
-#include <iostream>
-#include <complex>
-
-namespace po = boost::program_options;
-
-/***********************************************************************
- * Test result variables
- **********************************************************************/
-unsigned long long num_overflows = 0;
-unsigned long long num_underflows = 0;
-unsigned long long num_rx_samps = 0;
-unsigned long long num_tx_samps = 0;
-unsigned long long num_dropped_samps = 0;
-unsigned long long num_seq_errors = 0;
-
-/***********************************************************************
- * RX Hammer
- **********************************************************************/
-void rx_hammer(uhd::usrp::multi_usrp::sptr usrp, const std::string &rx_cpu, uhd::rx_streamer::sptr rx_stream){
- uhd::set_thread_priority_safe();
-
- //print pre-test summary
- std::cout << boost::format(
- "Testing receive rate %f Msps"
- ) % (usrp->get_rx_rate()/1e6) << std::endl;
-
- //setup variables and allocate buffer
- uhd::rx_metadata_t md;
- const size_t max_samps_per_packet = rx_stream->get_max_num_samps();
- std::vector<char> buff(max_samps_per_packet*uhd::convert::get_bytes_per_item(rx_cpu));
- std::vector<void *> buffs;
- for (size_t ch = 0; ch < rx_stream->get_num_channels(); ch++)
- buffs.push_back(&buff.front()); //same buffer for each channel
- bool had_an_overflow = false;
- uhd::time_spec_t last_time;
- const double rate = usrp->get_rx_rate();
- double timeout = 1;
-
- uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE);
- cmd.time_spec = usrp->get_time_now() + uhd::time_spec_t(0.05);
- cmd.stream_now = (buffs.size() == 1);
- srand( time(NULL) );
-
- while (not boost::this_thread::interruption_requested()){
- cmd.num_samps = rand() % 100000;
- rx_stream->issue_stream_cmd(cmd);
- num_rx_samps += rx_stream->recv(buffs, max_samps_per_packet, md, timeout, true);
-
- //handle the error codes
- switch(md.error_code){
- case uhd::rx_metadata_t::ERROR_CODE_NONE:
- if (had_an_overflow){
- had_an_overflow = false;
- num_dropped_samps += boost::math::iround((md.time_spec - last_time).get_real_secs()*rate);
- }
- break;
-
- case uhd::rx_metadata_t::ERROR_CODE_OVERFLOW:
- had_an_overflow = true;
- last_time = md.time_spec;
- if (!md.out_of_sequence)
- num_overflows++;
- break;
-
- default:
- std::cerr << "Receiver error: " << md.strerror() << std::endl;
- std::cerr << "Unexpected error on recv, continuing..." << std::endl;
- break;
- }
- }
-}
-
-/***********************************************************************
- * TX Hammer
- **********************************************************************/
-void tx_hammer(uhd::usrp::multi_usrp::sptr usrp, const std::string &tx_cpu, uhd::tx_streamer::sptr tx_stream){
- uhd::set_thread_priority_safe();
-
- uhd::tx_metadata_t md;
- const size_t max_samps_per_packet = tx_stream->get_max_num_samps();
- std::vector<char> buff(max_samps_per_packet*uhd::convert::get_bytes_per_item(tx_cpu));
- std::vector<void *> buffs;
- for (size_t ch = 0; ch < tx_stream->get_num_channels(); ch++)
- buffs.push_back(&buff.front()); //same buffer for each channel
-
- //print pre-test summary
- std::cout << boost::format(
- "Testing transmit rate %f Msps"
- ) % (usrp->get_tx_rate()/1e6) << std::endl;
-
- //setup variables and allocate buffer
- std::srand( time(NULL) );
- while(not boost::this_thread::interruption_requested()){
- size_t total_num_samps = rand() % 100000;
- size_t num_acc_samps = 0;
- float timeout = 1;
-
- usrp->set_time_now(uhd::time_spec_t(0.0));
- while(num_acc_samps < total_num_samps){
-
- //send a single packet
- num_tx_samps += tx_stream->send(buffs, max_samps_per_packet, md, timeout);
-
- num_acc_samps += std::min(total_num_samps-num_acc_samps, tx_stream->get_max_num_samps());
- }
- //send a mini EOB packet
- md.end_of_burst = true;
- tx_stream->send("", 0, md);
- }
-}
-
-void tx_hammer_async_helper(uhd::tx_streamer::sptr tx_stream){
- //setup variables and allocate buffer
- uhd::async_metadata_t async_md;
-
- while (not boost::this_thread::interruption_requested()){
-
- if (not tx_stream->recv_async_msg(async_md)) continue;
-
- //handle the error codes
- switch(async_md.event_code){
- case uhd::async_metadata_t::EVENT_CODE_BURST_ACK:
- return;
-
- case uhd::async_metadata_t::EVENT_CODE_UNDERFLOW:
- case uhd::async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET:
- num_underflows++;
- break;
-
- case uhd::async_metadata_t::EVENT_CODE_SEQ_ERROR:
- case uhd::async_metadata_t::EVENT_CODE_SEQ_ERROR_IN_BURST:
- num_seq_errors++;
- break;
-
- default:
- std::cerr << "Event code: " << async_md.event_code << std::endl;
- std::cerr << "Unexpected event on async recv, continuing..." << std::endl;
- break;
- }
- }
-}
-
-/***********************************************************************
- * Main code + dispatcher
- **********************************************************************/
-int UHD_SAFE_MAIN(int argc, char *argv[]){
- uhd::set_thread_priority_safe();
-
- //variables to be set by po
- std::string args;
- double duration;
- double rx_rate, tx_rate;
- std::string rx_otw, tx_otw;
- std::string rx_cpu, tx_cpu;
- std::string mode;
-
- //setup the program options
- po::options_description desc("Allowed options");
- desc.add_options()
- ("help", "help message")
- ("args", po::value<std::string>(&args)->default_value(""), "single uhd device address args")
- ("duration", po::value<double>(&duration)->default_value(10.0), "if random, specify duration for the test in seconds")
- ("rx_rate", po::value<double>(&rx_rate), "specify to perform a RX rate test (sps)")
- ("tx_rate", po::value<double>(&tx_rate), "specify to perform a TX rate test (sps)")
- ("rx_otw", po::value<std::string>(&rx_otw)->default_value("sc16"), "specify the over-the-wire sample mode for RX")
- ("tx_otw", po::value<std::string>(&tx_otw)->default_value("sc16"), "specify the over-the-wire sample mode for TX")
- ("rx_cpu", po::value<std::string>(&rx_cpu)->default_value("fc32"), "specify the host/cpu sample mode for RX")
- ("tx_cpu", po::value<std::string>(&tx_cpu)->default_value("fc32"), "specify the host/cpu sample mode for TX")
- ("mode", po::value<std::string>(&mode)->default_value("none"), "multi-channel sync mode option: none, mimo")
- ;
- po::variables_map vm;
- po::store(po::parse_command_line(argc, argv, desc), vm);
- po::notify(vm);
-
- //print the help message
- if (vm.count("help") or (vm.count("rx_rate") + vm.count("tx_rate")) == 0){
- //std::cout << boost::format("UHD Transport Hammer - %s") % desc << std::endl;
- std::cout <<
- "UHD Transport Hammer: a transport layer stress test that continuously\n"
- "calls for random amounts of TX and RX samples\n\n";
- std::cout << desc << std::endl <<
- " Specify --rx_rate for a receive-only test.\n"
- " Specify --tx_rate for a transmit-only test.\n"
- " Specify both options for a full-duplex test.\n"
- << std::endl;
- return ~0;
- }
-
- //create a usrp device
- std::cout << std::endl;
- uhd::device_addrs_t device_addrs = uhd::device::find(args, uhd::device::USRP);
- if (not device_addrs.empty() and device_addrs.at(0).get("type", "") == "usrp1"){
- std::cerr << "*** Warning! ***" << std::endl;
- std::cerr << "Results will be inaccurate on USRP1 due to insufficient features.\n" << std::endl;
- }
- std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl;
- uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args);
- std::cout << boost::format("Using Device: %s") % usrp->get_pp_string() << std::endl;
-
- if (mode == "mimo"){
- usrp->set_clock_source("mimo", 0);
- usrp->set_time_source("mimo", 0);
- boost::this_thread::sleep(boost::posix_time::seconds(1));
- }
-
- boost::thread_group thread_group;
-
- //spawn the receive test thread
- if (vm.count("rx_rate")){
- usrp->set_rx_rate(rx_rate);
- //create a receive streamer
- uhd::stream_args_t stream_args(rx_cpu, rx_otw);
- for (size_t ch = 0; ch < usrp->get_num_mboards(); ch++) //linear channel mapping
- stream_args.channels.push_back(ch);
- uhd::rx_streamer::sptr rx_stream = usrp->get_rx_stream(stream_args);
- thread_group.create_thread(boost::bind(&rx_hammer, usrp, rx_cpu, rx_stream));
- }
-
- //spawn the transmit test thread
- if (vm.count("tx_rate")){
- usrp->set_tx_rate(tx_rate);
- //create a transmit streamer
- uhd::stream_args_t stream_args(tx_cpu, tx_otw);
- for (size_t ch = 0; ch < usrp->get_num_mboards(); ch++) //linear channel mapping
- stream_args.channels.push_back(ch);
- uhd::tx_streamer::sptr tx_stream = usrp->get_tx_stream(stream_args);
- thread_group.create_thread(boost::bind(&tx_hammer, usrp, tx_cpu, tx_stream));
- thread_group.create_thread(boost::bind(&tx_hammer_async_helper, tx_stream));
- }
-
- //sleep for the required duration
- const long secs = long(duration);
- const long usecs = long((duration - secs)*1e6);
- boost::this_thread::sleep(boost::posix_time::seconds(secs) + boost::posix_time::microseconds(usecs));
-
- //interrupt and join the threads
- thread_group.interrupt_all();
- thread_group.join_all();
-
- //print summary
- std::cout << std::endl << boost::format(
- "Transport Hammer summary:\n"
- " Num received samples: %u\n"
- " Num dropped samples: %u\n"
- " Num overflows detected: %u\n"
- " Num transmitted samples: %u\n"
- " Num sequence errors: %u\n"
- " Num underflows detected: %u\n"
- ) % num_rx_samps % num_dropped_samps % num_overflows % num_tx_samps % num_seq_errors % num_underflows << std::endl;
-
- //finished
- std::cout << std::endl << "Done!" << std::endl << std::endl;
-
- return EXIT_SUCCESS;
-}
diff --git a/host/examples/tx_bursts.cpp b/host/examples/tx_bursts.cpp
index fec89a0e4..bb71d4581 100644
--- a/host/examples/tx_bursts.cpp
+++ b/host/examples/tx_bursts.cpp
@@ -148,7 +148,6 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
size_t num_tx_samps = tx_stream->send(
buffs, samps_to_send, md, timeout
);
-
//do not use time spec for subsequent packets
md.has_time_spec = false;
md.start_of_burst = false;
diff --git a/host/examples/tx_waveforms.cpp b/host/examples/tx_waveforms.cpp
index 7e633262c..9254c3b24 100644
--- a/host/examples/tx_waveforms.cpp
+++ b/host/examples/tx_waveforms.cpp
@@ -15,6 +15,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
+#include "wavetable.hpp"
#include <uhd/utils/thread_priority.hpp>
#include <uhd/utils/safe_main.hpp>
#include <uhd/utils/static.hpp>
@@ -28,9 +29,7 @@
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include <iostream>
-#include <complex>
#include <csignal>
-#include <cmath>
namespace po = boost::program_options;
@@ -41,52 +40,6 @@ static bool stop_signal_called = false;
void sig_int_handler(int){stop_signal_called = true;}
/***********************************************************************
- * Waveform generators
- **********************************************************************/
-static const size_t wave_table_len = 8192;
-
-class wave_table_class{
-public:
- wave_table_class(const std::string &wave_type, const float ampl):
- _wave_table(wave_table_len)
- {
- //compute real wave table with 1.0 amplitude
- std::vector<double> real_wave_table(wave_table_len);
- if (wave_type == "CONST"){
- for (size_t i = 0; i < wave_table_len; i++)
- real_wave_table[i] = 1.0;
- }
- else if (wave_type == "SQUARE"){
- for (size_t i = 0; i < wave_table_len; i++)
- real_wave_table[i] = (i < wave_table_len/2)? 0.0 : 1.0;
- }
- else if (wave_type == "RAMP"){
- for (size_t i = 0; i < wave_table_len; i++)
- real_wave_table[i] = 2.0*i/(wave_table_len-1) - 1.0;
- }
- else if (wave_type == "SINE"){
- static const double tau = 2*std::acos(-1.0);
- for (size_t i = 0; i < wave_table_len; i++)
- real_wave_table[i] = std::sin((tau*i)/wave_table_len);
- }
- else throw std::runtime_error("unknown waveform type: " + wave_type);
-
- //compute i and q pairs with 90% offset and scale to amplitude
- for (size_t i = 0; i < wave_table_len; i++){
- const size_t q = (i+(3*wave_table_len)/4)%wave_table_len;
- _wave_table[i] = std::complex<float>(ampl*real_wave_table[i], ampl*real_wave_table[q]);
- }
- }
-
- inline std::complex<float> operator()(const size_t index) const{
- return _wave_table[index % wave_table_len];
- }
-
-private:
- std::vector<std::complex<float> > _wave_table;
-};
-
-/***********************************************************************
* Main function
**********************************************************************/
int UHD_SAFE_MAIN(int argc, char *argv[]){
diff --git a/host/examples/txrx_loopback_to_file.cpp b/host/examples/txrx_loopback_to_file.cpp
index efa23c410..7dc3bd9c2 100644
--- a/host/examples/txrx_loopback_to_file.cpp
+++ b/host/examples/txrx_loopback_to_file.cpp
@@ -15,6 +15,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
+#include "wavetable.hpp"
#include <uhd/types/tune_request.hpp>
#include <uhd/utils/thread_priority.hpp>
#include <uhd/utils/safe_main.hpp>
@@ -31,7 +32,6 @@
#include <iostream>
#include <fstream>
#include <csignal>
-#include <cmath>
namespace po = boost::program_options;
@@ -61,51 +61,6 @@ std::string generate_out_filename(const std::string &base_fn, size_t n_names, si
return base_fn_fp.string();
}
-/***********************************************************************
- * Waveform generators
- **********************************************************************/
-static const size_t wave_table_len = 8192;
-
-class wave_table_class{
-public:
- wave_table_class(const std::string &wave_type, const float ampl):
- _wave_table(wave_table_len)
- {
- //compute real wave table with 1.0 amplitude
- std::vector<double> real_wave_table(wave_table_len);
- if (wave_type == "CONST"){
- for (size_t i = 0; i < wave_table_len; i++)
- real_wave_table[i] = 1.0;
- }
- else if (wave_type == "SQUARE"){
- for (size_t i = 0; i < wave_table_len; i++)
- real_wave_table[i] = (i < wave_table_len/2)? 0.0 : 1.0;
- }
- else if (wave_type == "RAMP"){
- for (size_t i = 0; i < wave_table_len; i++)
- real_wave_table[i] = 2.0*i/(wave_table_len-1) - 1.0;
- }
- else if (wave_type == "SINE"){
- static const double tau = 2*std::acos(-1.0);
- for (size_t i = 0; i < wave_table_len; i++)
- real_wave_table[i] = std::sin((tau*i)/wave_table_len);
- }
- else throw std::runtime_error("unknown waveform type: " + wave_type);
-
- //compute i and q pairs with 90% offset and scale to amplitude
- for (size_t i = 0; i < wave_table_len; i++){
- const size_t q = (i+(3*wave_table_len)/4)%wave_table_len;
- _wave_table[i] = std::complex<float>(ampl*real_wave_table[i], ampl*real_wave_table[q]);
- }
- }
-
- inline std::complex<float> operator()(const size_t index) const{
- return _wave_table[index % wave_table_len];
- }
-
-private:
- std::vector<std::complex<float> > _wave_table;
-};
/***********************************************************************
* transmit_worker function
diff --git a/host/examples/wavetable.hpp b/host/examples/wavetable.hpp
new file mode 100644
index 000000000..d7ffc8406
--- /dev/null
+++ b/host/examples/wavetable.hpp
@@ -0,0 +1,66 @@
+//
+// Copyright 2010-2012,2014 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 <string>
+#include <cmath>
+#include <complex>
+#include <vector>
+#include <stdexcept>
+
+static const size_t wave_table_len = 8192;
+
+class wave_table_class{
+public:
+ wave_table_class(const std::string &wave_type, const float ampl):
+ _wave_table(wave_table_len)
+ {
+ //compute real wave table with 1.0 amplitude
+ std::vector<double> real_wave_table(wave_table_len);
+ if (wave_type == "CONST"){
+ for (size_t i = 0; i < wave_table_len; i++)
+ real_wave_table[i] = 1.0;
+ }
+ else if (wave_type == "SQUARE"){
+ for (size_t i = 0; i < wave_table_len; i++)
+ real_wave_table[i] = (i < wave_table_len/2)? 0.0 : 1.0;
+ }
+ else if (wave_type == "RAMP"){
+ for (size_t i = 0; i < wave_table_len; i++)
+ real_wave_table[i] = 2.0*i/(wave_table_len-1) - 1.0;
+ }
+ else if (wave_type == "SINE"){
+ static const double tau = 2*std::acos(-1.0);
+ for (size_t i = 0; i < wave_table_len; i++)
+ real_wave_table[i] = std::sin((tau*i)/wave_table_len);
+ }
+ else throw std::runtime_error("unknown waveform type: " + wave_type);
+
+ //compute i and q pairs with 90% offset and scale to amplitude
+ for (size_t i = 0; i < wave_table_len; i++){
+ const size_t q = (i+(3*wave_table_len)/4)%wave_table_len;
+ _wave_table[i] = std::complex<float>(ampl*real_wave_table[i], ampl*real_wave_table[q]);
+ }
+ }
+
+ inline std::complex<float> operator()(const size_t index) const{
+ return _wave_table[index % wave_table_len];
+ }
+
+private:
+ std::vector<std::complex<float> > _wave_table;
+};
+
diff --git a/host/include/uhd/config.hpp b/host/include/uhd/config.hpp
index 7ecc4924a..23eb9cdb2 100644
--- a/host/include/uhd/config.hpp
+++ b/host/include/uhd/config.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2011 Ettus Research LLC
+// Copyright 2010-2011,2014 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
@@ -56,6 +56,13 @@ typedef ptrdiff_t ssize_t;
#define UHD_DEPRECATED __declspec(deprecated)
#define UHD_ALIGNED(x) __declspec(align(x))
#define UHD_UNUSED(x) x
+#elif defined(__MINGW32__)
+ #define UHD_EXPORT __declspec(dllexport)
+ #define UHD_IMPORT __declspec(dllimport)
+ #define UHD_INLINE inline
+ #define UHD_DEPRECATED __declspec(deprecated)
+ #define UHD_ALIGNED(x) __declspec(align(x))
+ #define UHD_UNUSED(x) x
#elif defined(__GNUG__) && __GNUG__ >= 4
#define UHD_EXPORT __attribute__((visibility("default")))
#define UHD_IMPORT __attribute__((visibility("default")))
diff --git a/host/include/uhd/convert.hpp b/host/include/uhd/convert.hpp
index d740d80fb..e42123b20 100644
--- a/host/include/uhd/convert.hpp
+++ b/host/include/uhd/convert.hpp
@@ -63,12 +63,13 @@ namespace uhd{ namespace convert{
typedef int priority_type;
//! Identify a conversion routine in the registry
- struct id_type : boost::equality_comparable<id_type>{
+ struct UHD_API id_type : boost::equality_comparable<id_type>{
std::string input_format;
size_t num_inputs;
std::string output_format;
size_t num_outputs;
std::string to_pp_string(void) const;
+ std::string to_string(void) const;
};
//! Implement equality_comparable interface
diff --git a/host/include/uhd/transport/CMakeLists.txt b/host/include/uhd/transport/CMakeLists.txt
index 2118674c6..623c179e9 100644
--- a/host/include/uhd/transport/CMakeLists.txt
+++ b/host/include/uhd/transport/CMakeLists.txt
@@ -1,5 +1,5 @@
#
-# Copyright 2010-2013 Ettus Research LLC
+# Copyright 2010-2014 Ettus Research LLC
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -15,11 +15,11 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
-
UHD_INSTALL(FILES
bounded_buffer.hpp
bounded_buffer.ipp
buffer_pool.hpp
+ chdr.hpp
if_addrs.hpp
udp_constants.hpp
udp_simple.hpp
diff --git a/host/include/uhd/transport/chdr.hpp b/host/include/uhd/transport/chdr.hpp
new file mode 100644
index 000000000..5e8cd58a9
--- /dev/null
+++ b/host/include/uhd/transport/chdr.hpp
@@ -0,0 +1,113 @@
+//
+// Copyright 2014 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_TRANSPORT_CHDR_HPP
+#define INCLUDED_UHD_TRANSPORT_CHDR_HPP
+
+#include <uhd/transport/vrt_if_packet.hpp>
+
+namespace uhd{ namespace transport{ namespace vrt{
+
+/*! \brief CVITA/CHDR related function
+ *
+ * See \ref rtp_chdr for details on the CVITA/CHDR protocol.
+ *
+ * All packers take the host format into account. Choose the _le functions
+ * if the transport uses little endian format (e.g. PCIe) and the _be
+ * functions if the transport uses big endian format (e.g. Ethernet).
+ *
+ * Note 1: All packers assume there to be enough space at the address
+ * provided by \p packet_buff. See also \ref vrt_pack_contract.
+ *
+ * Note 2: All these packers assume the following options without checking them:
+ * - `if_packet_info.link_type == LINK_TYPE_CHDR`
+ * - `if_packet_info.has_cid == false`
+ * - `if_packet_info.has_sid == true`
+ * - `if_packet_info.has_tsi == false`
+ * - `if_packet_info.has_tlr == false`
+ * This relaxes some of \ref vrt_pack_contract, but adds the additional
+ * constraint that the input data must be CHDR.
+ *
+ * In the unpacker, these values will be set accordingly.
+ */
+namespace chdr{
+
+ //! The maximum number of 64-bit words in a CVITA header
+ static const size_t max_if_hdr_words64 = 2; // CHDR + tsf (fractional timestamp)
+
+ /*!
+ * Pack a CHDR header from metadata (big endian format).
+ *
+ * See \ref vrt_pack_contract, but `link_type` is assumed to be
+ * `LINK_TYPE_CHDR`.
+ *
+ * \param packet_buff memory to write the packed vrt header
+ * \param if_packet_info the if packet info (read/write)
+ */
+ UHD_API void if_hdr_pack_be(
+ boost::uint32_t *packet_buff,
+ if_packet_info_t &if_packet_info
+ );
+
+ /*!
+ * Unpack a CHDR header to metadata (big endian format).
+ *
+ * See \ref vrt_unpack_contract, but `link_type` is assumed to be
+ * `LINK_TYPE_CHDR`.
+ *
+ * \param packet_buff memory to read the packed vrt header
+ * \param if_packet_info the if packet info (read/write)
+ */
+ UHD_API void if_hdr_unpack_be(
+ const boost::uint32_t *packet_buff,
+ if_packet_info_t &if_packet_info
+ );
+
+ /*!
+ * Pack a CHDR header from metadata (little endian format).
+ *
+ * See \ref vrt_pack_contract, but `link_type` is assumed to be
+ * `LINK_TYPE_CHDR`.
+ *
+ * \param packet_buff memory to write the packed vrt header
+ * \param if_packet_info the if packet info (read/write)
+ */
+ UHD_API void if_hdr_pack_le(
+ boost::uint32_t *packet_buff,
+ if_packet_info_t &if_packet_info
+ );
+
+ /*!
+ * Unpack a CHDR header to metadata (little endian format).
+ *
+ * See \ref vrt_unpack_contract, but `link_type` is assumed to be
+ * `LINK_TYPE_CHDR`.
+ *
+ * \param packet_buff memory to read the packed vrt header
+ * \param if_packet_info the if packet info (read/write)
+ */
+ UHD_API void if_hdr_unpack_le(
+ const boost::uint32_t *packet_buff,
+ if_packet_info_t &if_packet_info
+ );
+
+} //namespace chdr
+
+}}} //namespace uhd::transport::vrt
+
+#endif /* INCLUDED_UHD_TRANSPORT_CHDR_HPP */
+
diff --git a/host/include/uhd/transport/nirio/nirio_driver_iface.h b/host/include/uhd/transport/nirio/nirio_driver_iface.h
index 83afd816a..3e0e56a7f 100644
--- a/host/include/uhd/transport/nirio/nirio_driver_iface.h
+++ b/host/include/uhd/transport/nirio/nirio_driver_iface.h
@@ -24,9 +24,9 @@
#include <uhd/transport/nirio/status.h>
#include <uhd/config.hpp>
#if defined(UHD_PLATFORM_WIN32)
- #include <Windows.h>
+ #include <windows.h>
#pragma warning(disable:4201) // nonstandard extension used : nameless struct/union
- #include <WinIoCtl.h>
+ #include <winioctl.h>
#pragma warning(default:4201)
#elif !defined(UHD_PLATFORM_LINUX)
#include <IOKit/IOKitLib.h>
diff --git a/host/include/uhd/transport/nirio/nirio_fifo.h b/host/include/uhd/transport/nirio/nirio_fifo.h
index c424275fc..5a2e29631 100644
--- a/host/include/uhd/transport/nirio/nirio_fifo.h
+++ b/host/include/uhd/transport/nirio/nirio_fifo.h
@@ -59,8 +59,8 @@ public:
inline const std::string& get_name() const { return _name; }
inline uint32_t get_channel() const { return _fifo_channel; }
- inline uint32_t get_direction() const { return _fifo_direction; }
- inline uint32_t get_scalar_type() const { return _datatype_info.scalar_type; }
+ inline fifo_direction_t get_direction() const { return _fifo_direction; }
+ inline nirio_scalar_type_t get_scalar_type() const { return _datatype_info.scalar_type; }
nirio_status start();
diff --git a/host/include/uhd/transport/usb_device_handle.hpp b/host/include/uhd/transport/usb_device_handle.hpp
index fdea9e2be..bf122f549 100644
--- a/host/include/uhd/transport/usb_device_handle.hpp
+++ b/host/include/uhd/transport/usb_device_handle.hpp
@@ -41,6 +41,7 @@ namespace uhd { namespace transport {
class UHD_API usb_device_handle : boost::noncopyable {
public:
typedef boost::shared_ptr<usb_device_handle> sptr;
+ typedef std::pair<boost::uint16_t, boost::uint16_t> vid_pid_pair_t;
/*!
* Return the device's serial number
@@ -83,6 +84,8 @@ public:
* \return a vector of USB device handles that match vid and pid
*/
static std::vector<usb_device_handle::sptr> get_device_list(boost::uint16_t vid, boost::uint16_t pid);
+ static std::vector<usb_device_handle::sptr> get_device_list(const std::vector<usb_device_handle::vid_pid_pair_t>& vid_pid_pair_list);
+
}; //namespace usb
diff --git a/host/include/uhd/transport/vrt_if_packet.hpp b/host/include/uhd/transport/vrt_if_packet.hpp
index 362531567..1e54607c1 100644
--- a/host/include/uhd/transport/vrt_if_packet.hpp
+++ b/host/include/uhd/transport/vrt_if_packet.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2013 Ettus Research LLC
+// Copyright 2010-2014 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
@@ -52,9 +52,18 @@ namespace vrt{
//packet type
enum packet_type_t
{
+ // VRT language:
PACKET_TYPE_DATA = 0x0,
PACKET_TYPE_IF_EXT = 0x1,
- PACKET_TYPE_CONTEXT = 0x2 //extension context: has_sid = true
+ PACKET_TYPE_CONTEXT = 0x2, //extension context: has_sid = true
+
+ // CVITA language:
+ //PACKET_TYPE_DATA = 0x0, // Data
+ PACKET_TYPE_FC = 0x1, // Flow control
+ PACKET_TYPE_ACK = 0x1, // Flow control (ack)
+ PACKET_TYPE_CMD = 0x2, // Command
+ PACKET_TYPE_RESP = 0x3, // Command response
+ PACKET_TYPE_ERROR = 0x3 // Command response: Error (the EOB bit is raised in this case)
} packet_type;
//size fields
@@ -65,18 +74,46 @@ namespace vrt{
//header fields
size_t packet_count;
+ //! Asserted for start- or end-of-burst
bool sob, eob;
+ //! This is asserted for command responses that are errors (CHDR only)
+ bool error;
//optional fields
+ //! Stream ID (SID). See uhd::sid_t
bool has_sid; boost::uint32_t sid;
+ //! Class ID.
bool has_cid; boost::uint64_t cid;
+ //! Integer timestamp
bool has_tsi; boost::uint32_t tsi;
+ //! Fractional timestamp
bool has_tsf; boost::uint64_t tsf;
+ //! Trailer
bool has_tlr; boost::uint32_t tlr;
};
/*!
* Pack a vrt header from metadata (big endian format).
+ *
+ * \section vrt_pack_contract Packing contract
+ *
+ * \subsection Requirements:
+ * - packet_buff points to a valid address space with enough space to write
+ * the entire buffer, regardless of its length. At the very least, it must
+ * be able to hold an entire header.
+ * - `if_packet_info` has the following members set to correct values:
+ * - `has_*` members all set accordingly
+ * - For every true `has_*` member, the corresponding variable holds a valid
+ * value (e.g. if `has_sid` is true, `sid` contains a valid SID)
+ * - `num_payload_bytes` and `num_payload_words32` are both set to the correct values
+ *
+ * \subsection Result:
+ * - `packet_buff` now points to a valid header that can be sent over the transport
+ * without further modification
+ * - The following members on `if_packet_info` are set:
+ * - `num_header_words32`
+ * - `num_packet_words32`
+ *
* \param packet_buff memory to write the packed vrt header
* \param if_packet_info the if packet info (read/write)
*/
@@ -87,6 +124,34 @@ namespace vrt{
/*!
* Unpack a vrt header to metadata (big endian format).
+ *
+ * \section vrt_unpack_contract Unpacking contract
+ *
+ * \subsection Requirements
+ * - `packet_buff` points to a readable address space with a
+ * CHDR packet, starting at the header. `packet_buff[0]` *must* always
+ * point to a valid first word of the header. This implies that num_packet_words32
+ * must be at least 1.
+ * - `if_packet_info` has the following members set to correct values:
+ * - `num_packet_words32`. This means all values `packet_buff[0]`
+ * through `packet_buff[if_packet_info.num_packet_words32-1]` are
+ * readable words from this packet.
+ * - `link_type`
+ *
+ * \subsection Result
+ * - `if_packet_info` now has the following values set to correct values:
+ * - `packet_type`
+ * - `num_payload_bytes`
+ * - `num_payload_words32`
+ * - `num_header_words32`
+ * - `has_*`
+ * - `sob`, `eob`, `error`, `cid`, `sid` (if applicable)
+ * - `tsf`, `tsi` (if applicable)
+ *
+ * \subsection Exceptions
+ * - If the header is invalid, but the requirements are still met,
+ * will throw a uhd::value_error.
+ *
* \param packet_buff memory to read the packed vrt header
* \param if_packet_info the if packet info (read/write)
*/
@@ -97,6 +162,9 @@ namespace vrt{
/*!
* Pack a vrt header from metadata (little endian format).
+ *
+ * See \ref vrt_pack_contract.
+ *
* \param packet_buff memory to write the packed vrt header
* \param if_packet_info the if packet info (read/write)
*/
@@ -107,6 +175,9 @@ namespace vrt{
/*!
* Unpack a vrt header to metadata (little endian format).
+ *
+ * See \ref vrt_unpack_contract.
+ *
* \param packet_buff memory to read the packed vrt header
* \param if_packet_info the if packet info (read/write)
*/
@@ -124,6 +195,7 @@ namespace vrt{
num_packet_words32(0),
packet_count(0),
sob(false), eob(false),
+ error(false),
has_sid(false), sid(0),
has_cid(false), cid(0),
has_tsi(false), tsi(0),
diff --git a/host/include/uhd/types/CMakeLists.txt b/host/include/uhd/types/CMakeLists.txt
index 8bb1de381..b82c2b7f2 100644
--- a/host/include/uhd/types/CMakeLists.txt
+++ b/host/include/uhd/types/CMakeLists.txt
@@ -31,11 +31,13 @@ UHD_INSTALL(FILES
ref_vector.hpp
sensors.hpp
serial.hpp
+ sid.hpp
stream_cmd.hpp
time_spec.hpp
tune_request.hpp
tune_result.hpp
wb_iface.hpp
+ filters.hpp
DESTINATION ${INCLUDE_DIR}/uhd/types
COMPONENT headers
)
diff --git a/host/include/uhd/types/dict.hpp b/host/include/uhd/types/dict.hpp
index 97fa8f09c..51e3e1814 100644
--- a/host/include/uhd/types/dict.hpp
+++ b/host/include/uhd/types/dict.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2011 Ettus Research LLC
+// Copyright 2010-2011,2015 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -117,6 +117,23 @@ namespace uhd{
*/
Val pop(const Key &key);
+ /*! Update this dictionary with values from another.
+ *
+ * Basically, this copies all the key/value pairs from \p new_dict
+ * into this dict. When the key is already present in the current
+ * dict, it either overwrites the current value (if \p fail_on_conflict
+ * is false) or it throws (if \p fail_on_conflict is true *and* the
+ * values differ).
+ *
+ * With the exception of \p fail_on_conflict, this behaves analogously
+ * to Python's dict.update() method.
+ *
+ * \param new_args The arguments to copy.
+ * \param fail_on_conflict If true, throws.
+ * \throws uhd::value_error
+ */
+ void update(const dict<Key, Val> &new_dict, bool fail_on_conflict=true);
+
private:
typedef std::pair<Key, Val> pair_t;
std::list<pair_t> _map; //private container
diff --git a/host/include/uhd/types/dict.ipp b/host/include/uhd/types/dict.ipp
index 5e9cf97ad..5fd4b536e 100644
--- a/host/include/uhd/types/dict.ipp
+++ b/host/include/uhd/types/dict.ipp
@@ -135,6 +135,20 @@ namespace uhd{
throw key_not_found<Key, Val>(key);
}
+ template <typename Key, typename Val>
+ void dict<Key, Val>::update(const dict<Key, Val> &new_dict, bool fail_on_conflict)
+ {
+ BOOST_FOREACH(const Key &key, new_dict.keys()) {
+ if (fail_on_conflict and has_key(key) and get(key) != new_dict[key]) {
+ throw uhd::value_error(str(
+ boost::format("Option merge conflict: %s:%s != %s:%s")
+ % key % get(key) % key % new_dict[key]
+ ));
+ }
+ set(key, new_dict[key]);
+ }
+ }
+
} //namespace uhd
#endif /* INCLUDED_UHD_TYPES_DICT_IPP */
diff --git a/host/include/uhd/types/direction.hpp b/host/include/uhd/types/direction.hpp
index 0f257de44..59ee9b55f 100644
--- a/host/include/uhd/types/direction.hpp
+++ b/host/include/uhd/types/direction.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2015 Ettus Research LLC
+// Copyright 2014-2015 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
diff --git a/host/include/uhd/types/filters.hpp b/host/include/uhd/types/filters.hpp
new file mode 100644
index 000000000..976ae233d
--- /dev/null
+++ b/host/include/uhd/types/filters.hpp
@@ -0,0 +1,286 @@
+//
+// Copyright 2015 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_UHD_TYPES_FILTERS_HPP
+#define INCLUDED_UHD_TYPES_FILTERS_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/utils/log.hpp>
+#include <uhd/utils/msg.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/scoped_array.hpp>
+#include <string>
+#include <vector>
+#include <iostream>
+#include <ostream>
+#include <sstream>
+
+namespace uhd{
+
+ class UHD_API filter_info_base
+ {
+ public:
+ typedef boost::shared_ptr<filter_info_base> sptr;
+ enum filter_type
+ {
+ ANALOG_LOW_PASS,
+ ANALOG_BAND_PASS,
+ DIGITAL_I16,
+ DIGITAL_FIR_I16
+ };
+
+ filter_info_base(
+ filter_type type,
+ bool bypass,
+ size_t position_index
+ ):
+ _type(type), _bypass(bypass),
+ _position_index(position_index)
+ {
+ //NOP
+ }
+
+ inline virtual bool is_bypassed()
+ {
+ return _bypass;
+ }
+
+ inline filter_type get_type()
+ {
+ return _type;
+ }
+
+ virtual ~filter_info_base()
+ {
+ //NOP
+ }
+
+ virtual std::string to_pp_string();
+
+ protected:
+ filter_type _type;
+ bool _bypass;
+ size_t _position_index;
+
+ };
+
+ UHD_API std::ostream& operator<<(std::ostream& os, filter_info_base& f);
+
+ class UHD_API analog_filter_base : public filter_info_base
+ {
+ std::string _analog_type;
+ public:
+ typedef boost::shared_ptr<analog_filter_base> sptr;
+ analog_filter_base(
+ filter_type type,
+ bool bypass,
+ size_t position_index,
+ const std::string& analog_type
+ ):
+ filter_info_base(type, bypass, position_index),
+ _analog_type(analog_type)
+ {
+ //NOP
+ }
+
+ inline const std::string& get_analog_type()
+ {
+ return _analog_type;
+ }
+
+ virtual std::string to_pp_string();
+ };
+
+ class UHD_API analog_filter_lp : public analog_filter_base
+ {
+ double _cutoff;
+ double _rolloff;
+
+ public:
+ typedef boost::shared_ptr<analog_filter_lp> sptr;
+ analog_filter_lp(
+ filter_type type,
+ bool bypass,
+ size_t position_index,
+ const std::string& analog_type,
+ double cutoff,
+ double rolloff
+ ):
+ analog_filter_base(type, bypass, position_index, analog_type),
+ _cutoff(cutoff),
+ _rolloff(rolloff)
+ {
+ //NOP
+ }
+
+ inline double get_cutoff()
+ {
+ return _cutoff;
+ }
+
+ inline double get_rolloff()
+ {
+ return _cutoff;
+ }
+
+ inline void set_cutoff(const double cutoff)
+ {
+ _cutoff = cutoff;
+ }
+
+ virtual std::string to_pp_string();
+ };
+
+ template<typename tap_t>
+ class UHD_API digital_filter_base : public filter_info_base
+ {
+ protected:
+ double _rate;
+ boost::uint32_t _interpolation;
+ boost::uint32_t _decimation;
+ tap_t _tap_full_scale;
+ boost::uint32_t _max_num_taps;
+ std::vector<tap_t> _taps;
+
+ public:
+ typedef boost::shared_ptr<digital_filter_base> sptr;
+ digital_filter_base(
+ filter_type type,
+ bool bypass,
+ size_t position_index,
+ double rate,
+ size_t interpolation,
+ size_t decimation,
+ double tap_full_scale,
+ size_t max_num_taps,
+ const std::vector<tap_t>& taps
+ ):
+ filter_info_base(type, bypass, position_index),
+ _rate(rate),
+ _interpolation(interpolation),
+ _decimation(decimation),
+ _tap_full_scale(tap_full_scale),
+ _max_num_taps(max_num_taps),
+ _taps(taps)
+ {
+ //NOP
+ }
+
+ inline double get_output_rate()
+ {
+ return (_bypass ? _rate : (_rate / _decimation * _interpolation));
+ }
+
+ inline double get_input_rate()
+ {
+ return _rate;
+ }
+
+ inline double get_interpolation()
+ {
+ return _interpolation;
+ }
+
+ inline double get_decimation()
+ {
+ return _decimation;
+ }
+
+ inline double get_tap_full_scale()
+ {
+ return _tap_full_scale;
+ }
+
+ inline std::vector<tap_t>& get_taps()
+ {
+ return _taps;
+ }
+
+ virtual std::string to_pp_string()
+ {
+ std::ostringstream os;
+ os<<filter_info_base::to_pp_string()<<
+ "\t[digital_filter_base]"<<std::endl<<
+ "\tinput rate: "<<_rate<<std::endl<<
+ "\tinterpolation: "<<_interpolation<<std::endl<<
+ "\tdecimation: "<<_decimation<<std::endl<<
+ "\tfull-scale: "<<_tap_full_scale<<std::endl<<
+ "\tmax num taps: "<<_max_num_taps<<std::endl<<
+ "\ttaps: "<<std::endl;
+
+ os<<"\t\t";
+ for(size_t i = 0; i < _taps.size(); i++)
+ {
+ os<<"(tap "<<i<<": "<<_taps[i]<<")";
+ if( ((i%10) == 0) && (i != 0))
+ {
+ os<<std::endl<<"\t\t";
+ }
+ }
+ os<<std::endl;
+ return std::string(os.str());
+ }
+
+ };
+
+ template<typename tap_t>
+ class UHD_API digital_filter_fir : public digital_filter_base<tap_t>
+ {
+ public:
+ typedef boost::shared_ptr<digital_filter_fir<tap_t> > sptr;
+
+ digital_filter_fir(
+ filter_info_base::filter_type type,
+ bool bypass, size_t position_index,
+ double rate,
+ size_t interpolation,
+ size_t decimation,
+ size_t tap_bit_width,
+ size_t max_num_taps,
+ const std::vector<tap_t>& taps
+ ):
+ digital_filter_base<tap_t>(type, bypass, position_index, rate, interpolation, decimation, tap_bit_width, max_num_taps, taps)
+ {
+ //NOP
+ }
+
+ void set_taps(const std::vector<tap_t>& taps)
+ {
+ std::size_t num_taps = taps.size();
+ if(num_taps < this->_max_num_taps){
+ UHD_MSG(warning) << "digital_filter_fir::set_taps not enough coefficients. Appending zeros";
+ std::vector<tap_t> coeffs;
+ for (size_t i = 0; i < this->_max_num_taps; i++)
+ {
+ if(i < num_taps)
+ {
+ coeffs.push_back(taps[i]);
+ } else {
+ coeffs.push_back(0);
+ }
+ }
+ this->_taps = coeffs;
+ } else {
+ this->_taps = taps;
+ }
+ }
+ };
+
+} //namespace uhd
+
+#endif /* INCLUDED_UHD_TYPES_FILTERS_HPP */
diff --git a/host/include/uhd/types/sid.hpp b/host/include/uhd/types/sid.hpp
new file mode 100644
index 000000000..95034c7a5
--- /dev/null
+++ b/host/include/uhd/types/sid.hpp
@@ -0,0 +1,238 @@
+//
+// Copyright 2014 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_UHD_TYPES_SID_HPP
+#define INCLUDED_UHD_TYPES_SID_HPP
+
+#include <uhd/config.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/shared_ptr.hpp>
+#include <iostream>
+
+namespace uhd {
+ /*!
+ * \brief Represents a stream ID (SID).
+ *
+ * A stream ID (SID) is an identifier for data.
+ * It is a 32-Bit value which consistst of 16 Bits
+ * for the source address and 16 Bits for the destination
+ * address.
+ * Every address is split into two parts: The _address_, which
+ * identifies the device used, and the _endpoint_, which identifies
+ * a specific object inside the given device (e.g., a block).
+ * *Note:* In the case where there are several crossbars on a single
+ * device, each crossbar gets its own address.
+ * Both address and endpoint are 8 bits in length. If a 16-bit address
+ * is required, we use the combination of the 8-bit address and the 8-bit
+ * endpoint.
+ *
+ * \section sid_str_repr String Representation
+ *
+ * The string representation of a SID is of the form
+ *
+ * 2.3>0.6
+ *
+ * The '>' symbol shows the direction, so in this case,
+ * data is flowing from address 2.3 to 0.6.
+ *
+ * As a convention, ':' is used instead of '.' when giving the
+ * SID in hexadecimal numbers, and two characters are used for each
+ * address part. As an example, the following two SIDs are identical:
+ *
+ * 2.3>0.16 (decimal)
+ * 02:03>00:10 (hexadecimal)
+ *
+ * The format is:
+ * SRC_ADDRESS.SRC_ENDPOINT>DST_ADDRESS.DST_ENDPOINT
+ *
+ *
+ * \section sid_block_ports Block Ports
+ *
+ * In the special case where a block on a crossbar is addressed, the
+ * endpoint is further split up into two parts of four bits each: The
+ * first four bits specify the port number on the crossbar, whereas the
+ * lower four bits represent the *block port*. As an example, consider
+ * the following SID, given in hexadecimal:
+ *
+ * 00:10>02:A1
+ *
+ * In this example, assume data is flowing from the host computer to an
+ * X300. The crossbar address is 02. The endpoint is A1, which means we
+ * are accessing a block on crossbar port A (the tenth port), and are addressing
+ * block port 1.
+ *
+ */
+ class UHD_API sid_t
+ {
+ public:
+ //! Create an unset SID
+ sid_t();
+ //! Create a sid_t object from a 32-Bit SID value
+ sid_t(boost::uint32_t sid);
+ //! Create a sid_t object from its four components
+ sid_t(boost::uint8_t src_addr, boost::uint8_t src_ep, boost::uint8_t dst_addr, boost::uint8_t dst_ep);
+ //! Convert a string representation of a SID into its numerical representation
+ sid_t(const std::string &);
+
+ //! Return a decimal string representation of the SID.
+ std::string to_pp_string() const;
+ //! Return a hexadecimal string representation of the SID.
+ std::string to_pp_string_hex() const;
+
+ //! Returns true if this actually holds a valid SID
+ bool is_set() const { return _set; };
+
+ // Getters
+ //
+ //! Alias for get_sid()
+ UHD_INLINE boost::uint32_t get() const { return get_sid(); };
+ //! Returns a 32-Bit representation of the SID if set, or zero otherwise.
+ UHD_INLINE boost::uint32_t get_sid() const { return _set ? _sid : 0; };
+ //! Return the 16-bit source address of this SID
+ UHD_INLINE boost::uint32_t get_src() const {
+ return (_sid >> 16) & 0xFFFF;
+ }
+ //! Return the 16-bit destination address of this SID
+ UHD_INLINE boost::uint32_t get_dst() const {
+ return _sid & 0xFFFF;
+ }
+ //! Return 8-bit address of the source
+ UHD_INLINE boost::uint32_t get_src_addr() const {
+ return (get_src() >> 8) & 0xFF;
+ }
+ //! Return endpoint of the source
+ UHD_INLINE boost::uint32_t get_src_endpoint() const {
+ return get_src() & 0xFF;
+ }
+ //! Return crossbar port of the source
+ UHD_INLINE boost::uint32_t get_src_xbarport() const {
+ return (get_src_endpoint() >> 4) & 0xF;
+ }
+ //! Return block port of the source
+ UHD_INLINE boost::uint32_t get_src_blockport() const {
+ return (get_src_endpoint()) & 0xF;
+ }
+ //! Return 8-bit address of the destination
+ UHD_INLINE boost::uint32_t get_dst_addr() const {
+ return (get_dst() >> 8) & 0xFF;
+ }
+ //! Return endpoint of the destination
+ UHD_INLINE boost::uint32_t get_dst_endpoint() const {
+ return get_dst() & 0xFF;
+ }
+ //! Return crossbar port of the source
+ UHD_INLINE boost::uint32_t get_dst_xbarport() const {
+ return (get_dst_endpoint() >> 4) & 0xF;
+ }
+ //! Return block port of the source
+ UHD_INLINE boost::uint32_t get_dst_blockport() const {
+ return (get_dst_endpoint()) & 0xF;
+ }
+
+ // Setters
+
+ //! Alias for set_sid()
+ void set(boost::uint32_t new_sid) { set_sid(new_sid); };
+ //! Convert a string representation of a SID into a numerical one
+ // Throws uhd::value_error if the string is not a valid SID
+ // representation.
+ void set_from_str(const std::string &);
+ void set_sid(boost::uint32_t new_sid);
+ //! Set the source address of this SID
+ // (the first 16 Bits)
+ void set_src(boost::uint32_t new_addr);
+ //! Set the destination address of this SID
+ // (the last 16 Bits)
+ void set_dst(boost::uint32_t new_addr);
+ void set_src_addr(boost::uint32_t new_addr);
+ void set_src_endpoint(boost::uint32_t new_addr);
+ void set_dst_addr(boost::uint32_t new_addr);
+ void set_dst_endpoint(boost::uint32_t new_addr);
+ void set_dst_xbarport(boost::uint32_t new_xbarport);
+ void set_dst_blockport(boost::uint32_t new_blockport);
+
+ // Manipulators
+
+ //! Swaps dst and src address and returns the new SID.
+ sid_t reversed();
+
+ //! Swaps dst and src in-place.
+ void reverse();
+
+ // Overloaded operators
+
+ sid_t operator = (boost::uint32_t new_sid) {
+ set_sid(new_sid);
+ return *this;
+ }
+
+ sid_t operator = (sid_t &sid) {
+ set_sid(sid.get_sid());
+ return *this;
+ }
+
+ sid_t operator = (const std::string &sid_str) {
+ set_from_str(sid_str);
+ return *this;
+ }
+
+ bool operator == (const sid_t &sid) const {
+ return (not _set and not sid.is_set()) or (_sid == sid.get_sid());
+ }
+
+ bool operator == (boost::uint32_t sid) const {
+ return _set and _sid == sid;
+ }
+
+ bool operator == (const std::string &sid_str) const {
+ sid_t rhs(sid_str);
+ return *this == rhs;
+ }
+
+ // overloaded type casts are tricky, but for now we'll need them
+ // for backward compatibility. consider them deprecated.
+
+ //! If the SID is not set, always returns zero.
+ // Use is_set() to check if the return value is valid.
+ operator boost::uint32_t() const {
+ return get();
+ }
+
+ operator bool() const {
+ return _set;
+ }
+
+ private:
+ boost::uint32_t _sid;
+ bool _set;
+ };
+
+ //! Stream output operator. Honors std::ios::hex.
+ UHD_INLINE std::ostream& operator<< (std::ostream& out, const sid_t &sid) {
+ std::ios_base::fmtflags ff = out.flags();
+ if (ff & std::ios::hex) {
+ out << sid.to_pp_string_hex();
+ } else {
+ out << sid.to_pp_string();
+ }
+ return out;
+ }
+
+} //namespace uhd
+
+#endif /* INCLUDED_UHD_TYPES_SID_HPP */
+// vim: sw=4 et:
diff --git a/host/include/uhd/usrp/multi_usrp.hpp b/host/include/uhd/usrp/multi_usrp.hpp
index 6fd22ff23..f0bb6d8d3 100644
--- a/host/include/uhd/usrp/multi_usrp.hpp
+++ b/host/include/uhd/usrp/multi_usrp.hpp
@@ -22,10 +22,12 @@
#define UHD_USRP_MULTI_USRP_REF_SOURCES_API
#define UHD_USRP_MULTI_USRP_GET_RATES_API
#define UHD_USRP_MULTI_USRP_FRONTEND_CAL_API
+#define UHD_USRP_MULTI_USRP_FRONTEND_IQ_AUTO_API
#define UHD_USRP_MULTI_USRP_COMMAND_TIME_API
#define UHD_USRP_MULTI_USRP_BW_RANGE_API
#define UHD_USRP_MULTI_USRP_USER_REGS_API
#define UHD_USRP_MULTI_USRP_GET_USRP_INFO_API
+#define UHD_USRP_MULTI_USRP_NORMALIZED_GAIN
#include <uhd/config.hpp>
#include <uhd/device.hpp>
@@ -35,6 +37,7 @@
#include <uhd/types/tune_request.hpp>
#include <uhd/types/tune_result.hpp>
#include <uhd/types/sensors.hpp>
+#include <uhd/types/filters.hpp>
#include <uhd/usrp/subdev_spec.hpp>
#include <uhd/usrp/dboard_iface.hpp>
#include <boost/shared_ptr.hpp>
@@ -155,6 +158,11 @@ public:
* If the specified rate is not available, this method will throw.
* On other devices, this method notifies the software of the rate,
* but requires the the user has made the necessary hardware change.
+ *
+ * If the device has an 'auto clock rate' setting (e.g. B200, see also
+ * \ref b200_auto_mcr), this will get disabled and the clock rate will be
+ * fixed to \p rate.
+ *
* \param rate the new master clock rate in Hz
* \param mboard the motherboard index 0 to M-1
*/
@@ -490,6 +498,34 @@ public:
}
/*!
+ * Set the normalized RX gain value.
+ *
+ * The normalized gain is a value in [0, 1], where 0 is the
+ * smallest gain value available, and 1 is the largest, independent
+ * of the device. In between, gains are linearly interpolated.
+ *
+ * Check the individual device manual for notes on the gain range.
+ *
+ * Note that it is not possible to specify a gain name for
+ * this function, it will always set the overall gain.
+ *
+ * \param gain the normalized gain value
+ * \param chan the channel index 0 to N-1
+ * \throws A uhd::runtime_error if the gain value is outside [0, 1].
+ */
+ virtual void set_normalized_rx_gain(double gain, size_t chan = 0) = 0;
+
+ /*!
+ * Enable or disable the RX AGC module.
+ * Once this module is enabled manual gain settings will be ignored.
+ * The AGC will start in a default configuration which should be good for most use cases.
+ * Device specific configuration parameters can be found in the property tree.
+ * \param on Enable or Disable the AGC
+ * \param chan the channel index 0 to N-1
+ */
+ virtual void set_rx_agc(bool enable, size_t chan = 0) = 0;
+
+ /*!
* Get the RX gain value for the specified gain element.
* For an empty name, sum across all gain elements.
* \param name the name of the gain element
@@ -504,6 +540,19 @@ public:
}
/*!
+ * Return the normalized RX gain value.
+ *
+ * See set_normalized_rx_gain() for a discussion of normalized
+ * gains.
+ *
+ * \param gain the normalized gain value
+ * \param chan the channel index 0 to N-1
+ * \returns The normalized gain (in [0, 1])
+ * \throws A uhd::runtime_error if the gain value is outside [0, 1].
+ */
+ virtual double get_normalized_rx_gain(size_t chan = 0) = 0;
+
+ /*!
* Get the RX gain range for the specified gain element.
* For an empty name, calculate the overall gain range.
* \param name the name of the gain element
@@ -615,6 +664,14 @@ public:
virtual void set_rx_dc_offset(const std::complex<double> &offset, size_t chan = ALL_CHANS) = 0;
/*!
+ * Enable/disable the automatic IQ imbalance correction.
+ *
+ * \param enb true to enable automatic IQ balance correction
+ * \param chan the channel index 0 to N-1
+ */
+ virtual void set_rx_iq_balance(const bool enb, size_t chan) = 0;
+
+ /*!
* Set the RX frontend IQ imbalance correction.
* Use this to adjust the magnitude and phase of I and Q.
*
@@ -728,6 +785,18 @@ public:
}
/*!
+ * Set the normalized TX gain value.
+ *
+ * See set_normalized_rx_gain() for a discussion on normalized
+ * gains.
+ *
+ * \param gain the normalized gain value
+ * \param chan the channel index 0 to N-1
+ * \throws A uhd::runtime_error if the gain value is outside [0, 1].
+ */
+ virtual void set_normalized_tx_gain(double gain, size_t chan = 0) = 0;
+
+ /*!
* Get the TX gain value for the specified gain element.
* For an empty name, sum across all gain elements.
* \param name the name of the gain element
@@ -742,6 +811,19 @@ public:
}
/*!
+ * Return the normalized TX gain value.
+ *
+ * See set_normalized_rx_gain() for a discussion of normalized
+ * gains.
+ *
+ * \param gain the normalized gain value
+ * \param chan the channel index 0 to N-1
+ * \returns The normalized gain (in [0, 1])
+ * \throws A uhd::runtime_error if the gain value is outside [0, 1].
+ */
+ virtual double get_normalized_tx_gain(size_t chan = 0) = 0;
+
+ /*!
* Get the TX gain range for the specified gain element.
* For an empty name, calculate the overall gain range.
* \param name the name of the gain element
@@ -893,6 +975,38 @@ public:
*/
virtual boost::uint32_t get_gpio_attr(const std::string &bank, const std::string &attr, const size_t mboard = 0) = 0;
+ /*******************************************************************
+ * Filter API methods
+ ******************************************************************/
+
+ /*!
+ * Enumerate the available filters in the signal path.
+ * \param search_mask
+ * \parblock
+ * Select only certain filter names by specifying this search mask.
+ *
+ * E.g. if search mask is set to "rx_frontends/A" only filter names including that string will be returned.
+ * \endparblock
+ * \return a vector of strings representing the selected filter names.
+ */
+ virtual std::vector<std::string> get_filter_names(const std::string &search_mask = "") = 0;
+
+ /*!
+ * Return the filter object for the given name.
+ * \param path the name of the filter as returned from get_filter_names().
+ * \return a filter_info_base::sptr.
+ */
+ virtual filter_info_base::sptr get_filter(const std::string &path) = 0;
+
+ /*!
+ * Write back a filter obtained by get_filter() to the signal path.
+ * This filter can be a modified version of the originally returned one.
+ * The information about Rx or Tx is contained in the path parameter.
+ * \param path the name of the filter as returned from get_filter_names().
+ * \param filter the filter_info_base::sptr of the filter object to be written
+ */
+ virtual void set_filter(const std::string &path, filter_info_base::sptr filter) = 0;
+
};
}}
diff --git a/host/include/uhd/utils/math.hpp b/host/include/uhd/utils/math.hpp
index 4f88494d6..46a1cf7e4 100644
--- a/host/include/uhd/utils/math.hpp
+++ b/host/include/uhd/utils/math.hpp
@@ -18,11 +18,11 @@
#ifndef INCLUDED_UHD_UTILS_MATH_HPP
#define INCLUDED_UHD_UTILS_MATH_HPP
+#include <cmath>
#include <uhd/config.hpp>
#include <boost/cstdint.hpp>
#include <boost/numeric/conversion/bounds.hpp>
-
namespace uhd {
/*!
@@ -237,6 +237,16 @@ namespace fp_compare {
== fp_compare::fp_compare_delta<double>(rhs, FREQ_COMPARISON_DELTA_HZ));
}
+ //! Portable log2()
+ template <typename float_t> UHD_INLINE
+ float_t log2(float_t x)
+ {
+ // C++11 defines std::log2(), when that's universally supported
+ // we can switch over.
+ return std::log(x) / std::log(float_t(2));
+ }
+
+
} // namespace math
} // namespace uhd
diff --git a/host/lib/convert/convert_impl.cpp b/host/lib/convert/convert_impl.cpp
index 329e94a4d..fd6c8497e 100644
--- a/host/lib/convert/convert_impl.cpp
+++ b/host/lib/convert/convert_impl.cpp
@@ -43,10 +43,10 @@ bool convert::operator==(const convert::id_type &lhs, const convert::id_type &rh
std::string convert::id_type::to_pp_string(void) const{
return str(boost::format(
"conversion ID\n"
- " Input format: %s\n"
- " Num inputs: %d\n"
+ " Input format: %s\n"
+ " Num inputs: %d\n"
" Output format: %s\n"
- " Num outputs: %d\n"
+ " Num outputs: %d\n"
)
% this->input_format
% this->num_inputs
@@ -55,6 +55,15 @@ std::string convert::id_type::to_pp_string(void) const{
);
}
+std::string convert::id_type::to_string(void) const{
+ return str(boost::format("%s (%d) -> %s (%d)")
+ % this->input_format
+ % this->num_inputs
+ % this->output_format
+ % this->num_outputs
+ );
+}
+
/***********************************************************************
* Setup the table registry
**********************************************************************/
@@ -92,7 +101,15 @@ convert::function_type convert::get_converter(
//find a matching priority
priority_type best_prio = -1;
BOOST_FOREACH(priority_type prio_i, get_table()[id].keys()){
- if (prio_i == prio) return get_table()[id][prio];
+ if (prio_i == prio) {
+ //----------------------------------------------------------------//
+ UHD_LOGV(always) << "get_converter: For converter ID: " << id.to_pp_string() << std::endl
+ << "Using prio: " << prio << std::endl
+ << std::endl
+ ;
+ //----------------------------------------------------------------//
+ return get_table()[id][prio];
+ }
best_prio = std::max(best_prio, prio_i);
}
@@ -100,6 +117,13 @@ convert::function_type convert::get_converter(
if (prio != -1) throw uhd::key_error(
"Cannot find a conversion routine [with prio] for " + id.to_pp_string());
+ //----------------------------------------------------------------//
+ UHD_LOGV(always) << "get_converter: For converter ID: " << id.to_pp_string() << std::endl
+ << "Using prio: " << best_prio << std::endl
+ << std::endl
+ ;
+ //----------------------------------------------------------------//
+
//otherwise, return best prio
return get_table()[id][best_prio];
}
diff --git a/host/lib/transport/CMakeLists.txt b/host/lib/transport/CMakeLists.txt
index 5920f3d78..9ec8a5c0b 100644
--- a/host/lib/transport/CMakeLists.txt
+++ b/host/lib/transport/CMakeLists.txt
@@ -129,6 +129,7 @@ LIBUHD_APPEND_SOURCES(
${CMAKE_CURRENT_SOURCE_DIR}/if_addrs.cpp
${CMAKE_CURRENT_SOURCE_DIR}/udp_simple.cpp
${CMAKE_CURRENT_SOURCE_DIR}/nirio_zero_copy.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/chdr.cpp
)
# Verbose Debug output for send/recv
diff --git a/host/lib/transport/chdr.cpp b/host/lib/transport/chdr.cpp
new file mode 100644
index 000000000..47ac961b9
--- /dev/null
+++ b/host/lib/transport/chdr.cpp
@@ -0,0 +1,182 @@
+//
+// Copyright 2014 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <uhd/transport/chdr.hpp>
+#include <uhd/utils/byteswap.hpp>
+#include <uhd/exception.hpp>
+
+//define the endian macros to convert integers
+#ifdef BOOST_BIG_ENDIAN
+ #define BE_MACRO(x) (x)
+ #define LE_MACRO(x) uhd::byteswap(x)
+#else
+ #define BE_MACRO(x) uhd::byteswap(x)
+ #define LE_MACRO(x) (x)
+#endif
+
+using namespace uhd::transport::vrt;
+
+static const boost::uint32_t HDR_FLAG_TSF = (1 << 29);
+static const boost::uint32_t HDR_FLAG_EOB = (1 << 28);
+static const boost::uint32_t HDR_FLAG_ERROR = (1 << 28);
+
+/***************************************************************************/
+/* Packing */
+/***************************************************************************/
+/*! Translate the contents of \p if_packet_info into a 32-Bit word and return it.
+ */
+UHD_INLINE boost::uint32_t _hdr_pack_chdr(
+ if_packet_info_t &if_packet_info
+) {
+ // Set fields in if_packet_info
+ if_packet_info.num_header_words32 = 2 + (if_packet_info.has_tsf ? 2 : 0);
+ if_packet_info.num_packet_words32 =
+ if_packet_info.num_header_words32 +
+ if_packet_info.num_payload_words32;
+
+ boost::uint16_t pkt_length =
+ if_packet_info.num_payload_bytes + (4 * if_packet_info.num_header_words32);
+ boost::uint32_t chdr = 0
+ // 2 Bits: Packet type
+ | (if_packet_info.packet_type << 30)
+ // 1 Bit: Has time
+ | (if_packet_info.has_tsf ? HDR_FLAG_TSF : 0)
+ // 1 Bit: EOB or Error
+ | ((if_packet_info.eob or if_packet_info.error) ? HDR_FLAG_EOB : 0)
+ // 12 Bits: Sequence number
+ | ((if_packet_info.packet_count & 0xFFF) << 16)
+ // 16 Bits: Total packet length
+ | pkt_length;
+ return chdr;
+}
+
+void chdr::if_hdr_pack_be(
+ boost::uint32_t *packet_buff,
+ if_packet_info_t &if_packet_info
+) {
+ // Write header and update if_packet_info
+ packet_buff[0] = BE_MACRO(_hdr_pack_chdr(if_packet_info));
+
+ // Write SID
+ packet_buff[1] = BE_MACRO(if_packet_info.sid);
+
+ // Write time
+ if (if_packet_info.has_tsf) {
+ packet_buff[2] = BE_MACRO(boost::uint32_t(if_packet_info.tsf >> 32));
+ packet_buff[3] = BE_MACRO(boost::uint32_t(if_packet_info.tsf >> 0));
+ }
+}
+
+void chdr::if_hdr_pack_le(
+ boost::uint32_t *packet_buff,
+ if_packet_info_t &if_packet_info
+) {
+ // Write header and update if_packet_info
+ packet_buff[0] = LE_MACRO(_hdr_pack_chdr(if_packet_info));
+
+ // Write SID
+ packet_buff[1] = LE_MACRO(if_packet_info.sid);
+
+ // Write time
+ if (if_packet_info.has_tsf) {
+ packet_buff[2] = LE_MACRO(boost::uint32_t(if_packet_info.tsf >> 32));
+ packet_buff[3] = LE_MACRO(boost::uint32_t(if_packet_info.tsf >> 0));
+ }
+}
+
+
+/***************************************************************************/
+/* Unpacking */
+/***************************************************************************/
+UHD_INLINE void _hdr_unpack_chdr(
+ const boost::uint32_t chdr,
+ if_packet_info_t &if_packet_info
+) {
+ // Set constant members
+ if_packet_info.link_type = if_packet_info_t::LINK_TYPE_CHDR;
+ if_packet_info.has_cid = false;
+ if_packet_info.has_sid = true;
+ if_packet_info.has_tsi = false;
+ if_packet_info.has_tlr = false;
+ if_packet_info.sob = false;
+
+ // Set configurable members
+ if_packet_info.has_tsf = bool(chdr & HDR_FLAG_TSF);
+ if_packet_info.packet_type = if_packet_info_t::packet_type_t((chdr >> 30) & 0x3);
+ if_packet_info.eob = (if_packet_info.packet_type == if_packet_info_t::PACKET_TYPE_DATA)
+ && bool(chdr & HDR_FLAG_EOB);
+ if_packet_info.error = (if_packet_info.packet_type == if_packet_info_t::PACKET_TYPE_RESP)
+ && bool(chdr & HDR_FLAG_ERROR);
+ if_packet_info.packet_count = (chdr >> 16) & 0xFFF;
+
+ // Set packet length variables
+ if (if_packet_info.has_tsf) {
+ if_packet_info.num_header_words32 = 4;
+ } else {
+ if_packet_info.num_header_words32 = 2;
+ }
+ size_t pkt_size_bytes = (chdr & 0xFFFF);
+ size_t pkt_size_word32 = (pkt_size_bytes / 4) + ((pkt_size_bytes % 4) ? 1 : 0);
+ // Check lengths match:
+ if (pkt_size_word32 < if_packet_info.num_header_words32) {
+ throw uhd::value_error("Bad CHDR or invalid packet length");
+ }
+ if (if_packet_info.num_packet_words32 < pkt_size_word32) {
+ throw uhd::value_error("Bad CHDR or packet fragment");
+ }
+ if_packet_info.num_payload_bytes = pkt_size_bytes - (4 * if_packet_info.num_header_words32);
+ if_packet_info.num_payload_words32 = pkt_size_word32 - if_packet_info.num_header_words32;
+}
+
+void chdr::if_hdr_unpack_be(
+ const boost::uint32_t *packet_buff,
+ if_packet_info_t &if_packet_info
+) {
+ // Read header and update if_packet_info
+ boost::uint32_t chdr = BE_MACRO(packet_buff[0]);
+ _hdr_unpack_chdr(chdr, if_packet_info);
+
+ // Read SID
+ if_packet_info.sid = BE_MACRO(packet_buff[1]);
+
+ // Read time (has_tsf was updated earlier)
+ if (if_packet_info.has_tsf) {
+ if_packet_info.tsf = 0
+ | boost::uint64_t(BE_MACRO(packet_buff[2])) << 32
+ | BE_MACRO(packet_buff[3]);
+ }
+}
+
+void chdr::if_hdr_unpack_le(
+ const boost::uint32_t *packet_buff,
+ if_packet_info_t &if_packet_info
+) {
+ // Read header and update if_packet_info
+ boost::uint32_t chdr = LE_MACRO(packet_buff[0]);
+ _hdr_unpack_chdr(chdr, if_packet_info);
+
+ // Read SID
+ if_packet_info.sid = LE_MACRO(packet_buff[1]);
+
+ // Read time (has_tsf was updated earlier)
+ if (if_packet_info.has_tsf) {
+ if_packet_info.tsf = 0
+ | boost::uint64_t(LE_MACRO(packet_buff[2])) << 32
+ | LE_MACRO(packet_buff[3]);
+ }
+}
+
diff --git a/host/lib/transport/libusb1_base.cpp b/host/lib/transport/libusb1_base.cpp
index ee4e20adb..18acb1fdc 100644
--- a/host/lib/transport/libusb1_base.cpp
+++ b/host/lib/transport/libusb1_base.cpp
@@ -343,15 +343,21 @@ libusb::special_handle::sptr libusb::special_handle::make(device::sptr dev){
std::vector<usb_device_handle::sptr> usb_device_handle::get_device_list(
boost::uint16_t vid, boost::uint16_t pid
){
- std::vector<usb_device_handle::sptr> handles;
+ return usb_device_handle::get_device_list(std::vector<usb_device_handle::vid_pid_pair_t>(1,usb_device_handle::vid_pid_pair_t(vid,pid)));
+}
+std::vector<usb_device_handle::sptr> usb_device_handle::get_device_list(const std::vector<usb_device_handle::vid_pid_pair_t>& vid_pid_pair_list)
+{
+ std::vector<usb_device_handle::sptr> handles;
libusb::device_list::sptr dev_list = libusb::device_list::make();
- for (size_t i = 0; i < dev_list->size(); i++){
- usb_device_handle::sptr handle = libusb::special_handle::make(dev_list->at(i));
- if (handle->get_vendor_id() == vid and handle->get_product_id() == pid){
- handles.push_back(handle);
- }
+ for(size_t iter = 0; iter < vid_pid_pair_list.size(); ++iter)
+ {
+ for (size_t i = 0; i < dev_list->size(); i++){
+ usb_device_handle::sptr handle = libusb::special_handle::make(dev_list->at(i));
+ if (handle->get_vendor_id() == vid_pid_pair_list[iter].first and handle->get_product_id() == vid_pid_pair_list[iter].second){
+ handles.push_back(handle);
+ }
+ }
}
-
return handles;
}
diff --git a/host/lib/transport/nirio/rpc/rpc_client.cpp b/host/lib/transport/nirio/rpc/rpc_client.cpp
index cf8e9c1a9..48f47cfae 100644
--- a/host/lib/transport/nirio/rpc/rpc_client.cpp
+++ b/host/lib/transport/nirio/rpc/rpc_client.cpp
@@ -52,7 +52,7 @@ rpc_client::rpc_client (
//- address_configured: Only return addresses if a non-loopback address is configured for the system.
//- numeric_host: No name resolution should be attempted for host
//- numeric_service: No name resolution should be attempted for service
- tcp::resolver::query::flags query_flags;
+ tcp::resolver::query::flags query_flags = tcp::resolver::query::passive;
tcp::resolver::query query(tcp::v4(), server, port, query_flags);
tcp::resolver::iterator iterator = resolver.resolve(query);
diff --git a/host/lib/transport/super_recv_packet_handler.hpp b/host/lib/transport/super_recv_packet_handler.hpp
index 5c84327a4..c3c2b8e97 100644
--- a/host/lib/transport/super_recv_packet_handler.hpp
+++ b/host/lib/transport/super_recv_packet_handler.hpp
@@ -147,7 +147,7 @@ public:
*/
void set_xport_chan_get_buff(const size_t xport_chan, const get_buff_type &get_buff, const bool flush = false){
if (flush){
- while (get_buff(0.0));
+ while (get_buff(0.0)) {};
}
_props.at(xport_chan).get_buff = get_buff;
}
diff --git a/host/lib/types/CMakeLists.txt b/host/lib/types/CMakeLists.txt
index f19043c1e..821754386 100644
--- a/host/lib/types/CMakeLists.txt
+++ b/host/lib/types/CMakeLists.txt
@@ -86,8 +86,10 @@ LIBUHD_APPEND_SOURCES(
${CMAKE_CURRENT_SOURCE_DIR}/ranges.cpp
${CMAKE_CURRENT_SOURCE_DIR}/sensors.cpp
${CMAKE_CURRENT_SOURCE_DIR}/serial.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/sid.cpp
${CMAKE_CURRENT_SOURCE_DIR}/time_spec.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tune.cpp
${CMAKE_CURRENT_SOURCE_DIR}/types.cpp
${CMAKE_CURRENT_SOURCE_DIR}/wb_iface.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/filters.cpp
)
diff --git a/host/lib/types/filters.cpp b/host/lib/types/filters.cpp
new file mode 100644
index 000000000..4ee06491f
--- /dev/null
+++ b/host/lib/types/filters.cpp
@@ -0,0 +1,74 @@
+//
+// Copyright 2015 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <uhd/types/filters.hpp>
+
+using namespace uhd;
+
+std::ostream& uhd::operator<<(std::ostream& os, filter_info_base& f)
+{
+ return os << f.to_pp_string();
+}
+
+std::string filter_info_base::to_pp_string()
+{
+ std::ostringstream os;
+ os << "[filter_info_base]" << std::endl;
+ switch(_type){
+ case ANALOG_LOW_PASS:
+ os << "type: " << "Analog Low-pass" << std::endl;
+ break;
+ case ANALOG_BAND_PASS:
+ os << "type: " << "Analog Band-pass" << std::endl;
+ break;
+ case DIGITAL_I16:
+ os << "type: " << "Digital (i16)" << std::endl;
+ break;
+ case DIGITAL_FIR_I16:
+ os << "type: " << "Digital FIR (i16)" << std::endl;
+ break;
+ default:
+ os << "type: " << "Unknown type!" << std::endl;
+ break;
+ }
+
+ os << "bypass enable: " << _bypass << std::endl
+ <<"position index: " << _position_index << std::endl;
+
+ std::string str = os.str();
+ return str;
+}
+
+std::string analog_filter_base::to_pp_string()
+{
+ std::ostringstream os;
+ os << filter_info_base::to_pp_string() <<
+ "\t[analog_filter_base]" << std::endl <<
+ "\tdesc: " << _analog_type << std::endl;
+ return std::string(os.str());
+
+}
+
+std::string analog_filter_lp::to_pp_string()
+{
+ std::ostringstream os;
+ os << analog_filter_base::to_pp_string() <<
+ "\t\t[analog_filter_lp]" << std::endl <<
+ "\t\tcutoff: " << _cutoff << std::endl <<
+ "\t\trolloff: " << _rolloff << std::endl;
+ return std::string(os.str());
+}
diff --git a/host/lib/types/sid.cpp b/host/lib/types/sid.cpp
new file mode 100644
index 000000000..2fc3781cf
--- /dev/null
+++ b/host/lib/types/sid.cpp
@@ -0,0 +1,153 @@
+//
+// Copyright 2014 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 <boost/format.hpp>
+#include <boost/regex.hpp>
+#include <boost/lexical_cast.hpp>
+#include <uhd/exception.hpp>
+#include <uhd/types/sid.hpp>
+#include <uhd/utils/cast.hpp>
+
+using namespace uhd;
+
+sid_t::sid_t()
+ : _sid(0x0000), _set(false)
+{
+}
+
+sid_t::sid_t(boost::uint32_t sid)
+ : _sid(sid), _set(true)
+{
+}
+
+sid_t::sid_t(boost::uint8_t src_addr, boost::uint8_t src_ep, boost::uint8_t dst_addr, boost::uint8_t dst_ep)
+ : _sid(0x0000), _set(true)
+{
+ set_src_addr(src_addr);
+ set_src_endpoint(src_ep);
+ set_dst_addr(dst_addr);
+ set_dst_endpoint(dst_ep);
+}
+
+sid_t::sid_t(const std::string &sid_str)
+ : _sid(0x0000), _set(false)
+{
+ set_from_str(sid_str);
+}
+
+std::string sid_t::to_pp_string() const
+{
+ if (not _set) {
+ return "x.x>x.x";
+ }
+ return str(boost::format("%d.%d>%d.%d")
+ % get_src_addr()
+ % get_src_endpoint()
+ % get_dst_addr()
+ % get_dst_endpoint()
+ );
+}
+
+std::string sid_t::to_pp_string_hex() const
+{
+ if (not _set) {
+ return "xx:xx>xx:xx";
+ }
+ return str(boost::format("%02x:%02x>%02x:%02x")
+ % get_src_addr()
+ % get_src_endpoint()
+ % get_dst_addr()
+ % get_dst_endpoint()
+ );
+}
+
+
+void sid_t::set_sid(boost::uint32_t new_sid)
+{
+ _set = true;
+ _sid = new_sid;
+}
+
+void sid_t::set_from_str(const std::string &sid_str)
+{
+ const std::string dec_regex = "(\\d{1,3})\\.(\\d{1,3})[.:/><](\\d{1,3})\\.(\\d{1,3})";
+ const std::string hex_regex = "([[:xdigit:]]{2}):([[:xdigit:]]{2})[.:/><]([[:xdigit:]]{2}):([[:xdigit:]]{2})";
+
+ boost::cmatch matches;
+ if (boost::regex_match(sid_str.c_str(), matches, boost::regex(dec_regex))) {
+ set_src_addr(boost::lexical_cast<size_t>(matches[1]));
+ set_src_endpoint(boost::lexical_cast<size_t>(matches[2]));
+ set_dst_addr(boost::lexical_cast<size_t>(matches[3]));
+ set_dst_endpoint(boost::lexical_cast<size_t>(matches[4]));
+ return;
+ }
+
+ if (boost::regex_match(sid_str.c_str(), matches, boost::regex(hex_regex))) {
+ set_src_addr(uhd::cast::hexstr_cast<size_t>(matches[1]));
+ set_src_endpoint(uhd::cast::hexstr_cast<size_t>(matches[2]));
+ set_dst_addr(uhd::cast::hexstr_cast<size_t>(matches[3]));
+ set_dst_endpoint(uhd::cast::hexstr_cast<size_t>(matches[4]));
+ return;
+ }
+
+ throw uhd::value_error(str(boost::format("Invalid SID representation: %s") % sid_str));
+}
+
+void sid_t::set_src(boost::uint32_t new_addr) {
+ set_sid((_sid & 0x0000FFFF) | ((new_addr & 0xFFFF) << 16));
+}
+
+void sid_t::set_dst(boost::uint32_t new_addr) {
+ set_sid((_sid & 0xFFFF0000) | (new_addr & 0xFFFF));
+}
+
+void sid_t::set_src_addr(boost::uint32_t new_addr) {
+ set_sid((_sid & 0x00FFFFFF) | ((new_addr & 0xFF) << 24));
+}
+
+void sid_t::set_src_endpoint(boost::uint32_t new_addr) {
+ set_sid((_sid & 0xFF00FFFF) | ((new_addr & 0xFF) << 16));
+}
+
+void sid_t::set_dst_addr(boost::uint32_t new_addr) {
+ set_sid((_sid & 0xFFFF00FF) | ((new_addr & 0xFF) << 8));
+}
+
+void sid_t::set_dst_endpoint(boost::uint32_t new_addr) {
+ set_sid((_sid & 0xFFFFFF00) | ((new_addr & 0xFF) << 0));
+}
+
+void sid_t::set_dst_xbarport(boost::uint32_t new_xbarport)
+{
+ set_sid((_sid & 0xFFFFFF0F) | ((new_xbarport & 0xF) << 4));
+}
+
+void sid_t::set_dst_blockport(boost::uint32_t new_blockport)
+{
+ set_sid((_sid & 0xFFFFFFF0) | ((new_blockport & 0xF) << 0));
+}
+
+sid_t sid_t::reversed()
+{
+ return sid_t((get_dst() << 16) | get_src());
+}
+
+void sid_t::reverse()
+{
+ set_sid((get_dst() << 16) | get_src());
+}
+
diff --git a/host/lib/usrp/b200/b200_iface.hpp b/host/lib/usrp/b200/b200_iface.hpp
index 83adfdd64..1821865d3 100644
--- a/host/lib/usrp/b200/b200_iface.hpp
+++ b/host/lib/usrp/b200/b200_iface.hpp
@@ -26,7 +26,10 @@
#include "ad9361_ctrl.hpp"
const static boost::uint16_t B200_VENDOR_ID = 0x2500;
+const static boost::uint16_t B200_VENDOR_NI_ID = 0x3923;
const static boost::uint16_t B200_PRODUCT_ID = 0x0020;
+const static boost::uint16_t B200_PRODUCT_NI_ID = 0x7813;
+const static boost::uint16_t B210_PRODUCT_NI_ID = 0x7814;
const static boost::uint16_t FX3_VID = 0x04b4;
const static boost::uint16_t FX3_DEFAULT_PID = 0x00f3;
const static boost::uint16_t FX3_REENUM_PID = 0x00f0;
diff --git a/host/lib/usrp/b200/b200_impl.cpp b/host/lib/usrp/b200/b200_impl.cpp
index eead07e85..e1b106208 100644
--- a/host/lib/usrp/b200/b200_impl.cpp
+++ b/host/lib/usrp/b200/b200_impl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2012-2014 Ettus Research LLC
+// Copyright 2012-2015 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -90,14 +90,16 @@ static device_addrs_t b200_find(const device_addr_t &hint)
if (hint_i.has_key("addr") || hint_i.has_key("resource")) return b200_addrs;
}
- boost::uint16_t vid, pid;
+ size_t found = 0;
+ std::vector<usb_device_handle::vid_pid_pair_t> vid_pid_pair_list;//vid pid pair search list for devices.
if(hint.has_key("vid") && hint.has_key("pid") && hint.has_key("type") && hint["type"] == "b200") {
- vid = uhd::cast::hexstr_cast<boost::uint16_t>(hint.get("vid"));
- pid = uhd::cast::hexstr_cast<boost::uint16_t>(hint.get("pid"));
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(uhd::cast::hexstr_cast<boost::uint16_t>(hint.get("vid")),
+ uhd::cast::hexstr_cast<boost::uint16_t>(hint.get("pid"))));
} else {
- vid = B200_VENDOR_ID;
- pid = B200_PRODUCT_ID;
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_ID, B200_PRODUCT_ID));
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID, B200_PRODUCT_NI_ID));
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID, B210_PRODUCT_NI_ID));
}
// Important note:
@@ -107,8 +109,9 @@ static device_addrs_t b200_find(const device_addr_t &hint)
// This requirement is a courtesy of libusb1.0 on windows.
//find the usrps and load firmware
- size_t found = 0;
- BOOST_FOREACH(usb_device_handle::sptr handle, usb_device_handle::get_device_list(vid, pid)) {
+ std::vector<usb_device_handle::sptr> uhd_usb_device_vector = usb_device_handle::get_device_list(vid_pid_pair_list);
+
+ BOOST_FOREACH(usb_device_handle::sptr handle, uhd_usb_device_vector) {
//extract the firmware path for the b200
std::string b200_fw_image;
try{
@@ -139,7 +142,7 @@ static device_addrs_t b200_find(const device_addr_t &hint)
//search for the device until found or timeout
while (boost::get_system_time() < timeout_time and b200_addrs.empty() and found != 0)
{
- BOOST_FOREACH(usb_device_handle::sptr handle, usb_device_handle::get_device_list(vid, pid))
+ BOOST_FOREACH(usb_device_handle::sptr handle, usb_device_handle::get_device_list(vid_pid_pair_list))
{
usb_control::sptr control;
try{control = usb_control::make(handle, 0);}
@@ -156,12 +159,16 @@ static device_addrs_t b200_find(const device_addr_t &hint)
{
switch (boost::lexical_cast<boost::uint16_t>(mb_eeprom["product"]))
{
+ //0x0001 and 0x7737 are Ettus B200 product Ids.
case 0x0001:
case 0x7737:
+ case B200_PRODUCT_NI_ID:
new_addr["product"] = "B200";
break;
- case 0x7738:
+ //0x0002 and 0x7738 are Ettus B210 product Ids.
case 0x0002:
+ case 0x7738:
+ case B210_PRODUCT_NI_ID:
new_addr["product"] = "B210";
break;
default: UHD_MSG(error) << "B200 unknown product code: " << mb_eeprom["product"] << std::endl;
@@ -206,13 +213,50 @@ b200_impl::b200_impl(const device_addr_t &device_addr) :
//try to match the given device address with something on the USB bus
boost::uint16_t vid = B200_VENDOR_ID;
boost::uint16_t pid = B200_PRODUCT_ID;
+ bool specified_vid = false;
+ bool specified_pid = false;
+
if (device_addr.has_key("vid"))
+ {
vid = uhd::cast::hexstr_cast<boost::uint16_t>(device_addr.get("vid"));
+ specified_vid = true;
+ }
+
if (device_addr.has_key("pid"))
+ {
pid = uhd::cast::hexstr_cast<boost::uint16_t>(device_addr.get("pid"));
+ specified_pid = true;
+ }
+
+ std::vector<usb_device_handle::vid_pid_pair_t> vid_pid_pair_list;//search list for devices.
- std::vector<usb_device_handle::sptr> device_list =
- usb_device_handle::get_device_list(vid, pid);
+ // Search only for specified VID and PID if both specified
+ if (specified_vid && specified_pid)
+ {
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid,pid));
+ }
+ // Search for all supported PIDs limited to specified VID if only VID specified
+ else if (specified_vid)
+ {
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid,B200_PRODUCT_ID));
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid,B200_PRODUCT_NI_ID));
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid,B210_PRODUCT_NI_ID));
+ }
+ // Search for all supported VIDs limited to specified PID if only PID specified
+ else if (specified_pid)
+ {
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_ID,pid));
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID,pid));
+ }
+ // Search for all supported devices if neither VID nor PID specified
+ else
+ {
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_ID,B200_PRODUCT_ID));
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID,B200_PRODUCT_NI_ID));
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID,B210_PRODUCT_NI_ID));
+ }
+
+ std::vector<usb_device_handle::sptr> device_list = usb_device_handle::get_device_list(vid_pid_pair_list);
//locate the matching handle in the device list
usb_device_handle::sptr handle;
@@ -246,13 +290,17 @@ b200_impl::b200_impl(const device_addr_t &device_addr) :
{
switch (boost::lexical_cast<boost::uint16_t>(mb_eeprom["product"]))
{
+ //0x0001 and 0x7737 are Ettus B200 product Ids.
case 0x0001:
case 0x7737:
+ case B200_PRODUCT_NI_ID:
product_name = "B200";
default_file_name = B200_FPGA_FILE_NAME;
break;
- case 0x7738:
+ //0x0002 and 0x7738 are Ettus B210 product Ids.
case 0x0002:
+ case 0x7738:
+ case B210_PRODUCT_NI_ID:
product_name = "B210";
default_file_name = B210_FPGA_FILE_NAME;
break;
@@ -418,6 +466,7 @@ b200_impl::b200_impl(const device_addr_t &device_addr) :
.publish(boost::bind(&b200_impl::get_tick_rate, this))
.subscribe(boost::bind(&b200_impl::update_tick_rate, this, _1));
_tree->create<time_spec_t>(mb_path / "time" / "cmd");
+ _tree->create<bool>(mb_path / "auto_tick_rate").set(false);
////////////////////////////////////////////////////////////////////
// and do the misc mboard sensors
@@ -481,6 +530,19 @@ b200_impl::b200_impl(const device_addr_t &device_addr) :
_tree->create<std::vector<std::string> >(mb_path / "clock_source" / "options").set(clock_sources);
////////////////////////////////////////////////////////////////////
+ // front panel gpio
+ ////////////////////////////////////////////////////////////////////
+ _radio_perifs[0].fp_gpio = gpio_core_200::make(_radio_perifs[0].ctrl, TOREG(SR_FP_GPIO), RB32_FP_GPIO);
+ BOOST_FOREACH(const gpio_attr_map_t::value_type attr, gpio_attr_map)
+ {
+ _tree->create<boost::uint32_t>(mb_path / "gpio" / "FP0" / attr.second)
+ .set(0)
+ .subscribe(boost::bind(&b200_impl::set_fp_gpio, this, _radio_perifs[0].fp_gpio, attr.first, _1));
+ }
+ _tree->create<boost::uint32_t>(mb_path / "gpio" / "FP0" / "READBACK")
+ .publish(boost::bind(&b200_impl::get_fp_gpio, this, _radio_perifs[0].fp_gpio));
+
+ ////////////////////////////////////////////////////////////////////
// dboard eeproms but not really
////////////////////////////////////////////////////////////////////
dboard_eeprom_t db_eeprom;
@@ -518,6 +580,11 @@ b200_impl::b200_impl(const device_addr_t &device_addr) :
_tree->access<double>(mb_path / "rx_dsps" / str(boost::format("%u") % i)/ "rate/value").set(B200_DEFAULT_RATE);
_tree->access<double>(mb_path / "tx_dsps" / str(boost::format("%u") % i) / "rate/value").set(B200_DEFAULT_RATE);
}
+ // We can automatically choose a master clock rate, but not if the user specifies one
+ _tree->access<bool>(mb_path / "auto_tick_rate").set(not device_addr.has_key("master_clock_rate"));
+ if (not device_addr.has_key("master_clock_rate")) {
+ UHD_MSG(status) << "Setting master clock rate selection to 'automatic'." << std::endl;
+ }
//GPS installed: use external ref, time, and init time spec
if (_gps and _gps->gps_detected())
@@ -538,7 +605,7 @@ b200_impl::b200_impl(const device_addr_t &device_addr) :
b200_impl::~b200_impl(void)
{
- UHD_SAFE_CALL
+ UHD_SAFE_CALL
(
_async_task.reset();
)
@@ -581,7 +648,7 @@ void b200_impl::setup_radio(const size_t dspno)
_tree->create<meta_range_t>(rx_dsp_path / "rate" / "range")
.publish(boost::bind(&rx_dsp_core_3000::get_host_rates, perif.ddc));
_tree->create<double>(rx_dsp_path / "rate" / "value")
- .coerce(boost::bind(&rx_dsp_core_3000::set_host_rate, perif.ddc, _1))
+ .coerce(boost::bind(&b200_impl::coerce_rx_samp_rate, this, perif.ddc, dspno, _1))
.subscribe(boost::bind(&b200_impl::update_rx_samp_rate, this, dspno, _1))
.set(0.0); // Can only set this after tick rate is initialized.
_tree->create<double>(rx_dsp_path / "freq" / "value")
@@ -605,7 +672,7 @@ void b200_impl::setup_radio(const size_t dspno)
_tree->create<meta_range_t>(tx_dsp_path / "rate" / "range")
.publish(boost::bind(&tx_dsp_core_3000::get_host_rates, perif.duc));
_tree->create<double>(tx_dsp_path / "rate" / "value")
- .coerce(boost::bind(&tx_dsp_core_3000::set_host_rate, perif.duc, _1))
+ .coerce(boost::bind(&b200_impl::coerce_tx_samp_rate, this, perif.duc, dspno, _1))
.subscribe(boost::bind(&b200_impl::update_tx_samp_rate, this, dspno, _1))
.set(0.0); // Can only set this after tick rate is initialized.
_tree->create<double>(tx_dsp_path / "freq" / "value")
@@ -649,7 +716,7 @@ void b200_impl::setup_radio(const size_t dspno)
_tree->create<bool>(rf_fe_path / "use_lo_offset").set(false);
_tree->create<double>(rf_fe_path / "bandwidth" / "value")
.coerce(boost::bind(&ad9361_ctrl::set_bw_filter, _codec_ctrl, key, _1))
- .set(40e6);
+ .set(56e6);
_tree->create<meta_range_t>(rf_fe_path / "bandwidth" / "range")
.publish(boost::bind(&ad9361_ctrl::get_bw_filter_range, key));
_tree->create<double>(rf_fe_path / "freq" / "value")
@@ -658,8 +725,29 @@ void b200_impl::setup_radio(const size_t dspno)
.set(B200_DEFAULT_FREQ);
_tree->create<meta_range_t>(rf_fe_path / "freq" / "range")
.publish(boost::bind(&ad9361_ctrl::get_rf_freq_range));
+ _tree->create<sensor_value_t>(rf_fe_path / "sensors" / "temp")
+ .publish(boost::bind(&ad9361_ctrl::get_temperature, _codec_ctrl));
//setup RX related stuff
+ if(direction)
+ {
+ _tree->create<bool>(rf_fe_path / "dc_offset" / "enable" )
+ .subscribe(boost::bind(&ad9361_ctrl::set_dc_offset_auto, _codec_ctrl, key, _1)).set(true);
+
+ _tree->create<bool>(rf_fe_path / "iq_balance" / "enable" )
+ .subscribe(boost::bind(&ad9361_ctrl::set_iq_balance_auto, _codec_ctrl, key, _1)).set(true);
+ }
+
+ //add all frontend filters
+ std::vector<std::string> filter_names = _codec_ctrl->get_filter_names(key);
+ for(size_t i = 0;i < filter_names.size(); i++)
+ {
+ _tree->create<filter_info_base::sptr>(rf_fe_path / "filters" / filter_names[i] / "value" )
+ .publish(boost::bind(&ad9361_ctrl::get_filter, _codec_ctrl, key, filter_names[i]))
+ .subscribe(boost::bind(&ad9361_ctrl::set_filter, _codec_ctrl, key, filter_names[i], _1));
+ }
+
+ //setup antenna stuff
if (key[0] == 'R')
{
static const std::vector<std::string> ants = boost::assign::list_of("TX/RX")("RX2");
@@ -669,6 +757,16 @@ void b200_impl::setup_radio(const size_t dspno)
.set("RX2");
_tree->create<sensor_value_t>(rf_fe_path / "sensors" / "rssi")
.publish(boost::bind(&ad9361_ctrl::get_rssi, _codec_ctrl, key));
+
+ //AGC setup
+ const std::list<std::string> mode_strings = boost::assign::list_of("slow")("fast");
+ _tree->create<bool>(rf_fe_path / "gain" / "agc" / "enable")
+ .subscribe(boost::bind((&ad9361_ctrl::set_agc), _codec_ctrl, key, _1))
+ .set(false);
+ _tree->create<std::string>(rf_fe_path / "gain" / "agc" / "mode" / "value")
+ .subscribe(boost::bind((&ad9361_ctrl::set_agc_mode), _codec_ctrl, key, _1)).set(mode_strings.front());
+ _tree->create<std::list<std::string> >(rf_fe_path / "gain" / "agc" / "mode" / "options")
+ .set(mode_strings);
}
if (key[0] == 'T')
{
@@ -725,7 +823,7 @@ void b200_impl::codec_loopback_self_test(wb_iface::sptr iface)
/***********************************************************************
* Sample and tick rate comprehension below
**********************************************************************/
-void b200_impl::enforce_tick_rate_limits(size_t chan_count, double tick_rate, const char* direction /*= NULL*/)
+void b200_impl::enforce_tick_rate_limits(size_t chan_count, double tick_rate, const std::string &direction /*= ""*/)
{
const size_t max_chans = 2;
if (chan_count > max_chans)
@@ -733,7 +831,7 @@ void b200_impl::enforce_tick_rate_limits(size_t chan_count, double tick_rate, co
throw uhd::value_error(boost::str(
boost::format("cannot not setup %d %s channels (maximum is %d)")
% chan_count
- % (direction ? direction : "data")
+ % (direction.empty() ? "data" : direction)
% max_chans
));
}
@@ -747,20 +845,26 @@ void b200_impl::enforce_tick_rate_limits(size_t chan_count, double tick_rate, co
% (tick_rate/1e6)
% (max_tick_rate/1e6)
% chan_count
- % (direction ? direction : "data")
+ % (direction.empty() ? "data" : direction)
));
}
}
}
-double b200_impl::set_tick_rate(const double rate)
+double b200_impl::set_tick_rate(const double new_tick_rate)
{
- UHD_MSG(status) << (boost::format("Asking for clock rate %.6f MHz\n") % (rate/1e6));
-
- check_tick_rate_with_current_streamers(rate); // Defined in b200_io_impl.cpp
+ UHD_MSG(status) << (boost::format("Asking for clock rate %.6f MHz... ") % (new_tick_rate/1e6)) << std::flush;
+ check_tick_rate_with_current_streamers(new_tick_rate); // Defined in b200_io_impl.cpp
+
+ // Make sure the clock rate is actually changed before doing
+ // the full Monty of setting regs and loopback tests etc.
+ if (std::abs(new_tick_rate - _tick_rate) < 1.0) {
+ UHD_MSG(status) << "OK" << std::endl;
+ return _tick_rate;
+ }
- _tick_rate = _codec_ctrl->set_clock_rate(rate);
- UHD_MSG(status) << (boost::format("Actually got clock rate %.6f MHz\n") % (_tick_rate/1e6));
+ _tick_rate = _codec_ctrl->set_clock_rate(new_tick_rate);
+ UHD_MSG(status) << std::endl << (boost::format("Actually got clock rate %.6f MHz.") % (_tick_rate/1e6)) << std::endl;
//reset after clock rate change
this->reset_codec_dcm();
@@ -821,6 +925,26 @@ void b200_impl::set_mb_eeprom(const uhd::usrp::mboard_eeprom_t &mb_eeprom)
}
+boost::uint32_t b200_impl::get_fp_gpio(gpio_core_200::sptr gpio)
+{
+ return boost::uint32_t(gpio->read_gpio(dboard_iface::UNIT_RX));
+}
+
+void b200_impl::set_fp_gpio(gpio_core_200::sptr gpio, const gpio_attr_t attr, const boost::uint32_t value)
+{
+ switch (attr)
+ {
+ case GPIO_CTRL: return gpio->set_pin_ctrl(dboard_iface::UNIT_RX, value);
+ case GPIO_DDR: return gpio->set_gpio_ddr(dboard_iface::UNIT_RX, value);
+ case GPIO_OUT: return gpio->set_gpio_out(dboard_iface::UNIT_RX, value);
+ case GPIO_ATR_0X: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE, value);
+ case GPIO_ATR_RX: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY, value);
+ case GPIO_ATR_TX: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY, value);
+ case GPIO_ATR_XX: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, value);
+ default: UHD_THROW_INVALID_CODE_PATH();
+ }
+}
+
/***********************************************************************
* Reference time and clock
**********************************************************************/
diff --git a/host/lib/usrp/b200/b200_impl.hpp b/host/lib/usrp/b200/b200_impl.hpp
index 396819f9a..cff767b4b 100644
--- a/host/lib/usrp/b200/b200_impl.hpp
+++ b/host/lib/usrp/b200/b200_impl.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2012-2013 Ettus Research LLC
+// Copyright 2012-2015 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -98,7 +98,13 @@ public:
uhd::rx_streamer::sptr get_rx_stream(const uhd::stream_args_t &args);
uhd::tx_streamer::sptr get_tx_stream(const uhd::stream_args_t &args);
bool recv_async_msg(uhd::async_metadata_t &, double);
- void check_streamer_args(const uhd::stream_args_t &args, double tick_rate, const char* direction = NULL);
+
+ //! Check that the combination of stream args and tick rate are valid.
+ //
+ // Basically figures out the arguments for enforce_tick_rate_limits()
+ // and calls said method. If arguments are invalid, throws a
+ // uhd::value_error.
+ void check_streamer_args(const uhd::stream_args_t &args, double tick_rate, const std::string &direction = "");
private:
//controllers
@@ -150,6 +156,7 @@ private:
{
radio_ctrl_core_3000::sptr ctrl;
gpio_core_200_32wo::sptr atr;
+ gpio_core_200::sptr fp_gpio;
time_core_3000::sptr time64;
rx_vita_core_3000::sptr framer;
rx_dsp_core_3000::sptr ddc;
@@ -188,14 +195,63 @@ private:
void update_enables(void);
void update_atrs(void);
+ boost::uint32_t get_fp_gpio(gpio_core_200::sptr);
+ void set_fp_gpio(gpio_core_200::sptr, const gpio_attr_t, const boost::uint32_t);
+
double _tick_rate;
double get_tick_rate(void){return _tick_rate;}
double set_tick_rate(const double rate);
+
+ /*! \brief Choose a tick rate (master clock rate) that works well for the given sampling rate.
+ *
+ * This function will try and choose a master clock rate automatically.
+ * See the function definition for details on the algorithm.
+ *
+ * The chosen tick rate is the largest multiple of two that is smaler
+ * than the max tick rate.
+ * The base rate is either given explicitly, or is the lcm() of the tx
+ * and rx sampling rates. In that case, it reads the rates directly
+ * from the property tree. It also tries to guess the number of channels
+ * (for the max possible tick rate) by checking the available streamers.
+ * This value, too, can explicitly be given.
+ *
+ * \param rate If this is given, it will be used as a minimum rate, or
+ * argument to lcm().
+ * \param tree_dsp_path The sampling rate from this property tree path
+ * will be ignored.
+ * \param num_chans If given, specifies the number of channels.
+ */
+ void set_auto_tick_rate(
+ const double rate=0,
+ const uhd::fs_path &tree_dsp_path="",
+ size_t num_chans=0
+ );
+
void update_tick_rate(const double);
- void enforce_tick_rate_limits(size_t chan_count, double tick_rate, const char* direction = NULL);
+
+ /*! Check if \p tick_rate works with \p chan_count channels.
+ *
+ * Throws a uhd::value_error if not.
+ */
+ void enforce_tick_rate_limits(size_t chan_count, double tick_rate, const std::string &direction = "");
void check_tick_rate_with_current_streamers(double rate);
+ /*! Return the max number of channels on active rx_streamer or tx_streamer objects associated with this device.
+ *
+ * \param direction Set to "TX" to only check tx_streamers, "RX" to only check
+ * rx_streamers. Any other value will check if \e any active
+ * streamers are available.
+ * \return Return the number of tx streamers (direction=="TX"), the number of rx
+ * streamers (direction=="RX") or the total number of streamers.
+ */
+ size_t max_chan_count(const std::string &direction="");
+
+ //! Coercer, attached to the "rate/value" property on the rx dsps.
+ double coerce_rx_samp_rate(rx_dsp_core_3000::sptr, size_t, const double);
void update_rx_samp_rate(const size_t, const double);
+
+ //! Coercer, attached to the "rate/value" property on the tx dsps.
+ double coerce_tx_samp_rate(tx_dsp_core_3000::sptr, size_t, const double);
void update_tx_samp_rate(const size_t, const double);
};
diff --git a/host/lib/usrp/b200/b200_io_impl.cpp b/host/lib/usrp/b200/b200_io_impl.cpp
index 262c95f0d..60b925517 100644
--- a/host/lib/usrp/b200/b200_io_impl.cpp
+++ b/host/lib/usrp/b200/b200_io_impl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2012-2013 Ettus Research LLC
+// Copyright 2012-2014 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
@@ -21,8 +21,10 @@
#include "../../transport/super_recv_packet_handler.hpp"
#include "../../transport/super_send_packet_handler.hpp"
#include "async_packet_handler.hpp"
+#include <uhd/utils/math.hpp>
#include <boost/bind.hpp>
#include <boost/make_shared.hpp>
+#include <boost/math/common_factor.hpp>
#include <set>
using namespace uhd;
@@ -34,30 +36,32 @@ using namespace uhd::transport;
**********************************************************************/
void b200_impl::check_tick_rate_with_current_streamers(double rate)
{
- size_t max_tx_chan_count = 0, max_rx_chan_count = 0;
+ // Defined in b200_impl.cpp
+ enforce_tick_rate_limits(max_chan_count("RX"), rate, "RX");
+ enforce_tick_rate_limits(max_chan_count("TX"), rate, "TX");
+}
+
+// direction can either be "TX", "RX", or empty (default)
+size_t b200_impl::max_chan_count(const std::string &direction /* = "" */)
+{
+ size_t max_count = 0;
BOOST_FOREACH(radio_perifs_t &perif, _radio_perifs)
{
- {
+ if ((direction == "RX" or direction.empty()) and not perif.rx_streamer.expired()) {
boost::shared_ptr<sph::recv_packet_streamer> rx_streamer =
boost::dynamic_pointer_cast<sph::recv_packet_streamer>(perif.rx_streamer.lock());
- if (rx_streamer)
- max_rx_chan_count = std::max(max_rx_chan_count, rx_streamer->get_num_channels());
+ max_count = std::max(max_count, rx_streamer->get_num_channels());
}
-
- {
+ if ((direction == "TX" or direction.empty()) and not perif.tx_streamer.expired()) {
boost::shared_ptr<sph::send_packet_streamer> tx_streamer =
boost::dynamic_pointer_cast<sph::send_packet_streamer>(perif.tx_streamer.lock());
- if (tx_streamer)
- max_tx_chan_count = std::max(max_tx_chan_count, tx_streamer->get_num_channels());
+ max_count = std::max(max_count, tx_streamer->get_num_channels());
}
}
-
- // Defined in b200_impl.cpp
- enforce_tick_rate_limits(max_rx_chan_count, rate, "RX");
- enforce_tick_rate_limits(max_tx_chan_count, rate, "TX");
+ return max_count;
}
-void b200_impl::check_streamer_args(const uhd::stream_args_t &args, double tick_rate, const char* direction /*= NULL*/)
+void b200_impl::check_streamer_args(const uhd::stream_args_t &args, double tick_rate, const std::string &direction /*= ""*/)
{
std::set<size_t> chans_set;
for (size_t stream_i = 0; stream_i < args.channels.size(); stream_i++)
@@ -69,26 +73,120 @@ void b200_impl::check_streamer_args(const uhd::stream_args_t &args, double tick_
enforce_tick_rate_limits(chans_set.size(), tick_rate, direction); // Defined in b200_impl.cpp
}
-void b200_impl::update_tick_rate(const double rate)
+void b200_impl::set_auto_tick_rate(
+ const double rate,
+ const fs_path &tree_dsp_path,
+ size_t num_chans
+) {
+ if (num_chans == 0) { // Divine them
+ num_chans = std::max(size_t(1), max_chan_count());
+ }
+
+ // See also the doxygen documentation for these steps in b200_impl.hpp
+ // Step 1: Obtain LCM and max rate from all relevant dsps
+ boost::uint32_t lcm_rate = (rate == 0) ? 1 : static_cast<boost::uint32_t>(floor(rate + 0.5));
+ for (int i = 0; i < 2; i++) { // Loop through rx and tx
+ std::string dir = (i == 0) ? "tx" : "rx";
+ // We have no way of knowing which DSPs are used, so we check them all.
+ BOOST_FOREACH(const std::string &dsp_no, _tree->list(str(boost::format("/mboards/0/%s_dsps") % dir))) {
+ fs_path dsp_path = str(boost::format("/mboards/0/%s_dsps/%s") % dir % dsp_no);
+ if (dsp_path == tree_dsp_path) {
+ continue;
+ }
+ double this_dsp_rate = _tree->access<double>(dsp_path / "rate/value").get();
+ // If this_dsp_rate == B200_DEFAULT_RATE, we assume the user did not actually set
+ // the sampling rate. If the user *did* set the rate to
+ // B200_DEFAULT_RATE on all DSPs, then this will still work (see below).
+ // If the user set one DSP to B200_DEFAULT_RATE and the other to
+ // a different rate, this also works if the rates are integer multiples
+ // of one another. Only for certain configurations of B200_DEFAULT_RATE
+ // and another rate that is not an integer multiple, this will be problematic.
+ // Since this case is less common than the case where a rate is left unset,
+ // we don't handle that but rather explain that corner case in the documentation.
+ if (this_dsp_rate == B200_DEFAULT_RATE) {
+ continue;
+ }
+ lcm_rate = boost::math::lcm<boost::uint32_t>(
+ lcm_rate,
+ static_cast<boost::uint32_t>(floor(this_dsp_rate + 0.5))
+ );
+ }
+ }
+ if (lcm_rate == 1) {
+ lcm_rate = static_cast<boost::uint32_t>(B200_DEFAULT_RATE);
+ }
+
+ // Step 2: Determine whether if we can use lcm_rate (preferred),
+ // or have to give up because too large:
+ const double max_tick_rate =
+ ((num_chans <= 1) ? ad9361_device_t::AD9361_RECOMMENDED_MAX_CLOCK_RATE : ad9361_device_t::AD9361_MAX_CLOCK_RATE/2);
+ double base_rate = static_cast<double>(lcm_rate);
+ if (base_rate > max_tick_rate) {
+ UHD_MSG(warning)
+ << "Cannot automatically determine an appropriate tick rate for these sampling rates." << std::endl
+ << "Consider using different sampling rates, or manually specify a suitable master clock rate." << std::endl;
+ return; // Let the others handle this
+ }
+
+ // Step 3: Choose the new rate
+ // Rules for choosing the tick rate:
+ // Choose a rate that is a power of 2 larger than the sampling rate,
+ // but at least 4. Cannot exceed the max tick rate, of course, but must
+ // be larger than the minimum tick rate.
+ // An equation that does all that is:
+ //
+ // f_auto = r * 2^floor(log2(f_max/r))
+ //
+ // where r is the base rate and f_max is the maximum tick rate. The case
+ // where floor() yields 1 must be caught.
+ const double min_tick_rate = _codec_ctrl->get_clock_rate_range().start();
+ // We use shifts here instead of 2^x because exp2() is not available in all compilers,
+ // also this guarantees no rounding issues. The type cast to int32_t serves as floor():
+ boost::int32_t multiplier = (1 << boost::int32_t(uhd::math::log2(max_tick_rate / base_rate)));
+ if (multiplier == 2 and base_rate >= min_tick_rate) {
+ // Don't bother (see above)
+ multiplier = 1;
+ }
+ double new_rate = base_rate * multiplier;
+ UHD_ASSERT_THROW(new_rate >= min_tick_rate);
+ UHD_ASSERT_THROW(new_rate <= max_tick_rate);
+
+ if (_tree->access<double>("/mboards/0/tick_rate").get() != new_rate) {
+ _tree->access<double>("/mboards/0/tick_rate").set(new_rate);
+ }
+}
+
+void b200_impl::update_tick_rate(const double new_tick_rate)
{
- check_tick_rate_with_current_streamers(rate);
+ check_tick_rate_with_current_streamers(new_tick_rate);
BOOST_FOREACH(radio_perifs_t &perif, _radio_perifs)
{
boost::shared_ptr<sph::recv_packet_streamer> my_streamer =
boost::dynamic_pointer_cast<sph::recv_packet_streamer>(perif.rx_streamer.lock());
- if (my_streamer) my_streamer->set_tick_rate(rate);
- perif.framer->set_tick_rate(_tick_rate);
+ if (my_streamer) my_streamer->set_tick_rate(new_tick_rate);
+ perif.framer->set_tick_rate(new_tick_rate);
}
BOOST_FOREACH(radio_perifs_t &perif, _radio_perifs)
{
boost::shared_ptr<sph::send_packet_streamer> my_streamer =
boost::dynamic_pointer_cast<sph::send_packet_streamer>(perif.tx_streamer.lock());
- if (my_streamer) my_streamer->set_tick_rate(rate);
- perif.deframer->set_tick_rate(_tick_rate);
+ if (my_streamer) my_streamer->set_tick_rate(new_tick_rate);
+ perif.deframer->set_tick_rate(new_tick_rate);
}
}
+
+double b200_impl::coerce_rx_samp_rate(rx_dsp_core_3000::sptr ddc, size_t dspno, const double rx_rate)
+{
+ // Have to set tick rate first, or the ddc will change the requested rate based on default tick rate
+ if (_tree->access<bool>("/mboards/0/auto_tick_rate").get()) {
+ const std::string dsp_path = (boost::format("/mboards/0/rx_dsps/%s") % dspno).str();
+ set_auto_tick_rate(rx_rate, dsp_path);
+ }
+ return ddc->set_host_rate(rx_rate);
+}
+
void b200_impl::update_rx_samp_rate(const size_t dspno, const double rate)
{
boost::shared_ptr<sph::recv_packet_streamer> my_streamer =
@@ -99,6 +197,16 @@ void b200_impl::update_rx_samp_rate(const size_t dspno, const double rate)
my_streamer->set_scale_factor(adj);
}
+double b200_impl::coerce_tx_samp_rate(tx_dsp_core_3000::sptr duc, size_t dspno, const double tx_rate)
+{
+ // Have to set tick rate first, or the duc will change the requested rate based on default tick rate
+ if (_tree->access<bool>("/mboards/0/auto_tick_rate").get()) {
+ const std::string dsp_path = (boost::format("/mboards/0/tx_dsps/%s") % dspno).str();
+ set_auto_tick_rate(tx_rate, dsp_path);
+ }
+ return duc->set_host_rate(tx_rate);
+}
+
void b200_impl::update_tx_samp_rate(const size_t dspno, const double rate)
{
boost::shared_ptr<sph::send_packet_streamer> my_streamer =
@@ -264,6 +372,9 @@ rx_streamer::sptr b200_impl::get_rx_stream(const uhd::stream_args_t &args_)
if (args.otw_format.empty()) args.otw_format = "sc16";
args.channels = args.channels.empty()? std::vector<size_t>(1, 0) : args.channels;
+ if (_tree->access<bool>("/mboards/0/auto_tick_rate").get()) {
+ set_auto_tick_rate(0, "", args.channels.size());
+ }
check_streamer_args(args, this->get_tick_rate(), "RX");
boost::shared_ptr<sph::recv_packet_streamer> my_streamer;
@@ -371,7 +482,10 @@ tx_streamer::sptr b200_impl::get_tx_stream(const uhd::stream_args_t &args_)
if (args.otw_format.empty()) args.otw_format = "sc16";
args.channels = args.channels.empty()? std::vector<size_t>(1, 0) : args.channels;
- check_streamer_args(args, this->get_tick_rate(), "TX");
+ if (_tree->access<bool>("/mboards/0/auto_tick_rate").get()) {
+ set_auto_tick_rate(0, "", args.channels.size());
+ }
+ check_streamer_args(args, this->get_tick_rate(), "RX");
boost::shared_ptr<sph::send_packet_streamer> my_streamer;
for (size_t stream_i = 0; stream_i < args.channels.size(); stream_i++)
diff --git a/host/lib/usrp/b200/b200_regs.hpp b/host/lib/usrp/b200/b200_regs.hpp
index 900651f94..8f2dd03f3 100644
--- a/host/lib/usrp/b200/b200_regs.hpp
+++ b/host/lib/usrp/b200/b200_regs.hpp
@@ -46,11 +46,13 @@ localparam SR_TX_DSP = 184;
localparam SR_TIME = 128;
localparam SR_RX_FMT = 136;
localparam SR_TX_FMT = 138;
+localparam SR_FP_GPIO = 200;
localparam RB32_TEST = 0;
localparam RB64_TIME_NOW = 8;
localparam RB64_TIME_PPS = 16;
localparam RB64_CODEC_READBACK = 24;
+localparam RB32_FP_GPIO = 32;
//pll constants
static const int AD9361_SLAVENO = (1 << 0);
diff --git a/host/lib/usrp/common/ad9361_ctrl.cpp b/host/lib/usrp/common/ad9361_ctrl.cpp
index 85510530d..9c17a582d 100644
--- a/host/lib/usrp/common/ad9361_ctrl.cpp
+++ b/host/lib/usrp/common/ad9361_ctrl.cpp
@@ -16,7 +16,6 @@
//
#include "ad9361_ctrl.hpp"
-#include <uhd/exception.hpp>
#include <uhd/types/ranges.hpp>
#include <uhd/utils/msg.hpp>
#include <uhd/types/serial.hpp>
@@ -108,6 +107,27 @@ public:
return _device.set_gain(direction, chain, value);
}
+ void set_agc(const std::string &which, bool enable)
+ {
+ boost::lock_guard<boost::mutex> lock(_mutex);
+
+ ad9361_device_t::chain_t chain =_get_chain_from_antenna(which);
+ _device.set_agc(chain, enable);
+ }
+
+ void set_agc_mode(const std::string &which, const std::string &mode)
+ {
+ boost::lock_guard<boost::mutex> lock(_mutex);
+ ad9361_device_t::chain_t chain =_get_chain_from_antenna(which);
+ if(mode == "slow") {
+ _device.set_agc_mode(chain, ad9361_device_t::GAIN_MODE_SLOW_AGC);
+ } else if (mode == "fast"){
+ _device.set_agc_mode(chain, ad9361_device_t::GAIN_MODE_FAST_AGC);
+ } else {
+ throw uhd::runtime_error("ad9361_ctrl got an invalid AGC option.");
+ }
+ }
+
//! set a new clock rate, return the exact value
double set_clock_rate(const double rate)
{
@@ -172,6 +192,62 @@ public:
return sensor_value_t("RSSI", _device.get_rssi(chain), "dB");
}
+ //! read the internal temp sensor. Average over 3 results
+ sensor_value_t get_temperature()
+ {
+ return sensor_value_t("temp", _device.get_average_temperature(), "C");
+ }
+
+ void set_dc_offset_auto(const std::string &which, const bool on)
+ {
+ boost::lock_guard<boost::mutex> lock(_mutex);
+
+ ad9361_device_t::direction_t direction = _get_direction_from_antenna(which);
+ _device.set_dc_offset_auto(direction,on);
+ }
+
+ void set_iq_balance_auto(const std::string &which, const bool on)
+ {
+ boost::lock_guard<boost::mutex> lock(_mutex);
+
+ ad9361_device_t::direction_t direction = _get_direction_from_antenna(which);
+ _device.set_iq_balance_auto(direction,on);
+ }
+
+ double set_bw_filter(const std::string &which, const double bw)
+ {
+ boost::lock_guard<boost::mutex> lock(_mutex);
+
+ ad9361_device_t::direction_t direction = _get_direction_from_antenna(which);
+ return _device.set_bw_filter(direction, bw);
+ }
+
+ std::vector<std::string> get_filter_names(const std::string &which)
+ {
+ boost::lock_guard<boost::mutex> lock(_mutex);
+
+ ad9361_device_t::direction_t direction = _get_direction_from_antenna(which);
+ return _device.get_filter_names(direction);
+ }
+
+ filter_info_base::sptr get_filter(const std::string &which, const std::string &filter_name)
+ {
+ boost::lock_guard<boost::mutex> lock(_mutex);
+
+ ad9361_device_t::direction_t direction = _get_direction_from_antenna(which);
+ ad9361_device_t::chain_t chain =_get_chain_from_antenna(which);
+ return _device.get_filter(direction, chain, filter_name);
+ }
+
+ void set_filter(const std::string &which, const std::string &filter_name, const filter_info_base::sptr filter)
+ {
+ boost::lock_guard<boost::mutex> lock(_mutex);
+
+ ad9361_device_t::direction_t direction = _get_direction_from_antenna(which);
+ ad9361_device_t::chain_t chain = _get_chain_from_antenna(which);
+ _device.set_filter(direction, chain, filter_name, filter);
+ }
+
private:
static ad9361_device_t::direction_t _get_direction_from_antenna(const std::string& antenna)
{
diff --git a/host/lib/usrp/common/ad9361_ctrl.hpp b/host/lib/usrp/common/ad9361_ctrl.hpp
index c5718302f..a6d65ad11 100644
--- a/host/lib/usrp/common/ad9361_ctrl.hpp
+++ b/host/lib/usrp/common/ad9361_ctrl.hpp
@@ -22,9 +22,13 @@
#include <uhd/types/ranges.hpp>
#include <uhd/types/serial.hpp>
#include <uhd/types/sensors.hpp>
+#include <uhd/exception.hpp>
#include <boost/shared_ptr.hpp>
#include <ad9361_device.h>
#include <string>
+#include <complex>
+#include <uhd/types/filters.hpp>
+#include <vector>
namespace uhd { namespace usrp {
@@ -77,15 +81,18 @@ public:
return uhd::meta_range_t(5e6, ad9361_device_t::AD9361_MAX_CLOCK_RATE); //5 MHz DCM low end
}
- //! set the filter bandwidth for the frontend
- double set_bw_filter(const std::string &/*which*/, const double /*bw*/)
- {
- return 56e6; //TODO
- }
+ //! set the filter bandwidth for the frontend's analog low pass
+ virtual double set_bw_filter(const std::string &/*which*/, const double /*bw*/) = 0;
//! set the gain for a particular gain element
virtual double set_gain(const std::string &which, const double value) = 0;
+ //! Enable or disable the AGC module
+ virtual void set_agc(const std::string &which, bool enable) = 0;
+
+ //! configure the AGC module to slow or fast mode
+ virtual void set_agc_mode(const std::string &which, const std::string &mode) = 0;
+
//! set a new clock rate, return the exact value
virtual double set_clock_rate(const double rate) = 0;
@@ -95,11 +102,43 @@ public:
//! tune the given frontend, return the exact value
virtual double tune(const std::string &which, const double value) = 0;
- //! turn on/off data port loopback
+ //! set the DC offset for I and Q manually
+ void set_dc_offset(const std::string &, const std::complex<double>)
+ {
+ //This feature should not be used according to Analog Devices
+ throw uhd::runtime_error("ad9361_ctrl::set_dc_offset this feature is not supported on this device.");
+ }
+
+ //! enable or disable the BB/RF DC tracking feature
+ virtual void set_dc_offset_auto(const std::string &which, const bool on) = 0;
+
+ //! set the IQ correction value manually
+ void set_iq_balance(const std::string &, const std::complex<double>)
+ {
+ //This feature should not be used according to Analog Devices
+ throw uhd::runtime_error("ad9361_ctrl::set_iq_balance this feature is not supported on this device.");
+ }
+
+ //! enable or disable the quadrature calibration
+ virtual void set_iq_balance_auto(const std::string &which, const bool on) = 0;
+
+ //! turn on/off Catalina's data port loopback
virtual void data_port_loopback(const bool on) = 0;
//! read internal RSSI sensor
virtual sensor_value_t get_rssi(const std::string &which) = 0;
+
+ //! read the internal temp sensor
+ virtual sensor_value_t get_temperature() = 0;
+
+ //! List all available filters by name
+ virtual std::vector<std::string> get_filter_names(const std::string &which) = 0;
+
+ //! Return a list of all filters
+ virtual filter_info_base::sptr get_filter(const std::string &which, const std::string &filter_name) = 0;
+
+ //! Write back a filter
+ virtual void set_filter(const std::string &which, const std::string &filter_name, const filter_info_base::sptr) = 0;
};
}}
diff --git a/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp b/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp
index 7268aff2d..c3eb5fb9d 100644
--- a/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp
+++ b/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp
@@ -11,6 +11,7 @@
#include <cmath>
#include <uhd/exception.hpp>
#include <uhd/utils/log.hpp>
+#include <uhd/utils/msg.hpp>
#include <boost/cstdint.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread/thread.hpp>
@@ -79,6 +80,7 @@ int get_num_taps(int max_num_taps) {
const double ad9361_device_t::AD9361_MAX_GAIN = 89.75;
const double ad9361_device_t::AD9361_MAX_CLOCK_RATE = 61.44e6;
const double ad9361_device_t::AD9361_RECOMMENDED_MAX_CLOCK_RATE = 56e6;
+const double ad9361_device_t::AD9361_CAL_VALID_WINDOW = 100e6;
/* Program either the RX or TX FIR filter.
*
@@ -86,7 +88,7 @@ const double ad9361_device_t::AD9361_RECOMMENDED_MAX_CLOCK_RATE = 56e6;
* how many taps are in the filter, and given a vector of the taps
* themselves. */
-void ad9361_device_t::_program_fir_filter(direction_t direction, int num_taps, boost::uint16_t *coeffs)
+void ad9361_device_t::_program_fir_filter(direction_t direction, chain_t chain, int num_taps, boost::uint16_t *coeffs)
{
boost::uint16_t base;
@@ -101,8 +103,20 @@ void ad9361_device_t::_program_fir_filter(direction_t direction, int num_taps, b
/* Encode number of filter taps for programming register */
boost::uint8_t reg_numtaps = (((num_taps / 16) - 1) & 0x07) << 5;
+ boost::uint8_t reg_chain = 0;
+ switch (chain) {
+ case CHAIN_1:
+ reg_chain = 0x01 << 3;
+ break;
+ case CHAIN_2:
+ reg_chain = 0x02 << 3;
+ break;
+ default:
+ reg_chain = 0x03 << 3;
+ }
+
/* Turn on the filter clock. */
- _io_iface->poke8(base + 5, reg_numtaps | 0x1a);
+ _io_iface->poke8(base + 5, reg_numtaps | reg_chain | 0x02);
boost::this_thread::sleep(boost::posix_time::milliseconds(1));
/* Zero the unused taps just in case they have stale data */
@@ -111,7 +125,7 @@ void ad9361_device_t::_program_fir_filter(direction_t direction, int num_taps, b
_io_iface->poke8(base + 0, addr);
_io_iface->poke8(base + 1, 0x0);
_io_iface->poke8(base + 2, 0x0);
- _io_iface->poke8(base + 5, reg_numtaps | 0x1e);
+ _io_iface->poke8(base + 5, reg_numtaps | reg_chain | (1 << 1) | (1 << 2));
_io_iface->poke8(base + 4, 0x00);
_io_iface->poke8(base + 4, 0x00);
}
@@ -121,7 +135,7 @@ void ad9361_device_t::_program_fir_filter(direction_t direction, int num_taps, b
_io_iface->poke8(base + 0, addr);
_io_iface->poke8(base + 1, (coeffs[addr]) & 0xff);
_io_iface->poke8(base + 2, (coeffs[addr] >> 8) & 0xff);
- _io_iface->poke8(base + 5, reg_numtaps | 0x1e);
+ _io_iface->poke8(base + 5, reg_numtaps | reg_chain | (1 << 1) | (1 << 2));
_io_iface->poke8(base + 4, 0x00);
_io_iface->poke8(base + 4, 0x00);
}
@@ -132,9 +146,9 @@ void ad9361_device_t::_program_fir_filter(direction_t direction, int num_taps, b
before the clock stops. Wait 4 sample clock periods after setting D2 high while that data writes into the table"
*/
- _io_iface->poke8(base + 5, reg_numtaps | 0x1A);
+ _io_iface->poke8(base + 5, reg_numtaps | reg_chain | (1 << 1));
if (direction == RX) {
- _io_iface->poke8(base + 5, reg_numtaps | 0x18);
+ _io_iface->poke8(base + 5, reg_numtaps | reg_chain );
/* Rx Gain, set to prevent digital overflow/saturation in filters
0:+6dB, 1:0dB, 2:-6dB, 3:-12dB
page 35 of UG-671 */
@@ -143,7 +157,7 @@ void ad9361_device_t::_program_fir_filter(direction_t direction, int num_taps, b
/* Tx Gain. bit[0]. set to prevent digital overflow/saturation in filters
0: 0dB, 1:-6dB
page 25 of UG-671 */
- _io_iface->poke8(base + 5, reg_numtaps | 0x18);
+ _io_iface->poke8(base + 5, reg_numtaps | reg_chain );
}
}
@@ -174,7 +188,7 @@ void ad9361_device_t::_setup_rx_fir(size_t num_taps, boost::int32_t decimation)
}
}
- _program_fir_filter(RX, num_taps, coeffs.get());
+ _program_fir_filter(RX, CHAIN_BOTH, num_taps, coeffs.get());
}
/* Program the TX FIR Filter. */
@@ -206,7 +220,7 @@ void ad9361_device_t::_setup_tx_fir(size_t num_taps, boost::int32_t interpolatio
}
}
- _program_fir_filter(TX, num_taps, coeffs.get());
+ _program_fir_filter(TX, CHAIN_BOTH, num_taps, coeffs.get());
}
/***********************************************************************
@@ -281,16 +295,24 @@ void ad9361_device_t::_calibrate_synth_charge_pumps()
*
* Note that the filter calibration depends heavily on the baseband
* bandwidth, so this must be re-done after any change to the RX sample
- * rate. */
-double ad9361_device_t::_calibrate_baseband_rx_analog_filter()
+ * rate.
+ * UG570 Page 33 states that this filter should be calibrated to 1.4 * bbbw*/
+double ad9361_device_t::_calibrate_baseband_rx_analog_filter(double req_rfbw)
{
- /* For filter tuning, baseband BW is half the complex BW, and must be
- * between 28e6 and 0.2e6. */
- double bbbw = _baseband_bw / 2.0;
+ double bbbw = req_rfbw / 2.0;
+ if(bbbw > _baseband_bw / 2.0)
+ {
+ UHD_LOG << "baseband bandwidth too large for current sample rate. Setting bandwidth to: "<<_baseband_bw;
+ bbbw = _baseband_bw / 2.0;
+ }
+
+ /* Baseband BW must be between 28e6 and 0.143e6.
+ * Max filter BW is 39.2 MHz. 39.2 / 1.4 = 28
+ * Min filter BW is 200kHz. 200 / 1.4 = 143 */
if (bbbw > 28e6) {
bbbw = 28e6;
- } else if (bbbw < 0.20e6) {
- bbbw = 0.20e6;
+ } else if (bbbw < 0.143e6) {
+ bbbw = 0.143e6;
}
double rxtune_clk = ((1.4 * bbbw * 2 * M_PI) / M_LN2);
@@ -339,16 +361,25 @@ double ad9361_device_t::_calibrate_baseband_rx_analog_filter()
*
* Note that the filter calibration depends heavily on the baseband
* bandwidth, so this must be re-done after any change to the TX sample
- * rate. */
-double ad9361_device_t::_calibrate_baseband_tx_analog_filter()
+ * rate.
+ * UG570 Page 32 states that this filter should be calibrated to 1.6 * bbbw*/
+double ad9361_device_t::_calibrate_baseband_tx_analog_filter(double req_rfbw)
{
- /* For filter tuning, baseband BW is half the complex BW, and must be
- * between 28e6 and 0.2e6. */
- double bbbw = _baseband_bw / 2.0;
+ double bbbw = req_rfbw / 2.0;
+
+ if(bbbw > _baseband_bw / 2.0)
+ {
+ UHD_LOG << "baseband bandwidth too large for current sample rate. Setting bandwidth to: "<<_baseband_bw;
+ bbbw = _baseband_bw / 2.0;
+ }
+
+ /* Baseband BW must be between 20e6 and 0.391e6.
+ * Max filter BW is 32 MHz. 32 / 1.6 = 20
+ * Min filter BW is 625 kHz. 625 / 1.6 = 391 */
if (bbbw > 20e6) {
bbbw = 20e6;
- } else if (bbbw < 0.625e6) {
- bbbw = 0.625e6;
+ } else if (bbbw < 0.391e6) {
+ bbbw = 0.391e6;
}
double txtune_clk = ((1.6 * bbbw * 2 * M_PI) / M_LN2);
@@ -385,16 +416,25 @@ double ad9361_device_t::_calibrate_baseband_tx_analog_filter()
/* Calibrate the secondary TX filter.
*
* This filter also depends on the TX sample rate, so if a rate change is
- * made, the previous calibration will no longer be valid. */
-void ad9361_device_t::_calibrate_secondary_tx_filter()
+ * made, the previous calibration will no longer be valid.
+ * UG570 Page 32 states that this filter should be calibrated to 5 * bbbw*/
+double ad9361_device_t::_calibrate_secondary_tx_filter(double req_rfbw)
{
- /* For filter tuning, baseband BW is half the complex BW, and must be
- * between 20e6 and 0.53e6. */
- double bbbw = _baseband_bw / 2.0;
+ double bbbw = req_rfbw / 2.0;
+
+ if(bbbw > _baseband_bw / 2.0)
+ {
+ UHD_LOG << "baseband bandwidth too large for current sample rate. Setting bandwidth to: "<<_baseband_bw;
+ bbbw = _baseband_bw / 2.0;
+ }
+
+ /* Baseband BW must be between 20e6 and 0.54e6.
+ * Max filter BW is 100 MHz. 100 / 5 = 20
+ * Min filter BW is 2.7 MHz. 2.7 / 5 = 0.54 */
if (bbbw > 20e6) {
bbbw = 20e6;
- } else if (bbbw < 0.53e6) {
- bbbw = 0.53e6;
+ } else if (bbbw < 0.54e6) {
+ bbbw = 0.54e6;
}
double bbbw_mhz = bbbw / 1e6;
@@ -455,13 +495,17 @@ void ad9361_device_t::_calibrate_secondary_tx_filter()
_io_iface->poke8(0x0d2, reg0d2);
_io_iface->poke8(0x0d1, reg0d1);
_io_iface->poke8(0x0d0, reg0d0);
+
+ return bbbw;
}
/* Calibrate the RX TIAs.
*
* Note that the values in the TIA register, after calibration, vary with
- * the RX gain settings. */
-void ad9361_device_t::_calibrate_rx_TIAs()
+ * the RX gain settings.
+ * We do not really program the BW here. Most settings are taken form the BB LPF registers
+ * UG570 page 33 states that this filter should be calibrated to 2.5 * bbbw */
+double ad9361_device_t::_calibrate_rx_TIAs(double req_rfbw)
{
boost::uint8_t reg1eb = _io_iface->peek8(0x1eb) & 0x3F;
boost::uint8_t reg1ec = _io_iface->peek8(0x1ec) & 0x7F;
@@ -472,13 +516,21 @@ void ad9361_device_t::_calibrate_rx_TIAs()
boost::uint8_t reg1de = 0x00;
boost::uint8_t reg1df = 0x00;
- /* For calibration, baseband BW is half the complex BW, and must be
- * between 28e6 and 0.2e6. */
- double bbbw = _baseband_bw / 2.0;
- if (bbbw > 20e6) {
- bbbw = 20e6;
- } else if (bbbw < 0.20e6) {
- bbbw = 0.20e6;
+ double bbbw = req_rfbw / 2.0;
+
+ if(bbbw > _baseband_bw / 2.0)
+ {
+ UHD_LOG << "baseband bandwidth too large for current sample rate. Setting bandwidth to: "<<_baseband_bw;
+ bbbw = _baseband_bw / 2.0;
+ }
+
+ /* Baseband BW must be between 28e6 and 0.4e6.
+ * Max filter BW is 70 MHz. 70 / 2.5 = 28
+ * Min filter BW is 1 MHz. 1 / 2.5 = 0.4*/
+ if (bbbw > 28e6) {
+ bbbw = 28e6;
+ } else if (bbbw < 0.40e6) {
+ bbbw = 0.40e6;
}
double ceil_bbbw_mhz = std::ceil(bbbw / 1e6);
@@ -519,6 +571,8 @@ void ad9361_device_t::_calibrate_rx_TIAs()
_io_iface->poke8(0x1df, reg1df);
_io_iface->poke8(0x1dc, reg1dc);
_io_iface->poke8(0x1de, reg1de);
+
+ return bbbw;
}
/* Setup the AD9361 ADC.
@@ -650,11 +704,12 @@ void ad9361_device_t::_setup_adc()
}
/* Calibrate the baseband DC offset.
- *
- * Note that this function is called from within the TX quadrature
- * calibration function! */
+ * Disables tracking
+ */
void ad9361_device_t::_calibrate_baseband_dc_offset()
{
+ _io_iface->poke8(0x18b, 0x83); //Reset RF DC tracking flag
+
_io_iface->poke8(0x193, 0x3f); // Calibration settings
_io_iface->poke8(0x190, 0x0f); // Set tracking coefficient
//write_ad9361_reg(device, 0x190, /*0x0f*//*0xDF*/0x80*1 | 0x40*1 | (16+8/*+4*/)); // Set tracking coefficient: don't *4 counter, do decim /4, increased gain shift
@@ -674,9 +729,8 @@ void ad9361_device_t::_calibrate_baseband_dc_offset()
}
/* Calibrate the RF DC offset.
- *
- * Note that this function is called from within the TX quadrature
- * calibration function. */
+ * Disables tracking
+ */
void ad9361_device_t::_calibrate_rf_dc_offset()
{
/* Some settings are frequency-dependent. */
@@ -691,7 +745,7 @@ void ad9361_device_t::_calibrate_rf_dc_offset()
}
_io_iface->poke8(0x185, 0x20); // RF DC Offset wait count
- _io_iface->poke8(0x18b, 0x83);
+ _io_iface->poke8(0x18b, 0x83); // Disable tracking
_io_iface->poke8(0x189, 0x30);
/* Run the calibration! */
@@ -707,6 +761,16 @@ void ad9361_device_t::_calibrate_rf_dc_offset()
}
}
+void ad9361_device_t::_configure_bb_rf_dc_tracking(const bool on)
+{
+ if(on)
+ {
+ _io_iface->poke8(0x18b, 0xad); // Enable BB and RF DC tracking
+ } else {
+ _io_iface->poke8(0x18b, 0x83); // Disable BB and RF DC tracking
+ }
+}
+
/* Start the RX quadrature calibration.
*
* Note that we are using AD9361's 'tracking' feature for RX quadrature
@@ -719,16 +783,20 @@ void ad9361_device_t::_calibrate_rx_quadrature()
_io_iface->poke8(0x16e, 0x25); // RX Gain index to use for cal
_io_iface->poke8(0x16a, 0x75); // Set Kexp phase
_io_iface->poke8(0x16b, 0x15); // Set Kexp amplitude
- _io_iface->poke8(0x169, 0xcf); // Continuous tracking mode
- _io_iface->poke8(0x18b, 0xad);
+
+ if(_use_iq_balance_correction)
+ {
+ _io_iface->poke8(0x169, 0xcf); // Continuous tracking mode. Gets disabled in _tx_quadrature_cal_routine!
+ }
}
-/* TX quadtrature calibration routine.
+/* TX quadrature calibration routine.
*
* The TX quadrature needs to be done twice, once for each TX chain, with
* only one register change in between. Thus, this function enacts the
* calibrations, and it is called from calibrate_tx_quadrature. */
void ad9361_device_t::_tx_quadrature_cal_routine() {
+
/* This is a weird process, but here is how it works:
* 1) Read the calibrated NCO frequency bits out of 0A3.
* 2) Write the two bits to the RX NCO freq part of 0A0.
@@ -773,12 +841,6 @@ void ad9361_device_t::_tx_quadrature_cal_routine() {
_io_iface->poke8(0x0a4, 0xf0); // Cal setting conut
_io_iface->poke8(0x0ae, 0x00); // Cal LPF gain index (split mode)
- /* First, calibrate the baseband DC offset. */
- _calibrate_baseband_dc_offset();
-
- /* Second, calibrate the RF DC offset. */
- _calibrate_rf_dc_offset();
-
/* Now, calibrate the TX quadrature! */
size_t count = 0;
_io_iface->poke8(0x016, 0x10);
@@ -793,9 +855,7 @@ void ad9361_device_t::_tx_quadrature_cal_routine() {
}
/* Run the TX quadrature calibration.
- *
- * Note that from within this function we are also triggering the baseband
- * and RF DC calibrations. */
+ */
void ad9361_device_t::_calibrate_tx_quadrature()
{
/* Make sure we are, in fact, in the ALERT state. If not, something is
@@ -879,7 +939,7 @@ void ad9361_device_t::_program_mixer_gm_subtable()
void ad9361_device_t::_program_gain_table() {
/* Figure out which gain table we should be using for our current
* frequency band. */
- boost::uint8_t (*gain_table)[5] = NULL;
+ boost::uint8_t (*gain_table)[3] = NULL;
boost::uint8_t new_gain_table;
if (_rx_freq < 1300e6) {
gain_table = gain_table_sub_1300mhz;
@@ -910,9 +970,9 @@ void ad9361_device_t::_program_gain_table() {
boost::uint8_t index = 0;
for (; index < 77; index++) {
_io_iface->poke8(0x130, index);
- _io_iface->poke8(0x131, gain_table[index][1]);
- _io_iface->poke8(0x132, gain_table[index][2]);
- _io_iface->poke8(0x133, gain_table[index][3]);
+ _io_iface->poke8(0x131, gain_table[index][0]);
+ _io_iface->poke8(0x132, gain_table[index][1]);
+ _io_iface->poke8(0x133, gain_table[index][2]);
_io_iface->poke8(0x137, 0x1E);
_io_iface->poke8(0x134, 0x00);
_io_iface->poke8(0x134, 0x00);
@@ -938,28 +998,58 @@ void ad9361_device_t::_program_gain_table() {
/* Setup gain control registers.
*
- * This really only needs to be done once, at initialization. */
-void ad9361_device_t::_setup_gain_control()
+ * This really only needs to be done once, at initialization.
+ * If AGC is used the mode select bits (Reg 0x0FA) must be written manually */
+void ad9361_device_t::_setup_gain_control(bool agc)
{
- _io_iface->poke8(0x0FA, 0xE0); // Gain Control Mode Select
- _io_iface->poke8(0x0FB, 0x08); // Table, Digital Gain, Man Gain Ctrl
- _io_iface->poke8(0x0FC, 0x23); // Incr Step Size, ADC Overrange Size
- _io_iface->poke8(0x0FD, 0x4C); // Max Full/LMT Gain Table Index
- _io_iface->poke8(0x0FE, 0x44); // Decr Step Size, Peak Overload Time
- _io_iface->poke8(0x100, 0x6F); // Max Digital Gain
- _io_iface->poke8(0x104, 0x2F); // ADC Small Overload Threshold
- _io_iface->poke8(0x105, 0x3A); // ADC Large Overload Threshold
- _io_iface->poke8(0x107, 0x31); // Large LMT Overload Threshold
- _io_iface->poke8(0x108, 0x39); // Small LMT Overload Threshold
- _io_iface->poke8(0x109, 0x23); // Rx1 Full/LMT Gain Index
- _io_iface->poke8(0x10A, 0x58); // Rx1 LPF Gain Index
- _io_iface->poke8(0x10B, 0x00); // Rx1 Digital Gain Index
- _io_iface->poke8(0x10C, 0x23); // Rx2 Full/LMT Gain Index
- _io_iface->poke8(0x10D, 0x18); // Rx2 LPF Gain Index
- _io_iface->poke8(0x10E, 0x00); // Rx2 Digital Gain Index
- _io_iface->poke8(0x114, 0x30); // Low Power Threshold
- _io_iface->poke8(0x11A, 0x27); // Initial LMT Gain Limit
- _io_iface->poke8(0x081, 0x00); // Tx Symbol Gain Control
+ /* The AGC mode configuration should be good for all cases.
+ * However, non AGC configuration still used for backward compatibility. */
+ if (agc) {
+ /*mode select bits must be written before hand!*/
+ _io_iface->poke8(0x0FB, 0x08); // Table, Digital Gain, Man Gain Ctrl
+ _io_iface->poke8(0x0FC, 0x23); // Incr Step Size, ADC Overrange Size
+ _io_iface->poke8(0x0FD, 0x4C); // Max Full/LMT Gain Table Index
+ _io_iface->poke8(0x0FE, 0x44); // Decr Step Size, Peak Overload Time
+ _io_iface->poke8(0x100, 0x6F); // Max Digital Gain
+ _io_iface->poke8(0x101, 0x0A); // Max Digital Gain
+ _io_iface->poke8(0x103, 0x08); // Max Digital Gain
+ _io_iface->poke8(0x104, 0x2F); // ADC Small Overload Threshold
+ _io_iface->poke8(0x105, 0x3A); // ADC Large Overload Threshold
+ _io_iface->poke8(0x106, 0x22); // Max Digital Gain
+ _io_iface->poke8(0x107, 0x2B); // Large LMT Overload Threshold
+ _io_iface->poke8(0x108, 0x31);
+ _io_iface->poke8(0x111, 0x0A);
+ _io_iface->poke8(0x11A, 0x1C);
+ _io_iface->poke8(0x120, 0x0C);
+ _io_iface->poke8(0x121, 0x44);
+ _io_iface->poke8(0x122, 0x44);
+ _io_iface->poke8(0x123, 0x11);
+ _io_iface->poke8(0x124, 0xF5);
+ _io_iface->poke8(0x125, 0x3B);
+ _io_iface->poke8(0x128, 0x03);
+ _io_iface->poke8(0x129, 0x56);
+ _io_iface->poke8(0x12A, 0x22);
+ } else {
+ _io_iface->poke8(0x0FA, 0xE0); // Gain Control Mode Select
+ _io_iface->poke8(0x0FB, 0x08); // Table, Digital Gain, Man Gain Ctrl
+ _io_iface->poke8(0x0FC, 0x23); // Incr Step Size, ADC Overrange Size
+ _io_iface->poke8(0x0FD, 0x4C); // Max Full/LMT Gain Table Index
+ _io_iface->poke8(0x0FE, 0x44); // Decr Step Size, Peak Overload Time
+ _io_iface->poke8(0x100, 0x6F); // Max Digital Gain
+ _io_iface->poke8(0x104, 0x2F); // ADC Small Overload Threshold
+ _io_iface->poke8(0x105, 0x3A); // ADC Large Overload Threshold
+ _io_iface->poke8(0x107, 0x31); // Large LMT Overload Threshold
+ _io_iface->poke8(0x108, 0x39); // Small LMT Overload Threshold
+ _io_iface->poke8(0x109, 0x23); // Rx1 Full/LMT Gain Index
+ _io_iface->poke8(0x10A, 0x58); // Rx1 LPF Gain Index
+ _io_iface->poke8(0x10B, 0x00); // Rx1 Digital Gain Index
+ _io_iface->poke8(0x10C, 0x23); // Rx2 Full/LMT Gain Index
+ _io_iface->poke8(0x10D, 0x18); // Rx2 LPF Gain Index
+ _io_iface->poke8(0x10E, 0x00); // Rx2 Digital Gain Index
+ _io_iface->poke8(0x114, 0x30); // Low Power Threshold
+ _io_iface->poke8(0x11A, 0x27); // Initial LMT Gain Limit
+ _io_iface->poke8(0x081, 0x00); // Tx Symbol Gain Control
+ }
}
/* Setup the RX or TX synthesizers.
@@ -1256,6 +1346,7 @@ double ad9361_device_t::_setup_rates(const double rate)
int divfactor = 0;
_tfir_factor = 0;
_rfir_factor = 0;
+
if (rate < 0.33e6) {
// RX1 + RX2 enabled, 3, 2, 2, 4
_regs.rxfilt = B8(11101111);
@@ -1411,6 +1502,19 @@ void ad9361_device_t::initialize()
_rx2_gain = 0;
_tx1_gain = 0;
_tx2_gain = 0;
+ _use_dc_offset_correction = true;
+ _use_iq_balance_correction = true;
+ _rx1_agc_mode = GAIN_MODE_SLOW_AGC;
+ _rx2_agc_mode = GAIN_MODE_SLOW_AGC;
+ _rx1_agc_enable = false;
+ _rx2_agc_enable = false;
+ _last_calibration_freq = -AD9361_CAL_VALID_WINDOW;
+ _rx_analog_bw = 0;
+ _tx_analog_bw = 0;
+ _rx_tia_lp_bw = 0;
+ _tx_sec_lp_bw = 0;
+ _rx_bb_lp_bw = 0;
+ _tx_bb_lp_bw = 0;
/* Reset the device. */
_io_iface->poke8(0x000, 0x01);
@@ -1500,7 +1604,7 @@ void ad9361_device_t::initialize()
/* Setup AuxADC */
_io_iface->poke8(0x00B, 0x00); // Temp Sensor Setup (Offset)
_io_iface->poke8(0x00C, 0x00); // Temp Sensor Setup (Temp Window)
- _io_iface->poke8(0x00D, 0x03); // Temp Sensor Setup (Periodic Measure)
+ _io_iface->poke8(0x00D, 0x00); // Temp Sensor Setup (Manual Measure)
_io_iface->poke8(0x00F, 0x04); // Temp Sensor Setup (Decimation)
_io_iface->poke8(0x01C, 0x10); // AuxADC Setup (Clock Div)
_io_iface->poke8(0x01D, 0x01); // AuxADC Setup (Decimation/Enable)
@@ -1554,17 +1658,18 @@ void ad9361_device_t::initialize()
_program_mixer_gm_subtable();
_program_gain_table();
- _setup_gain_control();
+ _setup_gain_control(false);
- _calibrate_baseband_rx_analog_filter();
- _calibrate_baseband_tx_analog_filter();
- _calibrate_rx_TIAs();
- _calibrate_secondary_tx_filter();
+ set_bw_filter(RX, _baseband_bw);
+ set_bw_filter(TX, _baseband_bw);
_setup_adc();
+ _calibrate_baseband_dc_offset();
+ _calibrate_rf_dc_offset();
_calibrate_tx_quadrature();
_calibrate_rx_quadrature();
+ _configure_bb_rf_dc_tracking(_use_dc_offset_correction);
// cals done, set PPORT config
switch (_client_params->get_digital_interface_mode()) {
@@ -1677,18 +1782,19 @@ double ad9361_device_t::set_clock_rate(const double req_rate)
_program_mixer_gm_subtable();
_program_gain_table();
- _setup_gain_control();
+ _setup_gain_control(false);
_reprogram_gains();
- _calibrate_baseband_rx_analog_filter();
- _calibrate_baseband_tx_analog_filter();
- _calibrate_rx_TIAs();
- _calibrate_secondary_tx_filter();
+ set_bw_filter(RX, _baseband_bw);
+ set_bw_filter(TX, _baseband_bw);
_setup_adc();
+ _calibrate_baseband_dc_offset();
+ _calibrate_rf_dc_offset();
_calibrate_tx_quadrature();
_calibrate_rx_quadrature();
+ _configure_bb_rf_dc_tracking(_use_dc_offset_correction);
// cals done, set PPORT config
switch (_client_params->get_digital_interface_mode()) {
@@ -1840,9 +1946,16 @@ double ad9361_device_t::tune(direction_t direction, const double value)
/* Update the gain settings. */
_reprogram_gains();
- /* Run the calibration algorithms. */
- _calibrate_tx_quadrature();
- _calibrate_rx_quadrature();
+ /* Only run the following calibrations if we are more than 100MHz away
+ * from the previous calibration point. */
+ if (std::abs(_last_calibration_freq - tune_freq) > AD9361_CAL_VALID_WINDOW) {
+ /* Run the calibration algorithms. */
+ _calibrate_rf_dc_offset();
+ _calibrate_tx_quadrature();
+ _calibrate_rx_quadrature();
+ _configure_bb_rf_dc_tracking(_use_dc_offset_correction);
+ _last_calibration_freq = tune_freq;
+ }
/* If we were in the FDD state, return it now. */
if (not_in_alert) {
@@ -1946,4 +2059,678 @@ double ad9361_device_t::get_rssi(chain_t chain)
return rssi;
}
+/*
+ * Returns the reading of the internal temperature sensor.
+ * One point calibration of the sensor was done according to datasheet
+ * leading to the given default constant correction factor.
+ */
+double ad9361_device_t::_get_temperature(const double cal_offset, const double timeout)
+{
+ //set 0x01D[0] to 1 to disable AuxADC GPIO reading
+ boost::uint8_t tmp = 0;
+ tmp = _io_iface->peek8(0x01D);
+ _io_iface->poke8(0x01D, (tmp | 0x01));
+ _io_iface->poke8(0x00B, 0); //set offset to 0
+
+ _io_iface->poke8(0x00C, 0x01); //start reading, clears bit 0x00C[1]
+ boost::posix_time::ptime start_time = boost::posix_time::microsec_clock::local_time();
+ boost::posix_time::time_duration elapsed;
+ //wait for valid data (toggle of bit 1 in 0x00C)
+ while(((_io_iface->peek8(0x00C) >> 1) & 0x01) == 0) {
+ boost::this_thread::sleep(boost::posix_time::microseconds(100));
+ elapsed = boost::posix_time::microsec_clock::local_time() - start_time;
+ if(elapsed.total_milliseconds() > (timeout*1000))
+ {
+ throw uhd::runtime_error("[ad9361_device_t] timeout while reading temperature");
+ }
+ }
+ _io_iface->poke8(0x00C, 0x00); //clear read flag
+
+ boost::uint8_t temp = _io_iface->peek8(0x00E); //read temperature.
+ double tmp_temp = temp/1.140f; //according to ADI driver
+ tmp_temp = tmp_temp + cal_offset; //Constant offset acquired by one point calibration.
+
+ return tmp_temp;
+}
+
+double ad9361_device_t::get_average_temperature(const double cal_offset, const size_t num_samples)
+{
+ double d_temp = 0;
+ for(size_t i = 0; i < num_samples; i++) {
+ double tmp_temp = _get_temperature(cal_offset);
+ d_temp += (tmp_temp/num_samples);
+ }
+ return d_temp;
+}
+
+void ad9361_device_t::set_dc_offset_auto(direction_t direction, const bool on)
+{
+ if(direction == RX)
+ {
+ _use_dc_offset_correction = on;
+ _configure_bb_rf_dc_tracking(_use_dc_offset_correction);
+ if(on)
+ {
+ _io_iface->poke8(0x182, (_io_iface->peek8(0x182) & (~((1 << 7) | (1 << 6) | (1 << 3) | (1 << 2))))); //Clear force bits
+ //Do a single shot DC offset cal before enabling tracking (Not possible if not in ALERT state. Is it necessary?)
+ } else {
+ //clear current config values
+ _io_iface->poke8(0x182, (_io_iface->peek8(0x182) | ((1 << 7) | (1 << 6) | (1 << 3) | (1 << 2)))); //Set input A and input B&C force enable bits
+ _io_iface->poke8(0x174, 0x00);
+ _io_iface->poke8(0x175, 0x00);
+ _io_iface->poke8(0x176, 0x00);
+ _io_iface->poke8(0x177, 0x00);
+ _io_iface->poke8(0x178, 0x00);
+ _io_iface->poke8(0x17D, 0x00);
+ _io_iface->poke8(0x17E, 0x00);
+ _io_iface->poke8(0x17F, 0x00);
+ _io_iface->poke8(0x180, 0x00);
+ _io_iface->poke8(0x181, 0x00);
+ }
+ } else {
+ // DC offset is removed during TX quad cal
+ throw uhd::runtime_error("[ad9361_device_t] [set_iq_balance_auto] INVALID_CODE_PATH");
+ }
+}
+
+void ad9361_device_t::set_iq_balance_auto(direction_t direction, const bool on)
+{
+ if(direction == RX)
+ {
+ _use_iq_balance_correction = on;
+ if(on)
+ {
+ //disable force registers and enable tracking
+ _io_iface->poke8(0x182, (_io_iface->peek8(0x182) & (~ ( (1<<1) | (1<<0) | (1<<5) | (1<<4) ))));
+ _calibrate_rx_quadrature();
+ } else {
+ //disable IQ tracking
+ _io_iface->poke8(0x169, 0xc0);
+ //clear current config values
+ _io_iface->poke8(0x182, (_io_iface->peek8(0x182) | ((1 << 1) | (1 << 0) | (1 << 5) | (1 << 4)))); //Set Rx2 input B&C force enable bit
+ _io_iface->poke8(0x17B, 0x00);
+ _io_iface->poke8(0x17C, 0x00);
+ _io_iface->poke8(0x179, 0x00);
+ _io_iface->poke8(0x17A, 0x00);
+ _io_iface->poke8(0x170, 0x00);
+ _io_iface->poke8(0x171, 0x00);
+ _io_iface->poke8(0x172, 0x00);
+ _io_iface->poke8(0x173, 0x00);
+ }
+ } else {
+ throw uhd::runtime_error("[ad9361_device_t] [set_iq_balance_auto] INVALID_CODE_PATH");
+ }
+}
+
+/* Sets the RX gain mode to be used.
+ * If a transition from an AGC to an non AGC mode occurs (or vice versa)
+ * the gain configuration will be reloaded. */
+void ad9361_device_t::_setup_agc(chain_t chain, gain_mode_t gain_mode)
+{
+ boost::uint8_t gain_mode_reg = 0;
+ boost::uint8_t gain_mode_prev = 0;
+ boost::uint8_t gain_mode_bits_pos = 0;
+
+ gain_mode_reg = _io_iface->peek8(0x0FA);
+ gain_mode_prev = (gain_mode_reg & 0x0F);
+
+ if (chain == CHAIN_1) {
+ gain_mode_bits_pos = 0;
+ } else if (chain == CHAIN_2) {
+ gain_mode_bits_pos = 2;
+ } else
+ {
+ throw uhd::runtime_error("[ad9361_device_t] Wrong value for chain");
+ }
+
+ gain_mode_reg = (gain_mode_reg & (~(0x03<<gain_mode_bits_pos))); //clear mode bits
+ switch (gain_mode) {
+ case GAIN_MODE_MANUAL:
+ //leave bits cleared
+ break;
+ case GAIN_MODE_SLOW_AGC:
+ gain_mode_reg = (gain_mode_reg | (0x02<<gain_mode_bits_pos));
+ break;
+ case GAIN_MODE_FAST_AGC:
+ gain_mode_reg = (gain_mode_reg | (0x01<<gain_mode_bits_pos));
+ break;
+ default:
+ throw uhd::runtime_error("[ad9361_device_t] Gain mode does not exist");
+ }
+ _io_iface->poke8(0x0FA, gain_mode_reg);
+ boost::uint8_t gain_mode_status = _io_iface->peek8(0x0FA);
+ gain_mode_status = (gain_mode_status & 0x0F);
+ /*Check if gain mode configuration needs to be reprogrammed*/
+ if (((gain_mode_prev == 0) && (gain_mode_status != 0)) || ((gain_mode_prev != 0) && (gain_mode_status == 0))) {
+ if (gain_mode_status == 0) {
+ /*load manual mode config*/
+ _setup_gain_control(false);
+ } else {
+ /*load agc mode config*/
+ _setup_gain_control(true);
+ }
+ }
+}
+
+void ad9361_device_t::set_agc(chain_t chain, bool enable)
+{
+ if(chain == CHAIN_1) {
+ _rx1_agc_enable = enable;
+ if(enable) {
+ _setup_agc(chain, _rx1_agc_mode);
+ } else {
+ _setup_agc(chain, GAIN_MODE_MANUAL);
+ }
+ } else if (chain == CHAIN_2){
+ _rx2_agc_enable = enable;
+ if(enable) {
+ _setup_agc(chain, _rx2_agc_mode);
+ } else {
+ _setup_agc(chain, GAIN_MODE_MANUAL);
+ }
+ } else
+ {
+ throw uhd::runtime_error("[ad9361_device_t] Wrong value for chain");
+ }
+}
+
+void ad9361_device_t::set_agc_mode(chain_t chain, gain_mode_t gain_mode)
+{
+ if(chain == CHAIN_1) {
+ _rx1_agc_mode = gain_mode;
+ if(_rx1_agc_enable) {
+ _setup_agc(chain, _rx1_agc_mode);
+ }
+ } else if(chain == CHAIN_2){
+ _rx2_agc_mode = gain_mode;
+ if(_rx2_agc_enable) {
+ _setup_agc(chain, _rx2_agc_mode);
+ }
+ } else
+ {
+ throw uhd::runtime_error("[ad9361_device_t] Wrong value for chain");
+ }
+}
+
+std::vector<std::string> ad9361_device_t::get_filter_names(direction_t direction)
+{
+ std::vector<std::string> ret;
+ if(direction == RX) {
+ for(std::map<std::string, filter_query_helper>::iterator it = _rx_filters.begin(); it != _rx_filters.end(); ++it) {
+ ret.push_back(it->first);
+ }
+ } else if (direction == TX)
+ {
+ for(std::map<std::string, filter_query_helper>::iterator it = _tx_filters.begin(); it != _tx_filters.end(); ++it) {
+ ret.push_back(it->first);
+ }
+ }
+ return ret;
+}
+
+filter_info_base::sptr ad9361_device_t::get_filter(direction_t direction, chain_t chain, const std::string &name)
+{
+ if(direction == RX) {
+ if (not _rx_filters[name].get)
+ {
+ throw uhd::runtime_error("ad9361_device_t::get_filter this filter can not be read.");
+ }
+ return _rx_filters[name].get(direction, chain);
+ } else if (direction == TX) {
+ if (not _tx_filters[name].get)
+ {
+ throw uhd::runtime_error("ad9361_device_t::get_filter this filter can not be read.");
+ }
+ return _tx_filters[name].get(direction, chain);
+ }
+
+ throw uhd::runtime_error("ad9361_device_t::get_filter wrong direction parameter.");
+}
+
+void ad9361_device_t::set_filter(direction_t direction, chain_t chain, const std::string &name, filter_info_base::sptr filter)
+{
+
+ if(direction == RX) {
+ if(not _rx_filters[name].set)
+ {
+ throw uhd::runtime_error("ad9361_device_t::set_filter this filter can not be written.");
+ }
+ _rx_filters[name].set(direction, chain, filter);
+ } else if (direction == TX) {
+ if(not _tx_filters[name].set)
+ {
+ throw uhd::runtime_error("ad9361_device_t::set_filter this filter can not be written.");
+ }
+ _tx_filters[name].set(direction, chain, filter);
+ }
+
+}
+
+double ad9361_device_t::set_bw_filter(direction_t direction, const double rf_bw)
+{
+ //both low pass filters are programmed to the same bw. However, their cutoffs will differ.
+ //Together they should create the requested bb bw.
+ double set_analog_bb_bw = 0;
+ if(direction == RX)
+ {
+ _rx_bb_lp_bw = _calibrate_baseband_rx_analog_filter(rf_bw); //returns bb bw
+ _rx_tia_lp_bw = _calibrate_rx_TIAs(rf_bw);
+ _rx_analog_bw = _rx_bb_lp_bw;
+ set_analog_bb_bw = _rx_analog_bw;
+ } else {
+ _tx_bb_lp_bw = _calibrate_baseband_tx_analog_filter(rf_bw); //returns bb bw
+ _tx_sec_lp_bw = _calibrate_secondary_tx_filter(rf_bw);
+ _tx_analog_bw = _tx_bb_lp_bw;
+ set_analog_bb_bw = _tx_analog_bw;
+ }
+ return (2.0 * set_analog_bb_bw);
+}
+
+void ad9361_device_t::_set_fir_taps(direction_t direction, chain_t chain, const std::vector<boost::int16_t>& taps)
+{
+ size_t num_taps = taps.size();
+ size_t num_taps_avail = _get_num_fir_taps(direction);
+ if(num_taps == num_taps_avail)
+ {
+ boost::scoped_array<boost::uint16_t> coeffs(new boost::uint16_t[num_taps_avail]);
+ for (size_t i = 0; i < num_taps_avail; i++)
+ {
+ coeffs[i] = boost::uint16_t(taps[i]);
+ }
+ _program_fir_filter(direction, chain, num_taps_avail, coeffs.get());
+ } else if(num_taps < num_taps_avail){
+ throw uhd::runtime_error("ad9361_device_t::_set_fir_taps not enough coefficients.");
+ } else {
+ throw uhd::runtime_error("ad9361_device_t::_set_fir_taps too many coefficients.");
+ }
+}
+
+size_t ad9361_device_t::_get_num_fir_taps(direction_t direction)
+{
+ boost::uint8_t num = 0;
+ if(direction == RX)
+ num = _io_iface->peek8(0x0F5);
+ else
+ num = _io_iface->peek8(0x065);
+ num = ((num >> 5) & 0x07);
+ return ((num + 1) * 16);
+}
+
+size_t ad9361_device_t::_get_fir_dec_int(direction_t direction)
+{
+ boost::uint8_t dec_int = 0;
+ if(direction == RX)
+ dec_int = _io_iface->peek8(0x003);
+ else
+ dec_int = _io_iface->peek8(0x002);
+ /*
+ * 0 = dec/int by 1 and bypass filter
+ * 1 = dec/int by 1
+ * 2 = dec/int by 2
+ * 3 = dec/int by 4 */
+ dec_int = (dec_int & 0x03);
+ if(dec_int == 3)
+ {
+ return 4;
+ }
+ return dec_int;
+}
+
+std::vector<boost::int16_t> ad9361_device_t::_get_fir_taps(direction_t direction, chain_t chain)
+{
+ int base;
+ size_t num_taps = _get_num_fir_taps(direction);
+ boost::uint8_t config;
+ boost::uint8_t reg_numtaps = (((num_taps / 16) - 1) & 0x07) << 5;
+ config = reg_numtaps | 0x02; //start the programming clock
+
+ if(chain == CHAIN_1)
+ {
+ config = config | (1 << 3);
+ } else if (chain == CHAIN_2){
+ config = config | (1 << 4);
+ } else {
+ throw uhd::runtime_error("[ad9361_device_t] Can not read both chains synchronously");
+ }
+
+ if(direction == RX)
+ {
+ base = 0xF0;
+ } else {
+ base = 0x60;
+ }
+
+ _io_iface->poke8(base+5,config);
+
+ std::vector<boost::int16_t> taps;
+ boost::uint8_t lower_val;
+ boost::uint8_t higher_val;
+ boost::uint16_t coeff;
+ for(size_t i = 0;i < num_taps;i++)
+ {
+ _io_iface->poke8(base,0x00+i);
+ lower_val = _io_iface->peek8(base+3);
+ higher_val = _io_iface->peek8(base+4);
+ coeff = ((higher_val << 8) | lower_val);
+ taps.push_back(boost::int16_t(coeff));
+ }
+
+ config = (config & (~(1 << 1))); //disable filter clock
+ _io_iface->poke8(base+5,config);
+ return taps;
+}
+
+/*
+ * Returns either RX TIA LPF or TX Secondary LPF
+ * depending on the direction.
+ * See UG570 for details on used scaling factors. */
+filter_info_base::sptr ad9361_device_t::_get_filter_lp_tia_sec(direction_t direction)
+{
+ double cutoff = 0;
+
+ if(direction == RX)
+ {
+ cutoff = 2.5 * _rx_tia_lp_bw;
+ } else {
+ cutoff = 5 * _tx_sec_lp_bw;
+ }
+
+ filter_info_base::sptr lp(new analog_filter_lp(filter_info_base::ANALOG_LOW_PASS, false, 0, "single-pole", cutoff, 20));
+ return lp;
+}
+
+/*
+ * Returns RX/TX BB LPF.
+ * See UG570 for details on used scaling factors. */
+filter_info_base::sptr ad9361_device_t::_get_filter_lp_bb(direction_t direction)
+{
+ double cutoff = 0;
+ if(direction == RX)
+ {
+ cutoff = 1.4 * _rx_bb_lp_bw;
+ } else {
+ cutoff = 1.6 * _tx_bb_lp_bw;
+ }
+
+ filter_info_base::sptr bb_lp(new analog_filter_lp(filter_info_base::ANALOG_LOW_PASS, false, 1, "third-order Butterworth", cutoff, 60));
+ return bb_lp;
+}
+
+/*
+ * For RX direction the DEC3 is returned.
+ * For TX direction the INT3 is returned. */
+filter_info_base::sptr ad9361_device_t::_get_filter_dec_int_3(direction_t direction)
+{
+ boost::uint8_t enable = 0;
+ double rate = _adcclock_freq;
+ double full_scale;
+ size_t dec = 0;
+ size_t interpol = 0;
+ filter_info_base::filter_type type = filter_info_base::DIGITAL_I16;
+ std::string name;
+ boost::int16_t taps_array_rx[] = {55, 83, 0, -393, -580, 0, 1914, 4041, 5120, 4041, 1914, 0, -580, -393, 0, 83, 55};
+ boost::int16_t taps_array_tx[] = {36, -19, 0, -156, -12, 0, 479, 233, 0, -1215, -993, 0, 3569, 6277, 8192, 6277, 3569, 0, -993, -1215, 0, 223, 479, 0, -12, -156, 0, -19, 36};
+ std::vector<boost::int16_t> taps;
+
+ filter_info_base::sptr ret;
+
+ if(direction == RX)
+ {
+ full_scale = 16384;
+ dec = 3;
+ interpol = 1;
+
+ enable = _io_iface->peek8(0x003);
+ enable = ((enable >> 4) & 0x03);
+ taps.assign(taps_array_rx, taps_array_rx + sizeof(taps_array_rx) / sizeof(boost::int16_t) );
+
+ } else {
+ full_scale = 8192;
+ dec = 1;
+ interpol = 3;
+
+ boost::uint8_t use_dac_clk_div = _io_iface->peek8(0x00A);
+ use_dac_clk_div = ((use_dac_clk_div >> 3) & 0x01);
+ if(use_dac_clk_div == 1)
+ {
+ rate = rate / 2;
+ }
+
+ enable = _io_iface->peek8(0x002);
+ enable = ((enable >> 4) & 0x03);
+ if(enable == 2) //0 => int. by 1, 1 => int. by 2 (HB3), 2 => int. by 3
+ {
+ rate /= 3;
+ }
+
+ taps.assign(taps_array_tx, taps_array_tx + sizeof(taps_array_tx) / sizeof(boost::int16_t) );
+ }
+
+ ret = filter_info_base::sptr(new digital_filter_base<boost::int16_t>(type, (enable != 2) ? true : false, 2, rate, interpol, dec, full_scale, taps.size(), taps));
+ return ret;
+}
+
+filter_info_base::sptr ad9361_device_t::_get_filter_hb_3(direction_t direction)
+{
+ boost::uint8_t enable = 0;
+ double rate = _adcclock_freq;
+ double full_scale = 0;
+ size_t dec = 1;
+ size_t interpol = 1;
+ filter_info_base::filter_type type = filter_info_base::DIGITAL_I16;
+ boost::int16_t taps_array_rx[] = {1, 4, 6, 4, 1};
+ boost::int16_t taps_array_tx[] = {1, 2, 1};
+ std::vector<boost::int16_t> taps;
+
+ if(direction == RX)
+ {
+ full_scale = 16;
+ dec = 2;
+
+ enable = _io_iface->peek8(0x003);
+ enable = ((enable >> 4) & 0x03);
+ taps.assign(taps_array_rx, taps_array_rx + sizeof(taps_array_rx) / sizeof(boost::int16_t) );
+ } else {
+ full_scale = 2;
+ interpol = 2;
+
+ boost::uint8_t use_dac_clk_div = _io_iface->peek8(0x00A);
+ use_dac_clk_div = ((use_dac_clk_div >> 3) & 0x01);
+ if(use_dac_clk_div == 1)
+ {
+ rate = rate / 2;
+ }
+
+ enable = _io_iface->peek8(0x002);
+ enable = ((enable >> 4) & 0x03);
+ if(enable == 1)
+ {
+ rate /= 2;
+ }
+ taps.assign(taps_array_tx, taps_array_tx + sizeof(taps_array_tx) / sizeof(boost::int16_t) );
+ }
+
+ filter_info_base::sptr hb = filter_info_base::sptr(new digital_filter_base<boost::int16_t>(type, (enable != 1) ? true : false, 2, rate, interpol, dec, full_scale, taps.size(), taps));
+ return hb;
+}
+
+filter_info_base::sptr ad9361_device_t::_get_filter_hb_2(direction_t direction)
+{
+ boost::uint8_t enable = 0;
+ double rate = _adcclock_freq;
+ double full_scale = 0;
+ size_t dec = 1;
+ size_t interpol = 1;
+ filter_info_base::filter_type type = filter_info_base::DIGITAL_I16;
+ boost::int16_t taps_array[] = {-9, 0, 73, 128, 73, 0, -9};
+ std::vector<boost::int16_t> taps(taps_array, taps_array + sizeof(taps_array) / sizeof(boost::int16_t) );
+
+ digital_filter_base<boost::int16_t>::sptr hb_3 = boost::dynamic_pointer_cast<digital_filter_base<boost::int16_t> >(_get_filter_hb_3(direction));
+ digital_filter_base<boost::int16_t>::sptr dec_int_3 = boost::dynamic_pointer_cast<digital_filter_base<boost::int16_t> >(_get_filter_dec_int_3(direction));
+
+ if(direction == RX)
+ {
+ full_scale = 256;
+ dec = 2;
+ enable = _io_iface->peek8(0x003);
+ } else {
+ full_scale = 128;
+ interpol = 2;
+ enable = _io_iface->peek8(0x002);
+ }
+
+ enable = ((enable >> 3) & 0x01);
+
+ if(!(hb_3->is_bypassed()))
+ {
+ if(direction == RX)
+ {
+ rate = hb_3->get_output_rate();
+ }else if (direction == TX) {
+ rate = hb_3->get_input_rate();
+ if(enable)
+ {
+ rate /= 2;
+ }
+ }
+ } else { //else dec3/int3 or none of them is used.
+ if(direction == RX)
+ {
+ rate = dec_int_3->get_output_rate();
+ }else if (direction == TX) {
+ rate = dec_int_3->get_input_rate();
+ if(enable)
+ {
+ rate /= 2;
+ }
+ }
+ }
+
+ filter_info_base::sptr hb(new digital_filter_base<boost::int16_t>(type, (enable == 0) ? true : false, 3, rate, interpol, dec, full_scale, taps.size(), taps));
+ return hb;
+}
+
+filter_info_base::sptr ad9361_device_t::_get_filter_hb_1(direction_t direction)
+{
+ boost::uint8_t enable = 0;
+ double rate = 0;
+ double full_scale = 0;
+ size_t dec = 1;
+ size_t interpol = 1;
+ filter_info_base::filter_type type = filter_info_base::DIGITAL_I16;
+
+ std::vector<boost::int16_t> taps;
+ boost::int16_t taps_rx_array[] = {-8, 0, 42, 0, -147, 0, 619, 1013, 619, 0, -147, 0, 42, 0, -8};
+ boost::int16_t taps_tx_array[] = {-53, 0, 313, 0, -1155, 0, 4989, 8192, 4989, 0, -1155, 0, 313, 0, -53};
+
+ digital_filter_base<boost::int16_t>::sptr hb_2 = boost::dynamic_pointer_cast<digital_filter_base<boost::int16_t> >(_get_filter_hb_2(direction));
+
+ if(direction == RX)
+ {
+ full_scale = 2048;
+ dec = 2;
+ enable = _io_iface->peek8(0x003);
+ enable = ((enable >> 2) & 0x01);
+ rate = hb_2->get_output_rate();
+ taps.assign(taps_rx_array, taps_rx_array + sizeof(taps_rx_array) / sizeof(boost::int16_t) );
+ } else if (direction == TX) {
+ full_scale = 8192;
+ interpol = 2;
+ enable = _io_iface->peek8(0x002);
+ enable = ((enable >> 2) & 0x01);
+ rate = hb_2->get_input_rate();
+ if(enable)
+ {
+ rate /= 2;
+ }
+ taps.assign(taps_tx_array, taps_tx_array + sizeof(taps_tx_array) / sizeof(boost::int16_t) );
+ }
+
+ filter_info_base::sptr hb(new digital_filter_base<boost::int16_t>(type, (enable == 0) ? true : false, 4, rate, interpol, dec, full_scale, taps.size(), taps));
+ return hb;
+}
+
+filter_info_base::sptr ad9361_device_t::_get_filter_fir(direction_t direction, chain_t chain)
+{
+ double rate = 0;
+ size_t dec = 1;
+ size_t interpol = 1;
+ size_t max_num_taps = 128;
+ boost::uint8_t enable = 1;
+
+ digital_filter_base<boost::int16_t>::sptr hb_1 = boost::dynamic_pointer_cast<digital_filter_base<boost::int16_t> >(_get_filter_hb_1(direction));
+
+ if(direction == RX)
+ {
+ dec = _get_fir_dec_int(direction);
+ if(dec == 0)
+ {
+ enable = 0;
+ dec = 1;
+ }
+ interpol = 1;
+ rate = hb_1->get_output_rate();
+ }else if (direction == TX) {
+ interpol = _get_fir_dec_int(direction);
+ if(interpol == 0)
+ {
+ enable = 0;
+ interpol = 1;
+ }
+ dec = 1;
+ rate = hb_1->get_input_rate();
+ if(enable)
+ {
+ rate /= interpol;
+ }
+ }
+ max_num_taps = _get_num_fir_taps(direction);
+
+ filter_info_base::sptr fir(new digital_filter_fir<boost::int16_t>(filter_info_base::DIGITAL_FIR_I16, (enable == 0) ? true : false, 5, rate, interpol, dec, 32767, max_num_taps, _get_fir_taps(direction, chain)));
+
+ return fir;
+}
+
+void ad9361_device_t::_set_filter_fir(direction_t direction, chain_t channel, filter_info_base::sptr filter)
+{
+ digital_filter_fir<boost::int16_t>::sptr fir = boost::dynamic_pointer_cast<digital_filter_fir<boost::int16_t> >(filter);
+ //only write taps. Ignore everything else for now
+ _set_fir_taps(direction, channel, fir->get_taps());
+}
+
+/*
+ * If BW of one of the analog filters gets overwritten manually,
+ * _tx_analog_bw and _rx_analog_bw are not valid any more!
+ * For useful data in those variables set_bw_filter method should be used
+ */
+void ad9361_device_t::_set_filter_lp_bb(direction_t direction, filter_info_base::sptr filter)
+{
+ analog_filter_lp::sptr lpf = boost::dynamic_pointer_cast<analog_filter_lp>(filter);
+ double bw = lpf->get_cutoff();
+ if(direction == RX)
+ {
+ //remember: this function takes rf bw as its input and calibrated to 1.4 x the given value
+ _rx_bb_lp_bw = _calibrate_baseband_rx_analog_filter(2 * bw / 1.4); //returns bb bw
+
+ } else {
+ //remember: this function takes rf bw as its input and calibrates to 1.6 x the given value
+ _tx_bb_lp_bw = _calibrate_baseband_tx_analog_filter(2 * bw / 1.6);
+ }
+}
+
+void ad9361_device_t::_set_filter_lp_tia_sec(direction_t direction, filter_info_base::sptr filter)
+{
+ analog_filter_lp::sptr lpf = boost::dynamic_pointer_cast<analog_filter_lp>(filter);
+ double bw = lpf->get_cutoff();
+ if(direction == RX)
+ {
+ //remember: this function takes rf bw as its input and calibrated to 2.5 x the given value
+ _rx_tia_lp_bw = _calibrate_rx_TIAs(2 * bw / 2.5); //returns bb bw
+
+ } else {
+ //remember: this function takes rf bw as its input and calibrates to 5 x the given value
+ _tx_sec_lp_bw = _calibrate_secondary_tx_filter(2 * bw / 5);
+ }
+}
+
}}
diff --git a/host/lib/usrp/common/ad9361_driver/ad9361_device.h b/host/lib/usrp/common/ad9361_driver/ad9361_device.h
index ca83f3037..a242f35e9 100644
--- a/host/lib/usrp/common/ad9361_driver/ad9361_device.h
+++ b/host/lib/usrp/common/ad9361_driver/ad9361_device.h
@@ -8,6 +8,14 @@
#include <ad9361_client.h>
#include <boost/noncopyable.hpp>
#include <boost/thread/recursive_mutex.hpp>
+#include <uhd/types/filters.hpp>
+#include <uhd/types/sensors.hpp>
+#include <complex>
+#include <vector>
+#include <map>
+#include "boost/assign.hpp"
+#include "boost/bind.hpp"
+#include "boost/function.hpp"
namespace uhd { namespace usrp {
@@ -15,10 +23,34 @@ class ad9361_device_t : public boost::noncopyable
{
public:
enum direction_t { RX, TX };
- enum chain_t { CHAIN_1, CHAIN_2 };
+ enum gain_mode_t {GAIN_MODE_MANUAL, GAIN_MODE_SLOW_AGC, GAIN_MODE_FAST_AGC};
+ enum chain_t { CHAIN_1, CHAIN_2, CHAIN_BOTH };
ad9361_device_t(ad9361_params::sptr client, ad9361_io::sptr io_iface) :
- _client_params(client), _io_iface(io_iface) {}
+ _client_params(client), _io_iface(io_iface) {
+
+ _rx_filters = boost::assign::map_list_of("LPF_TIA", filter_query_helper(boost::bind(&ad9361_device_t::_get_filter_lp_tia_sec, this, _1),
+ boost::bind(&ad9361_device_t::_set_filter_lp_tia_sec, this, _1, _3)))
+ ("LPF_BB", filter_query_helper(boost::bind(&ad9361_device_t::_get_filter_lp_bb, this, _1),
+ boost::bind(&ad9361_device_t::_set_filter_lp_bb, this, _1, _3)))
+ ("HB_3", filter_query_helper(boost::bind(&ad9361_device_t::_get_filter_hb_3, this, _1), 0))
+ ("DEC_3", filter_query_helper(boost::bind(&ad9361_device_t::_get_filter_dec_int_3, this, _1), 0))
+ ("HB_2", filter_query_helper(boost::bind(&ad9361_device_t::_get_filter_hb_2, this, _1), 0))
+ ("HB_1", filter_query_helper(boost::bind(&ad9361_device_t::_get_filter_hb_1, this, _1), 0))
+ ("FIR_1", filter_query_helper(boost::bind(&ad9361_device_t::_get_filter_fir, this, _1, _2),
+ boost::bind(&ad9361_device_t::_set_filter_fir, this, _1, _2, _3)));
+
+ _tx_filters = boost::assign::map_list_of("LPF_SECONDARY", filter_query_helper(boost::bind(&ad9361_device_t::_get_filter_lp_tia_sec, this, _1),
+ boost::bind(&ad9361_device_t::_set_filter_lp_tia_sec, this, _1, _3)))
+ ("LPF_BB", filter_query_helper(boost::bind(&ad9361_device_t::_get_filter_lp_bb, this, _1),
+ boost::bind(&ad9361_device_t::_set_filter_lp_bb, this, _1, _3)))
+ ("HB_3", filter_query_helper(boost::bind(&ad9361_device_t::_get_filter_hb_3, this, _1), 0))
+ ("INT_3", filter_query_helper(boost::bind(&ad9361_device_t::_get_filter_dec_int_3, this, _1), 0))
+ ("HB_2", filter_query_helper(boost::bind(&ad9361_device_t::_get_filter_hb_2, this, _1), 0))
+ ("HB_1", filter_query_helper(boost::bind(&ad9361_device_t::_get_filter_hb_1, this, _1), 0))
+ ("FIR_1", filter_query_helper(boost::bind(&ad9361_device_t::_get_filter_fir, this, _1, _2),
+ boost::bind(&ad9361_device_t::_set_filter_fir, this, _1, _2, _3)));
+ }
/* Initialize the AD9361 codec. */
void initialize();
@@ -66,21 +98,56 @@ public:
/* Read back the internal RSSI measurement data. */
double get_rssi(chain_t chain);
+ /*! Read the internal temperature sensor
+ *\param calibrate return raw sensor readings or apply calibration factor.
+ *\param num_samples number of measurements to average over
+ */
+ double get_average_temperature(const double cal_offset = -30.0, const size_t num_samples = 3);
+
+ /* Turn on/off AD9361's RX DC offset correction */
+ void set_dc_offset_auto(direction_t direction, const bool on);
+
+ /* Turn on/off AD9361's RX IQ imbalance correction */
+ void set_iq_balance_auto(direction_t direction, const bool on);
+
+ /* Configure AD9361's AGC module to use either fast or slow AGC mode. */
+ void set_agc_mode(chain_t chain, gain_mode_t gain_mode);
+
+ /* Enable AD9361's AGC gain mode. */
+ void set_agc(chain_t chain, bool enable);
+
+ /* Set bandwidth of AD9361's analog LP filters.
+ * Bandwidth should be RF bandwidth */
+ double set_bw_filter(direction_t direction, const double rf_bw);
+
+ /*
+ * Filter API implementation
+ * */
+ filter_info_base::sptr get_filter(direction_t direction, chain_t chain, const std::string &name);
+
+ void set_filter(direction_t direction, chain_t chain, const std::string &name, filter_info_base::sptr filter);
+
+ std::vector<std::string> get_filter_names(direction_t direction);
+
//Constants
static const double AD9361_MAX_GAIN;
static const double AD9361_MAX_CLOCK_RATE;
static const double AD9361_RECOMMENDED_MAX_CLOCK_RATE;
+ static const double AD9361_CAL_VALID_WINDOW;
private: //Methods
void _program_fir_filter(direction_t direction, int num_taps, boost::uint16_t *coeffs);
void _setup_tx_fir(size_t num_taps, boost::int32_t interpolation);
void _setup_rx_fir(size_t num_taps, boost::int32_t decimation);
+ void _program_fir_filter(direction_t direction, chain_t chain, int num_taps, boost::uint16_t *coeffs);
+ void _setup_tx_fir(size_t num_taps);
+ void _setup_rx_fir(size_t num_taps);
void _calibrate_lock_bbpll();
void _calibrate_synth_charge_pumps();
- double _calibrate_baseband_rx_analog_filter();
- double _calibrate_baseband_tx_analog_filter();
- void _calibrate_secondary_tx_filter();
- void _calibrate_rx_TIAs();
+ double _calibrate_baseband_rx_analog_filter(double rfbw);
+ double _calibrate_baseband_tx_analog_filter(double rfbw);
+ double _calibrate_secondary_tx_filter(double rfbw);
+ double _calibrate_rx_TIAs(double rfbw);
void _setup_adc();
void _calibrate_baseband_dc_offset();
void _calibrate_rf_dc_offset();
@@ -89,12 +156,29 @@ private: //Methods
void _calibrate_tx_quadrature();
void _program_mixer_gm_subtable();
void _program_gain_table();
- void _setup_gain_control();
+ void _setup_gain_control(bool use_agc);
void _setup_synth(direction_t direction, double vcorate);
double _tune_bbvco(const double rate);
void _reprogram_gains();
double _tune_helper(direction_t direction, const double value);
double _setup_rates(const double rate);
+ double _get_temperature(const double cal_offset, const double timeout = 0.1);
+ void _configure_bb_rf_dc_tracking(const bool on);
+ void _setup_agc(chain_t chain, gain_mode_t gain_mode);
+ void _set_fir_taps(direction_t direction, chain_t chain, const std::vector<boost::int16_t>& taps);
+ std::vector<boost::int16_t> _get_fir_taps(direction_t direction, chain_t chain);
+ size_t _get_num_fir_taps(direction_t direction);
+ size_t _get_fir_dec_int(direction_t direction);
+ filter_info_base::sptr _get_filter_lp_tia_sec(direction_t direction);
+ filter_info_base::sptr _get_filter_lp_bb(direction_t direction);
+ filter_info_base::sptr _get_filter_dec_int_3(direction_t direction);
+ filter_info_base::sptr _get_filter_hb_3(direction_t direction);
+ filter_info_base::sptr _get_filter_hb_2(direction_t direction);
+ filter_info_base::sptr _get_filter_hb_1(direction_t direction);
+ filter_info_base::sptr _get_filter_fir(direction_t direction, chain_t chain);
+ void _set_filter_fir(direction_t direction, chain_t channel, filter_info_base::sptr filter);
+ void _set_filter_lp_bb(direction_t direction, filter_info_base::sptr filter);
+ void _set_filter_lp_tia_sec(direction_t direction, filter_info_base::sptr filter);
private: //Members
typedef struct {
@@ -107,22 +191,45 @@ private: //Members
boost::uint8_t bbftune_mode;
} chip_regs_t;
+ struct filter_query_helper
+ {
+ filter_query_helper(
+ boost::function<filter_info_base::sptr (direction_t, chain_t)> p_get,
+ boost::function<void (direction_t, chain_t, filter_info_base::sptr)> p_set
+ ) : get(p_get), set(p_set) { }
+
+ filter_query_helper(){ }
+
+ boost::function<filter_info_base::sptr (direction_t, chain_t)> get;
+ boost::function<void (direction_t, chain_t, filter_info_base::sptr)> set;
+ };
+
+ std::map<std::string, filter_query_helper> _rx_filters;
+ std::map<std::string, filter_query_helper> _tx_filters;
+
//Interfaces
ad9361_params::sptr _client_params;
ad9361_io::sptr _io_iface;
//Intermediate state
double _rx_freq, _tx_freq, _req_rx_freq, _req_tx_freq;
+ double _last_calibration_freq;
double _baseband_bw, _bbpll_freq, _adcclock_freq;
+ double _rx_analog_bw, _tx_analog_bw, _rx_bb_lp_bw, _tx_bb_lp_bw;
+ double _rx_tia_lp_bw, _tx_sec_lp_bw;
double _req_clock_rate, _req_coreclk;
boost::uint16_t _rx_bbf_tunediv;
boost::uint8_t _curr_gain_table;
double _rx1_gain, _rx2_gain, _tx1_gain, _tx2_gain;
boost::int32_t _tfir_factor;
boost::int32_t _rfir_factor;
+ gain_mode_t _rx1_agc_mode, _rx2_agc_mode;
+ bool _rx1_agc_enable, _rx2_agc_enable;
//Register soft-copies
chip_regs_t _regs;
//Synchronization
boost::recursive_mutex _mutex;
+ bool _use_dc_offset_correction;
+ bool _use_iq_balance_correction;
};
}} //namespace
diff --git a/host/lib/usrp/common/ad9361_driver/ad9361_gain_tables.h b/host/lib/usrp/common/ad9361_driver/ad9361_gain_tables.h
index 786029d6e..553655fa5 100644
--- a/host/lib/usrp/common/ad9361_driver/ad9361_gain_tables.h
+++ b/host/lib/usrp/common/ad9361_driver/ad9361_gain_tables.h
@@ -7,91 +7,91 @@
#include <boost/cstdint.hpp>
-boost::uint8_t gain_table_sub_1300mhz[77][5] = { {0,0x00,0x00,0x20,1},
- {1,0x00,0x00,0x00,0}, {2,0x00,0x00,0x00,0}, {3,0x00,0x01,0x00,0},
- {4,0x00,0x02,0x00,0}, {5,0x00,0x03,0x00,0}, {6,0x00,0x04,0x00,0},
- {7,0x00,0x05,0x00,0}, {8,0x01,0x03,0x20,1}, {9,0x01,0x04,0x00,0},
- {10,0x01,0x05,0x00,0}, {11,0x01,0x06,0x00,0}, {12,0x01,0x07,0x00,0},
- {13,0x01,0x08,0x00,0}, {14,0x01,0x09,0x00,0}, {15,0x01,0x0A,0x00,0},
- {16,0x01,0x0B,0x00,0}, {17,0x01,0x0C,0x00,0}, {18,0x01,0x0D,0x00,0},
- {19,0x01,0x0E,0x00,0}, {20,0x02,0x09,0x20,1}, {21,0x02,0x0A,0x00,0},
- {22,0x02,0x0B,0x00,0}, {23,0x02,0x0C,0x00,0}, {24,0x02,0x0D,0x00,0},
- {25,0x02,0x0E,0x00,0}, {26,0x02,0x0F,0x00,0}, {27,0x02,0x10,0x00,0},
- {28,0x02,0x2B,0x20,1}, {29,0x02,0x2C,0x00,0}, {30,0x04,0x27,0x20,1},
- {31,0x04,0x28,0x00,0}, {32,0x04,0x29,0x00,0}, {33,0x04,0x2A,0x00,0},
- {34,0x04,0x2B,0x00,1}, {35,0x24,0x21,0x20,0}, {36,0x24,0x22,0x00,1},
- {37,0x44,0x20,0x20,0}, {38,0x44,0x21,0x00,0}, {39,0x44,0x22,0x00,0},
- {40,0x44,0x23,0x00,0}, {41,0x44,0x24,0x00,0}, {42,0x44,0x25,0x00,0},
- {43,0x44,0x26,0x00,0}, {44,0x44,0x27,0x00,0}, {45,0x44,0x28,0x00,0},
- {46,0x44,0x29,0x00,0}, {47,0x44,0x2A,0x00,0}, {48,0x44,0x2B,0x00,0},
- {49,0x44,0x2C,0x00,0}, {50,0x44,0x2D,0x00,0}, {51,0x44,0x2E,0x00,0},
- {52,0x44,0x2F,0x00,0}, {53,0x44,0x30,0x00,0}, {54,0x44,0x31,0x00,0},
- {55,0x64,0x2E,0x20,1}, {56,0x64,0x2F,0x00,0}, {57,0x64,0x30,0x00,0},
- {58,0x64,0x31,0x00,0}, {59,0x64,0x32,0x00,0}, {60,0x64,0x33,0x00,0},
- {61,0x64,0x34,0x00,0}, {62,0x64,0x35,0x00,0}, {63,0x64,0x36,0x00,0},
- {64,0x64,0x37,0x00,0}, {65,0x64,0x38,0x00,0}, {66,0x65,0x38,0x20,1},
- {67,0x66,0x38,0x20,1}, {68,0x67,0x38,0x20,1}, {69,0x68,0x38,0x20,1},
- {70,0x69,0x38,0x20,1}, {71,0x6A,0x38,0x20,1}, {72,0x6B,0x38,0x20,1},
- {73,0x6C,0x38,0x20,1}, {74,0x6D,0x38,0x20,1}, {75,0x6E,0x38,0x20,1},
- {76,0x6F,0x38,0x20,1}};
+boost::uint8_t gain_table_sub_1300mhz[77][3] = {
+{ 0x00, 0x00, 0x20 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 },
+{ 0x00, 0x01, 0x00 }, { 0x00, 0x02, 0x00 }, { 0x00, 0x03, 0x00 },
+{ 0x00, 0x04, 0x00 }, { 0x00, 0x05, 0x00 }, { 0x01, 0x03, 0x20 },
+{ 0x01, 0x04, 0x00 }, { 0x01, 0x05, 0x00 }, { 0x01, 0x06, 0x00 },
+{ 0x01, 0x07, 0x00 }, { 0x01, 0x08, 0x00 }, { 0x01, 0x09, 0x00 },
+{ 0x01, 0x0A, 0x00 }, { 0x01, 0x0B, 0x00 }, { 0x01, 0x0C, 0x00 },
+{ 0x01, 0x0D, 0x00 }, { 0x01, 0x0E, 0x00 }, { 0x02, 0x09, 0x20 },
+{ 0x02, 0x0A, 0x00 }, { 0x02, 0x0B, 0x00 }, { 0x02, 0x0C, 0x00 },
+{ 0x02, 0x0D, 0x00 }, { 0x02, 0x0E, 0x00 }, { 0x02, 0x0F, 0x00 },
+{ 0x02, 0x10, 0x00 }, { 0x02, 0x2B, 0x20 }, { 0x02, 0x2C, 0x00 },
+{ 0x04, 0x28, 0x20 }, { 0x04, 0x29, 0x00 }, { 0x04, 0x2A, 0x00 },
+{ 0x04, 0x2B, 0x00 }, { 0x24, 0x20, 0x20 }, { 0x24, 0x21, 0x00 },
+{ 0x44, 0x20, 0x20 }, { 0x44, 0x21, 0x00 }, { 0x44, 0x22, 0x00 },
+{ 0x44, 0x23, 0x00 }, { 0x44, 0x24, 0x00 }, { 0x44, 0x25, 0x00 },
+{ 0x44, 0x26, 0x00 }, { 0x44, 0x27, 0x00 }, { 0x44, 0x28, 0x00 },
+{ 0x44, 0x29, 0x00 }, { 0x44, 0x2A, 0x00 }, { 0x44, 0x2B, 0x00 },
+{ 0x44, 0x2C, 0x00 }, { 0x44, 0x2D, 0x00 }, { 0x44, 0x2E, 0x00 },
+{ 0x44, 0x2F, 0x00 }, { 0x44, 0x30, 0x00 }, { 0x44, 0x31, 0x00 },
+{ 0x44, 0x32, 0x00 }, { 0x64, 0x2E, 0x20 }, { 0x64, 0x2F, 0x00 },
+{ 0x64, 0x30, 0x00 }, { 0x64, 0x31, 0x00 }, { 0x64, 0x32, 0x00 },
+{ 0x64, 0x33, 0x00 }, { 0x64, 0x34, 0x00 }, { 0x64, 0x35, 0x00 },
+{ 0x64, 0x36, 0x00 }, { 0x64, 0x37, 0x00 }, { 0x64, 0x38, 0x00 },
+{ 0x65, 0x38, 0x20 }, { 0x66, 0x38, 0x20 }, { 0x67, 0x38, 0x20 },
+{ 0x68, 0x38, 0x20 }, { 0x69, 0x38, 0x20 }, { 0x6A, 0x38, 0x20 },
+{ 0x6B, 0x38, 0x20 }, { 0x6C, 0x38, 0x20 }, { 0x6D, 0x38, 0x20 },
+{ 0x6E, 0x38, 0x20 }, { 0x6F, 0x38, 0x20 } };
-boost::uint8_t gain_table_1300mhz_to_4000mhz[77][5] = { {0,0x00,0x00,0x20,1},
- {1,0x00,0x00,0x00,0}, {2,0x00,0x00,0x00,0}, {3,0x00,0x01,0x00,0},
- {4,0x00,0x02,0x00,0}, {5,0x00,0x03,0x00,0}, {6,0x00,0x04,0x00,0},
- {7,0x00,0x05,0x00,0}, {8,0x01,0x03,0x20,1}, {9,0x01,0x04,0x00,0},
- {10,0x01,0x05,0x00,0}, {11,0x01,0x06,0x00,0}, {12,0x01,0x07,0x00,0},
- {13,0x01,0x08,0x00,0}, {14,0x01,0x09,0x00,0}, {15,0x01,0x0A,0x00,0},
- {16,0x01,0x0B,0x00,0}, {17,0x01,0x0C,0x00,0}, {18,0x01,0x0D,0x00,0},
- {19,0x01,0x0E,0x00,0}, {20,0x02,0x09,0x20,1}, {21,0x02,0x0A,0x00,0},
- {22,0x02,0x0B,0x00,0}, {23,0x02,0x0C,0x00,0}, {24,0x02,0x0D,0x00,0},
- {25,0x02,0x0E,0x00,0}, {26,0x02,0x0F,0x00,0}, {27,0x02,0x10,0x00,0},
- {28,0x02,0x2B,0x20,1}, {29,0x02,0x2C,0x00,0}, {30,0x04,0x28,0x20,1},
- {31,0x04,0x29,0x00,0}, {32,0x04,0x2A,0x00,0}, {33,0x04,0x2B,0x00,0},
- {34,0x24,0x20,0x20,0}, {35,0x24,0x21,0x00,1}, {36,0x44,0x20,0x20,0},
- {37,0x44,0x21,0x00,1}, {38,0x44,0x22,0x00,0}, {39,0x44,0x23,0x00,0},
- {40,0x44,0x24,0x00,0}, {41,0x44,0x25,0x00,0}, {42,0x44,0x26,0x00,0},
- {43,0x44,0x27,0x00,0}, {44,0x44,0x28,0x00,0}, {45,0x44,0x29,0x00,0},
- {46,0x44,0x2A,0x00,0}, {47,0x44,0x2B,0x00,0}, {48,0x44,0x2C,0x00,0},
- {49,0x44,0x2D,0x00,0}, {50,0x44,0x2E,0x00,0}, {51,0x44,0x2F,0x00,0},
- {52,0x44,0x30,0x00,0}, {53,0x44,0x31,0x00,0}, {54,0x44,0x32,0x00,0},
- {55,0x64,0x2E,0x20,1}, {56,0x64,0x2F,0x00,0}, {57,0x64,0x30,0x00,0},
- {58,0x64,0x31,0x00,0}, {59,0x64,0x32,0x00,0}, {60,0x64,0x33,0x00,0},
- {61,0x64,0x34,0x00,0}, {62,0x64,0x35,0x00,0}, {63,0x64,0x36,0x00,0},
- {64,0x64,0x37,0x00,0}, {65,0x64,0x38,0x00,0}, {66,0x65,0x38,0x20,1},
- {67,0x66,0x38,0x20,1}, {68,0x67,0x38,0x20,1}, {69,0x68,0x38,0x20,1},
- {70,0x69,0x38,0x20,1}, {71,0x6A,0x38,0x20,1}, {72,0x6B,0x38,0x20,1},
- {73,0x6C,0x38,0x20,1}, {74,0x6D,0x38,0x20,1}, {75,0x6E,0x38,0x20,1},
- {76,0x6F,0x38,0x20,1}};
+boost::uint8_t gain_table_1300mhz_to_4000mhz[77][3] = {
+{ 0x00, 0x00, 0x20 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 },
+{ 0x00, 0x01, 0x00 }, { 0x00, 0x02, 0x00 }, { 0x00, 0x03, 0x00 },
+{ 0x00, 0x04, 0x00 }, { 0x00, 0x05, 0x00 }, { 0x01, 0x03, 0x20 },
+{ 0x01, 0x04, 0x00 }, { 0x01, 0x05, 0x00 }, { 0x01, 0x06, 0x00 },
+{ 0x01, 0x07, 0x00 }, { 0x01, 0x08, 0x00 }, { 0x01, 0x09, 0x00 },
+{ 0x01, 0x0A, 0x00 }, { 0x01, 0x0B, 0x00 }, { 0x01, 0x0C, 0x00 },
+{ 0x01, 0x0D, 0x00 }, { 0x01, 0x0E, 0x00 }, { 0x02, 0x09, 0x20 },
+{ 0x02, 0x0A, 0x00 }, { 0x02, 0x0B, 0x00 }, { 0x02, 0x0C, 0x00 },
+{ 0x02, 0x0D, 0x00 }, { 0x02, 0x0E, 0x00 }, { 0x02, 0x0F, 0x00 },
+{ 0x02, 0x10, 0x00 }, { 0x02, 0x2B, 0x20 }, { 0x02, 0x2C, 0x00 },
+{ 0x04, 0x27, 0x20 }, { 0x04, 0x28, 0x00 }, { 0x04, 0x29, 0x00 },
+{ 0x04, 0x2A, 0x00 }, { 0x04, 0x2B, 0x00 }, { 0x24, 0x21, 0x20 },
+{ 0x24, 0x22, 0x00 }, { 0x44, 0x20, 0x20 }, { 0x44, 0x21, 0x00 },
+{ 0x44, 0x22, 0x00 }, { 0x44, 0x23, 0x00 }, { 0x44, 0x24, 0x00 },
+{ 0x44, 0x25, 0x00 }, { 0x44, 0x26, 0x00 }, { 0x44, 0x27, 0x00 },
+{ 0x44, 0x28, 0x00 }, { 0x44, 0x29, 0x00 }, { 0x44, 0x2A, 0x00 },
+{ 0x44, 0x2B, 0x00 }, { 0x44, 0x2C, 0x00 }, { 0x44, 0x2D, 0x00 },
+{ 0x44, 0x2E, 0x00 }, { 0x44, 0x2F, 0x00 }, { 0x44, 0x30, 0x00 },
+{ 0x44, 0x31, 0x00 }, { 0x64, 0x2E, 0x20 }, { 0x64, 0x2F, 0x00 },
+{ 0x64, 0x30, 0x00 }, { 0x64, 0x31, 0x00 }, { 0x64, 0x32, 0x00 },
+{ 0x64, 0x33, 0x00 }, { 0x64, 0x34, 0x00 }, { 0x64, 0x35, 0x00 },
+{ 0x64, 0x36, 0x00 }, { 0x64, 0x37, 0x00 }, { 0x64, 0x38, 0x00 },
+{ 0x65, 0x38, 0x20 }, { 0x66, 0x38, 0x20 }, { 0x67, 0x38, 0x20 },
+{ 0x68, 0x38, 0x20 }, { 0x69, 0x38, 0x20 }, { 0x6A, 0x38, 0x20 },
+{ 0x6B, 0x38, 0x20 }, { 0x6C, 0x38, 0x20 }, { 0x6D, 0x38, 0x20 },
+{ 0x6E, 0x38, 0x20 }, { 0x6F, 0x38, 0x20 } };
-boost::uint8_t gain_table_4000mhz_to_6000mhz[77][5] = { {0,0x00,0x00,0x20,1},
- {1,0x00,0x00,0x00,0}, {2,0x00,0x00,0x00,0}, {3,0x00,0x00,0x00,0},
- {4,0x00,0x00,0x00,0}, {5,0x00,0x01,0x00,0}, {6,0x00,0x02,0x00,0},
- {7,0x00,0x03,0x00,0}, {8,0x01,0x01,0x20,1}, {9,0x01,0x02,0x00,0},
- {10,0x01,0x03,0x00,0}, {11,0x01,0x04,0x20,1}, {12,0x01,0x05,0x00,0},
- {13,0x01,0x06,0x00,0}, {14,0x01,0x07,0x00,0}, {15,0x01,0x08,0x00,0},
- {16,0x01,0x09,0x00,0}, {17,0x01,0x0A,0x00,0}, {18,0x01,0x0B,0x00,0},
- {19,0x01,0x0C,0x00,0}, {20,0x02,0x08,0x20,1}, {21,0x02,0x09,0x00,0},
- {22,0x02,0x0A,0x00,0}, {23,0x02,0x0B,0x20,1}, {24,0x02,0x0C,0x00,0},
- {25,0x02,0x0D,0x00,0}, {26,0x02,0x0E,0x00,0}, {27,0x02,0x0F,0x00,0},
- {28,0x02,0x2A,0x20,1}, {29,0x02,0x2B,0x00,0}, {30,0x04,0x27,0x20,1},
- {31,0x04,0x28,0x00,0}, {32,0x04,0x29,0x00,0}, {33,0x04,0x2A,0x00,0},
- {34,0x04,0x2B,0x00,0}, {35,0x04,0x2C,0x00,0}, {36,0x04,0x2D,0x00,0},
- {37,0x24,0x20,0x20,1}, {38,0x24,0x21,0x00,0}, {39,0x24,0x22,0x00,0},
- {40,0x44,0x20,0x20,1}, {41,0x44,0x21,0x00,0}, {42,0x44,0x22,0x00,0},
- {43,0x44,0x23,0x00,0}, {44,0x44,0x24,0x00,0}, {45,0x44,0x25,0x00,0},
- {46,0x44,0x26,0x00,0}, {47,0x44,0x27,0x00,0}, {48,0x44,0x28,0x00,0},
- {49,0x44,0x29,0x00,0}, {50,0x44,0x2A,0x00,0}, {51,0x44,0x2B,0x00,0},
- {52,0x44,0x2C,0x00,0}, {53,0x44,0x2D,0x00,0}, {54,0x44,0x2E,0x00,0},
- {55,0x64,0x2E,0x20,1}, {56,0x64,0x2F,0x00,0}, {57,0x64,0x30,0x00,0},
- {58,0x64,0x31,0x00,0}, {59,0x64,0x32,0x00,0}, {60,0x64,0x33,0x00,0},
- {61,0x64,0x34,0x00,0}, {62,0x64,0x35,0x00,0}, {63,0x64,0x36,0x00,0},
- {64,0x64,0x37,0x00,0}, {65,0x64,0x38,0x00,0}, {66,0x65,0x38,0x20,1},
- {67,0x66,0x38,0x20,1}, {68,0x67,0x38,0x20,1}, {69,0x68,0x38,0x20,1},
- {70,0x69,0x38,0x20,1}, {71,0x6A,0x38,0x20,1}, {72,0x6B,0x38,0x20,1},
- {73,0x6C,0x38,0x20,1}, {74,0x6D,0x38,0x20,1}, {75,0x6E,0x38,0x20,1},
- {76,0x6F,0x38,0x20,1}};
+boost::uint8_t gain_table_4000mhz_to_6000mhz[77][3] = {
+{ 0x00, 0x00, 0x20 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 },
+{ 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x01, 0x00 },
+{ 0x00, 0x02, 0x00 }, { 0x00, 0x03, 0x00 }, { 0x01, 0x01, 0x20 },
+{ 0x01, 0x02, 0x00 }, { 0x01, 0x03, 0x00 }, { 0x01, 0x04, 0x20 },
+{ 0x01, 0x05, 0x00 }, { 0x01, 0x06, 0x00 }, { 0x01, 0x07, 0x00 },
+{ 0x01, 0x08, 0x00 }, { 0x01, 0x09, 0x00 }, { 0x01, 0x0A, 0x00 },
+{ 0x01, 0x0B, 0x00 }, { 0x01, 0x0C, 0x00 }, { 0x02, 0x08, 0x20 },
+{ 0x02, 0x09, 0x00 }, { 0x02, 0x0A, 0x00 }, { 0x02, 0x0B, 0x20 },
+{ 0x02, 0x0C, 0x00 }, { 0x02, 0x0D, 0x00 }, { 0x02, 0x0E, 0x00 },
+{ 0x02, 0x0F, 0x00 }, { 0x02, 0x2A, 0x20 }, { 0x02, 0x2B, 0x00 },
+{ 0x04, 0x27, 0x20 }, { 0x04, 0x28, 0x00 }, { 0x04, 0x29, 0x00 },
+{ 0x04, 0x2A, 0x00 }, { 0x04, 0x2B, 0x00 }, { 0x04, 0x2C, 0x00 },
+{ 0x04, 0x2D, 0x00 }, { 0x24, 0x20, 0x20 }, { 0x24, 0x21, 0x00 },
+{ 0x24, 0x22, 0x00 }, { 0x44, 0x20, 0x20 }, { 0x44, 0x21, 0x00 },
+{ 0x44, 0x22, 0x00 }, { 0x44, 0x23, 0x00 }, { 0x44, 0x24, 0x00 },
+{ 0x44, 0x25, 0x00 }, { 0x44, 0x26, 0x00 }, { 0x44, 0x27, 0x00 },
+{ 0x44, 0x28, 0x00 }, { 0x44, 0x29, 0x00 }, { 0x44, 0x2A, 0x00 },
+{ 0x44, 0x2B, 0x00 }, { 0x44, 0x2C, 0x00 }, { 0x44, 0x2D, 0x00 },
+{ 0x44, 0x2E, 0x00 }, { 0x64, 0x2E, 0x20 }, { 0x64, 0x2F, 0x00 },
+{ 0x64, 0x30, 0x00 }, { 0x64, 0x31, 0x00 }, { 0x64, 0x32, 0x00 },
+{ 0x64, 0x33, 0x00 }, { 0x64, 0x34, 0x00 }, { 0x64, 0x35, 0x00 },
+{ 0x64, 0x36, 0x00 }, { 0x64, 0x37, 0x00 }, { 0x64, 0x38, 0x00 },
+{ 0x65, 0x38, 0x20 }, { 0x66, 0x38, 0x20 }, { 0x67, 0x38, 0x20 },
+{ 0x68, 0x38, 0x20 }, { 0x69, 0x38, 0x20 }, { 0x6A, 0x38, 0x20 },
+{ 0x6B, 0x38, 0x20 }, { 0x6C, 0x38, 0x20 }, { 0x6D, 0x38, 0x20 },
+{ 0x6E, 0x38, 0x20 }, { 0x6F, 0x38, 0x20 } };
#endif /* INCLUDED_AD9361_GAIN_TABLES_HPP */
diff --git a/host/lib/usrp/common/ad9361_driver/ad9361_synth_lut.h b/host/lib/usrp/common/ad9361_driver/ad9361_synth_lut.h
index cb320e1f4..0475a5eb1 100644
--- a/host/lib/usrp/common/ad9361_driver/ad9361_synth_lut.h
+++ b/host/lib/usrp/common/ad9361_driver/ad9361_synth_lut.h
@@ -6,20 +6,20 @@
#define INCLUDED_AD9361_SYNTH_LUT_HPP
-double vco_index[53] = {12605000000, 12245000000, 11906000000, 11588000000,
- 11288000000, 11007000000, 10742000000, 10492000000,
- 10258000000, 10036000000, 9827800000, 9631100000,
- 9445300000, 9269800000, 9103600000, 8946300000,
- 8797000000, 8655300000, 8520600000, 8392300000,
- 8269900000, 8153100000, 8041400000, 7934400000,
- 7831800000, 7733200000, 7638400000, 7547100000,
- 7459000000, 7374000000, 7291900000, 7212400000,
- 7135500000, 7061000000, 6988700000, 6918600000,
- 6850600000, 6784600000, 6720500000, 6658200000,
- 6597800000, 6539200000, 6482300000, 6427000000,
- 6373400000, 6321400000, 6270900000, 6222000000,
- 6174500000, 6128400000, 6083600000, 6040100000,
- 5997700000};
+double vco_index[53] = {12605000000.0, 12245000000.0, 11906000000.0, 11588000000.0,
+ 11288000000.0, 11007000000.0, 10742000000.0, 10492000000.0,
+ 10258000000.0, 10036000000.0, 9827800000.0, 9631100000.0,
+ 9445300000.0, 9269800000.0, 9103600000.0, 8946300000.0,
+ 8797000000.0, 8655300000.0, 8520600000.0, 8392300000.0,
+ 8269900000.0, 8153100000.0, 8041400000.0, 7934400000.0,
+ 7831800000.0, 7733200000.0, 7638400000.0, 7547100000.0,
+ 7459000000.0, 7374000000.0, 7291900000.0, 7212400000.0,
+ 7135500000.0, 7061000000.0, 6988700000.0, 6918600000.0,
+ 6850600000.0, 6784600000.0, 6720500000.0, 6658200000.0,
+ 6597800000.0, 6539200000.0, 6482300000.0, 6427000000.0,
+ 6373400000.0, 6321400000.0, 6270900000.0, 6222000000.0,
+ 6174500000.0, 6128400000.0, 6083600000.0, 6040100000.0,
+ 5997700000.0};
int synth_cal_lut[53][12] = { {10, 0, 4, 0, 15, 8, 8, 13, 4, 13, 15, 9},
{10, 0, 4, 0, 15, 8, 9, 13, 4, 13, 15, 9},
diff --git a/host/lib/usrp/cores/gpio_core_200.hpp b/host/lib/usrp/cores/gpio_core_200.hpp
index 164437f40..e22834fd9 100644
--- a/host/lib/usrp/cores/gpio_core_200.hpp
+++ b/host/lib/usrp/cores/gpio_core_200.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011,2014 Ettus Research LLC
+// Copyright 2011,2014,2015 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -20,10 +20,34 @@
#include <uhd/config.hpp>
#include <uhd/usrp/dboard_iface.hpp>
+#include <boost/assign.hpp>
#include <boost/cstdint.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
#include <uhd/types/wb_iface.hpp>
+#include <map>
+
+typedef enum {
+ GPIO_CTRL,
+ GPIO_DDR,
+ GPIO_OUT,
+ GPIO_ATR_0X,
+ GPIO_ATR_RX,
+ GPIO_ATR_TX,
+ GPIO_ATR_XX
+} gpio_attr_t;
+
+typedef std::map<gpio_attr_t,std::string> gpio_attr_map_t;
+static const gpio_attr_map_t gpio_attr_map =
+ boost::assign::map_list_of
+ (GPIO_CTRL, "CTRL")
+ (GPIO_DDR, "DDR")
+ (GPIO_OUT, "OUT")
+ (GPIO_ATR_0X, "ATR_0X")
+ (GPIO_ATR_RX, "ATR_RX")
+ (GPIO_ATR_TX, "ATR_TX")
+ (GPIO_ATR_XX, "ATR_XX")
+;
class gpio_core_200 : boost::noncopyable{
public:
diff --git a/host/lib/usrp/e300/e300_impl.cpp b/host/lib/usrp/e300/e300_impl.cpp
index 2e8f50e05..3d92bc5c8 100644
--- a/host/lib/usrp/e300/e300_impl.cpp
+++ b/host/lib/usrp/e300/e300_impl.cpp
@@ -469,15 +469,14 @@ e300_impl::e300_impl(const uhd::device_addr_t &device_addr)
// internal gpios
////////////////////////////////////////////////////////////////////
gpio_core_200::sptr fp_gpio = gpio_core_200::make(_radio_perifs[0].ctrl, TOREG(SR_FP_GPIO), RB32_FP_GPIO);
- const std::vector<std::string> gpio_attrs = boost::assign::list_of("CTRL")("DDR")("OUT")("ATR_0X")("ATR_RX")("ATR_TX")("ATR_XX");
- BOOST_FOREACH(const std::string &attr, gpio_attrs)
+ BOOST_FOREACH(const gpio_attr_map_t::value_type attr, gpio_attr_map)
{
- _tree->create<boost::uint32_t>(mb_path / "gpio" / "INT0" / attr)
- .subscribe(boost::bind(&e300_impl::_set_internal_gpio, this, fp_gpio, attr, _1))
+ _tree->create<boost::uint32_t>(mb_path / "gpio" / "INT0" / attr.second)
+ .subscribe(boost::bind(&e300_impl::_set_internal_gpio, this, fp_gpio, attr.first, _1))
.set(0);
}
_tree->create<boost::uint8_t>(mb_path / "gpio" / "INT0" / "READBACK")
- .publish(boost::bind(&e300_impl::_get_internal_gpio, this, fp_gpio, "READBACK"));
+ .publish(boost::bind(&e300_impl::_get_internal_gpio, this, fp_gpio));
////////////////////////////////////////////////////////////////////
@@ -576,32 +575,35 @@ e300_impl::e300_impl(const uhd::device_addr_t &device_addr)
_tree->access<subdev_spec_t>(mb_path / "tx_subdev_spec").set(tx_spec);
}
-boost::uint8_t e300_impl::_get_internal_gpio(
- gpio_core_200::sptr gpio,
- const std::string &)
+boost::uint8_t e300_impl::_get_internal_gpio(gpio_core_200::sptr gpio)
{
return boost::uint32_t(gpio->read_gpio(dboard_iface::UNIT_RX));
}
void e300_impl::_set_internal_gpio(
gpio_core_200::sptr gpio,
- const std::string &attr,
+ const gpio_attr_t attr,
const boost::uint32_t value)
{
- if (attr == "CTRL")
+ switch (attr)
+ {
+ case GPIO_CTRL:
return gpio->set_pin_ctrl(dboard_iface::UNIT_RX, value);
- else if (attr == "DDR")
+ case GPIO_DDR:
return gpio->set_gpio_ddr(dboard_iface::UNIT_RX, value);
- else if (attr == "OUT")
+ case GPIO_OUT:
return gpio->set_gpio_out(dboard_iface::UNIT_RX, value);
- else if (attr == "ATR_0X")
+ case GPIO_ATR_0X:
return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE, value);
- else if (attr == "ATR_RX")
+ case GPIO_ATR_RX:
return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY, value);
- else if (attr == "ATR_TX")
+ case GPIO_ATR_TX:
return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY, value);
- else if (attr == "ATR_XX")
+ case GPIO_ATR_XX:
return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, value);
+ default:
+ UHD_THROW_INVALID_CODE_PATH();
+ }
}
uhd::sensor_value_t e300_impl::_get_fe_pll_lock(const bool is_tx)
@@ -1028,6 +1030,8 @@ void e300_impl::_setup_radio(const size_t dspno)
_tree->create<int>(rf_fe_path / "sensors"); //empty TODO
_tree->create<sensor_value_t>(rf_fe_path / "sensors" / "lo_locked")
.publish(boost::bind(&e300_impl::_get_fe_pll_lock, this, direction == "tx"));
+ _tree->create<sensor_value_t>(rf_fe_path / "sensors" / "temp")
+ .publish(boost::bind(&ad9361_ctrl::get_temperature, _codec_ctrl));
BOOST_FOREACH(const std::string &name, ad9361_ctrl::get_gain_names(key))
{
_tree->create<meta_range_t>(rf_fe_path / "gains" / name / "range")
@@ -1052,6 +1056,18 @@ void e300_impl::_setup_radio(const size_t dspno)
_tree->create<meta_range_t>(rf_fe_path / "freq" / "range")
.publish(boost::bind(&ad9361_ctrl::get_rf_freq_range));
+ //only in local mode
+ if(_xport_path == AXI) {
+ //add all frontend filters
+ std::vector<std::string> filter_names = _codec_ctrl->get_filter_names(key);
+ for(size_t i = 0;i < filter_names.size(); i++)
+ {
+ _tree->create<filter_info_base::sptr>(rf_fe_path / "filters" / filter_names[i] / "value" )
+ .publish(boost::bind(&ad9361_ctrl::get_filter, _codec_ctrl, key, filter_names[i]))
+ .subscribe(boost::bind(&ad9361_ctrl::set_filter, _codec_ctrl, key, filter_names[i], _1));
+ }
+ }
+
//setup RX related stuff
if (key[0] == 'R') {
static const std::vector<std::string> ants = boost::assign::list_of("TX/RX")("RX2");
diff --git a/host/lib/usrp/e300/e300_impl.hpp b/host/lib/usrp/e300/e300_impl.hpp
index c7d683f58..21aef215d 100644
--- a/host/lib/usrp/e300/e300_impl.hpp
+++ b/host/lib/usrp/e300/e300_impl.hpp
@@ -264,13 +264,11 @@ private: // methods
uhd::sensor_value_t _get_fe_pll_lock(const bool is_tx);
// internal gpios
- boost::uint8_t _get_internal_gpio(
- gpio_core_200::sptr,
- const std::string &);
+ boost::uint8_t _get_internal_gpio(gpio_core_200::sptr);
void _set_internal_gpio(
gpio_core_200::sptr gpio,
- const std::string &attr,
+ const gpio_attr_t attr,
const boost::uint32_t value);
private: // members
diff --git a/host/lib/usrp/e300/e300_network.cpp b/host/lib/usrp/e300/e300_network.cpp
index bb904773b..2a63abc25 100644
--- a/host/lib/usrp/e300/e300_network.cpp
+++ b/host/lib/usrp/e300/e300_network.cpp
@@ -227,6 +227,27 @@ static void e300_codec_ctrl_tunnel(
case codec_xact_t::ACTION_GET_RSSI:
out->rssi = _codec_ctrl->get_rssi(which_str).to_real();
break;
+ case codec_xact_t::ACTION_GET_TEMPERATURE:
+ out->temp = _codec_ctrl->get_temperature().to_real();
+ break;
+ case codec_xact_t::ACTION_SET_DC_OFFSET_AUTO:
+ _codec_ctrl->set_dc_offset_auto(which_str, in->use_dc_correction == 1);
+ break;
+ case codec_xact_t::ACTION_SET_IQ_BALANCE_AUTO:
+ _codec_ctrl->set_iq_balance_auto(which_str, in->use_iq_correction == 1);
+ case codec_xact_t::ACTION_SET_AGC:
+ _codec_ctrl->set_agc(which_str, in->use_agc == 1);
+ break;
+ case codec_xact_t::ACTION_SET_AGC_MODE:
+ if(in->agc_mode == 0) {
+ _codec_ctrl->set_agc_mode(which_str, "slow");
+ } else if (in->agc_mode == 1) {
+ _codec_ctrl->set_agc_mode(which_str, "fast");
+ }
+ break;
+ case codec_xact_t::ACTION_SET_BW:
+ out->bw = _codec_ctrl->set_bw_filter(which_str, in->bw);
+ break;
default:
UHD_MSG(status) << "Got unknown request?!" << std::endl;
//Zero out actions to fail this request on client
diff --git a/host/lib/usrp/e300/e300_remote_codec_ctrl.cpp b/host/lib/usrp/e300/e300_remote_codec_ctrl.cpp
index ed8131e2f..c78946a6c 100644
--- a/host/lib/usrp/e300/e300_remote_codec_ctrl.cpp
+++ b/host/lib/usrp/e300/e300_remote_codec_ctrl.cpp
@@ -116,10 +116,118 @@ public:
_args.bits = uhd::htonx<boost::uint32_t>(0);
_transact();
-
return sensor_value_t("RSSI", _retval.rssi, "dB");
}
+ sensor_value_t get_temperature()
+ {
+ _clear();
+ _args.action = uhd::htonx<boost::uint32_t>(transaction_t::ACTION_GET_TEMPERATURE);
+ _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_NONE); /*Unused*/
+ _args.bits = uhd::htonx<boost::uint32_t>(0);
+
+ _transact();
+ return sensor_value_t("temp", _retval.temp, "C");
+ }
+
+ void set_dc_offset_auto(const std::string &which, const bool on)
+ {
+ _clear();
+ _args.action = uhd::htonx<boost::uint32_t>(transaction_t::ACTION_SET_DC_OFFSET_AUTO);
+ if (which == "TX1") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_TX1);
+ else if (which == "TX2") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_TX2);
+ else if (which == "RX1") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_RX1);
+ else if (which == "RX2") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_RX2);
+ else throw std::runtime_error("e300_remote_codec_ctrl_impl incorrect chain string.");
+ _args.use_dc_correction = on ? 1 : 0;
+
+ _transact();
+ }
+
+ void set_iq_balance_auto(const std::string &which, const bool on)
+ {
+ _clear();
+ _args.action = uhd::htonx<boost::uint32_t>(transaction_t::ACTION_SET_IQ_BALANCE_AUTO);
+ if (which == "TX1") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_TX1);
+ else if (which == "TX2") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_TX2);
+ else if (which == "RX1") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_RX1);
+ else if (which == "RX2") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_RX2);
+ else throw std::runtime_error("e300_remote_codec_ctrl_impl incorrect chain string.");
+ _args.use_iq_correction = on ? 1 : 0;
+
+ _transact();
+ }
+
+ void set_agc(const std::string &which, bool enable)
+ {
+ _clear();
+ _args.action = uhd::htonx<boost::uint32_t>(transaction_t::ACTION_SET_AGC);
+ if (which == "TX1") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_TX1);
+ else if (which == "TX2") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_TX2);
+ else if (which == "RX1") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_RX1);
+ else if (which == "RX2") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_RX2);
+ else throw std::runtime_error("e300_remote_codec_ctrl_impl incorrect chain string.");
+ _args.use_agc = enable ? 1 : 0;
+
+ _transact();
+ }
+
+ void set_agc_mode(const std::string &which, const std::string &mode)
+ {
+ _clear();
+ _args.action = uhd::htonx<boost::uint32_t>(transaction_t::ACTION_SET_AGC_MODE);
+
+ if (which == "TX1") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_TX1);
+ else if (which == "TX2") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_TX2);
+ else if (which == "RX1") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_RX1);
+ else if (which == "RX2") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_RX2);
+ else throw std::runtime_error("e300_remote_codec_ctrl_impl incorrect chain string.");
+
+ if(mode == "slow") {
+ _args.agc_mode = 0;
+ } else if (mode == "fast") {
+ _args.agc_mode = 1;
+ } else {
+ throw std::runtime_error("e300_remote_codec_ctrl_impl incorrect agc mode.");
+ }
+
+ _transact();
+ }
+
+ //! set the filter bandwidth for the frontend's analog low pass
+ double set_bw_filter(const std::string &which, const double bw)
+ {
+ _clear();
+ _args.action = uhd::htonx<boost::uint32_t>(transaction_t::ACTION_SET_BW);
+ if (which == "TX1") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_TX1);
+ else if (which == "TX2") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_TX2);
+ else if (which == "RX1") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_RX1);
+ else if (which == "RX2") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_RX2);
+ else throw std::runtime_error("e300_remote_codec_ctrl_impl incorrect chain string.");
+ _args.bw = bw;
+
+ _transact();
+ return _retval.bw;
+ }
+
+ //! List all available filters by name
+ std::vector<std::string> get_filter_names(const std::string &)
+ {
+ UHD_THROW_INVALID_CODE_PATH();
+ }
+
+ //! Return a list of all filters
+ filter_info_base::sptr get_filter(const std::string &, const std::string &)
+ {
+ UHD_THROW_INVALID_CODE_PATH();
+ }
+
+ //! Write back a filter
+ void set_filter(const std::string &, const std::string &, const filter_info_base::sptr)
+ {
+ UHD_THROW_INVALID_CODE_PATH();
+ }
+
private:
void _transact() {
{
diff --git a/host/lib/usrp/e300/e300_remote_codec_ctrl.hpp b/host/lib/usrp/e300/e300_remote_codec_ctrl.hpp
index cbc4b52d2..065c5e7a0 100644
--- a/host/lib/usrp/e300/e300_remote_codec_ctrl.hpp
+++ b/host/lib/usrp/e300/e300_remote_codec_ctrl.hpp
@@ -34,6 +34,12 @@ public:
double gain;
double freq;
double rssi;
+ double temp;
+ double bw;
+ boost::uint32_t use_dc_correction;
+ boost::uint32_t use_iq_correction;
+ boost::uint32_t use_agc;
+ boost::uint32_t agc_mode;
boost::uint64_t bits;
};
@@ -44,6 +50,13 @@ public:
static const boost::uint32_t ACTION_TUNE = 13;
static const boost::uint32_t ACTION_SET_LOOPBACK = 14;
static const boost::uint32_t ACTION_GET_RSSI = 15;
+ static const boost::uint32_t ACTION_GET_TEMPERATURE = 16;
+ static const boost::uint32_t ACTION_SET_DC_OFFSET_AUTO = 17;
+ static const boost::uint32_t ACTION_SET_IQ_BALANCE_AUTO = 18;
+ static const boost::uint32_t ACTION_SET_AGC = 19;
+ static const boost::uint32_t ACTION_SET_AGC_MODE = 20;
+ static const boost::uint32_t ACTION_SET_BW = 21;
+
//Values for "which"
static const boost::uint32_t CHAIN_NONE = 0;
diff --git a/host/lib/usrp/multi_usrp.cpp b/host/lib/usrp/multi_usrp.cpp
index 794438b90..1866255c9 100644
--- a/host/lib/usrp/multi_usrp.cpp
+++ b/host/lib/usrp/multi_usrp.cpp
@@ -30,6 +30,8 @@
#include <boost/thread.hpp>
#include <boost/foreach.hpp>
#include <boost/format.hpp>
+#include <boost/algorithm/string.hpp>
+#include <algorithm>
#include <cmath>
using namespace uhd;
@@ -431,6 +433,9 @@ public:
******************************************************************/
void set_master_clock_rate(double rate, size_t mboard){
if (mboard != ALL_MBOARDS){
+ if (_tree->exists(mb_root(mboard) / "auto_tick_rate")) {
+ _tree->access<bool>(mb_root(mboard) / "auto_tick_rate").set(false);
+ }
_tree->access<double>(mb_root(mboard) / "tick_rate").set(rate);
return;
}
@@ -821,6 +826,26 @@ public:
}
void set_rx_gain(double gain, const std::string &name, size_t chan){
+ /* Check if any AGC mode is enable and if so warn the user */
+ if (chan != ALL_CHANS) {
+ if (_tree->exists(rx_rf_fe_root(chan) / "gain" / "agc")) {
+ bool agc = _tree->access<bool>(rx_rf_fe_root(chan) / "gain" / "agc" / "enable").get();
+ if(agc) {
+ UHD_MSG(warning) << "AGC enabled for this channel. Setting will be ignored." << std::endl;
+ }
+ }
+ } else {
+ for (size_t c = 0; c < get_rx_num_channels(); c++){
+ if (_tree->exists(rx_rf_fe_root(c) / "gain" / "agc")) {
+ bool agc = _tree->access<bool>(rx_rf_fe_root(chan) / "gain" / "agc" / "enable").get();
+ if(agc) {
+ UHD_MSG(warning) << "AGC enabled for this channel. Setting will be ignored." << std::endl;
+ }
+ }
+ }
+ }
+ /* Apply gain setting.
+ * If device is in AGC mode it will ignore the setting. */
try {
return rx_gain_group(chan)->set_value(gain, name);
} catch (uhd::key_error &) {
@@ -828,6 +853,32 @@ public:
}
}
+ void set_normalized_rx_gain(double gain, size_t chan = 0)
+ {
+ if (gain > 1.0 || gain < 0.0) {
+ throw uhd::runtime_error("Normalized gain out of range, must be in [0, 1].");
+ }
+ gain_range_t gain_range = get_rx_gain_range(ALL_GAINS, chan);
+ double abs_gain = (gain * (gain_range.stop() - gain_range.start())) + gain_range.start();
+ set_rx_gain(abs_gain, ALL_GAINS, chan);
+ }
+
+ void set_rx_agc(bool enable, size_t chan = 0)
+ {
+ if (chan != ALL_CHANS){
+ if (_tree->exists(rx_rf_fe_root(chan) / "gain" / "agc" / "enable")) {
+ _tree->access<bool>(rx_rf_fe_root(chan) / "gain" / "agc" / "enable").set(enable);
+ } else {
+ UHD_MSG(warning) << "AGC is not available on this device." << std::endl;
+ }
+ return;
+ }
+ for (size_t c = 0; c < get_rx_num_channels(); c++){
+ this->set_rx_agc(enable, c);
+ }
+
+ }
+
double get_rx_gain(const std::string &name, size_t chan){
try {
return rx_gain_group(chan)->get_value(name);
@@ -836,6 +887,21 @@ public:
}
}
+ double get_normalized_rx_gain(size_t chan)
+ {
+ gain_range_t gain_range = get_rx_gain_range(ALL_GAINS, chan);
+ double gain_range_width = gain_range.stop() - gain_range.start();
+ // In case we have a device without a range of gains:
+ if (gain_range_width == 0.0) {
+ return 0;
+ }
+ double norm_gain = (get_rx_gain(ALL_GAINS, chan) - gain_range.start()) / gain_range_width;
+ // Avoid rounding errors:
+ if (norm_gain > 1.0) return 1.0;
+ if (norm_gain < 0.0) return 0.0;
+ return norm_gain;
+ }
+
gain_range_t get_rx_gain_range(const std::string &name, size_t chan){
try {
return rx_gain_group(chan)->get_range(name);
@@ -888,6 +954,9 @@ public:
if (chan != ALL_CHANS){
if (_tree->exists(rx_fe_root(chan) / "dc_offset" / "enable")) {
_tree->access<bool>(rx_fe_root(chan) / "dc_offset" / "enable").set(enb);
+ } else if (_tree->exists(rx_rf_fe_root(chan) / "dc_offset" / "enable")) {
+ /*For B2xx devices the dc-offset correction is implemented in the rf front-end*/
+ _tree->access<bool>(rx_rf_fe_root(chan) / "dc_offset" / "enable").set(enb);
} else {
UHD_MSG(warning) << "Setting DC offset compensation is not possible on this device." << std::endl;
}
@@ -912,6 +981,20 @@ public:
}
}
+ void set_rx_iq_balance(const bool enb, size_t chan){
+ if (chan != ALL_CHANS){
+ if (_tree->exists(rx_rf_fe_root(chan) / "iq_balance" / "enable")) {
+ _tree->access<bool>(rx_rf_fe_root(chan) / "iq_balance" / "enable").set(enb);
+ } else {
+ UHD_MSG(warning) << "Setting IQ imbalance compensation is not possible on this device." << std::endl;
+ }
+ return;
+ }
+ for (size_t c = 0; c < get_rx_num_channels(); c++){
+ this->set_rx_iq_balance(enb, c);
+ }
+ }
+
void set_rx_iq_balance(const std::complex<double> &offset, size_t chan){
if (chan != ALL_CHANS){
if (_tree->exists(rx_fe_root(chan) / "iq_balance" / "value")) {
@@ -926,6 +1009,87 @@ public:
}
}
+ std::vector<std::string> get_filter_names(const std::string &search_mask)
+ {
+ std::vector<std::string> ret;
+
+ for (size_t chan = 0; chan < get_rx_num_channels(); chan++){
+
+ if (_tree->exists(rx_rf_fe_root(chan) / "filters")) {
+ std::vector<std::string> names = _tree->list(rx_rf_fe_root(chan) / "filters");
+ for(size_t i = 0; i < names.size(); i++)
+ {
+ std::string name = rx_rf_fe_root(chan) / "filters" / names[i];
+ if((search_mask.empty()) or boost::contains(name, search_mask)) {
+ ret.push_back(name);
+ }
+ }
+ }
+ if (_tree->exists(rx_dsp_root(chan) / "filters")) {
+ std::vector<std::string> names = _tree->list(rx_dsp_root(chan) / "filters");
+ for(size_t i = 0; i < names.size(); i++)
+ {
+ std::string name = rx_dsp_root(chan) / "filters" / names[i];
+ if((search_mask.empty()) or (boost::contains(name, search_mask))) {
+ ret.push_back(name);
+ }
+ }
+ }
+
+ }
+
+ for (size_t chan = 0; chan < get_tx_num_channels(); chan++){
+
+ if (_tree->exists(tx_rf_fe_root(chan) / "filters")) {
+ std::vector<std::string> names = _tree->list(tx_rf_fe_root(chan) / "filters");
+ for(size_t i = 0; i < names.size(); i++)
+ {
+ std::string name = tx_rf_fe_root(chan) / "filters" / names[i];
+ if((search_mask.empty()) or (boost::contains(name, search_mask))) {
+ ret.push_back(name);
+ }
+ }
+ }
+ if (_tree->exists(rx_dsp_root(chan) / "filters")) {
+ std::vector<std::string> names = _tree->list(tx_dsp_root(chan) / "filters");
+ for(size_t i = 0; i < names.size(); i++)
+ {
+ std::string name = tx_dsp_root(chan) / "filters" / names[i];
+ if((search_mask.empty()) or (boost::contains(name, search_mask))) {
+ ret.push_back(name);
+ }
+ }
+ }
+
+ }
+
+ return ret;
+ }
+
+ filter_info_base::sptr get_filter(const std::string &path)
+ {
+ std::vector<std::string> possible_names = get_filter_names("");
+ std::vector<std::string>::iterator it;
+ it = find(possible_names.begin(), possible_names.end(), path);
+ if (it == possible_names.end()) {
+ throw uhd::runtime_error("Attempting to get non-existing filter: "+path);
+ }
+
+ return _tree->access<filter_info_base::sptr>(path / "value").get();
+ }
+
+ void set_filter(const std::string &path, filter_info_base::sptr filter)
+ {
+ std::vector<std::string> possible_names = get_filter_names("");
+ std::vector<std::string>::iterator it;
+ it = find(possible_names.begin(), possible_names.end(), path);
+ if (it == possible_names.end()) {
+ throw uhd::runtime_error("Attempting to set non-existing filter: "+path);
+ }
+
+ _tree->access<filter_info_base::sptr>(path / "value").set(filter);
+ }
+
/*******************************************************************
* TX methods
******************************************************************/
@@ -1029,6 +1193,17 @@ public:
}
}
+ void set_normalized_tx_gain(double gain, size_t chan = 0)
+ {
+ if (gain > 1.0 || gain < 0.0) {
+ throw uhd::runtime_error("Normalized gain out of range, must be in [0, 1].");
+ }
+ gain_range_t gain_range = get_tx_gain_range(ALL_GAINS, chan);
+ double abs_gain = (gain * (gain_range.stop() - gain_range.start())) + gain_range.start();
+ set_tx_gain(abs_gain, ALL_GAINS, chan);
+ }
+
+
double get_tx_gain(const std::string &name, size_t chan){
try {
return tx_gain_group(chan)->get_value(name);
@@ -1037,6 +1212,21 @@ public:
}
}
+ double get_normalized_tx_gain(size_t chan)
+ {
+ gain_range_t gain_range = get_tx_gain_range(ALL_GAINS, chan);
+ double gain_range_width = gain_range.stop() - gain_range.start();
+ // In case we have a device without a range of gains:
+ if (gain_range_width == 0.0) {
+ return 0.0;
+ }
+ double norm_gain = (get_rx_gain(ALL_GAINS, chan) - gain_range.start()) / gain_range_width;
+ // Avoid rounding errors:
+ if (norm_gain > 1.0) return 1.0;
+ if (norm_gain < 0.0) return 0.0;
+ return norm_gain;
+ }
+
gain_range_t get_tx_gain_range(const std::string &name, size_t chan){
try {
return tx_gain_group(chan)->get_range(name);
diff --git a/host/lib/usrp/x300/x300_impl.cpp b/host/lib/usrp/x300/x300_impl.cpp
index 2de44a99d..641adc048 100644
--- a/host/lib/usrp/x300/x300_impl.cpp
+++ b/host/lib/usrp/x300/x300_impl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2013-2014 Ettus Research LLC
+// Copyright 2013-2015 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -41,7 +41,7 @@
#define NIUSRPRIO_DEFAULT_RPC_PORT "5444"
-#define X300_REV(x) (x - "A" + 1)
+#define X300_REV(x) ((x) - "A" + 1)
using namespace uhd;
using namespace uhd::usrp;
@@ -695,15 +695,14 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr)
// front panel gpio
////////////////////////////////////////////////////////////////////
mb.fp_gpio = gpio_core_200::make(mb.radio_perifs[0].ctrl, TOREG(SR_FP_GPIO), RB32_FP_GPIO);
- const std::vector<std::string> GPIO_ATTRS = boost::assign::list_of("CTRL")("DDR")("OUT")("ATR_0X")("ATR_RX")("ATR_TX")("ATR_XX");
- BOOST_FOREACH(const std::string &attr, GPIO_ATTRS)
+ BOOST_FOREACH(const gpio_attr_map_t::value_type attr, gpio_attr_map)
{
- _tree->create<boost::uint32_t>(mb_path / "gpio" / "FP0" / attr)
+ _tree->create<boost::uint32_t>(mb_path / "gpio" / "FP0" / attr.second)
.set(0)
- .subscribe(boost::bind(&x300_impl::set_fp_gpio, this, mb.fp_gpio, attr, _1));
+ .subscribe(boost::bind(&x300_impl::set_fp_gpio, this, mb.fp_gpio, attr.first, _1));
}
_tree->create<boost::uint32_t>(mb_path / "gpio" / "FP0" / "READBACK")
- .publish(boost::bind(&x300_impl::get_fp_gpio, this, mb.fp_gpio, "READBACK"));
+ .publish(boost::bind(&x300_impl::get_fp_gpio, this, mb.fp_gpio));
////////////////////////////////////////////////////////////////////
// register the time keepers - only one can be the highlander
@@ -1353,7 +1352,7 @@ void x300_impl::set_time_source_out(mboard_members_t &mb, const bool enb)
void x300_impl::update_clock_source(mboard_members_t &mb, const std::string &source)
{
//Optimize for the case when the current source is internal and we are trying
- //to set it to internal. This is the only case where we are guaranteed that
+ //to set it to internal. This is the only case where we are guaranteed that
//the clock has not gone away so we can skip setting the MUX and reseting the LMK.
if (not (mb.current_refclk_src == "internal" and source == "internal")) {
//Update the clock MUX on the motherboard to select the requested source
@@ -1432,8 +1431,8 @@ bool x300_impl::wait_for_ref_locked(wb_iface::sptr ctrl, double timeout)
boost::this_thread::sleep(boost::posix_time::milliseconds(1));
} while (boost::get_system_time() < timeout_time);
- //failed to lock on reference
- return false;
+ //Check one last time
+ return get_ref_locked(ctrl).to_bool();
}
sensor_value_t x300_impl::get_ref_locked(wb_iface::sptr ctrl)
@@ -1534,20 +1533,24 @@ void x300_impl::set_mb_eeprom(i2c_iface::sptr i2c, const mboard_eeprom_t &mb_eep
* front-panel GPIO
**********************************************************************/
-boost::uint32_t x300_impl::get_fp_gpio(gpio_core_200::sptr gpio, const std::string &)
+boost::uint32_t x300_impl::get_fp_gpio(gpio_core_200::sptr gpio)
{
return boost::uint32_t(gpio->read_gpio(dboard_iface::UNIT_RX));
}
-void x300_impl::set_fp_gpio(gpio_core_200::sptr gpio, const std::string &attr, const boost::uint32_t value)
+void x300_impl::set_fp_gpio(gpio_core_200::sptr gpio, const gpio_attr_t attr, const boost::uint32_t value)
{
- if (attr == "CTRL") return gpio->set_pin_ctrl(dboard_iface::UNIT_RX, value);
- if (attr == "DDR") return gpio->set_gpio_ddr(dboard_iface::UNIT_RX, value);
- if (attr == "OUT") return gpio->set_gpio_out(dboard_iface::UNIT_RX, value);
- if (attr == "ATR_0X") return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE, value);
- if (attr == "ATR_RX") return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY, value);
- if (attr == "ATR_TX") return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY, value);
- if (attr == "ATR_XX") return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, value);
+ switch (attr)
+ {
+ case GPIO_CTRL: return gpio->set_pin_ctrl(dboard_iface::UNIT_RX, value);
+ case GPIO_DDR: return gpio->set_gpio_ddr(dboard_iface::UNIT_RX, value);
+ case GPIO_OUT: return gpio->set_gpio_out(dboard_iface::UNIT_RX, value);
+ case GPIO_ATR_0X: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE, value);
+ case GPIO_ATR_RX: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY, value);
+ case GPIO_ATR_TX: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY, value);
+ case GPIO_ATR_XX: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, value);
+ default: UHD_THROW_INVALID_CODE_PATH();
+ }
}
/***********************************************************************
@@ -1720,14 +1723,20 @@ x300_impl::x300_mboard_t x300_impl::get_mb_type_from_pcie(const std::string& res
case X300_USRP_PCIE_SSID:
mb_type = USRP_X300_MB; break;
case X310_USRP_PCIE_SSID:
- case X310_2940R_PCIE_SSID:
- case X310_2942R_PCIE_SSID:
- case X310_2943R_PCIE_SSID:
- case X310_2944R_PCIE_SSID:
- case X310_2950R_PCIE_SSID:
- case X310_2952R_PCIE_SSID:
- case X310_2953R_PCIE_SSID:
- case X310_2954R_PCIE_SSID:
+ case X310_2940R_40MHz_PCIE_SSID:
+ case X310_2940R_120MHz_PCIE_SSID:
+ case X310_2942R_40MHz_PCIE_SSID:
+ case X310_2942R_120MHz_PCIE_SSID:
+ case X310_2943R_40MHz_PCIE_SSID:
+ case X310_2943R_120MHz_PCIE_SSID:
+ case X310_2944R_40MHz_PCIE_SSID:
+ case X310_2950R_40MHz_PCIE_SSID:
+ case X310_2950R_120MHz_PCIE_SSID:
+ case X310_2952R_40MHz_PCIE_SSID:
+ case X310_2952R_120MHz_PCIE_SSID:
+ case X310_2953R_40MHz_PCIE_SSID:
+ case X310_2953R_120MHz_PCIE_SSID:
+ case X310_2954R_40MHz_PCIE_SSID:
mb_type = USRP_X310_MB; break;
default:
mb_type = UNKNOWN; break;
@@ -1755,14 +1764,20 @@ x300_impl::x300_mboard_t x300_impl::get_mb_type_from_eeprom(const uhd::usrp::mbo
case X300_USRP_PCIE_SSID:
mb_type = USRP_X300_MB; break;
case X310_USRP_PCIE_SSID:
- case X310_2940R_PCIE_SSID:
- case X310_2942R_PCIE_SSID:
- case X310_2943R_PCIE_SSID:
- case X310_2944R_PCIE_SSID:
- case X310_2950R_PCIE_SSID:
- case X310_2952R_PCIE_SSID:
- case X310_2953R_PCIE_SSID:
- case X310_2954R_PCIE_SSID:
+ case X310_2940R_40MHz_PCIE_SSID:
+ case X310_2940R_120MHz_PCIE_SSID:
+ case X310_2942R_40MHz_PCIE_SSID:
+ case X310_2942R_120MHz_PCIE_SSID:
+ case X310_2943R_40MHz_PCIE_SSID:
+ case X310_2943R_120MHz_PCIE_SSID:
+ case X310_2944R_40MHz_PCIE_SSID:
+ case X310_2950R_40MHz_PCIE_SSID:
+ case X310_2950R_120MHz_PCIE_SSID:
+ case X310_2952R_40MHz_PCIE_SSID:
+ case X310_2952R_120MHz_PCIE_SSID:
+ case X310_2953R_40MHz_PCIE_SSID:
+ case X310_2953R_120MHz_PCIE_SSID:
+ case X310_2954R_40MHz_PCIE_SSID:
mb_type = USRP_X310_MB; break;
default:
UHD_MSG(warning) << "X300 unknown product code in EEPROM: " << product_num << std::endl;
diff --git a/host/lib/usrp/x300/x300_impl.hpp b/host/lib/usrp/x300/x300_impl.hpp
index 70c5dccb4..9ad060c85 100644
--- a/host/lib/usrp/x300/x300_impl.hpp
+++ b/host/lib/usrp/x300/x300_impl.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2013-2014 Ettus Research LLC
+// Copyright 2013-2015 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -360,8 +360,8 @@ private:
void check_fpga_compat(const uhd::fs_path &mb_path, uhd::wb_iface::sptr iface);
void update_atr_leds(gpio_core_200_32wo::sptr, const std::string &ant);
- boost::uint32_t get_fp_gpio(gpio_core_200::sptr, const std::string &);
- void set_fp_gpio(gpio_core_200::sptr, const std::string &, const boost::uint32_t);
+ boost::uint32_t get_fp_gpio(gpio_core_200::sptr);
+ void set_fp_gpio(gpio_core_200::sptr, const gpio_attr_t, const boost::uint32_t);
//**PRECONDITION**
//This function assumes that all the VITA times in "radios" are synchronized
diff --git a/host/lib/usrp/x300/x300_io_impl.cpp b/host/lib/usrp/x300/x300_io_impl.cpp
index 334ae8168..e3515af0c 100644
--- a/host/lib/usrp/x300/x300_io_impl.cpp
+++ b/host/lib/usrp/x300/x300_io_impl.cpp
@@ -23,6 +23,7 @@
#include <uhd/transport/nirio_zero_copy.hpp>
#include "async_packet_handler.hpp"
#include <uhd/transport/bounded_buffer.hpp>
+#include <uhd/transport/chdr.hpp>
#include <boost/bind.hpp>
#include <uhd/utils/tasks.hpp>
#include <uhd/utils/log.hpp>
@@ -124,41 +125,6 @@ void x300_impl::update_subdev_spec(const std::string &tx_rx, const size_t mb_i,
/***********************************************************************
- * VITA stuff
- **********************************************************************/
-static void x300_if_hdr_unpack_be(
- const boost::uint32_t *packet_buff,
- vrt::if_packet_info_t &if_packet_info
-){
- if_packet_info.link_type = vrt::if_packet_info_t::LINK_TYPE_CHDR;
- return vrt::if_hdr_unpack_be(packet_buff, if_packet_info);
-}
-
-static void x300_if_hdr_pack_be(
- boost::uint32_t *packet_buff,
- vrt::if_packet_info_t &if_packet_info
-){
- if_packet_info.link_type = vrt::if_packet_info_t::LINK_TYPE_CHDR;
- return vrt::if_hdr_pack_be(packet_buff, if_packet_info);
-}
-
-static void x300_if_hdr_unpack_le(
- const boost::uint32_t *packet_buff,
- vrt::if_packet_info_t &if_packet_info
-){
- if_packet_info.link_type = vrt::if_packet_info_t::LINK_TYPE_CHDR;
- return vrt::if_hdr_unpack_le(packet_buff, if_packet_info);
-}
-
-static void x300_if_hdr_pack_le(
- boost::uint32_t *packet_buff,
- vrt::if_packet_info_t &if_packet_info
-){
- if_packet_info.link_type = vrt::if_packet_info_t::LINK_TYPE_CHDR;
- return vrt::if_hdr_pack_le(packet_buff, if_packet_info);
-}
-
-/***********************************************************************
* RX flow control handler
**********************************************************************/
static size_t get_rx_flow_control_window(size_t frame_size, size_t sw_buff_size, const device_addr_t& rx_args)
@@ -209,9 +175,9 @@ static void handle_rx_flowctrl(const boost::uint32_t sid, zero_copy_if::sptr xpo
//load header
if (big_endian)
- x300_if_hdr_pack_be(pkt, packet_info);
+ vrt::chdr::if_hdr_pack_be(pkt, packet_info);
else
- x300_if_hdr_pack_le(pkt, packet_info);
+ vrt::chdr::if_hdr_pack_le(pkt, packet_info);
//load payload
pkt[packet_info.num_header_words32+0] = uhd::htonx<boost::uint32_t>(0);
@@ -276,12 +242,12 @@ static void handle_tx_async_msgs(boost::shared_ptr<x300_tx_fc_guts_t> guts, zero
{
if (big_endian)
{
- x300_if_hdr_unpack_be(packet_buff, if_packet_info);
+ vrt::chdr::if_hdr_unpack_be(packet_buff, if_packet_info);
endian_conv = uhd::ntohx;
}
else
{
- x300_if_hdr_unpack_le(packet_buff, if_packet_info);
+ vrt::chdr::if_hdr_unpack_le(packet_buff, if_packet_info);
endian_conv = uhd::wtohx;
}
}
@@ -430,10 +396,10 @@ rx_streamer::sptr x300_impl::get_rx_stream(const uhd::stream_args_t &args_)
//init some streamer stuff
std::string conv_endianness;
if (mb.if_pkt_is_big_endian) {
- my_streamer->set_vrt_unpacker(&x300_if_hdr_unpack_be);
+ my_streamer->set_vrt_unpacker(&vrt::chdr::if_hdr_unpack_be);
conv_endianness = "be";
} else {
- my_streamer->set_vrt_unpacker(&x300_if_hdr_unpack_le);
+ my_streamer->set_vrt_unpacker(&vrt::chdr::if_hdr_unpack_le);
conv_endianness = "le";
}
@@ -594,10 +560,10 @@ tx_streamer::sptr x300_impl::get_tx_stream(const uhd::stream_args_t &args_)
std::string conv_endianness;
if (mb.if_pkt_is_big_endian) {
- my_streamer->set_vrt_packer(&x300_if_hdr_pack_be);
+ my_streamer->set_vrt_packer(&vrt::chdr::if_hdr_pack_be);
conv_endianness = "be";
} else {
- my_streamer->set_vrt_packer(&x300_if_hdr_pack_le);
+ my_streamer->set_vrt_packer(&vrt::chdr::if_hdr_pack_le);
conv_endianness = "le";
}
diff --git a/host/lib/usrp/x300/x300_regs.hpp b/host/lib/usrp/x300/x300_regs.hpp
index f920b5ae2..4c5729efe 100644
--- a/host/lib/usrp/x300/x300_regs.hpp
+++ b/host/lib/usrp/x300/x300_regs.hpp
@@ -25,40 +25,40 @@
#define localparam static const int
-localparam SR_DACSYNC = 5;
-localparam SR_LOOPBACK = 6;
-localparam SR_TEST = 7;
-localparam SR_SPI = 8;
-localparam SR_GPIO = 16;
-localparam SR_MISC_OUTS = 24;
-localparam SR_READBACK = 32;
-localparam SR_TX_CTRL = 64;
-localparam SR_RX_CTRL = 96;
-localparam SR_TIME = 128;
-localparam SR_RX_DSP = 144;
-localparam SR_TX_DSP = 184;
-localparam SR_LEDS = 195;
-localparam SR_FP_GPIO = 200;
-localparam SR_RX_FRONT = 208;
-localparam SR_TX_FRONT = 216;
-
-localparam RB32_GPIO = 0;
-localparam RB32_SPI = 4;
-localparam RB64_TIME_NOW = 8;
-localparam RB64_TIME_PPS = 16;
-localparam RB32_TEST = 24;
-localparam RB32_RX = 28;
-localparam RB32_FP_GPIO = 32;
-
-localparam BL_ADDRESS = 0;
-localparam BL_DATA = 1;
+localparam SR_DACSYNC = 5;
+localparam SR_LOOPBACK = 6;
+localparam SR_TEST = 7;
+localparam SR_SPI = 8;
+localparam SR_GPIO = 16;
+localparam SR_MISC_OUTS = 24;
+localparam SR_READBACK = 32;
+localparam SR_TX_CTRL = 64;
+localparam SR_RX_CTRL = 96;
+localparam SR_TIME = 128;
+localparam SR_RX_DSP = 144;
+localparam SR_TX_DSP = 184;
+localparam SR_LEDS = 195;
+localparam SR_FP_GPIO = 200;
+localparam SR_RX_FRONT = 208;
+localparam SR_TX_FRONT = 216;
+
+localparam RB32_GPIO = 0;
+localparam RB32_SPI = 4;
+localparam RB64_TIME_NOW = 8;
+localparam RB64_TIME_PPS = 16;
+localparam RB32_TEST = 24;
+localparam RB32_RX = 28;
+localparam RB32_FP_GPIO = 32;
+
+localparam BL_ADDRESS = 0;
+localparam BL_DATA = 1;
//wishbone settings map - relevant to host code
-#define SET0_BASE 0xa000
-#define SETXB_BASE 0xb000
-#define BOOT_LDR_BASE 0xFA00
-#define I2C0_BASE 0xfe00
-#define I2C1_BASE 0xff00
+#define SET0_BASE 0xa000
+#define SETXB_BASE 0xb000
+#define BOOT_LDR_BASE 0xfa00
+#define I2C0_BASE 0xfe00
+#define I2C1_BASE 0xff00
#define SR_ADDR(base, offset) ((base) + (offset)*4)
localparam ZPU_SR_LEDS = 00;
@@ -70,56 +70,62 @@ localparam ZPU_SR_ETHINT0 = 40;
localparam ZPU_SR_ETHINT1 = 56;
//clock controls
-#define ZPU_SR_CLOCK_CTRL_CLK_SRC_EXTERNAL 0x00
-#define ZPU_SR_CLOCK_CTRL_CLK_SRC_INTERNAL 0x02
-#define ZPU_SR_CLOCK_CTRL_CLK_SRC_GPSDO 0x03
-#define ZPU_SR_CLOCK_CTRL_PPS_SRC_EXTERNAL 0x00
-#define ZPU_SR_CLOCK_CTRL_PPS_SRC_INTERNAL 0x02
-#define ZPU_SR_CLOCK_CTRL_PPS_SRC_GPSDO 0x03
-
-localparam ZPU_RB_SPI = 2;
+#define ZPU_SR_CLOCK_CTRL_CLK_SRC_EXTERNAL 0x00
+#define ZPU_SR_CLOCK_CTRL_CLK_SRC_INTERNAL 0x02
+#define ZPU_SR_CLOCK_CTRL_CLK_SRC_GPSDO 0x03
+#define ZPU_SR_CLOCK_CTRL_PPS_SRC_EXTERNAL 0x00
+#define ZPU_SR_CLOCK_CTRL_PPS_SRC_INTERNAL 0x02
+#define ZPU_SR_CLOCK_CTRL_PPS_SRC_GPSDO 0x03
+
+localparam ZPU_RB_SPI = 2;
localparam ZPU_RB_CLK_STATUS = 3;
localparam ZPU_RB_COMPAT_NUM = 6;
localparam ZPU_RB_ETH_TYPE0 = 4;
localparam ZPU_RB_ETH_TYPE1 = 5;
//clock status
-#define ZPU_RB_CLK_STATUS_LMK_STATUS (0x3 << 0)
-#define ZPU_RB_CLK_STATUS_LMK_LOCK (0x1 << 2)
-#define ZPU_RB_CLK_STATUS_LMK_HOLDOVER (0x1 << 3)
-#define ZPU_RB_CLK_STATUS_PPS_DETECT (0x1 << 4)
+#define ZPU_RB_CLK_STATUS_LMK_STATUS (0x3 << 0)
+#define ZPU_RB_CLK_STATUS_LMK_LOCK (0x1 << 2)
+#define ZPU_RB_CLK_STATUS_LMK_HOLDOVER (0x1 << 3)
+#define ZPU_RB_CLK_STATUS_PPS_DETECT (0x1 << 4)
//spi slaves on radio
-#define DB_DAC_SEN (1 << 7)
-#define DB_ADC_SEN (1 << 6)
+#define DB_DAC_SEN (1 << 7)
+#define DB_ADC_SEN (1 << 6)
#define DB_RX_LSADC_SEN (1 << 5)
#define DB_RX_LSDAC_SEN (1 << 4)
#define DB_TX_LSADC_SEN (1 << 3)
#define DB_TX_LSDAC_SEN (1 << 2)
-#define DB_RX_SEN (1 << 1)
-#define DB_TX_SEN (1 << 0)
+#define DB_RX_SEN (1 << 1)
+#define DB_TX_SEN (1 << 0)
//-------------------------------------------------------------------
// PCIe Registers
//-------------------------------------------------------------------
-static const uint32_t X300_PCIE_VID = 0x1093;
-static const uint32_t X300_PCIE_PID = 0xC4C4;
-static const uint32_t X300_USRP_PCIE_SSID = 0x7736;
-static const uint32_t X310_USRP_PCIE_SSID = 0x76CA;
-static const uint32_t X310_2940R_PCIE_SSID = 0x772B;
-static const uint32_t X310_2942R_PCIE_SSID = 0x772C;
-static const uint32_t X310_2943R_PCIE_SSID = 0x772D;
-static const uint32_t X310_2944R_PCIE_SSID = 0x772E;
-static const uint32_t X310_2950R_PCIE_SSID = 0x772F;
-static const uint32_t X310_2952R_PCIE_SSID = 0x7730;
-static const uint32_t X310_2953R_PCIE_SSID = 0x7731;
-static const uint32_t X310_2954R_PCIE_SSID = 0x7732;
+static const uint32_t X300_PCIE_VID = 0x1093;
+static const uint32_t X300_PCIE_PID = 0xC4C4;
+static const uint32_t X300_USRP_PCIE_SSID = 0x7736;
+static const uint32_t X310_USRP_PCIE_SSID = 0x76CA;
+static const uint32_t X310_2940R_40MHz_PCIE_SSID = 0x772B;
+static const uint32_t X310_2940R_120MHz_PCIE_SSID = 0x77FB;
+static const uint32_t X310_2942R_40MHz_PCIE_SSID = 0x772C;
+static const uint32_t X310_2942R_120MHz_PCIE_SSID = 0x77FC;
+static const uint32_t X310_2943R_40MHz_PCIE_SSID = 0x772D;
+static const uint32_t X310_2943R_120MHz_PCIE_SSID = 0x77FD;
+static const uint32_t X310_2944R_40MHz_PCIE_SSID = 0x772E;
+static const uint32_t X310_2950R_40MHz_PCIE_SSID = 0x772F;
+static const uint32_t X310_2950R_120MHz_PCIE_SSID = 0x77FE;
+static const uint32_t X310_2952R_40MHz_PCIE_SSID = 0x7730;
+static const uint32_t X310_2952R_120MHz_PCIE_SSID = 0x77FF;
+static const uint32_t X310_2953R_40MHz_PCIE_SSID = 0x7731;
+static const uint32_t X310_2953R_120MHz_PCIE_SSID = 0x7800;
+static const uint32_t X310_2954R_40MHz_PCIE_SSID = 0x7732;
static const uint32_t FPGA_X3xx_SIG_VALUE = 0x58333030;
static const uint32_t PCIE_FPGA_ADDR_BASE = 0xC0000;
-#define PCIE_FPGA_REG(X) (PCIE_FPGA_ADDR_BASE + X)
+#define PCIE_FPGA_REG(X) (PCIE_FPGA_ADDR_BASE + (X))
static const uint32_t FPGA_PCIE_SIG_REG = PCIE_FPGA_REG(0x0000);
static const uint32_t FPGA_CNTR_LO_REG = PCIE_FPGA_REG(0x0004);
@@ -140,8 +146,8 @@ static const uint32_t DMA_FRAME_SIZE_REG = 0x4;
static const uint32_t DMA_SAMPLE_COUNT_REG = 0x8;
static const uint32_t DMA_PKT_COUNT_REG = 0xC;
-#define PCIE_TX_DMA_REG(REG, CHAN) (PCIE_TX_DMA_REG_BASE + (CHAN*DMA_REG_GRP_SIZE) + REG)
-#define PCIE_RX_DMA_REG(REG, CHAN) (PCIE_RX_DMA_REG_BASE + (CHAN*DMA_REG_GRP_SIZE) + REG)
+#define PCIE_TX_DMA_REG(REG, CHAN) (PCIE_TX_DMA_REG_BASE + ((CHAN)*DMA_REG_GRP_SIZE) + (REG))
+#define PCIE_RX_DMA_REG(REG, CHAN) (PCIE_RX_DMA_REG_BASE + ((CHAN)*DMA_REG_GRP_SIZE) + (REG))
static const uint32_t DMA_CTRL_DISABLED = 0x00000000;
static const uint32_t DMA_CTRL_ENABLED = 0x00000002;
@@ -154,15 +160,15 @@ static const uint32_t DMA_STATUS_ERROR = 0x00000001;
static const uint32_t DMA_STATUS_BUSY = 0x00000002;
static const uint32_t PCIE_ROUTER_REG_BASE = PCIE_FPGA_REG(0x0500);
-#define PCIE_ROUTER_REG(X) (PCIE_ROUTER_REG_BASE + X)
+#define PCIE_ROUTER_REG(X) (PCIE_ROUTER_REG_BASE + (X))
static const uint32_t PCIE_ZPU_DATA_BASE = 0x30000;
static const uint32_t PCIE_ZPU_READ_BASE = 0x20000; //Trig and Status share the same base
static const uint32_t PCIE_ZPU_STATUS_BASE = 0x20000;
-#define PCIE_ZPU_DATA_REG(X) (PCIE_FPGA_REG(PCIE_ZPU_DATA_BASE) + X)
-#define PCIE_ZPU_READ_REG(X) (PCIE_FPGA_REG(PCIE_ZPU_READ_BASE) + X)
-#define PCIE_ZPU_STATUS_REG(X) (PCIE_FPGA_REG(PCIE_ZPU_STATUS_BASE) + X)
+#define PCIE_ZPU_DATA_REG(X) (PCIE_FPGA_REG(PCIE_ZPU_DATA_BASE) + (X))
+#define PCIE_ZPU_READ_REG(X) (PCIE_FPGA_REG(PCIE_ZPU_READ_BASE) + (X))
+#define PCIE_ZPU_STATUS_REG(X) (PCIE_FPGA_REG(PCIE_ZPU_STATUS_BASE) + (X))
static const uint32_t PCIE_ZPU_READ_START = 0x0;
static const uint32_t PCIE_ZPU_READ_CLOBBER = 0x80000000;
diff --git a/host/lib/utils/platform.cpp b/host/lib/utils/platform.cpp
index e2f92039e..a9cef663b 100644
--- a/host/lib/utils/platform.cpp
+++ b/host/lib/utils/platform.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2012 Ettus Research LLC
+// Copyright 2010-2012,2014 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
@@ -19,7 +19,7 @@
#include <uhd/config.hpp>
#include <boost/functional/hash.hpp>
#ifdef UHD_PLATFORM_WIN32
-#include <Windows.h>
+#include <windows.h>
#else
#include <unistd.h>
#endif
diff --git a/host/tests/CMakeLists.txt b/host/tests/CMakeLists.txt
index 62544b69b..596ab1017 100644
--- a/host/tests/CMakeLists.txt
+++ b/host/tests/CMakeLists.txt
@@ -27,16 +27,19 @@ SET(test_sources
addr_test.cpp
buffer_test.cpp
byteswap_test.cpp
- convert_test.cpp
cast_test.cpp
+ chdr_test.cpp
+ convert_test.cpp
dict_test.cpp
error_test.cpp
fp_compare_delta_test.cpp
fp_compare_epsilon_test.cpp
gain_group_test.cpp
+ math_test.cpp
msg_test.cpp
property_test.cpp
ranges_test.cpp
+ sid_t_test.cpp
sph_recv_test.cpp
sph_send_test.cpp
subdev_spec_test.cpp
@@ -45,7 +48,11 @@ SET(test_sources
)
#turn each test cpp file into an executable with an int main() function
-ADD_DEFINITIONS(-DBOOST_TEST_DYN_LINK -DBOOST_TEST_MAIN)
+IF(MINGW)
+ ADD_DEFINITIONS(-DBOOST_TEST_MAIN)
+ELSE()
+ ADD_DEFINITIONS(-DBOOST_TEST_DYN_LINK -DBOOST_TEST_MAIN)
+ENDIF()
SET(UHD_TEST_TARGET_DEPS uhd)
SET(UHD_TEST_LIBRARY_DIRS ${Boost_LIBRARY_DIRS})
@@ -54,7 +61,7 @@ SET(UHD_TEST_LIBRARY_DIRS ${Boost_LIBRARY_DIRS})
FOREACH(test_source ${test_sources})
GET_FILENAME_COMPONENT(test_name ${test_source} NAME_WE)
ADD_EXECUTABLE(${test_name} ${test_source})
- TARGET_LINK_LIBRARIES(${test_name} uhd)
+ TARGET_LINK_LIBRARIES(${test_name} uhd ${Boost_LIBRARIES})
UHD_ADD_TEST(${test_name} ${test_name})
UHD_INSTALL(TARGETS ${test_name} RUNTIME DESTINATION ${PKG_LIB_DIR}/tests COMPONENT tests)
ENDFOREACH(test_source)
diff --git a/host/tests/addr_test.cpp b/host/tests/addr_test.cpp
index cea2f224c..61bb6d049 100644
--- a/host/tests/addr_test.cpp
+++ b/host/tests/addr_test.cpp
@@ -66,6 +66,13 @@ BOOST_AUTO_TEST_CASE(test_device_addr){
old_dev_addr_vals.begin(), old_dev_addr_vals.end(),
new_dev_addr_vals.begin(), new_dev_addr_vals.end()
);
+
+ uhd::device_addr_t dev_addr_lhs1("key1=val1,key2=val2");
+ dev_addr_lhs1.update(uhd::device_addr_t("key2=val2x,key3=val3"), false);
+ BOOST_CHECK_EQUAL(dev_addr_lhs1["key1"], "val1");
+ BOOST_CHECK_EQUAL(dev_addr_lhs1["key2"], "val2x");
+ BOOST_CHECK_EQUAL(dev_addr_lhs1["key3"], "val3");
+ std::cout << "Merged: " << dev_addr_lhs1.to_string() << std::endl;
}
BOOST_AUTO_TEST_CASE(test_dboard_id){
diff --git a/host/tests/chdr_test.cpp b/host/tests/chdr_test.cpp
new file mode 100644
index 000000000..ed6c690f9
--- /dev/null
+++ b/host/tests/chdr_test.cpp
@@ -0,0 +1,141 @@
+//
+// Copyright 2014 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <uhd/transport/chdr.hpp>
+#include <uhd/utils/byteswap.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/format.hpp>
+#include <cstdlib>
+#include <iostream>
+
+using namespace uhd::transport::vrt;
+
+static void pack_and_unpack(
+ if_packet_info_t &if_packet_info_in
+){
+ // Temp buffer for packed packet
+ boost::uint32_t packet_buff[2048] = {0};
+
+ // Check input (must not be lazy)
+ BOOST_REQUIRE(
+ (if_packet_info_in.num_payload_words32 == 0 and if_packet_info_in.num_payload_bytes == 0)
+ or
+ (if_packet_info_in.num_payload_words32 != 0 and if_packet_info_in.num_payload_bytes != 0)
+ );
+ if (if_packet_info_in.num_payload_words32) {
+ BOOST_REQUIRE(if_packet_info_in.num_payload_bytes <= 4 * if_packet_info_in.num_payload_words32);
+ BOOST_REQUIRE(if_packet_info_in.num_payload_bytes > 4*(if_packet_info_in.num_payload_words32-1));
+ }
+
+ //pack metadata into a vrt header
+ chdr::if_hdr_pack_be(
+ packet_buff, if_packet_info_in
+ );
+ std::cout << std::endl;
+ boost::uint32_t header_bits = (uhd::ntohx(packet_buff[0]) >> 28);
+ std::cout << boost::format("header bits = 0b%d%d%d%d") % bool(header_bits & 8) % bool(header_bits & 4) % bool(header_bits & 2) % bool(header_bits & 1) << std::endl;
+ for (size_t i = 0; i < 5; i++)
+ {
+ std::cout << boost::format("packet_buff[%u] = 0x%08x") % i % uhd::ntohx(packet_buff[i]) << std::endl;
+ }
+
+ if_packet_info_t if_packet_info_out;
+ // Must be set a-priori as per contract
+ if_packet_info_out.num_packet_words32 = if_packet_info_in.num_packet_words32;
+
+ //unpack the vrt header back into metadata
+ chdr::if_hdr_unpack_be(
+ packet_buff, if_packet_info_out
+ );
+
+ //check the the unpacked metadata is the same
+ BOOST_CHECK_EQUAL(if_packet_info_in.packet_count, if_packet_info_out.packet_count);
+ BOOST_CHECK_EQUAL(if_packet_info_in.num_header_words32, if_packet_info_out.num_header_words32);
+ BOOST_CHECK_EQUAL(if_packet_info_in.num_payload_words32, if_packet_info_out.num_payload_words32);
+ BOOST_CHECK(if_packet_info_out.has_sid);
+ BOOST_CHECK_EQUAL(if_packet_info_in.sid, if_packet_info_out.sid);
+ BOOST_CHECK(if_packet_info_out.has_sid);
+ BOOST_CHECK_EQUAL(if_packet_info_in.has_tsf, if_packet_info_out.has_tsf);
+ if (if_packet_info_in.has_tsf and if_packet_info_out.has_tsf){
+ BOOST_CHECK_EQUAL(if_packet_info_in.tsf, if_packet_info_out.tsf);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_with_chdr){
+ if_packet_info_t if_packet_info;
+ if_packet_info.packet_type = if_packet_info_t::PACKET_TYPE_DATA;
+ if_packet_info.eob = false;
+ if_packet_info.packet_count = 7;
+ if_packet_info.has_tsf = true;
+ if_packet_info.tsf = 0x1234567890ABCDEFull;
+ if_packet_info.sid = 0xAABBCCDD;
+ if_packet_info.num_payload_words32 = 24;
+ if_packet_info.num_payload_bytes = 95;
+ pack_and_unpack(if_packet_info);
+}
+
+BOOST_AUTO_TEST_CASE(test_with_chdr_fc){
+ if_packet_info_t if_packet_info;
+ if_packet_info.packet_type = if_packet_info_t::PACKET_TYPE_FC;
+ if_packet_info.eob = false;
+ if_packet_info.packet_count = 19;
+ if_packet_info.has_tsf = false;
+ if_packet_info.tsf = 0x1234567890ABCDEFull;
+ if_packet_info.sid = 0xAABBCCDD;
+ if_packet_info.num_payload_words32 = 4;
+ if_packet_info.num_payload_bytes = 16;
+ pack_and_unpack(if_packet_info);
+}
+
+BOOST_AUTO_TEST_CASE(test_with_chdr_cmd){
+ if_packet_info_t if_packet_info;
+ if_packet_info.packet_type = if_packet_info_t::PACKET_TYPE_CMD;
+ if_packet_info.packet_count = 19;
+ if_packet_info.has_tsf = true;
+ if_packet_info.tsf = 0x1234567890ABCDEFull;
+ if_packet_info.sid = 0xAABBCCDD;
+ if_packet_info.num_payload_words32 = 4;
+ if_packet_info.num_payload_bytes = 16;
+ pack_and_unpack(if_packet_info);
+}
+
+BOOST_AUTO_TEST_CASE(test_with_chdr_resp){
+ if_packet_info_t if_packet_info;
+ if_packet_info.packet_type = if_packet_info_t::PACKET_TYPE_RESP;
+ if_packet_info.packet_count = 123;
+ if_packet_info.has_tsf = false;
+ if_packet_info.tsf = 0x1234567890ABCDEFull;
+ if_packet_info.sid = 0xAABBCCDD;
+ if_packet_info.num_payload_words32 = 4;
+ if_packet_info.num_payload_bytes = 16;
+ pack_and_unpack(if_packet_info);
+}
+
+BOOST_AUTO_TEST_CASE(test_with_chdr_err){
+ if_packet_info_t if_packet_info;
+ if_packet_info.packet_type = if_packet_info_t::PACKET_TYPE_ERROR;
+ if_packet_info.packet_count = 1928;
+ if_packet_info.eob = false;
+ if_packet_info.error = false; // Needs to be set explicitly
+ if_packet_info.has_tsf = false;
+ if_packet_info.tsf = 0x1234567890ABCDEFull;
+ if_packet_info.sid = 0xAABBCCDD;
+ if_packet_info.num_payload_words32 = 4;
+ if_packet_info.num_payload_bytes = 16;
+ pack_and_unpack(if_packet_info);
+}
+
diff --git a/host/tests/dict_test.cpp b/host/tests/dict_test.cpp
index 7b388d090..333aadbba 100644
--- a/host/tests/dict_test.cpp
+++ b/host/tests/dict_test.cpp
@@ -70,3 +70,28 @@ BOOST_AUTO_TEST_CASE(test_dict_pop){
BOOST_CHECK(d.keys()[0] == -1);
BOOST_CHECK(d.keys()[1] == 1);
}
+
+BOOST_AUTO_TEST_CASE(test_dict_update)
+{
+ uhd::dict<std::string, std::string> d1 = boost::assign::map_list_of
+ ("key1", "val1")
+ ("key2", "val2")
+ ;
+ uhd::dict<std::string, std::string> d2 = boost::assign::map_list_of
+ ("key2", "val2x")
+ ("key3", "val3")
+ ;
+
+ d1.update(d2, false /* don't throw cause of conflict */);
+ BOOST_CHECK_EQUAL(d1["key1"], "val1");
+ BOOST_CHECK_EQUAL(d1["key2"], "val2x");
+ BOOST_CHECK_EQUAL(d1["key3"], "val3");
+
+ uhd::dict<std::string, std::string> d3 = boost::assign::map_list_of
+ ("key1", "val1")
+ ("key2", "val2")
+ ;
+ BOOST_CHECK_THROW(d3.update(d2), uhd::value_error);
+}
+
+
diff --git a/host/tests/fp_compare_delta_test.cpp b/host/tests/fp_compare_delta_test.cpp
index 0ac4e257d..36ff14756 100644
--- a/host/tests/fp_compare_delta_test.cpp
+++ b/host/tests/fp_compare_delta_test.cpp
@@ -239,12 +239,12 @@ BOOST_AUTO_TEST_CASE(double_greaterthanequals_operators) {
BOOST_AUTO_TEST_CASE(frequency_compare_function) {
- BOOST_CHECK(uhd::math::frequencies_are_equal(6817333232, 6817333232));
- BOOST_CHECK(!uhd::math::frequencies_are_equal(6817333233, 6817333232));
+ BOOST_CHECK(uhd::math::frequencies_are_equal(6817333232.0, 6817333232.0));
+ BOOST_CHECK(!uhd::math::frequencies_are_equal(6817333233.0, 6817333232.0));
BOOST_CHECK(uhd::math::frequencies_are_equal(6817333232.1, 6817333232.1));
BOOST_CHECK(!uhd::math::frequencies_are_equal(6817333232.5, 6817333232.6));
BOOST_CHECK(uhd::math::frequencies_are_equal(16.8173332321e9, 16.8173332321e9));
BOOST_CHECK(!uhd::math::frequencies_are_equal(16.8173332322e9, 16.8173332321e9));
BOOST_CHECK(!uhd::math::frequencies_are_equal(5.0, 4.0));
- BOOST_CHECK(uhd::math::frequencies_are_equal(48750000, 48749999.9946));
+ BOOST_CHECK(uhd::math::frequencies_are_equal(48750000.0, 48749999.9946));
}
diff --git a/host/tests/math_test.cpp b/host/tests/math_test.cpp
new file mode 100644
index 000000000..6c890c484
--- /dev/null
+++ b/host/tests/math_test.cpp
@@ -0,0 +1,29 @@
+//
+// Copyright 2014 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 <boost/test/unit_test.hpp>
+#include <boost/cstdint.hpp>
+#include <uhd/utils/math.hpp>
+
+// NOTE: This is not the only math test case, see e.g. special tests
+// for fp comparison.
+
+BOOST_AUTO_TEST_CASE(test_log2){
+ double y = uhd::math::log2(16.0);
+ BOOST_CHECK_EQUAL(y, 4.0);
+}
+
diff --git a/host/tests/sid_t_test.cpp b/host/tests/sid_t_test.cpp
new file mode 100644
index 000000000..b5cdeb3d8
--- /dev/null
+++ b/host/tests/sid_t_test.cpp
@@ -0,0 +1,158 @@
+//
+// Copyright 2014 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 <iostream>
+#include <sstream>
+#include <boost/test/unit_test.hpp>
+#include <uhd/types/sid.hpp>
+#include <uhd/exception.hpp>
+
+using uhd::sid_t;
+
+BOOST_AUTO_TEST_CASE(test_sid_t) {
+ boost::uint32_t sid_value = 0x01020310;
+ sid_t sid(sid_value);
+
+ BOOST_CHECK_EQUAL(sid.is_set(), true);
+ BOOST_CHECK_EQUAL(sid.to_pp_string(), "1.2>3.16");
+ BOOST_CHECK_EQUAL(sid.to_pp_string_hex(), "01:02>03:10");
+ BOOST_CHECK_EQUAL(sid.get_src(), (uint32_t)0x0102);
+ BOOST_CHECK_EQUAL(sid.get_dst(), (uint32_t)0x0310);
+ BOOST_CHECK_EQUAL(sid.get_src_addr(), (uint32_t)0x01);
+ BOOST_CHECK_EQUAL(sid.get_src_endpoint(), (uint32_t)0x02);
+ BOOST_CHECK_EQUAL(sid.get_dst_addr(), (uint32_t)0x03);
+ BOOST_CHECK_EQUAL(sid.get_dst_endpoint(), (uint32_t)0x10);
+ BOOST_CHECK_EQUAL(sid == sid, true);
+ BOOST_CHECK_EQUAL(sid == sid_value, true);
+
+ boost::uint32_t check_sid_val = (boost::uint32_t) sid;
+ BOOST_CHECK_EQUAL(check_sid_val, sid_value);
+
+ std::stringstream ss_dec;
+ ss_dec << sid;
+ BOOST_CHECK_EQUAL(ss_dec.str(), "1.2>3.16");
+
+ std::stringstream ss_hex;
+ ss_hex << std::hex << sid;
+ BOOST_CHECK_EQUAL(ss_hex.str(), "01:02>03:10");
+
+ sid_t empty_sid;
+ BOOST_CHECK_EQUAL(empty_sid.is_set(), false);
+ BOOST_CHECK_EQUAL(empty_sid.to_pp_string(), "x.x>x.x");
+ BOOST_CHECK_EQUAL(empty_sid.to_pp_string_hex(), "xx:xx>xx:xx");
+ BOOST_CHECK_EQUAL(empty_sid == sid, false);
+ BOOST_CHECK_EQUAL(empty_sid == sid_value, false);
+ BOOST_CHECK_EQUAL((bool) empty_sid, false);
+
+ empty_sid = sid_value; // No longer empty
+ BOOST_CHECK_EQUAL(empty_sid.is_set(), true);
+ BOOST_CHECK_EQUAL(empty_sid == sid, true);
+}
+
+BOOST_AUTO_TEST_CASE(test_sid_t_set) {
+ boost::uint32_t sid_value = 0x0;
+ sid_t sid(sid_value);
+
+ sid.set(0x01020304);
+ BOOST_CHECK_EQUAL(sid.get(), (uint32_t)0x01020304);
+ BOOST_CHECK_EQUAL(sid.get_src_addr(),(uint32_t)0x01);
+ BOOST_CHECK_EQUAL(sid.get_src_endpoint(), (uint32_t)0x02);
+ BOOST_CHECK_EQUAL(sid.get_dst_addr(), (uint32_t)0x03);
+ BOOST_CHECK_EQUAL(sid.get_dst_endpoint(), (uint32_t)0x04);
+ BOOST_CHECK_EQUAL(sid.get_dst_xbarport(), (uint32_t)0x0);
+ BOOST_CHECK_EQUAL(sid.get_dst_blockport(), (uint32_t)0x4);
+
+ sid.set_src_addr(0x0a);
+ BOOST_CHECK_EQUAL(sid.get(), (uint32_t)0x0a020304);
+ BOOST_CHECK_EQUAL(sid.get_src_addr(), (uint32_t)0x0a);
+ BOOST_CHECK_EQUAL(sid.get_src_endpoint(), (uint32_t)0x02);
+ BOOST_CHECK_EQUAL(sid.get_dst_addr(), (uint32_t)0x03);
+ BOOST_CHECK_EQUAL(sid.get_dst_endpoint(), (uint32_t)0x04);
+
+ sid.set_src_endpoint(0x0b);
+ BOOST_CHECK_EQUAL(sid.get(), (uint32_t)0x0a0b0304);
+ BOOST_CHECK_EQUAL(sid.get_src_addr(), (uint32_t)0x0a);
+ BOOST_CHECK_EQUAL(sid.get_src_endpoint(), (uint32_t)0x0b);
+ BOOST_CHECK_EQUAL(sid.get_dst_addr(), (uint32_t)0x03);
+ BOOST_CHECK_EQUAL(sid.get_dst_endpoint(), (uint32_t)0x04);
+
+ sid.set_dst_addr(0x0c);
+ BOOST_CHECK_EQUAL(sid.get(), (uint32_t)0x0a0b0c04);
+ BOOST_CHECK_EQUAL(sid.get_src_addr(), (uint32_t)0x0a);
+ BOOST_CHECK_EQUAL(sid.get_src_endpoint(), (uint32_t)0x0b);
+ BOOST_CHECK_EQUAL(sid.get_dst_addr(), (uint32_t)0x0c);
+ BOOST_CHECK_EQUAL(sid.get_dst_endpoint(), (uint32_t)0x04);
+
+ sid.set_dst_endpoint(0x0d);
+ BOOST_CHECK_EQUAL(sid.get(), (uint32_t)0x0a0b0c0d);
+ BOOST_CHECK_EQUAL(sid.get_src_addr(), (uint32_t)0x0a);
+ BOOST_CHECK_EQUAL(sid.get_src_endpoint(), (uint32_t)0x0b);
+ BOOST_CHECK_EQUAL(sid.get_dst_addr(), (uint32_t)0x0c);
+ BOOST_CHECK_EQUAL(sid.get_dst_endpoint(), (uint32_t)0x0d);
+
+ sid.set_dst_xbarport(0xb);
+ BOOST_CHECK_EQUAL(sid.get(), (uint32_t)0x0a0b0cbd);
+ BOOST_CHECK_EQUAL(sid.get_src_addr(), (uint32_t)0x0a);
+ BOOST_CHECK_EQUAL(sid.get_src_endpoint(), (uint32_t)0x0b);
+ BOOST_CHECK_EQUAL(sid.get_dst_addr(), (uint32_t)0x0c);
+ BOOST_CHECK_EQUAL(sid.get_dst_endpoint(), (uint32_t)0xbd);
+
+ sid.set_dst_blockport(0xc);
+ BOOST_CHECK_EQUAL(sid.get(), (uint32_t)0x0a0b0cbc);
+ BOOST_CHECK_EQUAL(sid.get_src_addr(), (uint32_t)0x0a);
+ BOOST_CHECK_EQUAL(sid.get_src_endpoint(), (uint32_t)0x0b);
+ BOOST_CHECK_EQUAL(sid.get_dst_addr(), (uint32_t)0x0c);
+ BOOST_CHECK_EQUAL(sid.get_dst_endpoint(), (uint32_t)0xbc);
+
+ sid_t flipped_sid = sid.reversed();
+ BOOST_CHECK_EQUAL(flipped_sid.get(), (uint32_t)0x0cbc0a0b);
+
+ // In-place
+ sid.reverse();
+ BOOST_CHECK_EQUAL(sid.get(), (uint32_t)0x0cbc0a0b);
+}
+
+BOOST_AUTO_TEST_CASE(test_sid_t_from_str) {
+ sid_t sid("1.2>3.4");
+ BOOST_CHECK_EQUAL(sid.get_src_addr(), (uint32_t)1);
+ BOOST_CHECK_EQUAL(sid.get_src_endpoint(), (uint32_t)2);
+ BOOST_CHECK_EQUAL(sid.get_dst_addr(), (uint32_t)3);
+ BOOST_CHECK_EQUAL(sid.get_dst_endpoint(), (uint32_t)4);
+
+ sid = "01:02>03:10";
+ BOOST_CHECK_EQUAL(sid.get_src_addr(), (uint32_t)1);
+ BOOST_CHECK_EQUAL(sid.get_src_endpoint(), (uint32_t)2);
+ BOOST_CHECK_EQUAL(sid.get_dst_addr(), (uint32_t)3);
+ BOOST_CHECK_EQUAL(sid.get_dst_endpoint(), (uint32_t)16);
+
+ sid = "01:06/03:10";
+ BOOST_CHECK_EQUAL(sid.get_src_addr(), (uint32_t)1);
+ BOOST_CHECK_EQUAL(sid.get_src_endpoint(), (uint32_t)6);
+ BOOST_CHECK_EQUAL(sid.get_dst_addr(), (uint32_t)3);
+ BOOST_CHECK_EQUAL(sid.get_dst_endpoint(), (uint32_t)16);
+
+ sid = "01:02:04:10";
+ BOOST_CHECK_EQUAL(sid.get_src_addr(), (uint32_t)1);
+ BOOST_CHECK_EQUAL(sid.get_src_endpoint(), (uint32_t)2);
+ BOOST_CHECK_EQUAL(sid.get_dst_addr(), (uint32_t)4);
+ BOOST_CHECK_EQUAL(sid.get_dst_endpoint(), (uint32_t)16);
+
+ BOOST_REQUIRE_THROW(sid_t fail_sid("foobar"), uhd::value_error);
+ BOOST_REQUIRE_THROW(sid_t fail_sid("01:02:03:4"), uhd::value_error);
+ BOOST_REQUIRE_THROW(sid_t fail_sid("01:02:03:004"), uhd::value_error);
+ BOOST_REQUIRE_THROW(sid_t fail_sid("1.2.3.0004"), uhd::value_error);
+}
diff --git a/host/tests/time_spec_test.cpp b/host/tests/time_spec_test.cpp
index c9b9652f9..b98bea7d9 100644
--- a/host/tests/time_spec_test.cpp
+++ b/host/tests/time_spec_test.cpp
@@ -112,8 +112,8 @@ BOOST_AUTO_TEST_CASE(test_time_large_ticks_to_time_spec)
BOOST_AUTO_TEST_CASE(test_time_error_irrational_rate)
{
- static const double rate = 1625e3/6;
- const long long tick_in = 23423436291667;
+ static const double rate = 1625e3/6.0;
+ const long long tick_in = 23423436291667ll;
const uhd::time_spec_t ts = uhd::time_spec_t::from_ticks(tick_in, rate);
const long long tick_out = ts.to_ticks(rate);
const long long err = tick_in - tick_out;
diff --git a/host/utils/b2xx_fx3_utils.cpp b/host/utils/b2xx_fx3_utils.cpp
index 572daef70..bc14932f1 100644
--- a/host/utils/b2xx_fx3_utils.cpp
+++ b/host/utils/b2xx_fx3_utils.cpp
@@ -51,20 +51,26 @@ struct vid_pid_t {
const static vid_pid_t known_vid_pids[] = {
{FX3_VID, FX3_DEFAULT_PID},
{FX3_VID, FX3_REENUM_PID},
- {B200_VENDOR_ID, B200_PRODUCT_ID}
+ {B200_VENDOR_ID, B200_PRODUCT_ID},
+ {B200_VENDOR_NI_ID, B200_PRODUCT_NI_ID},
+ {B200_VENDOR_NI_ID, B210_PRODUCT_NI_ID}
};
const static std::vector<vid_pid_t> known_vid_pid_vector(known_vid_pids, known_vid_pids + (sizeof(known_vid_pids) / sizeof(known_vid_pids[0])));
-const static boost::uint8_t eeprom_init_values[] = {
- 0x43,
- 0x59,
- 0x14,
- 0xB2,
- (B200_PRODUCT_ID & 0xff),
- (B200_PRODUCT_ID >> 8),
- (B200_VENDOR_ID & 0xff),
- (B200_VENDOR_ID >> 8)
- };
-const static uhd::byte_vector_t eeprom_init_value_vector(eeprom_init_values, eeprom_init_values + (sizeof(eeprom_init_values) / sizeof(eeprom_init_values[0])));
+
+static const size_t EEPROM_INIT_VALUE_VECTOR_SIZE = 8;
+static uhd::byte_vector_t construct_eeprom_init_value_vector(boost::uint16_t vid, boost::uint16_t pid)
+{
+ uhd::byte_vector_t init_values(EEPROM_INIT_VALUE_VECTOR_SIZE);
+ init_values.at(0) = 0x43;
+ init_values.at(1) = 0x59;
+ init_values.at(2) = 0x14;
+ init_values.at(3) = 0xB2;
+ init_values.at(4) = static_cast<boost::uint8_t>(pid & 0xff);
+ init_values.at(5) = static_cast<boost::uint8_t>(pid >> 8);
+ init_values.at(6) = static_cast<boost::uint8_t>(vid & 0xff);
+ init_values.at(7) = static_cast<boost::uint8_t>(vid >> 8);
+ return init_values;
+}
//!used with lexical cast to parse a hex string
template <class T> struct to_hex{
@@ -153,15 +159,22 @@ uhd::transport::usb_device_handle::sptr open_device(const boost::uint16_t vid, c
try {
// try caller's VID/PID first
- handles = uhd::transport::usb_device_handle::get_device_list(vp.vid,vp.pid);
- if (user_supplied && handles.size() == 0)
- std::cerr << (boost::format("Failed to open device with VID 0x%04x and PID 0x%04x - trying other known VID/PIDs") % vid % pid).str() << std::endl;
-
- // try known VID/PIDs next
- for (size_t i = 0; handles.size() == 0 && i < known_vid_pid_vector.size(); i++)
+ std::vector<uhd::transport::usb_device_handle::vid_pid_pair_t> vid_pid_pair_list(1,uhd::transport::usb_device_handle::vid_pid_pair_t(vid,pid));
+ handles = uhd::transport::usb_device_handle::get_device_list(vid_pid_pair_list);
+ if (handles.size() == 0)
{
- vp = known_vid_pid_vector[i];
- handles = uhd::transport::usb_device_handle::get_device_list(vp.vid,vp.pid);
+ if (user_supplied)
+ {
+ std::cerr << (boost::format("Failed to open device with VID 0x%04x and PID 0x%04x - trying other known VID/PIDs") % vid % pid).str() << std::endl;
+ }
+
+ // try known VID/PIDs next
+ for (size_t i = 0; handles.size() == 0 && i < known_vid_pid_vector.size(); i++)
+ {
+ vp = known_vid_pid_vector[i];
+ handles = uhd::transport::usb_device_handle::get_device_list(vp.vid, vp.pid);
+ }
+
}
if (handles.size() > 0)
@@ -221,7 +234,7 @@ int read_eeprom(b200_iface::sptr& b200, uhd::byte_vector_t& data)
int write_eeprom(b200_iface::sptr& b200, const uhd::byte_vector_t& data)
{
try {
- b200->write_eeprom(0x0, 0x0, data);
+ b200->write_eeprom(0x0, 0x0, data);
} catch (std::exception &e) {
std::cerr << "Exception while writing EEPROM: " << e.what() << std::endl;
return -1;
@@ -281,7 +294,7 @@ int erase_eeprom(b200_iface::sptr& b200)
boost::int32_t main(boost::int32_t argc, char *argv[]) {
boost::uint16_t vid, pid;
- std::string pid_str, vid_str, fw_file, fpga_file;
+ std::string pid_str, vid_str, fw_file, fpga_file, writevid_str, writepid_str;
bool user_supplied_vid_pid = false;
po::options_description visible("Allowed options");
@@ -295,7 +308,6 @@ boost::int32_t main(boost::int32_t argc, char *argv[]) {
("reset-device,D", "Reset the B2xx Device.")
("reset-fpga,F", "Reset the FPGA (does not require re-programming.")
("reset-usb,U", "Reset the USB subsystem on your host computer.")
- ("init-device,I", "Initialize a B2xx device.")
("load-fw,W", po::value<std::string>(&fw_file),
"Load a firmware (hex) file into the FX3.")
("load-fpga,L", po::value<std::string>(&fpga_file),
@@ -305,9 +317,14 @@ boost::int32_t main(boost::int32_t argc, char *argv[]) {
// Hidden options provided for testing - use at your own risk!
po::options_description hidden("Hidden options");
hidden.add_options()
- ("uninit-device,U", "Uninitialize a B2xx device.")
+ ("init-device,I", "Initialize a B2xx device.")
+ ("uninit-device", "Uninitialize a B2xx device.")
("read-eeprom,R", "Read first 8 bytes of EEPROM")
- ("erase-eeprom,E", "Erase first 8 bytes of EEPROM");
+ ("erase-eeprom,E", "Erase first 8 bytes of EEPROM")
+ ("write-vid", po::value<std::string>(&writevid_str),
+ "Write VID field of EEPROM")
+ ("write-pid", po::value<std::string>(&writepid_str),
+ "Write PID field of EEPROM");
po::options_description desc;
desc.add(visible);
@@ -486,9 +503,24 @@ boost::int32_t main(boost::int32_t argc, char *argv[]) {
* Cypress VID/PID for the initial FW load, but we can initialize from any state. */
if (vm.count("init-device"))
{
+ uint16_t writevid = B200_VENDOR_ID;
+ uint16_t writepid = B200_PRODUCT_ID;
+
/* Now, initialize the device. */
- if (write_and_verify_eeprom(b200, eeprom_init_value_vector))
- return -1;
+ // Added for testing purposes - not exposed
+ if (vm.count("write-vid") && vm.count("write-pid"))
+ {
+ try {
+ writevid = atoh(writevid_str);
+ writepid = atoh(writepid_str);
+ } catch (std::exception &e) {
+ std::cerr << "Exception while parsing write VID and PID: " << e.what() << std:: endl;
+ return ~0;
+ }
+ }
+
+ std::cout << "Writing VID and PID to EEPROM..." << std::endl << std::endl;
+ if (write_and_verify_eeprom(b200, construct_eeprom_init_value_vector(writevid, writepid))) return -1;
std::cout << "EEPROM initialized, resetting device..."
<< std::endl << std::endl;
diff --git a/tools/uhd_txrx_debug_prints/uhd_txrx_debug_prints_README.md b/tools/uhd_txrx_debug_prints/uhd_txrx_debug_prints_README.md
new file mode 100644
index 000000000..1425a4d96
--- /dev/null
+++ b/tools/uhd_txrx_debug_prints/uhd_txrx_debug_prints_README.md
@@ -0,0 +1,17 @@
+UHD TX/RX DEBUG PRINTS
+======================
+
+A tool for extensive debugging with UHD.
+
+Install
+-------
+Activate it by ticking `UHD_TXRX_DEBUG_PRINTS` in cmake-gui for your UHD installation. Then recompile and reinstall UHD.
+
+Use
+---
+Run your application and pipe stderr to a file.
+this is mostly done by <br>
+`app_call 2> dbg_print_file.txt`<br>
+After finishing the application offline processing of the gathered data is done with a python script called<br>
+`uhd_txrx_debug_prints_graph.py`<br>
+There are a lot of functions that help to preprocess your data and that describe the actual meaning of all the data points. in the end though, it comes down to the users needs what he wants to plot and see. \ No newline at end of file
diff --git a/tools/uhd_txrx_debug_prints/uhd_txrx_debug_prints_graph.py b/tools/uhd_txrx_debug_prints/uhd_txrx_debug_prints_graph.py
new file mode 100755
index 000000000..b0f6681f6
--- /dev/null
+++ b/tools/uhd_txrx_debug_prints/uhd_txrx_debug_prints_graph.py
@@ -0,0 +1,415 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2013-2014 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/>.
+#
+"""
+Plots the output of the streamers that is produced when DEBUG_TXRX
+is enabled.
+"""
+
+import argparse
+import matplotlib.pyplot as plt
+import numpy as np
+
+# This is a top level function to load a debug file. It will return a list of lists with all the data.
+def get_data(filename):
+ res = []
+ with open(filename) as f:
+ for line in f.readlines():
+ line = line.rstrip('\n')
+ s = line.split(',')
+ res.append(s)
+ res = fix_known_data_corruption_patterns(res)
+ return res
+
+# Sometimes 'O' etc. get printed to stderr. This disturbs further processing. Thus, known pattern will be removed here.
+def fix_known_data_corruption_patterns(data):
+ # Some lines might be corrupted in the way that e.g. UHD prints sth else in the same line.
+ # O, D, Press Enter... are known patterns. These should be fixed.
+ counts = {'O': 0, 'D': 0, 'exit_msg': 0}
+ for i in range(len(data)):
+ if data[i][0].startswith('O'):
+ counts['O'] += 1
+ data[i][0] = data[i][0].replace('O', '')
+ if data[i][0].startswith('D'):
+ counts['D'] += 1
+ data[i][0] = data[i][0].replace('D', '')
+ if data[i][0].startswith('Press Enter to quit: '):
+ counts['exit_msg'] += 1
+ data[i][0] = data[i][0].replace('Press Enter to quit: ', '')
+ print counts
+ return data
+
+# Extract lines with a certain prefix.
+def extract_lines(prefix, data):
+ res = []
+ for line in data:
+ if line[0] == prefix:
+ res.append(line[1:])
+ return res
+
+# boolean values are stored as true/false. Convert them to real booleans again.
+def convert_to_bool(data):
+ res = []
+ for d in data:
+ res.append(d == "true")
+ return res
+
+# The different outputs have different structures. With this function you can conert them back to their actual type.
+def convert_data_set(data, reqtype):
+ zdata = zip(*data)
+ res = []
+ if len(zdata) == 0:
+ return res
+ for i in range(len(reqtype)):
+ if reqtype[i] == np.bool:
+ res.append(np.asarray(convert_to_bool(zdata[i]), dtype=np.bool))
+ else:
+ res.append(np.asarray(zdata[i], dtype=reqtype[i]))
+ return res
+
+# Wrapper for super_send_packet_handler data to be used with convert_data_set
+def convert_super_send_packet_handler_data(data):
+ # wallclock, timeout, avail_samps, sent_samps, sob, eob, has_time_spec, time_spec (ticks)
+ reqtype = [np.uint64, np.float, np.int, np.int, np.bool, np.bool, np.bool, np.uint64]
+ cdata = convert_data_set(data, reqtype)
+ return cdata
+
+# same o' same o'
+def convert_super_recv_packet_handler_data(data):
+ # wallclock, timeout, requested_samps, received_samps, one_packet, error_code, sob, eob, more_fragments, fragment_offset, has_timespec, time_spec
+ reqtype = [np.uint64, np.float, np.int, np.int, np.bool, np.int, np.bool, np.bool, np.bool, np.int, np.bool, np.uint64]
+ cdata = convert_data_set(data, reqtype)
+ return cdata
+
+def extract_super_recv_packet_handler_data(data):
+ pref1 = "super_recv_packet_handler"
+ pref2 = "recv"
+ super_recv = extract_lines(pref1, data)
+ recv = extract_lines(pref2, super_recv)
+ recv = convert_super_recv_packet_handler_data(recv)
+ return recv
+
+# Sometimes TX or RX is interrupted by system jiffies. Those are found by this function.
+def find_jiffy(data, thr):
+ res = []
+ last = data[0]
+ for i in range(len(data)):
+ if data[i] - last > thr:
+ res.append([last, data[i]])
+ last = data[i]
+ return res
+
+
+# Get difference between tx and rx wallclock
+def get_diff(tx, rx):
+ print "get diff, len(rx) = ", len(rx)
+ diff = [0] * len(rx[0])
+ for i in range(len(diff)):
+ r = rx[3][i]
+ idx = rx[0][i] - 1 # call count starts at 1. idx is 0 based.
+ t = tx[3][idx]
+ diff[i] = t - r
+ return diff
+
+
+def bps(samps, time):
+ bp = []
+ last = time[0]-1000
+ for i in range(len(samps)):
+ td = time[i] - last
+ last = time[i]
+ td = td /1e6
+ bp.append(samps[i] * 4 / td)
+ return bp
+
+
+# same as the other wrappers this time for libusb1
+def extract_libusb(trx, data):
+ pr1 = "libusb1_zero_copy"
+ pr2 = "libusb_async_cb"
+ ldata = extract_lines(pr1, data)
+ edata = extract_lines(pr2, ldata)
+ d = extract_lines(trx, edata)
+ # buff_num, actual_length, status, end_time, start_time
+ reqtype = [np.int, np.int, np.int, np.uint64, np.uint64]
+ return convert_data_set(d, reqtype)
+
+
+# Extract data for stream buffers. Typically there are 16 TX and 16 RX buffers. And there numbers are static. Though the number of buffers might be changed and the constant parameters must be adjusted in this case.
+def extract_txrx(data):
+ tx = [[], [], [], [], []]
+ rx = [[], [], [], [], []]
+ for i in range(len(data[0])):
+ print data[0][i]
+ if data[0][i] > 31 and data[0][i] < 48:
+ rx[0].append(data[0][i])
+ rx[1].append(data[1][i])
+ rx[2].append(data[2][i])
+ rx[3].append(data[3][i])
+ rx[4].append(data[4][i])
+ #print "tx\t", data[0][i], "\t", data[3][i], "\t", data[4][i]
+ if data[0][i] > 47 and data[0][i] < 64:
+ tx[0].append(data[0][i])
+ tx[1].append(data[1][i])
+ tx[2].append(data[2][i])
+ tx[3].append(data[3][i])
+ tx[4].append(data[4][i])
+ #print "rx\t", data[0][i], "\t", data[3][i], "\t", data[4][i]
+ return [tx, rx]
+
+# Calculate momentary throughput
+def throughput(data):
+ start = data[2][0]
+ total = data[1][-1] - data[2][0]
+ print total
+ thr = np.zeros(total)
+
+ for i in range(len(data[0])):
+ s = data[2][i] - start
+ f = data[1][i] - start
+ ticks = data[1][i] - data[2][i]
+ pertick = 1. * data[0][i] / ticks
+ vals = [pertick] * ticks
+ thr[s:f] = np.add(thr[s:f], vals)
+ #print pertick
+ print np.shape(thr)
+ return thr
+
+
+# Calculate a moving average
+def ma(data, wl):
+ ap = np.zeros(wl)
+ data = np.concatenate((ap, data, ap))
+ print np.shape(data)
+ res = np.zeros(len(data)-wl)
+ for i in range(len(data)-wl):
+ av = np.sum(data[i:i+wl]) / wl
+ res[i] = av
+ print i, "\t", av
+ return res
+
+
+def get_x_axis(stamps):
+ scale = 10e-6
+ return np.multiply(stamps, scale)
+
+
+# plot status codes.
+def plot_status_codes_over_time(data, fignum):
+ print "printing status numbers over time"
+
+ # extract and convert the data
+ recv = extract_super_recv_packet_handler_data(data)
+ libusb_rx = extract_libusb("rx", data)
+ libusb_tx = extract_libusb("tx", data)
+
+ # Plot all data
+ plt.figure(fignum) # Make sure these plots are printed to a new figure.
+ #plt.plot(get_x_axis(libusb_rx[3]), libusb_rx[2], marker='x', label='RX')
+ #plt.plot(get_x_axis(libusb_tx[3]), libusb_tx[2], marker='x', label='TX')
+
+ pos = 5
+ recv_error_codes = recv[pos]
+ plt.plot(get_x_axis(recv[0]), recv_error_codes, marker='x', label='recv')
+ plt.title("Status codes over timestamps")
+ plt.ylabel("status codes")
+ plt.xlabel("timestamps")
+ plt.grid()
+ plt.legend()
+
+ for i in range(len(recv[0])):
+ if recv[pos][i] == 8:
+ xaxis = get_x_axis([recv[0][i]])
+ plt.axvline(xaxis, color='b')
+
+
+ # Get some statistics and print them too
+ codes = []
+ code_dict = {}
+ for i in range(len(recv_error_codes)):
+ if recv_error_codes[i] != 0:
+ code = rx_metadata_error_codes[recv_error_codes[i]]
+ pair = [i, code]
+ codes.append(pair)
+ if not code_dict.has_key(code):
+ code_dict[code] = 0
+ code_dict[code] += 1
+ print codes
+ print code_dict
+
+
+# plot rtt times as peaks. That's the fast and easy way.
+def plot_rtt_times(data, fignum):
+ print "plot RTT times"
+ rx = extract_libusb("rx", data)
+ tx = extract_libusb("tx", data)
+
+ scale = 10e-6
+ rx_diff = np.multiply(np.subtract(rx[3], rx[4]), scale)
+ tx_diff = np.multiply(np.subtract(tx[3], tx[4]), scale)
+
+ plt.figure(fignum)
+ plt.plot(get_x_axis(rx[3]), rx_diff, marker='x', ls='', label="rx RTT")
+ plt.plot(get_x_axis(tx[3]), tx_diff, marker='x', ls='', label="tx RTT")
+ plt.title("Round trip times")
+ plt.ylabel("RTT (us)")
+ plt.grid()
+ plt.legend()
+
+
+# plot RTT as actual lines as long as buffers are on the fly.
+# This can take a long time if the function has to print a lot of small lines. Careful with this!
+def plot_rtt_lines(data, fignum):
+ print "plot RTT lines"
+ rx = extract_libusb("rx", data)
+ #tx = extract_libusb("tx", data)
+
+ if len(data) == 0 or len(rx) == 0:
+ return
+
+ plt.figure(fignum)
+ for i in range(len(rx[0])):
+ if rx[0][i] > -1:
+ start = rx[4][i]
+ stop = rx[3][i]
+ status = rx[2][i]
+
+ val = rx[0][i]#(stop - start) * scale
+ if not status == 0:
+ if status == 2:
+ print "status = ", status
+ val +=0.5
+ xaxis = get_x_axis([start, stop])
+ plt.plot(xaxis, [val, val], marker='x')
+ plt.ylabel('buffer number')
+
+ # Careful with these lines here.
+ # Basically they should always have these values to separate CTRL, TX, RX buffer number blocks.
+ # But these values can be adjusted. Thus, it requires you to adjust these lines
+ plt.axhline(15.5)
+ plt.axhline(31.5)
+ plt.axhline(47.5)
+ plt.grid()
+
+
+# only plot on-the-fly buffers.
+def plot_buff_otf(trx, nrange, data):
+ d = extract_libusb(trx, data)
+ res = [[], []]
+ num = 0
+ for i in range(len(d[0])):
+ if d[0][i] in nrange:
+ res
+
+
+# If there are still unknown lines after cleanup, they can be caught and printed here.
+# This way you can check what got caught but shouldn't have been caught.
+def get_unknown_lines(data):
+ # These are the 3 known starting lines. More might be added in the future.
+ known = ['super_recv_packet_handler', 'super_send_packet_handler', 'libusb1_zero_copy']
+ res = []
+ for i in range(len(data)):
+ if not data[i][0] in known:
+ print data[i]
+ res.append(data[i])
+ return res
+
+# LUT for all the return codes
+rx_metadata_error_codes = {0x0: "NONE", 0x1: "TIMEOUT", 0x2: "LATE_COMMAND", 0x4: "BROKEN_CHAIN", 0x8: "OVERFLOW",
+ 0xc: "ALIGNMENT", 0xf: "BAD_PACKET"}
+
+
+def parse_args():
+ """ Parse args, yo """
+ parser = argparse.ArgumentParser(description='Plot tool for debug prints.')
+ parser.add_argument('-f', '--filename', default=None, help='Debug output file')
+ return parser.parse_args()
+
+# Be really careful with the input files. They get pretty huge in a small time.
+# Doing some of the plotting can eat up a lot of time then.
+# Although this file contains a lot of functions by now, it is still left to the user to use everythin correctly.
+def main():
+ args = parse_args()
+ filename = args.filename
+ print "get data from: ", filename
+ #pref1 = "super_recv_packet_handler"
+ #pref2 = "recv"
+
+ # Here you get the data from a file
+ data = get_data(filename)
+ #print "data len: ", len(data)
+
+ # extract lines with unknown content.
+ unknown = get_unknown_lines(data)
+
+ # plot status codes and RTT lines.
+ plot_status_codes_over_time(data, 0)
+ plot_rtt_lines(data, 0)
+ #plot_rtt_times(data, 0)
+
+ #[tx, rx] = extract_txrx(data)
+ #print "txlen\t", len(tx[0])
+ #print "rxlen\t", len(rx[0])
+
+
+ #print "plot data"
+ #plt.title(filename)
+ #plt.plot(tx_data[0], tx_data[7], 'r', marker='o', label='TX')
+ #plt.plot(rx_data[0], rx_data[11], 'g', marker='x', label='RX')
+ #for j in jiffies:
+ # plt.axvline(x=j[0], color='r')
+ # plt.axvline(x=j[1], color='g')
+ #
+ #plt.xlabel('wallclock (us)')
+ #plt.ylabel('timestamp (ticks)')
+ #plt.legend()
+
+ #lencal = 200000
+
+ # calculate and plot rx throughput
+ #rxthr = throughput([rx[1], rx[3], rx[4]])
+ #plt.plot(rxthr[0:lencal])
+ #rxav = ma(rxthr[0:lencal], 2000)
+ #plt.plot(rxav)
+
+ # calculate and plot tx throughput
+ #txthr = throughput([tx[1], tx[3], tx[4]])
+ #plt.plot(txthr[0:lencal])
+ #txav = ma(txthr[0:lencal], 20)
+ #plt.plot(txav)
+
+
+ #bp = bps(data[1], data[2])
+ #print np.sum(bp)
+ #ave = np.sum(bp)/len(bp)
+ #print ave
+ #plt.plot(tx_data[0], tx_data[2], 'r')
+ #plt.plot(rx_data[0], rx_data[2], 'b')
+ #plt.plot(bp, 'g', marker='+')
+ #plt.plot(np.multiply(data[1], 1e6), 'r', marker='o')
+ #plt.plot(np.multiply(data[3],1e2), 'b', marker='x')
+ #plt.plot(ave)
+
+ # in the end, put a grid on the graph and show it.
+ plt.grid()
+ plt.show()
+
+if __name__ == '__main__':
+ print "[WARNING] This tool is in alpha status. Only use if you know what you're doing!"
+ main()
+