summaryrefslogtreecommitdiff
path: root/usrp2
diff options
context:
space:
mode:
Diffstat (limited to 'usrp2')
-rw-r--r--usrp2/firmware/apps/app_common_v2.c59
-rw-r--r--usrp2/firmware/apps/app_common_v2.h4
-rw-r--r--usrp2/firmware/apps/factory_test.c25
-rw-r--r--usrp2/firmware/apps/mimo_tx_slave.c10
-rw-r--r--usrp2/firmware/apps/serdes_txrx.c10
-rw-r--r--usrp2/firmware/apps/txrx.c61
-rw-r--r--usrp2/firmware/config/grc_usrp2_firmware.m46
-rw-r--r--usrp2/firmware/lib/db_init.c2
-rw-r--r--usrp2/firmware/lib/db_tvrx.c32
-rw-r--r--usrp2/firmware/lib/db_xcvr2450.c4
-rw-r--r--usrp2/firmware/lib/memory_map.h4
-rw-r--r--usrp2/fpga/control_lib/pic.v183
-rw-r--r--usrp2/fpga/control_lib/priority_enc.v44
-rwxr-xr-xusrp2/fpga/top/u2_core/u2_core.v44
-rw-r--r--usrp2/fpga/top/u2_rev3/Makefile3
-rw-r--r--usrp2/host/include/usrp2/usrp2.h59
-rw-r--r--usrp2/host/lib/control.h26
-rw-r--r--usrp2/host/lib/usrp2.cc52
-rw-r--r--usrp2/host/lib/usrp2_impl.cc296
-rw-r--r--usrp2/host/lib/usrp2_impl.h16
20 files changed, 709 insertions, 231 deletions
diff --git a/usrp2/firmware/apps/app_common_v2.c b/usrp2/firmware/apps/app_common_v2.c
index 67cccd53b..2d131bda7 100644
--- a/usrp2/firmware/apps/app_common_v2.c
+++ b/usrp2/firmware/apps/app_common_v2.c
@@ -152,7 +152,7 @@ config_tx_v2_cmd(const op_config_tx_v2_t *p,
memset(&tune_result, 0, sizeof(tune_result));
bool ok = true;
-
+
if (p->valid & CFGV_GAIN){
ok &= db_set_gain(tx_dboard, p->gain);
}
@@ -161,7 +161,7 @@ config_tx_v2_cmd(const op_config_tx_v2_t *p,
bool was_streaming = is_streaming();
if (was_streaming)
stop_rx_cmd();
-
+
u2_fxpt_freq_t f = u2_fxpt_freq_from_hilo(p->freq_hi, p->freq_lo);
bool tune_ok = db_tune(tx_dboard, f, &tune_result);
ok &= tune_ok;
@@ -185,7 +185,7 @@ config_tx_v2_cmd(const op_config_tx_v2_t *p,
hb1 = 1;
interp = interp >> 1;
}
-
+
if (interp < MIN_CIC_INTERP || interp > MAX_CIC_INTERP)
ok = false;
else {
@@ -215,7 +215,7 @@ config_tx_v2_cmd(const op_config_tx_v2_t *p,
}
static size_t
-config_rx_v2_cmd(const op_config_rx_v2_t *p,
+config_rx_v2_cmd(const op_config_rx_v2_t *p,
void *reply_payload, size_t reply_payload_space)
{
op_config_rx_reply_v2_t *r = (op_config_rx_reply_v2_t *) reply_payload;
@@ -226,7 +226,7 @@ config_rx_v2_cmd(const op_config_rx_v2_t *p,
memset(&tune_result, 0, sizeof(tune_result));
bool ok = true;
-
+
if (p->valid & CFGV_GAIN){
ok &= db_set_gain(rx_dboard, p->gain);
}
@@ -235,7 +235,7 @@ config_rx_v2_cmd(const op_config_rx_v2_t *p,
bool was_streaming = is_streaming();
if (was_streaming)
stop_rx_cmd();
-
+
u2_fxpt_freq_t f = u2_fxpt_freq_from_hilo(p->freq_hi, p->freq_lo);
bool tune_ok = db_tune(rx_dboard, f, &tune_result);
ok &= tune_ok;
@@ -249,17 +249,17 @@ config_rx_v2_cmd(const op_config_rx_v2_t *p,
int decim = p->decim;
int hb1 = 0;
int hb2 = 0;
-
+
if(!(decim & 1)) {
hb2 = 1;
decim = decim >> 1;
}
-
+
if(!(decim & 1)) {
hb1 = 1;
decim = decim >> 1;
}
-
+
if (decim < MIN_CIC_DECIM || decim > MAX_CIC_DECIM)
ok = false;
else {
@@ -294,7 +294,7 @@ read_time_cmd(const op_generic_t *p,
void *reply_payload, size_t reply_payload_space)
{
op_read_time_reply_t *r = (op_read_time_reply_t *) reply_payload;
- if (reply_payload_space < sizeof(*r))
+ if (reply_payload_space < sizeof(*r))
return 0; // no room
r->opcode = OP_READ_TIME_REPLY;
@@ -323,7 +323,7 @@ dboard_info_cmd(const op_generic_t *p,
void *reply_payload, size_t reply_payload_space)
{
op_dboard_info_reply_t *r = (op_dboard_info_reply_t *) reply_payload;
- if (reply_payload_space < sizeof(*r))
+ if (reply_payload_space < sizeof(*r))
return 0; // no room
r->opcode = OP_DBOARD_INFO_REPLY;
@@ -411,14 +411,14 @@ generic_reply(const op_generic_t *p,
bool ok)
{
op_generic_t *r = (op_generic_t *) reply_payload;
- if (reply_payload_space < sizeof(*r))
+ if (reply_payload_space < sizeof(*r))
return 0; // no room
-
+
r->opcode = p->opcode | OP_REPLY_BIT;
r->len = sizeof(*r);
r->rid = p->rid;
r->ok = ok;
-
+
return r->len;
}
@@ -426,14 +426,14 @@ static size_t
add_eop(void *reply_payload, size_t reply_payload_space)
{
op_generic_t *r = (op_generic_t *) reply_payload;
- if (reply_payload_space < sizeof(*r))
+ if (reply_payload_space < sizeof(*r))
return 0; // no room
-
+
r->opcode = OP_EOP;
r->len = sizeof(*r);
r->rid = 0;
r->ok = 0;
-
+
return r->len;
}
@@ -443,15 +443,15 @@ handle_control_chan_frame(u2_eth_packet_t *pkt, size_t len)
unsigned char reply[sizeof(u2_eth_packet_t) + 4 * sizeof(u2_subpkt_t)] _AL4;
unsigned char *reply_payload = &reply[sizeof(u2_eth_packet_t)];
int reply_payload_space = sizeof(reply) - sizeof(u2_eth_packet_t);
-
+
// initialize reply
memset(reply, 0, sizeof(reply));
set_reply_hdr((u2_eth_packet_t *) reply, pkt);
-
+
// point to beginning of payload (subpackets)
unsigned char *payload = ((unsigned char *) pkt) + sizeof(u2_eth_packet_t);
int payload_len = len - sizeof(u2_eth_packet_t);
-
+
size_t subpktlen = 0;
bool ok = false;
@@ -468,7 +468,7 @@ handle_control_chan_frame(u2_eth_packet_t *pkt, size_t len)
case OP_ID:
subpktlen = op_id_cmd(gp, reply_payload, reply_payload_space);
break;
-
+
case OP_CONFIG_TX_V2:
subpktlen = config_tx_v2_cmd((op_config_tx_v2_t *) payload, reply_payload, reply_payload_space);
break;
@@ -478,15 +478,18 @@ handle_control_chan_frame(u2_eth_packet_t *pkt, size_t len)
break;
case OP_START_RX_STREAMING:
- start_rx_streaming_cmd(&pkt->ehdr.src, (op_start_rx_streaming_t *) payload);
+ if (pkt->fixed.timestamp == -1) // Start now (default)
+ start_rx_streaming_cmd(&pkt->ehdr.src, (op_start_rx_streaming_t *) payload);
+ else
+ start_rx_streaming_at_cmd(&pkt->ehdr.src, (op_start_rx_streaming_t *)payload, pkt->fixed.timestamp);
ok = true;
goto generic_reply;
-
+
case OP_STOP_RX:
stop_rx_cmd();
ok = true;
goto generic_reply;
-
+
case OP_BURN_MAC_ADDR:
ok = ethernet_set_mac_addr(&((op_burn_mac_addr_t *)payload)->addr);
goto generic_reply;
@@ -532,8 +535,8 @@ handle_control_chan_frame(u2_eth_packet_t *pkt, size_t len)
case OP_GPIO_SET_DDR:
ok = true;
- hal_gpio_set_ddr(((op_gpio_t *)payload)->bank,
- ((op_gpio_t *)payload)->value,
+ hal_gpio_set_ddr(((op_gpio_t *)payload)->bank,
+ ((op_gpio_t *)payload)->value,
((op_gpio_t *)payload)->mask);
goto generic_reply;
@@ -549,8 +552,8 @@ handle_control_chan_frame(u2_eth_packet_t *pkt, size_t len)
case OP_GPIO_WRITE:
ok = true;
- hal_gpio_write(((op_gpio_t *)payload)->bank,
- ((op_gpio_t *)payload)->value,
+ hal_gpio_write(((op_gpio_t *)payload)->bank,
+ ((op_gpio_t *)payload)->value,
((op_gpio_t *)payload)->mask);
goto generic_reply;
diff --git a/usrp2/firmware/apps/app_common_v2.h b/usrp2/firmware/apps/app_common_v2.h
index 5058661ad..ff1baec06 100644
--- a/usrp2/firmware/apps/app_common_v2.h
+++ b/usrp2/firmware/apps/app_common_v2.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2007,2008 Free Software Foundation, Inc.
+ * Copyright 2007,2008,2009 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -55,8 +55,10 @@ print_tune_result(char *msg, bool tune_ok,
void start_rx_streaming_cmd(const u2_mac_addr_t *host, op_start_rx_streaming_t *p);
+void start_rx_streaming_at_cmd(const u2_mac_addr_t *host, op_start_rx_streaming_t *p, uint32_t time);
void stop_rx_cmd(void);
void restart_streaming(void);
+void restart_streaming_at(uint32_t time);
bool is_streaming(void);
void handle_control_chan_frame(u2_eth_packet_t *pkt, size_t len);
diff --git a/usrp2/firmware/apps/factory_test.c b/usrp2/firmware/apps/factory_test.c
index a4bc06d58..e7dde524a 100644
--- a/usrp2/firmware/apps/factory_test.c
+++ b/usrp2/firmware/apps/factory_test.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2007,2008 Free Software Foundation, Inc.
+ * Copyright 2007,2008,2009 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -154,7 +154,7 @@ restart_streaming(void)
dsp_rx_regs->rx_command =
MK_RX_CMD(FRAMES_PER_CMD * streaming_items_per_frame,
streaming_items_per_frame,
- 1, 1);
+ 1, 1);
dsp_rx_regs->rx_time = 0; // enqueue second command
}
@@ -187,6 +187,11 @@ start_rx_streaming_cmd(const u2_mac_addr_t *host, op_start_rx_streaming_t *p)
}
+void start_rx_streaming_at_cmd(const u2_mac_addr_t *host, op_start_rx_streaming_t *p, uint32_t time)
+{}
+void restart_streaming_at(uint32_t time)
+{}
+
void
stop_rx_cmd(void)
{
@@ -224,7 +229,7 @@ setup_tx()
* that we didn't handle the packet. A bit of a kludge
* but it should work.
*/
-bool
+bool
fw_sets_seqno_inspector(dbsm_t *sm, int buf_this) // returns false
{
uint32_t *p = buffer_ram(buf_this);
@@ -259,22 +264,22 @@ int test_ram()
{
int i,j,k;
output_regs->ram_page = 1<<10;
-
+
extram[0] = 0xDEADBEEF;
extram[1] = 0xF00D1234;
extram[7] = 0x76543210;
-
+
output_regs->ram_page = 2<<10;
extram[7] = 0x55555555;
extram[1] = 0xaaaaaaaa;
extram[0] = 0xeeeeeeee;
-
+
output_regs->ram_page = 1<<10;
-
+
i = extram[0];
k = extram[1];
j = extram[7];
-
+
if((i != 0xDEADBEEF)||(j!=0x76543210)||(k!=0xF00D1234)) {
puts("RAM FAIL1!\n");
puthex32_nl(i);
@@ -282,7 +287,7 @@ int test_ram()
puthex32_nl(k);
return 0;
}
-
+
output_regs->ram_page = 2<<10;
j = extram[7];
@@ -306,7 +311,7 @@ int test_sd()
puts("FAILED INIT of Card\n");
return 0;
}
-
+
unsigned char buf[512];
i = sd_read_block(2048,buf);
if(i == 0) {
diff --git a/usrp2/firmware/apps/mimo_tx_slave.c b/usrp2/firmware/apps/mimo_tx_slave.c
index e7da984c5..4c284b7c9 100644
--- a/usrp2/firmware/apps/mimo_tx_slave.c
+++ b/usrp2/firmware/apps/mimo_tx_slave.c
@@ -160,7 +160,7 @@ restart_streaming(void)
dsp_rx_regs->rx_command =
MK_RX_CMD(FRAMES_PER_CMD * streaming_items_per_frame,
streaming_items_per_frame,
- 1, 1);
+ 1, 1);
dsp_rx_regs->rx_time = 0; // enqueue second command
}
@@ -192,6 +192,10 @@ start_rx_streaming_cmd(const u2_mac_addr_t *host, op_start_rx_streaming_t *p)
restart_streaming();
}
+void start_rx_streaming_at_cmd(const u2_mac_addr_t *host, op_start_rx_streaming_t *p, uint32_t time)
+{}
+void restart_streaming_at(uint32_t time)
+{}
void
stop_rx_cmd(void)
@@ -230,7 +234,7 @@ setup_tx()
* that we didn't handle the packet. A bit of a kludge
* but it should work.
*/
-bool
+bool
fw_sets_seqno_inspector(dbsm_t *sm, int buf_this) // returns false
{
uint32_t *p = buffer_ram(buf_this);
@@ -310,7 +314,7 @@ main(void)
//output_regs->flush_icache = 1;
-
+
// initialize double buffering state machine for DSP RX -> Ethernet
if (FW_SETS_SEQNO){
diff --git a/usrp2/firmware/apps/serdes_txrx.c b/usrp2/firmware/apps/serdes_txrx.c
index 7816f7a65..aa4a3f33c 100644
--- a/usrp2/firmware/apps/serdes_txrx.c
+++ b/usrp2/firmware/apps/serdes_txrx.c
@@ -152,7 +152,7 @@ restart_streaming(void)
dsp_rx_regs->rx_command =
MK_RX_CMD(FRAMES_PER_CMD * streaming_items_per_frame,
streaming_items_per_frame,
- 1, 1);
+ 1, 1);
dsp_rx_regs->rx_time = 0; // enqueue second command
}
@@ -184,6 +184,10 @@ start_rx_streaming_cmd(const u2_mac_addr_t *host, op_start_rx_streaming_t *p)
restart_streaming();
}
+void start_rx_streaming_at_cmd(const u2_mac_addr_t *host, op_start_rx_streaming_t *p, uint32_t time)
+{}
+void restart_streaming_at(uint32_t time)
+{}
void
stop_rx_cmd(void)
@@ -222,7 +226,7 @@ setup_tx()
* that we didn't handle the packet. A bit of a kludge
* but it should work.
*/
-bool
+bool
fw_sets_seqno_inspector(dbsm_t *sm, int buf_this) // returns false
{
uint32_t *p = buffer_ram(buf_this);
@@ -302,7 +306,7 @@ main(void)
//output_regs->flush_icache = 1;
-
+
// initialize double buffering state machine for DSP RX -> Ethernet
if (FW_SETS_SEQNO){
diff --git a/usrp2/firmware/apps/txrx.c b/usrp2/firmware/apps/txrx.c
index b2487ed89..975f314bd 100644
--- a/usrp2/firmware/apps/txrx.c
+++ b/usrp2/firmware/apps/txrx.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2007,2008 Free Software Foundation, Inc.
+ * Copyright 2007,2008,2009 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -152,7 +152,35 @@ restart_streaming(void)
dsp_rx_regs->rx_command =
MK_RX_CMD(FRAMES_PER_CMD * streaming_items_per_frame,
streaming_items_per_frame,
- 1, 1);
+ 1, 1);
+
+ dsp_rx_regs->rx_time = 0; // enqueue second command
+}
+
+void
+restart_streaming_at(uint32_t time)
+{
+ // setup RX DSP regs
+ dsp_rx_regs->clear_state = 1; // reset
+
+ streaming_p = true;
+ streaming_frame_count = FRAMES_PER_CMD;
+
+ dsp_rx_regs->rx_command =
+ MK_RX_CMD(FRAMES_PER_CMD * streaming_items_per_frame,
+ streaming_items_per_frame,
+ 0, 1); // set "chain" bit
+
+ // kick off the state machine
+ dbsm_start(&dsp_rx_sm);
+
+ dsp_rx_regs->rx_time = time; // enqueue first of two commands
+
+ // make sure this one and the rest have the "now" and "chain" bits set.
+ dsp_rx_regs->rx_command =
+ MK_RX_CMD(FRAMES_PER_CMD * streaming_items_per_frame,
+ streaming_items_per_frame,
+ 1, 1);
dsp_rx_regs->rx_time = 0; // enqueue second command
}
@@ -184,6 +212,33 @@ start_rx_streaming_cmd(const u2_mac_addr_t *host, op_start_rx_streaming_t *p)
restart_streaming();
}
+void
+start_rx_streaming_at_cmd(const u2_mac_addr_t *host, op_start_rx_streaming_t *p, uint32_t time)
+{
+ host_mac_addr = *host; // remember who we're sending to
+
+ /*
+ * Construct ethernet header and word0 and preload into two buffers
+ */
+ u2_eth_packet_t pkt;
+ memset(&pkt, 0, sizeof(pkt));
+ pkt.ehdr.dst = *host;
+ pkt.ehdr.src = *ethernet_mac_addr();
+ pkt.ehdr.ethertype = U2_ETHERTYPE;
+ u2p_set_word0(&pkt.fixed, 0, 0);
+ // DSP RX will fill in timestamp
+
+ memcpy_wa(buffer_ram(DSP_RX_BUF_0), &pkt, sizeof(pkt));
+ memcpy_wa(buffer_ram(DSP_RX_BUF_1), &pkt, sizeof(pkt));
+
+
+ if (FW_SETS_SEQNO)
+ fw_seqno = 0;
+
+ streaming_items_per_frame = p->items_per_frame;
+ restart_streaming_at(time);
+}
+
void
stop_rx_cmd(void)
@@ -222,7 +277,7 @@ setup_tx()
* that we didn't handle the packet. A bit of a kludge
* but it should work.
*/
-bool
+bool
fw_sets_seqno_inspector(dbsm_t *sm, int buf_this) // returns false
{
uint32_t *p = buffer_ram(buf_this);
diff --git a/usrp2/firmware/config/grc_usrp2_firmware.m4 b/usrp2/firmware/config/grc_usrp2_firmware.m4
index 7f1f9a796..53ff03ce4 100644
--- a/usrp2/firmware/config/grc_usrp2_firmware.m4
+++ b/usrp2/firmware/config/grc_usrp2_firmware.m4
@@ -17,6 +17,12 @@ dnl along with GNU Radio; see the file COPYING. If not, write to
dnl the Free Software Foundation, Inc., 51 Franklin Street,
dnl Boston, MA 02110-1301, USA.
+dnl Fix 2.64 cross compile detection for AVR and RTEMS
+dnl by not trying to compile fopen.
+m4_if(m4_defn([m4_PACKAGE_VERSION]), [2.64],
+ [m4_foreach([_GCC_LANG], [C, C++, Fortran, Fortran 77],
+ [m4_define([_AC_LANG_IO_PROGRAM(]_GCC_LANG[)], m4_defn([AC_LANG_PROGRAM(]_GCC_LANG[)]))])])
+
AC_DEFUN([GRC_USRP2_FIRMWARE],[
dnl we use --enable-usrp2-firmware to enable this
GRC_ENABLE(usrp2-firmware)
diff --git a/usrp2/firmware/lib/db_init.c b/usrp2/firmware/lib/db_init.c
index 925a34f39..a0bfc5cfb 100644
--- a/usrp2/firmware/lib/db_init.c
+++ b/usrp2/firmware/lib/db_init.c
@@ -69,7 +69,9 @@ struct db_base *all_dboards[] = {
&db_rfx_2400_tx,
&db_rfx_2400_rx,
&db_tvrx1,
+#if 0
&db_tvrx2,
+#endif
&db_tvrx3,
&db_dbsrx,
&db_xcvr2450_tx,
diff --git a/usrp2/firmware/lib/db_tvrx.c b/usrp2/firmware/lib/db_tvrx.c
index ba70b6402..49bf75883 100644
--- a/usrp2/firmware/lib/db_tvrx.c
+++ b/usrp2/firmware/lib/db_tvrx.c
@@ -28,7 +28,7 @@ bool tvrx_set_freq(struct db_base *db, u2_fxpt_freq_t freq, u2_fxpt_freq_t *dc);
bool tvrx_set_gain(struct db_base *db, u2_fxpt_gain_t gain);
#define I2C_ADDR 0x60
-#define ref_freq (U2_DOUBLE_TO_FXPT_FREQ(4e6)/640*8)
+#define REF_FREQ (U2_DOUBLE_TO_FXPT_FREQ(4e6)/640*8)
#define ref_div 640 /* choices are 640, 512, 1024 */
@@ -101,6 +101,7 @@ struct db_tvrx1 db_tvrx1 = {
.common.second_if = U2_DOUBLE_TO_FXPT_FREQ(5.75e6),
};
+#if 0
struct db_tvrx2 db_tvrx2 = {
.base.dbid = 0x000c,
.base.is_tx = false,
@@ -113,7 +114,7 @@ struct db_tvrx2 db_tvrx2 = {
.base.gain_step_size = U2_DOUBLE_TO_FXPT_GAIN(1),
.base.is_quadrature = false,
.base.i_and_q_swapped = false,
- .base.spectrum_inverted = true,
+ .base.spectrum_inverted = false,
.base.default_lo_offset = U2_DOUBLE_TO_FXPT_FREQ(0),
.base.init = tvrx_init,
.base.set_freq = tvrx_set_freq,
@@ -125,8 +126,9 @@ struct db_tvrx2 db_tvrx2 = {
// .base.atr_tx_delay =
// .base.atr_rx_delay =
.common.first_if = U2_DOUBLE_TO_FXPT_FREQ(44e6),
- .common.second_if = U2_DOUBLE_TO_FXPT_FREQ(44e6),
+ .common.second_if = U2_DOUBLE_TO_FXPT_FREQ(56e6), // Fs - 44e6
};
+#endif
struct db_tvrx3 db_tvrx3 = {
.base.dbid = 0x0040,
@@ -140,7 +142,7 @@ struct db_tvrx3 db_tvrx3 = {
.base.gain_step_size = U2_DOUBLE_TO_FXPT_GAIN(1),
.base.is_quadrature = false,
.base.i_and_q_swapped = false,
- .base.spectrum_inverted = true,
+ .base.spectrum_inverted = false,
.base.default_lo_offset = U2_DOUBLE_TO_FXPT_FREQ(0),
.base.init = tvrx_init,
.base.set_freq = tvrx_set_freq,
@@ -152,7 +154,7 @@ struct db_tvrx3 db_tvrx3 = {
// .base.atr_tx_delay =
// .base.atr_rx_delay =
.common.first_if = U2_DOUBLE_TO_FXPT_FREQ(44e6),
- .common.second_if = U2_DOUBLE_TO_FXPT_FREQ(44e6),
+ .common.second_if = U2_DOUBLE_TO_FXPT_FREQ(56e6), // Fs - 44e6
};
bool
@@ -173,25 +175,25 @@ tvrx_set_freq(struct db_base *dbb, u2_fxpt_freq_t freq, u2_fxpt_freq_t *dc)
struct db_tvrx_dummy *db = (struct db_tvrx_dummy *) dbb;
u2_fxpt_freq_t target_lo_freq = freq + db->common.first_if;
- int N_DIV = u2_fxpt_freq_round_to_int(((1LL<<20) * target_lo_freq)/ref_freq);
+ int n_div = u2_fxpt_freq_round_to_int(((1LL<<20) * target_lo_freq)/REF_FREQ);
- u2_fxpt_freq_t actual_lo_freq = ref_freq * N_DIV;
+ u2_fxpt_freq_t actual_lo_freq = REF_FREQ * n_div;
u2_fxpt_freq_t actual_freq = actual_lo_freq - db->common.first_if;
- if(N_DIV > 32767)
+ if(n_div > 32767)
return false;
if (0)
- printf("N_DIV = %d, actual_freq = %d, actual_lo_freq = %d\n",
- N_DIV, u2_fxpt_freq_round_to_int(actual_freq),
+ printf("n_div = %d, actual_freq = %d, actual_lo_freq = %d\n",
+ n_div, u2_fxpt_freq_round_to_int(actual_freq),
u2_fxpt_freq_round_to_int(actual_lo_freq));
unsigned char buf[4];
- buf[0] = (N_DIV>>8) & 0xff;
- buf[1] = N_DIV & 0xff;
+ buf[0] = (n_div>>8) & 0xff;
+ buf[1] = n_div & 0xff;
buf[2] = control_byte_1;
- buf[3] = (freq < U2_DOUBLE_TO_FXPT_FREQ(158e6)) ? 0xa8 : // VHF LOW
- (freq < U2_DOUBLE_TO_FXPT_FREQ(464e6)) ? 0x98 : // VHF HIGH
- 0x38; // UHF
+ buf[3] = ((actual_freq < U2_DOUBLE_TO_FXPT_FREQ(158e6)) ? 0xa8 : // VHF LOW
+ (actual_freq < U2_DOUBLE_TO_FXPT_FREQ(464e6)) ? 0x98 : // VHF HIGH
+ 0x38); // UHF
*dc = actual_freq - db->common.second_if;
return i2c_write(I2C_ADDR,buf,4);
diff --git a/usrp2/firmware/lib/db_xcvr2450.c b/usrp2/firmware/lib/db_xcvr2450.c
index ffdf8d660..a48af9035 100644
--- a/usrp2/firmware/lib/db_xcvr2450.c
+++ b/usrp2/firmware/lib/db_xcvr2450.c
@@ -250,8 +250,8 @@ static void
set_reg_lpf(struct db_xcvr2450_dummy *db){
int reg_lpf = (
(db->common->d_rssi_hbw<<15) |
- (db->common->d_txlpf_bw<<10) |
- (db->common->d_rxlpf_bw<<9) |
+ (db->common->d_txlpf_bw<<9) |
+ (db->common->d_rxlpf_bw<<7) |
(db->common->d_rxlpf_fine<<4) | 7);
send_reg(reg_lpf);
}
diff --git a/usrp2/firmware/lib/memory_map.h b/usrp2/firmware/lib/memory_map.h
index 78a4330d2..0d0cf04f6 100644
--- a/usrp2/firmware/lib/memory_map.h
+++ b/usrp2/firmware/lib/memory_map.h
@@ -175,6 +175,10 @@ typedef struct {
volatile uint32_t last_line[NBUFFERS]; // last line xfer'd in buffer
volatile uint32_t status; // error and done flags
volatile uint32_t hw_config; // see below
+ volatile uint32_t dummy[3];
+ volatile uint32_t irqs;
+ volatile uint32_t pri_enc_bp_status;
+ volatile uint32_t cycle_count;
} buffer_pool_status_t;
#define buffer_pool_status ((buffer_pool_status_t *) BUFFER_POOL_STATUS_BASE)
diff --git a/usrp2/fpga/control_lib/pic.v b/usrp2/fpga/control_lib/pic.v
new file mode 100644
index 000000000..9b9944d4a
--- /dev/null
+++ b/usrp2/fpga/control_lib/pic.v
@@ -0,0 +1,183 @@
+
+// Heavily modified by M. Ettus, 2009, little original code remains
+// Modified by M. Ettus, 2008 for 32 bit width
+
+/////////////////////////////////////////////////////////////////////
+//// ////
+//// OpenCores Simple Programmable Interrupt Controller ////
+//// ////
+//// Author: Richard Herveille ////
+//// richard@asics.ws ////
+//// www.asics.ws ////
+//// ////
+/////////////////////////////////////////////////////////////////////
+//// ////
+//// Copyright (C) 2002 Richard Herveille ////
+//// richard@asics.ws ////
+//// ////
+//// This source file may be used and distributed without ////
+//// restriction provided that this copyright statement is not ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+//// ////
+//// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ////
+//// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ////
+//// POSSIBILITY OF SUCH DAMAGE. ////
+//// ////
+/////////////////////////////////////////////////////////////////////
+//
+// This is a simple Programmable Interrupt Controller.
+// The number of interrupts is depending on the databus size.
+// There's one interrupt input per databit (i.e. 16 interrupts for a 16
+// bit databus).
+// All attached devices share the same CPU priority level.
+//
+//
+//
+// Registers:
+//
+// 0x00: EdgeEnable Register
+// bits 7:0 R/W Edge Enable '1' = edge triggered interrupt source
+// '0' = level triggered interrupt source
+// 0x01: PolarityRegister
+// bits 7:0 R/W Polarity '1' = high level / rising edge
+// '0' = low level / falling edge
+// 0x02: MaskRegister
+// bits 7:0 R/W Mask '1' = interrupt masked (disabled)
+// '0' = interrupt not masked (enabled)
+// 0x03: PendingRegister
+// bits 7:0 R/W Pending '1' = interrupt pending
+// '0' = no interrupt pending
+//
+// A CPU interrupt is generated when an interrupt is pending and its
+// MASK bit is cleared.
+//
+//
+//
+// HOWTO:
+//
+// Clearing pending interrupts:
+// Writing a '1' to a bit in the interrupt pending register clears the
+// interrupt. Make sure to clear the interrupt at the source before
+// writing to the interrupt pending register. Otherwise the interrupt
+// will be set again.
+//
+// Priority based interrupts:
+// Upon reception of an interrupt, check the interrupt register and
+// determine the highest priority interrupt. Mask all interrupts from the
+// current level to the lowest level. This negates the interrupt line, and
+// makes sure only interrupts with a higher level are triggered. After
+// completion of the interrupt service routine, clear the interrupt source,
+// the interrupt bit in the pending register, and restore the MASK register
+// to it's previous state.
+//
+// Addapt the core for fewer interrupt sources:
+// If less than 8 interrupt sources are required, than the 'is' parameter
+// can be set to the amount of required interrupts. Interrupts are mapped
+// starting at the LSBs. So only the 'is' LSBs per register are valid. All
+// other bits (i.e. the 8-'is' MSBs) are set to zero '0'.
+// Codesize is approximately linear to the amount of interrupts. I.e. using
+// 4 instead of 8 interrupt sources reduces the size by approx. half.
+//
+
+
+module pic
+ (input clk_i, input rst_i, input cyc_i, input stb_i,
+ input [2:0] adr_i,
+ input we_i,
+ input [31:0] dat_i,
+ output reg [31:0] dat_o,
+ output reg ack_o,
+ output reg int_o,
+ input [31:0] irq
+ );
+
+ reg [31:0] pol, edgen, pending, mask; // register bank
+ reg [31:0] lirq, dirq; // latched irqs, delayed latched irqs
+
+ // latch interrupt inputs
+ always @(posedge clk_i)
+ lirq <= irq;
+
+ // generate delayed latched irqs
+ always @(posedge clk_i)
+ dirq <= lirq;
+
+ // generate actual triggers
+ function trigger;
+ input edgen, pol, lirq, dirq;
+ reg edge_irq, level_irq;
+ begin
+ edge_irq = pol ? (lirq & ~dirq) : (dirq & ~lirq);
+ level_irq = pol ? lirq : ~lirq;
+ trigger = edgen ? edge_irq : level_irq;
+ end
+ endfunction
+
+ reg [31:0] irq_event;
+ integer n;
+ always @(posedge clk_i)
+ for(n = 0; n < 32; n = n+1)
+ irq_event[n] <= trigger(edgen[n], pol[n], lirq[n], dirq[n]);
+
+ // generate wishbone register bank writes
+ wire wb_acc = cyc_i & stb_i; // WISHBONE access
+ wire wb_wr = wb_acc & we_i; // WISHBONE write access
+
+ always @(posedge clk_i)
+ if (rst_i)
+ begin
+ pol <= 0; // clear polarity register
+ edgen <= 0; // clear edge enable register
+ mask <= 0; // mask all interrupts
+ end
+ else if(wb_wr) // wishbone write cycle??
+ case (adr_i) // synopsys full_case parallel_case
+ 3'd0 : edgen <= dat_i; // EDGE-ENABLE register
+ 3'd1 : pol <= dat_i; // POLARITY register
+ 3'd2 : mask <= dat_i; // MASK register
+ 3'd3 : ; // PENDING register is a special case (see below)
+ 3'd4 : ; // Priority encoded live (pending & ~mask)
+ endcase
+
+ // pending register is a special case
+ always @(posedge clk_i)
+ if (rst_i)
+ pending <= 0; // clear all pending interrupts
+ else if ( wb_wr & (adr_i == 3'd3) )
+ pending <= (pending & ~dat_i) | irq_event;
+ else
+ pending <= pending | irq_event;
+
+ wire [31:0] live_enc;
+ priority_enc priority_enc ( .in(pending & ~mask), .out(live_enc) );
+
+ always @(posedge clk_i)
+ case (adr_i) // synopsys full_case parallel_case
+ 3'd0 : dat_o <= edgen;
+ 3'd1 : dat_o <= pol;
+ 3'd2 : dat_o <= mask;
+ 3'd3 : dat_o <= pending;
+ 3'd4 : dat_o <= live_enc;
+ endcase
+
+ always @(posedge clk_i)
+ ack_o <= wb_acc & !ack_o;
+
+ always @(posedge clk_i)
+ if(rst_i)
+ int_o <= 0;
+ else
+ int_o <= |(pending & ~mask);
+
+endmodule
diff --git a/usrp2/fpga/control_lib/priority_enc.v b/usrp2/fpga/control_lib/priority_enc.v
new file mode 100644
index 000000000..916192445
--- /dev/null
+++ b/usrp2/fpga/control_lib/priority_enc.v
@@ -0,0 +1,44 @@
+
+module priority_enc
+ (input [31:0] in,
+ output reg [31:0] out);
+
+ always @*
+ casex(in)
+ 32'b1xxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : out <= 31;
+ 32'b01xx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : out <= 30;
+ 32'b001x_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : out <= 29;
+ 32'b0001_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : out <= 28;
+ 32'b0000_1xxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : out <= 27;
+ 32'b0000_01xx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : out <= 26;
+ 32'b0000_001x_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : out <= 25;
+ 32'b0000_0001_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : out <= 24;
+ 32'b0000_0000_1xxx_xxxx_xxxx_xxxx_xxxx_xxxx : out <= 23;
+ 32'b0000_0000_01xx_xxxx_xxxx_xxxx_xxxx_xxxx : out <= 22;
+ 32'b0000_0000_001x_xxxx_xxxx_xxxx_xxxx_xxxx : out <= 21;
+ 32'b0000_0000_0001_xxxx_xxxx_xxxx_xxxx_xxxx : out <= 20;
+ 32'b0000_0000_0000_1xxx_xxxx_xxxx_xxxx_xxxx : out <= 19;
+ 32'b0000_0000_0000_01xx_xxxx_xxxx_xxxx_xxxx : out <= 18;
+ 32'b0000_0000_0000_001x_xxxx_xxxx_xxxx_xxxx : out <= 17;
+ 32'b0000_0000_0000_0001_xxxx_xxxx_xxxx_xxxx : out <= 16;
+ 32'b0000_0000_0000_0000_1xxx_xxxx_xxxx_xxxx : out <= 15;
+ 32'b0000_0000_0000_0000_01xx_xxxx_xxxx_xxxx : out <= 14;
+ 32'b0000_0000_0000_0000_001x_xxxx_xxxx_xxxx : out <= 13;
+ 32'b0000_0000_0000_0000_0001_xxxx_xxxx_xxxx : out <= 12;
+ 32'b0000_0000_0000_0000_0000_1xxx_xxxx_xxxx : out <= 11;
+ 32'b0000_0000_0000_0000_0000_01xx_xxxx_xxxx : out <= 10;
+ 32'b0000_0000_0000_0000_0000_001x_xxxx_xxxx : out <= 9;
+ 32'b0000_0000_0000_0000_0000_0001_xxxx_xxxx : out <= 8;
+ 32'b0000_0000_0000_0000_0000_0000_1xxx_xxxx : out <= 7;
+ 32'b0000_0000_0000_0000_0000_0000_01xx_xxxx : out <= 6;
+ 32'b0000_0000_0000_0000_0000_0000_001x_xxxx : out <= 5;
+ 32'b0000_0000_0000_0000_0000_0000_0001_xxxx : out <= 4;
+ 32'b0000_0000_0000_0000_0000_0000_0000_1xxx : out <= 3;
+ 32'b0000_0000_0000_0000_0000_0000_0000_01xx : out <= 2;
+ 32'b0000_0000_0000_0000_0000_0000_0000_001x : out <= 1;
+ 32'b0000_0000_0000_0000_0000_0000_0000_0001 : out <= 0;
+ 32'b0000_0000_0000_0000_0000_0000_0000_0000 : out <= 32'hFFFF_FFFF;
+ default : out <= 32'hFFFF_FFFF;
+ endcase // casex (in)
+
+endmodule // priority_enc
diff --git a/usrp2/fpga/top/u2_core/u2_core.v b/usrp2/fpga/top/u2_core/u2_core.v
index 03016e9b3..fd17a10a7 100755
--- a/usrp2/fpga/top/u2_core/u2_core.v
+++ b/usrp2/fpga/top/u2_core/u2_core.v
@@ -158,6 +158,7 @@ module u2_core
wire serdes_link_up;
wire epoch;
+ wire [31:0] irq;
// ///////////////////////////////////////////////////////////////////////////////////////////////
// Wishbone Single Master INTERCON
@@ -278,6 +279,7 @@ module u2_core
.wb_we_o(ram_loader_we),.wb_ack_i(ram_loader_ack),
.ram_loader_done_o(ram_loader_done));
+ // /////////////////////////////////////////////////////////////////////////
// Processor
aeMB_core_BE #(.ISIZ(16),.DSIZ(16),.MUL(0),.BSF(1))
aeMB (.sys_clk_i(wb_clk), .sys_rst_i(wb_rst),
@@ -292,6 +294,7 @@ module u2_core
assign bus_error = m0_err | m0_rty;
+ // /////////////////////////////////////////////////////////////////////////
// Dual Ported RAM -- D-Port is Slave #0 on main Wishbone
// I-port connects directly to processor and ram loader
@@ -314,6 +317,7 @@ module u2_core
setting_reg #(.my_addr(7)) sr_icache (.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr),
.in(set_data),.out(),.changed(flush_icache));
+ // /////////////////////////////////////////////////////////////////////////
// Buffer Pool, slave #1
wire rd0_ready_i, rd0_ready_o;
wire rd1_ready_i, rd1_ready_o;
@@ -353,6 +357,10 @@ module u2_core
.rd3_data_o(rd3_dat), .rd3_flags_o(rd3_flags), .rd3_ready_i(rd3_ready_i), .rd3_ready_o(rd3_ready_o)
);
+ wire [31:0] status_enc;
+ priority_enc priority_enc (.in({16'b0,status[15:0]}), .out(status_enc));
+
+ // /////////////////////////////////////////////////////////////////////////
// SPI -- Slave #2
spi_top shared_spi
(.wb_clk_i(wb_clk),.wb_rst_i(wb_rst),.wb_adr_i(s2_adr[4:0]),.wb_dat_i(s2_dat_o),
@@ -361,6 +369,7 @@ module u2_core
.ss_pad_o({sen_tx_db,sen_tx_adc,sen_tx_dac,sen_rx_db,sen_rx_adc,sen_rx_dac,sen_dac,sen_clk}),
.sclk_pad_o(sclk),.mosi_pad_o(mosi),.miso_pad_i(miso) );
+ // /////////////////////////////////////////////////////////////////////////
// I2C -- Slave #3
i2c_master_top #(.ARST_LVL(1))
i2c (.wb_clk_i(wb_clk),.wb_rst_i(wb_rst),.arst_i(1'b0),
@@ -372,6 +381,7 @@ module u2_core
assign s3_dat_i[31:8] = 24'd0;
+ // /////////////////////////////////////////////////////////////////////////
// GPIOs -- Slave #4
nsgpio nsgpio(.clk_i(wb_clk),.rst_i(wb_rst),
.cyc_i(s4_cyc),.stb_i(s4_stb),.adr_i(s4_adr[3:0]),.we_i(s4_we),
@@ -379,19 +389,24 @@ module u2_core
.atr(atr_lines),.debug_0(debug_gpio_0),.debug_1(debug_gpio_1),
.gpio( {io_tx,io_rx} ) );
- // Buffer Pool Status -- Slave #5
+ // /////////////////////////////////////////////////////////////////////////
+ // Buffer Pool Status -- Slave #5
+
+ reg [31:0] cycle_count;
+ always @(posedge wb_clk)
+ if(wb_rst)
+ cycle_count <= 0;
+ else
+ cycle_count <= cycle_count + 1;
+
wb_readback_mux buff_pool_status
- (.wb_clk_i(wb_clk),
- .wb_rst_i(wb_rst),
- .wb_stb_i(s5_stb),
- .wb_adr_i(s5_adr),
- .wb_dat_o(s5_dat_i),
- .wb_ack_o(s5_ack),
+ (.wb_clk_i(wb_clk), .wb_rst_i(wb_rst), .wb_stb_i(s5_stb),
+ .wb_adr_i(s5_adr), .wb_dat_o(s5_dat_i), .wb_ack_o(s5_ack),
.word00(status_b0),.word01(status_b1),.word02(status_b2),.word03(status_b3),
.word04(status_b4),.word05(status_b5),.word06(status_b6),.word07(status_b7),
.word08(status),.word09({sim_mode,27'b0,clock_divider[3:0]}),.word10(32'b0),
- .word11(32'b0),.word12(32'b0),.word13(32'b0),.word14(32'b0),.word15(32'b0)
+ .word11(32'b0),.word12(32'b0),.word13(irq),.word14(status_enc),.word15(cycle_count)
);
// /////////////////////////////////////////////////////////////////////////
@@ -457,13 +472,14 @@ module u2_core
// /////////////////////////////////////////////////////////////////////////
// Interrupt Controller, Slave #8
- wire [15:0] irq={{4'b0, clk_status, serdes_link_up, uart_tx_int, uart_rx_int},
- {pps_int,overrun,underrun,PHY_INTn,i2c_int,spi_int,timer_int,buffer_int}};
+ assign irq= {{8'b0},
+ {8'b0},
+ {4'b0, clk_status, serdes_link_up, uart_tx_int, uart_rx_int},
+ {pps_int,overrun,underrun,PHY_INTn,i2c_int,spi_int,timer_int,buffer_int}};
- simple_pic #(.is(16),.dwidth(32)) simple_pic
- (.clk_i(wb_clk),.rst_i(wb_rst),.cyc_i(s8_cyc),.stb_i(s8_stb),.adr_i(s8_adr[3:2]),
- .we_i(s8_we),.dat_i(s8_dat_o),.dat_o(s8_dat_i),.ack_o(s8_ack),.int_o(proc_int),
- .irq(irq) );
+ pic pic(.clk_i(wb_clk),.rst_i(wb_rst),.cyc_i(s8_cyc),.stb_i(s8_stb),.adr_i(s8_adr[3:2]),
+ .we_i(s8_we),.dat_i(s8_dat_o),.dat_o(s8_dat_i),.ack_o(s8_ack),.int_o(proc_int),
+ .irq(irq) );
// /////////////////////////////////////////////////////////////////////////
// Master Timer, Slave #9
diff --git a/usrp2/fpga/top/u2_rev3/Makefile b/usrp2/fpga/top/u2_rev3/Makefile
index 94681f6cd..4358d7c56 100644
--- a/usrp2/fpga/top/u2_rev3/Makefile
+++ b/usrp2/fpga/top/u2_rev3/Makefile
@@ -82,6 +82,8 @@ control_lib/sd_spi.v \
control_lib/sd_spi_wb.v \
control_lib/wb_bridge_16_32.v \
control_lib/reset_sync.v \
+control_lib/priority_enc.v \
+control_lib/pic.v \
simple_gemac/simple_gemac_wrapper.v \
simple_gemac/simple_gemac.v \
simple_gemac/simple_gemac_wb.v \
@@ -132,7 +134,6 @@ opencores/i2c/rtl/verilog/i2c_master_byte_ctrl.v \
opencores/i2c/rtl/verilog/i2c_master_defines.v \
opencores/i2c/rtl/verilog/i2c_master_top.v \
opencores/i2c/rtl/verilog/timescale.v \
-opencores/simple_pic/rtl/simple_pic.v \
opencores/spi/rtl/verilog/spi_clgen.v \
opencores/spi/rtl/verilog/spi_defines.v \
opencores/spi/rtl/verilog/spi_shift.v \
diff --git a/usrp2/host/include/usrp2/usrp2.h b/usrp2/host/include/usrp2/usrp2.h
index 7a612f945..2d9e2a4b0 100644
--- a/usrp2/host/include/usrp2/usrp2.h
+++ b/usrp2/host/include/usrp2/usrp2.h
@@ -60,7 +60,7 @@ namespace usrp2 {
*
* \returns a vector of properties, 1 entry for each matching USRP2 found.
*/
- props_vector_t find(const std::string &ifc, const std::string &mac_addr="");
+ props_vector_t find(const std::string &ifc, const std::string &mac_addr="");
class tune_result;
@@ -79,10 +79,10 @@ namespace usrp2 {
/*!
* Shared pointer to this class
- */
+ */
typedef boost::shared_ptr<usrp2> sptr;
-
- /*!
+
+ /*!
* Static function to return an instance of usrp2 as a shared pointer
*
* \param ifc Network interface name, e.g., "eth0"
@@ -96,7 +96,7 @@ namespace usrp2 {
/*!
* Class destructor
*/
- ~usrp2();
+ ~usrp2();
/*!
* Returns the MAC address associated with this USRP
@@ -120,10 +120,10 @@ namespace usrp2 {
*/
bool set_rx_gain(double gain);
- //! return minimum Rx gain
+ //! return minimum Rx gain
double rx_gain_min();
- //! return maximum Rx gain
+ //! return maximum Rx gain
double rx_gain_max();
//! return Rx gain db_per_step
@@ -160,7 +160,7 @@ namespace usrp2 {
/*!
* Set received sample format
- *
+ *
* domain: complex or real
* type: floating, fixed point, or raw
* depth: bits per sample
@@ -172,12 +172,33 @@ namespace usrp2 {
/*!
* Start streaming receive mode. USRP2 will send a continuous stream of
* DSP pipeline samples to host. Call rx_samples(...) to access.
- *
+ *
* \param channel Stream channel number (0-30)
* \param items_per_frame Number of 32-bit items per frame.
*/
bool start_rx_streaming(unsigned int channel=0, unsigned int items_per_frame=0);
-
+
+ /*!
+ * Start streaming receive mode at specified timestamp. USRP2 will send a
+ * continuous stream of DSP pipeline samples to host. Call rx_samples(...)
+ * to access.
+ *
+ * \param channel Stream channel number (0-30)
+ * \param items_per_frame Number of 32-bit items per frame.
+ * \param time Timestamp to start streaming at
+ */
+ bool start_rx_streaming_at(unsigned int channel=0, unsigned int items_per_frame=0, unsigned int time=0);
+
+ /*!
+ * Sync to PPS and start streaming receive mode at specified timestamp.
+ * Just like calling sync_to_pps() and start_rx_streaming_at().
+ *
+ * \param channel Stream channel number (0-30)
+ * \param items_per_frame Number of 32-bit items per frame.
+ * \param time Timestamp to start streaming at
+ */
+ bool sync_and_start_rx_streaming_at(unsigned int channel=0, unsigned int items_per_frame=0, uint32_t time=0);
+
/*!
* Stop streaming receive mode.
*/
@@ -193,7 +214,7 @@ namespace usrp2 {
* Returns number of times receive overruns have occurred
*/
unsigned int rx_overruns();
-
+
/*!
* Returns total number of missing frames from overruns.
*/
@@ -210,10 +231,10 @@ namespace usrp2 {
*/
bool set_tx_gain(double gain);
- //! return minimum Tx gain
+ //! return minimum Tx gain
double tx_gain_min();
- //! return maximum Tx gain
+ //! return maximum Tx gain
double tx_gain_max();
//! return Tx gain db_per_step
@@ -255,7 +276,7 @@ namespace usrp2 {
/*!
* Set transmit sample format
- *
+ *
* domain: complex or real
* type: floating, fixed point, or raw
* depth: bits per sample
@@ -272,7 +293,7 @@ namespace usrp2 {
* \param nsamples is the number of samples to transmit
* \param metadata provides the timestamp and flags
*
- * The complex<float> samples are converted to the appropriate
+ * The complex<float> samples are converted to the appropriate
* "on the wire" representation, depending on the current USRP2
* configuration. Typically, this is big-endian 16-bit I & Q.
*/
@@ -400,12 +421,12 @@ namespace usrp2 {
*
* \param addr 32-bit aligned address. Only the lower 16-bits are significant.
* \param words Number of 32-bit words
- *
+ *
* \returns Vector of 32-bit read values
*
* WARNING: Attempts to read memory from addresses that do not correspond to RAM or
* memory-mapped peripherals may cause the USRP2 to hang, requiring a power cycle.
- *
+ *
*/
std::vector<uint32_t> peek32(uint32_t addr, uint32_t words);
@@ -419,7 +440,7 @@ namespace usrp2 {
*
* WARNING: Attempts to read memory from addresses that do not correspond to RAM or
* memory-mapped peripherals may cause the USRP2 to hang, requiring a power cycle.
- *
+ *
*/
bool poke32(uint32_t addr, const std::vector<uint32_t> &data);
@@ -587,7 +608,7 @@ namespace usrp2 {
// Only class members can instantiate this class
usrp2(const std::string &ifc, props *p, size_t rx_bufsize);
-
+
// All private state is held in opaque pointer
std::auto_ptr<impl> d_impl;
};
diff --git a/usrp2/host/lib/control.h b/usrp2/host/lib/control.h
index 8769e4522..46ce791ea 100644
--- a/usrp2/host/lib/control.h
+++ b/usrp2/host/lib/control.h
@@ -33,27 +33,35 @@ namespace usrp2 {
/*!
* OP_CONFIG_RX_V2 command packet
*/
- struct op_config_rx_v2_cmd
+ struct op_config_rx_v2_cmd
{
u2_eth_packet_t h;
op_config_rx_v2_t op;
op_generic_t eop;
};
- struct op_start_rx_streaming_cmd
+ struct op_start_rx_streaming_cmd
{
u2_eth_packet_t h;
op_start_rx_streaming_t op;
op_generic_t eop;
};
-
+
+ struct op_sync_and_start_rx_streaming_cmd
+ {
+ u2_eth_packet_t h;
+ op_generic_t sync_op;
+ op_start_rx_streaming_t rx_op;
+ op_generic_t eop;
+ };
+
struct op_stop_rx_cmd {
u2_eth_packet_t h;
op_generic_t op;
op_generic_t eop;
};
- struct op_config_tx_v2_cmd
+ struct op_config_tx_v2_cmd
{
u2_eth_packet_t h;
op_config_tx_v2_t op;
@@ -67,7 +75,7 @@ namespace usrp2 {
op_generic_t eop;
};
- struct op_burn_mac_addr_cmd
+ struct op_burn_mac_addr_cmd
{
u2_eth_packet_t h;
op_burn_mac_addr_t op;
@@ -113,20 +121,20 @@ namespace usrp2 {
/*!
* Control mechanism to allow API calls to block waiting for reply packets
- */
+ */
class pending_reply
{
private:
unsigned int d_rid;
void *d_buffer;
size_t d_len;
-
+
// d_mutex is used with d_cond and also protects d_complete
omni_mutex d_mutex;
omni_condition d_cond;
bool d_complete;
- public:
+ public:
/*!
* Construct a pending reply from the reply ID, response packet
* buffer, and buffer length.
@@ -165,7 +173,7 @@ namespace usrp2 {
*/
size_t len() const { return d_len; }
};
-
+
} // namespace usrp2
#endif /* INCLUDED_CONTROL_H */
diff --git a/usrp2/host/lib/usrp2.cc b/usrp2/host/lib/usrp2.cc
index a2a9ecc11..801a436a3 100644
--- a/usrp2/host/lib/usrp2.cc
+++ b/usrp2/host/lib/usrp2.cc
@@ -62,7 +62,7 @@ namespace usrp2 {
else {
if (key == p->key) // found it
return usrp2::sptr(p->value);
- else
+ else
++p; // keep looking
}
}
@@ -90,15 +90,15 @@ namespace usrp2 {
p.addr[3] = 0x85;
p.addr[4] = 0x30;
p.addr[5] = 0x00;
-
+
int len = s.size();
switch (len) {
-
+
case 5:
if (sscanf(s.c_str(), "%hhx:%hhx", &p.addr[4], &p.addr[5]) != 2)
return false;
break;
-
+
case 17:
if (sscanf(s.c_str(), "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
&p.addr[0], &p.addr[1], &p.addr[2],
@@ -109,7 +109,7 @@ namespace usrp2 {
default:
return false;
}
-
+
char buf[128];
snprintf(buf, sizeof(buf),
"%02x:%02x:%02x:%02x:%02x:%02x",
@@ -148,13 +148,13 @@ namespace usrp2 {
{
// NOP
}
-
+
// Public class destructor. d_impl will auto-delete.
usrp2::~usrp2()
{
// NOP
}
-
+
std::string
usrp2::mac_addr()
{
@@ -169,12 +169,12 @@ namespace usrp2 {
// Receive
- bool
+ bool
usrp2::set_rx_gain(double gain)
{
return d_impl->set_rx_gain(gain);
}
-
+
double
usrp2::rx_gain_min()
{
@@ -204,7 +204,7 @@ namespace usrp2 {
{
return d_impl->set_rx_center_freq(frequency, result);
}
-
+
double
usrp2::rx_freq_min()
{
@@ -222,7 +222,7 @@ namespace usrp2 {
{
return d_impl->set_rx_decim(decimation_factor);
}
-
+
int
usrp2::rx_decim()
{
@@ -234,13 +234,25 @@ namespace usrp2 {
{
return d_impl->set_rx_scale_iq(scale_i, scale_q);
}
-
+
bool
usrp2::start_rx_streaming(unsigned int channel, unsigned int items_per_frame)
{
return d_impl->start_rx_streaming(channel, items_per_frame);
}
-
+
+ bool
+ usrp2::start_rx_streaming_at(unsigned int channel, unsigned int items_per_frame, unsigned int time)
+ {
+ return d_impl->start_rx_streaming_at(channel, items_per_frame,time);
+ }
+
+ bool
+ usrp2::sync_and_start_rx_streaming_at(unsigned int channel, unsigned int items_per_frame, unsigned int time)
+ {
+ return d_impl->sync_and_start_rx_streaming_at(channel, items_per_frame, time);
+ }
+
bool
usrp2::rx_samples(unsigned int channel, rx_sample_handler *handler)
{
@@ -258,7 +270,7 @@ namespace usrp2 {
{
return d_impl->rx_overruns();
}
-
+
unsigned int
usrp2::rx_missing()
{
@@ -267,12 +279,12 @@ namespace usrp2 {
// Transmit
- bool
+ bool
usrp2::set_tx_gain(double gain)
{
return d_impl->set_tx_gain(gain);
}
-
+
double
usrp2::tx_gain_min()
{
@@ -302,7 +314,7 @@ namespace usrp2 {
{
return d_impl->set_tx_center_freq(frequency, result);
}
-
+
double
usrp2::tx_freq_min()
{
@@ -321,7 +333,7 @@ namespace usrp2 {
{
return d_impl->set_tx_interp(interpolation_factor);
}
-
+
int
usrp2::tx_interp()
{
@@ -339,7 +351,7 @@ namespace usrp2 {
{
return d_impl->set_tx_scale_iq(scale_i, scale_q);
}
-
+
bool
usrp2::tx_32fc(unsigned int channel,
const std::complex<float> *samples,
@@ -404,7 +416,7 @@ namespace usrp2 {
{
return d_impl->rx_daughterboard_id(dbid);
}
-
+
// low level methods
diff --git a/usrp2/host/lib/usrp2_impl.cc b/usrp2/host/lib/usrp2_impl.cc
index 3d0304324..a74707634 100644
--- a/usrp2/host/lib/usrp2_impl.cc
+++ b/usrp2/host/lib/usrp2_impl.cc
@@ -106,7 +106,7 @@ namespace usrp2 {
//assert((((uintptr_t) p) % 4) == 0); // must be 4-byte aligned
u2_fixed_hdr_t *fh = static_cast<u2_fixed_hdr_t *>(p);
-
+
// FIXME unaligned loads!
md->word0 = u2p_word0(fh);
md->timestamp = u2p_timestamp(fh);
@@ -131,13 +131,13 @@ namespace usrp2 {
usrp2::impl::impl(const std::string &ifc, props *p, size_t rx_bufsize)
: d_eth_buf(new eth_buffer(rx_bufsize)), d_interface_name(ifc), d_pf(0), d_bg_thread(0),
d_bg_running(false), d_rx_seqno(-1), d_tx_seqno(0), d_next_rid(0),
- d_num_rx_frames(0), d_num_rx_missing(0), d_num_rx_overruns(0), d_num_rx_bytes(0),
+ d_num_rx_frames(0), d_num_rx_missing(0), d_num_rx_overruns(0), d_num_rx_bytes(0),
d_num_enqueued(0), d_enqueued_mutex(), d_bg_pending_cond(&d_enqueued_mutex),
d_channel_rings(NCHANS), d_tx_interp(0), d_rx_decim(0), d_dont_enqueue(true)
{
if (!d_eth_buf->open(ifc, htons(U2_ETHERTYPE)))
throw std::runtime_error("Unable to register USRP2 protocol");
-
+
d_addr = p->addr;
// Create a packet filter for U2_ETHERTYPE packets sourced from target USRP2
@@ -146,7 +146,7 @@ namespace usrp2 {
d_pf = pktfilter::make_ethertype_inbound_target(U2_ETHERTYPE, (const unsigned char*)&(usrp_mac.addr));
if (!d_pf || !d_eth_buf->attach_pktfilter(d_pf))
throw std::runtime_error("Unable to attach packet filter.");
-
+
if (USRP2_IMPL_DEBUG)
std::cerr << "usrp2 constructor: using USRP2 at " << d_addr << std::endl;
@@ -199,12 +199,12 @@ namespace usrp2 {
if (!set_rx_decim(12))
std::cerr << "usrp2::ctor set_rx_decim failed\n";
-
+
// set workable defaults for scaling
if (!set_rx_scale_iq(DEFAULT_RX_SCALE, DEFAULT_RX_SCALE))
std::cerr << "usrp2::ctor set_rx_scale_iq failed\n";
}
-
+
usrp2::impl::~impl()
{
stop_bg();
@@ -212,17 +212,17 @@ namespace usrp2 {
delete d_pf;
d_eth_buf->close();
delete d_eth_buf;
-
+
if (USRP2_IMPL_DEBUG) {
std::cerr << std::endl
- << "usrp2 destructor: received " << d_num_rx_frames
+ << "usrp2 destructor: received " << d_num_rx_frames
<< " frames, with " << d_num_rx_missing << " lost ("
<< (d_num_rx_frames == 0 ? 0 : (int)(100.0*d_num_rx_missing/d_num_rx_frames))
<< "%), totaling " << d_num_rx_bytes
<< " bytes" << std::endl;
}
}
-
+
bool
usrp2::impl::parse_mac_addr(const std::string &s, u2_mac_addr_t *p)
{
@@ -232,14 +232,14 @@ namespace usrp2 {
p->addr[3] = 0x85;
p->addr[4] = 0x30;
p->addr[5] = 0x00;
-
+
int len = s.size();
-
+
switch (len){
-
+
case 5:
return sscanf(s.c_str(), "%hhx:%hhx", &p->addr[4], &p->addr[5]) == 2;
-
+
case 17:
return sscanf(s.c_str(), "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
&p->addr[0], &p->addr[1], &p->addr[2],
@@ -248,36 +248,36 @@ namespace usrp2 {
return false;
}
}
-
+
void
usrp2::impl::init_et_hdrs(u2_eth_packet_t *p, const std::string &dst)
{
p->ehdr.ethertype = htons(U2_ETHERTYPE);
- parse_mac_addr(dst, &p->ehdr.dst);
+ parse_mac_addr(dst, &p->ehdr.dst);
memcpy(&p->ehdr.src, d_eth_buf->mac(), 6);
p->thdr.flags = 0; // FIXME transport header values?
p->thdr.seqno = d_tx_seqno++;
p->thdr.ack = 0;
}
-
- void
+
+ void
usrp2::impl::init_etf_hdrs(u2_eth_packet_t *p, const std::string &dst,
int word0_flags, int chan, uint32_t timestamp)
{
init_et_hdrs(p, dst);
u2p_set_word0(&p->fixed, word0_flags, chan);
u2p_set_timestamp(&p->fixed, timestamp);
-
+
if (chan == CONTROL_CHAN) { // no sequence numbers, back it out
p->thdr.seqno = 0;
d_tx_seqno--;
}
}
-
+
void
usrp2::impl::init_config_rx_v2_cmd(op_config_rx_v2_cmd *cmd)
{
- memset(cmd, 0, sizeof(*cmd));
+ memset(cmd, 0, sizeof(*cmd));
init_etf_hdrs(&cmd->h, d_addr, 0, CONTROL_CHAN, -1);
cmd->op.opcode = OP_CONFIG_RX_V2;
cmd->op.len = sizeof(cmd->op);
@@ -289,7 +289,7 @@ namespace usrp2 {
void
usrp2::impl::init_config_tx_v2_cmd(op_config_tx_v2_cmd *cmd)
{
- memset(cmd, 0, sizeof(*cmd));
+ memset(cmd, 0, sizeof(*cmd));
init_etf_hdrs(&cmd->h, d_addr, 0, CONTROL_CHAN, -1);
cmd->op.opcode = OP_CONFIG_TX_V2;
cmd->op.len = sizeof(cmd->op);
@@ -320,7 +320,7 @@ namespace usrp2 {
usrp2::impl::transmit_cmd_and_wait(void *cmd, size_t len, pending_reply *p, double secs)
{
d_pending_replies[p->rid()] = p;
-
+
if (!transmit_cmd(cmd, len)){
d_pending_replies[p->rid()] = 0;
return false;
@@ -340,11 +340,11 @@ namespace usrp2 {
{
d_bg_running = false;
d_bg_pending_cond.signal();
-
+
void *dummy_status;
- d_bg_thread->join(&dummy_status);
+ d_bg_thread->join(&dummy_status);
}
-
+
void
usrp2::impl::bg_loop()
{
@@ -356,10 +356,10 @@ namespace usrp2 {
// rings, and signal blocked API threads
int res = d_eth_buf->rx_frames(this, 100); // FIXME magic timeout
if (res == eth_buffer::EB_ERROR)
- break;
+ break;
// Wait for user API thread(s) to process all enqueued packets.
- // The channel ring thread that decrements d_num_enqueued to zero
+ // The channel ring thread that decrements d_num_enqueued to zero
// will signal this thread to continue.
{
omni_mutex_lock l(d_enqueued_mutex);
@@ -369,7 +369,7 @@ namespace usrp2 {
}
d_bg_running = false;
}
-
+
//
// passed to eth_buffer::rx_frames
//
@@ -401,11 +401,11 @@ namespace usrp2 {
{
// point to beginning of payload (subpackets)
unsigned char *p = (unsigned char *)base + sizeof(u2_eth_packet_t);
-
+
// FIXME (p % 4) == 2. Not good. Must watch for unaligned loads.
// FIXME iterate over payload, handling more than a single subpacket.
-
+
int opcode = p[0];
unsigned int oplen = p[1];
unsigned int rid = p[2];
@@ -417,8 +417,8 @@ namespace usrp2 {
std::cerr << "usrp2: mismatched command reply length (expected: "
<< buflen << " got: " << oplen << "). "
<< "op = " << opcode_to_string(opcode) << std::endl;
- }
-
+ }
+
// Copy reply into caller's buffer
memcpy(rp->buffer(), p, std::min(oplen, buflen));
rp->notify_completion();
@@ -430,26 +430,26 @@ namespace usrp2 {
DEBUG_LOG("l");
return data_handler::RELEASE;
}
-
+
data_handler::result
usrp2::impl::handle_data_packet(const void *base, size_t len)
{
u2_eth_samples_t *pkt = (u2_eth_samples_t *)base;
d_num_rx_frames++;
d_num_rx_bytes += len;
-
+
/* --- FIXME start of fake transport layer handler --- */
if (d_rx_seqno != -1) {
int expected_seqno = (d_rx_seqno + 1) & 0xFF;
- int seqno = pkt->hdrs.thdr.seqno;
-
+ int seqno = pkt->hdrs.thdr.seqno;
+
if (seqno != expected_seqno) {
::write(2, "S", 1); // missing sequence number
int missing = seqno - expected_seqno;
if (missing < 0)
missing += 256;
-
+
d_num_rx_overruns++;
d_num_rx_missing += missing;
}
@@ -469,9 +469,9 @@ namespace usrp2 {
DEBUG_LOG("!");
return data_handler::RELEASE; // discard packet, no channel handler
}
-
+
// Strip off ethernet header and transport header and enqueue the rest
-
+
size_t offset = offsetof(u2_eth_samples_t, hdrs.fixed);
if (d_channel_rings[chan]->enqueue(&pkt->hdrs.fixed, len-offset)) {
inc_enqueued();
@@ -481,7 +481,7 @@ namespace usrp2 {
else {
DEBUG_LOG("!");
return data_handler::RELEASE; // discard, no room in channel ring
- }
+ }
return data_handler::RELEASE;
}
}
@@ -491,7 +491,7 @@ namespace usrp2 {
// Receive
// ----------------------------------------------------------------
- bool
+ bool
usrp2::impl::set_rx_gain(double gain)
{
op_config_rx_v2_cmd cmd;
@@ -500,7 +500,7 @@ namespace usrp2 {
init_config_rx_v2_cmd(&cmd);
cmd.op.valid = htons(CFGV_GAIN);
cmd.op.gain = htons(u2_double_to_fxpt_gain(gain));
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
@@ -508,7 +508,7 @@ namespace usrp2 {
bool success = (ntohx(reply.ok) == 1);
return success;
}
-
+
bool
usrp2::impl::set_rx_lo_offset(double frequency)
{
@@ -527,7 +527,7 @@ namespace usrp2 {
cmd.eop.opcode = OP_EOP;
cmd.eop.len = sizeof(cmd.eop);
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
@@ -547,7 +547,7 @@ namespace usrp2 {
u2_fxpt_freq_t fxpt = u2_double_to_fxpt_freq(frequency);
cmd.op.freq_hi = htonl(u2_fxpt_freq_hi(fxpt));
cmd.op.freq_lo = htonl(u2_fxpt_freq_lo(fxpt));
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
@@ -555,18 +555,18 @@ namespace usrp2 {
bool success = (ntohx(reply.ok) == 1);
if (result && success) {
result->baseband_freq =
- u2_fxpt_freq_to_double(
- u2_fxpt_freq_from_hilo(ntohl(reply.baseband_freq_hi),
+ u2_fxpt_freq_to_double(
+ u2_fxpt_freq_from_hilo(ntohl(reply.baseband_freq_hi),
ntohl(reply.baseband_freq_lo)));
result->dxc_freq =
- u2_fxpt_freq_to_double(
- u2_fxpt_freq_from_hilo(ntohl(reply.ddc_freq_hi),
+ u2_fxpt_freq_to_double(
+ u2_fxpt_freq_from_hilo(ntohl(reply.ddc_freq_hi),
ntohl(reply.ddc_freq_lo)));
result->residual_freq =
- u2_fxpt_freq_to_double(
- u2_fxpt_freq_from_hilo(ntohl(reply.residual_freq_hi),
+ u2_fxpt_freq_to_double(
+ u2_fxpt_freq_from_hilo(ntohl(reply.residual_freq_hi),
ntohl(reply.residual_freq_lo)));
result->spectrum_inverted = (bool)(ntohx(reply.inverted) == 1);
@@ -574,7 +574,7 @@ namespace usrp2 {
return success;
}
-
+
bool
usrp2::impl::set_rx_decim(int decimation_factor)
{
@@ -584,7 +584,7 @@ namespace usrp2 {
init_config_rx_v2_cmd(&cmd);
cmd.op.valid = htons(CFGV_INTERP_DECIM);
cmd.op.decim = htonl(decimation_factor);
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
@@ -594,7 +594,7 @@ namespace usrp2 {
d_rx_decim = decimation_factor;
return success;
}
-
+
bool
usrp2::impl::set_rx_scale_iq(int scale_i, int scale_q)
{
@@ -604,7 +604,7 @@ namespace usrp2 {
init_config_rx_v2_cmd(&cmd);
cmd.op.valid = htons(CFGV_SCALE_IQ);
cmd.op.scale_iq = htonl(((scale_i & 0xffff) << 16) | (scale_q & 0xffff));
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
@@ -612,7 +612,7 @@ namespace usrp2 {
bool success = (ntohx(reply.ok) == 1);
return success;
}
-
+
bool
usrp2::impl::start_rx_streaming(unsigned int channel, unsigned int items_per_frame)
{
@@ -635,10 +635,10 @@ namespace usrp2 {
<< " already streaming" << std::endl;
return false;
}
-
+
if (items_per_frame == 0)
items_per_frame = U2_MAX_SAMPLES; // minimize overhead
-
+
op_start_rx_streaming_cmd cmd;
op_generic_t reply;
@@ -650,13 +650,13 @@ namespace usrp2 {
cmd.op.items_per_frame = htonl(items_per_frame);
cmd.eop.opcode = OP_EOP;
cmd.eop.len = sizeof(cmd.eop);
-
+
d_dont_enqueue = false;
bool success = false;
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
success = transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT);
success = success && (ntohx(reply.ok) == 1);
-
+
if (success)
d_channel_rings[channel] = ring_sptr(new ring(d_eth_buf->max_frames()));
else
@@ -666,7 +666,111 @@ namespace usrp2 {
return success;
}
}
-
+
+ bool
+ usrp2::impl::start_rx_streaming_at(unsigned int channel, unsigned int items_per_frame, unsigned int time)
+ {
+ if (channel > MAX_CHAN) {
+ std::cerr << "usrp2: invalid channel number (" << channel
+ << ")" << std::endl;
+ return false;
+ }
+
+ if (channel > 0) { // until firmware supports multiple streams
+ std::cerr << "usrp2: channel " << channel
+ << " not implemented" << std::endl;
+ return false;
+ }
+
+ {
+ omni_mutex_lock l(d_channel_rings_mutex);
+ if (d_channel_rings[channel]) {
+ std::cerr << "usrp2: channel " << channel
+ << " already streaming" << std::endl;
+ return false;
+ }
+
+ if (items_per_frame == 0)
+ items_per_frame = U2_MAX_SAMPLES; // minimize overhead
+
+ op_start_rx_streaming_cmd cmd;
+ op_generic_t reply;
+
+ memset(&cmd, 0, sizeof(cmd));
+ init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, time);
+ cmd.op.opcode = OP_START_RX_STREAMING;
+ cmd.op.len = sizeof(cmd.op);
+ cmd.op.rid = d_next_rid++;
+ cmd.op.items_per_frame = htonl(items_per_frame);
+ cmd.eop.opcode = OP_EOP;
+ cmd.eop.len = sizeof(cmd.eop);
+
+ bool success = false;
+ pending_reply p(cmd.op.rid, &reply, sizeof(reply));
+ success = transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT);
+ success = success && (ntohx(reply.ok) == 1);
+
+ if (success)
+ d_channel_rings[channel] = ring_sptr(new ring(d_eth_buf->max_frames()));
+
+ return success;
+ }
+ }
+
+ bool
+ usrp2::impl::sync_and_start_rx_streaming_at(unsigned int channel, unsigned int items_per_frame, unsigned int time)
+ {
+
+ if (channel > MAX_CHAN) {
+ std::cerr << "usrp2: invalid channel number (" << channel
+ << ")" << std::endl;
+ return false;
+ }
+
+ if (channel > 0) { // until firmware supports multiple streams
+ std::cerr << "usrp2: channel " << channel
+ << " not implemented" << std::endl;
+ return false;
+ }
+
+ {
+ omni_mutex_lock l(d_channel_rings_mutex);
+ if (d_channel_rings[channel]) {
+ std::cerr << "usrp2: channel " << channel
+ << " already streaming" << std::endl;
+ return false;
+ }
+
+ if (items_per_frame == 0)
+ items_per_frame = U2_MAX_SAMPLES; // minimize overhead
+
+ op_sync_and_start_rx_streaming_cmd cmd;
+ op_generic_t reply;
+
+ memset(&cmd, 0, sizeof(cmd));
+ init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, time);
+ cmd.sync_op.opcode = OP_SYNC_TO_PPS;
+ cmd.sync_op.len = sizeof(cmd.sync_op);
+ cmd.sync_op.rid = d_next_rid++;
+ cmd.rx_op.opcode = OP_START_RX_STREAMING;
+ cmd.rx_op.len = sizeof(cmd.rx_op);
+ cmd.rx_op.rid = d_next_rid++;
+ cmd.rx_op.items_per_frame = htonl(items_per_frame);
+ cmd.eop.opcode = OP_EOP;
+ cmd.eop.len = sizeof(cmd.eop);
+
+ bool success = false;
+ pending_reply p(cmd.sync_op.rid, &reply, sizeof(reply));
+ success = transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT);
+ success = success && (ntohx(reply.ok) == 1);
+
+ if (success)
+ d_channel_rings[channel] = ring_sptr(new ring(d_eth_buf->max_frames()));
+
+ return success;
+ }
+ }
+
bool
usrp2::impl::stop_rx_streaming(unsigned int channel)
{
@@ -698,7 +802,7 @@ namespace usrp2 {
cmd.op.rid = d_next_rid++;
cmd.eop.opcode = OP_EOP;
cmd.eop.len = sizeof(cmd.eop);
-
+
bool success = false;
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
success = transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT);
@@ -717,25 +821,25 @@ namespace usrp2 {
<< " )" << std::endl;
return false;
}
-
+
if (channel > 0) {
std::cerr << "usrp2: channel " << channel
<< " not implemented" << std::endl;
return false;
}
-
+
ring_sptr rp = d_channel_rings[channel];
if (!rp){
std::cerr << "usrp2: channel " << channel
<< " not receiving" << std::endl;
return false;
}
-
+
// Wait for frames available in channel ring
DEBUG_LOG("W");
rp->wait_for_not_empty();
DEBUG_LOG("s");
-
+
// Iterate through frames and present to user
void *p;
size_t frame_len_in_bytes;
@@ -791,7 +895,7 @@ namespace usrp2 {
// Transmit
// ----------------------------------------------------------------
- bool
+ bool
usrp2::impl::set_tx_gain(double gain)
{
op_config_tx_v2_cmd cmd;
@@ -800,7 +904,7 @@ namespace usrp2 {
init_config_tx_v2_cmd(&cmd);
cmd.op.valid = htons(CFGV_GAIN);
cmd.op.gain = htons(u2_double_to_fxpt_gain(gain));
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
@@ -808,7 +912,7 @@ namespace usrp2 {
bool success = (ntohx(reply.ok) == 1);
return success;
}
-
+
bool
usrp2::impl::set_tx_lo_offset(double frequency)
{
@@ -827,7 +931,7 @@ namespace usrp2 {
cmd.eop.opcode = OP_EOP;
cmd.eop.len = sizeof(cmd.eop);
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
@@ -847,7 +951,7 @@ namespace usrp2 {
u2_fxpt_freq_t fxpt = u2_double_to_fxpt_freq(frequency);
cmd.op.freq_hi = htonl(u2_fxpt_freq_hi(fxpt));
cmd.op.freq_lo = htonl(u2_fxpt_freq_lo(fxpt));
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
@@ -855,18 +959,18 @@ namespace usrp2 {
bool success = (ntohx(reply.ok) == 1);
if (result && success) {
result->baseband_freq =
- u2_fxpt_freq_to_double(
- u2_fxpt_freq_from_hilo(ntohl(reply.baseband_freq_hi),
+ u2_fxpt_freq_to_double(
+ u2_fxpt_freq_from_hilo(ntohl(reply.baseband_freq_hi),
ntohl(reply.baseband_freq_lo)));
result->dxc_freq =
- u2_fxpt_freq_to_double(
- u2_fxpt_freq_from_hilo(ntohl(reply.duc_freq_hi),
+ u2_fxpt_freq_to_double(
+ u2_fxpt_freq_from_hilo(ntohl(reply.duc_freq_hi),
ntohl(reply.duc_freq_lo)));
result->residual_freq =
- u2_fxpt_freq_to_double(
- u2_fxpt_freq_from_hilo(ntohl(reply.residual_freq_hi),
+ u2_fxpt_freq_to_double(
+ u2_fxpt_freq_from_hilo(ntohl(reply.residual_freq_hi),
ntohl(reply.residual_freq_lo)));
result->spectrum_inverted = (bool)(ntohx(reply.inverted) == 1);
@@ -874,7 +978,7 @@ namespace usrp2 {
return success;
}
-
+
bool
usrp2::impl::set_tx_interp(int interpolation_factor)
{
@@ -884,7 +988,7 @@ namespace usrp2 {
init_config_tx_v2_cmd(&cmd);
cmd.op.valid = htons(CFGV_INTERP_DECIM);
cmd.op.interp = htonl(interpolation_factor);
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
@@ -901,7 +1005,7 @@ namespace usrp2 {
return success;
}
-
+
void
usrp2::impl::default_tx_scale_iq(int interpolation_factor, int *scale_i, int *scale_q)
{
@@ -914,7 +1018,7 @@ namespace usrp2 {
// Calculate dsp_core_tx gain absent scale multipliers
float gain = (1.65*i*i*i)/(4096*pow(2, ceil(log2(i*i*i))));
-
+
// Calculate closest multiplier constant to reverse gain
int scale = (int)rint(1.0/gain);
// fprintf(stderr, "if=%i i=%i gain=%f scale=%i\n", interpolation_factor, i, gain, scale);
@@ -935,7 +1039,7 @@ namespace usrp2 {
init_config_tx_v2_cmd(&cmd);
cmd.op.valid = htons(CFGV_SCALE_IQ);
cmd.op.scale_iq = htonl(((scale_i & 0xffff) << 16) | (scale_q & 0xffff));
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
@@ -1063,7 +1167,7 @@ namespace usrp2 {
cmd.op.flags = flags;
cmd.eop.opcode = OP_EOP;
cmd.eop.len = sizeof(cmd.eop);
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
@@ -1137,10 +1241,10 @@ namespace usrp2 {
dst->dbid = ntohl(src->dbid);
dst->freq_min =
- u2_fxpt_freq_to_double(u2_fxpt_freq_from_hilo(ntohl(src->freq_min_hi),
+ u2_fxpt_freq_to_double(u2_fxpt_freq_from_hilo(ntohl(src->freq_min_hi),
ntohl(src->freq_min_lo)));
dst->freq_max =
- u2_fxpt_freq_to_double(u2_fxpt_freq_from_hilo(ntohl(src->freq_max_hi),
+ u2_fxpt_freq_to_double(u2_fxpt_freq_from_hilo(ntohl(src->freq_max_hi),
ntohl(src->freq_max_lo)));
dst->gain_min = u2_fxpt_gain_to_double(ntohs(src->gain_min));
@@ -1161,7 +1265,7 @@ namespace usrp2 {
cmd.op.rid = d_next_rid++;
cmd.eop.opcode = OP_EOP;
cmd.eop.len = sizeof(cmd.eop);
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
@@ -1188,7 +1292,7 @@ namespace usrp2 {
cmd.op.rid = d_next_rid++;
cmd.eop.opcode = OP_EOP;
cmd.eop.len = sizeof(cmd.eop);
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
@@ -1210,7 +1314,7 @@ namespace usrp2 {
cmd.op.ok = enable ? 1 : 0;
cmd.eop.opcode = OP_EOP;
cmd.eop.len = sizeof(cmd.eop);
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
@@ -1225,7 +1329,7 @@ namespace usrp2 {
// fprintf(stderr, "usrp2::peek: addr=%08X words=%u\n", addr, words);
if (addr % 4 != 0) {
- fprintf(stderr, "usrp2::peek: addr (=%08X) must be 32-bit word aligned\n", addr);
+ fprintf(stderr, "usrp2::peek: addr (=%08X) must be 32-bit word aligned\n", addr);
return result;
}
@@ -1267,7 +1371,7 @@ namespace usrp2 {
usrp2::impl::poke32(uint32_t addr, const std::vector<uint32_t> &data)
{
if (addr % 4 != 0) {
- fprintf(stderr, "usrp2::poke32: addr (=%08X) must be 32-bit word aligned\n", addr);
+ fprintf(stderr, "usrp2::poke32: addr (=%08X) must be 32-bit word aligned\n", addr);
return false;
}
@@ -1339,7 +1443,7 @@ namespace usrp2 {
cmd.op.rid = d_next_rid++;
cmd.eop.opcode = OP_EOP;
cmd.eop.len = sizeof(cmd.eop);
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
@@ -1368,7 +1472,7 @@ namespace usrp2 {
cmd.op.mask = htons(mask);
cmd.eop.opcode = OP_EOP;
cmd.eop.len = sizeof(cmd.eop);
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
@@ -1401,7 +1505,7 @@ namespace usrp2 {
memcpy(&cmd.op.sels, sels.c_str(), 16);
cmd.eop.opcode = OP_EOP;
cmd.eop.len = sizeof(cmd.eop);
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
@@ -1430,7 +1534,7 @@ namespace usrp2 {
cmd.op.mask = htons(mask);
cmd.eop.opcode = OP_EOP;
cmd.eop.len = sizeof(cmd.eop);
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
@@ -1459,7 +1563,7 @@ namespace usrp2 {
cmd.op.mask = 0; // not used
cmd.eop.opcode = OP_EOP;
cmd.eop.len = sizeof(cmd.eop);
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
@@ -1496,7 +1600,7 @@ namespace usrp2 {
cmd.op.mask = 0; // not used
cmd.eop.opcode = OP_EOP;
cmd.eop.len = sizeof(cmd.eop);
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
diff --git a/usrp2/host/lib/usrp2_impl.h b/usrp2/host/lib/usrp2_impl.h
index ed71a6ba3..d78a00db4 100644
--- a/usrp2/host/lib/usrp2_impl.h
+++ b/usrp2/host/lib/usrp2_impl.h
@@ -30,7 +30,7 @@
#define MAX_SUBPKT_LEN 252
namespace usrp2 {
-
+
class eth_buffer;
class pktfilter;
class usrp2_thread;
@@ -62,7 +62,7 @@ namespace usrp2 {
std::string d_addr; // FIXME: use u2_mac_addr_t instead
usrp2_thread *d_bg_thread;
volatile bool d_bg_running; // TODO: multistate if needed
-
+
int d_rx_seqno;
int d_tx_seqno;
int d_next_rid;
@@ -84,7 +84,7 @@ namespace usrp2 {
db_info d_tx_db_info;
db_info d_rx_db_info;
- int d_tx_interp; // shadow tx interp
+ int d_tx_interp; // shadow tx interp
int d_rx_decim; // shadow rx decim
bool d_dont_enqueue;
@@ -93,13 +93,13 @@ namespace usrp2 {
omni_mutex_lock l(d_enqueued_mutex);
d_num_enqueued++;
}
-
+
void dec_enqueued() {
omni_mutex_lock l(d_enqueued_mutex);
if (--d_num_enqueued == 0)
d_bg_pending_cond.signal();
}
-
+
static bool parse_mac_addr(const std::string &s, u2_mac_addr_t *p);
void init_et_hdrs(u2_eth_packet_t *p, const std::string &dst);
void init_etf_hdrs(u2_eth_packet_t *p, const std::string &dst,
@@ -118,7 +118,7 @@ namespace usrp2 {
public:
impl(const std::string &ifc, props *p, size_t rx_bufsize);
~impl();
-
+
void bg_loop();
std::string mac_addr() const { return d_addr; } // FIXME: convert from u2_mac_addr_t
@@ -143,6 +143,8 @@ namespace usrp2 {
bool write_gpio(int bank, uint16_t value, uint16_t mask);
bool read_gpio(int bank, uint16_t *value);
bool start_rx_streaming(unsigned int channel, unsigned int items_per_frame);
+ bool start_rx_streaming_at(unsigned int channel, unsigned int items_per_frame, unsigned int time);
+ bool sync_and_start_rx_streaming_at(unsigned int channel, unsigned int items_per_frame, unsigned int time);
bool rx_samples(unsigned int channel, rx_sample_handler *handler);
bool flush_rx_samples(unsigned int channel);
bool stop_rx_streaming(unsigned int channel);
@@ -196,7 +198,7 @@ namespace usrp2 {
std::vector<uint32_t> peek32(uint32_t addr, uint32_t words);
bool poke32(uint32_t addr, const std::vector<uint32_t> &data);
};
-
+
} // namespace usrp2
#endif /* INCLUDED_USRP2_IMPL_H */