diff options
Diffstat (limited to 'usrp2')
-rw-r--r-- | usrp2/firmware/apps/app_common_v2.c | 59 | ||||
-rw-r--r-- | usrp2/firmware/apps/app_common_v2.h | 4 | ||||
-rw-r--r-- | usrp2/firmware/apps/factory_test.c | 25 | ||||
-rw-r--r-- | usrp2/firmware/apps/mimo_tx_slave.c | 10 | ||||
-rw-r--r-- | usrp2/firmware/apps/serdes_txrx.c | 10 | ||||
-rw-r--r-- | usrp2/firmware/apps/txrx.c | 61 | ||||
-rw-r--r-- | usrp2/firmware/config/grc_usrp2_firmware.m4 | 6 | ||||
-rw-r--r-- | usrp2/firmware/lib/db_init.c | 2 | ||||
-rw-r--r-- | usrp2/firmware/lib/db_tvrx.c | 32 | ||||
-rw-r--r-- | usrp2/firmware/lib/db_xcvr2450.c | 4 | ||||
-rw-r--r-- | usrp2/firmware/lib/memory_map.h | 4 | ||||
-rw-r--r-- | usrp2/fpga/control_lib/pic.v | 183 | ||||
-rw-r--r-- | usrp2/fpga/control_lib/priority_enc.v | 44 | ||||
-rwxr-xr-x | usrp2/fpga/top/u2_core/u2_core.v | 44 | ||||
-rw-r--r-- | usrp2/fpga/top/u2_rev3/Makefile | 3 | ||||
-rw-r--r-- | usrp2/host/include/usrp2/usrp2.h | 59 | ||||
-rw-r--r-- | usrp2/host/lib/control.h | 26 | ||||
-rw-r--r-- | usrp2/host/lib/usrp2.cc | 52 | ||||
-rw-r--r-- | usrp2/host/lib/usrp2_impl.cc | 296 | ||||
-rw-r--r-- | usrp2/host/lib/usrp2_impl.h | 16 |
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 */ |