diff options
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 */ | 
