summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--firmware/microblaze/lib/Makefile.inc1
-rw-r--r--firmware/microblaze/lib/eth_mac.c10
-rw-r--r--firmware/microblaze/lib/pic.c2
-rw-r--r--firmware/microblaze/usrp2/Makefile.am3
-rw-r--r--firmware/microblaze/usrp2/eth_phy.h (renamed from firmware/microblaze/lib/eth_phy.h)0
-rw-r--r--firmware/microblaze/usrp2/ethernet.c (renamed from firmware/microblaze/lib/ethernet.c)2
-rw-r--r--firmware/microblaze/usrp2p/Makefile.am3
-rw-r--r--firmware/microblaze/usrp2p/eth_phy.h235
-rw-r--r--firmware/microblaze/usrp2p/ethernet.c392
-rw-r--r--host/examples/benchmark_rx_rate.cpp2
-rw-r--r--host/include/uhd/device.hpp11
-rw-r--r--host/include/uhd/types/metadata.hpp48
-rw-r--r--host/include/uhd/usrp/simple_usrp.hpp6
-rw-r--r--host/lib/device.cpp2
-rw-r--r--host/lib/transport/udp_zero_copy_asio.cpp16
-rw-r--r--host/lib/transport/vrt_packet_handler.hpp35
-rw-r--r--host/lib/types.cpp12
-rw-r--r--host/lib/usrp/simple_usrp.cpp12
-rw-r--r--host/lib/usrp/usrp2/io_impl.cpp41
-rw-r--r--host/lib/usrp/usrp2/mboard_impl.cpp6
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.hpp2
-rw-r--r--host/lib/usrp/usrp2/usrp2_regs.cpp3
-rw-r--r--host/lib/usrp/usrp2/usrp2_regs.hpp12
23 files changed, 795 insertions, 61 deletions
diff --git a/firmware/microblaze/lib/Makefile.inc b/firmware/microblaze/lib/Makefile.inc
index 0e88298b8..02a267d35 100644
--- a/firmware/microblaze/lib/Makefile.inc
+++ b/firmware/microblaze/lib/Makefile.inc
@@ -25,7 +25,6 @@ COMMON_SRCS = \
$(top_srcdir)/lib/buffer_pool.c \
$(top_srcdir)/lib/dbsm.c \
$(top_srcdir)/lib/eeprom.c \
- $(top_srcdir)/lib/ethernet.c \
$(top_srcdir)/lib/eth_mac.c \
$(top_srcdir)/lib/_exit.c \
$(top_srcdir)/lib/exit.c \
diff --git a/firmware/microblaze/lib/eth_mac.c b/firmware/microblaze/lib/eth_mac.c
index 375d3f4d4..034a4d494 100644
--- a/firmware/microblaze/lib/eth_mac.c
+++ b/firmware/microblaze/lib/eth_mac.c
@@ -83,14 +83,6 @@ eth_mac_read_rmon(int addr)
int
eth_mac_miim_read(int addr)
{
- if (hwconfig_simulation_p()){
- switch(addr){
- case PHY_LINK_AN:
- return LANSR_MASTER | LANSR_LINK_GOOD | LANSR_SPEED_1000;
- default:
- return 0;
- }
- }
int phy_addr = PHY_ADDR;
eth_mac->miiaddress = ((addr & 0x1f) << 8) | phy_addr;
@@ -112,7 +104,7 @@ eth_mac_miim_write(int addr, int value)
eth_mac->miitx_data = value;
eth_mac->miicommand = MIIC_WCTRLDATA;
- //printf("MIIM-WRITE ADDR 0x%x VAL 0x%x\n",addr,value);
+// printf("MIIM-WRITE ADDR 0x%x VAL 0x%x\n",addr,value);
while((eth_mac->miistatus & MIIS_BUSY) != 0)
;
}
diff --git a/firmware/microblaze/lib/pic.c b/firmware/microblaze/lib/pic.c
index 4575bd775..e89d2b755 100644
--- a/firmware/microblaze/lib/pic.c
+++ b/firmware/microblaze/lib/pic.c
@@ -44,7 +44,7 @@ pic_init(void)
// uP is level triggered
pic_regs->mask = ~0; // mask all interrupts
- pic_regs->edge_enable = PIC_ONETIME_INT | PIC_PHY_INT;
+ pic_regs->edge_enable = PIC_ONETIME_INT;
pic_regs->polarity = ~0 & ~PIC_PHY_INT; // rising edge
pic_regs->pending = ~0; // clear all pending ints
}
diff --git a/firmware/microblaze/usrp2/Makefile.am b/firmware/microblaze/usrp2/Makefile.am
index 859ded9e5..b45d2481b 100644
--- a/firmware/microblaze/usrp2/Makefile.am
+++ b/firmware/microblaze/usrp2/Makefile.am
@@ -34,7 +34,8 @@ noinst_LIBRARIES = libusrp2.a
libusrp2_a_SOURCES = \
$(COMMON_SRCS) \
clocks.c \
- sd.c
+ sd.c \
+ ethernet.c
noinst_PROGRAMS = \
usrp2_txrx_uhd.elf
diff --git a/firmware/microblaze/lib/eth_phy.h b/firmware/microblaze/usrp2/eth_phy.h
index 6c16f97b7..6c16f97b7 100644
--- a/firmware/microblaze/lib/eth_phy.h
+++ b/firmware/microblaze/usrp2/eth_phy.h
diff --git a/firmware/microblaze/lib/ethernet.c b/firmware/microblaze/usrp2/ethernet.c
index 2d7c4d7bd..d60d7dc4c 100644
--- a/firmware/microblaze/lib/ethernet.c
+++ b/firmware/microblaze/usrp2/ethernet.c
@@ -27,7 +27,7 @@
#include "i2c.h"
#include "usrp2/fw_common.h"
-#define VERBOSE 0
+#define VERBOSE 1
static ethernet_t ed_state;
static ethernet_link_changed_callback_t ed_callback = 0;
diff --git a/firmware/microblaze/usrp2p/Makefile.am b/firmware/microblaze/usrp2p/Makefile.am
index eff544294..86affc1f3 100644
--- a/firmware/microblaze/usrp2p/Makefile.am
+++ b/firmware/microblaze/usrp2p/Makefile.am
@@ -49,7 +49,8 @@ libusrp2p_a_SOURCES = \
spif.c \
spi_flash.c \
spi_flash_read.c \
- bootloader_utils.c
+ bootloader_utils.c \
+ ethernet.c
noinst_PROGRAMS = \
usrp2p_txrx_uhd.elf \
diff --git a/firmware/microblaze/usrp2p/eth_phy.h b/firmware/microblaze/usrp2p/eth_phy.h
new file mode 100644
index 000000000..d233e96e8
--- /dev/null
+++ b/firmware/microblaze/usrp2p/eth_phy.h
@@ -0,0 +1,235 @@
+/* -*- c -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ *
+ * 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/>.
+ */
+
+/* Much of this was extracted from the Linux e1000_hw.h file */
+
+#ifndef INCLUDED_ETH_PHY_H
+#define INCLUDED_ETH_PHY_H
+
+/* PHY 1000 MII Register/Bit Definitions */
+/* PHY Registers defined by IEEE */
+
+#define PHY_CTRL 0x00 /* Control Register */
+#define PHY_STATUS 0x01 /* Status Regiser */
+#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */
+#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */
+#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */
+#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */
+#define PHY_AUTONEG_EXP 0x06 /* Autoneg Expansion Reg */
+#define PHY_NEXT_PAGE_TX 0x07 /* Next Page TX */
+#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */
+#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */
+#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
+#define PHY_EXT_STATUS 0x0F /* Extended Status Reg */
+
+/* PHY 1000 MII Register additions in ET1011C */
+#define PHY_INT_MASK 24
+#define PHY_INT_STATUS 25
+#define PHY_PHY_STATUS 26
+#define PHY_LED2 28
+
+/* Bit definitions for some of the registers above */
+
+/* PHY Control Register (PHY_CTRL) */
+#define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */
+#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */
+#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */
+#define MII_CR_ISOLATE 0x0400 /* Isolate PHY from MII */
+#define MII_CR_POWER_DOWN 0x0800 /* Power down */
+#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */
+#define MII_CR_SPEED_SELECT_LSB 0x2000 /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */
+#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */
+
+/* PHY Status Register (PHY_STATUS) */
+#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */
+#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */
+#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */
+#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */
+#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */
+#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */
+#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */
+#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */
+#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */
+#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */
+#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */
+#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */
+#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */
+#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */
+#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */
+
+/* Autoneg Advertisement Register (PHY_AUTONEG_ADV) */
+#define NWAY_AR_SELECTOR_FIELD 0x0001 /* indicates IEEE 802.3 CSMA/CD */
+#define NWAY_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */
+#define NWAY_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */
+#define NWAY_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */
+#define NWAY_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */
+#define NWAY_AR_100T4_CAPS 0x0200 /* 100T4 Capable */
+#define NWAY_AR_PAUSE 0x0400 /* Pause operation desired */
+#define NWAY_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */
+#define NWAY_AR_REMOTE_FAULT 0x2000 /* Remote Fault detected */
+#define NWAY_AR_NEXT_PAGE 0x8000 /* Next Page ability supported */
+
+/* Link Partner Ability Register (Base Page) (PHY_LP_ABILITY) */
+#define NWAY_LPAR_SELECTOR_FIELD 0x0000 /* LP protocol selector field */
+#define NWAY_LPAR_10T_HD_CAPS 0x0020 /* LP is 10T Half Duplex Capable */
+#define NWAY_LPAR_10T_FD_CAPS 0x0040 /* LP is 10T Full Duplex Capable */
+#define NWAY_LPAR_100TX_HD_CAPS 0x0080 /* LP is 100TX Half Duplex Capable */
+#define NWAY_LPAR_100TX_FD_CAPS 0x0100 /* LP is 100TX Full Duplex Capable */
+#define NWAY_LPAR_100T4_CAPS 0x0200 /* LP is 100T4 Capable */
+#define NWAY_LPAR_PAUSE 0x0400 /* LP Pause operation desired */
+#define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */
+#define NWAY_LPAR_REMOTE_FAULT 0x2000 /* LP has detected Remote Fault */
+#define NWAY_LPAR_ACKNOWLEDGE 0x4000 /* LP has rx'd link code word */
+#define NWAY_LPAR_NEXT_PAGE 0x8000 /* Next Page ability supported */
+
+/* Autoneg Expansion Register (PHY_AUTONEG_EXP) */
+#define NWAY_ER_LP_NWAY_CAPS 0x0001 /* LP has Auto Neg Capability */
+#define NWAY_ER_PAGE_RXD 0x0002 /* LP is 10T Half Duplex Capable */
+#define NWAY_ER_NEXT_PAGE_CAPS 0x0004 /* LP is 10T Full Duplex Capable */
+#define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */
+#define NWAY_ER_PAR_DETECT_FAULT 0x0010 /* LP is 100TX Full Duplex Capable */
+
+/* Next Page TX Register (PHY_NEXT_PAGE_TX) */
+#define NPTX_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */
+#define NPTX_TOGGLE 0x0800 /* Toggles between exchanges
+ * of different NP
+ */
+#define NPTX_ACKNOWLDGE2 0x1000 /* 1 = will comply with msg
+ * 0 = cannot comply with msg
+ */
+#define NPTX_MSG_PAGE 0x2000 /* formatted(1)/unformatted(0) pg */
+#define NPTX_NEXT_PAGE 0x8000 /* 1 = addition NP will follow
+ * 0 = sending last NP
+ */
+
+/* Link Partner Next Page Register (PHY_LP_NEXT_PAGE) */
+#define LP_RNPR_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */
+#define LP_RNPR_TOGGLE 0x0800 /* Toggles between exchanges
+ * of different NP
+ */
+#define LP_RNPR_ACKNOWLDGE2 0x1000 /* 1 = will comply with msg
+ * 0 = cannot comply with msg
+ */
+#define LP_RNPR_MSG_PAGE 0x2000 /* formatted(1)/unformatted(0) pg */
+#define LP_RNPR_ACKNOWLDGE 0x4000 /* 1 = ACK / 0 = NO ACK */
+#define LP_RNPR_NEXT_PAGE 0x8000 /* 1 = addition NP will follow
+ * 0 = sending last NP
+ */
+
+/* 1000BASE-T Control Register (PHY_1000T_CTRL) */
+#define CR_1000T_ASYM_PAUSE 0x0080 /* Advertise asymmetric pause bit */
+#define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */
+#define CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */
+#define CR_1000T_REPEATER_DTE 0x0400 /* 1=Repeater/switch device port */
+ /* 0=DTE device */
+#define CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master */
+ /* 0=Configure PHY as Slave */
+#define CR_1000T_MS_ENABLE 0x1000 /* 1=Master/Slave manual config value */
+ /* 0=Automatic Master/Slave config */
+#define CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */
+#define CR_1000T_TEST_MODE_1 0x2000 /* Transmit Waveform test */
+#define CR_1000T_TEST_MODE_2 0x4000 /* Master Transmit Jitter test */
+#define CR_1000T_TEST_MODE_3 0x6000 /* Slave Transmit Jitter test */
+#define CR_1000T_TEST_MODE_4 0x8000 /* Transmitter Distortion test */
+
+/* 1000BASE-T Status Register (PHY_1000T_STATUS) */
+#define SR_1000T_IDLE_ERROR_CNT 0x00FF /* Num idle errors since last read */
+#define SR_1000T_ASYM_PAUSE_DIR 0x0100 /* LP asymmetric pause direction bit */
+#define SR_1000T_LP_HD_CAPS 0x0400 /* LP is 1000T HD capable */
+#define SR_1000T_LP_FD_CAPS 0x0800 /* LP is 1000T FD capable */
+#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */
+#define SR_1000T_LOCAL_RX_STATUS 0x2000 /* Local receiver OK */
+#define SR_1000T_MS_CONFIG_RES 0x4000 /* 1=Local TX is Master, 0=Slave */
+#define SR_1000T_MS_CONFIG_FAULT 0x8000 /* Master/Slave config fault */
+#define SR_1000T_REMOTE_RX_STATUS_SHIFT 12
+#define SR_1000T_LOCAL_RX_STATUS_SHIFT 13
+#define SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT 5
+#define FFE_IDLE_ERR_COUNT_TIMEOUT_20 20
+#define FFE_IDLE_ERR_COUNT_TIMEOUT_100 100
+
+/* Extended Status Register (PHY_EXT_STATUS) */
+#define IEEE_ESR_1000T_HD_CAPS 0x1000 /* 1000T HD capable */
+#define IEEE_ESR_1000T_FD_CAPS 0x2000 /* 1000T FD capable */
+#define IEEE_ESR_1000X_HD_CAPS 0x4000 /* 1000X HD capable */
+#define IEEE_ESR_1000X_FD_CAPS 0x8000 /* 1000X FD capable */
+
+#define PHY_TX_POLARITY_MASK 0x0100 /* register 10h bit 8 (polarity bit) */
+#define PHY_TX_NORMAL_POLARITY 0 /* register 10h bit 8 (normal polarity) */
+
+#define AUTO_POLARITY_DISABLE 0x0010 /* register 11h bit 4 */
+ /* (0=enable, 1=disable) */
+
+/* PHY Status Register (PHY_PHY_STATUS) */
+#define PHYSTAT_ASYMMETRIC (1 << 0)
+#define PHYSTAT_PAUSE (1 << 1)
+#define PHYSTAT_AUTONEG_EN (1 << 2)
+#define PHYSTAT_COLLISION (1 << 3)
+#define PHYSTAT_RXSTAT (1 << 4)
+#define PHYSTAT_TXSTAT (1 << 5)
+#define PHYSTAT_LINK (1 << 6)
+#define PHYSTAT_DUPLEX (1 << 7)
+#define PHYSTAT_SPEED_MASK ((1 << 8) | (1 << 9))
+#define PHYSTAT_SPEED_1000 (1 << 9)
+#define PHYSTAT_SPEED_100 (1 << 8)
+#define PHYSTAT_SPEED_10 0
+#define PHYSTAT_POLARITY (1 << 10)
+#define PHYSTAT_MDIX (1 << 11)
+#define PHYSTAT_AUTONEG_STAT (1 << 12)
+#define PHYSTAT_STANDBY (1 << 13)
+
+/* Interrupt status, mask and clear regs (PHY_INT_{STATUS,MASK,CLEAR}) */
+#define PHY_INT_ENABLE (1 << 0)
+#define PHY_INT_DOWNSHIFT (1 << 1)
+#define PHY_INT_LINK_STATUS_CHANGE (1 << 2)
+#define PHY_INT_RX_STATUS_CHANGE (1 << 3)
+#define PHY_INT_FIFO_ERROR (1 << 4)
+#define PHY_INT_ERR_CTR_FULL (1 << 5)
+#define PHY_INT_NEXT_PAGE_RX (1 << 6)
+#define PHY_INT_CRC_ERROR (1 << 7)
+#define PHY_INT_AUTONEG_STATUS_CHANGE (1 << 8)
+#define PHY_INT_MDIO_SYNC_LOST (1 << 9)
+#define PHY_INT_TDR_IP_PHONE (1 << 10)
+
+/* PHY LED status register 2 (used for controlling link LED for activity light) */
+#define PHY_LED_TXRX_LSB 12
+#define PHY_LED_LINK_LSB 8
+#define PHY_LED_100_LSB 4
+#define PHY_LED_1000_LSB 0
+
+#define LED_1000 0
+#define LED_100_TX 1
+#define LED_10 2
+#define LED_1000_ON_100_BLINK 3
+#define LED_LINK 4
+#define LED_TX 5
+#define LED_RX 6
+#define LED_ACTIVITY 7
+#define LED_FULLDUPLEX 8
+#define LED_COLLISION 9
+#define LED_LINK_ON_ACTIVITY_BLINK 10
+#define LED_LINK_ON_RX_BLINK 11
+#define LED_FULL_DUPLEX_ON_COLLISION_BLINK 12
+#define LED_BLINK 13
+#define LED_ON 14
+#define LED_OFF 15
+
+
+#endif /* INCLUDED_ETH_PHY_H */
diff --git a/firmware/microblaze/usrp2p/ethernet.c b/firmware/microblaze/usrp2p/ethernet.c
new file mode 100644
index 000000000..07224d3b7
--- /dev/null
+++ b/firmware/microblaze/usrp2p/ethernet.c
@@ -0,0 +1,392 @@
+/*
+ * 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/>.
+ */
+
+//Changes for USRP2P: status registers different (ethernet.h)
+
+#include "ethernet.h"
+#include "memory_map.h"
+#include "eth_phy.h"
+#include <eth_mac.h>
+#include <eth_mac_regs.h>
+#include <pic.h>
+#include <hal_io.h>
+#include <nonstdio.h>
+#include <stdbool.h>
+#include <i2c.h>
+#include "usrp2/fw_common.h"
+
+#define VERBOSE 0
+
+static ethernet_t ed_state;
+static ethernet_link_changed_callback_t ed_callback = 0;
+
+void
+ethernet_register_link_changed_callback(ethernet_link_changed_callback_t new_callback)
+{
+ ed_callback = new_callback;
+}
+
+
+static void
+ed_set_mac_speed(int speed)
+{
+ printf("Speed set to %d\n",speed);
+ /*
+ switch(speed){
+ case 10:
+ eth_mac->speed = 1;
+ break;
+ case 100:
+ eth_mac->speed = 2;
+ break;
+ case 1000:
+ eth_mac->speed = 4;
+ break;
+ default:
+ break;
+ }
+ */
+}
+
+static void
+ed_link_up(int speed)
+{
+ // putstr("ed_link_up: "); puthex16_nl(speed);
+
+ ed_set_mac_speed(speed);
+
+ if (ed_callback) // fire link changed callback
+ (*ed_callback)(speed);
+}
+
+static void
+ed_link_down(void)
+{
+ // putstr("ed_link_down\n");
+
+ if (ed_callback) // fire link changed callback
+ (*ed_callback)(0);
+}
+
+
+static void
+ed_link_speed_change(int speed)
+{
+ ed_link_down();
+ ed_link_up(speed);
+}
+
+static void
+print_flow_control(int flow_control)
+{
+ static const char *flow_control_msg[4] = {
+ "NONE", "WE_TX", "WE_RX", "SYMMETRIC"
+ };
+ putstr("ethernet flow control: ");
+ puts(flow_control_msg[flow_control & 0x3]);
+}
+
+static void
+check_flow_control_resolution(void)
+{
+ static const unsigned char table[16] = {
+ // index = {local_asm, local_pause, partner_asm, partner_pause}
+ FC_NONE, FC_NONE, FC_NONE, FC_NONE,
+ FC_NONE, FC_SYMM, FC_NONE, FC_SYMM,
+ FC_NONE, FC_NONE, FC_NONE, FC_WE_TX,
+ FC_NONE, FC_SYMM, FC_WE_RX, FC_SYMM
+ };
+
+ int us = eth_mac_miim_read(PHY_AUTONEG_ADV);
+ int lp = eth_mac_miim_read(PHY_LP_ABILITY);
+ int index = (((us >> 10) & 0x3) << 2) | ((lp >> 10) & 0x3);
+ ed_state.flow_control = table[index];
+
+ if (1)
+ print_flow_control(ed_state.flow_control);
+}
+
+/*
+ * Read the PHY state register to determine link state and speed
+ */
+static void
+ed_check_phy_state(void)
+{
+ int phystat = eth_mac_miim_read(PHY_PHY_STATUS);
+ eth_link_state_t new_state = LS_UNKNOWN;
+ int new_speed = S_UNKNOWN;
+
+ if (VERBOSE){
+ putstr("PHYSTAT: ");
+ puthex16_nl(phystat);
+ }
+
+ if (phystat & PHYSTAT_LINK){ // link's up
+ if (VERBOSE)
+ puts(" LINK_GOOD");
+
+ new_state = LS_UP;
+ switch (phystat & PHYSTAT_SPEED_MASK){
+ case PHYSTAT_SPEED_10:
+ new_speed = 10;
+ break;
+
+ case PHYSTAT_SPEED_100:
+ new_speed = 100;
+ break;
+
+ case PHYSTAT_SPEED_1000:
+ new_speed = 1000;
+ break;
+
+ default:
+ new_speed = S_UNKNOWN;
+ break;
+ }
+
+ check_flow_control_resolution();
+ }
+ else { // link's down
+ if (VERBOSE)
+ puts(" NOT LINK_GOOD");
+
+ new_state = LS_DOWN;
+ new_speed = S_UNKNOWN;
+ }
+
+ if (new_state != ed_state.link_state){
+ ed_state.link_state = new_state; // remember new state
+ if (new_state == LS_UP)
+ ed_link_up(new_speed);
+ else if (new_state == LS_DOWN)
+ ed_link_down();
+ }
+ else if (new_state == LS_UP && new_speed != ed_state.link_speed){
+ ed_state.link_speed = new_speed; // remember new speed
+ ed_link_speed_change(new_speed);
+ }
+}
+
+/*
+ * This is fired when the ethernet PHY state changes
+ */
+static void
+eth_phy_irq_handler(unsigned irq)
+{
+ ed_check_phy_state();
+ eth_mac_miim_read(PHY_INT_STATUS);
+// eth_mac_miim_write(PHY_INT_CLEAR, ~0); // clear all ints
+}
+
+void
+ethernet_init(void)
+{
+ eth_mac_init(ethernet_mac_addr());
+
+ ed_state.link_state = LS_UNKNOWN;
+ ed_state.link_speed = S_UNKNOWN;
+
+ // initialize MAC registers
+ // eth_mac->tx_hwmark = 0x1e;
+ //eth_mac->tx_lwmark = 0x19;
+
+ //eth_mac->crc_chk_en = 1;
+ //eth_mac->rx_max_length = 2048;
+
+ // configure PAUSE frame stuff
+ //eth_mac->tx_pause_en = 1; // pay attn to pause frames sent to us
+
+ //eth_mac->pause_quanta_set = 38; // a bit more than 1 max frame 16kb/512 + fudge
+ //eth_mac->pause_frame_send_en = 1; // enable sending pause frames
+
+
+ // setup PHY to interrupt on changes
+
+ unsigned mask =
+ (PHY_INT_ENABLE //master interrupt enable
+ | PHY_INT_LINK_STATUS_CHANGE
+ | PHY_INT_RX_STATUS_CHANGE
+ );
+
+ eth_mac_miim_read(PHY_INT_STATUS); //clear interrupts
+ eth_mac_miim_write(PHY_INT_MASK, mask); // enable the ones we want
+
+ //set the LED behavior to activity instead of link
+ unsigned led = (LED_ACTIVITY << PHY_LED_LINK_LSB);
+ eth_mac_miim_write(PHY_LED2, led);
+
+ pic_register_handler(IRQ_PHY, eth_phy_irq_handler);
+
+ // Advertise our flow control configuation.
+ //
+ // We and the link partner each specify two bits in the base page
+ // related to autoconfiguration: NWAY_AR_PAUSE and NWAY_AR_ASM_DIR.
+ // The bits say what a device is "willing" to do, not what may actually
+ // happen as a result of the negotiation. There are 4 cases:
+ //
+ // PAUSE ASM_DIR
+ //
+ // 0 0 I have no flow control capability.
+ //
+ // 1 0 I both assert and respond to flow control.
+ //
+ // 0 1 I assert flow control, but cannot respond. That is,
+ // I want to be able to send PAUSE frames, but will ignore any
+ // you send to me. (This is our configuration.)
+ //
+ // 1 1 I can both assert and respond to flow control AND I am willing
+ // to operate symmetrically OR asymmetrically in EITHER direction.
+ // (We hope the link partner advertises this, otherwise we don't
+ // get what we want.)
+
+ int t = eth_mac_miim_read(PHY_AUTONEG_ADV);
+ t &= ~(NWAY_AR_PAUSE | NWAY_AR_ASM_DIR);
+ t |= NWAY_AR_ASM_DIR;
+
+ // Say we can't to 10BASE-T or 100BASE-TX, half or full duplex
+ t &= ~(NWAY_AR_10T_HD_CAPS | NWAY_AR_10T_FD_CAPS | NWAY_AR_100TX_HD_CAPS | NWAY_AR_100TX_FD_CAPS);
+
+ eth_mac_miim_write(PHY_AUTONEG_ADV, t);
+ int r = eth_mac_miim_read(PHY_AUTONEG_ADV); // DEBUG, read back
+ if (t != r){
+ printf("PHY_AUTONEG_ADV: wrote 0x%x, got 0x%x\n", t, r);
+ }
+
+ // Restart autonegotation.
+ // We want to ensure that we're advertising our PAUSE capabilities.
+ t = eth_mac_miim_read(PHY_CTRL);
+ eth_mac_miim_write(PHY_CTRL, t | MII_CR_RESTART_AUTO_NEG);
+}
+
+static bool
+unprogrammed(const void *t, size_t len)
+{
+ int i;
+ uint8_t *p = (uint8_t *)t;
+ bool all_zeros = true;
+ bool all_ones = true;
+ for (i = 0; i < len; i++){
+ all_zeros &= p[i] == 0x00;
+ all_ones &= p[i] == 0xff;
+ }
+ return all_ones | all_zeros;
+}
+
+//////////////////// MAC Addr Stuff ///////////////////////
+
+static int8_t src_mac_addr_initialized = false;
+static eth_mac_addr_t src_mac_addr = {{
+ 0x00, 0x50, 0xC2, 0x85, 0x3f, 0xff
+ }};
+
+const eth_mac_addr_t *
+ethernet_mac_addr(void)
+{
+ if (!src_mac_addr_initialized){ // fetch from eeprom
+ src_mac_addr_initialized = true;
+
+ // if we're simulating, don't read the EEPROM model, it's REALLY slow
+ if (hwconfig_simulation_p())
+ return &src_mac_addr;
+
+ eth_mac_addr_t tmp;
+ bool ok = eeprom_read(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_MAC_ADDR, &tmp, sizeof(tmp));
+ if (!ok || unprogrammed(&tmp, sizeof(tmp))){
+ // use the default
+ }
+ else
+ src_mac_addr = tmp;
+ }
+
+ return &src_mac_addr;
+}
+
+bool
+ethernet_set_mac_addr(const eth_mac_addr_t *t)
+{
+ bool ok = eeprom_write(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_MAC_ADDR, t, sizeof(eth_mac_addr_t));
+ if (ok){
+ src_mac_addr = *t;
+ src_mac_addr_initialized = true;
+ //eth_mac_set_addr(t); //this breaks the link
+ }
+
+ return ok;
+}
+
+//////////////////// IP Addr Stuff ///////////////////////
+
+static int8_t src_ip_addr_initialized = false;
+static struct ip_addr src_ip_addr = {
+ (192 << 24 | 168 << 16 | 10 << 8 | 2 << 0)
+};
+
+
+const struct ip_addr *get_ip_addr(void)
+{
+ if (!src_ip_addr_initialized){ // fetch from eeprom
+ src_ip_addr_initialized = true;
+
+ // if we're simulating, don't read the EEPROM model, it's REALLY slow
+ if (hwconfig_simulation_p())
+ return &src_ip_addr;
+
+ struct ip_addr tmp;
+ bool ok = eeprom_read(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_IP_ADDR, &tmp, sizeof(tmp));
+ if (!ok || unprogrammed(&tmp, sizeof(tmp))){
+ // use the default
+ }
+ else
+ src_ip_addr = tmp;
+ }
+
+ return &src_ip_addr;
+}
+
+bool set_ip_addr(const struct ip_addr *t){
+ bool ok = eeprom_write(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_IP_ADDR, t, sizeof(struct ip_addr));
+ if (ok){
+ src_ip_addr = *t;
+ src_ip_addr_initialized = true;
+ }
+
+ return ok;
+}
+
+int
+ethernet_check_errors(void)
+{
+ // these registers are reset when read
+
+ int r = 0;
+ /*
+ if (eth_mac_read_rmon(0x05) != 0)
+ r |= RME_RX_CRC;
+ if (eth_mac_read_rmon(0x06) != 0)
+ r |= RME_RX_FIFO_FULL;
+ if (eth_mac_read_rmon(0x07) != 0)
+ r |= RME_RX_2SHORT_2LONG;
+
+ if (eth_mac_read_rmon(0x25) != 0)
+ r |= RME_TX_JAM_DROP;
+ if (eth_mac_read_rmon(0x26) != 0)
+ r |= RME_TX_FIFO_UNDER;
+ if (eth_mac_read_rmon(0x27) != 0)
+ r |= RME_TX_FIFO_OVER;
+ */
+ return r;
+}
diff --git a/host/examples/benchmark_rx_rate.cpp b/host/examples/benchmark_rx_rate.cpp
index 752facb0d..8fae813cf 100644
--- a/host/examples/benchmark_rx_rate.cpp
+++ b/host/examples/benchmark_rx_rate.cpp
@@ -66,7 +66,7 @@ static inline void test_device(
//handle the error codes
switch(md.error_code){
case uhd::rx_metadata_t::ERROR_CODE_NONE:
- case uhd::rx_metadata_t::ERROR_CODE_OVERRUN:
+ case uhd::rx_metadata_t::ERROR_CODE_OVERFLOW:
break;
default:
diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp
index ee297ec8a..78bb83c66 100644
--- a/host/include/uhd/device.hpp
+++ b/host/include/uhd/device.hpp
@@ -219,6 +219,17 @@ public:
*/
virtual size_t get_max_recv_samps_per_packet(void) const = 0;
+ /*!
+ * Receive and asynchronous message from the device.
+ * \param async_metadata the metadata to be filled in
+ * \param timeout_ms the timeout in milliseconds to wait for a message
+ * \return true when the async_metadata is valid, false for timeout
+ */
+ virtual bool recv_async_msg(
+ async_metadata_t &async_metadata,
+ size_t timeout_ms = default_recv_timeout_ms
+ ) = 0;
+
};
} //namespace uhd
diff --git a/host/include/uhd/types/metadata.hpp b/host/include/uhd/types/metadata.hpp
index 039196250..65952941c 100644
--- a/host/include/uhd/types/metadata.hpp
+++ b/host/include/uhd/types/metadata.hpp
@@ -26,7 +26,7 @@ namespace uhd{
/*!
* RX metadata structure for describing sent IF data.
- * Includes stream ID, time specification, and fragmentation flags.
+ * Includes time specification, fragmentation flags, burst flags, and error codes.
* The receive routines will convert IF data headers into metadata.
*/
struct UHD_API rx_metadata_t{
@@ -62,7 +62,7 @@ namespace uhd{
* - timeout: no packet received, underlying code timed-out
* - late command: a stream command was issued in the past
* - broken chain: expected another stream command
- * - overrun: an internal receive buffer has overrun
+ * - overflow: an internal receive buffer has filled
* - bad packet: the buffer was unrecognizable as a vrt packet
*
* Note: When an overrun occurs in continuous streaming mode,
@@ -74,27 +74,21 @@ namespace uhd{
* - none
* - late command
* - broken chain
- * - overrun
+ * - overflow
*/
enum error_code_t {
ERROR_CODE_NONE = 0x0,
ERROR_CODE_TIMEOUT = 0x1,
ERROR_CODE_LATE_COMMAND = 0x2,
ERROR_CODE_BROKEN_CHAIN = 0x4,
- ERROR_CODE_OVERRUN = 0x8,
+ ERROR_CODE_OVERFLOW = 0x8,
ERROR_CODE_BAD_PACKET = 0xf
} error_code;
-
- /*!
- * The default constructor:
- * Sets the fields to default values (flags set to false).
- */
- rx_metadata_t(void);
};
/*!
* TX metadata structure for describing received IF data.
- * Includes stream ID, time specification, and burst flags.
+ * Includes time specification, and start and stop burst flags.
* The send routines will convert the metadata to IF data headers.
*/
struct UHD_API tx_metadata_t{
@@ -121,6 +115,38 @@ namespace uhd{
tx_metadata_t(void);
};
+ /*!
+ * Async metadata structure for describing transmit related events.
+ */
+ struct UHD_API async_metadata_t{
+ //! The channel number in a mimo configuration
+ size_t channel;
+
+ /*!
+ * Time specification: when the async event occurred.
+ */
+ bool has_time_spec;
+ time_spec_t time_spec;
+
+ /*!
+ * Event codes:
+ * - success: a packet was successfully transmitted
+ * - underflow: an internal send buffer has emptied
+ * - sequence error: packet loss between host and device
+ * - time error: packet had time that was late (or too early)
+ * - underflow in packet: underflow occurred inside a packet
+ * - sequence error in burst: packet loss within a burst
+ */
+ enum event_code_t {
+ EVENT_CODE_SUCCESS = 0x1,
+ EVENT_CODE_UNDERFLOW = 0x2,
+ EVENT_CODE_SEQ_ERROR = 0x4,
+ EVENT_CODE_TIME_ERROR = 0x8,
+ EVENT_CODE_UNDERFLOW_IN_PACKET = 0x10,
+ EVENT_CODE_SEQ_ERROR_IN_BURST = 0x20
+ } event_code;
+ };
+
} //namespace uhd
#endif /* INCLUDED_UHD_TYPES_METADATA_HPP */
diff --git a/host/include/uhd/usrp/simple_usrp.hpp b/host/include/uhd/usrp/simple_usrp.hpp
index a100579ce..8fc6d59d9 100644
--- a/host/include/uhd/usrp/simple_usrp.hpp
+++ b/host/include/uhd/usrp/simple_usrp.hpp
@@ -152,6 +152,12 @@ public:
virtual std::vector<std::string> get_tx_antennas(void) = 0;
virtual bool get_tx_lo_locked(void) = 0;
+
+ /*******************************************************************
+ * Interface access methods
+ ******************************************************************/
+ virtual wax::obj get_rx_dboard_iface(void) = 0;
+ virtual wax::obj get_tx_dboard_iface(void) = 0;
};
}}
diff --git a/host/lib/device.cpp b/host/lib/device.cpp
index 431595c4f..d575ebaab 100644
--- a/host/lib/device.cpp
+++ b/host/lib/device.cpp
@@ -12,7 +12,7 @@
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
-// asize_t with this program. If not, see <http://www.gnu.org/licenses/>.
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
#include <uhd/device.hpp>
diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp
index bfbcf62d8..bbbabf6d0 100644
--- a/host/lib/transport/udp_zero_copy_asio.cpp
+++ b/host/lib/transport/udp_zero_copy_asio.cpp
@@ -29,7 +29,11 @@ using namespace uhd::transport;
* Constants
**********************************************************************/
//enough buffering for half a second of samples at full rate on usrp2
-static const size_t MIN_SOCK_BUFF_SIZE = size_t(sizeof(boost::uint32_t) * 25e6 * 0.5);
+static const size_t MIN_RECV_SOCK_BUFF_SIZE = size_t(sizeof(boost::uint32_t) * 25e6 * 0.5);
+//Large buffers cause more underflow at high rates.
+//Perhaps this is due to the kernel scheduling,
+//but may change with host-based flow control.
+static const size_t MIN_SEND_SOCK_BUFF_SIZE = size_t(10e3);
static const double RECV_TIMEOUT = 0.1; //100 ms
/***********************************************************************
@@ -143,6 +147,10 @@ template<typename Opt> static void resize_buff_helper(
size_t target_size,
const std::string &name
){
+ size_t min_sock_buff_size = 0;
+ if (name == "recv") min_sock_buff_size = MIN_RECV_SOCK_BUFF_SIZE;
+ if (name == "send") min_sock_buff_size = MIN_SEND_SOCK_BUFF_SIZE;
+
//resize the buffer if size was provided
if (target_size > 0){
size_t actual_size = udp_trans->resize_buff<Opt>(target_size);
@@ -158,14 +166,14 @@ template<typename Opt> static void resize_buff_helper(
" The %s buffer is smaller than the requested size.\n"
" The minimum recommended buffer size is %d bytes.\n"
" See the USRP2 application notes on buffer resizing.\n"
- ) % name % MIN_SOCK_BUFF_SIZE << std::endl;
+ ) % name % min_sock_buff_size << std::endl;
}
//only enable on platforms that are happy with the large buffer resize
#if defined(UHD_PLATFORM_LINUX) || defined(UHD_PLATFORM_WIN32)
//otherwise, ensure that the buffer is at least the minimum size
- else if (udp_trans->get_buff_size<Opt>() < MIN_SOCK_BUFF_SIZE){
- resize_buff_helper<Opt>(udp_trans, MIN_SOCK_BUFF_SIZE, name);
+ else if (udp_trans->get_buff_size<Opt>() < min_sock_buff_size){
+ resize_buff_helper<Opt>(udp_trans, min_sock_buff_size, name);
}
#endif /*defined(UHD_PLATFORM_LINUX) || defined(UHD_PLATFORM_WIN32)*/
}
diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp
index cf9d649dd..7e0588f03 100644
--- a/host/lib/transport/vrt_packet_handler.hpp
+++ b/host/lib/transport/vrt_packet_handler.hpp
@@ -35,15 +35,25 @@
namespace vrt_packet_handler{
+template <typename T> UHD_INLINE T get_context_code(
+ const boost::uint32_t *vrt_hdr,
+ const uhd::transport::vrt::if_packet_info_t &if_packet_info
+){
+ //extract the context word (we dont know the endianness so mirror the bytes)
+ boost::uint32_t word0 = vrt_hdr[if_packet_info.num_header_words32] |
+ uhd::byteswap(vrt_hdr[if_packet_info.num_header_words32]);
+ return T(word0 & 0xff);
+}
+
/***********************************************************************
* vrt packet handler for recv
**********************************************************************/
typedef std::vector<uhd::transport::managed_recv_buffer::sptr> managed_recv_buffs_t;
typedef boost::function<bool(managed_recv_buffs_t &)> get_recv_buffs_t;
- typedef boost::function<void(size_t /*which channel*/)> handle_overrun_t;
+ typedef boost::function<void(size_t /*which channel*/)> handle_overflow_t;
typedef boost::function<void(const boost::uint32_t *, uhd::transport::vrt::if_packet_info_t &)> vrt_unpacker_t;
- static inline void handle_overrun_nop(size_t){}
+ static inline void handle_overflow_nop(size_t){}
struct recv_state{
//width of the receiver in channels
@@ -75,7 +85,7 @@ namespace vrt_packet_handler{
uhd::rx_metadata_t &metadata,
double tick_rate,
const vrt_unpacker_t &vrt_unpacker,
- const handle_overrun_t &handle_overrun,
+ const handle_overflow_t &handle_overflow,
size_t vrt_header_offset_words32
){
//vrt unpack each managed buffer
@@ -92,22 +102,19 @@ namespace vrt_packet_handler{
const boost::uint32_t *vrt_hdr = state.managed_buffs[i]->cast<const boost::uint32_t *>() + vrt_header_offset_words32;
if_packet_info.num_packet_words32 = num_packet_words32 - vrt_header_offset_words32;
vrt_unpacker(vrt_hdr, if_packet_info);
- const boost::uint32_t *vrt_data = vrt_hdr + if_packet_info.num_header_words32;
//handle the non-data packet case and parse its contents
if (if_packet_info.packet_type != uhd::transport::vrt::if_packet_info_t::PACKET_TYPE_DATA){
- //extract the context word (we dont know the endianness so mirror the bytes)
- boost::uint32_t word0 = vrt_data[0] | uhd::byteswap(vrt_data[0]);
- if (word0 & uhd::rx_metadata_t::ERROR_CODE_OVERRUN) handle_overrun(i);
- metadata.error_code = uhd::rx_metadata_t::error_code_t(word0 & 0xf);
+ metadata.error_code = get_context_code<uhd::rx_metadata_t::error_code_t>(vrt_hdr, if_packet_info);
+ if (metadata.error_code == uhd::rx_metadata_t::ERROR_CODE_OVERFLOW) handle_overflow(i);
//break to exit loop and store metadata below
state.size_of_copy_buffs = 0; break;
}
//setup the buffer to point to the data
- state.copy_buffs[i] = reinterpret_cast<const boost::uint8_t *>(vrt_data);
+ state.copy_buffs[i] = reinterpret_cast<const boost::uint8_t *>(vrt_hdr + if_packet_info.num_header_words32);
//store the minimum payload length into the copy buffer length
size_t num_payload_bytes = if_packet_info.num_payload_words32*sizeof(boost::uint32_t);
@@ -142,7 +149,7 @@ namespace vrt_packet_handler{
double tick_rate,
const vrt_unpacker_t &vrt_unpacker,
const get_recv_buffs_t &get_recv_buffs,
- const handle_overrun_t &handle_overrun,
+ const handle_overflow_t &handle_overflow,
size_t vrt_header_offset_words32
){
metadata.error_code = uhd::rx_metadata_t::ERROR_CODE_NONE;
@@ -157,7 +164,7 @@ namespace vrt_packet_handler{
try{
_recv1_helper(
state, metadata, tick_rate,
- vrt_unpacker, handle_overrun,
+ vrt_unpacker, handle_overflow,
vrt_header_offset_words32
);
}catch(const std::exception &e){
@@ -216,7 +223,7 @@ namespace vrt_packet_handler{
double tick_rate,
const vrt_unpacker_t &vrt_unpacker,
const get_recv_buffs_t &get_recv_buffs,
- const handle_overrun_t &handle_overrun = &handle_overrun_nop,
+ const handle_overflow_t &handle_overflow = &handle_overflow_nop,
size_t vrt_header_offset_words32 = 0
){
switch(recv_mode){
@@ -233,7 +240,7 @@ namespace vrt_packet_handler{
tick_rate,
vrt_unpacker,
get_recv_buffs,
- handle_overrun,
+ handle_overflow,
vrt_header_offset_words32
);
}
@@ -253,7 +260,7 @@ namespace vrt_packet_handler{
tick_rate,
vrt_unpacker,
get_recv_buffs,
- handle_overrun,
+ handle_overflow,
vrt_header_offset_words32
);
if (num_samps == 0) break; //had a recv timeout or error, break loop
diff --git a/host/lib/types.cpp b/host/lib/types.cpp
index fdc435fef..1cfe84832 100644
--- a/host/lib/types.cpp
+++ b/host/lib/types.cpp
@@ -98,18 +98,6 @@ stream_cmd_t::stream_cmd_t(const stream_mode_t &stream_mode):
/***********************************************************************
* metadata
**********************************************************************/
-rx_metadata_t::rx_metadata_t(void):
- has_time_spec(false),
- time_spec(time_spec_t()),
- more_fragments(false),
- fragment_offset(0),
- start_of_burst(false),
- end_of_burst(false),
- error_code(ERROR_CODE_NONE)
-{
- /* NOP */
-}
-
tx_metadata_t::tx_metadata_t(void):
has_time_spec(false),
time_spec(time_spec_t()),
diff --git a/host/lib/usrp/simple_usrp.cpp b/host/lib/usrp/simple_usrp.cpp
index 704232782..a8c20c439 100644
--- a/host/lib/usrp/simple_usrp.cpp
+++ b/host/lib/usrp/simple_usrp.cpp
@@ -228,6 +228,18 @@ public:
return _tx_subdev[SUBDEV_PROP_LO_LOCKED].as<bool>();
}
+ /*******************************************************************
+ * Interface access methods
+ ******************************************************************/
+
+ wax::obj get_rx_dboard_iface(void) {
+ return _rx_dboard;
+ }
+
+ wax::obj get_tx_dboard_iface(void) {
+ return _tx_dboard;
+ }
+
private:
device::sptr _dev;
wax::obj _mboard;
diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp
index 7e7ce40a2..aa6d15783 100644
--- a/host/lib/usrp/usrp2/io_impl.cpp
+++ b/host/lib/usrp/usrp2/io_impl.cpp
@@ -32,6 +32,8 @@ using namespace uhd::usrp;
using namespace uhd::transport;
namespace asio = boost::asio;
+static const int underflow_flags = async_metadata_t::EVENT_CODE_UNDERFLOW | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET;
+
/***********************************************************************
* io impl details (internal to this file)
* - pirate crew
@@ -44,7 +46,8 @@ struct usrp2_impl::io_impl{
io_impl(size_t num_frames, size_t width):
packet_handler_recv_state(width),
- recv_pirate_booty(alignment_buffer_type::make(num_frames, width))
+ recv_pirate_booty(alignment_buffer_type::make(num_frames, width)),
+ async_msg_fifo(bounded_buffer<async_metadata_t>::make(100/*messages deep*/))
{
/* NOP */
}
@@ -69,6 +72,7 @@ struct usrp2_impl::io_impl{
boost::thread_group recv_pirate_crew;
bool recv_pirate_crew_raiding;
alignment_buffer_type::sptr recv_pirate_booty;
+ bounded_buffer<async_metadata_t>::sptr async_msg_fifo;
};
/***********************************************************************
@@ -93,12 +97,31 @@ void usrp2_impl::io_impl::recv_pirate_loop(
//extract the vrt header packet info
vrt::if_packet_info_t if_packet_info;
if_packet_info.num_packet_words32 = buff->size()/sizeof(boost::uint32_t);
- vrt::if_hdr_unpack_be(buff->cast<const boost::uint32_t *>(), if_packet_info);
+ const boost::uint32_t *vrt_hdr = buff->cast<const boost::uint32_t *>();
+ vrt::if_hdr_unpack_be(vrt_hdr, if_packet_info);
+
+ //handle a tx async report message
+ if (if_packet_info.sid == 1 and if_packet_info.packet_type != vrt::if_packet_info_t::PACKET_TYPE_DATA){
+
+ //fill in the async metadata
+ async_metadata_t metadata;
+ metadata.channel = index;
+ metadata.has_time_spec = if_packet_info.has_tsi and if_packet_info.has_tsf;
+ metadata.time_spec = time_spec_t(
+ time_t(if_packet_info.tsi), size_t(if_packet_info.tsf), mboard->get_master_clock_freq()
+ );
+ metadata.event_code = vrt_packet_handler::get_context_code<async_metadata_t::event_code_t>(vrt_hdr, if_packet_info);
+
+ //print the famous U, and push the metadata into the message queue
+ if (metadata.event_code & underflow_flags) std::cerr << "U";
+ async_msg_fifo->push_with_pop_on_full(metadata);
+ continue;
+ }
//handle the packet count / sequence number
if (if_packet_info.packet_count != next_packet_seq){
//std::cerr << "S" << (if_packet_info.packet_count - next_packet_seq)%16;
- std::cerr << "O"; //report overrun (drops in the kernel)
+ std::cerr << "O"; //report overflow (drops in the kernel)
}
next_packet_seq = (if_packet_info.packet_count+1)%16;
@@ -150,6 +173,18 @@ void usrp2_impl::io_init(void){
}
/***********************************************************************
+ * Async Data
+ **********************************************************************/
+bool usrp2_impl::recv_async_msg(
+ async_metadata_t &async_metadata, size_t timeout_ms
+){
+ boost::this_thread::disable_interruption di; //disable because the wait can throw
+ return _io_impl->async_msg_fifo->pop_with_timed_wait(
+ async_metadata, boost::posix_time::milliseconds(timeout_ms)
+ );
+}
+
+/***********************************************************************
* Send Data
**********************************************************************/
bool get_send_buffs(
diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp
index d6a129415..7243880f3 100644
--- a/host/lib/usrp/usrp2/mboard_impl.cpp
+++ b/host/lib/usrp/usrp2/mboard_impl.cpp
@@ -75,6 +75,7 @@ usrp2_mboard_impl::usrp2_mboard_impl(
_iface->poke32(_iface->regs.rx_ctrl_nchannels, 1);
_iface->poke32(_iface->regs.rx_ctrl_clear_overrun, 1); //reset
_iface->poke32(_iface->regs.rx_ctrl_vrt_header, 0
+
| (0x1 << 28) //if data with stream id
| (0x1 << 26) //has trailer
| (0x3 << 22) //integer time other
@@ -84,6 +85,11 @@ usrp2_mboard_impl::usrp2_mboard_impl(
_iface->poke32(_iface->regs.rx_ctrl_vrt_trailer, 0);
_iface->poke32(_iface->regs.time64_tps, size_t(get_master_clock_freq()));
+ //init the tx control registers
+ _iface->poke32(_iface->regs.tx_ctrl_num_chan, 0); //1 channel
+ _iface->poke32(_iface->regs.tx_ctrl_clear_state, 1); //reset
+ _iface->poke32(_iface->regs.tx_ctrl_report_sid, 1); //sid 1 (different from rx)
+
//init the ddc
init_ddc_config();
diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp
index 70c3705c9..8421b6b39 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.hpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.hpp
@@ -169,6 +169,7 @@ private:
void tx_codec_set(const wax::obj &, const wax::obj &);
wax_obj_proxy::sptr _rx_codec_proxy;
wax_obj_proxy::sptr _tx_codec_proxy;
+
void rx_codec_set_gain(float, const std::string &);
uhd::dict<std::string, float> _codec_rx_gains;
@@ -246,6 +247,7 @@ public:
uhd::rx_metadata_t &, const uhd::io_type_t &,
uhd::device::recv_mode_t, size_t
);
+ bool recv_async_msg(uhd::async_metadata_t &, size_t);
private:
//device properties interface
diff --git a/host/lib/usrp/usrp2/usrp2_regs.cpp b/host/lib/usrp/usrp2/usrp2_regs.cpp
index 071ba0cd2..e40407f99 100644
--- a/host/lib/usrp/usrp2/usrp2_regs.cpp
+++ b/host/lib/usrp/usrp2/usrp2_regs.cpp
@@ -89,6 +89,9 @@ usrp2_regs_t usrp2_get_regs(int hw_rev) {
x.rx_ctrl_vrt_trailer = sr_addr(misc_output_base, x.sr_rx_ctrl + 6);
x.rx_ctrl_nsamps_per_pkt = sr_addr(misc_output_base, x.sr_rx_ctrl + 7);
x.rx_ctrl_nchannels = sr_addr(misc_output_base, x.sr_rx_ctrl + 8);
+ x.tx_ctrl_num_chan = sr_addr(misc_output_base, x.sr_tx_ctrl + 0);
+ x.tx_ctrl_clear_state = sr_addr(misc_output_base, x.sr_tx_ctrl + 1);
+ x.tx_ctrl_report_sid = sr_addr(misc_output_base, x.sr_tx_ctrl + 2);
return x;
}
diff --git a/host/lib/usrp/usrp2/usrp2_regs.hpp b/host/lib/usrp/usrp2/usrp2_regs.hpp
index 0ebce6a85..8dbd6c4b4 100644
--- a/host/lib/usrp/usrp2/usrp2_regs.hpp
+++ b/host/lib/usrp/usrp2/usrp2_regs.hpp
@@ -94,6 +94,9 @@ typedef struct {
int rx_ctrl_vrt_trailer;
int rx_ctrl_nsamps_per_pkt;
int rx_ctrl_nchannels;
+ int tx_ctrl_num_chan;
+ int tx_ctrl_clear_state;
+ int tx_ctrl_report_sid;
} usrp2_regs_t;
extern const usrp2_regs_t usrp2_regs; //the register definitions, set in usrp2_regs.cpp and usrp2p_regs.cpp
@@ -248,8 +251,15 @@ usrp2_regs_t usrp2_get_regs(int hw_rev);
///////////////////////////////////////////////////
-// VITA RX CTRL regs
+// RX CTRL regs
///////////////////////////////////////////////////
+///////////////////////////////////////////////////
+// TX CTRL regs
+///////////////////////////////////////////////////
+//#define U2_REG_TX_CTRL_NUM_CHAN _SR_ADDR(SR_TX_CTRL + 0)
+//#define U2_REG_TX_CTRL_CLEAR_STATE _SR_ADDR(SR_TX_CTRL + 1)
+//#define U2_REG_TX_CTRL_REPORT_SID _SR_ADDR(SR_TX_CTRL + 2)
+
#endif /* INCLUDED_USRP2_REGS_HPP */