[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Commit-gnuradio] r9142 - in usrp2/trunk: firmware firmware/apps firmwar
From: |
eb |
Subject: |
[Commit-gnuradio] r9142 - in usrp2/trunk: firmware firmware/apps firmware/include firmware/lib host/apps host-ng host-ng/apps host-ng/include/usrp2 host-ng/lib |
Date: |
Fri, 1 Aug 2008 14:34:21 -0600 (MDT) |
Author: eb
Date: 2008-08-01 14:34:19 -0600 (Fri, 01 Aug 2008)
New Revision: 9142
Added:
usrp2/trunk/firmware/lib/usrp2_bytesex.h
usrp2/trunk/host-ng/apps/find_usrps.cc
usrp2/trunk/host-ng/apps/gen_2tone.py
usrp2/trunk/host-ng/apps/gen_const.cc
usrp2/trunk/host-ng/apps/gen_sine.py
usrp2/trunk/host-ng/apps/rx_samples.cc
usrp2/trunk/host-ng/apps/stdin_int32_fft.py
usrp2/trunk/host-ng/apps/streaming_fft.py
usrp2/trunk/host-ng/apps/test2_usrp2.cc
usrp2/trunk/host-ng/apps/tx_samples.cc
usrp2/trunk/host-ng/apps/u2_burn_mac_addr.cc
usrp2/trunk/host-ng/include/usrp2/copiers.h
usrp2/trunk/host-ng/include/usrp2/metadata.h
usrp2/trunk/host-ng/include/usrp2/rx_sample_handler.h
usrp2/trunk/host-ng/include/usrp2/strtod_si.h
usrp2/trunk/host-ng/include/usrp2/tune_result.h
usrp2/trunk/host-ng/lib/copiers.cc
usrp2/trunk/host-ng/lib/data_handler.cc
usrp2/trunk/host-ng/lib/ring.cc
usrp2/trunk/host-ng/lib/ring.h
usrp2/trunk/host-ng/lib/rx_sample_handler.cc
usrp2/trunk/host-ng/lib/strtod_si.c
usrp2/trunk/host-ng/lib/usrp2_bytesex.h
Removed:
usrp2/trunk/firmware/apps/app_common.h
usrp2/trunk/firmware/apps/rx_only.c
usrp2/trunk/firmware/apps/tx_only.c
usrp2/trunk/firmware/include/usrp2_bytesex.h
usrp2/trunk/host/apps/find_usrps.cc
usrp2/trunk/host/apps/gen_2tone.py
usrp2/trunk/host/apps/gen_const.cc
usrp2/trunk/host/apps/gen_sine.py
usrp2/trunk/host/apps/rx_samples.cc
usrp2/trunk/host/apps/stdin_int32_fft.py
usrp2/trunk/host/apps/streaming_fft.py
usrp2/trunk/host/apps/tx_samples.cc
usrp2/trunk/host/apps/u2_burn_mac_addr.cc
Modified:
usrp2/trunk/firmware/apps/Makefile.am
usrp2/trunk/firmware/apps/app_common_v2.c
usrp2/trunk/firmware/apps/app_common_v2.h
usrp2/trunk/firmware/include/usrp2_eth_packet.h
usrp2/trunk/firmware/lib/memory_map.h
usrp2/trunk/firmware/u2_flash_tool
usrp2/trunk/host-ng/apps/
usrp2/trunk/host-ng/apps/Makefile.am
usrp2/trunk/host-ng/apps/test.sh
usrp2/trunk/host-ng/apps/test_usrp2.cc
usrp2/trunk/host-ng/configure.ac
usrp2/trunk/host-ng/include/usrp2/Makefile.am
usrp2/trunk/host-ng/include/usrp2/copy_handler.h
usrp2/trunk/host-ng/include/usrp2/data_handler.h
usrp2/trunk/host-ng/include/usrp2/usrp2.h
usrp2/trunk/host-ng/lib/Makefile.am
usrp2/trunk/host-ng/lib/control.cc
usrp2/trunk/host-ng/lib/control.h
usrp2/trunk/host-ng/lib/copy_handler.cc
usrp2/trunk/host-ng/lib/eth_buffer.cc
usrp2/trunk/host-ng/lib/eth_buffer.h
usrp2/trunk/host-ng/lib/ethernet.cc
usrp2/trunk/host-ng/lib/ethernet.h
usrp2/trunk/host-ng/lib/find.cc
usrp2/trunk/host-ng/lib/usrp2.cc
usrp2/trunk/host-ng/lib/usrp2_impl.cc
usrp2/trunk/host-ng/lib/usrp2_impl.h
usrp2/trunk/host-ng/lib/usrp2_thread.cc
Log:
The grand unified merger! merged eb/merge-wip -r9112:9140 into
usrp2/trunk. This brings everything from features/host-ng into the
trunk. The firmware, host-ng and fpga code all match. What a concept!
The host directory currently won't build. As soon as everything we
need is extracted from it, we'll nuke it and svn mv host-ng to host.
Modified: usrp2/trunk/firmware/apps/Makefile.am
===================================================================
--- usrp2/trunk/firmware/apps/Makefile.am 2008-08-01 20:25:36 UTC (rev
9141)
+++ usrp2/trunk/firmware/apps/Makefile.am 2008-08-01 20:34:19 UTC (rev
9142)
@@ -1,5 +1,5 @@
#
-# Copyright 2007 Free Software Foundation, Inc.
+# Copyright 2007,2008 Free Software Foundation, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -30,7 +30,6 @@
ibs_rx_test \
ibs_tx_test \
rcv_eth_packets \
- rx_only \
rx_only_v2 \
read_dbids \
test1 \
@@ -41,12 +40,9 @@
test_lsdac \
test_serdes \
timer_test \
- tx_only \
tx_only_v2 \
tx_standalone \
txrx \
- eth_to_serdes \
- serdes_to_dsp \
sd_gentest \
sd_bounce
@@ -54,13 +50,11 @@
# tx_drop_SOURCES = tx_drop.c app_common.c
# tx_drop_rate_limited_SOURCES = tx_drop_rate_limited.c app_common.c
# tx_drop2_SOURCES = tx_drop2.c app_common.c
-tx_only_SOURCES = tx_only.c app_common.c
-rx_only_SOURCES = rx_only.c app_common.c
rx_only_v2_SOURCES = rx_only_v2.c app_common_v2.c
tx_only_v2_SOURCES = tx_only_v2.c app_common_v2.c
txrx_SOURCES = txrx.c app_common_v2.c
-eth_to_serdes_SOURCES = eth_to_serdes.c app_passthru.c
-serdes_to_dsp_SOURCES = serdes_to_dsp.c app_common.c
+#eth_to_serdes_SOURCES = eth_to_serdes.c app_passthru.c
+#serdes_to_dsp_SOURCES = serdes_to_dsp.c app_common.c
Deleted: usrp2/trunk/firmware/apps/app_common.h
Modified: usrp2/trunk/firmware/apps/app_common_v2.c
===================================================================
--- usrp2/trunk/firmware/apps/app_common_v2.c 2008-08-01 20:25:36 UTC (rev
9141)
+++ usrp2/trunk/firmware/apps/app_common_v2.c 2008-08-01 20:34:19 UTC (rev
9142)
@@ -39,15 +39,19 @@
static unsigned char exp_seqno = 0;
-void config_mimo_cmd(op_config_mimo_t *p /* , op_generic_t *r */);
-
-
-static void
+static bool
burn_mac_addr(const op_burn_mac_addr_t *p)
{
- ethernet_set_mac_addr(&p->addr);
+ return ethernet_set_mac_addr(&p->addr);
}
+static bool
+config_mimo_cmd(const op_config_mimo_t *p)
+{
+ clocks_mimo_config(p->flags);
+ return true;
+}
+
void
set_reply_hdr(u2_eth_packet_t *reply_pkt, u2_eth_packet_t const *cmd_pkt)
{
@@ -94,168 +98,38 @@
}
-void
-handle_control_chan_frame(u2_eth_packet_t *pkt, size_t len)
+static size_t
+op_id_cmd(const op_generic_t *p,
+ void *reply_payload, size_t reply_payload_space)
{
- unsigned char reply[sizeof(u2_eth_packet_t) + sizeof(u2_subpkt_t)] _AL4;
- unsigned char *s = &reply[sizeof(u2_eth_packet_t)];
- size_t reply_len = 0;
+ op_id_reply_t *r = (op_id_reply_t *) reply_payload;
+ if (reply_payload_space < sizeof(*r)) // no room
+ return 0;
- // initialize reply
- memset(reply, 0, sizeof(reply));
- set_reply_hdr((u2_eth_packet_t *) reply, pkt);
+ // Build reply subpacket
- // point to beginning of payload (subpackets)
- unsigned char *p = ((unsigned char *) pkt) + sizeof(u2_eth_packet_t);
+ r->opcode = OP_ID_REPLY;
+ r->len = sizeof(op_id_reply_t);
+ r->rid = p->rid;
+ r->addr = *ethernet_mac_addr();
+ r->hw_rev = 0x0000; // FIXME
+ // r->fpga_md5sum = ; // FIXME
+ // r->sw_md5sum = ; // FIXME
- // FIXME iterate over payload, handling more than a single subpacket
+ // FIXME Add d'board info, including dbid, min/max gain, min/max freq
- int opcode = p[0];
-
- switch(opcode){
- case OP_ID:
- {
- op_id_reply_t *r = (op_id_reply_t *) s;
- reply_len = sizeof(u2_eth_packet_t) + sizeof(op_id_reply_t);
- r->opcode = OP_ID_REPLY;
- r->len = sizeof(op_id_reply_t);
- r->rid = ((op_id_t *) p)->rid;
- r->addr = *ethernet_mac_addr();
- r->hw_rev = 0x0000; // FIXME
- // r->fpga_md5sum = ; // FIXME
- // r->sw_md5sum = ; // FIXME
-
- // FIXME Add d'board info, including dbid, min/max gain, min/max freq
- }
- send_reply(reply, reply_len);
- break;
-
- case OP_CONFIG_TX_V2:
- config_tx_v2_cmd((op_config_tx_v2_t *) p, (op_config_tx_reply_v2_t *) s);
- send_reply(reply, sizeof(u2_eth_packet_t) + s[1]);
- break;
-
- case OP_CONFIG_RX_V2:
- config_rx_v2_cmd((op_config_rx_v2_t *) p, (op_config_rx_reply_v2_t *) s);
- send_reply(reply, sizeof(u2_eth_packet_t) + s[1]);
- break;
-
- case OP_START_RX_STREAMING:
- start_rx_streaming_cmd(&pkt->ehdr.src, (op_start_rx_streaming_t *) p);
- break;
-
- case OP_STOP_RX:
- stop_rx_cmd();
- break;
-
- case OP_BURN_MAC_ADDR:
- burn_mac_addr((op_burn_mac_addr_t *) p);
- break;
-
- case OP_READ_TIME:
- {
- op_read_time_reply_t *r = (op_read_time_reply_t *) s;
- reply_len = sizeof(u2_eth_packet_t) + sizeof(op_read_time_reply_t);
- r->opcode = OP_READ_TIME_REPLY;
- r->len = sizeof(op_read_time_reply_t);
- r->rid = ((op_read_time_t *) p)->rid;
- r->time = timer_regs->time;
- }
- send_reply(reply, reply_len);
- break;
-
- case OP_CONFIG_MIMO:
- config_mimo_cmd((op_config_mimo_t *) p);
- break;
-
- default:
- printf("app_common_v2: unhandled opcode = %d\n", opcode);
- break;
- }
+ return r->len;
}
-/*
- * Called when an ethernet packet is received.
- * Return true if we handled it here, otherwise
- * it'll be passed on to the DSP Tx pipe
- */
-bool
-eth_pkt_inspector(dbsm_t *sm, int bufno)
+static size_t
+config_tx_v2_cmd(const op_config_tx_v2_t *p,
+ void *reply_payload, size_t reply_payload_space)
{
- u2_eth_packet_t *pkt = (u2_eth_packet_t *) buffer_ram(bufno);
- size_t byte_len = (buffer_pool_status->last_line[bufno] - 3) * 4;
+ op_config_tx_reply_v2_t *r = (op_config_tx_reply_v2_t *) reply_payload;
+ if (reply_payload_space < sizeof(*r))
+ return 0; // no room
- // static size_t last_len = 0; // kludge
-
- // hal_toggle_leds(0x1);
-
- // inspect rcvd frame and figure out what do do.
-
- if (pkt->ehdr.ethertype != U2_ETHERTYPE)
- return true; // ignore, probably bogus PAUSE frame from MAC
-
- int chan = u2p_chan(&pkt->fixed);
-
- switch (chan){
- case CONTROL_CHAN:
- handle_control_chan_frame(pkt, byte_len);
- return true; // we handled the packet
- break;
-
- case 0:
- default:
-#if 0
- if (last_len != 0){
- if (byte_len != last_len){
- printf("Len: %d last: %d\n", byte_len, last_len);
- }
- }
- last_len = byte_len;
-
- if((pkt->thdr.seqno) == exp_seqno){
- exp_seqno++;
- //putchar('.');
- }
- else {
- puts("Seq");
- //printf("S%d %d ",exp_seqno,pkt->thdr.seqno);
- exp_seqno = pkt->thdr.seqno + 1;
- }
-#endif
- return false; // pass it on to Tx DSP
- break;
- }
-}
-
-/*
- * Called when eth phy state changes (w/ interrupts disabled)
- */
-void
-link_changed_callback(int speed)
-{
- link_is_up = speed != 0;
- hal_set_leds(link_is_up ? 0x10 : 0x0, 0x10);
- printf("\neth link changed: speed = %d\n", speed);
-}
-
-
-void
-print_tune_result(char *msg, bool tune_ok,
- u2_fxpt_freq_t target_freq, struct tune_result *r)
-{
- printf("db_tune %s %s\n", msg, tune_ok ? "true" : "false");
- putstr(" target_freq "); print_fxpt_freq(target_freq); newline();
- putstr(" baseband_freq "); print_fxpt_freq(r->baseband_freq); newline();
- putstr(" dxc_freq "); print_fxpt_freq(r->dxc_freq); newline();
- putstr(" residual_freq "); print_fxpt_freq(r->residual_freq); newline();
- printf(" inverted %s\n", r->inverted ? "true" : "false");
-}
-
-
-void
-config_tx_v2_cmd(const op_config_tx_v2_t *p, op_config_tx_reply_v2_t *r)
-{
struct tune_result tune_result;
memset(&tune_result, 0, sizeof(tune_result));
@@ -276,29 +150,33 @@
int interp = p->interp;
int hb1 = 0;
int hb2 = 0;
-
- if(!(interp & 1)) {
- hb1 = 1;
- interp = interp >> 1;
- }
-
- if(!(interp & 1)) {
+
+ if (!(interp & 1)){
hb2 = 1;
interp = interp >> 1;
}
+
+ if (!(interp & 1)){
+ hb1 = 1;
+ interp = interp >> 1;
+ }
- dsp_tx_regs->interp_rate =(hb1<<9) | (hb2<<8) | interp;
- // printf("Interp: %d, register %d\n", p->interp, (hb1<<9) | (hb2<<8) |
interp);
+ if (p->interp < MIN_INTERP || p->interp > MAX_INTERP)
+ ok = false;
+ else {
+ dsp_tx_regs->interp_rate = (hb1<<9) | (hb2<<8) | interp;
+ // printf("Interp: %d, register %d\n", p->interp, (hb1<<9) | (hb2<<8) |
interp);
+ }
}
-
+
if (p->valid & CFGV_SCALE_IQ){
dsp_tx_regs->scale_iq = p->scale_iq;
}
- // Build reply; it's sent by our caller.
+ // Build reply subpacket
r->opcode = OP_CONFIG_TX_REPLY_V2;
- r->len = sizeof(op_config_tx_reply_v2_t);
+ r->len = sizeof(*r);
r->rid = p->rid;
r->ok = ok;
r->inverted = tune_result.inverted;
@@ -308,11 +186,17 @@
r->duc_freq_lo = u2_fxpt_freq_lo(tune_result.dxc_freq);
r->residual_freq_hi = u2_fxpt_freq_hi(tune_result.residual_freq);
r->residual_freq_lo = u2_fxpt_freq_lo(tune_result.residual_freq);
+ return r->len;
}
-void
-config_rx_v2_cmd(const op_config_rx_v2_t *p, op_config_rx_reply_v2_t *r)
+static size_t
+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;
+ if (reply_payload_space < sizeof(*r))
+ return 0; // no room
+
struct tune_result tune_result;
memset(&tune_result, 0, sizeof(tune_result));
@@ -344,18 +228,22 @@
decim = decim >> 1;
}
- dsp_rx_regs->decim_rate = (hb1<<9) | (hb2<<8) | decim;
- // printf("Decim: %d, register %d\n", p->decim, (hb1<<9) | (hb2<<8) |
decim);
+ if (decim < MIN_DECIM || decim > MAX_DECIM)
+ ok = false;
+ else {
+ dsp_rx_regs->decim_rate = (hb1<<9) | (hb2<<8) | decim;
+ // printf("Decim: %d, register %d\n", p->decim, (hb1<<9) | (hb2<<8) |
decim);
+ }
}
if (p->valid & CFGV_SCALE_IQ){
dsp_rx_regs->scale_iq = p->scale_iq;
}
- // Build reply; it's sent by our caller.
+ // Build reply subpacket
r->opcode = OP_CONFIG_RX_REPLY_V2;
- r->len = sizeof(op_config_rx_reply_v2_t);
+ r->len = sizeof(*r);
r->rid = p->rid;
r->ok = ok;
r->inverted = tune_result.inverted;
@@ -365,11 +253,220 @@
r->ddc_freq_lo = u2_fxpt_freq_lo(tune_result.dxc_freq);
r->residual_freq_hi = u2_fxpt_freq_hi(tune_result.residual_freq);
r->residual_freq_lo = u2_fxpt_freq_lo(tune_result.residual_freq);
+
+ return r->len;
}
+static size_t
+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))
+ return 0; // no room
+
+ r->opcode = OP_READ_TIME_REPLY;
+ r->len = sizeof(*r);
+ r->rid = p->rid;
+ r->time = timer_regs->time;
+
+ return r->len;
+}
+
+static size_t
+generic_reply(const op_generic_t *p,
+ void *reply_payload, size_t reply_payload_space,
+ bool ok)
+{
+ op_generic_t *r = (op_generic_t *) reply_payload;
+ 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;
+}
+
+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))
+ return 0; // no room
+
+ r->opcode = OP_EOP;
+ r->len = sizeof(*r);
+ r->rid = 0;
+ r->ok = 0;
+
+ return r->len;
+}
+
void
-config_mimo_cmd(op_config_mimo_t *p /* , op_generic_t *r */)
+handle_control_chan_frame(u2_eth_packet_t *pkt, size_t len)
{
- clocks_mimo_config(p->flags);
- // FIXME build generic reply
+ 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;
+
+ while (payload_len >= sizeof(op_generic_t)){
+ const op_generic_t *gp = (const op_generic_t *) payload;
+ subpktlen = 0;
+
+ switch(gp->opcode){
+ case OP_EOP: // end of subpackets
+ goto end_of_subpackets;
+
+ 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;
+
+ case OP_CONFIG_RX_V2:
+ subpktlen = config_rx_v2_cmd((op_config_rx_v2_t *) payload,
+ reply_payload, reply_payload_space);
+ break;
+
+ case OP_START_RX_STREAMING:
+ start_rx_streaming_cmd(&pkt->ehdr.src, (op_start_rx_streaming_t *)
payload);
+ subpktlen = generic_reply(gp, reply_payload, reply_payload_space, true);
+ break;
+
+ case OP_STOP_RX:
+ stop_rx_cmd();
+ subpktlen = generic_reply(gp, reply_payload, reply_payload_space, true);
+ break;
+
+ case OP_BURN_MAC_ADDR:
+ subpktlen = generic_reply(gp, reply_payload, reply_payload_space,
+ burn_mac_addr((op_burn_mac_addr_t *) payload));
+ break;
+
+ case OP_CONFIG_MIMO:
+ subpktlen = generic_reply(gp, reply_payload, reply_payload_space,
+ config_mimo_cmd((op_config_mimo_t *) payload));
+ break;
+
+ case OP_READ_TIME:
+ subpktlen = read_time_cmd(gp, reply_payload, reply_payload_space);
+ break;
+
+ default:
+ printf("app_common_v2: unhandled opcode = %d\n", gp->opcode);
+ break;
+ }
+
+ int t = (gp->len + 3) & ~3; // bump to a multiple of 4
+ payload += t;
+ payload_len -= t;
+
+ subpktlen = (subpktlen + 3) & ~3; // bump to a multiple of 4
+ reply_payload += subpktlen;
+ reply_payload_space -= subpktlen;
+ }
+
+ end_of_subpackets:
+
+ // add the EOP marker
+ subpktlen = add_eop(reply_payload, reply_payload_space);
+ subpktlen = (subpktlen + 3) & ~3; // bump to a multiple of 4
+ reply_payload += subpktlen;
+ reply_payload_space -= subpktlen;
+
+ send_reply(reply, reply_payload - reply);
}
+
+
+/*
+ * Called when an ethernet packet is received.
+ * Return true if we handled it here, otherwise
+ * it'll be passed on to the DSP Tx pipe
+ */
+bool
+eth_pkt_inspector(dbsm_t *sm, int bufno)
+{
+ u2_eth_packet_t *pkt = (u2_eth_packet_t *) buffer_ram(bufno);
+ size_t byte_len = (buffer_pool_status->last_line[bufno] - 3) * 4;
+
+ //static size_t last_len = 0;
+
+ // hal_toggle_leds(0x1);
+
+ // inspect rcvd frame and figure out what do do.
+
+ if (pkt->ehdr.ethertype != U2_ETHERTYPE)
+ return true; // ignore, probably bogus PAUSE frame from MAC
+
+ int chan = u2p_chan(&pkt->fixed);
+
+ switch (chan){
+ case CONTROL_CHAN:
+ handle_control_chan_frame(pkt, byte_len);
+ return true; // we handled the packet
+ break;
+
+ case 0:
+ default:
+#if 0
+ if (last_len != 0){
+ if (byte_len != last_len){
+ printf("Len: %d last: %d\n", byte_len, last_len);
+ }
+ }
+ last_len = byte_len;
+
+ if((pkt->thdr.seqno) == exp_seqno){
+ exp_seqno++;
+ //putchar('.');
+ }
+ else {
+ // putchar('S');
+ //printf("S%d %d ",exp_seqno,pkt->thdr.seqno);
+ exp_seqno = pkt->thdr.seqno + 1;
+ }
+#endif
+ return false; // pass it on to Tx DSP
+ break;
+ }
+}
+
+/*
+ * Called when eth phy state changes (w/ interrupts disabled)
+ */
+void
+link_changed_callback(int speed)
+{
+ link_is_up = speed != 0;
+ hal_set_leds(link_is_up ? 0x10 : 0x0, 0x10);
+ printf("\neth link changed: speed = %d\n", speed);
+}
+
+
+void
+print_tune_result(char *msg, bool tune_ok,
+ u2_fxpt_freq_t target_freq, struct tune_result *r)
+{
+ printf("db_tune %s %s\n", msg, tune_ok ? "true" : "false");
+ putstr(" target_freq "); print_fxpt_freq(target_freq); newline();
+ putstr(" baseband_freq "); print_fxpt_freq(r->baseband_freq); newline();
+ putstr(" dxc_freq "); print_fxpt_freq(r->dxc_freq); newline();
+ putstr(" residual_freq "); print_fxpt_freq(r->residual_freq); newline();
+ printf(" inverted %s\n", r->inverted ? "true" : "false");
+}
Modified: usrp2/trunk/firmware/apps/app_common_v2.h
===================================================================
--- usrp2/trunk/firmware/apps/app_common_v2.h 2008-08-01 20:25:36 UTC (rev
9141)
+++ usrp2/trunk/firmware/apps/app_common_v2.h 2008-08-01 20:34:19 UTC (rev
9142)
@@ -54,8 +54,6 @@
u2_fxpt_freq_t target_freq, struct tune_result *r);
-void config_tx_v2_cmd(const op_config_tx_v2_t *p, op_config_tx_reply_v2_t *r);
-void config_rx_v2_cmd(const op_config_rx_v2_t *p, op_config_rx_reply_v2_t *r);
void start_rx_streaming_cmd(const u2_mac_addr_t *host, op_start_rx_streaming_t
*p);
void stop_rx_cmd(void);
Deleted: usrp2/trunk/firmware/apps/rx_only.c
Deleted: usrp2/trunk/firmware/apps/tx_only.c
Deleted: usrp2/trunk/firmware/include/usrp2_bytesex.h
Modified: usrp2/trunk/firmware/include/usrp2_eth_packet.h
===================================================================
--- usrp2/trunk/firmware/include/usrp2_eth_packet.h 2008-08-01 20:25:36 UTC
(rev 9141)
+++ usrp2/trunk/firmware/include/usrp2_eth_packet.h 2008-08-01 20:34:19 UTC
(rev 9142)
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2007 Free Software Foundation, Inc.
+ * Copyright 2007,2008 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -33,6 +33,9 @@
* All these data structures are BIG-ENDIAN on the wire
*/
+// FIXME gcc specific. Really ought to come from compiler.h
+#define _AL4 __attribute__((aligned (4)))
+
/*
* \brief The classic 14-byte ethernet header
*/
@@ -155,48 +158,55 @@
/*
* Opcodes for control channel
+ *
+ * Reply opcodes are the same as the request opcode with the OP_REPLY_BIT set
(0x80).
*/
-#define OP_EOP 0 // marks last subpacket in
packet
-#define OP_ID 1
-#define OP_ID_REPLY 2
-#define OP_BURN_MAC_ADDR 3
-#define OP_READ_TIME 4 // What time is it? (100 MHz
counter)
-#define OP_READ_TIME_REPLY 5 // This time.
-#define OP_CONFIG_RX_V2 6
-#define OP_CONFIG_RX_REPLY_V2 7
-#define OP_CONFIG_TX_V2 8
-#define OP_CONFIG_TX_REPLY_V2 9
-#define OP_START_RX_STREAMING 10
-#define OP_STOP_RX 11
-#define OP_CONFIG_MIMO 12 // FIXME on merge
+#define OP_REPLY_BIT 0x80
-#define OP_START_RX 20 // deprecated
-#define OP_CONFIG_TX 21 // deprecated
+#define OP_EOP 0 // marks last subpacket in
packet
-#define OP_WRITE_REG 25 // not implemented
-#define OP_WRITE_REG_MASKED 26
-#define OP_READ_REG 27
-#define OP_READ_REG_REPLY 28
+#define OP_ID 1
+#define OP_ID_REPLY (OP_ID | OP_REPLY_BIT)
+#define OP_BURN_MAC_ADDR 2
+#define OP_BURN_MAC_ADDR_REPLY (OP_BURN_MAC_ADDR | OP_REPLY_BIT)
+#define OP_READ_TIME 3 // What time is it? (100 MHz
counter)
+#define OP_READ_TIME_REPLY (OP_READ_TIME | OP_REPLY_BIT)
+#define OP_CONFIG_RX_V2 4
+#define OP_CONFIG_RX_REPLY_V2 (OP_CONFIG_RX_V2 | OP_REPLY_BIT)
+#define OP_CONFIG_TX_V2 5
+#define OP_CONFIG_TX_REPLY_V2 (OP_CONFIG_TX_V2 | OP_REPLY_BIT)
+#define OP_START_RX_STREAMING 6
+#define OP_START_RX_STREAMING_REPLY (OP_START_RX_STREAMING |
OP_REPLY_BIT)
+#define OP_STOP_RX 7
+#define OP_STOP_RX_REPLY (OP_STOP_RX | OP_REPLY_BIT)
+#define OP_CONFIG_MIMO 8
+#define OP_CONFIG_MIMO_REPLY (OP_CONFIG_MIMO | OP_REPLY_BIT)
-/*!
- * \brief Marker for last subpacket in packet
+//#define OP_WRITE_REG xx // not implemented
+//#define OP_WRITE_REG_MASKED xx
+//#define OP_READ_REG xx
+//#define OP_READ_REG_REPLY xx
+
+/*
+ * All subpackets are a multiple of 4 bytes long.
+ * All subpackets start with an 8-bit opcode, an 8-bit len and an 8-bit rid.
*/
-typedef struct {
- uint8_t opcode;
- uint8_t len;
- uint16_t mbz;
-} op_eop_t;
+
/*!
- * \brief Look for USRP2's
+ * \brief Generic request and reply packet
+ *
+ * Used by:
+ * OP_EOP, OP_BURN_MAC_ADDR_REPLY, OP_START_RX_STREAMING_REPLY,
+ * OP_STOP_RX_REPLY
*/
typedef struct {
uint8_t opcode;
uint8_t len;
uint8_t rid;
- uint8_t mbz;
-} op_id_t;
+ uint8_t ok; // bool
+} _AL4 op_generic_t;
/*!
* \brief Reply info from a USRP2
@@ -210,41 +220,30 @@
uint16_t hw_rev;
uint8_t fpga_md5sum[16];
uint8_t sw_md5sum[16];
-} op_id_reply_t;
+} _AL4 op_id_reply_t;
typedef struct {
uint8_t opcode;
uint8_t len;
- uint16_t mbz;
+ uint8_t rid;
+ uint8_t mbz;
uint32_t items_per_frame; // # of 32-bit data items; MTU=1500: [9,371]
-} op_start_rx_streaming_t;
+} _AL4 op_start_rx_streaming_t;
typedef struct {
uint8_t opcode;
uint8_t len;
- uint16_t mbz;
-} op_stop_rx_t;
-
-typedef struct {
- uint8_t opcode;
- uint8_t len;
+ uint8_t rid;
u2_mac_addr_t addr;
-} op_burn_mac_addr_t;
+} _AL4 op_burn_mac_addr_t;
typedef struct {
uint8_t opcode;
uint8_t len;
uint8_t rid;
uint8_t mbz;
-} op_read_time_t;
-
-typedef struct {
- uint8_t opcode;
- uint8_t len;
- uint8_t rid;
- uint8_t mbz;
uint32_t time;
-} op_read_time_reply_t;
+} _AL4 op_read_time_reply_t;
/*!
@@ -262,7 +261,7 @@
uint32_t freq_lo; // low 32-bits of 64-bit fxpt_freq (Q44.20)
uint32_t decim; // desired decimation factor (NOT -1)
uint32_t scale_iq; // (scale_i << 16) | scale_q [16.0 format]
-} op_config_rx_v2_t;
+} _AL4 op_config_rx_v2_t;
// bitmask for "valid" field. If the bit is set, there's
// meaningful data in the corresonding field.
@@ -294,7 +293,7 @@
uint32_t residual_freq_hi;
uint32_t residual_freq_lo;
-} op_config_rx_reply_v2_t;
+} _AL4 op_config_rx_reply_v2_t;
/*!
* \brief Configure transmitter
@@ -312,7 +311,7 @@
uint32_t freq_lo; // low 32-bits of 64-bit fxpt_freq (Q44.20)
uint32_t interp; // desired interpolation factor (NOT -1)
uint32_t scale_iq; // (scale_i << 16) | scale_q [16.0 format]
-} op_config_tx_v2_t;
+} _AL4 op_config_tx_v2_t;
/*!
* \brief Reply to configure transmitter
@@ -336,7 +335,7 @@
uint32_t residual_freq_hi;
uint32_t residual_freq_lo;
-} op_config_tx_reply_v2_t;
+} _AL4 op_config_tx_reply_v2_t;
/*!
* \brief Configure MIMO clocking, etc (uses generic reply)
@@ -351,54 +350,22 @@
/*
* ================================================================
- * deprecated subpacket types
- * ================================================================
- */
-
-typedef struct { // Deprecated. Don't use.
- uint8_t opcode;
- uint8_t len;
- uint8_t rx_now; // 1 -> receive now, 0 -> at rx_time
- uint8_t mbz;
- int32_t phase_inc; // 2**32 * desired_freq/100e6
- uint32_t scale_iq; // (scale_i << 16) | scale_q [16.0 format]
- uint32_t decim; // desired decimation factor (NOT -1)
- uint32_t samples_per_frame; // MTU=1500: [9,372]; MTU=2034: [9,506]
- uint32_t total_samples; // [9, 2^21-1] == [9, 2,097,151]
- uint32_t rx_time; // when to begin receiving
-} op_start_rx_t;
-
-typedef struct { // Deprecated. Don't use
- uint8_t opcode;
- uint8_t len;
- uint16_t mbz;
- int32_t phase_inc; // 2**32 * desired_freq/100e6
- uint32_t scale_iq; // (scale_i << 16) | scale_q [16.0 format]
- uint32_t interp; // desired interpolation factor (NOT -1)
-} op_config_tx_t;
-
-/*
- * ================================================================
* union of all of subpacket types
* ================================================================
*/
typedef union {
- op_eop_t op_eop;
- op_id_t op_id;
+
+ op_generic_t op_generic;
op_id_reply_t op_id_reply;
op_start_rx_streaming_t op_start_rx_streaming;
- op_stop_rx_t op_stop_rx;
op_burn_mac_addr_t op_burn_mac_addr;
- op_read_time_t op_read_time;
op_read_time_reply_t op_read_time_reply;
op_config_rx_v2_t op_config_rx_v2;
op_config_rx_reply_v2_t op_config_rx_reply_v2;
op_config_tx_v2_t op_config_tx_v2;
op_config_tx_reply_v2_t op_config_tx_reply_v2;
+ op_config_mimo_t op_config_mimo;
- op_start_rx_t op_start_rx; // deprecated
- op_config_tx_t op_config_tx; // deprecated
-
} u2_subpkt_t;
Modified: usrp2/trunk/firmware/lib/memory_map.h
===================================================================
--- usrp2/trunk/firmware/lib/memory_map.h 2008-08-01 20:25:36 UTC (rev
9141)
+++ usrp2/trunk/firmware/lib/memory_map.h 2008-08-01 20:34:19 UTC (rev
9142)
@@ -367,6 +367,9 @@
// --- dsp tx regs ---
+#define MIN_INTERP 1
+#define MAX_INTERP 128
+
typedef struct {
volatile int32_t freq;
volatile uint32_t scale_iq; // {scale_i,scale_q}
@@ -381,6 +384,9 @@
#define T_NOW (-1)
+#define MIN_DECIM 1
+#define MAX_DECIM 128
+
typedef struct {
volatile int32_t freq;
volatile uint32_t scale_iq; // {scale_i,scale_q}
Copied: usrp2/trunk/firmware/lib/usrp2_bytesex.h (from rev 9140,
usrp2/branches/developers/eb/merge-wip/firmware/lib/usrp2_bytesex.h)
===================================================================
--- usrp2/trunk/firmware/lib/usrp2_bytesex.h (rev 0)
+++ usrp2/trunk/firmware/lib/usrp2_bytesex.h 2008-08-01 20:34:19 UTC (rev
9142)
@@ -0,0 +1,66 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef INCLUDED_USRP2_BYTESEX_H
+#define INCLUDED_USRP2_BYTESEX_H
+
+// The USRP2 speaks big-endian...
+// Use the standard include files or provide substitutions for
+// htons and friends
+
+#if defined(HAVE_ARPA_INET_H)
+#include <arpa/inet.h>
+#elif defined(HAVE_NETINET_IN_H)
+#include <netinet/in.h>
+#else
+#include <stdint.h>
+
+#ifdef WORDS_BIGENDIAN // nothing to do...
+
+static inline uint32_t htonl(uint32_t x){ return x; }
+static inline uint16_t htons(uint16_t x){ return x; }
+static inline uint32_t ntohl(uint32_t x){ return x; }
+static inline uint16_t ntohs(uint16_t x){ return x; }
+
+#else
+
+#ifdef HAVE_BYTESWAP_H
+#include <byteswap.h>
+#else
+
+static inline uint16_t
+bswap_16 (uint16_t x)
+{
+ return ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8));
+}
+
+static inline uint32_t
+bswap_32 (uint32_t x)
+{
+ return ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) \
+ | (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24));
+}
+#endif
+
+static inline uint32_t htonl(uint32_t x){ return bswap_32(x); }
+static inline uint16_t htons(uint16_t x){ return bswap_16(x); }
+static inline uint32_t ntohl(uint32_t x){ return bswap_32(x); }
+static inline uint16_t ntohs(uint16_t x){ return bswap_16(x); }
+
+#endif
+#endif
+#endif /* INCLUDED_USRP2_BYTESEX_H */
Modified: usrp2/trunk/firmware/u2_flash_tool
===================================================================
--- usrp2/trunk/firmware/u2_flash_tool 2008-08-01 20:25:36 UTC (rev 9141)
+++ usrp2/trunk/firmware/u2_flash_tool 2008-08-01 20:34:19 UTC (rev 9142)
@@ -52,6 +52,13 @@
break
return False
+def read_flash(offset, filename, devname):
+ dev = open(devname, "rb")
+ dev.seek(offset, 0) # seek to absolute byte offset
+ dev_data = dev.read(MAX_FILE_SIZE)
+ dev.close()
+ open(filename, "wb").write(dev_data)
+
def main():
parser = OptionParser(usage="%prog: [options] filename")
@@ -59,6 +66,8 @@
help="write FILE to TARGET slot")
parser.add_option("-v", "--verify", action="store_const", const="verify",
dest="mode",
help="verify FILE against TARGET slot")
+ parser.add_option("-r", "--read", action="store_const", const="read",
dest="mode",
+ help="read TARGET slot, write to FILE")
parser.add_option("-t", "--target", type="choice", choices=("fpga",
"s/w"), default="s/w",
help="select TARGET slot from: fpga, s/w
[default=%default]")
parser.add_option("", "--dev", default=None,
@@ -73,7 +82,7 @@
filename = args[0]
if options.mode is None:
- sys.stderr.write("specify mode with -w or -v\n")
+ sys.stderr.write("specify mode with -w, -v or -r\n")
parser.print_help()
raise SystemExit
@@ -87,8 +96,12 @@
if options.mode == "write":
r = (write_flash(offset, filename, options.dev)
and verify_flash(offset, filename, options.dev))
+ elif options.mode == "verify":
+ r = verify_flash(offset, filename, options.dev)
+ elif options.mode == "read":
+ r = read_flash(offset, filename, options.dev)
else:
- r = verify_flash(offset, filename, options.dev)
+ raise NotImplemented
if not r:
raise SystemExit, 1
Deleted: usrp2/trunk/host/apps/find_usrps.cc
Deleted: usrp2/trunk/host/apps/gen_2tone.py
Deleted: usrp2/trunk/host/apps/gen_const.cc
Deleted: usrp2/trunk/host/apps/gen_sine.py
Deleted: usrp2/trunk/host/apps/rx_samples.cc
Deleted: usrp2/trunk/host/apps/stdin_int32_fft.py
Deleted: usrp2/trunk/host/apps/streaming_fft.py
Deleted: usrp2/trunk/host/apps/tx_samples.cc
Deleted: usrp2/trunk/host/apps/u2_burn_mac_addr.cc
Property changes on: usrp2/trunk/host-ng/apps
___________________________________________________________________
Name: svn:ignore
- Makefile
Makefile.in
.libs
.deps
test_eth
test_usrp2
cerr
*.sh
+ Makefile
Makefile.in
.libs
.deps
test_eth
test_usrp2
test2_usrp2
gen_const
find_usrps
cerr
*.sh
tx_samples
Modified: usrp2/trunk/host-ng/apps/Makefile.am
===================================================================
--- usrp2/trunk/host-ng/apps/Makefile.am 2008-08-01 20:25:36 UTC (rev
9141)
+++ usrp2/trunk/host-ng/apps/Makefile.am 2008-08-01 20:34:19 UTC (rev
9142)
@@ -17,16 +17,21 @@
include $(top_srcdir)/Makefile.common
-AM_CPPFLAGS = -Wall -Werror
-INCLUDES = $(STD_DEFINES_AND_INCLUDES) $(CPPUNIT_INCLUDES)
+AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(CPPUNIT_INCLUDES) $(GRUEL_CFLAGS)
LDADD = \
../lib/libusrp2ng.la \
- $(GNURADIO_CORE_LIBS)
+ -lgruel
+bin_PROGRAMS = \
+ find_usrps
+
noinst_PROGRAMS = \
- test_usrp2
+ gen_const \
+ test2_usrp2 \
+ tx_samples
-test_usrp2_SOURCES = \
- test_usrp2.cc
-
+find_usrps = find_usrps.cc
+test2_usrp2_SOURCES = test2_usrp2.cc
+gen_const_SOURCES = gen_const.cc
+tx_samples_SOURCES = tx_samples.cc
Copied: usrp2/trunk/host-ng/apps/find_usrps.cc (from rev 9140,
usrp2/branches/developers/eb/merge-wip/host-ng/apps/find_usrps.cc)
===================================================================
--- usrp2/trunk/host-ng/apps/find_usrps.cc (rev 0)
+++ usrp2/trunk/host-ng/apps/find_usrps.cc 2008-08-01 20:34:19 UTC (rev
9142)
@@ -0,0 +1,70 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007,2008 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <usrp2/usrp2.h>
+#include <iostream>
+#include <getopt.h>
+
+static void
+usage(const char *progname)
+{
+ fprintf(stderr, "usage: %s [-e ethN]\n",
+ progname);
+}
+
+int
+main(int argc, char **argv)
+{
+ int ch;
+ const char *interface = "eth0";
+
+ while ((ch = getopt(argc, argv, "he:")) != EOF){
+ switch (ch){
+ case 'e':
+ interface = optarg;
+ break;
+
+ case 'h':
+ default:
+ usage(argv[0]);
+ exit(1);
+ }
+ }
+
+ if (argc - optind != 0){
+ usage(argv[0]);
+ exit(1);
+ }
+
+ usrp2::props_vector_t r = usrp2::find(interface);
+
+ for (size_t i = 0; i < r.size(); i++){
+ std::cout << r[i] << std::endl;
+ }
+
+ if (r.size() == 0){
+ std::cerr << "No USRP2 found.\n";
+ return 1;
+ }
+
+ return 0;
+}
Copied: usrp2/trunk/host-ng/apps/gen_2tone.py (from rev 9140,
usrp2/branches/developers/eb/merge-wip/host-ng/apps/gen_2tone.py)
===================================================================
--- usrp2/trunk/host-ng/apps/gen_2tone.py (rev 0)
+++ usrp2/trunk/host-ng/apps/gen_2tone.py 2008-08-01 20:34:19 UTC (rev
9142)
@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+#
+# Copyright 2007 Free Software Foundation, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+from gnuradio import gr, eng_notation
+from gnuradio.eng_option import eng_option
+from optparse import OptionParser
+import sys
+
+master_clock = 100e6
+
+class my_top_block(gr.top_block):
+
+ def __init__(self):
+ gr.top_block.__init__(self)
+
+ parser = OptionParser(option_class=eng_option)
+ parser.add_option("-f", "--freq1", type="eng_float", default=1e6,
+ help="set waveform frequency to FREQ
[default=%default]")
+ parser.add_option("-g", "--freq2", type="eng_float", default=1e6,
+ help="set waveform frequency to FREQ
[default=%default]")
+ parser.add_option ("-a", "--amplitude1", type="eng_float",
default=16e3,
+ help="set waveform amplitude to AMPLITUDE
[default=%default]", metavar="AMPL")
+ parser.add_option ("-b", "--amplitude2", type="eng_float",
default=16e3,
+ help="set waveform amplitude to AMPLITUDE
[default=%default]", metavar="AMPL")
+
+ parser.add_option("-i", "--interp", type="int", default=32,
+ help="assume fgpa interpolation rate is INTERP
[default=%default]")
+
+ (options, args) = parser.parse_args ()
+ if len(args) != 0:
+ parser.print_help()
+ raise SystemExit, 1
+
+
+ src0 = gr.sig_source_c(master_clock/options.interp,
+ gr.GR_SIN_WAVE,
+ options.freq1,
+ options.amplitude1)
+ src1 = gr.sig_source_c(master_clock/options.interp,
+ gr.GR_SIN_WAVE,
+ options.freq2,
+ options.amplitude2)
+
+ adder = gr.add_cc()
+
+
+ c2s = gr.complex_to_interleaved_short()
+
+ stdout_sink = gr.file_descriptor_sink(gr.sizeof_short, 1)
+
+ self.connect(src0, (adder,0))
+ self.connect(src1, (adder,1))
+ self.connect(adder, c2s, stdout_sink)
+
+
+if __name__ == '__main__':
+ try:
+ my_top_block().run()
+ except KeyboardInterrupt:
+ pass
Copied: usrp2/trunk/host-ng/apps/gen_const.cc (from rev 9140,
usrp2/branches/developers/eb/merge-wip/host-ng/apps/gen_const.cc)
===================================================================
--- usrp2/trunk/host-ng/apps/gen_const.cc (rev 0)
+++ usrp2/trunk/host-ng/apps/gen_const.cc 2008-08-01 20:34:19 UTC (rev
9142)
@@ -0,0 +1,27 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int
+main(int argc, char **argv)
+{
+ if (argc != 3){
+ fprintf(stderr, "usage: %s i-val q-val\n", argv[0]);
+ return 1;
+ }
+
+ int i_val = strtol(argv[1], 0, 0);
+ int q_val = strtol(argv[2], 0, 0);
+
+ static const int NSAMPLES = 16384;
+
+ uint32_t sample[NSAMPLES];
+ sample[0] = ((i_val & 0xffff) << 16) | (q_val & 0xffff);
+ for (int i = 1; i < NSAMPLES; i++)
+ sample[i] = sample[0];
+
+ while(1){
+ write(1, sample, sizeof(sample));
+ }
+}
Copied: usrp2/trunk/host-ng/apps/gen_sine.py (from rev 9140,
usrp2/branches/developers/eb/merge-wip/host-ng/apps/gen_sine.py)
===================================================================
--- usrp2/trunk/host-ng/apps/gen_sine.py (rev 0)
+++ usrp2/trunk/host-ng/apps/gen_sine.py 2008-08-01 20:34:19 UTC (rev
9142)
@@ -0,0 +1,63 @@
+#!/usr/bin/env python
+#
+# Copyright 2007 Free Software Foundation, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+from gnuradio import gr, eng_notation
+from gnuradio.eng_option import eng_option
+from optparse import OptionParser
+import sys
+
+master_clock = 100e6
+
+class my_top_block(gr.top_block):
+
+ def __init__(self):
+ gr.top_block.__init__(self)
+
+ parser = OptionParser(option_class=eng_option)
+ parser.add_option("-f", "--freq", type="eng_float", default=1e6,
+ help="set waveform frequency to FREQ
[default=%default]")
+ parser.add_option ("-a", "--amplitude", type="eng_float", default=16e3,
+ help="set waveform amplitude to AMPLITUDE
[default=%default]", metavar="AMPL")
+
+ parser.add_option("-i", "--interp", type="int", default=32,
+ help="assume fgpa interpolation rate is INTERP
[default=%default]")
+
+ (options, args) = parser.parse_args ()
+ if len(args) != 0:
+ parser.print_help()
+ raise SystemExit, 1
+
+
+ src0 = gr.sig_source_c(master_clock/options.interp,
+ gr.GR_SIN_WAVE,
+ options.freq,
+ options.amplitude)
+
+
+ c2s = gr.complex_to_interleaved_short()
+
+ stdout_sink = gr.file_descriptor_sink(gr.sizeof_short, 1)
+
+ self.connect(src0, c2s, stdout_sink)
+
+
+if __name__ == '__main__':
+ try:
+ my_top_block().run()
+ except KeyboardInterrupt:
+ pass
Copied: usrp2/trunk/host-ng/apps/rx_samples.cc (from rev 9140,
usrp2/branches/developers/eb/merge-wip/host-ng/apps/rx_samples.cc)
===================================================================
--- usrp2/trunk/host-ng/apps/rx_samples.cc (rev 0)
+++ usrp2/trunk/host-ng/apps/rx_samples.cc 2008-08-01 20:34:19 UTC (rev
9142)
@@ -0,0 +1,382 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "usrp2_basic.h"
+#include <iostream>
+#include <complex>
+#include <getopt.h>
+#include <string.h>
+#include "strtod_si.h"
+#include <signal.h>
+#include <stdexcept>
+#include "gri_if_stats.h"
+#include <gr_realtime.h>
+
+
+typedef std::complex<float> fcomplex;
+
+static volatile bool signaled = false;
+
+static void
+sig_handler(int sig)
+{
+ signaled = true;
+}
+
+static void
+install_sig_handler(int signum,
+ void (*new_handler)(int))
+{
+ struct sigaction new_action;
+ memset (&new_action, 0, sizeof (new_action));
+
+ new_action.sa_handler = new_handler;
+ sigemptyset (&new_action.sa_mask);
+ new_action.sa_flags = 0;
+
+ if (sigaction (signum, &new_action, 0) < 0){
+ perror ("sigaction (install new)");
+ throw std::runtime_error ("sigaction");
+ }
+}
+
+
+/*
+ * Vectorize me!
+ */
+void
+convert_samples_to_complex(size_t nsamples,
+ uint32_t *i_samples,
+ fcomplex *c_samples)
+{
+ uint32_t *p = i_samples;
+ for (size_t i = 0; i < nsamples; i++){
+ int16_t si = ((int16_t) (p[i] >> 16));
+ int16_t sq = ((int16_t) (p[i] & 0xffff));
+ c_samples[i] = fcomplex((float) si, (float) sq);
+ }
+}
+
+
+static void
+usage(const char *progname)
+{
+ const char *p = strrchr(progname, '/'); // drop leading directory path
+ if (p)
+ p++;
+
+ if (strncmp(p, "lt-", 3) == 0) // drop lt- libtool prefix
+ p += 3;
+
+ fprintf(stderr, "Usage: %s [options]\n\n", p);
+ fprintf(stderr, "Options:\n");
+ fprintf(stderr, " -h show this message and exit\n");
+ fprintf(stderr, " -e ETH_INTERFACE specify ethernet interface
[default=eth0]\n");
+ fprintf(stderr, " -m MAC_ADDR mac address of USRP2 HH:HH
[default=first one found]\n");
+ fprintf(stderr, " -o OUTPUT_FILE set output filename
[default=NONE]\n");
+ fprintf(stderr, " -f FREQ set frequency to FREQ
[default=0]\n");
+ fprintf(stderr, " -d DECIM set decimation rate to DECIM
[default=32]\n");
+ fprintf(stderr, " -N NSAMPLES total number of samples to receive
[default=2.5e6]\n");
+ fprintf(stderr, " -F SAMPLES_PER_FRAME number of samples in each frame
[default=371]\n");
+ fprintf(stderr, " -S SCALE fpga scaling factor for I & Q
[default=1024]\n");
+ fprintf(stderr, " -M DONT_LOCK|LOCK_TO_SMA|LOCK_TO_MIMO specify MIMO
clock source\n");
+ fprintf(stderr, " -P provide clock to MIMO connector\n");
+}
+
+struct pkt_info {
+ int d_nsamples;
+ int d_timestamp;
+ unsigned int d_seqno;
+
+ pkt_info(int nsamples, int timestamp, int seqno)
+ : d_nsamples(nsamples),
+ d_timestamp(timestamp),
+ d_seqno(seqno) {}
+};
+
+int
+main(int argc, char **argv)
+{
+
+ // options and their defaults
+ const char *interface = "eth0";
+ const char *mac_addr_str = 0;
+ const char *output_filename = 0;
+ double freq = 0;
+ int32_t decim = 32;
+ int32_t nsamples = static_cast<int32_t>(2.5e6);
+ int32_t samples_per_frame = 371;
+ int32_t scale = 1024;
+ int mimo_config = MC_WE_DONT_LOCK;
+ bool provide_clock = false;
+
+ int ch;
+ double tmp;
+ u2_mac_addr_t mac_addr;
+
+ setvbuf(stdout, 0, _IOFBF, 64 * 1024); // make stdout fully buffered
+
+ while ((ch = getopt(argc, argv, "he:m:o:f:d:N:F:S:M:P")) != EOF){
+ switch (ch){
+
+ case 'e':
+ interface = optarg;
+ break;
+
+ case 'm':
+ mac_addr_str = optarg;
+ if (!usrp2_basic::parse_mac_addr(optarg, &mac_addr)){
+ std::cerr << "invalid mac addr: " << optarg << std::endl;
+ usage(argv[0]);
+ exit(1);
+ }
+ break;
+
+ case 'o':
+ output_filename = optarg;
+ break;
+
+ case 'f':
+ if (!strtod_si(optarg, &freq)){
+ std::cerr << "invalid number: " << optarg << std::endl;
+ usage(argv[0]);
+ exit(1);
+ }
+ break;
+
+ case 'N':
+ if (!strtod_si(optarg, &tmp)){
+ std::cerr << "invalid number: " << optarg << std::endl;
+ usage(argv[0]);
+ exit(1);
+ }
+ nsamples = static_cast<int32_t>(tmp);
+ break;
+
+ case 'F':
+ samples_per_frame = strtol(optarg, 0, 0);
+ break;
+
+ case 'd':
+ decim = strtol(optarg, 0, 0);
+ break;
+
+ case 'S':
+ if (!strtod_si(optarg, &tmp)){
+ std::cerr << "invalid number: " << optarg << std::endl;
+ usage(argv[0]);
+ exit(1);
+ }
+ scale = static_cast<int32_t>(tmp);
+ break;
+
+ case 'M':
+ if (strcmp(optarg, "DONT_LOCK") == 0)
+ mimo_config = MC_WE_DONT_LOCK;
+ else if (strcmp(optarg, "LOCK_TO_SMA") == 0)
+ mimo_config = MC_WE_LOCK_TO_SMA;
+ else if (strcmp(optarg, "LOCK_TO_MIMO") == 0)
+ mimo_config = MC_WE_LOCK_TO_MIMO;
+ else {
+ usage(argv[0]);
+ exit(1);
+ }
+ break;
+
+ case 'P':
+ provide_clock = true;
+ break;
+
+ case 'h':
+ default:
+ usage(argv[0]);
+ exit(1);
+ }
+ }
+
+ if (argc - optind != 0){
+ usage(argv[0]);
+ exit(1);
+ }
+
+ FILE *of = 0;
+ if (output_filename)
+ of = fopen(output_filename, "wb");
+
+ usrp2_basic *u2 = new usrp2_basic();
+
+ if (!u2->open(interface)){
+ std::cerr << "couldn't open " << interface << std::endl;
+ return 0;
+ }
+
+
+ install_sig_handler(SIGINT, sig_handler);
+ if (1){
+ install_sig_handler(SIGALRM, sig_handler);
+ alarm(5);
+ }
+
+
+ std::vector<op_id_reply_t> r = u2->find_usrps();
+
+ for (size_t i = 0; i < r.size(); i++){
+ std::cout << r[i] << std::endl;
+ }
+
+ if (r.size() == 0){
+ std::cerr << "No USRP2 found.\n";
+ return 1;
+ }
+
+ u2_mac_addr_t which = r[0].addr; // pick the first one
+
+
+ gr_rt_status_t rt = gr_enable_realtime_scheduling();
+ if (rt != RT_OK)
+ std::cerr << "failed to enable realtime scheduling\n";
+
+ if (provide_clock)
+ mimo_config |= MC_PROVIDE_CLK_TO_MIMO;
+
+ u2->config_mimo(which, mimo_confg);
+
+
+ gri_if_stats start, stop;
+ gri_get_if_stats(interface, &start);
+
+ if (!u2->start_rx(which, freq, decim, nsamples, samples_per_frame, scale,
scale)){
+ std::cerr << "start_rx failed\n";
+ return 1;
+ }
+
+
+ std::vector<pkt_info> history;
+ history.reserve(64*1024); // preallocate 64K entries
+
+
+ long total_samples_recvd = 0;
+
+ while (!signaled && total_samples_recvd < nsamples){
+ u2_eth_samples_t pkt;
+ // fcomplex c_samples[U2_MAX_SAMPLES];
+
+ // read samples
+ int n = u2->read_samples(which, &pkt);
+ if (n <= 0)
+ break;
+
+ total_samples_recvd += n;
+
+ history.push_back(pkt_info(n, u2p_timestamp(&pkt.hdrs.fixed),
pkt.hdrs.thdr.seqno));
+
+ // convert_samples_to_complex(n, pkt.samples, c_samples);
+ // size_t r = fwrite(c_samples, sizeof(fcomplex), n, of);
+
+ if (of){
+ fwrite(pkt.samples, sizeof(uint32_t), n, of);
+ fflush(of);
+ }
+ }
+
+
+ gri_get_if_stats(interface, &stop);
+
+ if (!u2->stop_rx(which)){
+ std::cerr << "stop_rx failed\n";
+ return 1;
+ }
+
+
+ long expected_rx_packets =
+ (nsamples + samples_per_frame - 1)/samples_per_frame;
+
+ long expected_rx_bytes =
+ expected_rx_packets * sizeof(u2_eth_packet_t) + nsamples * 4;
+
+
+ long total_pkts_recvd = 0;
+ total_samples_recvd = 0;
+
+ int nbad_seqno = 0;
+
+ for (unsigned i = 0; i < history.size(); i++){
+ total_pkts_recvd++;
+ total_samples_recvd += history[i].d_nsamples;
+
+ bool bad_seqno = history[i].d_seqno != (i & 0xff);
+ if (bad_seqno)
+ nbad_seqno++;
+
+ printf("%3d %8d %8ld %8ld %3d %s\n",
+ history[i].d_nsamples,
+ history[i].d_timestamp,
+ total_pkts_recvd, total_samples_recvd,
+ history[i].d_seqno,
+ bad_seqno ? "BAD SEQNO" : ""
+ );
+ }
+
+ if (nbad_seqno == 0)
+ printf("\nAll sequence numbers are correct\n");
+ else
+ printf("\n%d sequence numbers were INCORRECT\n", nbad_seqno);
+
+
+ printf("\nUser space statistics:\n");
+ printf(" rx_samples: %8ld", total_samples_recvd);
+ printf(" expected %8d %s\n",
+ nsamples,
+ nsamples - total_samples_recvd == 0 ? "OK" : "NOT OK");
+
+ printf(" rx_packets: %8ld", total_pkts_recvd);
+ printf(" expected %8ld %s\n",
+ expected_rx_packets,
+ expected_rx_packets - total_pkts_recvd == 0 ? "OK" : "NOT OK");
+
+
+ fflush(stdout);
+
+ printf("\nKernel interface statistics:\n");
+
+ long long delta;
+ delta = stop.rx_bytes - start.rx_bytes;
+ printf(" rx_bytes: %8Ld", delta);
+ printf(" expected %8ld %s\n",
+ expected_rx_bytes,
+ expected_rx_bytes - delta == 0 ? "OK" : "NOT OK");
+
+ delta = stop.rx_packets - start.rx_packets;
+ printf(" rx_packets: %8Ld", delta);
+ printf(" expected %8ld %s\n",
+ expected_rx_packets,
+ expected_rx_packets - delta == 0 ? "OK" : "NOT OK");
+
+ printf(" rx_errs: %8Ld\n", stop.rx_errs - start.rx_errs);
+ printf(" rx_drop: %8Ld\n", stop.rx_drop - start.rx_drop);
+ printf(" tx_bytes: %8Ld\n", stop.tx_bytes - start.tx_bytes);
+ printf(" tx_packets: %8Ld\n", stop.tx_packets - start.tx_packets);
+ printf(" tx_errs: %8Ld\n", stop.tx_errs - start.tx_errs);
+ printf(" tx_drop: %8Ld\n", stop.tx_drop - start.tx_drop);
+
+
+ return 0;
+}
Copied: usrp2/trunk/host-ng/apps/stdin_int32_fft.py (from rev 9140,
usrp2/branches/developers/eb/merge-wip/host-ng/apps/stdin_int32_fft.py)
===================================================================
--- usrp2/trunk/host-ng/apps/stdin_int32_fft.py (rev 0)
+++ usrp2/trunk/host-ng/apps/stdin_int32_fft.py 2008-08-01 20:34:19 UTC (rev
9142)
@@ -0,0 +1,201 @@
+#!/usr/bin/env python
+#
+# Copyright 2004,2005,2007,2008 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+from gnuradio import gr, gru
+from gnuradio import eng_notation
+from gnuradio.eng_option import eng_option
+from gnuradio.wxgui import stdgui2, fftsink2, waterfallsink2, scopesink2,
form, slider
+from optparse import OptionParser
+import wx
+import sys
+import numpy
+
+
+class app_top_block(stdgui2.std_top_block):
+ def __init__(self, frame, panel, vbox, argv):
+ stdgui2.std_top_block.__init__(self, frame, panel, vbox, argv)
+
+ self.frame = frame
+ self.panel = panel
+
+ parser = OptionParser(option_class=eng_option)
+ parser.add_option("-d", "--decim", type="int", default=16,
+ help="set fgpa decimation rate to DECIM
[default=%default]")
+ parser.add_option("-f", "--freq", type="eng_float", default=None,
+ help="set frequency to FREQ", metavar="FREQ")
+ parser.add_option("-W", "--waterfall", action="store_true",
default=False,
+ help="Enable waterfall display")
+ parser.add_option("-S", "--oscilloscope", action="store_true",
default=False,
+ help="Enable oscilloscope display")
+ (options, args) = parser.parse_args()
+ if len(args) != 0:
+ parser.print_help()
+ sys.exit(1)
+ self.options = options
+ self.options.gain = 1.0
+ self.show_debug_info = True
+
+
+ input_rate = 100e6 / options.decim
+
+ self.src = gr.file_descriptor_source(gr.sizeof_short, 0, False);
+ self.s2c = gr.interleaved_short_to_complex()
+
+ if options.waterfall:
+ self.scope = \
+ waterfallsink2.waterfall_sink_c (panel, fft_size=1024,
sample_rate=input_rate)
+ elif options.oscilloscope:
+ self.scope = scopesink2.scope_sink_c(panel, sample_rate=input_rate)
+ else:
+ self.scope = fftsink2.fft_sink_c (panel, fft_size=1024, y_divs=12,
sample_rate=input_rate,ref_level=110,fft_rate=20)
+
+ self.connect(self.src, self.s2c, self.scope)
+
+ self._build_gui(vbox)
+ self._setup_events()
+
+ # set initial values
+
+ if options.freq is None:
+ # if no freq was specified, use the mid-point
+ options.freq = 0.0
+
+ if self.show_debug_info:
+ self.myform['decim'].set_value(self.options.decim)
+
+
+ def _set_status_msg(self, msg):
+ self.frame.GetStatusBar().SetStatusText(msg, 0)
+
+ def _build_gui(self, vbox):
+
+ def _form_set_freq(kv):
+ return self.set_freq(kv['freq'])
+
+ vbox.Add(self.scope.win, 10, wx.EXPAND)
+
+ # add control area at the bottom
+ self.myform = myform = form.form()
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ hbox.Add((5,0), 0, 0)
+ myform['freq'] = form.float_field(
+ parent=self.panel, sizer=hbox, label="Center freq", weight=1,
+ callback=myform.check_input_and_call(_form_set_freq,
self._set_status_msg))
+
+ hbox.Add((5,0), 0, 0)
+ vbox.Add(hbox, 0, wx.EXPAND)
+
+ self._build_subpanel(vbox)
+
+ def _build_subpanel(self, vbox_arg):
+ # build a secondary information panel (sometimes hidden)
+
+ # FIXME figure out how to have this be a subpanel that is always
+ # created, but has its visibility controlled by foo.Show(True/False)
+
+ def _form_set_decim(kv):
+ return self.set_decim(kv['decim'])
+
+ if not(self.show_debug_info):
+ return
+
+ panel = self.panel
+ vbox = vbox_arg
+ myform = self.myform
+
+ #panel = wx.Panel(self.panel, -1)
+ #vbox = wx.BoxSizer(wx.VERTICAL)
+
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ hbox.Add((5,0), 0)
+
+ myform['decim'] = form.int_field(
+ parent=panel, sizer=hbox, label="Decim",
+ callback=myform.check_input_and_call(_form_set_decim,
self._set_status_msg))
+
+ hbox.Add((5,0), 0)
+ vbox.Add(hbox, 0, wx.EXPAND)
+
+
+ def set_freq(self, target_freq):
+ """
+ Set the center frequency we're interested in.
+
+ @param target_freq: frequency in Hz
+ @rypte: bool
+
+ Tuning is a two step process. First we ask the front-end to
+ tune as close to the desired frequency as it can. Then we use
+ the result of that operation and our target_frequency to
+ determine the value for the digital down converter.
+ """
+
+ if True:
+ self.myform['freq'].set_value(target_freq) # update displayed
value
+ if not self.options.waterfall and not self.options.oscilloscope:
+ self.scope.win.set_baseband_freq(target_freq)
+ return True
+
+ return False
+
+ def set_gain(self, gain):
+ self.myform['gain'].set_value(gain) # update displayed value
+
+ def set_decim(self, decim):
+ input_rate = 100e6 / self.options.decim
+ self.scope.set_sample_rate(input_rate)
+ if self.show_debug_info: # update displayed values
+ self.myform['decim'].set_value(self.u.decim_rate())
+ return ok
+
+ def _setup_events(self):
+ if not self.options.waterfall and not self.options.oscilloscope:
+ self.scope.win.Bind(wx.EVT_LEFT_DCLICK, self.evt_left_dclick)
+
+ def evt_left_dclick(self, event):
+ (ux, uy) = self.scope.win.GetXY(event)
+ if event.CmdDown():
+ # Re-center on maximum power
+ points = self.scope.win._points
+ if self.scope.win.peak_hold:
+ if self.scope.win.peak_vals is not None:
+ ind = numpy.argmax(self.scope.win.peak_vals)
+ else:
+ ind = int(points.shape()[0]/2)
+ else:
+ ind = numpy.argmax(points[:,1])
+ (freq, pwr) = points[ind]
+ target_freq = freq/self.scope.win._scale_factor
+ print ind, freq, pwr
+ self.set_freq(target_freq)
+ else:
+ # Re-center on clicked frequency
+ target_freq = ux/self.scope.win._scale_factor
+ self.set_freq(target_freq)
+
+
+def main ():
+ app = stdgui2.stdapp(app_top_block, "USRP FFT", nstatus=1)
+ app.MainLoop()
+
+if __name__ == '__main__':
+ main ()
Copied: usrp2/trunk/host-ng/apps/streaming_fft.py (from rev 9140,
usrp2/branches/developers/eb/merge-wip/host-ng/apps/streaming_fft.py)
===================================================================
--- usrp2/trunk/host-ng/apps/streaming_fft.py (rev 0)
+++ usrp2/trunk/host-ng/apps/streaming_fft.py 2008-08-01 20:34:19 UTC (rev
9142)
@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+#
+# Copyright 2008 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+
+import os
+import os.path
+import sys
+from gnuradio.eng_option import eng_option
+from optparse import OptionParser
+
+def main():
+ parser = OptionParser(option_class=eng_option)
+ parser.add_option("-d", "--decim", type="int", default=16,
+ help="set fgpa decimation rate to DECIM
[default=%default]")
+ parser.add_option("-f", "--freq", type="eng_float", default=0.0,
+ help="set frequency to FREQ", metavar="FREQ")
+ parser.add_option("-g", "--gain", type="string", default=None,
+ help="set gain to GAIN [default=%default]")
+ parser.add_option("-W", "--waterfall", action="store_true", default=False,
+ help="Enable waterfall display")
+ parser.add_option("-S", "--oscilloscope", action="store_true",
default=False,
+ help="Enable oscilloscope display")
+ parser.add_option("-F", "--samples-per-frame", type="int", default=250,
+ help="[default=%default]")
+ parser.add_option("-e", "--eth", default="eth0",
+ help="specify ethernet interface [default=%default]")
+
+ (options, args) = parser.parse_args()
+ if len(args) != 0:
+ parser.print_help()
+ sys.exit(1)
+
+
+ path = os.path.dirname(sys.argv[0])
+ if path == '':
+ path = '.'
+
+
+ display_type = ''
+ if options.waterfall:
+ display_type = '-W'
+ if options.oscilloscope:
+ display_type = '-S'
+
+ gain_clause = ''
+ if options.gain:
+ gain_clause = '-g ' + options.gain
+
+ cmd = "sudo %s/rx_streaming_samples -e %s -f %g -d %d -F %d %s -o
/proc/self/fd/1 | %s/stdin_int32_fft.py %s -f %g -d %d" % (
+ path, options.eth, options.freq, options.decim,
options.samples_per_frame, gain_clause,
+ path, display_type, options.freq, options.decim)
+
+ print cmd
+ os.system(cmd)
+
+
+if __name__ == '__main__':
+ main()
Modified: usrp2/trunk/host-ng/apps/test.sh
===================================================================
--- usrp2/trunk/host-ng/apps/test.sh 2008-08-01 20:25:36 UTC (rev 9141)
+++ usrp2/trunk/host-ng/apps/test.sh 2008-08-01 20:34:19 UTC (rev 9142)
@@ -1,5 +1,5 @@
#!/bin/sh
-sudo ./test_usrp2 1>cerr 2>&1
+sudo ./test_usrp2 -d 4
Copied: usrp2/trunk/host-ng/apps/test2_usrp2.cc (from rev 9140,
usrp2/branches/developers/eb/merge-wip/host-ng/apps/test2_usrp2.cc)
===================================================================
--- usrp2/trunk/host-ng/apps/test2_usrp2.cc (rev 0)
+++ usrp2/trunk/host-ng/apps/test2_usrp2.cc 2008-08-01 20:34:19 UTC (rev
9142)
@@ -0,0 +1,378 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007,2008 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <usrp2/usrp2.h>
+#include <usrp2/strtod_si.h>
+#include <usrp2/copiers.h>
+#include <gruel/realtime.h>
+#include <sys/time.h>
+#include <iostream>
+#include <string.h>
+#include <boost/scoped_ptr.hpp>
+#include <boost/shared_ptr.hpp>
+#include <stdexcept>
+
+// ------------------------------------------------------------------------
+
+class rx_nop_handler : public usrp2::rx_sample_handler
+{
+ size_t d_max_samples;
+ size_t d_nsamples;
+ size_t d_nframes;
+
+public:
+
+ rx_nop_handler(size_t max_samples)
+ : d_max_samples(max_samples), d_nsamples(0), d_nframes(0) {}
+
+ ~rx_nop_handler();
+
+ size_t nframes() const { return d_nframes; }
+ size_t nsamples() const { return d_nsamples; }
+ size_t max_samples() const { return d_max_samples; }
+
+ bool
+ operator()(const uint32_t *items, size_t nitems, const usrp2::rx_metadata
*metadata)
+ {
+ // printf("W0: %08x TS: %08x\n", metadata->word0, metadata->timestamp);
+ // printf("I0: %08x\n", items[0]);
+
+ d_nsamples += nitems;
+ d_nframes++;
+
+ return d_nsamples < d_max_samples;
+ }
+};
+
+rx_nop_handler::~rx_nop_handler()
+{
+ // nop
+}
+
+// ------------------------------------------------------------------------
+
+// FIXME make this a template
+
+class complex_16_file_writer : public rx_nop_handler
+{
+ FILE *d_fp;
+ std::string d_filename;
+
+public:
+
+ complex_16_file_writer(const std::string &filename, size_t max_samples)
+ : rx_nop_handler(max_samples), d_filename(filename)
+ {
+ d_fp = fopen(filename.c_str(), "wb");
+ if (d_fp == 0){
+ perror(filename.c_str());
+ throw std::invalid_argument(filename);
+ }
+ }
+
+ ~complex_16_file_writer();
+
+ bool
+ operator()(const uint32_t *items, size_t nitems, const usrp2::rx_metadata
*metadata)
+ {
+ bool ok = rx_nop_handler::operator()(items, nitems, metadata);
+
+ size_t host_nitems = nitems;
+ std::complex<int16_t> host_items[host_nitems];
+
+ usrp2::copy_u2_complex_16_to_host_complex_16(nitems, items, host_items);
+
+ size_t n = 0;
+ while (n < host_nitems){
+ size_t r = fwrite(&host_items[n], sizeof(host_items[0]), host_nitems -
n, d_fp);
+ n += r;
+ if (r == 0){ // out of space?
+ perror(d_filename.c_str());
+ ok = false;
+ break;
+ }
+ }
+
+ return ok;
+ }
+};
+
+complex_16_file_writer::~complex_16_file_writer()
+{
+ fclose(d_fp);
+}
+
+// ------------------------------------------------------------------------
+
+class complex_float_file_writer : public rx_nop_handler
+{
+ FILE *d_fp;
+ std::string d_filename;
+
+public:
+
+ complex_float_file_writer(const std::string &filename, size_t max_samples)
+ : rx_nop_handler(max_samples), d_filename(filename)
+ {
+ d_fp = fopen(filename.c_str(), "wb");
+ if (d_fp == 0){
+ perror(filename.c_str());
+ throw std::invalid_argument(filename);
+ }
+ }
+
+ ~complex_float_file_writer();
+
+ bool
+ operator()(const uint32_t *items, size_t nitems, const usrp2::rx_metadata
*metadata)
+ {
+ bool ok = rx_nop_handler::operator()(items, nitems, metadata);
+
+ size_t host_nitems = nitems;
+ std::complex<float> host_items[host_nitems];
+
+ usrp2::copy_u2_complex_16_to_host_complex_float(nitems, items, host_items);
+
+ size_t n = 0;
+ while (n < host_nitems){
+ size_t r = fwrite(&host_items[n], sizeof(host_items[0]), host_nitems -
n, d_fp);
+ n += r;
+ if (r == 0){ // out of space?
+ perror(d_filename.c_str());
+ ok = false;
+ break;
+ }
+ }
+
+ return ok;
+ }
+};
+
+complex_float_file_writer::~complex_float_file_writer()
+{
+ fclose(d_fp);
+}
+
+// ------------------------------------------------------------------------
+
+
+
+
+static void
+usage(const char *progname)
+{
+ const char *p = strrchr(progname, '/'); // drop leading directory path
+ if (p)
+ p++;
+
+ if (strncmp(p, "lt-", 3) == 0) // drop lt- libtool prefix
+ p += 3;
+
+ fprintf(stderr, "Usage: %s [options]\n\n", p);
+ fprintf(stderr, "Options:\n");
+ fprintf(stderr, " -h show this message and exit\n");
+ fprintf(stderr, " -e ETH_INTERFACE specify ethernet interface
[default=eth0]\n");
+ fprintf(stderr, " -m MAC_ADDR mac address of USRP2 HH:HH
[default=first one found]\n");
+ fprintf(stderr, " -f FREQUENCY specify receive center frequency in
Hz [default=0.0]\n");
+ fprintf(stderr, " -d DECIM specify receive decimation rate
[default=5]\n");
+ fprintf(stderr, " -g GAIN specify receive daughterboard gain
[default=0]\n");
+ fprintf(stderr, " -N NSAMPLES specify number of samples to receive
[default=250e6]\n");
+//fprintf(stderr, " -b BUFSIZE specify size of receive buffer
[default=64k]\n");
+ fprintf(stderr, " -o OUTPUT_FILENAME specify file to receive samples
[default=none]\n");
+ fprintf(stderr, " -s write complex<short>
[default=complex<float>]\n");
+}
+
+int
+main(int argc, char **argv)
+{
+ // options and their defaults
+ const char *interface = "eth0";
+ const char *mac_addr_str = "";
+ double rx_freq = 0.0;
+ int rx_decim = 5;
+ double rx_gain = 0.0;
+ size_t nsamples = static_cast<size_t>(250e6);
+ bool output_shorts = false;
+ char *output_filename = 0;
+
+ int ch;
+
+ while ((ch = getopt(argc, argv, "he:m:f:d:g:N:o:s")) != EOF){
+ double tmp;
+ switch (ch){
+
+ case 'e':
+ interface = optarg;
+ break;
+
+ case 'm':
+ mac_addr_str = optarg;
+ break;
+
+ case 'f':
+ if (!strtod_si(optarg, &rx_freq)) {
+ std::cerr << "invalid number: " << optarg << std::endl;
+ usage(argv[0]);
+ exit(1);
+ }
+ break;
+
+ case 'g':
+ if (!strtod_si(optarg, &rx_gain)) {
+ std::cerr << "invalid number: " << optarg << std::endl;
+ usage(argv[0]);
+ exit(1);
+ }
+ break;
+
+ case 'd':
+ rx_decim = strtol(optarg, 0, 0);
+ if (rx_decim < 4 or rx_decim > 512) {
+ std::cerr << "invalid decimation rate: " << optarg << std::endl;
+ usage(argv[0]);
+ exit(1);
+ }
+ break;
+
+ case 'N':
+ if (!strtod_si(optarg, &tmp)) {
+ std::cerr << "invalid number: " << optarg << std::endl;
+ usage(argv[0]);
+ exit(1);
+ }
+ nsamples = static_cast<size_t>(tmp);
+ break;
+
+#if 0
+ case 'b':
+ if (!strtod_si(optarg, &tmp)) {
+ std::cerr << "invalid number: " << optarg << std::endl;
+ usage(argv[0]);
+ exit(1);
+ }
+ bufsize = static_cast<size_t>(tmp);
+ break;
+#endif
+
+ case 's':
+ output_shorts = true;
+ break;
+
+ case 'o':
+ output_filename = optarg;
+ break;
+
+ case 'h':
+ default:
+ usage(argv[0]);
+ exit(1);
+ }
+ }
+
+
+ typedef boost::shared_ptr<rx_nop_handler> handler_sptr;
+ handler_sptr handler;
+
+ if (output_filename){
+ if (output_shorts)
+ handler = handler_sptr(new complex_16_file_writer(output_filename,
nsamples));
+ else
+ handler = handler_sptr(new complex_float_file_writer(output_filename,
nsamples));
+ }
+ else
+ handler = handler_sptr(new rx_nop_handler(nsamples));
+
+
+ gruel::rt_status_t rt = gruel::enable_realtime_scheduling();
+ if (rt != gruel::RT_OK)
+ std::cerr << "Failed to enable realtime scheduling" << std::endl;
+
+ usrp2::usrp2::sptr u2 = usrp2::usrp2::make(interface, mac_addr_str);
+
+ // FIXME in case it was left running...
+ if (!u2->stop_rx_streaming()){
+ fprintf(stderr, "stop_rx_streaming failed\n");
+ }
+
+ if (!u2->set_rx_gain(rx_gain)){
+ fprintf(stderr, "set_rx_gain(%f) failed\n", rx_gain);
+ exit(1);
+ }
+
+ usrp2::tune_result tr;
+ if (!u2->set_rx_center_freq(rx_freq, &tr)){
+ fprintf(stderr, "set_rx_center_freq(%g) failed\n", rx_freq);
+ exit(1);
+ }
+
+ printf("Daughterboard configuration:\n");
+ printf(" baseband_freq=%f\n", tr.baseband_freq);
+ printf(" ddc_freq=%f\n", tr.dxc_freq);
+ printf(" residual_freq=%f\n", tr.residual_freq);
+ printf(" inverted=%s\n\n", tr.spectrum_inverted ? "yes" : "no");
+
+ if (!u2->set_rx_decim(rx_decim)) {
+ fprintf(stderr, "set_rx_decim(%d) failed\n", rx_decim);
+ exit(1);
+ }
+
+ printf("USRP2 using decimation rate of %d\n", rx_decim);
+
+ if (!u2->start_rx_streaming(0)){
+ fprintf(stderr, "start_rx_streaming failed\n");
+ exit(1);
+ }
+
+ printf("Receiving %zd samples\n\n", nsamples);
+
+ struct timeval start, end;
+ gettimeofday(&start, 0);
+
+
+ while(handler->nsamples() < handler->max_samples()){
+ bool ok = u2->rx_samples(0, handler.get());
+ if (!ok){
+ fprintf(stderr, "u2->rx_samples failed\n");
+ return 1;
+ }
+ }
+
+
+ gettimeofday(&end, 0);
+ long n_usecs = end.tv_usec-start.tv_usec;
+ long n_secs = end.tv_sec-start.tv_sec;
+ double elapsed = (double)n_secs + (double)n_usecs*1e-6;
+ double mbs = handler->nsamples()*sizeof(uint32_t)/elapsed/1e6;
+ double pps = handler->nframes()/elapsed;
+
+ u2->stop_rx_streaming();
+
+ printf("\nCopy handler called %zd times.\n", handler->nframes());
+ printf("Copy handler called with %zd bytes.\n\n",
handler->nsamples()*sizeof(uint32_t));
+ printf("Elapsed time was %5.3f seconds.\n", elapsed);
+ printf("Packet rate was %1.0f pkts/sec.\n", pps);
+ printf("Approximate throughput was %5.2f MB/sec.\n", mbs);
+ printf("Total instances of overruns was %d.\n", u2->rx_overruns());
+ printf("Total missing frames was %d.\n", u2->rx_missing());
+
+ return 0;
+}
Modified: usrp2/trunk/host-ng/apps/test_usrp2.cc
===================================================================
--- usrp2/trunk/host-ng/apps/test_usrp2.cc 2008-08-01 20:25:36 UTC (rev
9141)
+++ usrp2/trunk/host-ng/apps/test_usrp2.cc 2008-08-01 20:34:19 UTC (rev
9142)
@@ -21,9 +21,14 @@
#endif
#include <usrp2/usrp2.h>
-#include <gr_realtime.h>
+#include <usrp2/tune_result.h>
+#include <usrp2/strtod_si.h>
+#include <usrp2/copy_handler.h>
+#include <gruel/realtime.h>
+#include <sys/time.h>
#include <iostream>
#include <string.h>
+#include <boost/scoped_ptr.hpp>
static void
usage(const char *progname)
@@ -40,6 +45,11 @@
fprintf(stderr, " -h show this message and exit\n");
fprintf(stderr, " -e ETH_INTERFACE specify ethernet interface
[default=eth0]\n");
fprintf(stderr, " -m MAC_ADDR mac address of USRP2 HH:HH
[default=first one found]\n");
+ fprintf(stderr, " -f FREQUENCY specify receive center frequency in
Hz [default=0.0]\n");
+ fprintf(stderr, " -d DECIM specify receive decimation rate
[default=5]\n");
+ fprintf(stderr, " -g GAIN specify receive daughterboard gain
[default=0]\n");
+ fprintf(stderr, " -n SAMPLES specify number of samples to receive
[default=250e6]\n");
+ fprintf(stderr, " -b BUFSIZE specify size of receive buffer
[default=64k]\n");
}
int
@@ -48,10 +58,15 @@
// options and their defaults
const char *interface = "eth0";
const char *mac_addr_str = "";
-
+ double rx_freq = 0.0;
+ int rx_decim = 5;
+ double rx_gain = 0.0;
+ double samples = 250e6;
+ double bufsize = 65536;
+
int ch;
- while ((ch = getopt(argc, argv, "he:m:")) != EOF){
+ while ((ch = getopt(argc, argv, "he:m:f:d:g:n:b:")) != EOF){
switch (ch){
case 'e':
@@ -62,32 +77,144 @@
mac_addr_str = optarg;
break;
+ case 'f':
+ if (!strtod_si(optarg, &rx_freq)) {
+ std::cerr << "invalid number: " << optarg << std::endl;
+ usage(argv[0]);
+ exit(1);
+ }
+ break;
+
+ case 'g':
+ if (!strtod_si(optarg, &rx_gain)) {
+ std::cerr << "invalid number: " << optarg << std::endl;
+ usage(argv[0]);
+ exit(1);
+ }
+ break;
+
+ case 'd':
+ rx_decim = strtol(optarg, 0, 0);
+ if (rx_decim < 4 or rx_decim > 512) {
+ std::cerr << "invalid decimation rate: " << optarg << std::endl;
+ usage(argv[0]);
+ exit(1);
+ }
+ break;
+
+ case 'n':
+ if (!strtod_si(optarg, &samples)) {
+ std::cerr << "invalid number: " << optarg << std::endl;
+ usage(argv[0]);
+ exit(1);
+ }
+ break;
+
+ case 'b':
+ if (!strtod_si(optarg, &bufsize)) {
+ std::cerr << "invalid number: " << optarg << std::endl;
+ usage(argv[0]);
+ exit(1);
+ }
+ break;
+
case 'h':
default:
usage(argv[0]);
exit(1);
}
}
-
- gr_rt_status_t rt = gr_enable_realtime_scheduling();
- if (rt != RT_OK)
+
+ gruel::rt_status_t rt = gruel::enable_realtime_scheduling();
+ if (rt != gruel::RT_OK)
std::cerr << "Failed to enable realtime scheduling" << std::endl;
usrp2::usrp2::sptr u2 = usrp2::usrp2::make(interface, mac_addr_str);
- u2->set_rx_gain(1.0);
- u2->set_rx_freq(0.0, NULL);
- u2->set_rx_decim(5);
- //u2->start_rx_streaming();
+ // FIXME in case it was left running...
+ if (!u2->stop_rx_streaming()){
+ fprintf(stderr, "stop_rx_streaming failed\n");
+ }
+
+ if (!u2->set_rx_gain(rx_gain)){
+ fprintf(stderr, "set_rx_gain(%f) failed\n", rx_gain);
+ exit(1);
+ }
+
+ usrp2::tune_result tr;
+ if (!u2->set_rx_center_freq(rx_freq, &tr)){
+ fprintf(stderr, "set_rx_center_freq(%g) failed\n", rx_freq);
+ exit(1);
+ }
+
+ printf("Daughterboard configuration:\n");
+ printf(" baseband_freq=%f\n", tr.baseband_freq);
+ printf(" ddc_freq=%f\n", tr.dxc_freq);
+ printf(" residual_freq=%f\n", tr.residual_freq);
+ printf(" inverted=%s\n\n", tr.spectrum_inverted ? "yes" : "no");
- struct timespec ts;
- ts.tv_sec = 10;
- ts.tv_nsec = 0;
- int r = nanosleep(&ts, 0);
- if (r == -1)
- perror("nanosleep");
+ if (!u2->set_rx_decim(rx_decim)) {
+ fprintf(stderr, "set_rx_decim(%d) failed\n", rx_decim);
+ exit(1);
+ }
+
+ printf("USRP2 using decimation rate of %d\n", rx_decim);
+
+ if (!u2->start_rx_streaming()){
+ fprintf(stderr, "start_rx_streaming failed\n");
+ exit(1);
+ }
+
+ size_t nsamples = static_cast<size_t>(samples);
+ size_t buflen = static_cast<size_t>(bufsize);
+ boost::scoped_ptr<unsigned char> buf(new unsigned char[buflen]);
+
+ printf("Receiving %li samples into buffer of length %li bytes.\n\n",
nsamples, buflen);
- //u2->stop_rx_streaming();
+ struct timeval start, end;
+ gettimeofday(&start, 0);
+
+ printf("Each '.' is 100 packets:\n");
+
+ unsigned long bytes = 0;
+ unsigned long times = 0;
+
+ do {
+ usrp2::copy_handler h(buf.get(), buflen);
+ bool ok;
+ unsigned int n = 0;
+ do {
+ ok = u2->rx_samples(0, &h);
+ if (h.times() > n) {
+ printf("."); fflush(stdout);
+ n = n+100;
+ }
+ }
+ while (ok && !h.full() && (bytes+h.bytes()) <= nsamples*4);
+ if (!ok)
+ break;
+
+ bytes += h.bytes();
+ times += h.times();
+ }
+ while (bytes <= nsamples*4); // FIXME will vary by sample format
+
+ gettimeofday(&end, 0);
+ long n_usecs = end.tv_usec-start.tv_usec;
+ long n_secs = end.tv_sec-start.tv_sec;
+ double elapsed = (double)n_secs + (double)n_usecs*1e-6;
+ double mbs = bytes/elapsed/1e6;
+ double pps = times/elapsed;
+ u2->stop_rx_streaming();
+
+ printf("\nCopy handler called %li times.\n", times);
+ printf("Copy handler called with %li bytes.\n\n", bytes);
+ printf("Elapsed time was %5.3f seconds.\n", elapsed);
+ printf("Packet rate was %1.0f pkts/sec.\n", pps);
+ printf("Approximate throughput was %5.2f MB/sec.\n", mbs);
+ printf("Total instances of overruns was %d.\n", u2->rx_overruns());
+ printf("Total missing frames was %d.\n", u2->rx_missing());
+
return 0;
}
Copied: usrp2/trunk/host-ng/apps/tx_samples.cc (from rev 9140,
usrp2/branches/developers/eb/merge-wip/host-ng/apps/tx_samples.cc)
===================================================================
--- usrp2/trunk/host-ng/apps/tx_samples.cc (rev 0)
+++ usrp2/trunk/host-ng/apps/tx_samples.cc 2008-08-01 20:34:19 UTC (rev
9142)
@@ -0,0 +1,231 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007,2008 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <usrp2/usrp2.h>
+#include <usrp2/strtod_si.h>
+#include <iostream>
+#include <complex>
+#include <getopt.h>
+#include <gruel/realtime.h>
+
+typedef std::complex<float> fcomplex;
+
+static const char *
+prettify_progname(const char *progname) // that's probably
almost a word ;)
+{
+ const char *p = strrchr(progname, '/'); // drop leading directory path
+ if (p)
+ p++;
+
+ if (strncmp(p, "lt-", 3) == 0) // drop lt- libtool prefix
+ p += 3;
+
+ return p;
+}
+
+static void
+usage(const char *progname)
+{
+ fprintf(stderr, "Usage: %s [options]\n\n", prettify_progname(progname));
+ fprintf(stderr, "Options:\n");
+ fprintf(stderr, " -h show this message and exit\n");
+ fprintf(stderr, " -e ETH_INTERFACE specify ethernet interface
[default=eth0]\n");
+ fprintf(stderr, " -m MAC_ADDR mac address of USRP2 HH:HH
[default=first one found]\n");
+ fprintf(stderr, " -I INPUT_FILE set input filename
[default=stdin]\n");
+ fprintf(stderr, " -r repeat. When EOF of input file is
reached, seek to beginning\n");
+ fprintf(stderr, " -f FREQ set frequency to FREQ
[default=0]\n");
+ fprintf(stderr, " -i INTERP set interpolation rate to INTERP
[default=32]\n");
+ fprintf(stderr, " -g gain set tx gain\n");
+ fprintf(stderr, " -S SCALE fpga scaling factor for I & Q
[default=256]\n");
+}
+
+#define GAIN_NOT_SET (-1000)
+#define MAX_SAMPLES (371)
+
+int
+main(int argc, char **argv)
+{
+ const char *interface = "eth0";
+ const char *input_filename = 0;
+ bool repeat = false;
+ const char *mac_addr_str = "";
+ double freq = 0;
+ int32_t interp = 32;
+ int32_t samples_per_frame = MAX_SAMPLES;
+ int32_t scale = 3000;
+ double gain = GAIN_NOT_SET;
+
+ int ch;
+ double tmp;
+
+
+ while ((ch = getopt(argc, argv, "he:m:I:rf:i:S:F:g:")) != EOF){
+ switch (ch){
+
+ case 'e':
+ interface = optarg;
+ break;
+
+ case 'm':
+ mac_addr_str = optarg;
+#if 0
+ if (!usrp2_basic::parse_mac_addr(optarg, &mac_addr)){
+ std::cerr << "invalid mac addr: " << optarg << std::endl;
+ usage(argv[0]);
+ return 1;
+ }
+#endif
+ break;
+
+ case 'I':
+ input_filename = optarg;
+ break;
+
+ case 'r':
+ repeat = true;
+ break;
+
+ case 'f':
+ if (!strtod_si(optarg, &freq)){
+ std::cerr << "invalid number: " << optarg << std::endl;
+ usage(argv[0]);
+ return 1;
+ }
+ break;
+
+ case 'F':
+ samples_per_frame = strtol(optarg, 0, 0);
+ break;
+
+ case 'i':
+ interp = strtol(optarg, 0, 0);
+ break;
+
+ case 'S':
+ if (!strtod_si(optarg, &tmp)){
+ std::cerr << "invalid number: " << optarg << std::endl;
+ usage(argv[0]);
+ return 1;
+ }
+ scale = static_cast<int32_t>(tmp);
+ break;
+
+ case 'h':
+ default:
+ usage(argv[0]);
+ return 1;
+ }
+ }
+
+
+ if (argc - optind != 0){
+ usage(argv[0]);
+ return 1;
+ }
+
+ if (samples_per_frame < 9 || samples_per_frame > MAX_SAMPLES){
+ std::cerr << prettify_progname(argv[0])
+ << ": samples_per_frame is out of range. "
+ << "Must be in [9, " << MAX_SAMPLES << "].\n";
+ usage(argv[0]);
+ return 1;
+ }
+
+
+ FILE *fp = 0;
+ if (input_filename == 0)
+ fp = stdin;
+ else {
+ fp = fopen(input_filename, "rb");
+ if (fp == 0){
+ perror(input_filename);
+ return 1;
+ }
+ }
+
+
+ gruel::rt_status_t rt = gruel::enable_realtime_scheduling();
+ if (rt != gruel::RT_OK)
+ std::cerr << "Failed to enable realtime scheduling" << std::endl;
+
+
+ usrp2::usrp2::sptr u2 = usrp2::usrp2::make(interface, mac_addr_str);
+
+ if (gain != GAIN_NOT_SET){
+ if (!u2->set_tx_gain(gain)){
+ std::cerr << "set_tx_gain failed\n";
+ return 1;
+ }
+ }
+
+ usrp2::tune_result tr;
+ if (!u2->set_tx_center_freq(freq, &tr)){
+ fprintf(stderr, "set_tx_center_freq(%g) failed\n", freq);
+ return 1;
+ }
+
+ printf("Daughterboard configuration:\n");
+ printf(" baseband_freq=%f\n", tr.baseband_freq);
+ printf(" duc_freq=%f\n", tr.dxc_freq);
+ printf(" residual_freq=%f\n", tr.residual_freq);
+ printf(" inverted=%s\n\n", tr.spectrum_inverted ? "yes" : "no");
+
+ if (!u2->set_tx_interp(interp)){
+ fprintf(stderr, "set_tx_interp(%d) failed\n", interp);
+ return 1;
+ }
+
+ if (!u2->set_tx_scale_iq(scale, scale)){
+ std::cerr << "set_tx_scale_iq failed\n";
+ return 1;
+ }
+
+
+ usrp2::tx_metadata md;
+ md.timestamp = -1;
+ md.start_of_burst = 1;
+ md.send_now = 1;
+
+ while (1){
+
+ std::complex<int16_t> samples[MAX_SAMPLES];
+
+ int r = fread(samples, sizeof(uint32_t), samples_per_frame, fp);
+
+ // fprintf(stderr, "fread -> %d\n", r);
+
+ if (r == 0){
+ if (!repeat)
+ break;
+ if (fseek(fp, 0, SEEK_SET) == -1)
+ break;
+ }
+
+ // FIXME if r < 9, pad to 9 for minimum packet size constraint
+
+ if (!u2->tx_complex_int16(0, samples, r, &md)){
+ fprintf(stderr, "tx_complex_int16 failed\n");
+ break;
+ }
+ }
+
+ return 0;
+}
Copied: usrp2/trunk/host-ng/apps/u2_burn_mac_addr.cc (from rev 9140,
usrp2/branches/developers/eb/merge-wip/host-ng/apps/u2_burn_mac_addr.cc)
===================================================================
--- usrp2/trunk/host-ng/apps/u2_burn_mac_addr.cc
(rev 0)
+++ usrp2/trunk/host-ng/apps/u2_burn_mac_addr.cc 2008-08-01 20:34:19 UTC
(rev 9142)
@@ -0,0 +1,114 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "usrp2_basic.h"
+#include <iostream>
+#include <getopt.h>
+#include <string.h>
+#include <time.h>
+
+
+static void
+usage(const char *progname)
+{
+ fprintf(stderr, "usage: %s [-e ethN] [-m old_mac_addr] new_mac_addr\n",
+ progname);
+ fprintf(stderr, " old_mac_addr defaults to 00:50:c2:85:3f:ff\n");
+ fprintf(stderr, " new_mac_address must be HH:HH or HH:HH:HH:HH:HH:HH\n");
+}
+
+int
+main(int argc, char **argv)
+{
+ int ch;
+ const char *interface = "eth0";
+ char *old_mac_addr_str = "00:50:c2:85:3f:ff";
+ char *new_mac_addr_str = 0;
+ u2_mac_addr_t old_mac_addr;
+ u2_mac_addr_t new_mac_addr;
+
+ while ((ch = getopt(argc, argv, "he:m:")) != EOF){
+ switch (ch){
+ case 'e':
+ interface = optarg;
+ break;
+
+ case 'm':
+ old_mac_addr_str = optarg;
+ break;
+
+ case 'h':
+ default:
+ usage(argv[0]);
+ exit(1);
+ }
+ }
+
+ if (argc - optind != 1){
+ usage(argv[0]);
+ exit(1);
+ }
+
+ new_mac_addr_str = argv[optind];
+
+ if (!usrp2_basic::parse_mac_addr(old_mac_addr_str, &old_mac_addr)){
+ fprintf(stderr, "invalid mac address: %s\n", old_mac_addr_str);
+ exit(1);
+ }
+ if (!usrp2_basic::parse_mac_addr(new_mac_addr_str, &new_mac_addr)){
+ fprintf(stderr, "invalid mac address: %s\n", new_mac_addr_str);
+ exit(1);
+ }
+
+
+ usrp2_basic *u2 = new usrp2_basic();
+
+ if (!u2->open(interface)){
+ std::cerr << "couldn't open " << interface << std::endl;
+ return 0;
+ }
+
+ if (!u2->find_usrp_by_mac(old_mac_addr, 0)){
+ std::cerr << "No USRP2 with address "
+ << old_mac_addr << " found.\n";
+ return 1;
+ }
+
+ if (!u2->burn_mac_addr(old_mac_addr, new_mac_addr)){
+ std::cerr << "Failed to burn mac address\n";
+ return 1;
+ }
+
+ // wait 250 ms
+ struct timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = 250000000;
+ nanosleep(&ts, 0);
+
+ // Now see if we can find it using it's new address
+ if (!u2->find_usrp_by_mac(new_mac_addr, 0)){
+ std::cerr << "Failed to find USRP2 using new address "
+ << new_mac_addr << ".\n";
+ return 1;
+ }
+
+ return 0;
+}
Modified: usrp2/trunk/host-ng/configure.ac
===================================================================
--- usrp2/trunk/host-ng/configure.ac 2008-08-01 20:25:36 UTC (rev 9141)
+++ usrp2/trunk/host-ng/configure.ac 2008-08-01 20:34:19 UTC (rev 9142)
@@ -1,4 +1,4 @@
-dnl Copyright 2001,2002,2003,2004,2005,2006,2007 Free Software Foundation, Inc.
+dnl Copyright 2001,2002,2003,2004,2005,2006,2007,2008 Free Software
Foundation, Inc.
dnl
dnl This program is free software: you can redistribute it and/or modify
dnl it under the terms of the GNU General Public License as published by
@@ -81,10 +81,11 @@
AC_PROG_INSTALL
AC_PATH_PROG([RM_PROG], [rm])
+AC_LIBTOOL_WIN32_DLL
dnl AC_DISABLE_SHARED dnl don't build shared libraries
AC_ENABLE_SHARED dnl do build shared libraries
AC_DISABLE_STATIC dnl don't build static libraries
-AC_PROG_LIBTOOL
+m4_ifdef([LT_INIT],[LT_INIT],[AC_PROG_LIBTOOL])
dnl GR_FORTRAN
GR_NO_UNDEFINED dnl do we need the -no-undefined linker flag
@@ -160,6 +161,10 @@
#endif
])
+PKG_CHECK_MODULES(GRUEL, gruel > 3)
+AC_SUBST(GRUEL_LIBS)
+AC_SUBST(GRUEL_CFLAGS)
+
dnl Do we have "dot", part of the graphviz package from AT&T?
dnl Doxgen will use it to draw pretty diagrams ;-)
AC_CHECK_PROG(HAVE_DOT, [dot],[YES],[NO])
Modified: usrp2/trunk/host-ng/include/usrp2/Makefile.am
===================================================================
--- usrp2/trunk/host-ng/include/usrp2/Makefile.am 2008-08-01 20:25:36 UTC
(rev 9141)
+++ usrp2/trunk/host-ng/include/usrp2/Makefile.am 2008-08-01 20:34:19 UTC
(rev 9142)
@@ -22,6 +22,9 @@
usrp2includedir = $(includedir)/usrp2
usrp2include_HEADERS = \
+ copiers.h \
copy_handler.h \
data_handler.h \
+ strtod_si.h \
+ tune_result.h \
usrp2.h
Copied: usrp2/trunk/host-ng/include/usrp2/copiers.h (from rev 9140,
usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/copiers.h)
===================================================================
--- usrp2/trunk/host-ng/include/usrp2/copiers.h (rev 0)
+++ usrp2/trunk/host-ng/include/usrp2/copiers.h 2008-08-01 20:34:19 UTC (rev
9142)
@@ -0,0 +1,63 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2008 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef INCLUDED_USRP2_COPIERS_H
+#define INCLUDED_USRP2_COPIERS_H
+
+#include <complex>
+#include <stdint.h>
+
+namespace usrp2 {
+
+ // FIXME we may want to rework this, but this will get us on the air
+
+ /*
+ * ----------------------------------------------------------------
+ * Copy and convert from USRP2 wire format to host format
+ * ----------------------------------------------------------------
+ */
+
+ void
+ copy_u2_complex_16_to_host_complex_16(size_t nitems,
+ const uint32_t *items,
+ std::complex<int16_t> *host_items);
+
+ void
+ copy_u2_complex_16_to_host_complex_float(size_t nitems,
+ const uint32_t *items,
+ std::complex<float> *host_items);
+
+ /*
+ * ----------------------------------------------------------------
+ * Copy and convert from host format to USRP2 wire format
+ * ----------------------------------------------------------------
+ */
+
+ void
+ copy_host_complex_16_to_u2_complex_16(size_t nitems,
+ const std::complex<int16_t> *host_items,
+ uint32_t *items);
+
+ void
+ copy_host_complex_float_to_u2_complex_16(size_t nitems,
+ const std::complex<float>
*host_items,
+ uint32_t *items);
+}
+
+
+#endif /* INCLUDED_USRP2_COPIERS_H */
Modified: usrp2/trunk/host-ng/include/usrp2/copy_handler.h
===================================================================
--- usrp2/trunk/host-ng/include/usrp2/copy_handler.h 2008-08-01 20:25:36 UTC
(rev 9141)
+++ usrp2/trunk/host-ng/include/usrp2/copy_handler.h 2008-08-01 20:34:19 UTC
(rev 9142)
@@ -26,18 +26,24 @@
namespace usrp2 {
- class copy_handler : data_handler, boost::noncopyable
+ class copy_handler : public data_handler, boost::noncopyable
{
uint8_t *d_dest; // next write pointer
- unsigned int d_space; // space left in destination buffer
- unsigned int d_bytes; // total bytes copied
- unsigned int d_times; // number of times invoked
+ size_t d_space; // space left in destination buffer
+ size_t d_bytes; // total bytes copied
+ size_t d_times; // number of times invoked
public:
- copy_handler(void *dest, unsigned int len);
+ copy_handler(void *dest, size_t len);
~copy_handler();
- virtual uint32_t operator()(const void *base, unsigned int len);
+ virtual data_handler::result operator()(const void *base, size_t len);
+
+ size_t bytes() const { return d_bytes; }
+ size_t times() const { return d_times; }
+
+ static const size_t MIN_COPY_LEN = 1484; // FIXME: calculate eth packet -
thdr
+ bool full() const { return d_space < MIN_COPY_LEN; }
};
} // namespace usrp2
Modified: usrp2/trunk/host-ng/include/usrp2/data_handler.h
===================================================================
--- usrp2/trunk/host-ng/include/usrp2/data_handler.h 2008-08-01 20:25:36 UTC
(rev 9141)
+++ usrp2/trunk/host-ng/include/usrp2/data_handler.h 2008-08-01 20:34:19 UTC
(rev 9142)
@@ -22,24 +22,32 @@
#define INCLUDED_DATA_HANDLER_H
#include <stdint.h>
+#include <stddef.h>
namespace usrp2 {
/*!
- * \brief abstract function object called to handle received data blocks
+ * \brief Abstract function object called to handle received data blocks.
*/
class data_handler
{
public:
- static const unsigned int KEEP = 0x0001; // do not discard data
- static const unsigned int DONE = 0x0002; // do not call this object again
+
+ enum result_bits {
+ RELEASE = 0x0000, //< OK to release data (opposite of KEEP)
+ KEEP = 0x0001, //< do not discard data
+ DONE = 0x0002, //< do not call this object again
+ };
+ typedef int result; //< bitmask of result_bits
+
/*!
* \param base points to the beginning of the data
* \param len is the length in bytes of the data
+ * \returns bitmask composed of DONE, KEEP
*/
- virtual unsigned int operator()(const void *base, unsigned int len) = 0;
- virtual ~data_handler();
+ virtual result operator()(const void *base, size_t len) = 0;
+ virtual ~data_handler();
};
} // namespace usrp2
Copied: usrp2/trunk/host-ng/include/usrp2/metadata.h (from rev 9140,
usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/metadata.h)
===================================================================
--- usrp2/trunk/host-ng/include/usrp2/metadata.h
(rev 0)
+++ usrp2/trunk/host-ng/include/usrp2/metadata.h 2008-08-01 20:34:19 UTC
(rev 9142)
@@ -0,0 +1,60 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2008 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef INCLUDED_USRP2_METADATA_H
+#define INCLUDED_USRP2_METADATA_H
+
+#include <stdint.h>
+
+namespace usrp2 {
+
+ //! type of the timestamp returned from the USRP2 FPGA
+ typedef uint32_t fpga_timestamp;
+
+ /*!
+ * \brief metadata associated with received frames
+ */
+ struct rx_metadata {
+ uint32_t word0; //< debugging, extensions
+ fpga_timestamp timestamp; //< time that first sample of
frame was received
+ unsigned int start_of_burst : 1; //< this frame is the start of
a burst
+ unsigned int end_of_burst : 1; //< this frame is the end of a
burst
+ unsigned int rx_overrun : 1; //< An Rx overrun occurred in
the FPGA
+ // rssi
+ // agc_mode
+
+ rx_metadata() :
+ word0(0), timestamp(0), start_of_burst(0), end_of_burst(0),
rx_overrun(0) {}
+ };
+
+ /*!
+ * \brief metadata associated with transmitted frames
+ */
+ struct tx_metadata {
+ fpga_timestamp timestamp; //< time to transmit first
sample of frame
+ unsigned int send_now : 1; //< ignore timestamp, send now
+ unsigned int start_of_burst : 1; //< this frame is the start of
a burst
+ unsigned int end_of_burst : 1; //< this frame is the end of a
burst
+ // ...
+
+ tx_metadata() :
+ timestamp(0), send_now(0), start_of_burst(0), end_of_burst(0) {}
+ };
+
+}; // usrp2
+
+#endif /* INCLUDED_USRP2_METADATA_H */
Copied: usrp2/trunk/host-ng/include/usrp2/rx_sample_handler.h (from rev 9140,
usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/rx_sample_handler.h)
===================================================================
--- usrp2/trunk/host-ng/include/usrp2/rx_sample_handler.h
(rev 0)
+++ usrp2/trunk/host-ng/include/usrp2/rx_sample_handler.h 2008-08-01
20:34:19 UTC (rev 9142)
@@ -0,0 +1,58 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2008 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef INCLUDED_USRP2_RX_SAMPLE_HANDLER_H
+#define INCLUDED_USRP2_RX_SAMPLE_HANDLER_H
+
+#include <usrp2/metadata.h>
+#include <stddef.h>
+
+
+namespace usrp2 {
+
+ /*!
+ * \brief Abstract function object called to handle received data blocks.
+ *
+ * An object derived from this class is passed to usrp2::rx_samples
+ * to process the received frames of samples.
+ */
+ class rx_sample_handler {
+ public:
+ virtual ~rx_sample_handler();
+
+ /*!
+ * \param items points to the first 32-bit word of uninterpreted sample
data in the frame.
+ * \param nitems is the number of entries in the frame in units of
uint32_t's.
+ * \param metadata is the additional per frame data provided by the USRP2
FPGA.
+ *
+ * \p items points to the raw sample data received off of the ethernet.
The data is
+ * packed into big-endian 32-bit unsigned ints for transport, but the
actual format
+ * of the data is dependent on the current configuration of the USRP2.
The most common
+ * format is 16-bit I & Q, with I in the top of the 32-bit word.
+ *
+ * This is the general purpose, low level interface and relies on other
functions
+ * to handle all required endian-swapping and format conversion. \sa
FIXME.
+ *
+ * \returns true if the object wants to be called again with new data;
+ * false if no additional data is wanted.
+ */
+ virtual bool operator()(const uint32_t *items, size_t nitems, const
rx_metadata *metadata) = 0;
+ };
+
+};
+
+#endif /* INCLUDED_RX_SAMPLE_HANDLER_H */
Copied: usrp2/trunk/host-ng/include/usrp2/strtod_si.h (from rev 9140,
usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/strtod_si.h)
===================================================================
--- usrp2/trunk/host-ng/include/usrp2/strtod_si.h
(rev 0)
+++ usrp2/trunk/host-ng/include/usrp2/strtod_si.h 2008-08-01 20:34:19 UTC
(rev 9142)
@@ -0,0 +1,39 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef INCLUDED_STRTOD_SI_H
+#define INCLUDED_STRTOD_SI_H
+
+#include "usrp2_cdefs.h"
+__U2_BEGIN_DECLS
+
+
+/*!
+ * \brief convert string at s to double honoring any trailing SI suffixes
+ *
+ * \param[in] s is the string to convert
+ * \param[out] result is the converted value
+ * \returns non-zero iff conversion was successful.
+ */
+int strtod_si(const char *s, double *result);
+
+__U2_END_DECLS
+
+
+#endif /* INCLUDED_STRTOD_SI_H */
+
Copied: usrp2/trunk/host-ng/include/usrp2/tune_result.h (from rev 9140,
usrp2/branches/developers/eb/merge-wip/host-ng/include/usrp2/tune_result.h)
===================================================================
--- usrp2/trunk/host-ng/include/usrp2/tune_result.h
(rev 0)
+++ usrp2/trunk/host-ng/include/usrp2/tune_result.h 2008-08-01 20:34:19 UTC
(rev 9142)
@@ -0,0 +1,45 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2008 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef INCLUDED_TUNE_RESULT_H
+#define INCLUDED_TUNE_RESULT_H
+
+namespace usrp2 {
+
+ class tune_result
+ {
+ public:
+ // RF frequency that corresponds to DC in the IF
+ double baseband_freq;
+
+ // frequency programmed into the DDC/DUC
+ double dxc_freq;
+
+ // residual frequency (typically < 0.01 Hz)
+ double residual_freq;
+
+ // is the spectrum inverted?
+ bool spectrum_inverted;
+
+ tune_result()
+ : baseband_freq(0), dxc_freq(0), residual_freq(0),
spectrum_inverted(false) {}
+ };
+
+} // namespace usrp2
+
+#endif /* INCLUDED_TUNE_RESULT_H */
Modified: usrp2/trunk/host-ng/include/usrp2/usrp2.h
===================================================================
--- usrp2/trunk/host-ng/include/usrp2/usrp2.h 2008-08-01 20:25:36 UTC (rev
9141)
+++ usrp2/trunk/host-ng/include/usrp2/usrp2.h 2008-08-01 20:34:19 UTC (rev
9142)
@@ -22,131 +22,251 @@
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>
#include <vector>
+#include <complex>
+#include <iosfwd>
+#include <usrp2/rx_sample_handler.h>
+#include <usrp2/tune_result.h>
+#include <usrp2/rx_sample_handler.h>
+
namespace usrp2 {
-/*!
- * Structure to hold properties of USRP2 hardware devices.
- *
- */
-struct props
-{
- std::string addr;
- uint16_t hw_rev;
- uint8_t fpga_md5sum[16];
- uint8_t sw_md5sum[16];
-};
+ /*!
+ * Structure to hold properties of USRP2 hardware devices.
+ *
+ */
+ struct props
+ {
+ std::string addr;
+ uint16_t hw_rev;
+ uint8_t fpga_md5sum[16];
+ uint8_t sw_md5sum[16];
+ };
-typedef std::vector<props> props_vector_t;
+ typedef std::vector<props> props_vector_t;
-props_vector_t find(const std::string &ifc, const std::string &addr="");
+ /*!
+ * \brief Search the ethernet for all USRP2s or for a specific USRP2.
+ *
+ * \param ifc is the name of the OS ethernet interface (e.g., "eth0")
+ * \param mac_addr is the MAC address of the desired USRP2, or "" to search
for all.
+ * mac_addr must be either a zero length string, "", or must be of the form
+ * "01:02:03:04:05:06" or "05:06".
+ *
+ * \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="");
-/*!
- * Structure to hold results of tuning
- */
-class usrp2_tune_result
-{
-public:
- // RF frequency that corresponds to DC in the IF
- double baseband_freq;
+ class tune_result;
+
+ class usrp2 : boost::noncopyable
+ {
+ public:
+ static const unsigned int MAX_CHAN = 30;
- // frequency programmed into the DDC/DUC
- double dxc_freq;
+ /*!
+ * 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"
+ * \param addr Network mac address, e.g., "01:02:03:04:05:06", "05:06" or
"".
+ * "" will autoselect a USRP2 if there is only a single one
on the local ethernet.
+ */
+ static sptr make(const std::string &ifc, const std::string &addr="");
- // residual frequency (typically < 0.01 Hz)
- double residual_freq;
+ /*!
+ * Class destructor
+ */
+ ~usrp2();
- // is the spectrum inverted?
- bool spectrum_inverted;
+ /*
+ * ----------------------------------------------------------------
+ * Rx configuration and control
+ * ----------------------------------------------------------------
+ */
- usrp2_tune_result()
- : baseband_freq(0), dxc_freq(0), residual_freq(0),
spectrum_inverted(false) {}
- ~usrp2_tune_result();
-};
+ /*!
+ * Set receiver gain
+ */
+ bool set_rx_gain(double gain);
-class usrp2 : boost::noncopyable
-{
-public:
- /*!
- * 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"
- * \param addr Network mac address, e.g., "01:02:03:04:05:06" or "05:06",
- * default is auto-select
- */
- static sptr make(const std::string &ifc, const std::string &addr="");
+ /*!
+ * Set receiver center frequency
+ */
+ bool set_rx_center_freq(double frequency, tune_result *result);
- /*!
- * Class destructor
- */
- ~usrp2();
+ /*!
+ * Set receiver sample rate decimation
+ */
+ bool set_rx_decim(int decimation_factor);
- /*
- * Rx configuration and control
- */
+ /*!
+ * Set receiver IQ magnitude scaling
+ */
+ bool set_rx_scale_iq(int scale_i, int scale_q);
- /*!
- * Set receiver gain
- */
- bool set_rx_gain(double gain);
+ /*!
+ * Set received sample format
+ *
+ * domain: complex or real
+ * type: floating, fixed point, or raw
+ * depth: bits per sample
+ *
+ * Sets format over the wire for samples from USRP2.
+ */
+ // bool set_rx_format(...);
- /*!
- * Set receiver center frequency
- */
- bool set_rx_freq(double frequency, usrp2_tune_result *result);
+ /*!
+ * 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);
+
+ /*!
+ * Stop streaming receive mode.
+ */
+ bool stop_rx_streaming(unsigned int channel=0);
- /*!
- * Set receiver sample rate decimation
- */
- bool set_rx_decim(int decimation_factor);
+ /*!
+ * \brief Receive data from the specified channel
+ * This method is used to receive all data: streaming or discrete.
+ */
+ bool rx_samples(unsigned int channel, rx_sample_handler *handler);
- /*!
- * Set receiver IQ magnitude scaling
- */
- bool set_rx_scale_iq(int scale_i, int scale_q);
+ /*!
+ * Returns number of times receive overruns have occurred
+ */
+ unsigned int rx_overruns();
+
+ /*!
+ * Returns total number of missing frames from overruns.
+ */
+ unsigned int rx_missing();
- /*!
- * Set received sample format
- *
- * domain: complex or real
- * type: floating, fixed point, or raw
- * depth: bits per sample
- *
- * Sets format over the wire for samples from USRP2 and determines
- * default reader and writer functors
- *
- */
- // bool set_rx_format(...);
+ /*
+ * ----------------------------------------------------------------
+ * Tx configuration and control
+ * ----------------------------------------------------------------
+ */
- /*!
- * Start streaming receive mode. USRP2 will send a continuous stream of
- * DSP pipeline samples to host. Call rx_samples(...) to access.
- *
- * \param items_per_frame Interpreted according to current receive format
- */
- bool start_rx_streaming(unsigned int items_per_frame=0);
-
- /*!
- * Stop streaming receive mode.
- */
- bool stop_rx_streaming();
+ /*!
+ * Set receiver gain
+ */
+ bool set_tx_gain(double gain);
- /* Ignore :-) */
- class impl;
+ /*!
+ * Set transmitter center frequency
+ */
+ bool set_tx_center_freq(double frequency, tune_result *result);
-private:
- // Only usrp2::make factory function can instantiate this class
- usrp2(const std::string &ifc, const std::string &addr);
+ /*!
+ * Set transmitter sample rate interpolation
+ */
+ bool set_tx_interp(int interpolation_factor);
+
+ /*!
+ * Set transmit IQ magnitude scaling
+ */
+ bool set_tx_scale_iq(int scale_i, int scale_q);
+
+ /*!
+ * Set transmit sample format
+ *
+ * domain: complex or real
+ * type: floating, fixed point, or raw
+ * depth: bits per sample
+ *
+ * Sets format over the wire for samples to USRP2.
+ */
+ // bool set_tx_format(...);
+
+ /*!
+ * \brief transmit complex<float> samples to USRP2
+ *
+ * \param channel specifies the channel to send them to
+ * \param samples are the samples to transmit
+ * \param nsamples is the number of samples to transmit
+ * \param metadata provides the timestamp and flags
+ */
+ bool tx_complex_float(unsigned int channel,
+ const std::complex<float> *samples,
+ size_t nsamples,
+ const tx_metadata *metadata);
+
+ /*!
+ * \brief transmit complex<int16_t> samples to USRP2
+ *
+ * \param channel specifies the channel to send them to
+ * \param samples are the samples to transmit
+ * \param nsamples is the number of samples to transmit
+ * \param metadata provides the timestamp and flags
+ */
+ bool tx_complex_int16(unsigned int channel,
+ const std::complex<int16_t> *samples,
+ size_t nsamples,
+ const tx_metadata *metadata);
+
+ /*!
+ * \brief transmit raw uint32_t data items to USRP2
+ *
+ * The caller is responsible for ensuring that the items are
+ * formatted appropriately for the USRP2 and its configuration.
+ * This method is used primarily by the system itself. Users
+ * should call tx_complex_float or tx_complex_16 instead.
+ *
+ * \param channel specifies the channel to send them to
+ * \param items are the data items to transmit
+ * \param nitems is the number of items to transmit
+ * \param metadata provides the timestamp and flags
+ */
+ bool tx_raw(unsigned int channel,
+ const uint32_t *items,
+ size_t nitems,
+ const tx_metadata *metadata);
+
+ // ----------------------------------------------------------------
+
+ /*!
+ * \brief MIMO configuration
+ *
+ * \param flags from usrp2_mimo_config.h
+ *
+ * <pre>
+ * one of these:
+ *
+ * MC_WE_DONT_LOCK
+ * MC_WE_LOCK_TO_SMA
+ * MC_WE_LOCK_TO_MIMO
+ *
+ * and optionally this:
+ *
+ * MC_PROVIDE_CLK_TO_MIMO
+ * </pre>
+ */
+ bool config_mimo(int flags);
+
+
+
+ class impl; // implementation details
+
+ private:
+ // Only usrp2::make factory function can instantiate this class
+ usrp2(const std::string &ifc, const std::string &addr);
- // All private state is held in opaque pointer
- std::auto_ptr<impl> d_impl;
-};
+ // All private state is held in opaque pointer
+ std::auto_ptr<impl> d_impl;
+ };
};
+std::ostream& operator<<(std::ostream &os, const usrp2::props &x);
+
+
#endif /* INCLUDED_USRP2_H */
Modified: usrp2/trunk/host-ng/lib/Makefile.am
===================================================================
--- usrp2/trunk/host-ng/lib/Makefile.am 2008-08-01 20:25:36 UTC (rev 9141)
+++ usrp2/trunk/host-ng/lib/Makefile.am 2008-08-01 20:34:19 UTC (rev 9142)
@@ -17,25 +17,31 @@
include $(top_srcdir)/Makefile.common
-AM_CPPFLAGS = -Wall -Werror
-INCLUDES = $(STD_DEFINES_AND_INCLUDES) $(CPPUNIT_INCLUDES)
+#AM_CXXFLAGS = -Wall -Werror (handle this with: $ ./configure CXXFLAGS="-Wall
-Werror -O2 -g")
+AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(CPPUNIT_INCLUDES) $(GRUEL_CFLAGS)
$(BOOST_CFLAGS)
lib_LTLIBRARIES = \
libusrp2ng.la
libusrp2ng_la_SOURCES = \
control.cc \
+ copiers.cc \
copy_handler.cc \
+ data_handler.cc \
eth_buffer.cc \
ethernet.cc \
find.cc \
pktfilter.cc \
+ ring.cc \
+ rx_sample_handler.cc \
+ strtod_si.c \
usrp2.cc \
usrp2_impl.cc \
usrp2_thread.cc
libusrp2ng_la_LIBADD = \
- $(GR_OMNITHREAD_LIBS)
+ $(GR_OMNITHREAD_LIBS) \
+ $(GRUEL_LIBS)
# Private headers not needed for above the API development
noinst_HEADERS = \
@@ -44,5 +50,6 @@
eth_common.h \
ethernet.h \
pktfilter.h \
+ ring.h \
usrp2_impl.h \
usrp2_thread.h
Modified: usrp2/trunk/host-ng/lib/control.cc
===================================================================
--- usrp2/trunk/host-ng/lib/control.cc 2008-08-01 20:25:36 UTC (rev 9141)
+++ usrp2/trunk/host-ng/lib/control.cc 2008-08-01 20:34:19 UTC (rev 9142)
@@ -23,28 +23,28 @@
#include <config.h>
#endif
+#include <omni_time.h>
#include "control.h"
#include <iostream>
namespace usrp2 {
- pending_reply::pending_reply(int rid, void *buffer, int len)
+ pending_reply::pending_reply(unsigned int rid, void *buffer, size_t len)
: d_rid(rid), d_mutex(), d_cond(&d_mutex), d_buffer(buffer), d_len(len)
{
}
pending_reply::~pending_reply()
{
- signal();
+ signal(); // Needed?
}
int
- pending_reply::wait(int secs, long nsecs)
+ pending_reply::wait(double secs)
{
- int res = d_cond.timedwait(secs, nsecs);
- if (res == 0)
- std::cerr << "usrp2: no response to command packet" << std::endl;
- return res;
+ omni_mutex_lock l(d_mutex);
+ omni_time abs_timeout = omni_time::time(omni_time(secs));
+ return d_cond.timedwait(abs_timeout.d_secs, abs_timeout.d_nsecs);
}
void
Modified: usrp2/trunk/host-ng/lib/control.h
===================================================================
--- usrp2/trunk/host-ng/lib/control.h 2008-08-01 20:25:36 UTC (rev 9141)
+++ usrp2/trunk/host-ng/lib/control.h 2008-08-01 20:34:19 UTC (rev 9142)
@@ -30,27 +30,48 @@
{
u2_eth_packet_t h;
op_config_rx_v2_t op;
- op_eop_t eop;
+ op_generic_t eop;
};
+ struct op_start_rx_streaming_cmd
+ {
+ u2_eth_packet_t h;
+ op_start_rx_streaming_t 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
+ {
+ u2_eth_packet_t h;
+ op_config_tx_v2_t op;
+ op_generic_t eop;
+ };
+
+
/*!
* Control mechanism to allow API calls to block waiting for reply packets
*/
class pending_reply
{
private:
- int d_rid;
+ unsigned int d_rid;
omni_mutex d_mutex;
omni_condition d_cond;
void *d_buffer;
- int d_len;
+ size_t d_len;
public:
/*!
* Construct a pending reply from the reply ID, response packet
* buffer, and buffer length.
*/
- pending_reply(int rid, void *buffer, int len);
+ pending_reply(unsigned int rid, void *buffer, size_t len);
/*!
* Destructor. Signals creating thread.
@@ -62,7 +83,7 @@
* Returns: 1 = ok, reply packet in buffer
* 0 = timeout
*/
- int wait(int secs, long nsecs);
+ int wait(double secs);
/*!
* Allows creating thread to resume after copying reply into buffer
@@ -72,12 +93,17 @@
/*!
* Retrieve pending reply ID
*/
- int rid() const { return d_rid; }
+ unsigned int rid() const { return d_rid; }
/*!
* Retrieve destination buffer address
*/
void *buffer() const { return d_buffer; }
+
+ /*!
+ * Retrieve destination buffer length
+ */
+ size_t len() const { return d_len; }
};
} // namespace usrp2
Copied: usrp2/trunk/host-ng/lib/copiers.cc (from rev 9140,
usrp2/branches/developers/eb/merge-wip/host-ng/lib/copiers.cc)
===================================================================
--- usrp2/trunk/host-ng/lib/copiers.cc (rev 0)
+++ usrp2/trunk/host-ng/lib/copiers.cc 2008-08-01 20:34:19 UTC (rev 9142)
@@ -0,0 +1,133 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2008 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <usrp2/copiers.h>
+#include <gruel/inet.h>
+#include <gr_math.h>
+#include <math.h>
+#include <stdexcept>
+#include <assert.h>
+#include <string.h>
+
+// FIXME need gruel::not_implemented
+
+namespace usrp2 {
+
+ /*
+ * N.B., in all of these, uint32_t *items is NOT 32-bit aligned!
+ * FIXME Needs fix for non-x86 machines.
+ */
+
+ /*
+ * ----------------------------------------------------------------
+ * Copy and convert from USRP2 wire format to host format
+ * ----------------------------------------------------------------
+ */
+ void
+ copy_u2_complex_16_to_host_complex_16(size_t nitems,
+ const uint32_t *items,
+ std::complex<int16_t> *host_items)
+ {
+#ifdef WORDS_BIGENDIAN
+
+ assert(sizeof(items[0]) == sizeof(host_items[0]));
+ memcpy(host_items, items, nitems * sizeof(items[0]));
+
+#else
+
+ // FIXME SIMD welcome here
+
+ for (size_t i = 0; i < nitems; i++){
+ uint32_t t = ntohx(items[i]);
+ //printf("%9d\n", items[i]);
+ host_items[i] = std::complex<int16_t>((t >> 16), t & 0xffff);
+ }
+
+#endif
+ }
+
+
+ /*
+ * endian swap if required and map [-32768, 32767] -> [1.0, +1.0)
+ */
+ void
+ copy_u2_complex_16_to_host_complex_float(size_t nitems,
+ const uint32_t *items,
+ std::complex<float> *host_items)
+ {
+ for (size_t i = 0; i < nitems; i++){
+ uint32_t t = ntohx(items[i]);
+ int16_t re = (t >> 16) & 0xffff;
+ int16_t im = (t & 0xffff);
+ host_items[i] = std::complex<float>(re * 1.0/32768, im * 1.0/32768);
+ }
+ }
+
+ /*
+ * ----------------------------------------------------------------
+ * Copy and convert from host format to USRP2 wire format
+ * ----------------------------------------------------------------
+ */
+ void
+ copy_host_complex_16_to_u2_complex_16(size_t nitems,
+ const std::complex<int16_t> *host_items,
+ uint32_t *items)
+ {
+#ifdef WORDS_BIGENDIAN
+
+ assert(sizeof(items[0]) == sizeof(host_items[0]));
+ memcpy(items, host_items, nitems * sizeof(items[0]));
+
+#else
+
+ // FIXME SIMD welcome here
+
+ for (size_t i = 0; i < nitems; i++){
+ items[i] = htonl((host_items[i].real() << 16) | (host_items[i].imag() &
0xffff));
+ }
+
+#endif
+ }
+
+
+ static inline int16_t
+ clip_and_scale(float x)
+ {
+ return static_cast<int16_t>(rintf(gr_branchless_clip(x, 1.0) * 32767.0));
+ }
+
+ void
+ copy_host_complex_float_to_u2_complex_16(size_t nitems,
+ const std::complex<float>
*host_items,
+ uint32_t *items)
+ {
+ for (size_t i = 0; i < nitems; i++){
+ int16_t re = clip_and_scale(host_items[i].real());
+ int16_t im = clip_and_scale(host_items[i].imag());
+
+ items[i] = htonl((re << 16) | (im & 0xffff));
+ }
+ }
+
+}
Modified: usrp2/trunk/host-ng/lib/copy_handler.cc
===================================================================
--- usrp2/trunk/host-ng/lib/copy_handler.cc 2008-08-01 20:25:36 UTC (rev
9141)
+++ usrp2/trunk/host-ng/lib/copy_handler.cc 2008-08-01 20:34:19 UTC (rev
9142)
@@ -24,10 +24,11 @@
#endif
#include <usrp2/copy_handler.h>
+#include <iostream>
namespace usrp2 {
- copy_handler::copy_handler(void *dest, unsigned int len)
+ copy_handler::copy_handler(void *dest, size_t len)
: d_dest((uint8_t *)dest), d_space(len), d_bytes(0), d_times(0)
{
}
@@ -37,8 +38,8 @@
// NOP
}
- uint32_t
- copy_handler::operator()(const void *base, unsigned int len)
+ data_handler::result
+ copy_handler::operator()(const void *base, size_t len)
{
if (len > d_space)
return KEEP|DONE; // can't do anything, retry later
@@ -47,10 +48,10 @@
d_space -= len;
d_bytes += len;
d_times++;
+
+ if (d_space < MIN_COPY_LEN)
+ return DONE; // don't call me anymore
- if (d_space == 0)
- return DONE; // don't call me anymore
-
return 0;
}
Copied: usrp2/trunk/host-ng/lib/data_handler.cc (from rev 9140,
usrp2/branches/developers/eb/merge-wip/host-ng/lib/data_handler.cc)
===================================================================
--- usrp2/trunk/host-ng/lib/data_handler.cc (rev 0)
+++ usrp2/trunk/host-ng/lib/data_handler.cc 2008-08-01 20:34:19 UTC (rev
9142)
@@ -0,0 +1,32 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2008 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <usrp2/data_handler.h>
+
+namespace usrp2 {
+
+ data_handler::~data_handler()
+ {
+ // default nop destructor
+ }
+
+}
+
Modified: usrp2/trunk/host-ng/lib/eth_buffer.cc
===================================================================
--- usrp2/trunk/host-ng/lib/eth_buffer.cc 2008-08-01 20:25:36 UTC (rev
9141)
+++ usrp2/trunk/host-ng/lib/eth_buffer.cc 2008-08-01 20:34:19 UTC (rev
9142)
@@ -33,8 +33,10 @@
#include <iostream>
#include <cmath>
#include <errno.h>
+#include <stdexcept>
-#define ETH_BUFFER_DEBUG 1 // define to 0 or 1
+
+#define ETH_BUFFER_DEBUG 0 // define to 0 or 1
#if ETH_BUFFER_DEBUG
#define DEBUG_LOG(x) ::write(2, (x), 1)
#else
@@ -47,18 +49,10 @@
namespace usrp2 {
- data_handler::~data_handler()
- {
- // default nop destructor
- }
-
eth_buffer::eth_buffer(size_t rx_bufsize)
: d_fd(0), d_using_tpring(false), d_buflen(0), d_buf(0), d_frame_nr(0),
- d_head(0), d_ring(0), d_ethernet(new ethernet())
+ d_frame_size(0), d_head(0), d_ring(0), d_ethernet(new ethernet())
{
- if (ETH_BUFFER_DEBUG)
- std::cerr << "eth_buffer: constructor" << std::endl;
-
if (rx_bufsize == 0)
d_buflen = (size_t)MAX_MEM_SIZE;
else
@@ -69,19 +63,12 @@
eth_buffer::~eth_buffer()
{
- if (ETH_BUFFER_DEBUG)
- std::cerr << "eth_buffer: destructor" << std::endl;
-
close();
}
bool
eth_buffer::open(const std::string &ifname, int protocol)
{
- if (ETH_BUFFER_DEBUG)
- std::cerr << "eth_buffer: using interface " << ifname
- << ", protocol=" << protocol << std::endl;
-
if (!d_ethernet->open(ifname, protocol)) {
std::cerr << "eth_buffer: unable to open interface "
<< ifname << std::endl;
@@ -97,6 +84,7 @@
// Calculate minimum power-of-two aligned size for frames
req.tp_frame_size =
(unsigned int)rint(pow(2,
ceil(log2(TPACKET_ALIGN(TPACKET_HDRLEN)+TPACKET_ALIGN(MAX_PKT_SIZE)))));
+ d_frame_size = req.tp_frame_size;
// Calculate minimum contiguous pages needed to enclose a frame
int npages = (page_size > req.tp_frame_size) ? 1 :
((req.tp_frame_size+page_size-1)/page_size);
@@ -114,6 +102,7 @@
req.tp_frame_nr = d_buflen/req.tp_frame_size;
d_frame_nr = req.tp_frame_nr;
+#if 0
if (ETH_BUFFER_DEBUG)
std::cerr << "eth_buffer:"
<< " frame_size=" << req.tp_frame_size
@@ -122,6 +111,7 @@
<< " frame_nr=" << req.tp_frame_nr
<< " buflen=" << d_buflen
<< std::endl;
+#endif
// Try to get kernel shared memory buffer
if (setsockopt(d_fd, SOL_PACKET, PACKET_RX_RING, (void *)&req,
sizeof(req))) {
@@ -132,27 +122,25 @@
return false;
}
- if (ETH_BUFFER_DEBUG)
- std::cerr << "eth_buffer: using malloc'd memory for buffer" <<
std::endl;
+ std::cerr << "eth_buffer: using malloc'd memory for buffer" << std::endl;
}
else {
d_using_tpring = true;
- d_buf = (uint8_t *)mmap(0, d_buflen, PROT_READ|PROT_WRITE, MAP_SHARED,
d_fd, 0);
- if (!d_buf) {
+ void *p = mmap(0, d_buflen, PROT_READ|PROT_WRITE, MAP_SHARED, d_fd, 0);
+ if (p == MAP_FAILED){
perror("eth_buffer: mmap");
return false;
}
+ d_buf = (uint8_t *) p;
if (ETH_BUFFER_DEBUG)
std::cerr << "eth_buffer: using kernel shared mem for buffer" <<
std::endl;
}
- // Initialize packet ring
+ // Initialize our pointers into the packet ring
d_ring = std::vector<uint8_t *>(req.tp_frame_nr);
for (unsigned int i=0; i < req.tp_frame_nr; i++) {
d_ring[i] = (uint8_t *)(d_buf+i*req.tp_frame_size);
- ((tpacket_hdr *)(d_ring[i]))->tp_status = TP_STATUS_KERNEL; // free
- ((tpacket_hdr *)(d_ring[i]))->tp_len = req.tp_frame_size;
}
// If not using kernel ring, instantiate select/read thread here
@@ -183,15 +171,15 @@
return (((tpacket_hdr *)d_ring[d_head])->tp_status != TP_STATUS_KERNEL);
}
- int
- eth_buffer::rx_frames(data_handler *f, int timeout)
+ eth_buffer::result
+ eth_buffer::rx_frames(data_handler *f, int timeout_in_ms)
{
- DEBUG_LOG("'");
+ DEBUG_LOG("\n");
while (!frame_available()) {
- if (timeout == 0) {
+ if (timeout_in_ms == 0) {
DEBUG_LOG("w");
- return 0; // would block
+ return EB_WOULD_BLOCK;
}
struct pollfd pfd;
@@ -201,16 +189,15 @@
DEBUG_LOG("P");
- int pres = poll(&pfd, 1, timeout);
+ int pres = poll(&pfd, 1, timeout_in_ms);
if (pres == -1) {
perror("poll");
- DEBUG_LOG("E");
- return -1;
+ return EB_ERROR;
}
if (pres == 0) {
- DEBUG_LOG("-");
- return 2;
+ DEBUG_LOG("t");
+ return EB_TIMED_OUT;
}
}
@@ -219,37 +206,67 @@
// Get start of ethernet frame and length
tpacket_hdr *hdr = (tpacket_hdr *)d_ring[d_head];
void *base = (uint8_t *)hdr+hdr->tp_mac;
- unsigned int len = hdr->tp_len;
+ size_t len = hdr->tp_len;
+ // FYI, (base % 4 == 2) Not what we want given the current FPGA
+ // code. This means that our uint32_t samples are not 4-byte
+ // aligned. We'll have to deal with it downstream.
+
+ if (0)
+ fprintf(stderr, "eth_buffer: base = %p tp_mac = %3d tp_net = %3d\n",
+ base, hdr->tp_mac, hdr->tp_net);
+
// Invoke data handler
- unsigned int r = 0;
- r = (*f)(base, len);
-
- // data_handler::KEEP not yet implemented
- hdr->tp_status = TP_STATUS_KERNEL; // mark it free
- if (++d_head == d_frame_nr)
- d_head = 0;
+ data_handler::result r = (*f)(base, len);
+ if (!(r & data_handler::KEEP))
+ hdr->tp_status = TP_STATUS_KERNEL; // mark it free
+ inc_head();
+
if (r & data_handler::DONE)
break;
}
DEBUG_LOG("|");
- return 1;
+ return EB_OK;
}
- int
+ eth_buffer::result
eth_buffer::tx_frame(const void *base, size_t len, int flags)
{
- // TODO: implement flags
DEBUG_LOG("T");
+
+ if (flags & EF_DONTWAIT) // FIXME: implement flags
+ throw std::runtime_error("tx_frame: EF_DONTWAIT not implemented");
+
int res = d_ethernet->write_packet(base, len);
-
if (res < 0 || (unsigned int)res != len)
- return -1;
+ return EB_ERROR;
- return 1;
+ return EB_OK;
}
+
+ eth_buffer::result
+ eth_buffer::tx_framev(const eth_iovec *iov, int iovcnt, int flags)
+ {
+ DEBUG_LOG("T");
+
+ if (flags & EF_DONTWAIT) // FIXME: implement flags
+ throw std::runtime_error("tx_frame: EF_DONTWAIT not implemented");
+
+ int res = d_ethernet->write_packetv(iov, iovcnt);
+ if (res < 0)
+ return EB_ERROR;
+
+ return EB_OK;
+ }
+
+ void
+ eth_buffer::release_frame(void *base)
+ {
+ // Get d_frame_size aligned header
+ tpacket_hdr *hdr = (tpacket_hdr *)((intptr_t)base & ~(d_frame_size-1));
+ hdr->tp_status = TP_STATUS_KERNEL; // mark it free
+ }
} // namespace usrp2
-
Modified: usrp2/trunk/host-ng/lib/eth_buffer.h
===================================================================
--- usrp2/trunk/host-ng/lib/eth_buffer.h 2008-08-01 20:25:36 UTC (rev
9141)
+++ usrp2/trunk/host-ng/lib/eth_buffer.h 2008-08-01 20:34:19 UTC (rev
9142)
@@ -22,7 +22,7 @@
#define INCLUDED_USRP2_ETH_BUFFER_H
#include "pktfilter.h"
-#include "eth_common.h"
+#include <eth_common.h>
#include <boost/utility.hpp>
#include <vector>
#include <stdint.h>
@@ -49,6 +49,7 @@
size_t d_buflen; // length of our buffer
uint8_t *d_buf; // packet ring
unsigned int d_frame_nr; // max frames on ring
+ size_t d_frame_size; // frame storage size
unsigned int d_head; // pointer to next frame
std::vector<uint8_t *> d_ring; // pointers into buffer
@@ -56,8 +57,24 @@
bool frame_available();
+ void inc_head()
+ {
+ if (d_head + 1 >= d_frame_nr)
+ d_head = 0;
+ else
+ d_head = d_head + 1;
+ }
+
+
public:
+ enum result {
+ EB_OK, //< everything's fine
+ EB_ERROR, //< A non-recoverable error occurred
+ EB_WOULD_BLOCK, //< A timeout of 0 was specified and nothing was ready
+ EB_TIMED_OUT, //< The timeout expired before anything was ready
+ };
+
static const unsigned int MAX_PKTLEN = 1512;
static const unsigned int MIN_PKTLEN = 64;
@@ -96,7 +113,7 @@
/*!
* \brief Call \p f for each frame in the receive buffer.
* \param f is the frame data handler
- * \param timeout controls behavior when there are no frames to read
+ * \param timeout (in ms) controls behavior when there are no frames to
read
*
* If \p timeout is 0, rx_frames will not wait for frames if none are
* available, and f will not be invoked. If \p timeout is -1 (the
@@ -107,14 +124,14 @@
* invoked.
*
* \p f will be called on each ethernet frame that is available.
- * \p f returns a bit vector with one of the following set or cleared:
+ * \p f returns a bit mask with one of the following set or cleared:
*
* data_handler::KEEP - hold onto the frame and present it again during
- the next call to rx_frames, otherwise discard it
+ * the next call to rx_frames, otherwise discard it
*
- * data_handler::BREAK - return from rx_frames even though more frames
- * might be available, otherwise continue if more
- * frames are ready
+ * data_handler::DONE - return from rx_frames now even though more frames
+ * might be available; otherwise continue if more
+ * frames are ready.
*
* The idea of holding onto a frame for the next iteration allows
* the caller to scan the received packet stream for particular
@@ -123,14 +140,22 @@
* frames received, will be presented in order to \p f.
* See usrp2.cc for an example of the pattern.
*
- * \returns 0 if \p timeout is 0 and the call would have blocked
- * \returns 1 if at least one frame was received
- * \returns 2 if timeout occurred
- * \returns -1 if there was an unrecoverable error.
+ * \returns EB_OK if at least one frame was received
+ * \returns EB_WOULD_BLOCK if \p timeout is 0 and the call would have
blocked
+ * \returns EB_TIMED_OUT if timeout occurred
+ * \returns EB_ERROR if there was an unrecoverable error.
*/
- int rx_frames(data_handler *f, int timeout=-1);
+ result rx_frames(data_handler *f, int timeout=-1);
/*
+ * \brief Release frame from buffer
+ *
+ * Call to release a frame previously held by a data_handler::KEEP.
+ * The pointer may be offset from the base of the frame up to its length.
+ */
+ void release_frame(void *p);
+
+ /*
* \brief Write an ethernet frame to the interface.
*
* \param base points to the beginning of the frame (the 14-byte ethernet
header).
@@ -139,11 +164,11 @@
*
* The frame must begin with a 14-byte ethernet header.
*
- * \returns 0 if flags contains EF_DONT_WAIT and the call would have
blocked
- * \returns 1 if the frame was successfully enqueued.
- * \returns -1 if there was an unrecoverable error.
+ * \returns EB_OK if the frame was successfully enqueued.
+ * \returns EB_WOULD_BLOCK if flags contains EF_DONT_WAIT and the call
would have blocked.
+ * \returns EB_ERROR if there was an unrecoverable error.
*/
- int tx_frame(const void *base, size_t len, int flags=0);
+ result tx_frame(const void *base, size_t len, int flags=0);
/*
* \brief Write an ethernet frame to the interface using scatter/gather.
@@ -154,11 +179,17 @@
*
* The frame must begin with a 14-byte ethernet header.
*
- * \returns 0 if flags contains EF_DONT_WAIT and the call would have
blocked
- * \returns 1 if the frame was successfully enqueued.
- * \returns -1 if there was an unrecoverable error.
+ * \returns EB_OK if the frame was successfully enqueued.
+ * \returns EB_WOULD_BLOCK if flags contains EF_DONT_WAIT and the call
would have blocked.
+ * \returns EB_ERROR if there was an unrecoverable error.
*/
- int tx_framev(const eth_iovec *iov, int iovcnt, int flags=0);
+ result tx_framev(const eth_iovec *iov, int iovcnt, int flags=0);
+
+ /*
+ * \brief Returns maximum possible number of frames in buffer
+ */
+ unsigned int max_frames() const { return d_frame_nr; }
+
};
}; // namespace usrp2
Modified: usrp2/trunk/host-ng/lib/ethernet.cc
===================================================================
--- usrp2/trunk/host-ng/lib/ethernet.cc 2008-08-01 20:25:36 UTC (rev 9141)
+++ usrp2/trunk/host-ng/lib/ethernet.cc 2008-08-01 20:34:19 UTC (rev 9142)
@@ -182,6 +182,25 @@
}
return retval;
}
+
+ int
+ ethernet::write_packetv(const eth_iovec *iov, size_t iovlen)
+ {
+ struct msghdr mh;
+ memset(&mh, 0, sizeof(mh));
+ mh.msg_iov = const_cast<eth_iovec*>(iov);
+ mh.msg_iovlen = iovlen;
+
+ int retval = sendmsg(d_fd, &mh, 0);
+ if (retval < 0){
+ if (errno == EINTR)
+ return write_packetv(iov, iovlen);
+
+ perror("ethernet:write_packetv: send");
+ return -1;
+ }
+ return retval;
+ }
bool
ethernet::attach_pktfilter (pktfilter *pf)
Modified: usrp2/trunk/host-ng/lib/ethernet.h
===================================================================
--- usrp2/trunk/host-ng/lib/ethernet.h 2008-08-01 20:25:36 UTC (rev 9141)
+++ usrp2/trunk/host-ng/lib/ethernet.h 2008-08-01 20:34:19 UTC (rev 9142)
@@ -21,6 +21,7 @@
#include <string>
#include <vector>
+#include <eth_common.h>
namespace usrp2 {
@@ -103,6 +104,19 @@
* Packet must begin with 14-byte ethhdr, but does not include the FCS.
*/
int write_packet (const void *buf, int buflen);
+
+ /*
+ * \brief Write ethernet packet to interface.
+ *
+ * \param iov scatter/gather array
+ * \param iovlen number of elements in iov
+ *
+ * \returns number of bytes written or -1 if trouble.
+ *
+ * Packet must begin with 14-byte ethhdr, but does not include the FCS.
+ */
+ int write_packetv (const eth_iovec *iov, size_t iovlen);
+
};
} // namespace usrp2
Modified: usrp2/trunk/host-ng/lib/find.cc
===================================================================
--- usrp2/trunk/host-ng/lib/find.cc 2008-08-01 20:25:36 UTC (rev 9141)
+++ usrp2/trunk/host-ng/lib/find.cc 2008-08-01 20:34:19 UTC (rev 9142)
@@ -23,14 +23,91 @@
#include <usrp2_eth_packet.h>
#include <usrp2/usrp2.h>
#include <boost/scoped_ptr.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
#include "ethernet.h"
#include "pktfilter.h"
#include <iostream>
+#include <stdexcept>
#define FIND_DEBUG 0
+
+// FIXME move to gruel
+
+static struct timeval
+time_duration_to_timeval(boost::posix_time::time_duration delta)
+{
+ long total_us = delta.total_microseconds();
+ if (total_us < 0)
+ throw std::invalid_argument("duration_to_time: delta is negative");
+
+ struct timeval tv;
+ tv.tv_sec = total_us / 1000000;
+ tv.tv_usec = total_us % 1000000;
+ return tv;
+}
+
+
namespace usrp2 {
+ static props
+ reply_to_props(const op_id_reply_t *r)
+ {
+ const uint8_t *mac = (const uint8_t *)&r->addr;
+ char addr_buf[128];
+ snprintf(addr_buf, sizeof(addr_buf), "%02x:%02x:%02x:%02x:%02x:%02x",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+
+ props p;
+ p.addr = std::string(addr_buf);
+ p.hw_rev = ntohs(r->hw_rev);
+ memcpy(p.fpga_md5sum, r->fpga_md5sum, sizeof(p.fpga_md5sum));
+ memcpy(p.sw_md5sum, r->sw_md5sum, sizeof(p.sw_md5sum));
+ return p;
+ }
+
+ static void
+ read_replies(ethernet *enet, struct timeval timeout,
+ const std::string &target_addr, props_vector_t &result)
+ {
+ struct reply {
+ u2_eth_packet_t h;
+ op_id_reply_t op_id_reply;
+ };
+
+ uint8_t pktbuf[ethernet::MAX_PKTLEN];
+ memset(pktbuf, 0, sizeof(pktbuf));
+
+ fd_set read_fds;
+ FD_ZERO(&read_fds);
+ FD_SET(enet->fd(), &read_fds);
+
+ select(enet->fd()+1, &read_fds, 0, 0, &timeout);
+ while(1) {
+ memset(pktbuf, 0, sizeof(pktbuf));
+ int len = enet->read_packet_dont_block(pktbuf, sizeof(pktbuf));
+ if (len < 0){
+ perror("usrp2_basic: read_packet_dont_block");
+ return;
+ }
+ if (len == 0)
+ break;
+
+ reply *rp = (reply *)pktbuf;
+ if (u2p_chan(&rp->h.fixed) != CONTROL_CHAN) // ignore
+ continue;
+ if (rp->op_id_reply.opcode != OP_ID_REPLY) // ignore
+ continue;
+
+ props p = reply_to_props(&rp->op_id_reply);
+ if (FIND_DEBUG)
+ std::cerr << "usrp2::find: response from " << p.addr << std::endl;
+
+ if ((target_addr == "") || (target_addr == p.addr))
+ result.push_back(p);
+ }
+ }
+
props_vector_t
find(const std::string &ifc, const std::string &addr)
{
@@ -43,15 +120,9 @@
props_vector_t result;
struct command {
u2_eth_packet_t h;
- op_id_t op_id;
+ op_generic_t op_id;
};
- struct reply {
- u2_eth_packet_t h;
- op_id_reply_t op_id_reply;
- };
-
- std::vector<op_id_reply_t> replies;
std::auto_ptr<ethernet> enet(new ethernet());
if (!enet->open(ifc, htons(U2_ETHERTYPE)))
@@ -77,7 +148,7 @@
u2p_set_word0(&c->h.fixed, 0, CONTROL_CHAN);
u2p_set_timestamp(&c->h.fixed, -1);
c->op_id.opcode = OP_ID;
- c->op_id.len = sizeof(op_id_t);
+ c->op_id.len = sizeof(c->op_id);
int len = std::max((size_t) ethernet::MIN_PKTLEN, sizeof(command));
if (enet->write_packet(c, len) != len)
return result;
@@ -86,50 +157,22 @@
std::cerr << "usrp2::find: broadcast ID command" << std::endl;
/*
- * Wait no longer than 10ms and read all packets available.
+ * Gather all responses that occur within 50ms
*/
- fd_set read_fds;
- FD_ZERO(&read_fds);
- FD_SET(enet->fd(), &read_fds);
- struct timeval timeout;
- timeout.tv_sec = 0;
- timeout.tv_usec = 10 * 1000; // 10 ms
-
- select(enet->fd()+1, &read_fds, 0, 0, &timeout);
- while(1) {
- memset(pktbuf, 0, sizeof(pktbuf));
- len = enet->read_packet_dont_block(pktbuf, sizeof(pktbuf));
- if (len < 0){
- perror("usrp2_basic: read_packet_dont_block");
- return result;
- }
- if (len == 0)
+ boost::posix_time::ptime
start(boost::posix_time::microsec_clock::universal_time());
+ boost::posix_time::ptime limit(start +
boost::posix_time::milliseconds(50));
+ boost::posix_time::ptime now;
+
+ while (1){
+ now = boost::posix_time::microsec_clock::universal_time();
+ if (now >= limit)
break;
-
- reply *rp = (reply *)pktbuf;
- if (u2p_chan(&rp->h.fixed) != CONTROL_CHAN) // ignore
- continue;
- if (rp->op_id_reply.opcode != OP_ID_REPLY) // ignore
- continue;
-
- const uint8_t *mac = (const uint8_t *)&rp->op_id_reply.addr;
- char addr_buf[128];
- snprintf(addr_buf, sizeof(addr_buf), "%02x:%02x:%02x:%02x:%02x:%02x",
- mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
-
- props p;
- p.addr = std::string(addr_buf);
- p.hw_rev = ntohs(rp->op_id_reply.hw_rev);
- memcpy(&p.fpga_md5sum, &rp->op_id_reply.fpga_md5sum,
sizeof(p.fpga_md5sum));
- memcpy(&p.sw_md5sum, &rp->op_id_reply.sw_md5sum, sizeof(p.sw_md5sum));
-
- if (FIND_DEBUG)
- std::cerr << "usrp2::find: response from " << p.addr << std::endl;
-
- if ((addr == "") || (addr == p.addr))
- result.push_back(p);
+
+ boost::posix_time::time_duration delta(limit - now);
+ struct timeval timeout = time_duration_to_timeval(delta);
+
+ read_replies(enet.get(), timeout, addr, result);
}
-
return result;
}
Copied: usrp2/trunk/host-ng/lib/ring.cc (from rev 9140,
usrp2/branches/developers/eb/merge-wip/host-ng/lib/ring.cc)
===================================================================
--- usrp2/trunk/host-ng/lib/ring.cc (rev 0)
+++ usrp2/trunk/host-ng/lib/ring.cc 2008-08-01 20:34:19 UTC (rev 9142)
@@ -0,0 +1,78 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2008 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "ring.h"
+
+namespace usrp2 {
+
+ ring::ring(unsigned int entries)
+ : d_max(entries), d_read_ind(0), d_write_ind(0), d_ring(entries),
+ d_mutex(), d_not_empty(&d_mutex)
+ {
+ for (unsigned int i = 0; i < entries; i++) {
+ d_ring[i].d_base = 0;
+ d_ring[i].d_len = 0;
+ }
+ }
+
+ void
+ ring::wait_for_not_empty()
+ {
+ omni_mutex_lock l(d_mutex);
+ while (empty())
+ d_not_empty.wait();
+ }
+
+ bool
+ ring::enqueue(void *p, size_t len)
+ {
+ omni_mutex_lock l(d_mutex);
+ if (full())
+ return false;
+
+ d_ring[d_write_ind].d_len = len;
+ d_ring[d_write_ind].d_base = p;
+
+ inc_write_ind();
+ d_not_empty.signal();
+ return true;
+ }
+
+ bool
+ ring::dequeue(void **p, size_t *len)
+ {
+ omni_mutex_lock l(d_mutex);
+ if (empty())
+ return false;
+
+ *p = d_ring[d_read_ind].d_base;
+ *len = d_ring[d_read_ind].d_len;
+
+ inc_read_ind();
+ return true;
+ }
+
+} // namespace usrp2
+
Copied: usrp2/trunk/host-ng/lib/ring.h (from rev 9140,
usrp2/branches/developers/eb/merge-wip/host-ng/lib/ring.h)
===================================================================
--- usrp2/trunk/host-ng/lib/ring.h (rev 0)
+++ usrp2/trunk/host-ng/lib/ring.h 2008-08-01 20:34:19 UTC (rev 9142)
@@ -0,0 +1,83 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2008 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef INCLUDED_RING_H
+#define INCLUDED_RING_H
+
+#include <omnithread.h>
+#include <stddef.h>
+#include <vector>
+#include <boost/shared_ptr.hpp>
+
+namespace usrp2 {
+
+ class ring;
+ typedef boost::shared_ptr<ring> ring_sptr;
+
+ class ring
+ {
+ private:
+
+ size_t d_max;
+ size_t d_read_ind;
+ size_t d_write_ind;
+
+ struct ring_desc
+ {
+ void *d_base;
+ size_t d_len;
+ };
+ std::vector<ring_desc> d_ring;
+
+ omni_mutex d_mutex;
+ omni_condition d_not_empty;
+
+ void inc_read_ind()
+ {
+ if (d_read_ind + 1 >= d_max)
+ d_read_ind = 0;
+ else
+ d_read_ind = d_read_ind + 1;
+ }
+
+ void inc_write_ind()
+ {
+ if (d_write_ind + 1 >= d_max)
+ d_write_ind = 0;
+ else
+ d_write_ind = d_write_ind + 1;
+ }
+
+ bool empty() const { return d_read_ind == d_write_ind; }
+ bool full() const { return (d_write_ind+1)%d_max == d_read_ind; }
+
+ public:
+
+ ring(unsigned int entries);
+
+ void wait_for_not_empty();
+
+ bool enqueue(void *p, size_t len);
+ bool dequeue(void **p, size_t *len);
+ };
+
+} // namespace usrp2
+
+#endif /* INCLUDED_RING_H */
Copied: usrp2/trunk/host-ng/lib/rx_sample_handler.cc (from rev 9140,
usrp2/branches/developers/eb/merge-wip/host-ng/lib/rx_sample_handler.cc)
===================================================================
--- usrp2/trunk/host-ng/lib/rx_sample_handler.cc
(rev 0)
+++ usrp2/trunk/host-ng/lib/rx_sample_handler.cc 2008-08-01 20:34:19 UTC
(rev 9142)
@@ -0,0 +1,27 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2008 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <usrp2/rx_sample_handler.h>
+
+usrp2::rx_sample_handler::~rx_sample_handler()
+{
+ // nop
+}
Copied: usrp2/trunk/host-ng/lib/strtod_si.c (from rev 9140,
usrp2/branches/developers/eb/merge-wip/host-ng/lib/strtod_si.c)
===================================================================
--- usrp2/trunk/host-ng/lib/strtod_si.c (rev 0)
+++ usrp2/trunk/host-ng/lib/strtod_si.c 2008-08-01 20:34:19 UTC (rev 9142)
@@ -0,0 +1,53 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <usrp2/strtod_si.h>
+#include <stdlib.h>
+
+#define true 1
+#define false 0
+
+int
+strtod_si(const char *s, double *result)
+{
+ *result = 0;
+
+ char *endptr;
+ double r = strtod(s, &endptr);
+ if (s == endptr)
+ return false;
+
+ switch (*endptr){
+ case 'p': r *= 1e-12; break;
+ case 'n': r *= 1e-9; break;
+ case 'u': r *= 1e-6; break;
+ case 'm': r *= 1e-3; break;
+ case 'k': r *= 1e3; break;
+ case 'M': r *= 1e6; break;
+ case 'G': r *= 1e9; break;
+ case 'T': r *= 1e12; break;
+ default:
+ // ignore. FIXME could be more robust
+ break;
+ }
+
+ *result = r;
+ return true;
+}
+
+
Modified: usrp2/trunk/host-ng/lib/usrp2.cc
===================================================================
--- usrp2/trunk/host-ng/lib/usrp2.cc 2008-08-01 20:25:36 UTC (rev 9141)
+++ usrp2/trunk/host-ng/lib/usrp2.cc 2008-08-01 20:34:19 UTC (rev 9142)
@@ -45,6 +45,8 @@
// NOP
}
+ // Receive
+
bool
usrp2::set_rx_gain(double gain)
{
@@ -52,9 +54,9 @@
}
bool
- usrp2::set_rx_freq(double frequency, usrp2_tune_result *result)
+ usrp2::set_rx_center_freq(double frequency, tune_result *result)
{
- return d_impl->set_rx_freq(frequency, result);
+ return d_impl->set_rx_center_freq(frequency, result);
}
bool
@@ -70,15 +72,98 @@
}
bool
- usrp2::start_rx_streaming(unsigned int items_per_frame)
+ usrp2::start_rx_streaming(unsigned int channel, unsigned int items_per_frame)
{
- return d_impl->start_rx_streaming(items_per_frame);
+ return d_impl->start_rx_streaming(channel, items_per_frame);
}
bool
- usrp2::stop_rx_streaming()
+ usrp2::rx_samples(unsigned int channel, rx_sample_handler *handler)
{
- return d_impl->stop_rx_streaming();
+ return d_impl->rx_samples(channel, handler);
}
+ bool
+ usrp2::stop_rx_streaming(unsigned int channel)
+ {
+ return d_impl->stop_rx_streaming(channel);
+ }
+
+ unsigned int
+ usrp2::rx_overruns()
+ {
+ return d_impl->rx_overruns();
+ }
+
+ unsigned int
+ usrp2::rx_missing()
+ {
+ return d_impl->rx_missing();
+ }
+
+ // Transmit
+
+ bool
+ usrp2::set_tx_gain(double gain)
+ {
+ return d_impl->set_tx_gain(gain);
+ }
+
+ bool
+ usrp2::set_tx_center_freq(double frequency, tune_result *result)
+ {
+ return d_impl->set_tx_center_freq(frequency, result);
+ }
+
+ bool
+ usrp2::set_tx_interp(int interpolation_factor)
+ {
+ return d_impl->set_tx_interp(interpolation_factor);
+ }
+
+ bool
+ usrp2::set_tx_scale_iq(int scale_i, int scale_q)
+ {
+ return d_impl->set_tx_scale_iq(scale_i, scale_q);
+ }
+
+ bool
+ usrp2::tx_complex_float(unsigned int channel,
+ const std::complex<float> *samples,
+ size_t nsamples,
+ const tx_metadata *metadata)
+ {
+ return d_impl->tx_complex_float(channel, samples, nsamples, metadata);
+ }
+
+ bool
+ usrp2::tx_complex_int16(unsigned int channel,
+ const std::complex<int16_t> *samples,
+ size_t nsamples,
+ const tx_metadata *metadata)
+ {
+ return d_impl->tx_complex_int16(channel, samples, nsamples, metadata);
+ }
+
+ bool
+ usrp2::tx_raw(unsigned int channel,
+ const uint32_t *items,
+ size_t nitems,
+ const tx_metadata *metadata)
+ {
+ return d_impl->tx_raw(channel, items, nitems, metadata);
+ }
+
} // namespace usrp2
+
+
+std::ostream& operator<<(std::ostream &os, const usrp2::props &x)
+{
+ os << x.addr;
+
+ char buf[128];
+ snprintf(buf, sizeof(buf)," hw_rev = 0x%04x", x.hw_rev);
+
+ os << buf;
+ return os;
+}
Copied: usrp2/trunk/host-ng/lib/usrp2_bytesex.h (from rev 9140,
usrp2/branches/developers/eb/merge-wip/host-ng/lib/usrp2_bytesex.h)
===================================================================
--- usrp2/trunk/host-ng/lib/usrp2_bytesex.h (rev 0)
+++ usrp2/trunk/host-ng/lib/usrp2_bytesex.h 2008-08-01 20:34:19 UTC (rev
9142)
@@ -0,0 +1,19 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2008 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gruel/inet.h>
Modified: usrp2/trunk/host-ng/lib/usrp2_impl.cc
===================================================================
--- usrp2/trunk/host-ng/lib/usrp2_impl.cc 2008-08-01 20:25:36 UTC (rev
9141)
+++ usrp2/trunk/host-ng/lib/usrp2_impl.cc 2008-08-01 20:34:19 UTC (rev
9142)
@@ -21,25 +21,36 @@
#endif
#include <usrp2/usrp2.h>
+#include <usrp2/tune_result.h>
+#include <usrp2/copiers.h>
+#include <gruel/inet.h>
#include <usrp2_types.h>
#include "usrp2_impl.h"
#include "usrp2_thread.h"
#include "eth_buffer.h"
#include "pktfilter.h"
#include "control.h"
+#include "ring.h"
#include <stdexcept>
#include <iostream>
#include <stdio.h>
+#include <stddef.h>
+#include <assert.h>
-#define USRP2_IMPL_DEBUG 1
+#define USRP2_IMPL_DEBUG 0
#if USRP2_IMPL_DEBUG
#define DEBUG_LOG(x) ::write(2, x, 1)
#else
#define DEBUG_LOG(x)
#endif
+static const int DEFAULT_RX_SCALE = 1024;
+static const int DEFAULT_TX_SCALE = 3000;
+
namespace usrp2 {
+ static const double DEF_CMD_TIMEOUT = 0.1;
+
std::string
opcode_to_string(int opcode)
{
@@ -56,12 +67,12 @@
case OP_CONFIG_TX_REPLY_V2: return "OP_CONFIG_TX_REPLY_V2";
case OP_START_RX_STREAMING: return "OP_START_RX_STREAMING";
case OP_STOP_RX: return "OP_STOP_RX";
- case OP_START_RX: return "OP_START_RX";
- case OP_CONFIG_TX: return "OP_CONFIG_TX";
+#if 0
case OP_WRITE_REG: return "OP_WRITE_REG";
case OP_WRITE_REG_MASKED: return "OP_WRITE_REG_MASKED";
case OP_READ_REG: return "OP_READ_REG";
case OP_READ_REG_REPLY: return "OP_READ_REG_REPLY";
+#endif
default:
char buf[64];
snprintf(buf, sizeof(buf), "<unknown opcode: %d>", opcode);
@@ -70,45 +81,87 @@
}
+ /*!
+ * \param p points to fixed header
+ * \param payload_len_in_bytes is length of the fixed hdr and the payload
+ * \param[out] items is set to point to the first uint32 item in the payload
+ * \param[out] nitems is set to the number of uint32 items in the payload
+ * \param[out] md is filled in with the parsed metadata from the frame.
+ */
+ static bool
+ parse_rx_metadata(void *p, size_t payload_len_in_bytes,
+ uint32_t **items, size_t *nitems_in_uint32s, rx_metadata
*md)
+ {
+ if (payload_len_in_bytes < sizeof(u2_fixed_hdr_t)) // invalid format
+ return false;
+
+ // FIXME deal with the fact that (p % 4) == 2
+ //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);
+
+ // md->start_of_burst = (md->word0 & XXX) != 0;
+ // md->end_of_burst = (md->word0 & XXX) != 0;
+ // md->rx_overrun = (md->word0 & XXX) != 0;
+
+ *items = (uint32_t *)(&fh[1]);
+ size_t nbytes = payload_len_in_bytes - sizeof(u2_fixed_hdr_t);
+ assert((nbytes % sizeof(uint32_t)) == 0);
+ *nitems_in_uint32s = nbytes / sizeof(uint32_t);
+
+ return true;
+ }
+
+
usrp2::impl::impl(const std::string &ifc, const std::string &addr)
- : d_buffer(new eth_buffer()), d_pf(0), d_bg_thread(0), d_bg_running(false),
+ : d_eth_buf(new eth_buffer()), d_pf(0), d_bg_thread(0),
d_bg_running(false),
d_rx_decim(0), d_rx_seqno(-1), d_tx_seqno(0), d_next_rid(0),
- d_num_rx_frames(0), d_num_rx_lost(0), d_num_rx_bytes(0),
- d_pending_replies(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)
{
props_vector_t u2s = find(ifc, addr);
if (u2s.size() != 1)
throw std::runtime_error("Unable to find requested USRP2.");
- if (!d_buffer->open(ifc, htons(U2_ETHERTYPE)))
+ if (!d_eth_buf->open(ifc, htons(U2_ETHERTYPE)))
throw std::runtime_error("Unable to register USRP2 protocol");
- d_pf = pktfilter::make_ethertype_inbound(U2_ETHERTYPE, d_buffer->mac());
- if (!d_pf || !d_buffer->attach_pktfilter(d_pf))
+ d_pf = pktfilter::make_ethertype_inbound(U2_ETHERTYPE, d_eth_buf->mac());
+ if (!d_pf || !d_eth_buf->attach_pktfilter(d_pf))
throw std::runtime_error("Unable to attach packet filter.");
d_addr = u2s[0].addr;
if (USRP2_IMPL_DEBUG)
std::cerr << "usrp2 constructor: using USRP2 at " << d_addr << std::endl;
-
+
+ memset(d_pending_replies, 0, sizeof(d_pending_replies));
+
d_bg_thread = new usrp2_thread(this);
d_bg_thread->start();
+
+ set_rx_scale_iq(DEFAULT_RX_SCALE, DEFAULT_RX_SCALE); // set workable
default
+ set_tx_scale_iq(DEFAULT_TX_SCALE, DEFAULT_TX_SCALE); // set workable
default
}
usrp2::impl::~impl()
{
-
stop_bg();
d_bg_thread = 0; // thread class deletes itself
delete d_pf;
- d_buffer->close();
- delete d_buffer;
+ d_eth_buf->close();
+ delete d_eth_buf;
if (USRP2_IMPL_DEBUG) {
- std::cerr << "usrp2 destructor: received " << d_num_rx_frames
- << " frames, with " << d_num_rx_lost << " lost ("
- << (int)(100.0*d_num_rx_lost/d_num_rx_frames)
+ std::cerr << std::endl
+ << "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;
}
@@ -145,7 +198,7 @@
{
p->ehdr.ethertype = htons(U2_ETHERTYPE);
parse_mac_addr(dst, &p->ehdr.dst);
- memcpy(&p->ehdr.src, d_buffer->mac(), 6);
+ 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;
@@ -156,7 +209,7 @@
int word0_flags, int chan, uint32_t timestamp)
{
init_et_hdrs(p, dst);
- u2p_set_word0(&p->fixed, 0, chan);
+ u2p_set_word0(&p->fixed, word0_flags, chan);
u2p_set_timestamp(&p->fixed, timestamp);
if (chan == CONTROL_CHAN) { // no sequence numbers, back it out
@@ -171,18 +224,198 @@
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(op_config_rx_v2_t);
- cmd->op.rid = d_next_rid++; // TODO: reserve rid=0
+ cmd->op.len = sizeof(cmd->op);
+ cmd->op.rid = d_next_rid++;
cmd->eop.opcode = OP_EOP;
- cmd->eop.len = sizeof(op_eop_t);
+ cmd->eop.len = sizeof(cmd->eop);
}
+ void
+ usrp2::impl::init_config_tx_v2_cmd(op_config_tx_v2_cmd *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);
+ cmd->op.rid = d_next_rid++;
+ cmd->eop.opcode = OP_EOP;
+ cmd->eop.len = sizeof(cmd->eop);
+ }
+
+ bool
+ usrp2::impl::transmit_cmd(void *cmd, size_t len, pending_reply *p, double
secs)
+ {
+ if (p)
+ d_pending_replies[p->rid()] = p;
+
+ // Transmit command
+ if (d_eth_buf->tx_frame(cmd, len) != eth_buffer::EB_OK) {
+ d_pending_replies[p->rid()] = 0;
+ return false;
+ }
+
+ int res = 1;
+ if (p)
+ res = p->wait(secs);
+
+ d_pending_replies[p->rid()] = 0;
+ return res == 1;
+ }
+
+ // ----------------------------------------------------------------
+ // Background loop: received packet demuxing
+ // ----------------------------------------------------------------
+
+ void
+ usrp2::impl::stop_bg()
+ {
+ d_bg_running = false;
+ d_bg_pending_cond.signal();
+
+ void *dummy_status;
+ d_bg_thread->join(&dummy_status);
+ }
+
+ void
+ usrp2::impl::bg_loop()
+ {
+ d_bg_running = true;
+ while(d_bg_running) {
+ DEBUG_LOG(":");
+ // Receive available frames from ethernet buffer. Handler will
+ // process control frames, enqueue data packets in channel
+ // 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;
+
+ // Wait for user API thread(s) to process all enqueued packets.
+ // The channel ring thread that decrements d_num_enqueued to zero
+ // will signal this thread to continue.
+ {
+ omni_mutex_lock l(d_enqueued_mutex);
+ while(d_num_enqueued > 0 && d_bg_running)
+ d_bg_pending_cond.wait();
+ }
+ }
+ d_bg_running = false;
+ }
+
+ //
+ // passed to eth_buffer::rx_frames
+ //
+ data_handler::result
+ usrp2::impl::operator()(const void *base, size_t len)
+ {
+ u2_eth_samples_t *pkt = (u2_eth_samples_t *)base;
+
+ // FIXME unaligned load!
+ int chan = u2p_chan(&pkt->hdrs.fixed);
+
+ if (chan == CONTROL_CHAN) { // control packets
+ DEBUG_LOG("c");
+ return handle_control_packet(base, len);
+ }
+ else { // data packets
+ return handle_data_packet(base, len);
+ }
+
+ // not reached
+ }
+
+ data_handler::result
+ usrp2::impl::handle_control_packet(const void *base, size_t len)
+ {
+ // 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];
+
+ pending_reply *rp = d_pending_replies[rid];
+ if (rp) {
+ unsigned int buflen = rp->len();
+ if (oplen != buflen) {
+ std::cerr << "usrp2: mismatched command reply length ("
+ << oplen << " != " << buflen << ")"
+ << std::endl;
+ }
+
+ // Copy reply into caller's buffer
+ memcpy(rp->buffer(), p, std::min(oplen, buflen));
+ rp->signal();
+ d_pending_replies[rid] = 0;
+ return data_handler::RELEASE;
+ }
+
+ // TODO: handle unsolicited, USRP2 initiated, or late replies
+ 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;
+
+ 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;
+ }
+ }
+
+ d_rx_seqno = pkt->hdrs.thdr.seqno;
+
+ /* --- end of fake transport layer handler --- */
+
+ // FIXME unaligned load!
+ unsigned int chan = u2p_chan(&pkt->hdrs.fixed);
+
+ if (!d_channel_rings[chan]) {
+ 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();
+ DEBUG_LOG("+");
+ return data_handler::KEEP; // channel ring runner will mark frame
done
+ }
+ else {
+ DEBUG_LOG("!");
+ return data_handler::RELEASE; // discard, no room in channel ring
+ }
+ return data_handler::RELEASE;
+ }
+
+ // ----------------------------------------------------------------
+ // Receive
+ // ----------------------------------------------------------------
+
bool
usrp2::impl::set_rx_gain(double gain)
{
- if (USRP2_IMPL_DEBUG)
- std::cerr << "usrp2: setting receive gain to " << gain << std::endl;
-
op_config_rx_v2_cmd cmd;
op_config_rx_reply_v2_t reply;
@@ -191,26 +424,16 @@
cmd.op.gain = htons(u2_double_to_fxpt_gain(gain));
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
- // enqueue p into pending list
-
- // Transmit command
- if (d_buffer->tx_frame(&cmd, sizeof(cmd)) != 1)
+ if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
- // Wait for reply or timeout
- if (p.wait(0, 10000000) == 0)
- return false;
-
- // Process reply here
- return true;
+ bool success = (ntohx(reply.ok) == 1);
+ return success;
}
bool
- usrp2::impl::set_rx_freq(double frequency, usrp2_tune_result *result)
+ usrp2::impl::set_rx_center_freq(double frequency, tune_result *result)
{
- if (USRP2_IMPL_DEBUG)
- std::cerr << "usrp2: setting frequency to " << frequency << std::endl;
-
op_config_rx_v2_cmd cmd;
op_config_rx_reply_v2_t reply;
@@ -221,245 +444,398 @@
cmd.op.freq_lo = htonl(u2_fxpt_freq_lo(fxpt));
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
- // enqueue p into pending list
-
- // Transmit command
- if (d_buffer->tx_frame(&cmd, sizeof(cmd)) != 1)
+ if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
- // Wait for reply or timeout
- if (p.wait(0, 10000000) == 0)
- return false;
+ 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),
+ ntohl(reply.baseband_freq_lo)));
- // Process reply here
- return true;
+ result->dxc_freq =
+ 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),
+ ntohl(reply.residual_freq_lo)));
+
+ result->spectrum_inverted = (bool)(ntohx(reply.inverted) == 1);
+ }
+
+ return success;
}
bool
usrp2::impl::set_rx_decim(int decimation_factor)
{
- if (USRP2_IMPL_DEBUG)
- std::cerr << "usrp2: setting receive decimation rate to "
- << decimation_factor << std::endl;
- uint8_t pktbuf[eth_buffer::MAX_PKTLEN];
- memset(pktbuf, 0, sizeof(pktbuf));
+ op_config_rx_v2_cmd cmd;
+ op_config_rx_reply_v2_t reply;
+
+ init_config_rx_v2_cmd(&cmd);
+ cmd.op.valid = htons(CFGV_INTERP_DECIM);
+ cmd.op.decim = htonl(decimation_factor);
- struct command {
- u2_eth_packet_t h;
- op_config_rx_v2_t op;
- op_eop_t eop;
- };
-
- command *c = (command *) pktbuf;
- init_etf_hdrs(&c->h, d_addr, 0, CONTROL_CHAN, -1);
-
- c->op.opcode = OP_CONFIG_RX_V2;
- c->op.len = sizeof(op_config_rx_v2_t);
- c->op.rid = d_next_rid++;
-
- c->op.valid = htons(CFGV_INTERP_DECIM);
- c->op.decim = htonl(decimation_factor);
-
- c->eop.opcode = OP_EOP;
- c->eop.len = sizeof(op_eop_t);
-
- int len = std::max((size_t) eth_buffer::MIN_PKTLEN, sizeof(command));
- if (d_buffer->tx_frame(c, len) != len)
+ pending_reply p(cmd.op.rid, &reply, sizeof(reply));
+ if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
-
- // FIXME wait for corresponding reply, etc.
-
- d_rx_decim = decimation_factor;
- return true;
+
+ bool success = (ntohx(reply.ok) == 1);
+ return success;
}
bool
usrp2::impl::set_rx_scale_iq(int scale_i, int scale_q)
{
- if (USRP2_IMPL_DEBUG)
- std::cerr << "usrp2: setting RX IQ scaling to "
- << scale_i << ", " << scale_q << std::endl;
+ op_config_rx_v2_cmd cmd;
+ op_config_rx_reply_v2_t reply;
+
+ 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));
- uint8_t pktbuf[eth_buffer::MAX_PKTLEN];
- memset(pktbuf, 0, sizeof(pktbuf));
-
- struct command {
- u2_eth_packet_t h;
- op_config_rx_v2_t op;
- op_eop_t eop;
- };
-
- command *c = (command *) pktbuf;
- init_etf_hdrs(&c->h, d_addr, 0, CONTROL_CHAN, -1);
-
- c->op.opcode = OP_CONFIG_RX_V2;
- c->op.len = sizeof(op_config_rx_v2_t);
- c->op.rid = d_next_rid++;
-
- c->op.valid = htons(CFGV_SCALE_IQ);
- c->op.scale_iq = htonl(((scale_i & 0xffff) << 16) | (scale_q & 0xffff));
-
- c->eop.opcode = OP_EOP;
- c->eop.len = sizeof(op_eop_t);
-
- int len = std::max((size_t) eth_buffer::MIN_PKTLEN, sizeof(command));
- if (d_buffer->tx_frame(c, len) != len)
+ pending_reply p(cmd.op.rid, &reply, sizeof(reply));
+ if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
-
- // FIXME wait for corresponding reply, etc.
-
- return true;
+
+ bool success = (ntohx(reply.ok) == 1);
+ return success;
}
bool
- usrp2::impl::start_rx_streaming(unsigned int items_per_frame)
+ usrp2::impl::start_rx_streaming(unsigned int channel, unsigned int
items_per_frame)
{
- // Assume for now rx format is complex floats
+ 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;
+ }
+
+ if (d_channel_rings[channel]) {
+ std::cerr << "usrp2: channel " << channel
+ << " already streaming" << std::endl;
+ return false;
+ }
+
+ d_channel_rings[channel] = ring_sptr(new ring(d_eth_buf->max_frames()));
+
if (items_per_frame == 0)
- items_per_frame = 250; // TODO: calculate from d_itemsize;
+ items_per_frame = U2_MAX_SAMPLES; // minimize overhead
- uint8_t pktbuf[eth_buffer::MAX_PKTLEN];
- memset(pktbuf, 0, sizeof(pktbuf));
+ 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, -1);
+ 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);
- struct command {
- u2_eth_packet_t h;
- op_start_rx_streaming_t op;
- op_eop_t eop;
- };
+ pending_reply p(cmd.op.rid, &reply, sizeof(reply));
+ if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
+ return false;
+
+ bool success = (ntohx(reply.ok) == 1);
+ return success;
+ }
+
+ bool
+ usrp2::impl::stop_rx_streaming(unsigned int channel)
+ {
+ 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;
+ }
+
+#if 0 // don't be overzealous.
+ if (!d_channel_rings[channel]) {
+ std::cerr << "usrp2: channel " << channel
+ << " not streaming" << std::endl;
+ return false;
+ }
+#endif
+
+ op_stop_rx_cmd cmd;
+ op_generic_t reply;
+
+ memset(&cmd, 0, sizeof(cmd));
+ init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
+ cmd.op.opcode = OP_STOP_RX;
+ cmd.op.len = sizeof(cmd.op);
+ cmd.op.rid = d_next_rid++;
+ cmd.eop.opcode = OP_EOP;
+ cmd.eop.len = sizeof(cmd.eop);
- command *c = (command *) pktbuf;
- init_etf_hdrs(&c->h, d_addr, 0, CONTROL_CHAN, -1);
-
- c->op.opcode = OP_START_RX_STREAMING;
- c->op.len = sizeof(op_start_rx_streaming_t);
- c->op.items_per_frame = htonl(items_per_frame);
-
- c->eop.opcode = OP_EOP;
- c->eop.len = sizeof(op_eop_t);
-
- int len = std::max((size_t) eth_buffer::MIN_PKTLEN, sizeof(command));
- if (d_buffer->tx_frame(c, len) != len)
+ pending_reply p(cmd.op.rid, &reply, sizeof(reply));
+ if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
-
- return true;
+
+ bool success = (ntohx(reply.ok) == 1);
+ if (success)
+ d_channel_rings[channel].reset();
+
+ return success;
}
+
bool
- usrp2::impl::stop_rx_streaming()
+ usrp2::impl::rx_samples(unsigned int channel, rx_sample_handler *handler)
{
- uint8_t pktbuf[eth_buffer::MAX_PKTLEN];
- memset(pktbuf, 0, sizeof(pktbuf));
+ if (channel > MAX_CHAN) {
+ std::cerr << "usrp2: invalid channel (" << channel
+ << " )" << std::endl;
+ return false;
+ }
- struct command {
- u2_eth_packet_t h;
- op_id_t op_stop_rx;
- };
+ if (channel > 0) {
+ std::cerr << "usrp2: channel " << channel
+ << " not implemented" << std::endl;
+ return false;
+ }
- command *c = (command *) pktbuf;
- init_etf_hdrs(&c->h, d_addr, 0, CONTROL_CHAN, -1);
-
- c->op_stop_rx.opcode = OP_STOP_RX;
- c->op_stop_rx.len = sizeof(op_stop_rx_t);
- int len = std::max((size_t) eth_buffer::MIN_PKTLEN, sizeof(command));
- if (d_buffer->tx_frame(c, len) != len)
+ 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;
+ while (rp->dequeue(&p, &frame_len_in_bytes)) {
+ uint32_t *items; // points to beginning of data
items
+ size_t nitems_in_uint32s;
+ rx_metadata md;
+ if (!parse_rx_metadata(p, frame_len_in_bytes, &items,
&nitems_in_uint32s, &md))
+ return false;
+
+ bool want_more = (*handler)(items, nitems_in_uint32s, &md);
+ d_eth_buf->release_frame(p);
+ DEBUG_LOG("-");
+ dec_enqueued();
+
+ if (!want_more)
+ break;
+ }
return true;
}
-
- void
- usrp2::impl::bg_loop()
+
+ // ----------------------------------------------------------------
+ // Transmit
+ // ----------------------------------------------------------------
+
+ bool
+ usrp2::impl::set_tx_gain(double gain)
{
- d_bg_running = true;
- while(d_bg_running) {
- int res = d_buffer->rx_frames(this, 1000);
- if (res == -1)
- break;
- }
+ op_config_tx_v2_cmd cmd;
+ op_config_tx_reply_v2_t reply;
+
+ 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(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
+ return false;
+
+ bool success = (ntohx(reply.ok) == 1);
+ return success;
}
- unsigned int
- usrp2::impl::operator()(const void *base, unsigned int len)
+ bool
+ usrp2::impl::set_tx_center_freq(double frequency, tune_result *result)
{
- u2_eth_samples_t *pkt = (u2_eth_samples_t *)base;
- int chan = u2p_chan(&pkt->hdrs.fixed);
+ op_config_tx_v2_cmd cmd;
+ op_config_tx_reply_v2_t reply;
- if (chan == CONTROL_CHAN) { // control packets
- DEBUG_LOG("C");
- return handle_control_packet(base, len);
+ init_config_tx_v2_cmd(&cmd);
+ cmd.op.valid = htons(CFGV_FREQ);
+ 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(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
+ return false;
+
+ 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),
+ ntohl(reply.baseband_freq_lo)));
+
+ result->dxc_freq =
+ 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),
+ ntohl(reply.residual_freq_lo)));
+
+ result->spectrum_inverted = (bool)(ntohx(reply.inverted) == 1);
}
- else { // data packets
- DEBUG_LOG("D");
- return handle_data_packet(base, len);
- }
- // not reached
+ return success;
}
+
+ bool
+ usrp2::impl::set_tx_interp(int interpolation_factor)
+ {
+ op_config_tx_v2_cmd cmd;
+ op_config_tx_reply_v2_t reply;
- unsigned int
- usrp2::impl::handle_control_packet(const void *base, unsigned int len)
- {
- // point to beginning of payload (subpackets)
- unsigned char *p = (unsigned char *)base + sizeof(u2_eth_packet_t);
+ init_config_tx_v2_cmd(&cmd);
+ cmd.op.valid = htons(CFGV_INTERP_DECIM);
+ cmd.op.interp = htonl(interpolation_factor);
- // FIXME iterate over payload, handling more than a single
- // subpacket, when (if?) the firmware starts sending them
-
- int opcode = p[0];
- int oplen = p[1];
- int rid = p[2];
+ pending_reply p(cmd.op.rid, &reply, sizeof(reply));
+ if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
+ return false;
- if (USRP2_IMPL_DEBUG) {
- std::cerr << "cmd reply: id=" << rid
- << " len=" << oplen
- << " op=" << opcode_to_string(opcode)
- << std::endl;
- }
-
- // handle command reply here
- return 0;
+ bool success = (ntohx(reply.ok) == 1);
+ return success;
}
- unsigned int
- usrp2::impl::handle_data_packet(const void *base, unsigned int len)
+ bool
+ usrp2::impl::set_tx_scale_iq(int scale_i, int scale_q)
{
- u2_eth_samples_t *pkt = (u2_eth_samples_t *)base;
- d_num_rx_frames++;
- d_num_rx_bytes += len;
+ op_config_tx_v2_cmd cmd;
+ op_config_tx_reply_v2_t reply;
+
+ 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));
- if (d_rx_seqno != -1) {
- int expected_seqno = (d_rx_seqno + 1) & 0xFF;
- int seqno = pkt->hdrs.thdr.seqno;
-
- if (seqno != expected_seqno) {
- ::write(2, "uS", 2); // missing sequence number
- int missing = expected_seqno - seqno;
- if (missing < 0)
- missing += 256;
-
- d_num_rx_lost += missing;
- }
- }
+ pending_reply p(cmd.op.rid, &reply, sizeof(reply));
+ if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
+ return false;
- d_rx_seqno = pkt->hdrs.thdr.seqno;
+ bool success = (ntohx(reply.ok) == 1);
+ return success;
+ }
- // enqueue in channel ring here
- return 0; // will be KEEP, as the channel ring runner will retire packet
+ bool
+ usrp2::impl::tx_complex_float(unsigned int channel,
+ const std::complex<float> *samples,
+ size_t nsamples,
+ const tx_metadata *metadata)
+ {
+ uint32_t items[nsamples];
+ copy_host_complex_float_to_u2_complex_16(nsamples, samples, items);
+ return tx_raw(channel, items, nsamples, metadata);
}
- void
- usrp2::impl::stop_bg()
+ bool
+ usrp2::impl::tx_complex_int16(unsigned int channel,
+ const std::complex<int16_t> *samples,
+ size_t nsamples,
+ const tx_metadata *metadata)
{
- if (USRP2_IMPL_DEBUG)
- std::cerr << "usrp2_thread::stop: joining background thread "
- << this << std::endl;
- d_bg_running = false;
-
- void *dummy_status;
- d_bg_thread->join(&dummy_status);
-
- if (USRP2_IMPL_DEBUG)
- std::cerr << "usrp2_thread::stop: join returned" << std::endl;
+#ifdef WORDS_BIGENDIAN
+
+ // Already binary equivalent to 16-bit I/Q on the wire.
+ // No conversion required.
+
+ assert(sizeof(samples[0]) == sizeof(uint32_t));
+ return tx_raw(channel, (const uint32_t *) samples, nsamples, metadata);
+
+#else
+
+ uint32_t items[nsamples];
+ copy_host_complex_16_to_u2_complex_16(nsamples, samples, items);
+ return tx_raw(channel, items, nsamples, metadata);
+
+#endif
}
-
+
+ bool
+ usrp2::impl::tx_raw(unsigned int channel,
+ const uint32_t *items,
+ size_t nitems,
+ const tx_metadata *metadata)
+ {
+ if (nitems == 0)
+ return true;
+
+ // FIXME there's the possibility that we send fewer than 9 items in a
frame.
+ // That would end up glitching the transmitter, since the ethernet will
pad to
+ // 64-bytes total (9 items). We really need some part of the stack to
+ // carry the real length (thdr?).
+
+ // fragment as necessary then fire away
+
+ size_t nframes = (nitems + U2_MAX_SAMPLES - 1) / U2_MAX_SAMPLES;
+ size_t last_frame = nframes - 1;
+ u2_eth_packet_t hdrs;
+
+ size_t n = 0;
+ for (size_t fn = 0; fn < nframes; fn++){
+ uint32_t timestamp = 0;
+ uint32_t flags = 0;
+
+ if (fn == 0){
+ timestamp = metadata->timestamp;
+ if (metadata->send_now)
+ flags |= U2P_TX_IMMEDIATE;
+ if (metadata->start_of_burst)
+ flags |= U2P_TX_START_OF_BURST;
+ }
+ if (fn > 0){
+ flags |= U2P_TX_IMMEDIATE;
+ }
+ if (fn == last_frame){
+ if (metadata->end_of_burst)
+ flags |= U2P_TX_END_OF_BURST;
+ }
+
+ init_etf_hdrs(&hdrs, d_addr, flags, channel, timestamp);
+
+ size_t i = std::min((size_t) U2_MAX_SAMPLES, nitems - n);
+
+ eth_iovec iov[2];
+ iov[0].iov_base = &hdrs;
+ iov[0].iov_len = sizeof(hdrs);
+ iov[1].iov_base = const_cast<uint32_t *>(&items[n]);
+ iov[1].iov_len = i * sizeof(uint32_t);
+
+ if (d_eth_buf->tx_framev(iov, 2) != eth_buffer::EB_OK){
+ return false;
+ }
+
+ n += i;
+ }
+
+ return true;
+ }
+
+
} // namespace usrp2
Modified: usrp2/trunk/host-ng/lib/usrp2_impl.h
===================================================================
--- usrp2/trunk/host-ng/lib/usrp2_impl.h 2008-08-01 20:25:36 UTC (rev
9141)
+++ usrp2/trunk/host-ng/lib/usrp2_impl.h 2008-08-01 20:34:19 UTC (rev
9142)
@@ -22,10 +22,10 @@
#include <usrp2/usrp2.h>
#include <usrp2/data_handler.h>
#include <usrp2_eth_packet.h>
+#include <boost/scoped_ptr.hpp>
#include "control.h"
-
+#include "ring.h"
#include <string>
-#include <list>
namespace usrp2 {
@@ -34,48 +34,95 @@
class usrp2_thread;
class usrp2_tune_result;
class pending_reply;
+ class ring;
- class usrp2::impl : public data_handler
+ class usrp2::impl : private data_handler
{
- eth_buffer *d_buffer;
- pktfilter *d_pf;
- std::string d_addr;
- usrp2_thread *d_bg_thread;
- volatile bool d_bg_running; // TODO: multistate if needed
+ static const size_t NRIDS = 256;
+ static const size_t NCHANS = 32;
+
+ eth_buffer *d_eth_buf;
+ pktfilter *d_pf;
+ std::string d_addr;
+ usrp2_thread *d_bg_thread;
+ volatile bool d_bg_running; // TODO: multistate if needed
- int d_rx_decim;
- int d_rx_seqno;
- int d_tx_seqno;
- int d_next_rid;
- unsigned int d_num_rx_frames;
- unsigned int d_num_rx_lost;
- unsigned int d_num_rx_bytes;
+ int d_rx_decim;
+ int d_rx_seqno;
+ int d_tx_seqno;
+ int d_next_rid;
+ unsigned int d_num_rx_frames;
+ unsigned int d_num_rx_missing;
+ unsigned int d_num_rx_overruns;
+ unsigned int d_num_rx_bytes;
+
+ unsigned int d_num_enqueued;
+ omni_mutex d_enqueued_mutex;
+ omni_condition d_bg_pending_cond;
+
+ // all pending_replies are stack allocated, thus no possibility of leaking
these
+ pending_reply *d_pending_replies[NRIDS]; // indexed by 8-bit reply id
+
+ std::vector<ring_sptr> d_channel_rings; // indexed by 5-bit channel
number
+
+ void inc_enqueued() {
+ omni_mutex_lock l(d_enqueued_mutex);
+ d_num_enqueued++;
+ }
- std::list<pending_reply *> d_pending_replies;
- omni_mutex d_reply_mutex;
-
+ 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,
int word0_flags, int chan, uint32_t timestamp);
void stop_bg();
void init_config_rx_v2_cmd(op_config_rx_v2_cmd *cmd);
- virtual unsigned int operator()(const void *base, unsigned int len);
- unsigned int handle_control_packet(const void *base, unsigned int len);
- unsigned int handle_data_packet(const void *base, unsigned int len);
+ void init_config_tx_v2_cmd(op_config_tx_v2_cmd *cmd);
+ bool transmit_cmd(void *cmd, size_t len, pending_reply *p, double
secs=0.0);
+ virtual data_handler::result operator()(const void *base, size_t len);
+ data_handler::result handle_control_packet(const void *base, size_t len);
+ data_handler::result handle_data_packet(const void *base, size_t len);
public:
impl(const std::string &ifc, const std::string &addr);
~impl();
void bg_loop();
+
bool set_rx_gain(double gain);
- bool set_rx_freq(double frequency, usrp2_tune_result *result);
+ bool set_rx_center_freq(double frequency, tune_result *result);
bool set_rx_decim(int decimation_factor);
bool set_rx_scale_iq(int scale_i, int scale_q);
- bool start_rx_streaming(unsigned int items_per_frame);
- bool stop_rx_streaming();
+ bool start_rx_streaming(unsigned int channel, unsigned int
items_per_frame);
+ bool rx_samples(unsigned int channel, rx_sample_handler *handler);
+ bool stop_rx_streaming(unsigned int channel);
+ unsigned int rx_overruns() const { return d_num_rx_overruns; }
+ unsigned int rx_missing() const { return d_num_rx_missing; }
+ bool set_tx_gain(double gain);
+ bool set_tx_center_freq(double frequency, tune_result *result);
+ bool set_tx_interp(int interpolation_factor);
+ bool set_tx_scale_iq(int scale_i, int scale_q);
+
+ bool tx_complex_float(unsigned int channel,
+ const std::complex<float> *samples,
+ size_t nsamples,
+ const tx_metadata *metadata);
+
+ bool tx_complex_int16(unsigned int channel,
+ const std::complex<int16_t> *samples,
+ size_t nsamples,
+ const tx_metadata *metadata);
+
+ bool tx_raw(unsigned int channel,
+ const uint32_t *items,
+ size_t nitems,
+ const tx_metadata *metadata);
};
} // namespace usrp2
Modified: usrp2/trunk/host-ng/lib/usrp2_thread.cc
===================================================================
--- usrp2/trunk/host-ng/lib/usrp2_thread.cc 2008-08-01 20:25:36 UTC (rev
9141)
+++ usrp2/trunk/host-ng/lib/usrp2_thread.cc 2008-08-01 20:34:19 UTC (rev
9142)
@@ -22,6 +22,7 @@
#include "usrp2_thread.h"
#include "usrp2_impl.h"
+#include <gruel/realtime.h>
#include <iostream>
#define USRP2_THREAD_DEBUG 1
@@ -43,23 +44,15 @@
void
usrp2_thread::start()
{
- if (USRP2_THREAD_DEBUG)
- std::cerr << "usrp2_thread::start() "
- << this << std::endl;
-
start_undetached();
}
void *
usrp2_thread::run_undetached(void *arg)
{
-#if 0
- // FIXME hoist this from gnuradio-core into another library.
- gr_rt_status_t rt = gr_enable_realtime_scheduling();
- if (rt != RT_OK)
- std::cerr << "failed to enable realtime scheduling\n";
-#endif
-
+ if (gruel::enable_realtime_scheduling() != gruel::RT_OK)
+ std::cerr << "usrp2: failed to enable realtime scheduling" << std::endl;
+
// This is the first code to run in the new thread context.
d_u2->bg_loop();
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Commit-gnuradio] r9142 - in usrp2/trunk: firmware firmware/apps firmware/include firmware/lib host/apps host-ng host-ng/apps host-ng/include/usrp2 host-ng/lib,
eb <=