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 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