From b73d5fc1af46d739e841af89bf3841fd6a84bdf7 Mon Sep 17 00:00:00 2001 From: Werner Almesberger Date: Wed, 24 Jul 2013 07:57:35 -0300 Subject: [PATCH 1/7] atusb/fw/mac.c: remove queued_rx; buffer frames in the MCU instead queued_rx held a frame in the transceiver's receive buffer until we could transfer it. This may cause frame loss if a new reception begins. We now retrieve frames from the transceiver immediately and buffer them in the MCU. --- atusb/fw/mac.c | 77 ++++++++++++++++++++++++++++---------------------- 1 file changed, 44 insertions(+), 33 deletions(-) diff --git a/atusb/fw/mac.c b/atusb/fw/mac.c index 05d16d6..255ac6e 100644 --- a/atusb/fw/mac.c +++ b/atusb/fw/mac.c @@ -22,15 +22,18 @@ #include "mac.h" +#define RX_BUFS 2 + + bool (*mac_irq)(void) = NULL; -static uint8_t rx_buf[MAX_PSDU+2]; /* PHDR+payload+LQ */ +static uint8_t rx_buf[RX_BUFS][MAX_PSDU+2]; /* PHDR+payload+LQ */ +static bool rx_in = 0, rx_out = 0; static uint8_t tx_buf[MAX_PSDU]; static uint8_t tx_size = 0; static bool txing = 0; static bool queued_tx_ack = 0; -static bool queued_rx = 0; static uint8_t next_seq, this_seq, queued_seq; @@ -62,27 +65,45 @@ static void reg_write(uint8_t reg, uint8_t value) /* ----- Interrupt handling ------------------------------------------------ */ -static void receive_frame(void); +static void rx_done(void *user); +static void tx_ack_done(void *user); + + +static void usb_next(void) +{ + const uint8_t *buf; + + if (rx_in != rx_out) { + buf = rx_buf[rx_out]; + led(1); + usb_send(&eps[1], buf, buf[0]+2, rx_done, NULL); + } + + if (queued_tx_ack) { + usb_send(&eps[1], &queued_seq, 1, tx_ack_done, NULL); + queued_tx_ack = 0; + } +} + + +static void tx_ack_done(void *user) +{ + usb_next(); +} static void rx_done(void *user) { led(0); - if (queued_rx) { - receive_frame(); - queued_rx = 0; - return; - } - if (queued_tx_ack) { - usb_send(&eps[1], &queued_seq, 1, rx_done, NULL); - queued_tx_ack = 0; - } + rx_out = (rx_out+1) & (RX_BUFS-1); + usb_next(); } static void receive_frame(void) { uint8_t size, i; + uint8_t *buf; spi_begin(); if (!(spi_io(AT86RF230_BUF_READ) & RX_CRC_VALID)) { @@ -95,20 +116,16 @@ static void receive_frame(void) return; } - rx_buf[0] = size; + buf = rx_buf[rx_in]; for (i = 0; i != size+1; i++) - rx_buf[i+1] = spi_recv(); + buf[i+1] = spi_recv(); spi_end(); - led(1); - usb_send(&eps[1], rx_buf, size+2, rx_done, NULL); -} + buf[0] = size; + rx_in = (rx_in+1) & (RX_BUFS-1); -static void flush_queued_rx(void) -{ - if (queued_rx) - receive_frame(); - queued_rx = 0; + if (eps[1].state == EP_IDLE) + usb_next(); } @@ -122,7 +139,7 @@ static bool handle_irq(void) if (txing) { if (eps[1].state == EP_IDLE) { - usb_send(&eps[1], &this_seq, 1, rx_done, NULL); + usb_send(&eps[1], &this_seq, 1, tx_ack_done, NULL); } else { queued_tx_ack = 1; queued_seq = this_seq; @@ -131,13 +148,9 @@ static bool handle_irq(void) return 1; } - /* unlikely */ - if (eps[1].state != EP_IDLE) { - queued_rx = 1; - return 1; - } - - receive_frame(); + /* likely */ + if (eps[1].state == EP_IDLE || rx_in != rx_out) + receive_frame(); return 1; } @@ -193,9 +206,7 @@ static void do_tx(void *user) */ reg_write(REG_TRX_STATE, TRX_CMD_FORCE_PLL_ON); - flush_queued_rx(); handle_irq(); - queued_rx = 0; spi_begin(); spi_send(AT86RF230_BUF_WRITE); @@ -233,7 +244,7 @@ void mac_reset(void) mac_irq = NULL; txing = 0; queued_tx_ack = 0; - queued_rx = 0; + rx_in = rx_out = 0; next_seq = this_seq = queued_seq = 0; /* enable CRC and PHY_RSSI (with RX_CRC_VALID) in SPI status return */ From 998ac7e5c66ae7e5893e43b958183a138be1db10 Mon Sep 17 00:00:00 2001 From: Werner Almesberger Date: Wed, 24 Jul 2013 16:21:38 -0300 Subject: [PATCH 2/7] atusb/fw/mac.c (next_buf): dedicated function for incrementing buffer indices --- atusb/fw/mac.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/atusb/fw/mac.c b/atusb/fw/mac.c index 255ac6e..d4fd366 100644 --- a/atusb/fw/mac.c +++ b/atusb/fw/mac.c @@ -29,7 +29,6 @@ bool (*mac_irq)(void) = NULL; static uint8_t rx_buf[RX_BUFS][MAX_PSDU+2]; /* PHDR+payload+LQ */ -static bool rx_in = 0, rx_out = 0; static uint8_t tx_buf[MAX_PSDU]; static uint8_t tx_size = 0; static bool txing = 0; @@ -37,6 +36,18 @@ static bool queued_tx_ack = 0; static uint8_t next_seq, this_seq, queued_seq; +/* ----- Receive buffer management ----------------------------------------- */ + + +static uint8_t rx_in = 0, rx_out = 0; + + +static inline void next_buf(uint8_t *index) +{ + *index = (*index+1) % RX_BUFS; +} + + /* ----- Register access --------------------------------------------------- */ @@ -95,7 +106,7 @@ static void tx_ack_done(void *user) static void rx_done(void *user) { led(0); - rx_out = (rx_out+1) & (RX_BUFS-1); + next_buf(&rx_out); usb_next(); } @@ -122,7 +133,7 @@ static void receive_frame(void) spi_end(); buf[0] = size; - rx_in = (rx_in+1) & (RX_BUFS-1); + next_buf(&rx_in); if (eps[1].state == EP_IDLE) usb_next(); From 0706773e38d6cb1b85676a25738f90740a27af42 Mon Sep 17 00:00:00 2001 From: Werner Almesberger Date: Wed, 24 Jul 2013 17:18:33 -0300 Subject: [PATCH 3/7] atusb/fw/Makefile: improve size reporting (show segment sizes) --- atusb/fw/Makefile | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/atusb/fw/Makefile b/atusb/fw/Makefile index fb6937b..76b5b7f 100644 --- a/atusb/fw/Makefile +++ b/atusb/fw/Makefile @@ -1,8 +1,8 @@ # # Makefile - Makefile of the ATUSB firmware # -# Written 2010-2011 by Werner Almesberger -# Copyright 2010-2011 by Werner Almesberger +# Written 2010-2011, 2013 by Werner Almesberger +# Copyright 2010-2011, 2013 by Werner Almesberger # # 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 @@ -69,10 +69,12 @@ all: $(NAME).bin boot.hex $(NAME).elf: $(OBJS) $(MAKE) version.o $(CC) $(CFLAGS) -o $@ $(OBJS) version.o + $(SIZE) $@ boot.elf: $(BOOT_OBJS) $(CC) $(CFLAGS) -o $@ $(BOOT_OBJS) \ -Wl,--section-start=.text=$(BOOT_ADDR) + $(SIZE) $@ %.bin: %.elf $(BUILD) $(OBJCOPY) -j .text -j .data -O binary $< $@ @@ -80,7 +82,7 @@ boot.elf: $(BOOT_OBJS) %.hex: %.elf $(BUILD) $(OBJCOPY) -j .text -j .data -O ihex $< $@ - $(SIZE) $@ + @echo "Size: `$(SIZE) -A boot.hex | sed '/Total */s///p;d'` B" # ----- Cleanup --------------------------------------------------------------- From d1b65cb058b3e32681811f76311ae09d6f12e1e7 Mon Sep 17 00:00:00 2001 From: Werner Almesberger Date: Tue, 30 Jul 2013 13:48:55 -0300 Subject: [PATCH 4/7] tools/atrf-txrx/atrf-txrx.c: new option -q for quiet capture --- tools/atrf-txrx/atrf-txrx.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/tools/atrf-txrx/atrf-txrx.c b/tools/atrf-txrx/atrf-txrx.c index d8eff86..9477ab1 100644 --- a/tools/atrf-txrx/atrf-txrx.c +++ b/tools/atrf-txrx/atrf-txrx.c @@ -11,6 +11,7 @@ */ +#include #include #include #include @@ -74,6 +75,7 @@ enum mode { static volatile int run = 1; +static bool quiet = 0; /* ----- Helper functions -------------------------------------------------- */ @@ -237,7 +239,8 @@ static void receive_pcap(struct atrf_dsc *dsc, const char *name) write_pcap_hdr(file); while (run) { wait_for_interrupt(dsc, - IRQ_TRX_END, IRQ_TRX_END | IRQ_RX_START | IRQ_AMI, 0); + IRQ_TRX_END, + quiet ? 0xff : IRQ_TRX_END | IRQ_RX_START | IRQ_AMI, 0); if (!run) break; gettimeofday(&now, NULL); @@ -249,7 +252,8 @@ static void receive_pcap(struct atrf_dsc *dsc, const char *name) continue; } write_pcap_rec(file, &now, buf, n-1); - (void) write(2, ".", 1); + if (!quiet) + (void) write(2, ".", 1); count++; } if (fclose(file) == EOF) { @@ -666,7 +670,7 @@ static void usage(const char *name) " command shell command to run while transmitting (default: wait for\n" " SIGINT instead)\n\n" " common options: [-c channel|-f freq] [-C mhz] [-d driver[:arg]] [-o file]\n" -" [-p power] [-r rate] [-t trim]\n" +" [-p power] [-q] [-r rate] [-t trim]\n" " -c channel channel number, 11 to 26 (default %d)\n" " -C mhz output clock at 1, 2, 4, 8, or 16 MHz (default: off)\n" " -d driver[:arg]\n" @@ -674,6 +678,8 @@ static void usage(const char *name) " -f freq frequency in MHz, 2405 to 2480 (default %d)\n" " -o file write received data to a file in pcap format\n" " -p power transmit power, -17.2 to 3.0 dBm (default %.1f)\n" +" -q quiet - suppress progress reports and warnings\n" +" (currently only used when capturing)\n" " -r rate data rate, 250k, 500k, 1M, or 2M (default: 250k)\n" " -t trim trim capacitor, 0 to 15 (default %d)\n" , name, name, name, name, name, name, @@ -718,7 +724,7 @@ int main(int argc, char *const *argv) const char *pcap_file = NULL; struct atrf_dsc *dsc; - while ((c = getopt(argc, argv, "c:C:d:E:f:Ho:p:Pr:Rt:T:x")) != EOF) + while ((c = getopt(argc, argv, "c:C:d:E:f:Ho:p:Pqr:Rt:T:x")) != EOF) switch (c) { case 'c': channel = strtoul(optarg, &end, 0); @@ -767,6 +773,9 @@ int main(int argc, char *const *argv) case 'P': set_mode(&mode, mode_ping); break; + case 'q': + quiet = 1; + break; case 'r': if (!strcmp(optarg, "250k")) rate = OQPSK_DATA_RATE_250; From 7fd9044d94da8d8baede5a290efc7fb759b6e857 Mon Sep 17 00:00:00 2001 From: Werner Almesberger Date: Tue, 30 Jul 2013 19:46:55 -0300 Subject: [PATCH 5/7] atusb/fw/: add SPI block reception This decreases the retrieval time for a frame of 102 bytes from 660 us to 384 us, corresponding to a speed change from about 1.26 Mbps to 2.17 Mbps (102 bytes plus 2 bytes overhead). --- atusb/fw/mac.c | 5 ++--- atusb/fw/spi.c | 15 +++++++++++++++ atusb/fw/spi.h | 6 ++++-- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/atusb/fw/mac.c b/atusb/fw/mac.c index d4fd366..d87a063 100644 --- a/atusb/fw/mac.c +++ b/atusb/fw/mac.c @@ -113,7 +113,7 @@ static void rx_done(void *user) static void receive_frame(void) { - uint8_t size, i; + uint8_t size; uint8_t *buf; spi_begin(); @@ -128,8 +128,7 @@ static void receive_frame(void) } buf = rx_buf[rx_in]; - for (i = 0; i != size+1; i++) - buf[i+1] = spi_recv(); + spi_recv_block(buf+1, size+1); spi_end(); buf[0] = size; diff --git a/atusb/fw/spi.c b/atusb/fw/spi.c index 91a2de9..ded5673 100644 --- a/atusb/fw/spi.c +++ b/atusb/fw/spi.c @@ -47,6 +47,21 @@ void spi_end(void) } +void spi_recv_block(uint8_t *buf, uint8_t n) +{ + if (!n) + return; + UDR1 = 0; + while (--n) { + while (!(UCSR1A & 1 << RXC1)); + *buf++ = UDR1; + UDR1 = 0; + } + while (!(UCSR1A & 1 << RXC1)); + *buf++ = UDR1; +} + + void spi_off(void) { spi_initialized = 0; diff --git a/atusb/fw/spi.h b/atusb/fw/spi.h index ff9d005..6e04f4e 100644 --- a/atusb/fw/spi.h +++ b/atusb/fw/spi.h @@ -1,8 +1,8 @@ /* * fw/spi.h - ATmega8 family SPI I/O * - * Written 2011 by Werner Almesberger - * Copyright 2011 Werner Almesberger + * Written 2011, 2013 by Werner Almesberger + * Copyright 2011, 2013 Werner Almesberger * * 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 @@ -25,4 +25,6 @@ void spi_init(void); #define spi_send(v) (void) spi_io(v) #define spi_recv(v) spi_io(0) +void spi_recv_block(uint8_t *buf, uint8_t n); + #endif /* !SPI_H */ From 07b1da29ec94c00d52cd7c16a667c537e48a65e8 Mon Sep 17 00:00:00 2001 From: Werner Almesberger Date: Tue, 30 Jul 2013 19:59:11 -0300 Subject: [PATCH 6/7] tools/lib/: aggressive polling for wait_for_interrupt, if timeout_ms = -1 --- tools/include/misctxrx.h | 8 ++++++++ tools/lib/atben.c | 11 ++++++----- tools/lib/atusb-common.c | 2 +- tools/lib/misctxrx.c | 7 ++++--- 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/tools/include/misctxrx.h b/tools/include/misctxrx.h index 9d258bb..7e531ad 100644 --- a/tools/include/misctxrx.h +++ b/tools/include/misctxrx.h @@ -19,6 +19,14 @@ void flush_interrupts(struct atrf_dsc *dsc); + +/* + * timeout_ms: + * > 0: time out after that many milliseconds + * == 0: wait forever + * < 0: wait forever and eliminate poll delays (for high-speed capture) + */ + uint8_t wait_for_interrupt(struct atrf_dsc *dsc, uint8_t wait_for, uint8_t ignore, int timeout_ms); diff --git a/tools/lib/atben.c b/tools/lib/atben.c index 4230633..22abecc 100644 --- a/tools/lib/atben.c +++ b/tools/lib/atben.c @@ -1,8 +1,8 @@ /* * lib/atben.c - ATRF access functions library (Ben 8:10 card version) * - * Written 2010-2011 by Werner Almesberger - * Copyright 2010-2011 Werner Almesberger + * Written 2010-2011, 2013 by Werner Almesberger + * Copyright 2010-2011, 2013 Werner Almesberger * * 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 @@ -439,10 +439,10 @@ int atben_interrupt_wait(void *handle, int timeout_ms) int timedout = 0; uint8_t irq; - if (timeout_ms) + if (timeout_ms > 0) timeout_start(&to, timeout_ms); while (1) { - if (timeout_ms) + if (timeout_ms > 0) timedout = timeout_reached(&to); if (atben_interrupt(handle)) { irq = atben_reg_read(handle, REG_IRQ_STATUS); @@ -452,7 +452,8 @@ int atben_interrupt_wait(void *handle, int timeout_ms) } if (timedout) return 0; - usleep(1000); + if (timeout_ms >= 0) + usleep(1000); } return 0; diff --git a/tools/lib/atusb-common.c b/tools/lib/atusb-common.c index d43a168..2d9b15a 100644 --- a/tools/lib/atusb-common.c +++ b/tools/lib/atusb-common.c @@ -221,7 +221,7 @@ int atusb_interrupt_wait(void *handle, int timeout_ms) return 0; res = usb_bulk_read(dsc->dev, 1, - (char *) &buf, sizeof(buf), timeout_ms); + (char *) &buf, sizeof(buf), timeout_ms < 0 : 0 : timeout_ms); if (res == -ETIMEDOUT) return 0; if (res < 0) { diff --git a/tools/lib/misctxrx.c b/tools/lib/misctxrx.c index 2b46e9a..820ad00 100644 --- a/tools/lib/misctxrx.c +++ b/tools/lib/misctxrx.c @@ -62,14 +62,14 @@ uint8_t wait_for_interrupt(struct atrf_dsc *dsc, uint8_t wait_for, sigint = 0; old_sig = signal(SIGINT, die); - if (timeout_ms) { + if (timeout_ms > 0) { if (timeout_ms < MIN_TIMEOUT_MS) timeout_ms = MIN_TIMEOUT_MS; timeout_start(&to, timeout_ms); } while (!sigint && !timedout) { while (!sigint && !timedout) { - if (timeout_ms) { + if (timeout_ms > 0) { ms = timeout_left_ms(&to); if (ms <= 0) { timedout = 1; @@ -78,7 +78,8 @@ uint8_t wait_for_interrupt(struct atrf_dsc *dsc, uint8_t wait_for, } else { ms = 0; } - irq = atrf_interrupt_wait(dsc, ms); + irq = atrf_interrupt_wait(dsc, + timeout_ms < 0 ? -1 : ms); if (irq) break; } From 873f80cb4dac00800826958f9869ec55dbd9e91c Mon Sep 17 00:00:00 2001 From: Werner Almesberger Date: Tue, 30 Jul 2013 20:00:45 -0300 Subject: [PATCH 7/7] tools/atrf-txrx/atrf-txrx.c: option -q becomes "quick" and uses aggressive polling This allows us to capture frames at full speed speed. --- tools/atrf-txrx/atrf-txrx.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tools/atrf-txrx/atrf-txrx.c b/tools/atrf-txrx/atrf-txrx.c index 9477ab1..728681c 100644 --- a/tools/atrf-txrx/atrf-txrx.c +++ b/tools/atrf-txrx/atrf-txrx.c @@ -75,7 +75,7 @@ enum mode { static volatile int run = 1; -static bool quiet = 0; +static bool quick = 0; /* ----- Helper functions -------------------------------------------------- */ @@ -240,7 +240,8 @@ static void receive_pcap(struct atrf_dsc *dsc, const char *name) while (run) { wait_for_interrupt(dsc, IRQ_TRX_END, - quiet ? 0xff : IRQ_TRX_END | IRQ_RX_START | IRQ_AMI, 0); + quick ? 0xff : IRQ_TRX_END | IRQ_RX_START | IRQ_AMI, + quick ? -1 : 0); if (!run) break; gettimeofday(&now, NULL); @@ -252,7 +253,7 @@ static void receive_pcap(struct atrf_dsc *dsc, const char *name) continue; } write_pcap_rec(file, &now, buf, n-1); - if (!quiet) + if (!quick) (void) write(2, ".", 1); count++; } @@ -678,8 +679,8 @@ static void usage(const char *name) " -f freq frequency in MHz, 2405 to 2480 (default %d)\n" " -o file write received data to a file in pcap format\n" " -p power transmit power, -17.2 to 3.0 dBm (default %.1f)\n" -" -q quiet - suppress progress reports and warnings\n" -" (currently only used when capturing)\n" +" -q quick and quiet - suppress progress reports and warnings,\n" +" poll aggressively (currently only used when capturing)\n" " -r rate data rate, 250k, 500k, 1M, or 2M (default: 250k)\n" " -t trim trim capacitor, 0 to 15 (default %d)\n" , name, name, name, name, name, name, @@ -774,7 +775,7 @@ int main(int argc, char *const *argv) set_mode(&mode, mode_ping); break; case 'q': - quiet = 1; + quick = 1; break; case 'r': if (!strcmp(optarg, "250k"))