Add firmware for the ATUSB IEEE 802.15.4 USB Adapter
authorJason Self <j@jxself.org>
Thu, 4 Jul 2019 22:55:48 +0000 (15:55 -0700)
committerJason Self <j@jxself.org>
Thu, 4 Jul 2019 22:55:48 +0000 (15:55 -0700)
http://shop.sysmocom.de/products/atusb/

42 files changed:
INSTALL
Makefile
WHENCE
atusb/.README.kate-swp [new file with mode: 0644]
atusb/Makefile [new file with mode: 0644]
atusb/README [new file with mode: 0644]
atusb/an/README [new file with mode: 0644]
atusb/an/dec.py [new file with mode: 0755]
atusb/an/get.py [new file with mode: 0755]
atusb/an/plot [new file with mode: 0755]
atusb/atusb.c [new file with mode: 0644]
atusb/board.c [new file with mode: 0644]
atusb/board.h [new file with mode: 0644]
atusb/board_app.c [new file with mode: 0644]
atusb/board_atusb.c [new file with mode: 0644]
atusb/board_atusb.h [new file with mode: 0644]
atusb/board_hulusb.c [new file with mode: 0644]
atusb/board_hulusb.h [new file with mode: 0644]
atusb/board_rzusb.c [new file with mode: 0644]
atusb/board_rzusb.h [new file with mode: 0644]
atusb/boot.c [new file with mode: 0644]
atusb/descr.c [new file with mode: 0644]
atusb/ep0.c [new file with mode: 0644]
atusb/flash.c [new file with mode: 0644]
atusb/include/at86rf230.h [new file with mode: 0644]
atusb/include/atusb/atusb.h [new file with mode: 0644]
atusb/include/atusb/ep0.h [new file with mode: 0644]
atusb/mac.c [new file with mode: 0644]
atusb/mac.h [new file with mode: 0644]
atusb/sernum.c [new file with mode: 0644]
atusb/sernum.h [new file with mode: 0644]
atusb/spi.c [new file with mode: 0644]
atusb/spi.h [new file with mode: 0644]
atusb/uart.c [new file with mode: 0644]
atusb/uart.h [new file with mode: 0644]
atusb/usb/atu2.c [new file with mode: 0644]
atusb/usb/dfu.c [new file with mode: 0644]
atusb/usb/dfu.h [new file with mode: 0644]
atusb/usb/dfu_common.c [new file with mode: 0644]
atusb/usb/usb.c [new file with mode: 0644]
atusb/usb/usb.h [new file with mode: 0644]
atusb/version.h [new file with mode: 0644]

diff --git a/INSTALL b/INSTALL
index 74c5cfdeb7a9ab0d556761b4d8b91d13a8c78764..7fb111653d0885c3086970712c53adb08527bbfd 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -16,6 +16,8 @@ In order to build everything you will need the following on the host
 system:
 
     * A C/C++ compiler, like GCC
+    * AVR-GCC
+    * Standard C library for AVR-GCC
     * Cmake
     * GNU Bison/YACC
     * GNU Flex
@@ -32,13 +34,27 @@ system:
 
 On GNU/Linux distros that use apt you can install these with:
 
-    apt install binutils-arm-linux-gnueabi binutils-arm-none-eabi bison \
-    cmake flex g++ gcc gcc-arm-linux-gnueabi gcc-arm-none-eabi gperf make wget
+    apt install avr-gcc avr-libc binutils-arm-linux-gnueabi \
+    binutils-arm-none-eabi bison cmake flex g++ gcc \
+    gcc-arm-linux-gnueabi gcc-arm-none-eabi gperf make wget
 
 CARL9170 Firmware Configuration
+-------------------------------
 When building the carl9170 firmware you will be prompted with
 configuration questions.
 
+atusb: Firmware for the ATUSB IEEE 802.15.4 USB Adapter
+-------------------------------------------------------
+
+To flash the firmware you need dfu-util on the host. Issue
+
+    make dfu
+
+right after plugging the device into the USB port while the red led is
+still on.
+
+Refer to the included README file for more information.
+
 Licensing
 ---------
 
index 21d16fb5b8581c376cef4a0ddb62c872bf811974..8474b304f164eb89bcb5dbfb047bd9de71781c6a 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@ shell=/bin/sh
 prefix=/lib/firmware
 install_program=install
 
-.PHONY:        all test clean install a56 as31 aica ath9k_htc_toolchain ath9k_htc av7110 b43-tools carl9170fw-toolchain carl9170fw cis-tools cis dsp56k ihex2fw isci keyspan_pda openfwwf usbdux
+.PHONY:        all test clean install a56 as31 aica ath9k_htc_toolchain ath9k_htc atusb av7110 b43-tools carl9170fw-toolchain carl9170fw cis-tools cis dsp56k ihex2fw isci keyspan_pda openfwwf usbdux
 
 all: aica ath9k_htc av7110 carl9170fw cis dsp56k isci keyspan_pda openfwwf usbdux
 
@@ -36,6 +36,9 @@ ath9k_htc_toolchain:
 ath9k_htc: ath9k_htc_toolchain
        cd ath9k_htc && $(MAKE) -C target_firmware
 
+atusb:
+       cd atusb && $(MAKE)
+
 av7110:
        cd av7110 && $(MAKE)
 
@@ -81,6 +84,7 @@ clean:
        if [ -a as31/Makefile ]; then cd as31 && $(MAKE) clean; fi;
        cd ath9k_htc && $(MAKE) toolchain-clean
        cd ath9k_htc && $(MAKE) -C target_firmware clean
+       cd atusb && $(MAKE) clean
        cd av7110 && $(MAKE) clean
        cd carl9170fw/toolchain && $(MAKE) clean
        if [ -a carl9170fw/Makefile ]; then cd carl9170fw && $(MAKE) clean; fi;
diff --git a/WHENCE b/WHENCE
index 2932155fcb5036621ca6ba8b83f7ff98747490a3..756de43b4b48d0fc3fe983e377ba2338f5ebcf6a 100644 (file)
--- a/WHENCE
+++ b/WHENCE
@@ -112,6 +112,18 @@ From https://github.com/qca/open-ath9k-htc-firmware
 
 --------------------------------------------------------------------------
 
+atusb: Firmware for the ATUSB IEEE 802.15.4 USB Adapter
+http://shop.sysmocom.de/products/atusb/
+
+From http://projects.qi-hardware.com/index.php/p/ben-wpan/source/tree/master/atusb/fw
+
+License: GPL-2.0-or-later
+
+Version: Based on commit 805db6ebf5d80692158acadf88e239da9d3e67af 
+dated September 13 2017
+
+--------------------------------------------------------------------------
+
 Driver: b43 - OpenFWWF -- Free firmware for some Broadcom 43xx series WLAN chips
 
 License: GPLv2
