From 77c578fc639bb3d54c6730402de04a22636b1d6d Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sun, 18 Apr 2010 00:37:24 -0700 Subject: Created a docs directory to house restructured text documentation. Moved doxygen build rules into the docs build directory. Created rst docs for building and burning usrp2. --- host/docs/usrp2.rst | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 host/docs/usrp2.rst (limited to 'host/docs/usrp2.rst') diff --git a/host/docs/usrp2.rst b/host/docs/usrp2.rst new file mode 100644 index 000000000..1de61b734 --- /dev/null +++ b/host/docs/usrp2.rst @@ -0,0 +1,63 @@ +======================================================================== +UHD - USRP2 App Notes +======================================================================== + +.. contents:: Table of Contents + +------------------------------------------------------------------------ +Building firmware and FPGA images +------------------------------------------------------------------------ + +^^^^^^^^^^^^^^^^^^ +FPGA Image +^^^^^^^^^^^^^^^^^^ +Xilinx ISE 10.1 is required to build the FPGA image for the USRP2 +(newer version of ISE are known to build buggy images). +The build requires that you have a unix-like environment with make. +Make sure that xtclsh from the Xilinx ISE bin directory is in your $PATH. + +Run the following commands: +:: + + cd /fpga/usrp2/top/u2_rev3 + make bin + +*The image file will be ./build/u2_rev3.bin* + +^^^^^^^^^^^^^^^^^^ +Firmware Image +^^^^^^^^^^^^^^^^^^ +The Microblaze GCC compiler from the Xilinx EDK is required to build the firmware. +The build requires that you have a unix-like environment with autotools and make. +Make sure that mb-gcc from the Xilinx EDK/microblaze directory is in your $PATH. + +Run the following commands: +:: + + cd /firmware/microblaze + ./boostrap + ./configure host=mb + make + +*The image file will be ./apps/txrx.bin* + +------------------------------------------------------------------------ +Load the images onto the SD card +------------------------------------------------------------------------ +**Warning!** +Use the u2_flash_tool with caution. If you specify the wrong device node, +you could overwrite your hard drive. Make sure that --dev= specifies the SD card. + +Load the FPGA image: + +:: + + cd /firmware/microblaze + sudo ./u2_flash_tool --dev=/dev/sd -t fpga -w + +Load the firmware image: + +:: + + cd /firmware/microblaze directory + sudo ./u2_flash_tool --dev=/dev/sd -t s/w -w -- cgit v1.2.3 From b3d0c68ceaff1562c32fb8fe41c1e6845a0aad37 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sun, 18 Apr 2010 14:55:05 -0700 Subject: added usrp2 networking notes, tweaked style and build --- host/docs/CMakeLists.txt | 17 ++++++++++--- host/docs/style.css | 14 ++++++++--- host/docs/usrp2.rst | 65 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+), 7 deletions(-) (limited to 'host/docs/usrp2.rst') diff --git a/host/docs/CMakeLists.txt b/host/docs/CMakeLists.txt index e90f1e9a1..52376fe8c 100644 --- a/host/docs/CMakeLists.txt +++ b/host/docs/CMakeLists.txt @@ -31,16 +31,24 @@ MESSAGE(STATUS "Checking for rst2html (docutils)") FIND_PROGRAM(RST2HTML rst2html) IF(${RST2HTML} STREQUAL "RST2HTML-NOTFOUND") MESSAGE(STATUS "Checking for rst2html (docutils) - not found") + MESSAGE(STATUS " Disabled generation of HTML manual.") ELSE(${RST2HTML} STREQUAL "RST2HTML-NOTFOUND") MESSAGE(STATUS "Checking for rst2html (docutils) - found") + MESSAGE(STATUS " Enabled generation of HTML manual.") + SET(stylesheet ${CMAKE_CURRENT_SOURCE_DIR}/style.css) + SET(rst2html_options + --stylesheet=${stylesheet} + --no-toc-backlinks + --date + --time + ) FOREACH(rstfile ${manual_sources}) SET(rstfile ${CMAKE_CURRENT_SOURCE_DIR}/${rstfile}) GET_FILENAME_COMPONENT(rstfile_we ${rstfile} NAME_WE) SET(htmlfile ${CMAKE_CURRENT_BINARY_DIR}/${rstfile_we}.html) ADD_CUSTOM_COMMAND( - OUTPUT ${htmlfile} DEPENDS ${rstfile} ${CMAKE_CURRENT_SOURCE_DIR}/style.css - COMMAND ${RST2HTML} ${rstfile} ${htmlfile} - --stylesheet=${CMAKE_CURRENT_SOURCE_DIR}/style.css --no-toc-backlinks + OUTPUT ${htmlfile} DEPENDS ${rstfile} ${stylesheet} + COMMAND ${RST2HTML} ${rstfile} ${htmlfile} ${rst2html_options} COMMENT "Generating ${htmlfile}" ) LIST(APPEND manual_html_files ${htmlfile}) @@ -57,6 +65,7 @@ INSTALL(FILES ${manual_sources} DESTINATION ${PKG_DOC_DIR}/manual/rst) INCLUDE(FindDoxygen) IF(DOXYGEN_FOUND) + MESSAGE(STATUS " Enabled generation of Doxygen documentation.") SET(CMAKE_CURRENT_BINARY_DIR_DOXYGEN ${CMAKE_CURRENT_BINARY_DIR}/doxygen) CONFIGURE_FILE( ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in @@ -68,4 +77,6 @@ IF(DOXYGEN_FOUND) ) ADD_CUSTOM_TARGET(doxygen_html ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR_DOXYGEN}) INSTALL(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR_DOXYGEN} DESTINATION ${PKG_DOC_DIR}) +ELSE(DOXYGEN_FOUND) + MESSAGE(STATUS " Disabled generation of Doxygen documentation.") ENDIF(DOXYGEN_FOUND) diff --git a/host/docs/style.css b/host/docs/style.css index a50dce04a..7bd84c9c7 100644 --- a/host/docs/style.css +++ b/host/docs/style.css @@ -4,7 +4,7 @@ font-size:10pt; color:black; background-color:#FEFEFE; width:90%; -margin:0 auto; +margin:0 auto 0 auto; } div.document div.contents{ @@ -45,7 +45,7 @@ background-color:inherit; div.document h2.subtitle, div.section h1{ margin-top:50px; -border-top:1px solid #333333; +border-bottom:1px solid #333333; font-size:140%; text-align:center; padding:20px 0px 10px 0px; @@ -56,13 +56,13 @@ background-color:inherit; div.section h2{ font-size:110%; text-align:left; -padding:15px 0px 5px 10px; +padding:15px 0px 5px 0px; text-decoration:underline; color:#333333; background-color:inherit; } -div.document pre{ +div.document pre.literal-block{ border:1px inset #333333; padding:5px; margin:10px 5px 10px 5px; @@ -94,3 +94,9 @@ text-align:center; color:inherit; background-color:#FCFCFC; } + +div.footer{ +margin:50px auto 30px auto; +text-align:center; +font-size:85%; +} diff --git a/host/docs/usrp2.rst b/host/docs/usrp2.rst index 1de61b734..48ef60683 100644 --- a/host/docs/usrp2.rst +++ b/host/docs/usrp2.rst @@ -61,3 +61,68 @@ Load the firmware image: cd /firmware/microblaze directory sudo ./u2_flash_tool --dev=/dev/sd -t s/w -w + +------------------------------------------------------------------------ +Setup networking +------------------------------------------------------------------------ +The USRP2 only supports gigabit ethernet, and +will not work with a 10/100 Mbps interface. +Because the USRP2 uses gigabit ethernet pause frames for flow control, +you cannot use multiple USRP2s with a switch or a hub. +It is recommended that each USRP2 be plugged directly into its own +dedicated gigabit ethernet interface on the host computer. + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Setup the host interface +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The USRP2 communicates at the IP/UDP layer over the gigabit ethernet. +The default IP address of the USRP2 is **192.168.10.2** +You will need to configure the host's ethernet interface with a static IP address to enable communication. +An address of **192.168.10.1** is recommended. + +**Note:** +When using the UHD, if an IP address for the USRP2 is not specified, +the software will use UDP broadcast packets to locate the USRP2. +On some systems, the firewall will block UDP broadcast packets. +It is recommended that you change or disable your firewall settings. + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Change the USRP2's IP address +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +You may need to change the USRP2's IP address for several reasons: + +* to satisfy your particular network configuration +* to use multiple USRP2s on the same host computer +* to set a known IP address into USRP2 (in case you forgot) + +**Method 1:** +To change the USRP2's IP address +you must know the current address of the USRP2, +and the network must be setup properly as described above. +Run the following commands: +:: + + cd /share/uhd/utils + ./usrp_burner --addr=192.168.10.2 --new-ip=192.168.10.3 + +**Method 2 (Linux Only):** +This method assumes that you do not know the IP address of your USRP2. +It uses raw ethernet packets to bypass the IP/UDP layer to communicate with the USRP2. +Run the following commands: +:: + + cd /share/uhd/utils + ./usrp2 recovery.py --ifc=eth0 --new-ip=192.168.10.3 + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Debugging networking problems +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +**Monitor the USRP2:** +You can read the serial port on the rear of the USRP2 +to get debug verbose from the embedded microcontroller. +Use a standard USB to tty-level serial converter at 230400 baud. +The microcontroller prints useful information about IP addresses, +MAC addresses, control packets, and fast-path settings. + +**Monitor the host network traffic:** +Use wireshark to monitor packets send to and received from the USRP2. -- cgit v1.2.3 From 05d0a14a2eaf6054d304c153dc9035eaca8039b2 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 22 Apr 2010 12:55:54 -0700 Subject: pulled in some dboard docs and fixes --- host/docs/CMakeLists.txt | 4 ++- host/docs/dboards.rst | 64 ++++++++++++++++++++++++++++++++++++++++++++++++ host/docs/index.rst | 12 +++++---- host/docs/style.css | 4 +-- host/docs/usrp2.rst | 8 +++--- 5 files changed, 80 insertions(+), 12 deletions(-) create mode 100644 host/docs/dboards.rst (limited to 'host/docs/usrp2.rst') diff --git a/host/docs/CMakeLists.txt b/host/docs/CMakeLists.txt index 1bbd52fee..61eede8b7 100644 --- a/host/docs/CMakeLists.txt +++ b/host/docs/CMakeLists.txt @@ -22,6 +22,7 @@ SET(manual_sources index.rst build.rst coding.rst + dboards.rst usrp2.rst ) @@ -38,8 +39,9 @@ ELSE(${RST2HTML} STREQUAL "RST2HTML-NOTFOUND") MESSAGE(STATUS " Enabled generation of HTML manual.") #setup rst2html options + SET(stylesheet ${CMAKE_CURRENT_SOURCE_DIR}/style.css) SET(rst2html_options - --stylesheet=${CMAKE_CURRENT_SOURCE_DIR}/style.css + --stylesheet=${stylesheet} --no-toc-backlinks --date --time ) diff --git a/host/docs/dboards.rst b/host/docs/dboards.rst new file mode 100644 index 000000000..d08b752a6 --- /dev/null +++ b/host/docs/dboards.rst @@ -0,0 +1,64 @@ +======================================================================== +UHD - Daughterboard Application Notes +======================================================================== + +.. contents:: Table of Contents + +------------------------------------------------------------------------ +Daughterboard Properties +------------------------------------------------------------------------ + +The following contains interesting notes about each daughterboard. +Eventually, this page will be expanded to list out the full +properties of each board as well. + +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Basic RX and and LFRX +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The Basic RX and LFRX boards have 3 subdevices: + +* **Subdevice A:** real signal on antenna RXA +* **Subdevice B:** real signal on antenna RXB +* **Subdevice AB:** quadrature subdevice using both antennas + +The boards have no tunable elements or programmable gains. +Though the magic of aliasing, you can down-convert signals +greater than the nyquist rate of the ADC. + +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Basic TX and and LFTX +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The Basic TX and LFTX boards have 1 quadrature subdevice using both antennas. + +The boards have no tunable elements or programmable gains. +Though the magic of aliasing, you can up-convert signals +greater than the nyquist rate of the DAC. + +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +RFX Series +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Transmit Antennas: **TX/RX** + +Receive Antennas: **TX/RX** or **RX2** + +The user may set the receive antenna to be TX/RX or RX2. +However, when using an RFX board in full-duplex mode, +the receive antenna will always be set to RX2, regardless of the settings. + +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +XCVR 2450 +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The XCVR2450 has a non-contiguous tuning range consiting of a high band and a low band. +The high band consists of frequencies between...TODO + +Transmit Antennas: **J1** or **J2** + +Receive Antennas: **J1** or **J2** + +When using the XCVR2450 in full-duplex mode, +the user must set the receive antenna and the transmit antenna to be different; +not doing so will yeild undefined results. + +The XCVR2450 uses a common LO for both receive and transmit. +Even though the API allows the RX and TX LOs to be individually set, +a change of one LO setting will be reflected in the other LO setting. diff --git a/host/docs/index.rst b/host/docs/index.rst index 37853b0b6..3dc7a2d98 100644 --- a/host/docs/index.rst +++ b/host/docs/index.rst @@ -13,17 +13,19 @@ Contents ------------------------------------------------------------------------ ^^^^^^^^^^^^^^^^^^^^^ -API Documentation +Building the UHD ^^^^^^^^^^^^^^^^^^^^^ -* `Doxygen <./../../doxygen/html/index.html>`_ -* `Using the API <./coding.html>`_ +* `Build Guide <./build.html>`_ ^^^^^^^^^^^^^^^^^^^^^ Supported Devices ^^^^^^^^^^^^^^^^^^^^^ * `USRP2 App Notes <./usrp2.html>`_ +* `Daughterboard App Notes <./dboards.html>`_ ^^^^^^^^^^^^^^^^^^^^^ -Building the UHD +API Documentation ^^^^^^^^^^^^^^^^^^^^^ -* `Build Guide <./build.html>`_ +* `Doxygen <./../../doxygen/html/index.html>`_ +* `Using the API <./coding.html>`_ + diff --git a/host/docs/style.css b/host/docs/style.css index 7bd84c9c7..bf97bf007 100644 --- a/host/docs/style.css +++ b/host/docs/style.css @@ -1,8 +1,8 @@ body{ font-family:Arial, Helvetica, sans-serif; -font-size:10pt; +font-size:11pt; color:black; -background-color:#FEFEFE; +background-color:white; width:90%; margin:0 auto 0 auto; } diff --git a/host/docs/usrp2.rst b/host/docs/usrp2.rst index 48ef60683..32e7374c8 100644 --- a/host/docs/usrp2.rst +++ b/host/docs/usrp2.rst @@ -1,5 +1,5 @@ ======================================================================== -UHD - USRP2 App Notes +UHD - USRP2 Application Notes ======================================================================== .. contents:: Table of Contents @@ -36,7 +36,7 @@ Run the following commands: cd /firmware/microblaze ./boostrap - ./configure host=mb + ./configure --host=mb make *The image file will be ./apps/txrx.bin* @@ -112,7 +112,7 @@ Run the following commands: :: cd /share/uhd/utils - ./usrp2 recovery.py --ifc=eth0 --new-ip=192.168.10.3 + ./usrp2_recovery.py --ifc=eth0 --new-ip=192.168.10.3 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Debugging networking problems @@ -125,4 +125,4 @@ The microcontroller prints useful information about IP addresses, MAC addresses, control packets, and fast-path settings. **Monitor the host network traffic:** -Use wireshark to monitor packets send to and received from the USRP2. +Use wireshark to monitor packets sent to and received from the USRP2. -- cgit v1.2.3 From 15befa19de40fb82f30d71bf21a767e7d8054ba1 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sun, 25 Apr 2010 22:17:16 -0700 Subject: renamed the firmware main image to txrx_uhd.bin --- firmware/microblaze/apps/Makefile.am | 4 +- firmware/microblaze/apps/txrx.c | 691 ----------------------------------- firmware/microblaze/apps/txrx_uhd.c | 691 +++++++++++++++++++++++++++++++++++ host/docs/usrp2.rst | 2 +- 4 files changed, 694 insertions(+), 694 deletions(-) delete mode 100644 firmware/microblaze/apps/txrx.c create mode 100644 firmware/microblaze/apps/txrx_uhd.c (limited to 'host/docs/usrp2.rst') diff --git a/firmware/microblaze/apps/Makefile.am b/firmware/microblaze/apps/Makefile.am index ff426cf8c..a4f79935b 100644 --- a/firmware/microblaze/apps/Makefile.am +++ b/firmware/microblaze/apps/Makefile.am @@ -23,7 +23,7 @@ LDADD = $(top_srcdir)/lib/libu2fw.a AM_CFLAGS += -I$(top_srcdir)/../../host/lib/usrp -noinst_PROGRAMS = txrx.elf +noinst_PROGRAMS = txrx_uhd.elf # blink_leds \ # blink_leds2 \ @@ -66,7 +66,7 @@ noinst_PROGRAMS = txrx.elf # tx_drop_SOURCES = tx_drop.c app_common.c # tx_drop_rate_limited_SOURCES = tx_drop_rate_limited.c app_common.c # tx_drop2_SOURCES = tx_drop2.c app_common.c -txrx_elf_SOURCES = txrx.c +txrx_uhd_elf_SOURCES = txrx_uhd.c # app_common_v2.c #factory_test_SOURCES = factory_test.c app_common_v2.c #eth_serdes_SOURCES = eth_serdes.c app_passthru_v2.c diff --git a/firmware/microblaze/apps/txrx.c b/firmware/microblaze/apps/txrx.c deleted file mode 100644 index 7a6fbd993..000000000 --- a/firmware/microblaze/apps/txrx.c +++ /dev/null @@ -1,691 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -/* - * Copyright 2007,2008 Free Software Foundation, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#define DEBUG_MODE 0 //0 for normal operation - -#include -#include -#include "u2_init.h" -#include "memory_map.h" -#include "spi.h" -#include "hal_io.h" -#include "buffer_pool.h" -#include "pic.h" -#include -#include "ethernet.h" -#include "nonstdio.h" -#include "dbsm.h" -#include -#include -#include "memcpy_wa.h" -#include -#include -#include -#include "clocks.h" -#include -#include "usrp2/fw_common.h" -#include -#include -#include -#include - -#define LEDS_SW LED_A - -/* - * Full duplex Tx and Rx between ethernet and DSP pipelines - * - * Buffer 1 is used by the cpu to send frames to the host. - * Buffers 2 and 3 are used to double-buffer the DSP Rx to eth flow - * Buffers 4 and 5 are used to double-buffer the eth to DSP Tx eth flow - */ -//#define CPU_RX_BUF 0 // eth -> cpu - -#define DSP_RX_BUF_0 2 // dsp rx -> eth (double buffer) -#define DSP_RX_BUF_1 3 // dsp rx -> eth -#define DSP_TX_BUF_0 4 // eth -> dsp tx (double buffer) -#define DSP_TX_BUF_1 5 // eth -> dsp tx - -/* - * ================================================================ - * configure DSP TX double buffering state machine (eth -> dsp) - * ================================================================ - */ - -// DSP Tx reads ethernet header words -#define DSP_TX_FIRST_LINE ((sizeof(padded_eth_hdr_t) + sizeof(struct ip_hdr) + sizeof(struct udp_hdr))/sizeof(uint32_t)) - -// Receive from ethernet -buf_cmd_args_t dsp_tx_recv_args = { - PORT_ETH, - 0, - BP_LAST_LINE -}; - -// send to DSP Tx -buf_cmd_args_t dsp_tx_send_args = { - PORT_DSP, - DSP_TX_FIRST_LINE, // starts just past transport header - 0 // filled in from last_line register -}; - -dbsm_t dsp_tx_sm; // the state machine - -/* - * ================================================================ - * configure DSP RX double buffering state machine (dsp -> eth) - * ================================================================ - */ - -typedef struct{ - uint32_t control_word; - uint32_t vrt_header[]; -} rx_dsp_buff_t; - -#define MK_RX_CTRL_WORD(num_words) (((num_words)*sizeof(uint32_t)) | (1 << 16)) - -// DSP Rx writes ethernet header words -#define DSP_RX_FIRST_LINE 1 //1 = number of control words (see above) - -// receive from DSP -buf_cmd_args_t dsp_rx_recv_args = { - PORT_DSP, - DSP_RX_FIRST_LINE, - BP_LAST_LINE -}; - -// send to ETH -buf_cmd_args_t dsp_rx_send_args = { - PORT_ETH, - 0, // starts with ethernet header in line 0 - 0, // filled in from list_line register -}; - -dbsm_t dsp_rx_sm; // the state machine - - -// The mac address of the host we're sending to. -eth_mac_addr_t host_mac_addr; - -//controls continuous streaming... -static bool auto_reload_command = false; -static size_t streaming_items_per_frame = 0; -static int streaming_frame_count = 0; -#define FRAMES_PER_CMD 2 - -static void setup_network(void); -static void setup_vrt(void); - -// ---------------------------------------------------------------- -// the fast-path setup global variables -// ---------------------------------------------------------------- -static eth_mac_addr_t fp_mac_addr_src, fp_mac_addr_dst; -static struct socket_address fp_socket_src, fp_socket_dst; - -// ---------------------------------------------------------------- -void start_rx_streaming_cmd(void); -void stop_rx_cmd(void); - -static void print_ip_addr(const void *t){ - uint8_t *p = (uint8_t *)t; - printf("%d.%d.%d.%d", p[0], p[1], p[2], p[3]); -} - -void handle_udp_data_packet( - struct socket_address src, struct socket_address dst, - unsigned char *payload, int payload_len -){ - //store the 2nd word as the following: - streaming_items_per_frame = ((uint32_t *)payload)[1]; - - //its a tiny payload, load the fast-path variables - fp_mac_addr_src = *ethernet_mac_addr(); - arp_cache_lookup_mac(&src.addr, &fp_mac_addr_dst); - fp_socket_src = dst; - fp_socket_dst = src; - printf("Storing for fast path:\n"); - printf(" source mac addr: "); - print_mac_addr(fp_mac_addr_src.addr); newline(); - printf(" source ip addr: "); - print_ip_addr(&fp_socket_src.addr); newline(); - printf(" source udp port: %d\n", fp_socket_src.port); - printf(" destination mac addr: "); - print_mac_addr(fp_mac_addr_dst.addr); newline(); - printf(" destination ip addr: "); - print_ip_addr(&fp_socket_dst.addr); newline(); - printf(" destination udp port: %d\n", fp_socket_dst.port); - newline(); - - //setup network and vrt - setup_network(); - setup_vrt(); - - // kick off the state machine - dbsm_start(&dsp_rx_sm); - -} - -static void inline issue_stream_command(size_t nsamps, bool now, bool chain, uint32_t secs, uint32_t ticks, bool start){ - //printf("Stream cmd: nsamps %d, now %d, chain %d, secs %u, ticks %u\n", (int)nsamps, now, chain, secs, ticks); - sr_rx_ctrl->cmd = MK_RX_CMD(nsamps, now, chain); - - if (start) dbsm_start(&dsp_rx_sm); - - sr_rx_ctrl->time_secs = secs; - sr_rx_ctrl->time_ticks = ticks; // enqueue command -} - -#define OTW_GPIO_BANK_TO_NUM(bank) \ - (((bank) == USRP2_DIR_RX)? (GPIO_RX_BANK) : (GPIO_TX_BANK)) - -void handle_udp_ctrl_packet( - struct socket_address src, struct socket_address dst, - unsigned char *payload, int payload_len -){ - //printf("Got ctrl packet #words: %d\n", (int)payload_len); - usrp2_ctrl_data_t *ctrl_data_in = (usrp2_ctrl_data_t *)payload; - uint32_t ctrl_data_in_id = ctrl_data_in->id; - - //ensure that the protocol versions match - if (payload_len >= sizeof(uint32_t) && ctrl_data_in->proto_ver != USRP2_PROTO_VERSION){ - printf("!Error in control packet handler: Expected protocol version %d, but got %d\n", - USRP2_PROTO_VERSION, ctrl_data_in->proto_ver - ); - ctrl_data_in_id = USRP2_CTRL_ID_GIVE_ME_YOUR_IP_ADDR_BRO; - } - - //ensure that this is not a short packet - if (payload_len < sizeof(usrp2_ctrl_data_t)){ - printf("!Error in control packet handler: Expected payload length %d, but got %d\n", - (int)sizeof(usrp2_ctrl_data_t), payload_len - ); - ctrl_data_in_id = USRP2_CTRL_ID_HUH_WHAT; - } - - //setup the output data - usrp2_ctrl_data_t ctrl_data_out = { - .proto_ver = USRP2_PROTO_VERSION, - .id=USRP2_CTRL_ID_HUH_WHAT, - .seq=ctrl_data_in->seq - }; - - //handle the data based on the id - switch(ctrl_data_in_id){ - - /******************************************************************* - * Addressing - ******************************************************************/ - case USRP2_CTRL_ID_GIVE_ME_YOUR_IP_ADDR_BRO: - ctrl_data_out.id = USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE; - memcpy(&ctrl_data_out.data.ip_addr, get_ip_addr(), sizeof(struct ip_addr)); - break; - - case USRP2_CTRL_ID_HERE_IS_A_NEW_IP_ADDR_BRO: - ctrl_data_out.id = USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE; - set_ip_addr((struct ip_addr *)&ctrl_data_in->data.ip_addr); - memcpy(&ctrl_data_out.data.ip_addr, get_ip_addr(), sizeof(struct ip_addr)); - break; - - case USRP2_CTRL_ID_GIVE_ME_YOUR_MAC_ADDR_BRO: - ctrl_data_out.id = USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE; - memcpy(&ctrl_data_out.data.mac_addr, ethernet_mac_addr(), sizeof(eth_mac_addr_t)); - break; - - case USRP2_CTRL_ID_HERE_IS_A_NEW_MAC_ADDR_BRO: - ctrl_data_out.id = USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE; - ethernet_set_mac_addr((eth_mac_addr_t *)&ctrl_data_in->data.mac_addr); - memcpy(&ctrl_data_out.data.mac_addr, ethernet_mac_addr(), sizeof(eth_mac_addr_t)); - break; - - case USRP2_CTRL_ID_GIVE_ME_YOUR_DBOARD_IDS_BRO: - ctrl_data_out.id = USRP2_CTRL_ID_THESE_ARE_MY_DBOARD_IDS_DUDE; - ctrl_data_out.data.dboard_ids.tx_id = read_dboard_eeprom(I2C_ADDR_TX_A); - ctrl_data_out.data.dboard_ids.rx_id = read_dboard_eeprom(I2C_ADDR_RX_A); - break; - - /******************************************************************* - * SPI - ******************************************************************/ - case USRP2_CTRL_ID_TRANSACT_ME_SOME_SPI_BRO:{ - //transact - uint32_t result = spi_transact( - (ctrl_data_in->data.spi_args.readback == 0)? SPI_TXONLY : SPI_TXRX, - ctrl_data_in->data.spi_args.dev, //which device - ctrl_data_in->data.spi_args.data, //32 bit data - ctrl_data_in->data.spi_args.num_bits, //length in bits - (ctrl_data_in->data.spi_args.mosi_edge == USRP2_CLK_EDGE_RISE)? SPIF_PUSH_FALL : SPIF_PUSH_RISE | - (ctrl_data_in->data.spi_args.miso_edge == USRP2_CLK_EDGE_RISE)? SPIF_LATCH_RISE : SPIF_LATCH_FALL - ); - - //load output - ctrl_data_out.data.spi_args.data = result; - ctrl_data_out.id = USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE; - } - break; - - /******************************************************************* - * I2C - ******************************************************************/ - case USRP2_CTRL_ID_DO_AN_I2C_READ_FOR_ME_BRO:{ - uint8_t num_bytes = ctrl_data_in->data.i2c_args.bytes; - i2c_read( - ctrl_data_in->data.i2c_args.addr, - ctrl_data_out.data.i2c_args.data, - num_bytes - ); - ctrl_data_out.id = USRP2_CTRL_ID_HERES_THE_I2C_DATA_DUDE; - ctrl_data_out.data.i2c_args.bytes = num_bytes; - } - break; - - case USRP2_CTRL_ID_WRITE_THESE_I2C_VALUES_BRO:{ - uint8_t num_bytes = ctrl_data_in->data.i2c_args.bytes; - i2c_write( - ctrl_data_in->data.i2c_args.addr, - ctrl_data_in->data.i2c_args.data, - num_bytes - ); - ctrl_data_out.id = USRP2_CTRL_ID_COOL_IM_DONE_I2C_WRITE_DUDE; - ctrl_data_out.data.i2c_args.bytes = num_bytes; - } - break; - - /******************************************************************* - * Streaming - ******************************************************************/ - case USRP2_CTRL_ID_SEND_STREAM_COMMAND_FOR_ME_BRO:{ - - //issue two commands and set the auto-reload flag - if (ctrl_data_in->data.stream_cmd.continuous){ - printf("Setting up continuous streaming...\n"); - printf("items per frame: %d\n", (int)streaming_items_per_frame); - hal_set_leds(LED_A, LEDS_SW); - auto_reload_command = true; - streaming_frame_count = FRAMES_PER_CMD; - - issue_stream_command( - streaming_items_per_frame * FRAMES_PER_CMD, - (ctrl_data_in->data.stream_cmd.now == 0)? false : true, //now - true, //chain - ctrl_data_in->data.stream_cmd.secs, - ctrl_data_in->data.stream_cmd.ticks, - true //start - ); - - issue_stream_command( - streaming_items_per_frame * FRAMES_PER_CMD, - true, //now - true, //chain - 0, 0, //time does not matter - false - ); - - } - - //issue regular stream commands (split commands if too large) - else{ - hal_set_leds(0, LEDS_SW); - auto_reload_command = false; - size_t num_samps = ctrl_data_in->data.stream_cmd.num_samps; - if (num_samps == 0) num_samps = 1; //FIXME hack, zero is used when stopping continuous streaming but it somehow makes it inifinite - - bool chain = num_samps > MAX_SAMPLES_PER_CMD; - issue_stream_command( - (chain)? streaming_items_per_frame : num_samps, //nsamps - (ctrl_data_in->data.stream_cmd.now == 0)? false : true, //now - (ctrl_data_in->data.stream_cmd.chain == 0)? chain : true, //chain - ctrl_data_in->data.stream_cmd.secs, - ctrl_data_in->data.stream_cmd.ticks, - false - ); - - //handle rest of the samples that did not fit into one cmd - while(chain){ - num_samps -= MAX_SAMPLES_PER_CMD; - chain = num_samps > MAX_SAMPLES_PER_CMD; - issue_stream_command( - (chain)? streaming_items_per_frame : num_samps, //nsamps - true, //now - (ctrl_data_in->data.stream_cmd.chain == 0)? chain : true, //chain - 0, 0, //time does not matter - false - ); - } - } - ctrl_data_out.id = USRP2_CTRL_ID_GOT_THAT_STREAM_COMMAND_DUDE; - break; - } - - /******************************************************************* - * Peek and Poke Register - ******************************************************************/ - case USRP2_CTRL_ID_POKE_THIS_REGISTER_FOR_ME_BRO: - if (ctrl_data_in->data.poke_args.addr < 0xC000){ - printf("error! tried to poke into 0x%x\n", ctrl_data_in->data.poke_args.addr); - } - else switch(ctrl_data_in->data.poke_args.num_bytes){ - case sizeof(uint32_t): - *((uint32_t *) ctrl_data_in->data.poke_args.addr) = (uint32_t)ctrl_data_in->data.poke_args.data; - break; - - case sizeof(uint16_t): - *((uint16_t *) ctrl_data_in->data.poke_args.addr) = (uint16_t)ctrl_data_in->data.poke_args.data; - break; - - case sizeof(uint8_t): - *((uint8_t *) ctrl_data_in->data.poke_args.addr) = (uint8_t)ctrl_data_in->data.poke_args.data; - break; - - } - ctrl_data_out.id = USRP2_CTRL_ID_OMG_POKED_REGISTER_SO_BAD_DUDE; - break; - - case USRP2_CTRL_ID_PEEK_AT_THIS_REGISTER_FOR_ME_BRO: - switch(ctrl_data_in->data.poke_args.num_bytes){ - case sizeof(uint32_t): - ctrl_data_in->data.poke_args.data = *((uint32_t *) ctrl_data_in->data.poke_args.addr); - break; - - case sizeof(uint16_t): - ctrl_data_in->data.poke_args.data = *((uint16_t *) ctrl_data_in->data.poke_args.addr); - break; - - case sizeof(uint8_t): - ctrl_data_in->data.poke_args.data = *((uint8_t *) ctrl_data_in->data.poke_args.addr); - break; - - } - ctrl_data_out.id = USRP2_CTRL_ID_WOAH_I_DEFINITELY_PEEKED_IT_DUDE; - break; - - /******************************************************************* - * Hardware Rev Numbers - ******************************************************************/ - case USRP2_CTRL_ID_WHATS_THE_HARDWARE_REV_NOS_BRO: - ctrl_data_out.data.hw_rev.major = u2_hw_rev_major; - ctrl_data_out.data.hw_rev.minor = u2_hw_rev_minor; - ctrl_data_out.id = USRP2_CTRL_ID_TAKE_THE_HARDWARE_REV_NOS_DUDE; - break; - - default: - ctrl_data_out.id = USRP2_CTRL_ID_HUH_WHAT; - - } - send_udp_pkt(USRP2_UDP_CTRL_PORT, src, &ctrl_data_out, sizeof(ctrl_data_out)); -} - -/* - * Called when an ethernet packet is received. - * Return true if we handled it here, otherwise - * it'll be passed on to the DSP Tx pipe - */ -static bool -eth_pkt_inspector(dbsm_t *sm, int bufno) -{ - //point me to the ethernet frame - uint32_t *buff = (uint32_t *)buffer_ram(bufno); - - //treat this as fast-path data? - // We have to do this operation as fast as possible. - // Therefore, we do not check all the headers, - // just check that the udp port matches - // and that the vrt header is non zero. - // In the future, a hardware state machine will do this... - if ( //warning! magic numbers approaching.... - (((buff + ((2 + 14 + 20)/sizeof(uint32_t)))[0] & 0xffff) == USRP2_UDP_DATA_PORT) && - ((buff + ((2 + 14 + 20 + 8)/sizeof(uint32_t)))[0] != USRP2_INVALID_VRT_HEADER) - ) return false; - - //test if its an ip recovery packet - typedef struct{ - padded_eth_hdr_t eth_hdr; - char code[4]; - union { - struct ip_addr ip_addr; - } data; - }recovery_packet_t; - recovery_packet_t *recovery_packet = (recovery_packet_t *)buff; - if (recovery_packet->eth_hdr.ethertype == 0xbeee && strncmp(recovery_packet->code, "addr", 4) == 0){ - printf("Got ip recovery packet: "); print_ip_addr(&recovery_packet->data.ip_addr); newline(); - set_ip_addr(&recovery_packet->data.ip_addr); - return true; - } - - //pass it to the slow-path handler - size_t len = buffer_pool_status->last_line[bufno] - 3; - handle_eth_packet(buff, len); - return true; -} - -//------------------------------------------------------------------ - -static bool vrt_has_trailer(void){ - return USRP2_HOST_RX_VRT_TRAILER_WORDS32 > 0; -} - -static void setup_vrt(void){ - // setup RX DSP regs - sr_rx_ctrl->nsamples_per_pkt = streaming_items_per_frame; - sr_rx_ctrl->nchannels = 1; - sr_rx_ctrl->clear_overrun = 1; // reset - sr_rx_ctrl->vrt_header = (0 - | VRTH_PT_IF_DATA_WITH_SID - | (vrt_has_trailer()? VRTH_HAS_TRAILER : 0) - | VRTH_TSI_OTHER - | VRTH_TSF_SAMPLE_CNT - ); - sr_rx_ctrl->vrt_stream_id = 0; - sr_rx_ctrl->vrt_trailer = 0; -} - -/* - * 1's complement sum for IP and UDP headers - * - * init chksum to zero to start. - */ -static unsigned int -CHKSUM(unsigned int x, unsigned int *chksum) -{ - *chksum += x; - *chksum = (*chksum & 0xffff) + (*chksum>>16); - *chksum = (*chksum & 0xffff) + (*chksum>>16); - return x; -} - -/* - * Called when eth phy state changes (w/ interrupts disabled) - */ -volatile bool link_is_up = false; // eth handler sets this -void -link_changed_callback(int speed) -{ - link_is_up = speed != 0; - hal_set_leds(link_is_up ? LED_RJ45 : 0x0, LED_RJ45); - printf("\neth link changed: speed = %d\n", speed); -} - -static void setup_network(void){ - - //setup ethernet header machine - sr_udp_sm->eth_hdr.mac_dst_0_1 = (fp_mac_addr_dst.addr[0] << 8) | fp_mac_addr_dst.addr[1]; - sr_udp_sm->eth_hdr.mac_dst_2_3 = (fp_mac_addr_dst.addr[2] << 8) | fp_mac_addr_dst.addr[3]; - sr_udp_sm->eth_hdr.mac_dst_4_5 = (fp_mac_addr_dst.addr[4] << 8) | fp_mac_addr_dst.addr[5]; - sr_udp_sm->eth_hdr.mac_src_0_1 = (fp_mac_addr_src.addr[0] << 8) | fp_mac_addr_src.addr[1]; - sr_udp_sm->eth_hdr.mac_src_2_3 = (fp_mac_addr_src.addr[2] << 8) | fp_mac_addr_src.addr[3]; - sr_udp_sm->eth_hdr.mac_src_4_5 = (fp_mac_addr_src.addr[4] << 8) | fp_mac_addr_src.addr[5]; - sr_udp_sm->eth_hdr.ether_type = ETHERTYPE_IPV4; - - //setup ip header machine - unsigned int chksum = 0; - sr_udp_sm->ip_hdr.ver_ihl_tos = CHKSUM(0x4500, &chksum); // IPV4, 5 words of header (20 bytes), TOS=0 - sr_udp_sm->ip_hdr.total_length = UDP_SM_INS_IP_LEN; // Don't checksum this line in SW - sr_udp_sm->ip_hdr.identification = CHKSUM(0x0000, &chksum); // ID - sr_udp_sm->ip_hdr.flags_frag_off = CHKSUM(0x4000, &chksum); // don't fragment - sr_udp_sm->ip_hdr.ttl_proto = CHKSUM(0x2011, &chksum); // TTL=32, protocol = UDP (17 decimal) - //sr_udp_sm->ip_hdr.checksum .... filled in below - uint32_t src_ip_addr = fp_socket_src.addr.addr; - uint32_t dst_ip_addr = fp_socket_dst.addr.addr; - sr_udp_sm->ip_hdr.src_addr_high = CHKSUM(src_ip_addr >> 16, &chksum); // IP src high - sr_udp_sm->ip_hdr.src_addr_low = CHKSUM(src_ip_addr & 0xffff, &chksum); // IP src low - sr_udp_sm->ip_hdr.dst_addr_high = CHKSUM(dst_ip_addr >> 16, &chksum); // IP dst high - sr_udp_sm->ip_hdr.dst_addr_low = CHKSUM(dst_ip_addr & 0xffff, &chksum); // IP dst low - sr_udp_sm->ip_hdr.checksum = UDP_SM_INS_IP_HDR_CHKSUM | (chksum & 0xffff); - - //setup the udp header machine - sr_udp_sm->udp_hdr.src_port = fp_socket_src.port; - sr_udp_sm->udp_hdr.dst_port = fp_socket_dst.port; - sr_udp_sm->udp_hdr.length = UDP_SM_INS_UDP_LEN; - sr_udp_sm->udp_hdr.checksum = UDP_SM_LAST_WORD; // zero UDP checksum -} - -/* - * This is called when the DSP Rx chain has filled in a packet. - */ -bool -fw_sets_seqno_inspector(dbsm_t *sm, int buf_this) // returns false -{ - // insert the correct length into the control word and vrt header - rx_dsp_buff_t *buff = (rx_dsp_buff_t*)buffer_ram(buf_this); - size_t vrt_len = buffer_pool_status->last_line[buf_this]-1; - buff->control_word = MK_RX_CTRL_WORD(vrt_len); - buff->vrt_header[0] = (buff->vrt_header[0] & ~VRTH_PKT_SIZE_MASK) | (vrt_len & VRTH_PKT_SIZE_MASK); - - // queue up another rx command when required - if (auto_reload_command && --streaming_frame_count == 0){ - streaming_frame_count = FRAMES_PER_CMD; - sr_rx_ctrl->time_secs = 0; - sr_rx_ctrl->time_ticks = 0; //enqueue last command - } - - return false; // we didn't handle the packet -} - - -inline static void -buffer_irq_handler(unsigned irq) -{ - uint32_t status = buffer_pool_status->status; - - dbsm_process_status(&dsp_tx_sm, status); - dbsm_process_status(&dsp_rx_sm, status); -} - -int -main(void) -{ - u2_init(); - - putstr("\nTxRx-NEWETH\n"); - print_mac_addr(ethernet_mac_addr()->addr); - newline(); - print_ip_addr(get_ip_addr()); newline(); - printf("Control protocol version: %d\n", USRP2_PROTO_VERSION); - - ethernet_register_link_changed_callback(link_changed_callback); - ethernet_init(); - - register_mac_addr(ethernet_mac_addr()); - register_ip_addr(get_ip_addr()); - - register_udp_listener(USRP2_UDP_CTRL_PORT, handle_udp_ctrl_packet); - register_udp_listener(USRP2_UDP_DATA_PORT, handle_udp_data_packet); - - hal_set_led_src(0, LEDS_SW); - -#if 0 - // make bit 15 of Tx gpio's be a s/w output - hal_gpio_set_sel(GPIO_TX_BANK, 15, 's'); - hal_gpio_set_ddr(GPIO_TX_BANK, 0x8000, 0x8000); -#endif - -//set them all to the atr settings by default -hal_gpio_set_sels(GPIO_TX_BANK, "aaaaaaaaaaaaaaaa"); -hal_gpio_set_sels(GPIO_RX_BANK, "aaaaaaaaaaaaaaaa"); - - output_regs->debug_mux_ctrl = 1; -#if DEBUG_MODE - hal_gpio_set_sels(GPIO_TX_BANK, "0000000000000000"); - hal_gpio_set_sels(GPIO_RX_BANK, "0000000000000000"); - hal_gpio_set_ddr(GPIO_TX_BANK, 0xffff, 0xffff); - hal_gpio_set_ddr(GPIO_RX_BANK, 0xffff, 0xffff); -#endif - - - // initialize double buffering state machine for ethernet -> DSP Tx - - dbsm_init(&dsp_tx_sm, DSP_TX_BUF_0, - &dsp_tx_recv_args, &dsp_tx_send_args, - eth_pkt_inspector); - - - // initialize double buffering state machine for DSP RX -> Ethernet - - dbsm_init(&dsp_rx_sm, DSP_RX_BUF_0, - &dsp_rx_recv_args, &dsp_rx_send_args, - fw_sets_seqno_inspector); - - - // tell app_common that this dbsm could be sending to the ethernet - ac_could_be_sending_to_eth = &dsp_rx_sm; - - sr_tx_ctrl->clear_state = 1; - bp_clear_buf(DSP_TX_BUF_0); - bp_clear_buf(DSP_TX_BUF_1); - - // kick off the state machine - dbsm_start(&dsp_tx_sm); - - //int which = 0; - - while(1){ - // hal_gpio_write(GPIO_TX_BANK, which, 0x8000); - // which ^= 0x8000; - - buffer_irq_handler(0); - - int pending = pic_regs->pending; // poll for under or overrun - - if (pending & PIC_UNDERRUN_INT){ - dbsm_handle_tx_underrun(&dsp_tx_sm); - pic_regs->pending = PIC_UNDERRUN_INT; // clear interrupt - putchar('U'); - } - - if (pending & PIC_OVERRUN_INT){ - dbsm_handle_rx_overrun(&dsp_rx_sm); - pic_regs->pending = PIC_OVERRUN_INT; // clear pending interrupt - - // FIXME Figure out how to handle this robustly. - // Any buffers that are emptying should be allowed to drain... - - if (auto_reload_command){ - // restart_streaming(); - // FIXME report error - } - else { - // FIXME report error - } - putchar('O'); - } - } -} diff --git a/firmware/microblaze/apps/txrx_uhd.c b/firmware/microblaze/apps/txrx_uhd.c new file mode 100644 index 000000000..7a6fbd993 --- /dev/null +++ b/firmware/microblaze/apps/txrx_uhd.c @@ -0,0 +1,691 @@ +// +// Copyright 2010 Ettus Research LLC +// +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define DEBUG_MODE 0 //0 for normal operation + +#include +#include +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include +#include "ethernet.h" +#include "nonstdio.h" +#include "dbsm.h" +#include +#include +#include "memcpy_wa.h" +#include +#include +#include +#include "clocks.h" +#include +#include "usrp2/fw_common.h" +#include +#include +#include +#include + +#define LEDS_SW LED_A + +/* + * Full duplex Tx and Rx between ethernet and DSP pipelines + * + * Buffer 1 is used by the cpu to send frames to the host. + * Buffers 2 and 3 are used to double-buffer the DSP Rx to eth flow + * Buffers 4 and 5 are used to double-buffer the eth to DSP Tx eth flow + */ +//#define CPU_RX_BUF 0 // eth -> cpu + +#define DSP_RX_BUF_0 2 // dsp rx -> eth (double buffer) +#define DSP_RX_BUF_1 3 // dsp rx -> eth +#define DSP_TX_BUF_0 4 // eth -> dsp tx (double buffer) +#define DSP_TX_BUF_1 5 // eth -> dsp tx + +/* + * ================================================================ + * configure DSP TX double buffering state machine (eth -> dsp) + * ================================================================ + */ + +// DSP Tx reads ethernet header words +#define DSP_TX_FIRST_LINE ((sizeof(padded_eth_hdr_t) + sizeof(struct ip_hdr) + sizeof(struct udp_hdr))/sizeof(uint32_t)) + +// Receive from ethernet +buf_cmd_args_t dsp_tx_recv_args = { + PORT_ETH, + 0, + BP_LAST_LINE +}; + +// send to DSP Tx +buf_cmd_args_t dsp_tx_send_args = { + PORT_DSP, + DSP_TX_FIRST_LINE, // starts just past transport header + 0 // filled in from last_line register +}; + +dbsm_t dsp_tx_sm; // the state machine + +/* + * ================================================================ + * configure DSP RX double buffering state machine (dsp -> eth) + * ================================================================ + */ + +typedef struct{ + uint32_t control_word; + uint32_t vrt_header[]; +} rx_dsp_buff_t; + +#define MK_RX_CTRL_WORD(num_words) (((num_words)*sizeof(uint32_t)) | (1 << 16)) + +// DSP Rx writes ethernet header words +#define DSP_RX_FIRST_LINE 1 //1 = number of control words (see above) + +// receive from DSP +buf_cmd_args_t dsp_rx_recv_args = { + PORT_DSP, + DSP_RX_FIRST_LINE, + BP_LAST_LINE +}; + +// send to ETH +buf_cmd_args_t dsp_rx_send_args = { + PORT_ETH, + 0, // starts with ethernet header in line 0 + 0, // filled in from list_line register +}; + +dbsm_t dsp_rx_sm; // the state machine + + +// The mac address of the host we're sending to. +eth_mac_addr_t host_mac_addr; + +//controls continuous streaming... +static bool auto_reload_command = false; +static size_t streaming_items_per_frame = 0; +static int streaming_frame_count = 0; +#define FRAMES_PER_CMD 2 + +static void setup_network(void); +static void setup_vrt(void); + +// ---------------------------------------------------------------- +// the fast-path setup global variables +// ---------------------------------------------------------------- +static eth_mac_addr_t fp_mac_addr_src, fp_mac_addr_dst; +static struct socket_address fp_socket_src, fp_socket_dst; + +// ---------------------------------------------------------------- +void start_rx_streaming_cmd(void); +void stop_rx_cmd(void); + +static void print_ip_addr(const void *t){ + uint8_t *p = (uint8_t *)t; + printf("%d.%d.%d.%d", p[0], p[1], p[2], p[3]); +} + +void handle_udp_data_packet( + struct socket_address src, struct socket_address dst, + unsigned char *payload, int payload_len +){ + //store the 2nd word as the following: + streaming_items_per_frame = ((uint32_t *)payload)[1]; + + //its a tiny payload, load the fast-path variables + fp_mac_addr_src = *ethernet_mac_addr(); + arp_cache_lookup_mac(&src.addr, &fp_mac_addr_dst); + fp_socket_src = dst; + fp_socket_dst = src; + printf("Storing for fast path:\n"); + printf(" source mac addr: "); + print_mac_addr(fp_mac_addr_src.addr); newline(); + printf(" source ip addr: "); + print_ip_addr(&fp_socket_src.addr); newline(); + printf(" source udp port: %d\n", fp_socket_src.port); + printf(" destination mac addr: "); + print_mac_addr(fp_mac_addr_dst.addr); newline(); + printf(" destination ip addr: "); + print_ip_addr(&fp_socket_dst.addr); newline(); + printf(" destination udp port: %d\n", fp_socket_dst.port); + newline(); + + //setup network and vrt + setup_network(); + setup_vrt(); + + // kick off the state machine + dbsm_start(&dsp_rx_sm); + +} + +static void inline issue_stream_command(size_t nsamps, bool now, bool chain, uint32_t secs, uint32_t ticks, bool start){ + //printf("Stream cmd: nsamps %d, now %d, chain %d, secs %u, ticks %u\n", (int)nsamps, now, chain, secs, ticks); + sr_rx_ctrl->cmd = MK_RX_CMD(nsamps, now, chain); + + if (start) dbsm_start(&dsp_rx_sm); + + sr_rx_ctrl->time_secs = secs; + sr_rx_ctrl->time_ticks = ticks; // enqueue command +} + +#define OTW_GPIO_BANK_TO_NUM(bank) \ + (((bank) == USRP2_DIR_RX)? (GPIO_RX_BANK) : (GPIO_TX_BANK)) + +void handle_udp_ctrl_packet( + struct socket_address src, struct socket_address dst, + unsigned char *payload, int payload_len +){ + //printf("Got ctrl packet #words: %d\n", (int)payload_len); + usrp2_ctrl_data_t *ctrl_data_in = (usrp2_ctrl_data_t *)payload; + uint32_t ctrl_data_in_id = ctrl_data_in->id; + + //ensure that the protocol versions match + if (payload_len >= sizeof(uint32_t) && ctrl_data_in->proto_ver != USRP2_PROTO_VERSION){ + printf("!Error in control packet handler: Expected protocol version %d, but got %d\n", + USRP2_PROTO_VERSION, ctrl_data_in->proto_ver + ); + ctrl_data_in_id = USRP2_CTRL_ID_GIVE_ME_YOUR_IP_ADDR_BRO; + } + + //ensure that this is not a short packet + if (payload_len < sizeof(usrp2_ctrl_data_t)){ + printf("!Error in control packet handler: Expected payload length %d, but got %d\n", + (int)sizeof(usrp2_ctrl_data_t), payload_len + ); + ctrl_data_in_id = USRP2_CTRL_ID_HUH_WHAT; + } + + //setup the output data + usrp2_ctrl_data_t ctrl_data_out = { + .proto_ver = USRP2_PROTO_VERSION, + .id=USRP2_CTRL_ID_HUH_WHAT, + .seq=ctrl_data_in->seq + }; + + //handle the data based on the id + switch(ctrl_data_in_id){ + + /******************************************************************* + * Addressing + ******************************************************************/ + case USRP2_CTRL_ID_GIVE_ME_YOUR_IP_ADDR_BRO: + ctrl_data_out.id = USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE; + memcpy(&ctrl_data_out.data.ip_addr, get_ip_addr(), sizeof(struct ip_addr)); + break; + + case USRP2_CTRL_ID_HERE_IS_A_NEW_IP_ADDR_BRO: + ctrl_data_out.id = USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE; + set_ip_addr((struct ip_addr *)&ctrl_data_in->data.ip_addr); + memcpy(&ctrl_data_out.data.ip_addr, get_ip_addr(), sizeof(struct ip_addr)); + break; + + case USRP2_CTRL_ID_GIVE_ME_YOUR_MAC_ADDR_BRO: + ctrl_data_out.id = USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE; + memcpy(&ctrl_data_out.data.mac_addr, ethernet_mac_addr(), sizeof(eth_mac_addr_t)); + break; + + case USRP2_CTRL_ID_HERE_IS_A_NEW_MAC_ADDR_BRO: + ctrl_data_out.id = USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE; + ethernet_set_mac_addr((eth_mac_addr_t *)&ctrl_data_in->data.mac_addr); + memcpy(&ctrl_data_out.data.mac_addr, ethernet_mac_addr(), sizeof(eth_mac_addr_t)); + break; + + case USRP2_CTRL_ID_GIVE_ME_YOUR_DBOARD_IDS_BRO: + ctrl_data_out.id = USRP2_CTRL_ID_THESE_ARE_MY_DBOARD_IDS_DUDE; + ctrl_data_out.data.dboard_ids.tx_id = read_dboard_eeprom(I2C_ADDR_TX_A); + ctrl_data_out.data.dboard_ids.rx_id = read_dboard_eeprom(I2C_ADDR_RX_A); + break; + + /******************************************************************* + * SPI + ******************************************************************/ + case USRP2_CTRL_ID_TRANSACT_ME_SOME_SPI_BRO:{ + //transact + uint32_t result = spi_transact( + (ctrl_data_in->data.spi_args.readback == 0)? SPI_TXONLY : SPI_TXRX, + ctrl_data_in->data.spi_args.dev, //which device + ctrl_data_in->data.spi_args.data, //32 bit data + ctrl_data_in->data.spi_args.num_bits, //length in bits + (ctrl_data_in->data.spi_args.mosi_edge == USRP2_CLK_EDGE_RISE)? SPIF_PUSH_FALL : SPIF_PUSH_RISE | + (ctrl_data_in->data.spi_args.miso_edge == USRP2_CLK_EDGE_RISE)? SPIF_LATCH_RISE : SPIF_LATCH_FALL + ); + + //load output + ctrl_data_out.data.spi_args.data = result; + ctrl_data_out.id = USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE; + } + break; + + /******************************************************************* + * I2C + ******************************************************************/ + case USRP2_CTRL_ID_DO_AN_I2C_READ_FOR_ME_BRO:{ + uint8_t num_bytes = ctrl_data_in->data.i2c_args.bytes; + i2c_read( + ctrl_data_in->data.i2c_args.addr, + ctrl_data_out.data.i2c_args.data, + num_bytes + ); + ctrl_data_out.id = USRP2_CTRL_ID_HERES_THE_I2C_DATA_DUDE; + ctrl_data_out.data.i2c_args.bytes = num_bytes; + } + break; + + case USRP2_CTRL_ID_WRITE_THESE_I2C_VALUES_BRO:{ + uint8_t num_bytes = ctrl_data_in->data.i2c_args.bytes; + i2c_write( + ctrl_data_in->data.i2c_args.addr, + ctrl_data_in->data.i2c_args.data, + num_bytes + ); + ctrl_data_out.id = USRP2_CTRL_ID_COOL_IM_DONE_I2C_WRITE_DUDE; + ctrl_data_out.data.i2c_args.bytes = num_bytes; + } + break; + + /******************************************************************* + * Streaming + ******************************************************************/ + case USRP2_CTRL_ID_SEND_STREAM_COMMAND_FOR_ME_BRO:{ + + //issue two commands and set the auto-reload flag + if (ctrl_data_in->data.stream_cmd.continuous){ + printf("Setting up continuous streaming...\n"); + printf("items per frame: %d\n", (int)streaming_items_per_frame); + hal_set_leds(LED_A, LEDS_SW); + auto_reload_command = true; + streaming_frame_count = FRAMES_PER_CMD; + + issue_stream_command( + streaming_items_per_frame * FRAMES_PER_CMD, + (ctrl_data_in->data.stream_cmd.now == 0)? false : true, //now + true, //chain + ctrl_data_in->data.stream_cmd.secs, + ctrl_data_in->data.stream_cmd.ticks, + true //start + ); + + issue_stream_command( + streaming_items_per_frame * FRAMES_PER_CMD, + true, //now + true, //chain + 0, 0, //time does not matter + false + ); + + } + + //issue regular stream commands (split commands if too large) + else{ + hal_set_leds(0, LEDS_SW); + auto_reload_command = false; + size_t num_samps = ctrl_data_in->data.stream_cmd.num_samps; + if (num_samps == 0) num_samps = 1; //FIXME hack, zero is used when stopping continuous streaming but it somehow makes it inifinite + + bool chain = num_samps > MAX_SAMPLES_PER_CMD; + issue_stream_command( + (chain)? streaming_items_per_frame : num_samps, //nsamps + (ctrl_data_in->data.stream_cmd.now == 0)? false : true, //now + (ctrl_data_in->data.stream_cmd.chain == 0)? chain : true, //chain + ctrl_data_in->data.stream_cmd.secs, + ctrl_data_in->data.stream_cmd.ticks, + false + ); + + //handle rest of the samples that did not fit into one cmd + while(chain){ + num_samps -= MAX_SAMPLES_PER_CMD; + chain = num_samps > MAX_SAMPLES_PER_CMD; + issue_stream_command( + (chain)? streaming_items_per_frame : num_samps, //nsamps + true, //now + (ctrl_data_in->data.stream_cmd.chain == 0)? chain : true, //chain + 0, 0, //time does not matter + false + ); + } + } + ctrl_data_out.id = USRP2_CTRL_ID_GOT_THAT_STREAM_COMMAND_DUDE; + break; + } + + /******************************************************************* + * Peek and Poke Register + ******************************************************************/ + case USRP2_CTRL_ID_POKE_THIS_REGISTER_FOR_ME_BRO: + if (ctrl_data_in->data.poke_args.addr < 0xC000){ + printf("error! tried to poke into 0x%x\n", ctrl_data_in->data.poke_args.addr); + } + else switch(ctrl_data_in->data.poke_args.num_bytes){ + case sizeof(uint32_t): + *((uint32_t *) ctrl_data_in->data.poke_args.addr) = (uint32_t)ctrl_data_in->data.poke_args.data; + break; + + case sizeof(uint16_t): + *((uint16_t *) ctrl_data_in->data.poke_args.addr) = (uint16_t)ctrl_data_in->data.poke_args.data; + break; + + case sizeof(uint8_t): + *((uint8_t *) ctrl_data_in->data.poke_args.addr) = (uint8_t)ctrl_data_in->data.poke_args.data; + break; + + } + ctrl_data_out.id = USRP2_CTRL_ID_OMG_POKED_REGISTER_SO_BAD_DUDE; + break; + + case USRP2_CTRL_ID_PEEK_AT_THIS_REGISTER_FOR_ME_BRO: + switch(ctrl_data_in->data.poke_args.num_bytes){ + case sizeof(uint32_t): + ctrl_data_in->data.poke_args.data = *((uint32_t *) ctrl_data_in->data.poke_args.addr); + break; + + case sizeof(uint16_t): + ctrl_data_in->data.poke_args.data = *((uint16_t *) ctrl_data_in->data.poke_args.addr); + break; + + case sizeof(uint8_t): + ctrl_data_in->data.poke_args.data = *((uint8_t *) ctrl_data_in->data.poke_args.addr); + break; + + } + ctrl_data_out.id = USRP2_CTRL_ID_WOAH_I_DEFINITELY_PEEKED_IT_DUDE; + break; + + /******************************************************************* + * Hardware Rev Numbers + ******************************************************************/ + case USRP2_CTRL_ID_WHATS_THE_HARDWARE_REV_NOS_BRO: + ctrl_data_out.data.hw_rev.major = u2_hw_rev_major; + ctrl_data_out.data.hw_rev.minor = u2_hw_rev_minor; + ctrl_data_out.id = USRP2_CTRL_ID_TAKE_THE_HARDWARE_REV_NOS_DUDE; + break; + + default: + ctrl_data_out.id = USRP2_CTRL_ID_HUH_WHAT; + + } + send_udp_pkt(USRP2_UDP_CTRL_PORT, src, &ctrl_data_out, sizeof(ctrl_data_out)); +} + +/* + * Called when an ethernet packet is received. + * Return true if we handled it here, otherwise + * it'll be passed on to the DSP Tx pipe + */ +static bool +eth_pkt_inspector(dbsm_t *sm, int bufno) +{ + //point me to the ethernet frame + uint32_t *buff = (uint32_t *)buffer_ram(bufno); + + //treat this as fast-path data? + // We have to do this operation as fast as possible. + // Therefore, we do not check all the headers, + // just check that the udp port matches + // and that the vrt header is non zero. + // In the future, a hardware state machine will do this... + if ( //warning! magic numbers approaching.... + (((buff + ((2 + 14 + 20)/sizeof(uint32_t)))[0] & 0xffff) == USRP2_UDP_DATA_PORT) && + ((buff + ((2 + 14 + 20 + 8)/sizeof(uint32_t)))[0] != USRP2_INVALID_VRT_HEADER) + ) return false; + + //test if its an ip recovery packet + typedef struct{ + padded_eth_hdr_t eth_hdr; + char code[4]; + union { + struct ip_addr ip_addr; + } data; + }recovery_packet_t; + recovery_packet_t *recovery_packet = (recovery_packet_t *)buff; + if (recovery_packet->eth_hdr.ethertype == 0xbeee && strncmp(recovery_packet->code, "addr", 4) == 0){ + printf("Got ip recovery packet: "); print_ip_addr(&recovery_packet->data.ip_addr); newline(); + set_ip_addr(&recovery_packet->data.ip_addr); + return true; + } + + //pass it to the slow-path handler + size_t len = buffer_pool_status->last_line[bufno] - 3; + handle_eth_packet(buff, len); + return true; +} + +//------------------------------------------------------------------ + +static bool vrt_has_trailer(void){ + return USRP2_HOST_RX_VRT_TRAILER_WORDS32 > 0; +} + +static void setup_vrt(void){ + // setup RX DSP regs + sr_rx_ctrl->nsamples_per_pkt = streaming_items_per_frame; + sr_rx_ctrl->nchannels = 1; + sr_rx_ctrl->clear_overrun = 1; // reset + sr_rx_ctrl->vrt_header = (0 + | VRTH_PT_IF_DATA_WITH_SID + | (vrt_has_trailer()? VRTH_HAS_TRAILER : 0) + | VRTH_TSI_OTHER + | VRTH_TSF_SAMPLE_CNT + ); + sr_rx_ctrl->vrt_stream_id = 0; + sr_rx_ctrl->vrt_trailer = 0; +} + +/* + * 1's complement sum for IP and UDP headers + * + * init chksum to zero to start. + */ +static unsigned int +CHKSUM(unsigned int x, unsigned int *chksum) +{ + *chksum += x; + *chksum = (*chksum & 0xffff) + (*chksum>>16); + *chksum = (*chksum & 0xffff) + (*chksum>>16); + return x; +} + +/* + * Called when eth phy state changes (w/ interrupts disabled) + */ +volatile bool link_is_up = false; // eth handler sets this +void +link_changed_callback(int speed) +{ + link_is_up = speed != 0; + hal_set_leds(link_is_up ? LED_RJ45 : 0x0, LED_RJ45); + printf("\neth link changed: speed = %d\n", speed); +} + +static void setup_network(void){ + + //setup ethernet header machine + sr_udp_sm->eth_hdr.mac_dst_0_1 = (fp_mac_addr_dst.addr[0] << 8) | fp_mac_addr_dst.addr[1]; + sr_udp_sm->eth_hdr.mac_dst_2_3 = (fp_mac_addr_dst.addr[2] << 8) | fp_mac_addr_dst.addr[3]; + sr_udp_sm->eth_hdr.mac_dst_4_5 = (fp_mac_addr_dst.addr[4] << 8) | fp_mac_addr_dst.addr[5]; + sr_udp_sm->eth_hdr.mac_src_0_1 = (fp_mac_addr_src.addr[0] << 8) | fp_mac_addr_src.addr[1]; + sr_udp_sm->eth_hdr.mac_src_2_3 = (fp_mac_addr_src.addr[2] << 8) | fp_mac_addr_src.addr[3]; + sr_udp_sm->eth_hdr.mac_src_4_5 = (fp_mac_addr_src.addr[4] << 8) | fp_mac_addr_src.addr[5]; + sr_udp_sm->eth_hdr.ether_type = ETHERTYPE_IPV4; + + //setup ip header machine + unsigned int chksum = 0; + sr_udp_sm->ip_hdr.ver_ihl_tos = CHKSUM(0x4500, &chksum); // IPV4, 5 words of header (20 bytes), TOS=0 + sr_udp_sm->ip_hdr.total_length = UDP_SM_INS_IP_LEN; // Don't checksum this line in SW + sr_udp_sm->ip_hdr.identification = CHKSUM(0x0000, &chksum); // ID + sr_udp_sm->ip_hdr.flags_frag_off = CHKSUM(0x4000, &chksum); // don't fragment + sr_udp_sm->ip_hdr.ttl_proto = CHKSUM(0x2011, &chksum); // TTL=32, protocol = UDP (17 decimal) + //sr_udp_sm->ip_hdr.checksum .... filled in below + uint32_t src_ip_addr = fp_socket_src.addr.addr; + uint32_t dst_ip_addr = fp_socket_dst.addr.addr; + sr_udp_sm->ip_hdr.src_addr_high = CHKSUM(src_ip_addr >> 16, &chksum); // IP src high + sr_udp_sm->ip_hdr.src_addr_low = CHKSUM(src_ip_addr & 0xffff, &chksum); // IP src low + sr_udp_sm->ip_hdr.dst_addr_high = CHKSUM(dst_ip_addr >> 16, &chksum); // IP dst high + sr_udp_sm->ip_hdr.dst_addr_low = CHKSUM(dst_ip_addr & 0xffff, &chksum); // IP dst low + sr_udp_sm->ip_hdr.checksum = UDP_SM_INS_IP_HDR_CHKSUM | (chksum & 0xffff); + + //setup the udp header machine + sr_udp_sm->udp_hdr.src_port = fp_socket_src.port; + sr_udp_sm->udp_hdr.dst_port = fp_socket_dst.port; + sr_udp_sm->udp_hdr.length = UDP_SM_INS_UDP_LEN; + sr_udp_sm->udp_hdr.checksum = UDP_SM_LAST_WORD; // zero UDP checksum +} + +/* + * This is called when the DSP Rx chain has filled in a packet. + */ +bool +fw_sets_seqno_inspector(dbsm_t *sm, int buf_this) // returns false +{ + // insert the correct length into the control word and vrt header + rx_dsp_buff_t *buff = (rx_dsp_buff_t*)buffer_ram(buf_this); + size_t vrt_len = buffer_pool_status->last_line[buf_this]-1; + buff->control_word = MK_RX_CTRL_WORD(vrt_len); + buff->vrt_header[0] = (buff->vrt_header[0] & ~VRTH_PKT_SIZE_MASK) | (vrt_len & VRTH_PKT_SIZE_MASK); + + // queue up another rx command when required + if (auto_reload_command && --streaming_frame_count == 0){ + streaming_frame_count = FRAMES_PER_CMD; + sr_rx_ctrl->time_secs = 0; + sr_rx_ctrl->time_ticks = 0; //enqueue last command + } + + return false; // we didn't handle the packet +} + + +inline static void +buffer_irq_handler(unsigned irq) +{ + uint32_t status = buffer_pool_status->status; + + dbsm_process_status(&dsp_tx_sm, status); + dbsm_process_status(&dsp_rx_sm, status); +} + +int +main(void) +{ + u2_init(); + + putstr("\nTxRx-NEWETH\n"); + print_mac_addr(ethernet_mac_addr()->addr); + newline(); + print_ip_addr(get_ip_addr()); newline(); + printf("Control protocol version: %d\n", USRP2_PROTO_VERSION); + + ethernet_register_link_changed_callback(link_changed_callback); + ethernet_init(); + + register_mac_addr(ethernet_mac_addr()); + register_ip_addr(get_ip_addr()); + + register_udp_listener(USRP2_UDP_CTRL_PORT, handle_udp_ctrl_packet); + register_udp_listener(USRP2_UDP_DATA_PORT, handle_udp_data_packet); + + hal_set_led_src(0, LEDS_SW); + +#if 0 + // make bit 15 of Tx gpio's be a s/w output + hal_gpio_set_sel(GPIO_TX_BANK, 15, 's'); + hal_gpio_set_ddr(GPIO_TX_BANK, 0x8000, 0x8000); +#endif + +//set them all to the atr settings by default +hal_gpio_set_sels(GPIO_TX_BANK, "aaaaaaaaaaaaaaaa"); +hal_gpio_set_sels(GPIO_RX_BANK, "aaaaaaaaaaaaaaaa"); + + output_regs->debug_mux_ctrl = 1; +#if DEBUG_MODE + hal_gpio_set_sels(GPIO_TX_BANK, "0000000000000000"); + hal_gpio_set_sels(GPIO_RX_BANK, "0000000000000000"); + hal_gpio_set_ddr(GPIO_TX_BANK, 0xffff, 0xffff); + hal_gpio_set_ddr(GPIO_RX_BANK, 0xffff, 0xffff); +#endif + + + // initialize double buffering state machine for ethernet -> DSP Tx + + dbsm_init(&dsp_tx_sm, DSP_TX_BUF_0, + &dsp_tx_recv_args, &dsp_tx_send_args, + eth_pkt_inspector); + + + // initialize double buffering state machine for DSP RX -> Ethernet + + dbsm_init(&dsp_rx_sm, DSP_RX_BUF_0, + &dsp_rx_recv_args, &dsp_rx_send_args, + fw_sets_seqno_inspector); + + + // tell app_common that this dbsm could be sending to the ethernet + ac_could_be_sending_to_eth = &dsp_rx_sm; + + sr_tx_ctrl->clear_state = 1; + bp_clear_buf(DSP_TX_BUF_0); + bp_clear_buf(DSP_TX_BUF_1); + + // kick off the state machine + dbsm_start(&dsp_tx_sm); + + //int which = 0; + + while(1){ + // hal_gpio_write(GPIO_TX_BANK, which, 0x8000); + // which ^= 0x8000; + + buffer_irq_handler(0); + + int pending = pic_regs->pending; // poll for under or overrun + + if (pending & PIC_UNDERRUN_INT){ + dbsm_handle_tx_underrun(&dsp_tx_sm); + pic_regs->pending = PIC_UNDERRUN_INT; // clear interrupt + putchar('U'); + } + + if (pending & PIC_OVERRUN_INT){ + dbsm_handle_rx_overrun(&dsp_rx_sm); + pic_regs->pending = PIC_OVERRUN_INT; // clear pending interrupt + + // FIXME Figure out how to handle this robustly. + // Any buffers that are emptying should be allowed to drain... + + if (auto_reload_command){ + // restart_streaming(); + // FIXME report error + } + else { + // FIXME report error + } + putchar('O'); + } + } +} diff --git a/host/docs/usrp2.rst b/host/docs/usrp2.rst index 32e7374c8..092332442 100644 --- a/host/docs/usrp2.rst +++ b/host/docs/usrp2.rst @@ -39,7 +39,7 @@ Run the following commands: ./configure --host=mb make -*The image file will be ./apps/txrx.bin* +*The image file will be ./apps/txrx_uhd.bin* ------------------------------------------------------------------------ Load the images onto the SD card -- cgit v1.2.3