diff --git a/atusb/.README.kate-swp b/atusb/.README.kate-swp
new file mode 100644 (file)
index 0000000..9029df3
Binary files /dev/null and b/atusb/.README.kate-swp differ
diff --git a/atusb/Makefile b/atusb/Makefile
new file mode 100644 (file)
index 0000000..c79cb26
--- /dev/null
@@ -0,0 +1,236 @@
+#
+# Makefile - Makefile of the ATUSB firmware
+#
+# 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
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+
+SHELL = /bin/bash
+
+NAME = atusb
+DEBUG = false
+
+CFLAGS = -g -mmcu=$(CHIP) -DBOOT_ADDR=$(BOOT_ADDR) \
+        -Wall -Wextra -Wshadow -Werror -Wno-unused-parameter \
+        -Wmissing-prototypes -Wmissing-declarations -Wstrict-prototypes
+
+ifeq ($(DEBUG),true)
+CFLAGS += -DDEBUG
+endif
+
+ifeq ($(NAME),rzusb)
+CHIP=at90usb1287
+CFLAGS += -DRZUSB -DAT86RF230
+else ifeq ($(NAME),hulusb)
+CHIP=at90usb1287
+CFLAGS += -DHULUSB -DAT86RF212
+else
+CHIP=atmega32u2
+CFLAGS += -DATUSB -DAT86RF231
+endif
+HOST=jlime
+BOOT_ADDR=0x7000
+
+AVR_PREFIX = $(BIN_PATH) avr-
+CC = $(AVR_PREFIX)gcc
+OBJCOPY = $(AVR_PREFIX)objcopy
+#OBJDUMP = $(AVR_PREFIX)objdump
+SIZE = $(AVR_PREFIX)size
+
+# BCD notion is 0xJJMM with JJ being major and MM being minor. Thus 0x0020 is
+# version 0.2 */
+USB_BCD_VERSION = 0030
+USB_VENDOR_ID = 20b7
+USB_PRODUCT_ID = 1540
+USB_ID = $(USB_VENDOR_ID):$(USB_PRODUCT_ID)
+
+OBJS = atusb.o board.o board_app.o sernum.o spi.o descr.o ep0.o \
+       dfu_common.o usb.o app-atu2.o mac.o
+BOOT_OBJS = boot.o board.o sernum.o spi.o flash.o dfu.o \
+            dfu_common.o usb.o boot-atu2.o
+
+ifeq ($(DEBUG),true)
+OBJS +=  uart.o
+endif
+
+ifeq ($(NAME),rzusb)
+OBJS += board_rzusb.o
+BOOT_OBJS += board_rzusb.o
+else ifeq ($(NAME),hulusb)
+OBJS += board_hulusb.o
+BOOT_OBJS += board_hulusb.o
+else
+OBJS += board_atusb.o
+BOOT_OBJS += board_atusb.o
+endif
+
+
+vpath %.c usb/
+
+CFLAGS += -Iinclude -Iusb -I.
+
+# ----- Verbosity control -----------------------------------------------------
+
+CC_normal      := $(CC)
+BUILD_normal   :=
+DEPEND_normal  := $(CPP) $(CFLAGS) -MM -MG
+
+CC_quiet       = @echo "  CC       " $@ && $(CC_normal)
+BUILD_quiet    = @echo "  BUILD    " $@ && $(BUILD_normal)
+DEPEND_quiet   = @$(DEPEND_normal)
+
+ifeq ($(V),1)
+    CC         = $(CC_normal)
+    BUILD      = $(BUILD_normal)
+    DEPEND     = $(DEPEND_normal)
+else
+    CC         = $(CC_quiet)
+    BUILD      = $(BUILD_quiet)
+    DEPEND     = $(DEPEND_quiet)
+endif
+
+# ----- Rules -----------------------------------------------------------------
+
+.PHONY:                all clean upload prog dfu update version.c bindist
+.PHONY:                prog-app prog-read on off reset
+
+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 $< $@
+               @echo "build #`cat .version`, `ls -l $@`"
+
+%.dfu:         %.bin
+               cp $(NAME).bin $(NAME).dfu
+               dfu-suffix -a $(NAME).dfu -d 0x$(USB_BCD_VERSION) \
+                 -p 0x$(USB_PRODUCT_ID) -v 0x$(USB_VENDOR_ID)
+
+%.hex:         %.elf
+               $(BUILD) $(OBJCOPY) -j .text -j .data -O ihex $< $@
+               @echo "Size: `$(SIZE) -A boot.hex | sed '/Total */s///p;d'` B"
+
+# ----- Cleanup ---------------------------------------------------------------
+
+clean:
+               rm -f $(NAME).bin $(NAME).elf $(NAME).dfu
+               rm -f $(OBJS) $(OBJS:.o=.d)
+               rm -f boot.hex boot.elf
+               rm -f $(BOOT_OBJS) $(BOOT_OBJS:.o=.d)
+               rm -f version.c version.d version.o
+
+# ----- Build version ---------------------------------------------------------
+
+version.c:
+               @if [ -f .version ]; then \
+                   v=`cat .version`; \
+                   expr $$v + 1 >.version; \
+               else \
+                   echo 0 >.version; \
+               fi
+               @[ -s .version ] || echo 0 >.version
+               @echo '/* MACHINE-GENERATED. DO NOT EDIT ! */' >version.c
+               @echo '#include "version.h"' >>version.c
+               @echo "const char *build_date = \"`date`\";" >>version.c
+               @echo "const uint16_t build_number = `cat .version`;" \
+                 >>version.c
+
+# ----- Dependencies ----------------------------------------------------------
+
+MKDEP =                                                                        \
+       $(DEPEND) $< |                                                  \
+         sed                                                           \
+           -e 's|^$(basename $(notdir $<)).o:|$@:|'                    \
+           -e '/^\(.*:\)\? */{p;s///;s/ *\\\?$$/ /;s/  */:\n/g;H;}'    \
+           -e '$${g;p;}'                                               \
+           -e d >$(basename $@).d;                                     \
+         [ "$${PIPESTATUS[*]}" = "0 0" ] ||                            \
+         { rm -f $(basename $@).d; exit 1; }
+
+%.o:            %.c
+               $(CC) $(CFLAGS) -Os -c $<
+               $(MKDEP)
+
+-include $(OBJS:.o=.d)
+
+# ----- Object file variants --------------------------------------------------
+
+app-%.o:       usb/%.c
+               $(CC) $(CFLAGS) -Os -o $@ -c $<
+               $(MKDEP)
+
+boot-%.o:      usb/%.c
+               $(CC) $(CFLAGS) -DBOOT_LOADER -Os -o $@ -c $<
+               $(MKDEP)
+
+# ----- Distribution ----------------------------------------------------------
+
+BINDIST_BASE=http://downloads.qi-hardware.com/people/werner/wpan/bindist
+ATUSB_BIN_NAME=atusb-`git rev-parse HEAD | cut -c 1-7`.bin
+
+bindist:
+               qippl atusb.bin wpan/bindist/$(ATUSB_BIN_NAME)
+               @echo $(BINDIST_BASE)/$(ATUSB_BIN_NAME)
+               @echo md5sum: `md5sum atusb.bin | sed 's/ .*//'`
+               @echo atrf-id: \
+                 `sed '/.*number = \(.*\);/s//#\1/p;d' version.c` \
+                 `sed '/.*date = "\(.*\)";/s//\1/p;d' version.c`
+
+# ----- Programming and device control ----------------------------------------
+
+upload:                $(NAME).bin boot.hex
+               scp $(NAME).bin boot.hex $(HOST):
+
+# lfuse: external clock, slow start-up
+# hfuse: 4 kB boot loader, reset into boot loader
+# lock: allow everything but SPM to the boot loader
+#       Note: when trying to program 0xef, we get back 0x2f, failing
+#            verification. So we just program 0x2f.
+
+prog-app:
+               ssh $(HOST) avrdude -F -p $(CHIP) -c nanonote_atusb -e \
+                 -U flash:w:atusb.bin:r \
+                 -U lfuse:w:0x60:m
+
+prog:
+               ssh $(HOST) avrdude -F -p $(CHIP) -c nanonote_atusb -e \
+                 -U flash:w:boot.hex:i \
+                 -U lfuse:w:0x60:m \
+                 -U hfuse:w:0xd8:m \
+                 -U lock:w:0x2f:m
+
+prog-read:
+               ssh $(HOST) avrdude -F -p $(CHIP) -c nanonote_atusb \
+                 -U flash:r:mcu.bin:r
+
+dfu:           $(NAME).dfu
+               dfu-util -d $(USB_ID) -D $(NAME).dfu
+
+update:                $(NAME).bin
+               -atrf-reset -a
+               usbwait -r -i 0.01 -t 5 $(USB_ID)
+               $(MAKE) dfu
+
+on:
+               ssh $(HOST) poke 0x10010318 4
+
+off:
+               ssh $(HOST) poke 0x10010314 4
+
+reset:
+               ssh $(HOST) poke 0x10010318 2048
+               ssh $(HOST) poke 0x10010314 2048
diff --git a/atusb/README b/atusb/README
new file mode 100644 (file)
index 0000000..99ceb22
--- /dev/null
@@ -0,0 +1,94 @@
+Requires a very recent toolchain, because ATmega32U2 is relatively new.
+
+- Building:
+
+  make
+
+- Uploading the firmware to a Ben (for flashing with the atusb-pgm cable):
+
+  make HOST=<hostname> upload
+
+  Example:
+
+  make HOST=ben upload
+
+  HOST defaults to "jlime".
+
+- Flashing the boot loader:
+
+  Prerequisite: avrdude on the Ben.
+
+  Disconnect the atusb board from USB. Insert the atusb-pgm connector into
+  the Ben. Place the atusb-pgm adapter on the exposed contact pads of the
+  atusb board and push it down. Then run
+
+  make prog
+
+  This takes about 30 seconds. If the programming fails with an error
+  message like "Yikes!  Invalid device signature.", verify that the
+  atusb-pgm board is properly connected and placed, then try again.
+
+- Uploading the application:
+
+  Prerequisite: dfu-util installed on the PC.
+
+  Insert atusb into the PC, then run
+
+  make dfu
+
+  Note: since the boot loader resets the USB bus after timing out,
+  this operation can fail with a message like "No DFU capable USB device
+  found". Just retry, and it will eventually get through.
+
+
+HULUSB notes:
+-------------
+To prepare and flash the firmware on a HULUSB device some additional steps are
+needed;
+
+avr-objcopy -O ihex -R .signature -R .fuse -R .eeprom hulusb.elf hulusb.hex
+dfu-programmer at90usb1287 flash hulusb.hex
+dfu-programmer at90usb1287 reset
+
+--------------------------
+
+Making the toolchain:
+
+# patches according to
+# http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=789527
+
+# some gcc prerequisites
+
+apt-get remove avr-libc gcc-avr binutils-avr
+apt-get install libmpfr-dev libmpc-dev
+
+# binutils
+
+wget http://ftp.gnu.org/gnu/binutils/binutils-2.21.tar.bz2
+tar xfj binutils-2.21.tar.bz2 
+cd binutils-2.21
+./configure --target=avr --disable-nls
+make
+make install
+
+# gcc
+
+wget http://ftpmirror.gnu.org/gcc/gcc-4.5.2/gcc-4.5.2.tar.bz2
+wget -O gcc_452_avr.patch http://gcc.gnu.org/bugzilla/attachment.cgi?id=23050
+tar xfj gcc-4.5.2.tar.bz2
+cd gcc-4.5.2
+patch -p1 -s <../gcc_452_avr.patch
+mkdir obj-avr
+cd obj-avr
+../configure --target=avr --enable-languages=c \
+    --disable-nls --disable-libssp --with-dwarf2
+make
+make install
+
+wget http://download.savannah.gnu.org/releases/avr-libc/avr-libc-1.7.1.tar.bz2
+tar xfj avr-libc-1.7.1.tar.bz2 
+cd avr-libc-1.7.1
+./bootstrap    # the automake at the end takes a while
+./configure --build=`./config.guess` --host=avr
+make
+make install
diff --git a/atusb/an/README b/atusb/an/README
new file mode 100644 (file)
index 0000000..8e0d2fc
--- /dev/null
@@ -0,0 +1,25 @@
+workflow:
+
+- connect zprobe (note: it currently inverts because it didn't have any
+  other chips around. this may change later.)
+
+- capture the USB signals at an interesting moment with a sample rate of
+  50 MSa/s
+
+- zoom into the frame(s) of interest
+
+- download the data with
+  ./get.py
+
+- decode with
+  ./dec.py
+
+  For manual decoding, set the coders to D+ and D- (we need D- for SE0
+  and SE1 detection), then click on a rising clock edge left of the
+  packet and move the cursor to the right.
+
+- if there are problems with the clock, the analog signal and digital
+  signals derived from it can be examined after running dec.py with
+  ./plot
+
+  (Note that the digital zprobe hides any analog anomalies.)
diff --git a/atusb/an/dec.py b/atusb/an/dec.py
new file mode 100755 (executable)
index 0000000..8534857
--- /dev/null
@@ -0,0 +1,127 @@
+#!/usr/bin/python
+
+from tmc.wave import *
+from tmc.dxplore import dxplore
+from tmc.decode import d_usb_stream
+
+
+#
+# Clock recovery: we assume that each change in the wave is triggered by a
+# clock edge. We know the clock's nominal period and resynchronize on each
+# edge. Additionally, we can obtain a list of times when a timing violation
+# has occurred.
+#
+# Note that the timing violations logic doesn't make much sense in its present
+# form, since it mainly measures noise (particularly if we're digitizing slow
+# edges) and not clock drift.
+#
+# A more useful metric would be accumulated error from some point of reference
+# or at least the timing of same edges, to eliminate (generally harmless) time
+# offsets introduced by digitizing.
+#
+# So it would probably make more sense for "recover" not to check for timing
+# violations at all, and leave this to more specialized functions.
+#
+def recover(self, period, min = None, max = None, t0 = None):
+    if t0 is None:
+       t0 = self.data[0]
+    v = not self.initial
+    res = []
+    violations = []
+    for t in self.data:
+       v = not v
+       if t <= t0:
+           continue
+       n = 0
+       while t0 < t-period/2:
+           res.append(t0)
+           t0 += period
+           n += 1
+       if min is not None:
+           if t0-t > n*min:
+               violations.append(t)
+       if max is not None:
+           if t-t0 > n*max:
+               violations.append(t)
+       t0 = t
+    return res, violations
+
+
+#
+# Load the analog waves saved by get.py
+#
+wv = waves()
+wv.load("_wv")
+
+#
+# Digitize the waves and save the result.
+#
+dp = wv[0].digitize(1.5, 1.8)
+dm = wv[1].digitize(1.5, 1.8)
+wv = waves(dp, dm, dp-dm)
+wv.save("_dig")
+
+#
+# Also record the differential signal.
+#
+wd = wv[1]-wv[0]
+dd = wd.digitize(-0.5, 0.5)
+wd.save("_diff")
+
+#
+# Run clock recovery on D+/D-. We only need one, but check both to be sure.
+#
+#p = 1/1.5e6
+p = 1/12e6
+dp_t, viol = recover(dp, p, p*0.9, p*1.1)
+print viol
+dm_t, viol = recover(dm, p, p*.9, p*1.1, t0 = dp.data[0])
+print viol
+
+#
+# Shift the clock by half a period, add a few periods to get steady state and
+# SE0s (if any), and then sample the data lines.
+#
+clk = map(lambda t: t+p/2, dp_t)
+clk.extend((clk[-1]+p, clk[-1]+2*p, clk[-1]+3*p))
+dp_bv = dp.get(clk)
+dm_bv = dm.get(clk)
+
+#
+# Save a wave with the recovered clock to make it easier to find the bits in
+# analog graphs.
+#
+dd.data = dp_t;
+dd.save("_clk")
+
+#
+# For decoding, we need a fake bit clock. We generate it by doubling each data
+# bit and generating a L->H transition during this bit.
+#
+dpd = []
+dmd = []
+dck = []
+
+# err, silly, seems that we've mixed up D+ and D- all over the place :-)
+print d_usb_stream(dm_bv[:], dp_bv[:])
+
+for v in dp_bv:
+    dpd.append(v)
+    dpd.append(v)
+    dck.append(0)
+    dck.append(1)
+
+for v in dm_bv:
+    dmd.append(v)
+    dmd.append(v)
+
+#
+# Display the reconstructed digital signal. Note that the absolute time is only
+# correct at the beginning and that relative time is only accurate over
+# intervals in which no significant clock resynchronization has occurred.
+#
+# In fact, dxplore should probably have an option to either turn off time
+# entirely or to display a user-provided time axis. The latter may be a bit
+# tricky to implement.
+#
+dxplore((dmd, dpd, dck), 0, p/2, labels = ("D+", "D-", "CLK"))
diff --git a/atusb/an/get.py b/atusb/an/get.py
new file mode 100755 (executable)
index 0000000..685e00f
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/python
+
+from tmc.scope import rigol_ds1000c
+
+#-800, +1600
+s = rigol_ds1000c()
+#s.debug = False
+
+pos = s.hor.pos
+scale = s.hor.scale
+t0 = pos-scale*s.div_hor/2
+t1 = pos+scale*s.div_hor/2
+print t0, t1
+
+#zoom = 10
+#step = scale/s.samples_per_div/zoom
+#print step
+step = 4e-9
+step = 2e-9
+
+w = s.wave((s.ch[0], s.ch[1]), start = t0, end = t1, step = step)
+w[0] = 3.3-w[0]
+w[1] = 3.3-w[1]
+
+s.hor.pos = pos
+s.hor.scale = scale
+
+w[0].label = "D+";
+w[1].label = "D-";
+
+w.save("_wv")
diff --git a/atusb/an/plot b/atusb/an/plot
new file mode 100755 (executable)
index 0000000..1dea789
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/sh
+#
+# Plot output of "dec"
+#
+gnuplot -persist <<EOF
+set style data lines
+plot "_wv" using 1:(\$2-4), \
+  "_dig" using 1:(\$2*3.3-4) lw 2, \
+  "_wv" using 1:3, \
+  "_dig" using 1:(\$3*3.3) lw 2, \
+  "_clk" using 1:(\$2+1) lt 7
+EOF
diff --git a/atusb/atusb.c b/atusb/atusb.c
new file mode 100644 (file)
index 0000000..28faf40
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * fw/atusb.c - ATUSB initialization and main loop
+ *
+ * Written 2008-2011 by Werner Almesberger
+ * Copyright 2008-2011 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+
+#include <stdint.h>
+
+#include <avr/io.h>
+#include <avr/sleep.h>
+#include <avr/interrupt.h>
+
+#include "usb.h"
+
+#include "board.h"
+#include "sernum.h"
+#include "spi.h"
+#include "atusb/ep0.h"
+
+#ifdef DEBUG
+#include "uart.h"
+#endif
+
+
+int main(void)
+{
+       board_init();
+       board_app_init();
+       reset_rf();
+
+       user_get_descriptor = sernum_get_descr;
+
+       /* now we should be at 8 MHz */
+
+#ifdef DEBUG
+       uart_init();
+       static FILE atben_stdout = FDEV_SETUP_STREAM(uart_write_char, NULL,
+                                                    _FDEV_SETUP_WRITE);
+       stdout = &atben_stdout;
+#endif
+
+       usb_init();
+       ep0_init();
+#ifdef ATUSB
+       timer_init();
+
+       /* move interrupt vectors to 0 */
+       MCUCR = 1 << IVCE;
+       MCUCR = 0;
+#endif
+
+       sei();
+
+       while (1)
+               sleep_mode();
+}
diff --git a/atusb/board.c b/atusb/board.c
new file mode 100644 (file)
index 0000000..c3b8d26
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * fw/board.c - Board-specific functions (for boot loader and application)
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <avr/boot.h>
+
+#define F_CPU   8000000UL
+#include <util/delay.h>
+
+#include "usb.h"
+#include "at86rf230.h"
+#include "board.h"
+#include "spi.h"
+
+
+uint8_t board_sernum[42] = { 42, USB_DT_STRING };
+
+/* ----- Register access --------------------------------------------------- */
+
+void change_state(uint8_t new)
+{
+       while ((reg_read(REG_TRX_STATUS) & TRX_STATUS_MASK) ==
+               TRX_STATUS_TRANSITION);
+       reg_write(REG_TRX_STATE, new);
+}
+
+
+uint8_t reg_read(uint8_t reg)
+{
+       uint8_t value;
+
+       spi_begin();
+       spi_send(AT86RF230_REG_READ | reg);
+       value = spi_recv();
+       spi_end();
+
+       return value;
+}
+
+
+uint8_t subreg_read(uint8_t address, uint8_t mask, uint8_t position)
+{
+       /* Read current register value and mask out subregister. */
+       uint8_t register_value = reg_read(address);
+       register_value &= mask;
+       register_value >>= position; /* Align subregister value. */
+
+       return register_value;
+}
+
+
+void reg_write(uint8_t reg, uint8_t value)
+{
+       spi_begin();
+       spi_send(AT86RF230_REG_WRITE | reg);
+       spi_send(value);
+       spi_end();
+}
+
+
+void subreg_write(uint8_t address, uint8_t mask, uint8_t position, uint8_t value)
+{
+       /* Read current register value and mask area outside the subregister. */
+       uint8_t register_value = reg_read(address);
+       register_value &= ~mask;
+
+       /* Start preparing the new subregister value. shift in place and mask. */
+       value <<= position;
+       value &= mask;
+
+       value |= register_value; /* Set the new subregister value. */
+
+       /* Write the modified register value. */
+       reg_write(address, value);
+}
+
+
+void panic(void)
+{
+       cli();
+       while (1) {
+               SET(LED);
+               _delay_ms(100);
+               CLR(LED);
+               _delay_ms(100);
+       }
+}
+
+
+static char hex(uint8_t nibble)
+{
+       return nibble < 10 ? '0'+nibble : 'a'+nibble-10;
+}
+
+
+void get_sernum(void)
+{
+       uint8_t sig;
+       uint8_t i;
+
+       for (i = 0; i != 10; i++) {
+               sig = boot_signature_byte_get(i+0xe);
+               board_sernum[(i << 2)+2] = hex(sig >> 4);
+               board_sernum[(i << 2)+4] = hex(sig & 0xf);
+       }
+}
diff --git a/atusb/board.h b/atusb/board.h
new file mode 100644 (file)
index 0000000..dbcd410
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * fw/board.h - Board-specific functions and definitions
+ *
+ * Written 2008-2011, 2013, 2013 by Werner Almesberger
+ * Copyright 2008-2011, 2013, 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef BOARD_H
+#define        BOARD_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <atusb/atusb.h>
+
+#ifdef ATUSB
+#include "board_atusb.h"
+#endif
+#ifdef RZUSB
+#include "board_rzusb.h"
+#endif
+#ifdef HULUSB
+#include "board_hulusb.h"
+#endif
+
+#define        SET_2(p, b)     PORT##p |= 1 << (b)
+#define        CLR_2(p, b)     PORT##p &= ~(1 << (b))
+#define        IN_2(p, b)      DDR##p &= ~(1 << (b))
+#define        OUT_2(p, b)     DDR##p |= 1 << (b)
+#define        PIN_2(p, b)     ((PIN##p >> (b)) & 1)
+
+#define        SET_1(p, b)     SET_2(p, b)
+#define        CLR_1(p, b)     CLR_2(p, b)
+#define        IN_1(p, b)      IN_2(p, b)
+#define        OUT_1(p, b)     OUT_2(p, b)
+#define        PIN_1(p, b)     PIN_2(p, b)
+
+#define        SET(n)          SET_1(n##_PORT, n##_BIT)
+#define        CLR(n)          CLR_1(n##_PORT, n##_BIT)
+#define        IN(n)           IN_1(n##_PORT, n##_BIT)
+#define        OUT(n)          OUT_1(n##_PORT, n##_BIT)
+#define        PIN(n)          PIN_1(n##_PORT, n##_BIT)
+
+
+#define        USB_VENDOR      ATUSB_VENDOR_ID
+#define        USB_PRODUCT     ATUSB_PRODUCT_ID
+
+#define        DFU_USB_VENDOR  USB_VENDOR
+#define        DFU_USB_PRODUCT USB_PRODUCT
+
+
+#define        BOARD_MAX_mA    40
+
+#ifdef BOOT_LOADER
+#define        NUM_EPS 1
+#else
+#define        NUM_EPS 2
+#endif
+
+#define        HAS_BOARD_SERNUM
+
+extern uint8_t board_sernum[42];
+extern uint8_t irq_serial;
+
+
+void reset_rf(void);
+void reset_cpu(void);
+uint8_t read_irq(void);
+void slp_tr(void);
+
+void led(bool on);
+void panic(void);
+
+uint64_t timer_read(void);
+void timer_init(void);
+
+bool gpio(uint8_t port, uint8_t data, uint8_t dir, uint8_t mask, uint8_t *res);
+void gpio_cleanup(void);
+
+void get_sernum(void);
+
+void board_app_init(void);
+
+uint8_t reg_read(uint8_t reg);
+uint8_t subreg_read(uint8_t address, uint8_t mask, uint8_t position);
+void reg_write(uint8_t reg, uint8_t value);
+void subreg_write(uint8_t address, uint8_t mask, uint8_t position, uint8_t value);
+void change_state(uint8_t new);
+
+#endif /* !BOARD_H */
diff --git a/atusb/board_app.c b/atusb/board_app.c
new file mode 100644 (file)
index 0000000..1fa9bf4
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * fw/board_app.c - Board-specific functions (for the application)
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+
+#include <stddef.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <avr/io.h>
+#include <avr/interrupt.h>
+
+#define F_CPU   8000000UL
+#include <util/delay.h>
+
+#include "usb.h"
+#include "at86rf230.h"
+#include "spi.h"
+#include "mac.h"
+#include "board.h"
+
+
+static volatile uint32_t timer_h = 0;  /* 2^(16+32) / 8 MHz = ~1.1 years */
+
+
+void reset_cpu(void)
+{
+       WDTCSR = 1 << WDE;
+}
+
+
+uint8_t read_irq(void)
+{
+       return PIN(IRQ_RF);
+}
+
+
+void slp_tr(void)
+{
+       SET(SLP_TR);
+       CLR(SLP_TR);
+}
+
+
+ISR(TIMER1_OVF_vect)
+{
+       timer_h++;
+}
+
+
+uint64_t timer_read(void)
+{
+       uint32_t high;
+       uint8_t low, mid;
+
+       do {
+               if (TIFR1 & (1 << TOV1)) {
+                       TIFR1 = 1 << TOV1;
+                       timer_h++;
+               }
+               high = timer_h;
+               low = TCNT1L;
+               mid = TCNT1H;
+       }
+       while (TIFR1 & (1 << TOV1));
+
+       /*
+        * We need all these casts because the intermediate results are handled
+        * as if they were signed and thus get sign-expanded. Sounds wrong-ish.
+        */
+       return (uint64_t) high << 16 | (uint64_t) mid << 8 | (uint64_t) low;
+}
+
+
+void timer_init(void)
+{
+       /* configure timer 1 as a free-running CLK counter */
+
+       TCCR1A = 0;
+       TCCR1B = 1 << CS10;
+
+       /* enable timer overflow interrupt */
+
+       TIMSK1 = 1 << TOIE1;
+}
+
+
+bool gpio(uint8_t port, uint8_t data, uint8_t dir, uint8_t mask, uint8_t *res)
+{
+       EIMSK = 0; /* recover INT_RF to ATUSB_GPIO_CLEANUP or an MCU reset */
+
+       switch (port) {
+       case 1:
+               DDRB = (DDRB & ~mask) | dir;
+               PORTB = (PORTB & ~mask) | data;
+               break;
+       case 2:
+               DDRC = (DDRC & ~mask) | dir;
+               PORTC = (PORTC & ~mask) | data;
+               break;
+       case 3:
+               DDRD = (DDRD & ~mask) | dir;
+               PORTD = (PORTD & ~mask) | data;
+               break;
+       default:
+               return 0;
+       }
+
+       /* disable the UART so that we can meddle with these pins as well. */
+       spi_off();
+       _delay_ms(1);
+
+       switch (port) {
+       case 1:
+               res[0] = PINB;
+               res[1] = PORTB;
+               res[2] = DDRB;
+               break;
+       case 2:
+               res[0] = PINC;
+               res[1] = PORTC;
+               res[2] = DDRC;
+               break;
+       case 3:
+               res[0] = PIND;
+               res[1] = PORTD;
+               res[2] = DDRD;
+               break;
+       }
+
+       return 1;
+}
+
+
+void gpio_cleanup(void)
+{
+       EIMSK = 1 << 0;
+}
+
+
+static void done(void *user)
+{
+       led(0);
+}
+
+
+uint8_t irq_serial;
+
+#if defined(ATUSB) || defined(HULUSB)
+ISR(INT0_vect)
+#endif
+#ifdef RZUSB
+ISR(TIMER1_CAPT_vect)
+#endif
+{
+       if (mac_irq) {
+               if (mac_irq())
+                       return;
+       }
+       if (eps[1].state == EP_IDLE) {
+               led(1);
+               irq_serial = (irq_serial+1) | 0x80;
+               usb_send(&eps[1], &irq_serial, 1, done, NULL);
+       }
+}
diff --git a/atusb/board_atusb.c b/atusb/board_atusb.c
new file mode 100644 (file)
index 0000000..a02fb7f
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * fw/board_atusb.c - ATUSB Board-specific functions (for boot loader and application)
+ *
+ * Written 2016 by Stefan Schmidt
+ * Copyright 2016 Stefan Schmidt
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ */
+
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <avr/boot.h>
+
+#define F_CPU   8000000UL
+#include <util/delay.h>
+
+#include "usb.h"
+#include "at86rf230.h"
+#include "board.h"
+#include "spi.h"
+#include "usb/usb.h"
+
+static bool spi_initialized = 0;
+
+void reset_rf(void)
+{
+       /* set up all the outputs; default port value is 0 */
+
+       DDRB = 0;
+       DDRC = 0;
+       DDRD = 0;
+       PORTB = 0;
+       PORTC = 0;
+       PORTD = 0;
+
+       OUT(LED);
+       OUT(nRST_RF);   /* this also resets the transceiver */
+       OUT(SLP_TR);
+
+       spi_init();
+
+       /* AT86RF231 data sheet, 12.4.13, reset pulse width: 625 ns (min) */
+
+       CLR(nRST_RF);
+       _delay_us(2);
+       SET(nRST_RF);
+
+       /* 12.4.14: SPI access latency after reset: 625 ns (min) */
+
+       _delay_us(2);
+
+       /* we must restore TRX_CTRL_0 after each reset (9.6.4) */
+
+       set_clkm();
+}
+
+void led(bool on)
+{
+       if (on)
+               SET(LED);
+       else
+               CLR(LED);
+}
+
+void set_clkm(void)
+{
+       /* switch CLKM to 8 MHz */
+
+       /*
+        * @@@ Note: Atmel advise against changing the external clock in
+        * mid-flight. We should therefore switch to the RC clock first, then
+        * crank up the external clock, and finally switch back to the external
+        * clock. The clock switching procedure is described in the ATmega32U2
+        * data sheet in secton 8.2.2.
+        */
+       spi_begin();
+       spi_send(AT86RF230_REG_WRITE | REG_TRX_CTRL_0);
+       spi_send(CLKM_CTRL_8MHz);
+       spi_end();
+}
+
+void board_init(void)
+{
+       /* Disable the watchdog timer */
+
+       MCUSR = 0;              /* Remove override */
+       WDTCSR |= 1 << WDCE;    /* Enable change */
+       WDTCSR = 1 << WDCE;     /* Disable watchdog while still enabling
+                                  change */
+
+       CLKPR = 1 << CLKPCE;
+       /* We start with a 1 MHz/8 clock. Disable the prescaler. */
+       CLKPR = 0;
+
+       get_sernum();
+}
+
+void spi_begin(void)
+{
+       if (!spi_initialized)
+               spi_init();
+       CLR(nSS);
+}
+
+void spi_off(void)
+{
+       spi_initialized = 0;
+       UCSR1B = 0;
+}
+
+void spi_init(void)
+{
+       SET(nSS);
+       OUT(SCLK);
+       OUT(MOSI);
+       OUT(nSS);
+       IN(MISO);
+
+       UBRR1 = 0;      /* set bit rate to zero to begin */
+       UCSR1C = 1 << UMSEL11 | 1 << UMSEL10;
+                       /* set MSPI, MSB first, SPI data mode 0 */
+       UCSR1B = 1 << RXEN1 | 1 << TXEN1;
+                       /* enable receiver and transmitter */
+       UBRR1 = 0;      /* reconfirm the bit rate */
+
+       spi_initialized = 1;
+}
+
+void usb_init(void)
+{
+       USBCON |= 1 << FRZCLK;          /* freeze the clock */
+
+       /* enable the PLL and wait for it to lock */
+       PLLCSR &= ~(1 << PLLP2 | 1 << PLLP1 | 1 << PLLP0);
+       PLLCSR |= 1 << PLLE;
+       while (!(PLLCSR & (1 << PLOCK)));
+
+       USBCON &= ~(1 << USBE);         /* reset the controller */
+       USBCON |= 1 << USBE;
+
+       USBCON &= ~(1 << FRZCLK);       /* thaw the clock */
+
+       UDCON &= ~(1 << DETACH);        /* attach the pull-up */
+       UDIEN = 1 << EORSTE;            /* enable device interrupts  */
+//     UDCON |= 1 << RSTCPU;           /* reset CPU on bus reset */
+
+       ep_init();
+}
+
+void board_app_init(void)
+{
+       /* enable INT0, trigger on rising edge */
+       EICRA = 1 << ISC01 | 1 << ISC00;
+       EIMSK = 1 << 0;
+}
diff --git a/atusb/board_atusb.h b/atusb/board_atusb.h
new file mode 100644 (file)
index 0000000..e5974c7
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * fw/board_atusb.h - ATUSB Board-specific functions and definitions
+ *
+ * Written 2016 by Stefan Schmidt
+ * Copyright 2016 Stefan Schmidt
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef BOARD_ATUSB_H
+#define        BOARD_ATUSB_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#define        LED_PORT        B
+#define        LED_BIT           6
+#define        nRST_RF_PORT    C
+#define        nRST_RF_BIT       7
+#define        SLP_TR_PORT     B
+#define        SLP_TR_BIT        4
+
+#define SCLK_PORT      D
+#define SCLK_BIT         5
+#define        MOSI_PORT       D
+#define        MOSI_BIT          3
+
+#define        MISO_PORT       D
+#define        MISO_BIT          2
+#define        nSS_PORT        D
+#define        nSS_BIT           1
+#define        IRQ_RF_PORT     D
+#define        IRQ_RF_BIT        0
+
+#define SPI_WAIT_DONE()        while (!(UCSR1A & 1 << RXC1))
+#define SPI_DATA       UDR1
+
+void set_clkm(void);
+void board_init(void);
+
+void spi_begin(void);
+void spi_off(void);
+void spi_init(void);
+
+#endif /* !BOARD_H */
diff --git a/atusb/board_hulusb.c b/atusb/board_hulusb.c
new file mode 100644 (file)
index 0000000..084714e
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * fw/board_hulusb.c - Busware HUL Board-specific functions (for boot loader and application)
+ *
+ * Written 2017 by Filzmaier Josef
+ * Based on fw/board_rzusb written and Copyright 2016 Stefan Schmidt
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ */
+
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <avr/boot.h>
+
+#define F_CPU   8000000UL
+#include <util/delay.h>
+
+#include "usb.h"
+#include "at86rf230.h"
+#include "board.h"
+#include "spi.h"
+#include "usb/usb.h"
+
+static bool spi_initialized = 0;
+
+void reset_rf(void)
+{
+       /* set up all the outputs; default port value is 0 */
+
+       DDRB = 0;
+       DDRC = 0;
+       DDRD = 0;
+       PORTB = 0;
+       PORTC = 0;
+       PORTD = 0;
+
+       OUT(LED_RED);
+       OUT(LED_GREEN);
+       SET(LED_RED); /* Leds are active low on HULUSB board */
+       CLR(LED_GREEN); /* Green Led indicates the dongle is running */
+       OUT(nRST_RF);   /* this also resets the transceiver */
+       OUT(SLP_TR);
+
+       spi_init();
+
+       /* AT86RF212 data sheet, Appendix B, p166 Power-On Reset procedure */
+       /*-----------------------------------------------------------------*/
+       CLR(SLP_TR);
+       SET(nRST_RF);
+       SET(nSS);
+       _delay_us(400);
+
+       CLR(nRST_RF);
+       _delay_us(2);
+       SET(nRST_RF);
+
+       /* 5.1.4.5: Wait t10: 625 ns (min) */
+
+       _delay_us(2);
+
+       reg_write(REG_TRX_CTRL_0, 0x19);
+
+       change_state(TRX_CMD_FORCE_TRX_OFF);
+       /*-----------------------------------------------------------------*/
+
+       /* we must restore TRX_CTRL_0 after each reset (7.7.4) */
+
+       set_clkm();
+}
+
+void led_red(bool on) {
+       if (on)
+               CLR(LED_RED);
+       else
+               SET(LED_RED);
+}
+
+void led_green(bool on) {
+       if (on)
+               CLR(LED_GREEN);
+       else
+               SET(LED_GREEN);
+}
+
+void led(bool on)
+{
+       led_red(on);
+}
+
+void set_clkm(void)
+{
+       /* CLKM is not connected on BUSWARE HUL and therefore it is running in
+        * async mode. */
+       reg_write(REG_TRX_CTRL_0, 0x00);
+
+       /* TX_AUTO_CRC_ON, default disabled */
+       subreg_write(SR_TX_AUTO_CRC_ON, 1);
+}
+
+void board_init(void)
+{
+       /* Disable the watchdog timer */
+
+       MCUSR = 0;              /* Remove override */
+       WDTCSR |= 1 << WDCE;    /* Enable change */
+       WDTCSR = 1 << WDCE;     /* Disable watchdog while still enabling
+       change */
+
+       CLKPR = 1 << CLKPCE;
+       /* We start with a 16 MHz/8 clock. Put the prescaler to 2. */
+       CLKPR = 1 << CLKPS0;
+
+       get_sernum();
+}
+
+void spi_begin(void)
+{
+       if (!spi_initialized)
+               spi_init();
+       CLR(nSS);
+}
+
+void spi_off(void)
+{
+       spi_initialized = 0;
+       SPCR &= ~(1 << SPE);
+}
+
+void spi_init(void)
+{
+       SET(nSS);
+       OUT(SCLK);
+       OUT(MOSI);
+       OUT(nSS);
+       IN(MISO);
+
+       SPCR = (1 << SPE) | (1 << MSTR);
+       SPSR = (1 << SPI2X);
+
+       spi_initialized = 1;
+}
+
+void usb_init(void)
+{
+       USBCON |= 1 << FRZCLK;          /* freeze the clock */
+
+       /* enable the PLL and wait for it to lock */
+       /* TODO sheet page 50 For Atmel AT90USB128x only. Do not use with Atmel AT90USB64x. */
+       /*  FOR 8 XTAL Mhz only!!! */
+       PLLCSR = ((1 << PLLP1) | (1 << PLLP0));
+       PLLCSR |= 1 << PLLE;
+       while (!(PLLCSR & (1 << PLOCK)));
+
+       UHWCON |= (1 << UVREGE);
+
+       USBCON &= ~((1 << USBE) | (1 << OTGPADE));              /* reset the controller */
+       USBCON |= ((1 << USBE) | (1 << OTGPADE));
+
+       USBCON &= ~(1 << FRZCLK);       /* thaw the clock */
+
+       UDCON &= ~(1 << DETACH);        /* attach the pull-up */
+       UDIEN = 1 << EORSTE;            /* enable device interrupts  */
+       //      UDCON |= 1 << RSTCPU;           /* reset CPU on bus reset */
+
+       ep_init();
+}
+
+void board_app_init(void)
+{
+       /* enable INT0, trigger on rising edge */
+       EICRA = 1 << ISC01 | 1 << ISC00;
+       EIMSK = 1 << INT0;
+}
diff --git a/atusb/board_hulusb.h b/atusb/board_hulusb.h
new file mode 100644 (file)
index 0000000..a1dadf0
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * fw/board_hulusb.h - Busware HUL Board-specific functions (for boot loader and application)
+ *
+ * Written 2017 by Filzmaier Josef
+ * Based on fw/board_rzusb written and Copyright 2016 Stefan Schmidt
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef BOARD_HULUSB_H
+#define        BOARD_HULUSB_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#define LED_RED_PORT           A
+#define LED_GREEN_PORT         A
+#define LED_RED_BIT            3
+#define LED_GREEN_BIT          4
+#define LED_PORT               LED_RED_PORT
+#define LED_BIT                        LED_RED_BIT
+
+#define nRST_RF_PORT           B
+#define nRST_RF_BIT            5
+#define SLP_TR_PORT            B
+#define SLP_TR_BIT             4
+
+#define SCLK_PORT              B
+#define SCLK_BIT               1
+#define MOSI_PORT              B
+#define MOSI_BIT               2
+
+#define MISO_PORT              B
+#define MISO_BIT               3
+#define nSS_PORT               B
+#define nSS_BIT                        0
+#define IRQ_RF_PORT            D
+#define IRQ_RF_BIT             4
+
+#define SR_TX_AUTO_CRC_ON      0x04, 0x20, 5
+#define SR_CHANNEL             0x08, 0x1f, 0
+
+#define RG_CC_CTRL_1           (0x14)
+
+#define SPI_WAIT_DONE()        while ((SPSR & (1 << SPIF)) == 0)
+#define SPI_DATA       SPDR
+
+void set_clkm(void);
+void board_init(void);
+
+void led_red(bool on);
+void led_green(bool on);
+
+void spi_begin(void);
+void spi_off(void);
+void spi_init(void);
+
+#ifdef DEBUG
+void printStatus(void);
+#define PRINT_STATUS() printStatus()
+#endif
+
+#endif /* !BOARD_HULUSB_H */
diff --git a/atusb/board_rzusb.c b/atusb/board_rzusb.c
new file mode 100644 (file)
index 0000000..e83d6fa
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * fw/board_rzusb.c - RZUSB Board-specific functions (for boot loader and application)
+ *
+ * Written 2016 by Stefan Schmidt
+ * Copyright 2016 Stefan Schmidt
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ */
+
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <avr/boot.h>
+
+#define F_CPU   8000000UL
+#include <util/delay.h>
+
+#include "usb.h"
+#include "at86rf230.h"
+#include "board.h"
+#include "spi.h"
+#include "usb/usb.h"
+
+static bool spi_initialized = 0;
+
+void reset_rf(void)
+{
+       /* set up all the outputs; default port value is 0 */
+
+       DDRB = 0;
+       DDRC = 0;
+       DDRD = 0;
+       PORTB = 0;
+       PORTC = 0;
+       PORTD = 0;
+
+       OUT(LED);
+       OUT(nRST_RF);   /* this also resets the transceiver */
+       OUT(SLP_TR);
+
+       spi_init();
+
+       /* AT86RF231 data sheet, 12.4.13, reset pulse width: 625 ns (min) */
+
+       CLR(nRST_RF);
+       _delay_us(2);
+       SET(nRST_RF);
+
+       /* 12.4.14: SPI access latency after reset: 625 ns (min) */
+
+       _delay_us(2);
+
+       /* we must restore TRX_CTRL_0 after each reset (9.6.4) */
+
+       set_clkm();
+}
+
+void led(bool on)
+{
+       if (on)
+               SET(LED);
+       else
+               CLR(LED);
+}
+
+void set_clkm(void)
+{
+       /* switch CLKM to 8 MHz */
+
+       /*
+        * @@@ Note: Atmel advise against changing the external clock in
+        * mid-flight. We should therefore switch to the RC clock first, then
+        * crank up the external clock, and finally switch back to the external
+        * clock. The clock switching procedure is described in the ATmega32U2
+        * data sheet in secton 8.2.2.
+        */
+       spi_begin();
+       spi_send(AT86RF230_REG_WRITE | REG_TRX_CTRL_0);
+       spi_send(0x10);
+       spi_end();
+
+       /* TX_AUTO_CRC_ON, default disabled */
+       spi_begin();
+       spi_send(AT86RF230_REG_WRITE | 0x05);
+       spi_send(0x80);
+       spi_end();
+}
+
+void board_init(void)
+{
+       /* Disable the watchdog timer */
+
+       MCUSR = 0;              /* Remove override */
+       WDTCSR |= 1 << WDCE;    /* Enable change */
+       WDTCSR = 1 << WDCE;     /* Disable watchdog while still enabling
+                                  change */
+
+       CLKPR = 1 << CLKPCE;
+       /* We start with a 16 MHz/8 clock. Put the prescaler to 2. */
+       CLKPR = 1 << CLKPS0;
+
+       get_sernum();
+}
+
+void spi_begin(void)
+{
+       if (!spi_initialized)
+               spi_init();
+       CLR(nSS);
+}
+
+void spi_off(void)
+{
+       spi_initialized = 0;
+       SPCR &= ~(1 << SPE);
+}
+
+void spi_init(void)
+{
+       SET(nSS);
+       OUT(SCLK);
+       OUT(MOSI);
+       OUT(nSS);
+       IN(MISO);
+
+       SPCR = (1 << SPE) | (1 << MSTR);
+       SPSR = (1 << SPI2X);
+
+       spi_initialized = 1;
+}
+
+void usb_init(void)
+{
+       USBCON |= 1 << FRZCLK;          /* freeze the clock */
+
+       /* enable the PLL and wait for it to lock */
+       /* TODO sheet page 50 For Atmel AT90USB128x only. Do not use with Atmel AT90USB64x. */
+       /*  FOR 8 XTAL Mhz only!!! */
+       PLLCSR = ((1 << PLLP1) | (1 << PLLP0));
+       PLLCSR |= 1 << PLLE;
+       while (!(PLLCSR & (1 << PLOCK)));
+
+       UHWCON |= (1 << UVREGE);
+
+       USBCON &= ~((1 << USBE) | (1 << OTGPADE));              /* reset the controller */
+       USBCON |= ((1 << USBE) | (1 << OTGPADE));
+
+       USBCON &= ~(1 << FRZCLK);       /* thaw the clock */
+
+       UDCON &= ~(1 << DETACH);        /* attach the pull-up */
+       UDIEN = 1 << EORSTE;            /* enable device interrupts  */
+//     UDCON |= 1 << RSTCPU;           /* reset CPU on bus reset */
+
+       ep_init();
+}
+
+void board_app_init(void)
+{
+       /* enable timer input capture 1, trigger on rising edge */
+       TCCR1B = (1 << ICES1);
+       TIFR1 = (1 << ICF1);
+       TIMSK1 = (1 << ICIE1);
+}
diff --git a/atusb/board_rzusb.h b/atusb/board_rzusb.h
new file mode 100644 (file)
index 0000000..c2e518f
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * fw/board_rzusb.h - RZUSB Board-specific functions and definitions
+ *
+ * Written 2016 by Stefan Schmidt
+ * Copyright 2016 Stefan Schmidt
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef BOARD_RZUSB_H
+#define        BOARD_RZUSB_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#define        LED_PORT        D
+#define        LED_BIT           7
+#define        nRST_RF_PORT    B
+#define        nRST_RF_BIT       5
+#define        SLP_TR_PORT     B
+#define        SLP_TR_BIT        4
+
+#define SCLK_PORT      B
+#define SCLK_BIT         1
+#define        MOSI_PORT       B
+#define        MOSI_BIT          2
+
+#define        MISO_PORT       B
+#define        MISO_BIT          3
+#define        nSS_PORT        B
+#define        nSS_BIT           0
+#define        IRQ_RF_PORT     D
+#define        IRQ_RF_BIT        4
+
+#define SPI_WAIT_DONE()        while ((SPSR & (1 << SPIF)) == 0)
+#define SPI_DATA       SPDR
+
+void set_clkm(void);
+void board_init(void);
+
+void spi_begin(void);
+void spi_off(void);
+void spi_init(void);
+
+#endif /* !BOARD_H */
diff --git a/atusb/boot.c b/atusb/boot.c
new file mode 100644 (file)
index 0000000..6826ac6
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * fw/boot.c - DFU boot loader for ATUSB
+ *
+ * Written 2008-2011 by Werner Almesberger
+ * Copyright 2008-2011 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+
+#include <stdint.h>
+
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <avr/pgmspace.h>
+
+#define F_CPU   8000000UL
+#include <util/delay.h>
+
+#include "usb.h"
+#include "dfu.h"
+
+#include "board.h"
+#include "spi.h"
+#include "atusb/ep0.h"
+
+
+#define        MS_TO_LOOPS(ms) ((uint32_t) (ms)*335)
+
+
+static void (*run_payload)(void) = 0;
+
+
+int main(void)
+{
+       /*
+        * pgm_read_byte gets cached and there doesn't seem to be any other
+        * way to dissuade gcc from doing this.
+        */
+       volatile int zero = 0;
+       uint32_t loop = 0;
+
+       board_init();
+       reset_rf();
+
+       /* now we should be at 8 MHz */
+
+       usb_init();
+       dfu_init();
+
+       /* move interrupt vectors to the boot loader */
+       MCUCR = 1 << IVCE;
+       MCUCR = 1 << IVSEL;
+
+       sei();
+
+       led(1);
+
+       while (loop != MS_TO_LOOPS(2500)) {
+               if (dfu.state == dfuIDLE && pgm_read_byte(zero) != 0xff)
+                       loop++;
+               else
+                       loop = 0;
+       }
+
+       led(0);
+
+       cli();
+
+       usb_reset();
+       run_payload();
+
+       while (1);      /* not reached */
+}
diff --git a/atusb/descr.c b/atusb/descr.c
new file mode 100644 (file)
index 0000000..f96b0ee
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * fw/descr.c - USB descriptors
+ *
+ * Written 2008-2011, 2014 by Werner Almesberger
+ * Copyright 2008-2011, 2014 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+
+#include "usb.h"
+#include "dfu.h"
+#include "board.h"
+
+
+#define LE(x) ((uint16_t) (x) & 0xff), ((uint16_t) (x) >> 8)
+
+/*
+ * Device descriptor
+ */
+
+const uint8_t device_descriptor[18] = {
+       18,                     /* bLength */
+       USB_DT_DEVICE,          /* bDescriptorType */
+       LE(0x200),              /* bcdUSB */
+       USB_CLASS_VENDOR_SPEC,  /* bDeviceClass */
+       0x00,                   /* bDeviceSubClass */
+       0x00,                   /* bDeviceProtocol */
+       EP0_SIZE,               /* bMaxPacketSize */
+       LE(USB_VENDOR),         /* idVendor */
+       LE(USB_PRODUCT),        /* idProduct */
+       LE(0x0001),             /* bcdDevice */
+       0,                      /* iManufacturer */
+       0,                      /* iProduct */
+#ifdef HAS_BOARD_SERNUM
+       1,                      /* iSerialNumber */
+#else
+       0,                      /* iSerialNumber */
+#endif
+       1                       /* bNumConfigurations */
+};
+
+
+/*
+ * Our configuration
+ *
+ * We're always bus-powered.
+ */
+
+const uint8_t config_descriptor[] = {
+       9,                      /* bLength */
+       USB_DT_CONFIG,          /* bDescriptorType */
+#if 0
+       LE(9+9+7+7),            /* wTotalLength */
+#else
+       LE(9+9+7+9),            /* wTotalLength */
+#endif
+       2,                      /* bNumInterfaces */
+       1,                      /* bConfigurationValue (> 0 !) */
+       0,                      /* iConfiguration */
+       USB_ATTR_BUS_POWERED,   /* bmAttributes */
+       ((BOARD_MAX_mA)+1)/2,   /* bMaxPower */
+
+       /* Interface #0 */
+
+       9,                      /* bLength */
+       USB_DT_INTERFACE,       /* bDescriptorType */
+       0,                      /* bInterfaceNumber */
+       0,                      /* bAlternateSetting */
+       1,                      /* bNumEndpoints */
+       USB_CLASS_VENDOR_SPEC,  /* bInterfaceClass */
+       0,                      /* bInterfaceSubClass */
+       0,                      /* bInterfaceProtocol */
+       0,                      /* iInterface */
+
+#if 0
+       /* EP OUT */
+
+       7,                      /* bLength */
+       USB_DT_ENDPOINT,        /* bDescriptorType */
+       0x01,                   /* bEndPointAddress */
+       0x02,                   /* bmAttributes (bulk) */
+       LE(EP1_SIZE),           /* wMaxPacketSize */
+       0,                      /* bInterval */
+#endif
+
+#if 1
+       /* EP IN */
+
+       7,                      /* bLength */
+       USB_DT_ENDPOINT,        /* bDescriptorType */
+       0x81,                   /* bEndPointAddress */
+       0x02,                   /* bmAttributes (bulk) */
+       LE(EP1_SIZE),           /* wMaxPacketSize */
+       0,                      /* bInterval */
+#endif
+
+       /* Interface #1 */
+
+       DFU_ITF_DESCR(1, 0, dfu_proto_runtime, 0)
+};
diff --git a/atusb/ep0.c b/atusb/ep0.c
new file mode 100644 (file)
index 0000000..fa43f3b
--- /dev/null
@@ -0,0 +1,338 @@
+/*
+ * fw/ep0.c - EP0 extension protocol
+ *
+ * Written 2008-2011, 2013 by Werner Almesberger
+ * Copyright 2008-2011, 2013 Werner Almesberger
+ * Copyright 2015-2016 Stefan Schmidt
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ */
+
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <avr/io.h>
+#include <avr/eeprom.h>
+
+#define F_CPU   8000000UL
+#include <util/delay.h>
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#include "usb.h"
+#include "dfu.h"
+
+#include "at86rf230.h"
+#include "atusb/ep0.h"
+#include "version.h"
+#include "board.h"
+#include "sernum.h"
+#include "spi.h"
+#include "mac.h"
+
+#ifdef ATUSB
+#define        HW_TYPE         ATUSB_HW_TYPE_110131
+#endif
+
+#ifdef RZUSB
+#define        HW_TYPE         ATUSB_HW_TYPE_RZUSB
+#endif
+
+#ifdef HULUSB
+#define HW_TYPE                ATUSB_HW_TYPE_HULUSB
+#endif
+
+#ifdef DEBUG
+#include "uart.h"
+#include <stdio.h>
+#define debug(FORMAT,args...) printf(FORMAT,##args)
+#define error(FORMAT,args...) printf(FORMAT,##args)
+#else
+#define debug(...)
+#define error(...)
+#endif
+
+
+static const uint8_t id[] = { EP0ATUSB_MAJOR, EP0ATUSB_MINOR, HW_TYPE };
+static uint8_t buf[MAX_PSDU+3]; /* command, PHDR, and LQI */
+static uint8_t size;
+
+
+static void do_eeprom_write(void *user)
+{
+       int i;
+
+       for (i = 0; i < size; i++)
+               eeprom_update_byte((uint8_t*)i, buf[i]);
+}
+
+static void do_buf_write(void *user)
+{
+       uint8_t i;
+
+       spi_begin();
+       for (i = 0; i != size; i++)
+               spi_send(buf[i]);
+       spi_end();
+}
+
+
+#define        BUILD_OFFSET    7       /* '#' plus "65535" plus ' ' */
+
+
+static bool my_setup(const struct setup_request *setup)
+{
+       uint16_t req = setup->bmRequestType | setup->bRequest << 8;
+       unsigned tmp;
+       uint8_t i;
+       uint64_t tmp64;
+
+       switch (req) {
+       case ATUSB_FROM_DEV(ATUSB_ID):
+               debug("ATUSB_ID\n");
+               if (setup->wLength > 3)
+                       return 0;
+               usb_send(&eps[0], id, setup->wLength, NULL, NULL);
+               return 1;
+       case ATUSB_FROM_DEV(ATUSB_BUILD):
+               debug("ATUSB_BUILD\n");
+               tmp = build_number;
+               for (i = BUILD_OFFSET-2; tmp; i--) {
+                       buf[i] = (tmp % 10)+'0';
+                       tmp /= 10;
+               }
+               buf[i] = '#';
+               buf[BUILD_OFFSET-1] = ' ';
+               for (size = 0; build_date[size]; size++)
+                       buf[BUILD_OFFSET+size] = build_date[size];
+               size += BUILD_OFFSET-i;
+               if (size > setup->wLength)
+                       return 0;
+               usb_send(&eps[0], buf+i, size, NULL, NULL);
+               return 1;
+
+       case ATUSB_TO_DEV(ATUSB_RESET):
+               debug("ATUSB_RESET\n");
+               reset_cpu();
+               while (1);
+
+       case ATUSB_TO_DEV(ATUSB_RF_RESET):
+               debug("ATUSB_RF_RESET\n");
+               reset_rf();
+               mac_reset();
+               //ep_send_zlp(EP_CTRL);
+               return 1;
+
+       case ATUSB_FROM_DEV(ATUSB_POLL_INT):
+               debug("ATUSB_POLL_INT\n");
+               if (setup->wLength < 1)
+                       return 0;
+               *buf = read_irq();
+               usb_send(&eps[0], buf, 1, NULL, NULL);
+               return 1;
+
+       case ATUSB_FROM_DEV(ATUSB_TIMER):
+               debug("ATUSB_TIMER\n");
+               size = setup->wLength;
+               if (size > sizeof(tmp64))
+                       size = sizeof(tmp64);
+               tmp64 = timer_read();
+               memcpy(buf, &tmp64, sizeof(tmp64));
+               usb_send(&eps[0], buf, size, NULL, NULL);
+               return 1;
+
+       case ATUSB_FROM_DEV(ATUSB_GPIO):
+               debug("ATUSB_GPIO\n");
+               if (setup->wLength < 3)
+                       return 0;
+               if (!gpio(setup->wIndex, setup->wValue, setup->wValue >> 8,
+                   setup->wIndex >> 8, buf))
+                       return 0;
+               usb_send(&eps[0], buf, 3, NULL, NULL);
+               return 1;
+       case ATUSB_TO_DEV(ATUSB_GPIO_CLEANUP):
+               gpio_cleanup();
+               return 1;
+
+       case ATUSB_TO_DEV(ATUSB_SLP_TR):
+               debug("ATUSB_SLP_TR\n");
+               slp_tr();
+               return 1;
+
+       case ATUSB_TO_DEV(ATUSB_REG_WRITE):
+               debug("ATUSB_REG_WRITE\n");
+               spi_begin();
+               spi_send(AT86RF230_REG_WRITE | setup->wIndex);
+               spi_send(setup->wValue);
+               spi_end();
+               //ep_send_zlp(EP_CTRL);
+               return 1;
+       case ATUSB_FROM_DEV(ATUSB_REG_READ):
+               debug("ATUSB_REG_READ\n");
+               spi_begin();
+               spi_send(AT86RF230_REG_READ | setup->wIndex);
+               *buf = spi_recv();
+               spi_end();
+               usb_send(&eps[0], buf, 1, NULL, NULL);
+               return 1;
+
+       case ATUSB_TO_DEV(ATUSB_BUF_WRITE):
+               debug("ATUSB_BUF_WRITE\n");
+               if (setup->wLength < 1)
+                       return 0;
+               if (setup->wLength > MAX_PSDU)
+                       return 0;
+               buf[0] = AT86RF230_BUF_WRITE;
+               buf[1] = setup->wLength;
+               size = setup->wLength+2;
+               usb_recv(&eps[0], buf+2, setup->wLength, do_buf_write, NULL);
+               return 1;
+       case ATUSB_FROM_DEV(ATUSB_BUF_READ):
+               debug("ATUSB_BUF_READ\n");
+               if (setup->wLength < 2)                 /* PHR+LQI */
+                       return 0;
+               if (setup->wLength > MAX_PSDU+2)        /* PHR+PSDU+LQI */
+                       return 0;
+               spi_begin();
+               spi_send(AT86RF230_BUF_READ);
+               size = spi_recv();
+               if (size >= setup->wLength)
+                       size = setup->wLength-1;
+               for (i = 0; i != size+1; i++)
+                       buf[i] = spi_recv();
+               spi_end();
+               usb_send(&eps[0], buf, size+1, NULL, NULL);
+               return 1;
+
+       case ATUSB_TO_DEV(ATUSB_SRAM_WRITE):
+               debug("ATUSB_SRAM_WRITE\n");
+               if (setup->wIndex > SRAM_SIZE)
+                       return 0;
+               if (setup->wIndex+setup->wLength > SRAM_SIZE)
+                       return 0;
+               buf[0] = AT86RF230_SRAM_WRITE;
+               buf[1] = setup->wIndex;
+               size = setup->wLength+2;
+               usb_recv(&eps[0], buf+2, setup->wLength, do_buf_write, NULL);
+               return 1;
+       case ATUSB_FROM_DEV(ATUSB_SRAM_READ):
+               debug("ATUSB_SRAM_READ\n");
+               if (setup->wIndex > SRAM_SIZE)
+                       return 0;
+               if (setup->wIndex+setup->wLength > SRAM_SIZE)
+                       return 0;
+               spi_begin();
+               spi_send(AT86RF230_SRAM_READ);
+               spi_send(setup->wIndex);
+               for (i = 0; i != setup->wLength; i++)
+                       buf[i] = spi_recv();
+               spi_end();
+               usb_send(&eps[0], buf, setup->wLength, NULL, NULL);
+               return 1;
+
+       case ATUSB_TO_DEV(ATUSB_SPI_WRITE):
+               size = setup->wLength+2;
+               if (size > sizeof(buf))
+                       return 0;
+               buf[0] = setup->wValue;
+               buf[1] = setup->wIndex;
+               if (setup->wLength)
+                       usb_recv(&eps[0], buf+2, setup->wLength,
+                           do_buf_write, NULL);
+               else
+                       do_buf_write(NULL);
+               return 1;
+       case ATUSB_FROM_DEV(ATUSB_SPI_WRITE2_SYNC):
+               spi_begin();
+               spi_send(setup->wValue);
+               spi_send(setup->wIndex);
+               spi_end();
+               buf[0] = irq_serial;
+               if (setup->wLength)
+                       usb_send(&eps[0], buf, 1, NULL, NULL);
+               return 1;
+
+       case ATUSB_FROM_DEV(ATUSB_SPI_READ1):
+       case ATUSB_FROM_DEV(ATUSB_SPI_READ2):
+               spi_begin();
+               spi_send(setup->wValue);
+               if (req == ATUSB_FROM_DEV(ATUSB_SPI_READ2))
+                       spi_send(setup->wIndex);
+               for (i = 0; i != setup->wLength; i++)
+                       buf[i] = spi_recv();
+               spi_end();
+               usb_send(&eps[0], buf, setup->wLength, NULL, NULL);
+               return 1;
+
+       case ATUSB_TO_DEV(ATUSB_RX_MODE):
+               return mac_rx(setup->wValue);
+       case ATUSB_TO_DEV(ATUSB_TX):
+               return mac_tx(setup->wValue, setup->wIndex, setup->wLength);
+       case ATUSB_TO_DEV(ATUSB_EUI64_WRITE):
+               debug("ATUSB_EUI64_WRITE\n");
+               usb_recv(&eps[0], buf, setup->wLength, do_eeprom_write, NULL);
+               _delay_ms(100);
+               reset_cpu();
+               return 1;
+
+       case ATUSB_FROM_DEV(ATUSB_EUI64_READ):
+               debug("ATUSB_EUI64_READ\n");
+               eeprom_read_block(buf, (const void*)0, 8);
+               usb_send(&eps[0], buf, 8, NULL, NULL);
+               return 1;
+
+       default:
+               error("Unrecognized SETUP: 0x%02x 0x%02x ...\n",
+                   setup->bmRequestType, setup->bRequest);
+               return 0;
+       }
+}
+
+
+static bool my_dfu_setup(const struct setup_request *setup)
+{
+       switch (setup->bmRequestType | setup->bRequest << 8) {
+       case DFU_TO_DEV(DFU_DETACH):
+               /* @@@ should use wTimeout */
+               dfu.state = appDETACH;
+               return 1;
+       default:
+               return dfu_setup_common(setup);
+       }
+}
+
+
+static void my_set_interface(int nth)
+{
+       if (nth) {
+               user_setup = my_dfu_setup;
+               user_get_descriptor = dfu_my_descr;
+               dfu.state = appIDLE;
+       } else {
+               user_setup = my_setup;
+               user_get_descriptor = sernum_get_descr;
+       }
+}
+
+
+static void my_reset(void)
+{
+       if (dfu.state == appDETACH)
+               reset_cpu();
+}
+
+
+void ep0_init(void)
+{
+       user_setup = my_setup;
+       user_set_interface = my_set_interface;
+       my_set_interface(0);
+       user_reset = my_reset;
+}
diff --git a/atusb/flash.c b/atusb/flash.c
new file mode 100644 (file)
index 0000000..1f8e59d
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * fw/flash.c - Board-specific flash functions
+ *
+ * Written 2011, 2013-2015 by Werner Almesberger
+ * Copyright 2011, 2013-2015 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <avr/boot.h>
+#include <avr/pgmspace.h>
+
+#include "dfu.h"
+#include "board.h"
+
+
+static uint32_t payload;
+
+
+static void flash_start(void)
+{
+       payload = 0;
+}
+
+
+static bool flash_can_write(uint16_t size)
+{
+       return payload+size <= BOOT_ADDR;
+}
+
+
+static void flash_write(const uint8_t *buf, uint16_t size)
+{
+       static uint8_t last;
+       const uint8_t *p;
+
+       for (p = buf; p != buf+size; p++) {
+               if (!(payload & (SPM_PAGESIZE-1))) {
+                       boot_page_erase(payload);
+                       boot_spm_busy_wait();
+               }
+
+               if (payload & 1)
+                       boot_page_fill(payload, last | (*p << 8));
+               else
+                       last = *p;
+               payload++;
+
+               if (!(payload & (SPM_PAGESIZE-1))) {
+                       boot_page_write(payload-SPM_PAGESIZE);
+                       boot_spm_busy_wait();
+               }
+       }
+}
+
+
+static void flash_end_write(void)
+{
+       if (payload & (SPM_PAGESIZE-1)) {
+               boot_page_write(payload & ~(SPM_PAGESIZE-1));
+               boot_spm_busy_wait();
+       }
+       boot_rww_enable();
+}
+
+
+static uint16_t flash_read(uint8_t *buf, uint16_t size)
+{
+       uint16_t got = 0;
+
+       while (size && payload != (uint32_t) FLASHEND+1) {
+               *buf++ = pgm_read_byte(payload);
+               payload++;
+               size--;
+               got++;
+       }
+       return got;
+}
+
+
+static const struct dfu_flash_ops flash_ops = {
+       .start          = flash_start,
+       .can_write      = flash_can_write,
+       .write          = flash_write,
+       .end_write      = flash_end_write,
+       .read           = flash_read,
+};
+
+
+const struct dfu_flash_ops *dfu_flash_ops = &flash_ops;
diff --git a/atusb/include/at86rf230.h b/atusb/include/at86rf230.h
new file mode 100644 (file)
index 0000000..4c3ae22
--- /dev/null
@@ -0,0 +1,402 @@
+/*
+ * include/at86rf230.h - AT86RF230/AT86RF231 protocol and register definitions
+ *
+ * Written 2008-2011 by Werner Almesberger
+ * Copyright 2008-2011 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+
+#ifndef AT86RF230_H
+#define        AT86RF230_H
+
+enum {
+       AT86RF230_REG_WRITE     = 0xc0, /* 11... */
+       AT86RF230_REG_READ      = 0x80, /* 10... */
+       AT86RF230_BUF_WRITE     = 0x60, /* 011... */
+       AT86RF230_BUF_READ      = 0x20, /* 001... */
+       AT86RF230_SRAM_WRITE    = 0x40, /* 010... */
+       AT86RF230_SRAM_READ     = 0x00  /* 000... */
+};
+
+#define        MAX_PSDU        127     /* octets, see AT86RF230 manual section 8.1  */
+#define        SRAM_SIZE       128
+
+
+/* --- Registers ----------------------------------------------------------- */
+
+enum {
+       REG_TRX_STATUS          = 0x01,
+       REG_TRX_STATE           = 0x02,
+       REG_TRX_CTRL_0          = 0x03,
+
+       REG_TRX_CTRL_1          = 0x04, /* 231 only */
+
+       REG_PHY_TX_PWR          = 0x05,
+       REG_PHY_RSSI            = 0x06,
+       REG_PHY_ED_LEVEL        = 0x07,
+       REG_PHY_CC_CCA          = 0x08,
+       REG_CCA_THRES           = 0x09,
+
+       REG_RX_CTRL             = 0x0a, /* 231 only */
+       REG_SFD_VALUE           = 0x0b, /* 231 only */
+       REG_TRX_CTRL_2          = 0x0c, /* 231 only */
+       REG_ANT_DIV             = 0x0d, /* 231 only */
+
+       REG_IRQ_MASK            = 0x0e,
+       REG_IRQ_STATUS          = 0x0f,
+       REG_VREG_CTRL           = 0x10,
+       REG_BATMON              = 0x11,
+       REG_XOSC_CTRL           = 0x12,
+
+       REG_RX_SYN              = 0x15, /* 231 only */
+       REG_XAH_CTRL_1          = 0x17, /* 231 only */
+       REG_FTN_CTRL            = 0x18, /* 231 only */
+
+       REG_PLL_CF              = 0x1a,
+       REL_PLL_DCU             = 0x1b,
+       REG_PART_NUM            = 0x1c,
+       REG_VERSION_NUM         = 0x1d,
+       REG_MAN_ID_0            = 0x1e,
+       REG_MAN_ID_1            = 0x1f,
+       REG_SHORT_ADDR_0        = 0x20,
+       REG_SHORT_ADDR_1        = 0x21,
+       REG_PAN_ID_0            = 0x22,
+       REG_PAN_ID_1            = 0x23,
+       REG_IEEE_ADDR_0         = 0x24,
+       REG_IEEE_ADDR_1         = 0x25,
+       REG_IEEE_ADDR_2         = 0x26,
+       REG_IEEE_ADDR_3         = 0x27,
+       REG_IEEE_ADDR_4         = 0x28,
+       REG_IEEE_ADDR_5         = 0x29,
+       REG_IEEE_ADDR_6         = 0x2a,
+       REG_IEEE_ADDR_7         = 0x2b,
+
+       REG_XAH_CTRL_0          = 0x2c, /* XAH_CTRL in 230 */
+       REG_CSMA_SEED_0         = 0x2d,
+       REG_CSMA_SEED_1         = 0x2e,
+       REG_CSMA_BE             = 0x2f, /* 231 only */
+
+       REG_CONT_TX_0           = 0x36,
+       REG_CONT_TX_1           = 0x3d, /* 230 only */
+};
+
+/* --- TRX_STATUS --- ------------------------------------------------------ */
+
+#define        CCA_DONE        (1 << 7)
+#define        CCA_STATUS      (1 << 6)
+
+#define        TRX_STATUS_SHIFT        0
+#define        TRX_STATUS_MASK         0x1f
+
+enum {
+       TRX_STATUS_P_ON                 = 0x00, /* reset default */
+       TRX_STATUS_BUSY_RX              = 0x01,
+       TRX_STATUS_BUSY_TX              = 0x02,
+       TRX_STATUS_RX_ON                = 0x06,
+       TRX_STATUS_TRX_OFF              = 0x08,
+       TRX_STATUS_PLL_ON               = 0x09,
+       TRX_STATUS_SLEEP                = 0x0f,
+       TRX_STATUS_BUSY_RX_AACK         = 0x11,
+       TRX_STATUS_BUSY_TX_ARET         = 0x12,
+       TRX_STATUS_RX_AACK_ON           = 0x16,
+       TRX_STATUS_TX_ARET_ON           = 0x19,
+       TRX_STATUS_RX_ON_NOCLK          = 0x1c,
+       TRX_STATUS_RX_AACK_ON_NOCLK     = 0x1d,
+       TRX_STATUS_BUSY_RX_AACK_NOCLK   = 0x1e,
+       TRX_STATUS_TRANSITION           = 0x1f  /* ..._IN_PROGRESS */
+};
+
+/* --- TRX_STATE ----------------------------------------------------------- */
+
+#define        TRAC_STATUS_SHIFT       5
+#define        TRAC_STATUS_MASK        7
+
+enum {
+       TRAC_STATUS_SUCCESS                     = 0,    /* reset default */
+       TRAC_STATUS_SUCCESS_DATA_PENDING        = 1,
+       TRAC_STATUS_SUCCESS_WAIT_FOR_ACK        = 2,    /* 231 only */
+       TRAC_STATUS_CHANNEL_ACCESS_FAILURE      = 3,
+       TRAC_STATUS_NO_ACK                      = 5,
+       TRAC_STATUS_INVALID                     = 7
+};
+
+#define        TRX_CMD_SHIFT   0
+#define        TRX_CMD_MASK    0x1f
+
+enum {
+       TRX_CMD_NOP             = 0x00, /* reset default */
+       TRX_CMD_TX_START        = 0x02,
+       TRX_CMD_FORCE_TRX_OFF   = 0x03,
+       TRX_CMD_FORCE_PLL_ON    = 0x04, /* 231 only */
+       TRX_CMD_RX_ON           = 0x06,
+       TRX_CMD_TRX_OFF         = 0x08,
+       TRX_CMD_PLL_ON          = 0x09,
+       TRX_CMD_RX_AACK_ON      = 0x16,
+       TRX_CMD_TX_ARET_ON      = 0x19,
+};
+
+/* --- TRX_CTRL_0 ---------------------------------------------------------- */
+
+#define        PAD_IO_SHIFT    6
+#define        PAD_IO_MASK     3
+
+enum {
+       PAD_IO_2mA,     /* reset default */
+       PAD_IO_4mA,
+       PAD_IO_6mA,
+       PAD_IO_8mA
+};
+
+#define        PAD_IO_CLKM_SHIFT       4
+#define        PAD_IO_CLKM_MASK        3
+
+enum {
+       PAD_IO_CLKM_2mA,
+       PAD_IO_CLKM_4mA,        /* reset default */
+       PAD_IO_CLKM_5mA,
+       PAD_IO_CLKM_8mA,
+};
+
+#define        CLKM_SHA_SEL            (1 << 3)
+
+#define        CLKM_CTRL_SHIFT 0
+#define        CLKM_CTRL_MASK  7
+
+enum {
+       CLKM_CTRL_OFF   = 0,
+       CLKM_CTRL_1MHz  = 1,    /* reset default */
+       CLKM_CTRL_2MHz  = 2,
+       CLKM_CTRL_4MHz  = 3,
+       CLKM_CTRL_8MHz  = 4,
+       CLKM_CTRL_16MHz = 5
+};
+
+/* --- TRX_CTRL_1 (231 only) ----------------------------------------------- */
+
+#define        PA_EXT_EN               (1 << 7)
+#define        IRQ_2_EXT_EN            (1 << 6)
+#define        TX_AUTO_CRC_ON          (1 << 5)        /* 231 location */
+#define        RX_BL_CTRL              (1 << 4)
+
+#define        SPI_CMD_MODE_SHIFT      2
+#define        SPI_CMD_MODE_MASK       3
+
+enum {
+       SPI_CMD_MODE_EMPTY      = 0,    /* reset default */
+       SPI_CMD_MODE_TRX_STATUS = 1,
+       SPI_CMD_MODE_PHY_RSSI   = 2,
+       SPI_CMD_MODE_IRQ_STATUS = 3,
+};
+
+#define        IRQ_MASK_MODE           (1 << 1)
+#define        IRQ_POLARITY            (1 << 0)
+
+/* --- PHY_TX_PWR ---------------------------------------------------------- */
+
+#define        TX_AUTO_CRC_ON_230      (1 << 7)        /* 230 location */
+
+#define        PA_BUF_LT_SHIFT 6
+#define        PA_BUF_LT_MASK  3
+
+#define        PA_LT_SHIFT     4
+#define        PA_LT_MASK      3
+
+#define        TX_PWR_SHIFT    0
+#define        TX_PWR_MASK     0x0f
+
+/* --- PHY_RSSI ------------------------------------------------------------ */
+
+#define        RX_CRC_VALID    (1 << 7)
+
+#define        RND_VALUE_SHIFT 5               /* 231 only */
+#define        RND_VALUE_MASK  3
+
+#define        RSSI_SHIFT      0
+#define        RSSI_MASK       0x1f
+
+/* --- PHY_CC_CCA ---------------------------------------------------------- */
+
+#define        CCA_REQUEST     (1 << 7)
+
+#define        CCA_MODE_SHIFT  5
+#define        CCA_MODE_MASK   3
+
+enum {
+       CCA_MODE_CARRIER_OR_ENERGY      = 0,    /* 231 only */
+       CCA_MODE_ENERGY                 = 1,    /* reset default */
+       CCA_MODE_CARRIER                = 2,
+       CCA_MODE_CARRIER_AND_ENERGY     = 3
+};
+
+#define        CHANNEL_SHIFT   0
+#define        CHANNEL_MASK    0x1f
+
+/* --- CCA_THRES ----------------------------------------------------------- */
+
+#define        CCA_ED_THRES_SHIFT      0
+#define        CCA_ED_THRES_MASK       0x0f
+
+/* --- RX_CTRL (231 only) -------------------------------------------------- */
+
+#define        PDT_THRES_SHIFT 0
+#define        PDT_THRES_MASK  0x0f
+
+enum {
+       PDT_THRES_DEFAULT       = 0x07, /* reset default */
+       PDT_THRES_DIVERSITY     = 0x03,
+};
+
+/* --- TRX_CTRL_2 (231 only) ----------------------------------------------- */
+
+#define        RX_SAFE_MODE            (1 << 7)
+
+#define        OQPSK_DATA_RATE_SHIFT   0
+#define        OQPSK_DATA_RATE_MASK    3
+
+enum {
+       OQPSK_DATA_RATE_250     = 0,    /* reset default */
+       OQPSK_DATA_RATE_500     = 1,
+       OQPSK_DATA_RATE_1000    = 2,
+       OQPSK_DATA_RATE_2000    = 3
+};
+
+/* --- ANT_DIV (231 only) -------------------------------------------------- */
+
+#define        ANT_SEL         (1 << 7)
+#define        ANT_DIV_EN      (1 << 3)
+#define        ANT_EXT_SW_EN   (1 << 2)
+
+#define        ANT_CTRL_SHIFT  0
+#define        ANT_CTRL_MASK   3
+
+enum {
+       ANT_CTRL_ANT_0  = 1,
+       ANT_CTRL_ANT_1  = 2,
+       ANT_CTRL_NODIV  = 3,    /* reset default */
+};
+
+/* --- IRQ_MASK/IRQ_STATUS ------------------------------------------------- */
+
+enum {
+       IRQ_PLL_LOCK    = 1 << 0,
+       IRQ_PLL_UNLOCK  = 1 << 1,
+       IRQ_RX_START    = 1 << 2,
+       IRQ_TRX_END     = 1 << 3,
+       IRQ_CCA_ED_DONE = 1 << 4,       /* 231 only */
+       IRQ_AMI         = 1 << 5,       /* 231 only */
+       IRQ_TRX_UR      = 1 << 6,
+       IRQ_BAT_LOW     = 1 << 7
+};
+
+/* --- VREG_CTRL ----------------------------------------------------------- */
+
+#define        AVREG_EXT       (1 << 7)
+#define        AVDD_OK         (1 << 6)
+#define        DVREG_EXT       (1 << 3)
+#define        DVDD_OK         (1 << 2)
+
+/* --- BATMON -------------------------------------------------------------- */
+
+#define        BATMON_OK       (1 << 5)
+#define        BATMON_HR       (1 << 4)
+
+#define        BATMON_VTH_SHIFT        0
+#define        BATMON_VTH_MASK         0x0f
+
+/* --- XOSC_CTRL ----------------------------------------------------------- */
+
+#define        XTAL_MODE_SHIFT 4
+#define        XTAL_MODE_MASK  0x0f
+
+enum {
+       XTAL_MODE_OFF   = 0x0,  /* 230 only */
+       XTAL_MODE_EXT   = 0x4,
+       XTAL_MODE_INT   = 0xf   /* reset default */
+};
+
+#define        XTAL_TRIM_SHIFT 4
+#define        XTAL_TRIM_MASK  0x0f
+
+/* --- RX_SYN (231 only) --------------------------------------------------- */
+
+#define        RX_PDT_DIS              (1 << 7)
+
+#define        RX_PDT_LEVEL_SHIFT      0
+#define        RX_PDT_LEVEL_MASK       0xf
+
+/* --- XAH_CTRL_1 (231 only) ----------------------------------------------- */
+
+#define        AACK_FLTR_RES_FT        (1 << 5)
+#define        AACK_UPLD_RES_FT        (1 << 4)
+#define        AACK_ACK_TIME           (1 << 2)
+#define        AACK_PROM_MODE          (1 << 1)
+
+/* --- FTN_CTRL (231 only) ------------------------------------------------- */
+
+#define        FTN_START               (1 << 7)
+
+/* --- PLL_CF -------------------------------------------------------------- */
+
+#define        PLL_CF_START    (1 << 7)
+
+/* --- PLL_DCU ------------------------------------------------------------- */
+
+#define        PLL_DCU_START   (1 << 7)
+
+/* --- XAH_CTRL_0 (XAH_CTRL in 230) ---------------------------------------- */
+
+#define        MAX_FRAME_RETRIES_SHIFT 4
+#define        MAX_FRAME_RETRIES_MASK  0x0f
+
+#define        MAX_CSMA_RETRIES_SHIFT  1
+#define        MAX_CSMA_RETRIES_MASK   0x07
+
+#define        SLOTTED_OPERATION       (1 << 0)        /* 231 only */
+
+/* --- CSMA_SEED_1 --------------------------------------------------------- */
+
+#define        MIN_BE_SHIFT_230        6       /* 230 location */
+#define        MIN_BE_MASK_230         3
+
+#define        AACK_FVN_MODE_SHIFT     6       /* 231 only */
+#define        AACK_FVN_MODE_MASK      3
+
+enum {
+       AACK_FVN_MODE_0         = 0,
+       AACK_FVN_MODE_01        = 1,    /* reset default */
+       AACK_FVN_MODE_012       = 2,
+       AACK_FVN_MODE_ANY       = 3
+};
+
+#define        AACK_SET_PD             (1 << 5)
+#define        AACK_DIS_ACK            (1 << 4)        /* 231 only */
+#define        I_AM_COORD              (1 << 3)
+
+#define CSMA_SEED_1_SHIFT      0
+#define        CSMA_SEED_1_MASK        7
+
+/* --- CSMA_BE ------------------------------------------------------------- */
+
+#define        MAX_BE_SHIFT            4
+#define        MAX_BE_MASK             0x0f
+
+#define        MIN_BE_SHIFT            0       /* 231 location */
+#define        MIN_BE_MASK             0x0f
+
+/* --- REG_CONT_TX_0 ------------------------------------------------------- */
+
+#define        CONT_TX_MAGIC           0x0f
+
+/* --- REG_CONT_TX_1 (230 only) -------------------------------------------- */
+
+#define        CONT_TX_MOD             0x00    /* modulated */
+#define        CONT_TX_M2M             0x10    /* f_CH-2 MHz */
+#define        CONT_TX_M500K           0x80    /* f_CH-0.5 MHz */
+#define        CONT_TX_P500K           0xc0    /* f_CH+0.5 MHz */
+
+#endif /* !AT86RF230_H */
diff --git a/atusb/include/atusb/atusb.h b/atusb/include/atusb/atusb.h
new file mode 100644 (file)
index 0000000..555d14b
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * atusb.h - Definitions shared between kernel and ATUSB firmware
+ *
+ * Written 2013 by Werner Almesberger <werner@almesberger.net>
+ *
+ * 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, version 2, or
+ * (at your option) any later version.
+ *
+ * This file should be identical for kernel and firmware.
+ * Kernel: drivers/net/ieee802154/atusb.h
+ * Firmware: ben-wpan/atusb/fw/include/atusb/atusb.h
+ */
+
+#ifndef        _ATUSB_H
+#define        _ATUSB_H
+
+#define ATUSB_VENDOR_ID        0x20b7  /* Qi Hardware*/
+#define ATUSB_PRODUCT_ID 0x1540        /* 802.15.4, device 0 */
+                               /*     -- -         - */
+
+#define ATUSB_BUILD_SIZE 256   /* maximum build version/date message length */
+
+/* Commands to our device. Make sure this is synced with the firmware */
+enum atusb_requests {
+       ATUSB_ID                        = 0x00, /* system status/control grp */
+       ATUSB_BUILD,
+       ATUSB_RESET,
+       ATUSB_RF_RESET                  = 0x10, /* debug/test group */
+       ATUSB_POLL_INT,
+       ATUSB_TEST,                     /* atusb-sil only */
+       ATUSB_TIMER,
+       ATUSB_GPIO,
+       ATUSB_SLP_TR,
+       ATUSB_GPIO_CLEANUP,
+       ATUSB_REG_WRITE                 = 0x20, /* transceiver group */
+       ATUSB_REG_READ,
+       ATUSB_BUF_WRITE,
+       ATUSB_BUF_READ,
+       ATUSB_SRAM_WRITE,
+       ATUSB_SRAM_READ,
+       ATUSB_SPI_WRITE                 = 0x30, /* SPI group */
+       ATUSB_SPI_READ1,
+       ATUSB_SPI_READ2,
+       ATUSB_SPI_WRITE2_SYNC,
+       ATUSB_RX_MODE                   = 0x40, /* HardMAC group */
+       ATUSB_TX,
+       ATUSB_EUI64_WRITE               = 0x50, /* Parameter in EEPROM grp */
+       ATUSB_EUI64_READ,
+};
+
+enum {
+       ATUSB_HW_TYPE_100813,   /* 2010-08-13 */
+       ATUSB_HW_TYPE_101216,   /* 2010-12-16 */
+       ATUSB_HW_TYPE_110131,   /* 2011-01-31, ATmega32U2-based */
+       ATUSB_HW_TYPE_RZUSB,    /* Atmel Raven USB dongle with at86rf230 */
+       ATUSB_HW_TYPE_HULUSB,   /* Busware HUL USB dongle with at86rf212 */
+};
+
+/*
+ * Direction   bRequest                wValue          wIndex  wLength
+ *
+ * ->host      ATUSB_ID                -               -       3
+ * ->host      ATUSB_BUILD             -               -       #bytes
+ * host->      ATUSB_RESET             -               -       0
+ *
+ * host->      ATUSB_RF_RESET          -               -       0
+ * ->host      ATUSB_POLL_INT          -               -       1
+ * host->      ATUSB_TEST              -               -       0
+ * ->host      ATUSB_TIMER             -               -       #bytes (6)
+ * ->host      ATUSB_GPIO              dir+data        mask+p# 3
+ * host->      ATUSB_SLP_TR            -               -       0
+ * host->      ATUSB_GPIO_CLEANUP      -               -       0
+ *
+ * host->      ATUSB_REG_WRITE         value           addr    0
+ * ->host      ATUSB_REG_READ          -               addr    1
+ * host->      ATUSB_BUF_WRITE         -               -       #bytes
+ * ->host      ATUSB_BUF_READ          -               -       #bytes
+ * host->      ATUSB_SRAM_WRITE        -               addr    #bytes
+ * ->host      ATUSB_SRAM_READ         -               addr    #bytes
+ *
+ * host->      ATUSB_SPI_WRITE         byte0           byte1   #bytes
+ * ->host      ATUSB_SPI_READ1         byte0           -       #bytes
+ * ->host      ATUSB_SPI_READ2         byte0           byte1   #bytes
+ * ->host      ATUSB_SPI_WRITE2_SYNC   byte0           byte1   0/1
+ *
+ * host->      ATUSB_RX_MODE           on              -       0
+ * host->      ATUSB_TX                flags           ack_seq #bytes
+ * host->      ATUSB_EUI64_WRITE       -               -       #bytes (8)
+ * ->host      ATUSB_EUI64_READ        -               -       #bytes (8)
+ */
+
+#define ATUSB_REQ_FROM_DEV     (USB_TYPE_VENDOR | USB_DIR_IN)
+#define ATUSB_REQ_TO_DEV       (USB_TYPE_VENDOR | USB_DIR_OUT)
+
+#endif /* !_ATUSB_H */
diff --git a/atusb/include/atusb/ep0.h b/atusb/include/atusb/ep0.h
new file mode 100644 (file)
index 0000000..7777345
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * include/atusb/ep0.h - EP0 extension protocol
+ *
+ * Written 2008-2011, 2013 by Werner Almesberger
+ * Copyright 2008-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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+
+#ifndef EP0_H
+#define EP0_H
+
+#include <atusb/atusb.h>
+
+
+/*
+ * EP0 protocol:
+ *
+ * 0.0 initial release
+ * 0.1  addition of ATUSB_TEST
+ * 0.2  First public release
+ * 0.3 ATUSB_EUI64_READ/WRITE for permanent EUI64 handling
+ *     Support to run the firmware on Atmel Raven USB dongles
+ *     Remove FCS frame check from firmware and leave it to the driver
+ *     Use extended operation mode for TX for automatic ACK handling
+ */
+
+#define EP0ATUSB_MAJOR 0       /* EP0 protocol, major revision */
+#define EP0ATUSB_MINOR 3       /* EP0 protocol, minor revision */
+
+
+/*
+ * bmRequestType:
+ *
+ * D7 D6..5 D4...0
+ * |  |     |
+ * direction (0 = host->dev)
+ *    type (2 = vendor)
+ *          recipient (0 = device)
+ */
+
+#ifndef USB_TYPE_VENDOR
+#define        USB_TYPE_VENDOR         0x40
+#endif
+
+#ifndef USB_DIR_IN
+#define        USB_DIR_IN              0x80
+#endif
+
+#ifndef USB_DIR_OUT
+#define        USB_DIR_OUT             0x00
+#endif
+
+#define        ATUSB_FROM_DEV(req)     (ATUSB_REQ_FROM_DEV | (req) << 8)
+#define        ATUSB_TO_DEV(req)       (ATUSB_REQ_TO_DEV | (req) << 8)
+
+
+void ep0_init(void);
+
+#endif /* !EP0_H */
diff --git a/atusb/mac.c b/atusb/mac.c
new file mode 100644 (file)
index 0000000..835002c
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * fw/mac.c - HardMAC functions
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <stddef.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "usb.h"
+
+#include "at86rf230.h"
+#include "spi.h"
+#include "board.h"
+#include "mac.h"
+
+#define        RX_BUFS 3
+
+
+bool (*mac_irq)(void) = NULL;
+
+
+static uint8_t rx_buf[RX_BUFS][MAX_PSDU+2]; /* PHDR+payload+LQ */
+static uint8_t tx_buf[MAX_PSDU];
+static uint8_t tx_size = 0;
+static bool txing = 0;
+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;
+}
+
+
+/* ----- Interrupt handling ------------------------------------------------ */
+
+
+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);
+       next_buf(&rx_out);
+       usb_next();
+#ifdef AT86RF230
+       /* slap at86rf230 - reduce fragmentation issue */
+       change_state(TRX_STATUS_RX_AACK_ON);
+#endif
+}
+
+
+static void receive_frame(void)
+{
+       uint8_t size;
+       uint8_t *buf;
+
+       spi_begin();
+       spi_io(AT86RF230_BUF_READ);
+
+       size = spi_recv();
+       if (!size || (size & 0x80)) {
+               spi_end();
+               return;
+       }
+
+       buf = rx_buf[rx_in];
+       spi_recv_block(buf+1, size+1);
+       spi_end();
+
+       buf[0] = size;
+       next_buf(&rx_in);
+
+       if (eps[1].state == EP_IDLE)
+               usb_next();
+}
+
+
+static bool handle_irq(void)
+{
+       uint8_t irq;
+
+       irq = reg_read(REG_IRQ_STATUS);
+       if (!(irq & IRQ_TRX_END))
+               return 1;
+
+       if (txing) {
+               if (eps[1].state == EP_IDLE) {
+                       usb_send(&eps[1], &this_seq, 1, tx_ack_done, NULL);
+               } else {
+                       queued_tx_ack = 1;
+                       queued_seq = this_seq;
+               }
+               txing = 0;
+               return 1;
+       }
+
+       /* likely */
+       if (eps[1].state == EP_IDLE || rx_in != rx_out)
+               receive_frame();
+
+       return 1;
+}
+
+
+/* ----- TX/RX ------------------------------------------------------------- */
+
+
+bool mac_rx(int on)
+{
+       if (on) {
+               mac_irq = handle_irq;
+               reg_read(REG_IRQ_STATUS);
+               change_state(TRX_CMD_RX_AACK_ON);
+       } else {
+               mac_irq = NULL;
+               change_state(TRX_CMD_FORCE_TRX_OFF);
+               txing = 0;
+       }
+       return 1;
+}
+
+
+static void do_tx(void *user)
+{
+       uint16_t timeout = 0xffff;
+       uint8_t status;
+       uint8_t i;
+
+       /*
+        * If we time out here, the host driver will time out waiting for the
+        * TRX_END acknowledgement.
+        */
+       do {
+               if (!--timeout)
+                       return;
+               status = reg_read(REG_TRX_STATUS) & TRX_STATUS_MASK;
+       }
+       while (status != TRX_STATUS_RX_ON && status != TRX_STATUS_RX_AACK_ON);
+
+#ifdef AT86RF231
+       /*
+        * We use TRX_CMD_FORCE_PLL_ON instead of TRX_CMD_PLL_ON because a new
+        * reception may have begun while we were still working on the previous
+        * one.
+        */
+       reg_write(REG_TRX_STATE, TRX_CMD_FORCE_PLL_ON);
+#endif
+#ifdef AT86RF230
+       /*
+        * at86rf230 doesn't support force change, nevetherless this works
+        * somehow
+        */
+       reg_write(REG_TRX_STATE, TRX_CMD_PLL_ON);
+#endif
+#ifdef AT86RF212
+       /*
+       * We use TRX_CMD_FORCE_PLL_ON instead of TRX_CMD_PLL_ON because a new
+       * reception may have begun while we were still working on the previous
+       * one.
+       */
+       reg_write(REG_TRX_STATE, TRX_CMD_FORCE_PLL_ON);
+#endif
+
+       handle_irq();
+
+       spi_begin();
+       spi_send(AT86RF230_BUF_WRITE);
+       spi_send(tx_size+2); /* CRC */
+       for (i = 0; i != tx_size; i++)
+               spi_send(tx_buf[i]);
+       spi_end();
+
+       change_state(TRX_STATUS_TX_ARET_ON);
+
+       slp_tr();
+
+       txing = 1;
+       this_seq = next_seq;
+
+       /*
+        * Wait until we reach BUSY_TX_ARET, so that we command the transition to
+        * RX_AACK_ON which will be executed upon TX completion.
+        */
+       change_state(TRX_CMD_PLL_ON);
+       change_state(TRX_CMD_RX_AACK_ON);
+}
+
+
+bool mac_tx(uint16_t flags, uint8_t seq, uint16_t len)
+{
+       if (len > MAX_PSDU)
+               return 0;
+       tx_size = len;
+       next_seq = seq;
+       usb_recv(&eps[0], tx_buf, len, do_tx, NULL);
+       return 1;
+}
+
+
+void mac_reset(void)
+{
+       mac_irq = NULL;
+       txing = 0;
+       queued_tx_ack = 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 */
+       reg_write(REG_TRX_CTRL_1,
+           TX_AUTO_CRC_ON | SPI_CMD_MODE_PHY_RSSI << SPI_CMD_MODE_SHIFT);
+}
diff --git a/atusb/mac.h b/atusb/mac.h
new file mode 100644 (file)
index 0000000..f3c92fb
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * fw/mac.h - HardMAC functions
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef MAC_H
+#define        MAC_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+
+extern bool (*mac_irq)(void);
+
+bool mac_rx(int on);
+bool mac_tx(uint16_t flags, uint8_t seq, uint16_t len);
+void mac_reset(void);
+
+#endif /* !MAC_H */
diff --git a/atusb/sernum.c b/atusb/sernum.c
new file mode 100644 (file)
index 0000000..41e434c
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * fw/sernum.c - ATUSB serial number
+ *
+ * Written 2008-2011, 2013 by Werner Almesberger
+ * Copyright 2008-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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "usb.h"
+
+#include "board.h"
+#include "sernum.h"
+
+
+static const uint8_t string_descriptor_0[] = {
+       4,                              /* blength */
+       USB_DT_STRING,                  /* bDescriptorType */
+       LE(USB_LANGID_ENGLISH_US)       /* wLANGID[0]  */
+};
+
+
+bool sernum_get_descr(uint8_t type, uint8_t index, const uint8_t **reply,
+    uint8_t *size)
+{
+       if (type != USB_DT_STRING)
+               return 0;
+       switch (index) {
+       case 0:
+               *reply = string_descriptor_0;
+               *size = sizeof(string_descriptor_0);
+               return 1;
+       case 1:
+               *reply = board_sernum;
+               *size = sizeof(board_sernum);
+               return 1;
+       default:
+               return 0;
+       }
+}
diff --git a/atusb/sernum.h b/atusb/sernum.h
new file mode 100644 (file)
index 0000000..31a8e27
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * fw/sernum.h - ATUSB serial number
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef SERNUM_H
+#define        SERNUM_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "board.h"
+
+
+#ifdef HAS_BOARD_SERNUM
+
+bool sernum_get_descr(uint8_t type, uint8_t index, const uint8_t **reply,
+    uint8_t *size);
+
+#else /* HAS_BOARD_SERNUM */
+
+static inline bool sernum_get_descr(uint8_t type, uint8_t index,
+    const uint8_t **reply, uint8_t *size)
+{
+       return 0;
+}
+
+#endif /* !HAS_BOARD_SERNUM */
+
+#endif /* !SERNUM_H */
diff --git a/atusb/spi.c b/atusb/spi.c
new file mode 100644 (file)
index 0000000..3fa5715
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * fw/spi.c - ATmega8 family SPI I/O
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <avr/io.h>
+
+#include "board.h"
+#include "spi.h"
+
+
+uint8_t spi_io(uint8_t v)
+{
+//      while (!(UCSR1A & 1 << UDRE1));
+       SPI_DATA = v;
+       SPI_WAIT_DONE();
+       return SPI_DATA;
+}
+
+
+void spi_end(void)
+{
+//      while (!(UCSR1A & 1 << TXC1));
+       SET(nSS);
+}
+
+
+void spi_recv_block(uint8_t *buf, uint8_t n)
+{
+       if (!n)
+               return;
+       SPI_DATA = 0;
+       while (--n) {
+               SPI_WAIT_DONE();
+               *buf++ = SPI_DATA;
+               SPI_DATA = 0;
+       }
+       SPI_WAIT_DONE();
+       *buf++ = SPI_DATA;
+}
diff --git a/atusb/spi.h b/atusb/spi.h
new file mode 100644 (file)
index 0000000..6e04f4e
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * fw/spi.h - ATmega8 family SPI I/O
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef SPI_H
+#define        SPI_H
+
+#include <stdint.h>
+
+
+void spi_begin(void);
+uint8_t spi_io(uint8_t v);
+void spi_end(void);
+void spi_off(void);
+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 */
diff --git a/atusb/uart.c b/atusb/uart.c
new file mode 100644 (file)
index 0000000..44bec27
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * fw/uart.h - Functions needed for debugging over uart
+ *
+ * Code adapted from http://www.roboternetz.de/wissen/index.php/UART_mit_avr-gcc
+ * and http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial
+ *
+ * Published under the Creative Commons Share-Alike licence
+ * https://creativecommons.org/licenses/by-sa/2.0/de/
+ *
+ * S. Salewski 2007
+ *
+ * Adapted by
+ * Josef Filzmaier 2017
+ */
+
+#include <avr/io.h>
+#include "uart.h"
+
+#define USART_BAUD 38400UL
+#define F_CPU 8000000UL
+
+#define Wait_USART_Ready() while (!(UCSR1A & (1<<UDRE1)))
+#define UART_UBRR (F_CPU/(16L*USART_BAUD)-1)
+
+// initialize USART, 8N1 mode
+void
+uart_init(void)
+{
+/* TODO: Find a working configuration for uart for the atmega32u2 */
+#if CHIP == at90usb1287
+       CLKPR = (1 << CLKPCE);
+       CLKPR = 0; // clock prescaler == 0, so we have 16 MHz mpu frequency
+       UBRR1 = UART_UBRR;
+       UCSR1C = (1 << UCSZ10) | (1 << UCSZ11);
+       UCSR1B = (1 << TXEN1);
+       do
+       {
+               UDR1;
+       }
+       while (UCSR1A & (1 << RXC1));
+#endif
+
+}
+
+int uart_write_char(char c, FILE* stream)
+{
+       if (c == '\n'){
+               uart_new_line();
+       }
+       else {
+               Wait_USART_Ready();
+               UDR1 = c;
+       }
+       return 0;
+}
+
+void
+uart_new_line(void)
+{
+       Wait_USART_Ready();
+       UDR1 = '\r';
+       Wait_USART_Ready();
+       UDR1 = '\n';
+}
diff --git a/atusb/uart.h b/atusb/uart.h
new file mode 100644 (file)
index 0000000..4810f9c
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * fw/uart.h - Functions needed for debugging over uart
+ *
+ * Code adapted from http://www.roboternetz.de/wissen/index.php/UART_mit_avr-gcc
+ * and http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial
+ *
+ * Published under the Creative Commons Share-Alike licence
+ * https://creativecommons.org/licenses/by-sa/2.0/de/
+ *
+ * S. Salewski 2007
+ *
+ * Adapted by
+ * Josef Filzmaier 2017
+ */
+
+#ifndef UART_H_
+#define        UART_H_
+
+#include <stdio.h>
+
+void uart_init(void);
+int uart_write_char(char c, FILE* stream);
+void uart_new_line(void);
+
+#endif /* UART_H_ */
diff --git a/atusb/usb/atu2.c b/atusb/usb/atu2.c
new file mode 100644 (file)
index 0000000..98158bf
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * fw/usb/atu2.c - Chip-specific driver for Atmel ATxxxU2 USB chips
+ *
+ * Written 2008-2011, 2013-2014 by Werner Almesberger
+ * Copyright 2008-2011, 2013-2014 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+/*
+ * Known issues:
+ * - no suspend/resume
+ * - we don't call back after failed transmissions,
+ * - we don't reset the EP buffer after failed receptions
+ * - enumeration often encounters an error -71 (from which it recovers)
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#define F_CPU   8000000UL
+#include <util/delay.h>
+
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include "usb.h"
+#include "board.h"
+
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#if 1
+#define BUG_ON(cond)    do { if (cond) panic(); } while (0)
+#else
+#define BUG_ON(cond)
+#endif
+
+
+struct ep_descr eps[NUM_EPS];
+
+
+static uint16_t usb_read_word(void)
+{
+       uint8_t low;
+
+       low = UEDATX;
+       return low | UEDATX << 8;
+}
+
+
+static void enable_addr(void *user)
+{
+       while (!(UEINTX & (1 << TXINI)));
+       UDADDR |= 1 << ADDEN;
+}
+
+
+void set_addr(uint8_t addr)
+{
+       UDADDR = addr;
+       usb_send(&eps[0], NULL, 0, enable_addr, NULL);
+}
+
+
+void usb_ep_change(struct ep_descr *ep)
+{
+       if (ep->state == EP_TX) {
+               UENUM = ep-eps;
+               UEIENX |= 1 << TXINE;
+       }
+}
+
+
+static bool ep_setup(void)
+{
+       struct setup_request setup;
+
+       BUG_ON(UEBCLX < 8);
+
+       setup.bmRequestType = UEDATX;
+       setup.bRequest = UEDATX;
+       setup.wValue = usb_read_word();
+       setup.wIndex = usb_read_word();
+       setup.wLength = usb_read_word();
+
+       if (!handle_setup(&setup))
+               return 0;
+       if (!(setup.bmRequestType & 0x80) && eps[0].state == EP_IDLE)
+               usb_send(&eps[0], NULL, 0, NULL, NULL);
+       return 1;
+}
+
+
+static bool ep_rx(struct ep_descr *ep)
+{
+       uint8_t size;
+
+       size = UEBCLX;
+       if (size > ep->end-ep->buf)
+               return 0;
+       while (size--)
+               *ep->buf++ = UEDATX;
+       if (ep->buf == ep->end) {
+               ep->state = EP_IDLE;
+               if (ep->callback)
+                       ep->callback(ep->user);
+//             if (ep == &eps[0])
+                       usb_send(ep, NULL, 0, NULL, NULL);
+       }
+       return 1;
+}
+
+
+static void ep_tx(struct ep_descr *ep)
+{
+       uint8_t size = ep->end-ep->buf;
+       uint8_t left;
+
+       if (size > ep->size)
+               size = ep->size;
+       for (left = size; left; left--)
+               UEDATX = *ep->buf++;
+       if (size == ep->size)
+               return;
+       ep->state = EP_IDLE;
+}
+
+
+static void handle_ep(int n)
+{
+       struct ep_descr *ep = eps+n;
+       uint8_t mask;
+
+       UENUM = n;
+       if (UEINTX & (1 << RXSTPI)) {
+               /* @@@ EP_RX. EP_TX: cancel */
+               ep->state = EP_IDLE;
+               if (!ep_setup())
+                       goto stall;
+               UEINTX = ~(1 << RXSTPI);
+       }
+       if (UEINTX & (1 << RXOUTI)) {
+               /* @@ EP_TX: cancel */
+               if (ep->state != EP_RX)
+                       goto stall;
+               if (!ep_rx(ep))
+                       goto stall;
+               /* @@@ gcc 4.5.2 wants this cast */
+               UEINTX = (uint8_t) ~(1 << RXOUTI | 1 << FIFOCON);
+       }
+       if (UEINTX & (1 << STALLEDI)) {
+               ep->state = EP_IDLE;
+               UEINTX = ~(1 << STALLEDI);
+       }
+       if (UEINTX & (1 << TXINI)) {
+               /* @@ EP_RX: cancel (?) */
+               if (ep->state == EP_TX) {
+                       ep_tx(ep);
+                       mask = 1 << TXINI;
+                       if (n)
+                               mask |= 1 << FIFOCON;
+                       UEINTX = ~mask;
+                       if (ep->state == EP_IDLE && ep->callback)
+                               ep->callback(ep->user);
+               } else {
+                       UEIENX &= ~(1 << TXINE);
+               }
+       }
+       return;
+
+stall:
+       UEINTX = ~(1 << RXSTPI | 1 << RXOUTI | 1 << STALLEDI);
+       ep->state = EP_IDLE;
+       UECONX |= 1 << STALLRQ;
+}
+
+
+void ep_init(void)
+{
+       UENUM = 0;
+       UECONX = (1 << RSTDT) | (1 << EPEN);    /* enable */
+       UECFG0X = 0;    /* control, direction is ignored */
+       UECFG1X = 3 << EPSIZE0; /* 64 bytes */
+       UECFG1X |= 1 << ALLOC;
+
+       while (!(UESTA0X & (1 << CFGOK)));
+
+       UEIENX =
+           (1 << RXSTPE) | (1 << RXOUTE) | (1 << STALLEDE) | (1 << TXINE);
+
+       eps[0].state = EP_IDLE;
+       eps[0].size = 64;
+
+#ifndef BOOT_LOADER
+
+       UENUM = 1;
+       UECONX = (1 << RSTDT) | (1 << EPEN);    /* enable */
+       UECFG0X = (1 << EPTYPE1) | (1 << EPDIR); /* bulk IN */
+       UECFG1X = 3 << EPSIZE0; /* 64 bytes */
+       UECFG1X |= 1 << ALLOC;
+
+       while (!(UESTA0X & (1 << CFGOK)));
+
+       UEIENX = (1 << STALLEDE) | (1 << TXINE);
+
+       eps[1].state = EP_IDLE;
+       eps[1].size = 64;
+
+#endif
+}
+
+
+ISR(USB_GEN_vect)
+{
+       uint8_t flags;
+
+       flags = UDINT;
+       if (flags & (1 << EORSTI)) {
+               if (user_reset)
+                       user_reset();
+               ep_init();
+               UDINT = ~(1 << EORSTI);
+       }
+}
+
+
+ISR(USB_COM_vect)
+{
+       uint8_t flags, i;
+
+       flags = UEINT;
+       for (i = 0; i != NUM_EPS; i++)
+               if (flags & (1 << i))
+                       handle_ep(i);
+}
+
+
+void usb_reset(void)
+{
+       UDCON |= 1 << DETACH;   /* detach the pull-up */
+       _delay_ms(1);
+}
diff --git a/atusb/usb/dfu.c b/atusb/usb/dfu.c
new file mode 100644 (file)
index 0000000..c84a28d
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * boot/dfu.c - DFU protocol engine
+ *
+ * Written 2008-2011, 2013-2015 by Werner Almesberger
+ * Copyright 2008-2011, 2013-2015 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+/*
+ * http://www.usb.org/developers/devclass_docs/DFU_1.1.pdf
+ */
+
+/*
+ * A few, erm, shortcuts:
+ *
+ * - we don't bother with the app* states since DFU is all this firmware does
+ * - after DFU_DNLOAD, we just block until things are written, so we never
+ *   enter dfuDNLOAD_SYNC or dfuDNBUSY
+ * - no dfuMANIFEST_SYNC, dfuMANIFEST, or dfuMANIFEST_WAIT_RESET
+ * - to keep our buffers small, we only accept EP0-sized blocks
+ */
+
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "usb.h"
+#include "dfu.h"
+
+#include "board.h"
+
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#define debug(...)
+#define error(...)
+
+
+#ifndef DFU_ALT_SETTINGS
+#define        DFU_ALT_SETTINGS        1
+#endif
+
+#ifndef DFU_ALT_NAME_0_IDX
+#define        DFU_ALT_NAME_0_IDX      0
+#endif
+
+#ifndef DFU_ALT_NAME_1_IDX
+#define        DFU_ALT_NAME_1_IDX      0
+#endif
+
+#ifndef DFU_ALT_NAME_2_IDX
+#define        DFU_ALT_NAME_2_IDX      0
+#endif
+
+
+const uint8_t device_descriptor[] = {
+       18,                     /* bLength */
+       USB_DT_DEVICE,          /* bDescriptorType */
+       LE(0x100),              /* bcdUSB */
+       USB_CLASS_APP_SPEC,     /* bDeviceClass */
+       0x00,                   /* bDeviceSubClass (per interface) */
+       0x00,                   /* bDeviceProtocol (per interface) */
+       EP0_SIZE,               /* bMaxPacketSize */
+       LE(DFU_USB_VENDOR),     /* idVendor */
+       LE(DFU_USB_PRODUCT),    /* idProduct */
+       LE(0x0001),             /* bcdDevice */
+       0,                      /* iManufacturer */
+       0,                      /* iProduct */
+#ifdef HAS_BOARD_SERNUM
+       1,                      /* iSerialNumber */
+#else
+       0,                      /* iSerialNumber */
+#endif
+       1                       /* bNumConfigurations */
+};
+
+
+const uint8_t config_descriptor[] = {
+       9,                      /* bLength */
+       USB_DT_CONFIG,          /* bDescriptorType */
+       LE(9+9*DFU_ALT_SETTINGS), /* wTotalLength */
+       1,                      /* bNumInterfaces */
+       1,                      /* bConfigurationValue (> 0 !) */
+       0,                      /* iConfiguration */
+//     USB_ATTR_SELF_POWERED | USB_ATTR_BUS_POWERED,
+       USB_ATTR_BUS_POWERED,   /* bmAttributes */
+       ((BOARD_MAX_mA)+1)/2,   /* bMaxPower */
+
+       /* Interface #0 */
+
+       DFU_ITF_DESCR(0, 0, dfu_proto_dfu, DFU_ALT_NAME_0_IDX)
+#if DFU_ALT_SETTINGS > 1
+       DFU_ITF_DESCR(0, 1, dfu_proto_dfu, DFU_ALT_NAME_1_IDX)
+#endif
+#if DFU_ALT_SETTINGS > 2
+       DFU_ITF_DESCR(0, 2, dfu_proto_dfu, DFU_ALT_NAME_2_IDX)
+#endif
+};
+
+
+static uint16_t next_block = 0;
+static bool did_download;
+
+
+static uint8_t buf[EP0_SIZE];
+
+
+static void block_write(void *user)
+{
+       uint16_t *size = user;
+
+       dfu_flash_ops->write(buf, *size);
+}
+
+
+static bool block_receive(uint16_t length)
+{
+       static uint16_t size;
+
+       if (!dfu_flash_ops->can_write(length)) {
+               dfu.state = dfuERROR;   
+               dfu.status = errADDRESS;
+               return 0;
+       }
+       if (length > EP0_SIZE) {
+               dfu.state = dfuERROR;   
+               dfu.status = errUNKNOWN;
+               return 0;
+       }
+       size = length;
+       usb_recv(&eps[0], buf, size, block_write, &size);
+       return 1;
+}
+
+
+static bool block_transmit(uint16_t length)
+{
+       uint16_t got;
+
+       if (length > EP0_SIZE) {
+               dfu.state = dfuERROR;   
+               dfu.status = errUNKNOWN;
+               return 1;
+       }
+       got = dfu_flash_ops->read(buf, length);
+       if (got < length) {
+               length = got;
+               dfu.state = dfuIDLE;
+       }
+       usb_send(&eps[0], buf, length, NULL, NULL);
+       return 1;
+}
+
+
+static bool my_setup(const struct setup_request *setup)
+{
+       bool ok;
+
+       switch (setup->bmRequestType | setup->bRequest << 8) {
+       case DFU_TO_DEV(DFU_DETACH):
+               debug("DFU_DETACH\n");
+               /*
+                * The DFU spec says thay this is sent in protocol 1 only.
+                * However, dfu-util also sends it to get out of DFU mode,
+                * so we just don't make a fuss and ignore it.
+                */
+               return 1;
+       case DFU_TO_DEV(DFU_DNLOAD):
+               debug("DFU_DNLOAD\n");
+               if (dfu.state == dfuIDLE) {
+                       next_block = setup->wValue;
+                       dfu_flash_ops->start();
+               }
+               else if (dfu.state != dfuDNLOAD_IDLE) {
+                       error("bad state\n");
+                       return 0;
+               }
+               if (dfu.state != dfuIDLE && setup->wValue == next_block-1) {
+                       debug("retransmisson\n");
+                       return 1;
+               }
+               if (setup->wValue != next_block) {
+                       debug("bad block (%d vs. %d)\n",
+                           setup->wValue, next_block);
+                       dfu.state = dfuERROR;
+                       dfu.status = errUNKNOWN;
+                       return 1;
+               }
+               if (!setup->wLength) {
+                       debug("DONE\n");
+                       dfu_flash_ops->end_write();
+                       dfu.state = dfuIDLE;
+                       did_download = 1;
+                       return 1;
+               }
+               ok = block_receive(setup->wLength);
+               next_block++;
+               dfu.state = dfuDNLOAD_IDLE;
+               return ok;
+       case DFU_FROM_DEV(DFU_UPLOAD):
+               debug("DFU_UPLOAD\n");
+               if (dfu.state == dfuIDLE) {
+                       next_block = setup->wValue;
+                       dfu_flash_ops->start();
+               }
+               else if (dfu.state != dfuUPLOAD_IDLE)
+                       return 0;
+               if (dfu.state != dfuIDLE && setup->wValue == next_block-1) {
+                       debug("retransmisson\n");
+                       /* @@@ try harder */
+                       dfu.state = dfuERROR;
+                       dfu.status = errUNKNOWN;
+                       return 1;
+               }
+               if (setup->wValue != next_block) {
+                       debug("bad block (%d vs. %d)\n",
+                           setup->wValue, next_block);
+                       dfu.state = dfuERROR;
+                       dfu.status = errUNKNOWN;
+                       return 1;
+               }
+               ok = block_transmit(setup->wLength);
+               next_block++;
+               dfu.state = dfuUPLOAD_IDLE;
+               return ok;
+       case DFU_TO_DEV(DFU_ABORT):
+               debug("DFU_ABORT\n");
+               dfu.state = dfuIDLE;
+               dfu.status = OK;
+               return 1;
+       default:
+               return dfu_setup_common(setup);
+       }
+}
+
+
+static void my_reset(void)
+{
+#if 0
+       /* @@@ not nice -- think about where this should go */
+       extern void run_payload(void);
+
+       if (did_download)
+               run_payload();
+#endif
+}
+
+
+void dfu_init(void)
+{
+       user_setup = my_setup;
+       user_get_descriptor = dfu_my_descr;
+       user_reset = my_reset;
+}
diff --git a/atusb/usb/dfu.h b/atusb/usb/dfu.h
new file mode 100644 (file)
index 0000000..bc35bbc
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * boot/dfu.h - DFU protocol constants and data structures
+ *
+ * Written 2008, 2011, 2013-2015 by Werner Almesberger
+ * Copyright 2008, 2011, 2013-2015 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+
+#ifndef DFU_H
+#define DFU_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "usb.h"
+
+
+enum dfu_request {
+       DFU_DETACH,
+       DFU_DNLOAD,
+       DFU_UPLOAD,
+       DFU_GETSTATUS,
+       DFU_CLRSTATUS,
+       DFU_GETSTATE,
+       DFU_ABORT,
+};
+
+
+enum dfu_status {
+       OK,
+       errTARGET,
+       errFILE,
+       errWRITE,
+       errERASE,
+       errCHECK_ERASED,
+       errPROG,
+       errVERIFY,
+       errADDRESS,
+       errNOTDONE,
+       errFIRMWARE,
+       errVENDOR,
+       errUSBR,
+       errPOR,
+       errUNKNOWN,
+       errSTALLEDPKT,
+};
+
+
+enum dfu_state {
+       appIDLE,
+       appDETACH,
+       dfuIDLE,
+       dfuDNLOAD_SYNC,
+       dfuDNBUSY,
+       dfuDNLOAD_IDLE,
+       dfuMANIFEST_SYNC,
+       dfuMANIFEST,
+       dfuMANIFEST_WAIT_RESET,
+       dfuUPLOAD_IDLE,
+       dfuERROR
+};
+
+enum dfu_itf_proto {
+       dfu_proto_runtime       = 1,    /* Runtime protocol */
+       dfu_proto_dfu           = 2,    /* DFU mode protocol */
+};
+
+
+#define DFU_DT_FUNCTIONAL      0x21    /* DFU FUNCTIONAL descriptor type */
+
+
+#define        DFU_TO_DEV(req)         (0x21 | (req) << 8)
+#define        DFU_FROM_DEV(req)       (0xa1 | (req) << 8)
+
+
+struct dfu {
+       uint8_t status;         /* bStatus */
+       uint8_t toL, toM, toH;  /* bwPollTimeout */
+       uint8_t state;          /* bState */
+       uint8_t iString;
+};
+
+
+#define        DFU_ITF_DESCR(itf, alt, proto, idx)                                  \
+       9,                      /* bLength */                                \
+       USB_DT_INTERFACE,       /* bDescriptorType */                        \
+       (itf),                  /* bInterfaceNumber */                       \
+       (alt),                  /* bAlternateSetting */                      \
+       0,                      /* bNumEndpoints */                          \
+       0xfe,                   /* bInterfaceClass (application specific) */ \
+       0x01,                   /* bInterfaceSubClass (device fw upgrade) */ \
+       (proto),                /* bInterfaceProtocol (dfu_proto_*) */       \
+       (idx),                  /* iInterface */
+
+
+struct dfu_flash_ops {
+       void (*start)(void);
+       bool (*can_write)(uint16_t size);
+       void (*write)(const uint8_t *buf, uint16_t size);
+       void (*end_write)(void);
+       uint16_t (*read)(uint8_t *buf, uint16_t size);
+};
+
+extern struct dfu dfu;
+extern const struct dfu_flash_ops *dfu_flash_ops;
+
+
+bool dfu_setup_common(const struct setup_request *setup);
+bool dfu_my_descr(uint8_t type, uint8_t index, const uint8_t **reply,
+    uint8_t *size);
+
+void dfu_init(void);
+
+#endif /* !DFU_H */
diff --git a/atusb/usb/dfu_common.c b/atusb/usb/dfu_common.c
new file mode 100644 (file)
index 0000000..9b6feef
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * boot/dfu_common.c - DFU protocol engine parts common to App/DFU
+ *
+ * Written 2008-2011, 2013-2014 by Werner Almesberger
+ * Copyright 2008-2011, 2013-2014 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+/*
+ * http://www.usb.org/developers/devclass_docs/DFU_1.1.pdf
+ */
+
+/*
+ * A few, erm, shortcuts:
+ *
+ * - we don't bother with the app* states since DFU is all this firmware does
+ * - after DFU_DNLOAD, we just block until things are written, so we never
+ *   enter dfuDNLOAD_SYNC or dfuDNBUSY
+ * - no dfuMANIFEST_SYNC, dfuMANIFEST, or dfuMANIFEST_WAIT_RESET
+ * - to keep our buffers small, we only accept EP0-sized blocks
+ */
+
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "usb.h"
+#include "dfu.h"
+
+#include "board.h"
+#include "../sernum.h"
+
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#define debug(...)
+#define error(...)
+
+
+static const uint8_t functional_descriptor[] = {
+       9,                      /* bLength */
+       DFU_DT_FUNCTIONAL,      /* bDescriptorType */
+       0xf,                    /* bmAttributes (claim omnipotence :-) */
+       LE(0xffff),             /* wDetachTimeOut (we're very patient) */
+       LE(EP0_SIZE),           /* wTransferSize */
+       LE(0x101),              /* bcdDFUVersion */
+};
+
+
+/*
+ * The worst-case activity would be flashing a one page and erasing another
+ * one, would should take less than 10 ms. A 100 ms timeout ought to be plenty.
+ */
+
+struct dfu dfu = {
+       OK,                     /* bStatus */
+       LE(100), 0,             /* bwPollTimeout, 100 ms */
+       dfuIDLE,                /* bState */
+       0,                      /* iString */
+};
+
+
+bool dfu_setup_common(const struct setup_request *setup)
+{
+       switch (setup->bmRequestType | setup->bRequest << 8) {
+       case DFU_FROM_DEV(DFU_GETSTATUS):
+               debug("DFU_GETSTATUS\n");
+               usb_send(&eps[0], (uint8_t *) &dfu, sizeof(dfu), NULL, NULL);
+               return 1;
+       case DFU_TO_DEV(DFU_CLRSTATUS):
+               debug("DFU_CLRSTATUS\n");
+               dfu.state = dfuIDLE;
+               dfu.status = OK;
+               return 1;
+       case DFU_FROM_DEV(DFU_GETSTATE):
+               debug("DFU_GETSTATE\n");
+               usb_send(&eps[0], &dfu.state, 1, NULL, NULL);
+               return 1;
+       default:
+               error("DFU rt %x, rq%x ?\n",
+                   setup->bmRequestType, setup->bRequest);
+               return 0;
+       }
+}
+
+
+bool dfu_my_descr(uint8_t type, uint8_t index, const uint8_t **reply,
+    uint8_t *size)
+{
+       if (type != DFU_DT_FUNCTIONAL)
+               return sernum_get_descr(type, index, reply, size);
+       *reply = functional_descriptor;
+       *size = sizeof(functional_descriptor);
+       return 1;
+}
diff --git a/atusb/usb/usb.c b/atusb/usb/usb.c
new file mode 100644 (file)
index 0000000..543d8c2
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * fw/usb/usb.c - USB hardware setup and standard device requests
+ *
+ * Written 2008-2011, 2013, 2015 by Werner Almesberger
+ * Copyright 2008-2011, 2013, 2015 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+/*
+ * Known issues:
+ * - no suspend/resume
+ * - should support EP clearing and stalling
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "usb.h"
+#include "board.h"
+
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#if 1
+extern void panic(void);
+#define BUG_ON(cond)   do { if (cond) panic(); } while (0)
+#else
+#define BUG_ON(cond)
+#endif
+
+bool (*user_setup)(const struct setup_request *setup);
+void (*user_set_interface)(int nth);
+bool (*user_get_descriptor)(uint8_t type, uint8_t index,
+    const uint8_t **reply, uint8_t *size);
+void (*user_reset)(void);
+
+
+void usb_io(struct ep_descr *ep, enum ep_state state, uint8_t *buf,
+    uint8_t size, void (*callback)(void *user), void *user)
+{
+       BUG_ON(ep->state);
+       ep->state = state;
+       ep->buf = buf;
+       ep->end = buf+size;
+       ep->callback = callback;
+       ep->user = user;
+       usb_ep_change(ep);
+}
+
+
+static bool get_descriptor(uint8_t type, uint8_t index, uint16_t length)
+{
+       const uint8_t *reply;
+       uint8_t size;
+
+       switch (type) {
+       case USB_DT_DEVICE:
+               reply = device_descriptor;
+               size = reply[0];
+               break;
+       case USB_DT_CONFIG:
+               if (index)
+                       return 0;
+               reply = config_descriptor;
+               size = reply[2];
+               break;
+       default:
+               if (!user_get_descriptor)
+                       return 0;
+               if (!user_get_descriptor(type, index, &reply, &size))
+                       return 0;
+       }
+       if (length < size)
+               size = length;
+       usb_send(&eps[0], reply, size, NULL, NULL);
+       return 1;
+}
+
+
+bool handle_setup(const struct setup_request *setup)
+{
+       switch (setup->bmRequestType | setup->bRequest << 8) {
+
+       /*
+        * Device request
+        *
+        * See http://www.beyondlogic.org/usbnutshell/usb6.htm
+        */
+
+       case FROM_DEVICE(GET_STATUS):
+               if (setup->wLength != 2)
+                       return 0;
+               usb_send(&eps[0], "\000", 2, NULL, NULL);
+               break;
+       case TO_DEVICE(CLEAR_FEATURE):
+               break;
+       case TO_DEVICE(SET_FEATURE):
+               return 0;
+       case TO_DEVICE(SET_ADDRESS):
+               set_addr(setup->wValue);
+               break;
+       case FROM_DEVICE(GET_DESCRIPTOR):
+       case FROM_INTERFACE(GET_DESCRIPTOR):
+               if (!get_descriptor(setup->wValue >> 8, setup->wValue,
+                   setup->wLength))
+                       return 0;
+               break;
+       case TO_DEVICE(SET_DESCRIPTOR):
+               return 0;
+       case FROM_DEVICE(GET_CONFIGURATION):
+               usb_send(&eps[0], "", 1, NULL, NULL);
+               break;
+       case TO_DEVICE(SET_CONFIGURATION):
+               if (setup->wValue != config_descriptor[5])
+                       return 0;
+               break;
+
+       /*
+        * Interface request
+        */
+
+       case FROM_INTERFACE(GET_STATUS):
+               return 0;
+       case TO_INTERFACE(CLEAR_FEATURE):
+               return 0;
+       case TO_INTERFACE(SET_FEATURE):
+               return 0;
+       case FROM_INTERFACE(GET_INTERFACE):
+               return 0;
+       case TO_INTERFACE(SET_INTERFACE):
+               {
+                       const uint8_t *interface_descriptor =
+                           config_descriptor+9;
+                       const uint8_t *p;
+                       int i;
+
+                       i = 0;
+                       for (p = interface_descriptor;
+                           p != config_descriptor+config_descriptor[2];
+                           p += p[0]) {
+                               if (p[1] != USB_DT_INTERFACE)
+                                       continue;
+                               if (p[2] == setup->wIndex &&
+                                   p[3] == setup->wValue) {
+                                       if (user_set_interface)
+                                               user_set_interface(i);
+                                       return 1;
+                               }
+                               i++;
+                       }
+                       return 0;
+               }
+               break;
+
+       /*
+        * Endpoint request
+        */
+
+       case FROM_ENDPOINT(GET_STATUS):
+               return 0;
+       case TO_ENDPOINT(CLEAR_FEATURE):
+               return 0;
+       case TO_ENDPOINT(SET_FEATURE):
+               return 0;
+       case FROM_ENDPOINT(SYNCH_FRAME):
+               return 0;
+
+       default:
+               if (user_setup)
+                       return user_setup(setup);
+               return 0;
+       }
+
+       return 1;
+}
diff --git a/atusb/usb/usb.h b/atusb/usb/usb.h
new file mode 100644 (file)
index 0000000..cb40f9e
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * fw/usb//usb.h - USB hardware setup and standard device requests
+ *
+ * Written 2008, 2009, 2011, 2013, 2015 by Werner Almesberger
+ * Copyright 2008, 2009, 2011, 2013, 2015 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+
+#ifndef USB_H
+#define USB_H
+
+
+#include <stdbool.h>
+#include <stdint.h>
+
+
+/*
+ * Packet identifier types
+ */
+
+#define        PID_OUT         0x1
+#define        PID_IN          0x9
+#define        PID_SOF         0x5
+#define        PID_SETUP       0xd
+#define        PID_DATA0       0x3
+#define        PID_DATA1       0xb
+#define        PID_ACK         0x2
+#define        PID_NAK         0xa
+#define        PID_STALL       0xe
+
+/*
+ * Descriptor types
+ *
+ * Reuse libusb naming scheme (/usr/include/usb.h)
+ */
+
+#define        USB_DT_DEVICE           1
+#define        USB_DT_CONFIG           2
+#define        USB_DT_STRING           3
+#define        USB_DT_INTERFACE        4
+#define        USB_DT_ENDPOINT         5
+
+/*
+ * Device classes
+ *
+ * Reuse libusb naming scheme (/usr/include/usb.h)
+ */
+
+#define USB_CLASS_PER_INTERFACE        0
+#define        USB_CLASS_COMM          2
+#define        USB_CLASS_HID           3
+#define        USB_CLASS_MASS_STORAGE  8
+#define        USB_CLASS_HUB           9
+#define        USB_CLASS_DATA          10
+#define        USB_CLASS_APP_SPEC      0xfe
+#define USB_CLASS_VENDOR_SPEC  0xff
+
+/*
+ * Configuration attributes
+ */
+
+#define        USB_ATTR_BUS_POWERED    0x80
+#define        USB_ATTR_SELF_POWERED   0x40
+#define        USB_ATTR_REMOTE_WAKEUP  0x20
+
+/*
+ * Endpoint type
+ */
+
+#define        USB_ENDPOINT_TYPE_CONTROL       0
+#define        USB_ENDPOINT_TYPE_ISOCHRONOUS   1
+#define        USB_ENDPOINT_TYPE_BULK          2
+#define        USB_ENDPOINT_TYPE_INTERRUPT     3
+
+/*
+ * Setup request types
+ */
+
+#define        TO_DEVICE(req)          (0x00 | (req) << 8)
+#define        FROM_DEVICE(req)        (0x80 | (req) << 8)
+#define        TO_INTERFACE(req)       (0x01 | (req) << 8)
+#define        FROM_INTERFACE(req)     (0x81 | (req) << 8)
+#define        TO_ENDPOINT(req)        (0x02 | (req) << 8)
+#define        FROM_ENDPOINT(req)      (0x82 | (req) << 8)
+
+/*
+ * Setup requests
+ */
+
+#define        GET_STATUS              0x00
+#define        CLEAR_FEATURE           0x01
+#define        SET_FEATURE             0x03
+#define        SET_ADDRESS             0x05
+#define        GET_DESCRIPTOR          0x06
+#define        SET_DESCRIPTOR          0x07
+#define        GET_CONFIGURATION       0x08
+#define        SET_CONFIGURATION       0x09
+#define        GET_INTERFACE           0x0a
+#define        SET_INTERFACE           0x0b
+#define        SYNCH_FRAME             0x0c
+
+/*
+ * USB Language ID codes
+ *
+ * http://www.usb.org/developers/docs/USB_LANGIDs.pdf
+ */
+
+#define        USB_LANGID_ENGLISH_US   0x409
+
+
+/*
+ * Odd. sdcc seems to think "x" assumes the size of the destination, i.e.,
+ * uint8_t. Hence the cast.
+ */
+
+#define LE(x) ((uint16_t) (x) & 0xff), ((uint16_t) (x) >> 8)
+
+#define LO(x) (((uint8_t *) &(x))[0])
+#define HI(x) (((uint8_t *) &(x))[1])
+
+
+#ifdef LOW_SPEED
+#define        EP0_SIZE        8
+#else
+#define        EP0_SIZE        64
+#endif
+
+#define        EP1_SIZE        64      /* simplify */
+
+
+enum ep_state {
+       EP_IDLE,
+       EP_RX,
+       EP_TX,
+       EP_STALL,
+};
+
+struct ep_descr {
+       enum ep_state state;
+       uint8_t *buf;
+       uint8_t *end;
+       uint8_t size;
+       void (*callback)(void *user);
+       void *user;
+};
+
+struct setup_request {
+       uint8_t bmRequestType;
+       uint8_t bRequest;
+       uint16_t wValue;
+       uint16_t wIndex;
+       uint16_t wLength;
+};
+
+
+extern const uint8_t device_descriptor[];
+extern const uint8_t config_descriptor[];
+extern struct ep_descr eps[];
+
+extern bool (*user_setup)(const struct setup_request *setup);
+extern void (*user_set_interface)(int nth);
+extern bool (*user_get_descriptor)(uint8_t type, uint8_t index,
+    const uint8_t **reply, uint8_t *size);
+extern void (*user_reset)(void);
+
+
+#define        usb_left(ep) ((ep)->end-(ep)->buf)
+#define usb_send(ep, buf, size, callback, user) \
+       usb_io(ep, EP_TX, (void *) buf, size, callback, user)
+#define usb_recv(ep, buf, size, callback, user) \
+       usb_io(ep, EP_RX, buf, size, callback, user)
+
+void usb_io(struct ep_descr *ep, enum ep_state state, uint8_t *buf,
+    uint8_t size, void (*callback)(void *user), void *user);
+
+bool handle_setup(const struct setup_request *setup);
+void set_addr(uint8_t addr);
+void usb_ep_change(struct ep_descr *ep);
+void usb_reset(void);
+void usb_init(void);
+
+void ep_init(void);
+
+#endif /* !USB_H */
diff --git a/atusb/version.h b/atusb/version.h
new file mode 100644 (file)
index 0000000..8fd6a2c
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * fw/version.h - Automatically generated version string
+ *
+ * Written 2008, 2011 by Werner Almesberger
+ * Copyright 2008, 2011 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+
+#ifndef VERSION_H
+#define VERSION_H
+
+#include <stdint.h>
+
+
+extern const char *build_date;
+extern const uint16_t build_number;
+
+#endif /* !VERSION_H */