Commits

Trammell Hudson  committed cc14e8e

HID cards work!

  • Participants
  • Parent commits f82938b

Comments (0)

Files changed (3)

File Makefile.rfid

+# Hey Emacs, this is a -*- makefile -*-
+
+# AVR-GCC Makefile template, derived from the WinAVR template (which
+# is public domain), believed to be neutral to any flavor of "make"
+# (GNU make, BSD make, SysV make)
+
+
+MCU = attiny85
+FORMAT = ihex
+TARGET = avrfid
+SRC = avrfid.S
+ASRC = 
+OPT = s
+
+# Name of this Makefile (used for "make depend").
+MAKEFILE = Makefile
+
+# Debugging format.
+# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2.
+# AVR (extended) COFF requires stabs, plus an avr-objcopy run.
+DEBUG = stabs
+
+# Compiler flag to set the C Standard level.
+# c89   - "ANSI" C
+# gnu89 - c89 plus GCC extensions
+# c99   - ISO C99 standard (not yet fully implemented)
+# gnu99 - c99 plus GCC extensions
+CSTANDARD = -std=gnu99
+
+# Place -D or -U options here
+CDEFS =
+#CDEFS += -DREMOVE_FLASH_BYTE_SUPPORT
+#CDEFS += -DREMOVE_EEPROM_BYTE_SUPPORT
+#CDEFS += -DREMOVE_FUSE_AND_LOCK_BIT_SUPPORT
+#CDEFS += -DREMOVE_AVRPROG_SUPPORT
+#CDEFS += -DREMOVE_BLOCK_SUPPORT
+
+# Place -I options here
+CINCS =
+
+
+CDEBUG = -g$(DEBUG)
+CWARN = -Wall -Wstrict-prototypes
+CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
+#CEXTRA = -Wa,-adhlns=$(<:.c=.lst)
+CFLAGS = $(CDEBUG) $(CDEFS) $(CINCS) -O$(OPT) $(CWARN) $(CSTANDARD) $(CTUNING) $(CEXTRA)
+
+
+#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs 
+
+
+#Additional libraries.
+
+# Minimalistic printf version
+PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min
+
+# Floating point printf version (requires MATH_LIB = -lm below)
+PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt
+
+PRINTF_LIB = 
+
+# Minimalistic scanf version
+SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min
+
+# Floating point + %[ scanf version (requires MATH_LIB = -lm below)
+SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt
+
+SCANF_LIB = 
+
+MATH_LIB = -lm
+
+# External memory options
+
+# 64 KB of external RAM, starting after internal RAM (ATmega128!),
+# used for variables (.data/.bss) and heap (malloc()).
+#EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff
+
+# 64 KB of external RAM, starting after internal RAM (ATmega128!),
+# only used for heap (malloc()).
+#EXTMEMOPTS = -Wl,--defsym=__heap_start=0x801100,--defsym=__heap_end=0x80ffff
+
+EXTMEMOPTS =
+
+#LDMAP = $(LDFLAGS) -Wl,-Map=$(TARGET).map,--cref
+LDFLAGS = $(EXTMEMOPTS) $(LDMAP) $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB)
+
+
+# Programming support using avrdude. Settings and variables.
+
+AVRDUDE_PROGRAMMER = avrispmkII
+AVRDUDE_PORT = usb
+
+AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex
+#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep
+
+
+# Uncomment the following if you want avrdude's erase cycle counter.
+# Note that this counter needs to be initialized first using -Yn,
+# see avrdude manual.
+#AVRDUDE_ERASE_COUNTER = -y
+
+# Uncomment the following if you do /not/ wish a verification to be
+# performed after programming the device.
+#AVRDUDE_NO_VERIFY = -V
+
+# Increase verbosity level.  Please use this when submitting bug
+# reports about avrdude. See <http://savannah.nongnu.org/projects/avrdude> 
+# to submit bug reports.
+#AVRDUDE_VERBOSE = -v -v
+
+MY_CLOCK_IS_SLOW = -i 50
+
+AVRDUDE_BASIC = -p $(MCU) -c $(AVRDUDE_PROGRAMMER)
+AVRDUDE_FLAGS = \
+	-P $(AVRDUDE_PORT) \
+	-C $(AVR_PATH)/etc/avrdude.conf \
+	$(MY_CLOCK_IS_SLOW) \
+	$(AVRDUDE_BASIC) \
+	$(AVRDUDE_NO_VERIFY) \
+	$(AVRDUDE_VERBOSE) \
+	$(AVRDUDE_ERASE_COUNTER) \
+ 
+
+AVR_PATH = /Applications/Arduino.app/Contents//Resources/Java/hardware/tools/avr
+CC = $(AVR_PATH)/bin/avr-gcc
+OBJCOPY = $(AVR_PATH)/bin/avr-objcopy
+OBJDUMP = $(AVR_PATH)/bin/avr-objdump
+SIZE = $(AVR_PATH)/bin/avr-size
+NM = $(AVR_PATH)/bin/avr-nm
+AVRDUDE = $(AVR_PATH)/bin/avrdude
+
+REMOVE = rm -f
+MV = mv -f
+
+# Define all object files.
+OBJ = $(SRC:.c=.o) $(ASRC:.S=.o) 
+
+# Define all listing files.
+LST = $(ASRC:.S=.lst) $(SRC:.c=.lst)
+
+# Combine all necessary flags and optional flags.
+# Add target processor to flags.
+ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS)
+ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)
+
+
+# Default target.
+all: build
+
+build: elf hex eep
+
+elf: $(TARGET).elf
+hex: $(TARGET).hex
+eep: $(TARGET).eep
+lss: $(TARGET).lss 
+sym: $(TARGET).sym
+
+
+# Program the device.  
+program: $(TARGET).hex $(TARGET).eep
+	$(AVRDUDE) \
+		$(AVRDUDE_FLAGS) \
+		$(AVRDUDE_WRITE_FLASH) \
+		$(AVRDUDE_WRITE_EEPROM) \
+
+fuses:
+	$(AVRDUDE) \
+		$(AVRDUDE_FLAGS) \
+		-U lfuse:w:0xC0:m \
+
+
+
+
+
+# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
+COFFCONVERT=$(OBJCOPY) --debugging \
+--change-section-address .data-0x800000 \
+--change-section-address .bss-0x800000 \
+--change-section-address .noinit-0x800000 \
+--change-section-address .eeprom-0x810000 
+
+
+coff: $(TARGET).elf
+	$(COFFCONVERT) -O coff-avr $(TARGET).elf $(TARGET).cof
+
+
+extcoff: $(TARGET).elf
+	$(COFFCONVERT) -O coff-ext-avr $(TARGET).elf $(TARGET).cof
+
+
+.SUFFIXES: .elf .hex .eep .lss .sym
+
+.elf.hex:
+	$(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@
+
+.elf.eep:
+	-$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
+	--change-section-lma .eeprom=0 -O $(FORMAT) $< $@
+
+# Create extended listing file from ELF output file.
+.elf.lss:
+	$(OBJDUMP) -h -S $< > $@
+
+# Create a symbol table from ELF output file.
+.elf.sym:
+	$(NM) -n $< > $@
+
+
+
+# Link: create ELF output file from object files.
+$(TARGET).elf: $(OBJ)
+	$(CC) $(ALL_CFLAGS) $(OBJ) --output $@ $(LDFLAGS) -nostdlib
+
+
+# Compile: create object files from C source files.
+.c.o:
+	$(CC) -c $(ALL_CFLAGS) $< -o $@ 
+
+
+# Compile: create assembler files from C source files.
+.c.s:
+	$(CC) -S $(ALL_CFLAGS) $< -o $@
+
+
+# Assemble: create object files from assembler source files.
+.S.o:
+	$(CC) -c $(ALL_ASFLAGS) $< -o $@
+
+
+
+# Target: clean project.
+clean:
+	$(REMOVE) $(TARGET).hex $(TARGET).eep $(TARGET).cof $(TARGET).elf \
+	$(TARGET).map $(TARGET).sym $(TARGET).lss
+
+depend:
+	if grep '^# DO NOT DELETE' $(MAKEFILE) >/dev/null; \
+	then \
+		sed -e '/^# DO NOT DELETE/,$$d' $(MAKEFILE) > \
+			$(MAKEFILE).$$$$ && \
+		$(MV) $(MAKEFILE).$$$$ $(MAKEFILE); \
+	fi
+	echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' \
+		>> $(MAKEFILE); \
+	$(CC) -M -mmcu=$(MCU) $(CDEFS) $(CINCS) $(SRC) $(ASRC) >> $(MAKEFILE)
+
+.PHONY:	all build elf hex eep lss sym program coff extcoff clean depend
+
+
+/*
+ * Software-only implementation of a passive low-frequency RFID tag,
+ * using an AVR microcontroller.
+ *
+ * Version 1.1, 2010-06-15
+ *
+ * Copyright (c) 2008-2010 Micah Dowty <micah@navi.cx>
+ * See end of file for license terms. (BSD style)
+ * Improved HID modulation contributed by Luke Koops <luke.koops@gmail.com>
+ * HID parity bit support contributed by Cesar Fernandez <cex123@gmail.com>
+ *
+ * Supports EM4102-style tags, and the HID 125 kHz prox card protocol.
+ * The card format and ID number are set below, with #defines.
+ *
+ * Basic schematic:
+ *
+ *              ATtiny85
+ *              +--------------+
+ *            --| RST      Vcc |--
+ *    +- L1 ----| B3/CLKI  SCK |--
+ *    +---------| B4      MISO |--
+ *            --| GND     MOSI |--
+ *              +--------------+
+ *
+ * L1 is about 1 mH. It and the AVR are the only components.
+ * All other pins should be unconnected.
+ *
+ * AVR notes:
+ *
+ *   - Low-voltage parts are better, but I've had success using
+ *     this with the non-extended voltage range parts as well.
+ *
+ *   - Program the fuses for an external clock with no divider.
+ *     On the ATtiny85, this means setting lfuse to 0xC0.
+ *     Note that after you set this fuse, your programmer will
+ *     need to supply a clock on pin 2 for subsequent programming
+ *     operations.
+ *   - The hfuse stays at its default of 0xDF.
+ *
+ * Optional parts:
+ *
+ *   - Power decoupling capacitor, between 0.1 and 10uF.
+ *     Bigger is generally better, as it will increase the
+ *     usable range- but if you use this tag with readers that
+ *     have a pulsed carrier wave, bigger caps may take too long
+ *     to charge.
+ *
+ *   - A load capacitor, in parallel with L1. This will depend
+ *     on your coil. For physically small coils, the internal
+ *     capacitance of the AVR seems to be enough. For larger coils,
+ *     it may be necessary to use a cap here. Experiment to find the
+ *     best value. 
+ *
+ *   - A header, for in-circuit programming. You'll need to expose nearly
+ *     every pin on the chip, since the AVR will also need an external
+ *     clock.
+ *
+ *   - If you want to make an active (powered) tag, you could hook a 3V
+ *     battery up to the Vcc and GND pins on the AVR. To decrease the power
+ *     usage when idle, you may want to hook a large (a couple megohm)
+ *     pull-down resistor to the clock input, to be sure CLKI doesn't float
+ *     when there is no RF field present.
+ *
+ * Theory of operation:
+ *
+ *   Like all passive RFID tags, this circuit is powered by the 125 kHz
+ *   carrier wave emitted by the RFID reader. In our case, the coil is
+ *   just connected to two AVR I/O pins. We're actually powering the AVR
+ *   through its protective clamping diodes, and the power is retained by
+ *   the AVR die's internal capacitance.
+ *
+ *   This is a very weak power source, and the AVR typically gets little
+ *   over a volt of Vcc. As a result, most of the AVR's oscillators won't
+ *   start. We can, however, use the carrier wave itself as a clock as well.
+ *   This also makes the software easy, since the instruction clock is also
+ *   the RF clock. We're already clamping the coil voltage into something
+ *   resembles a square wave, so this makes a good external clock source.
+ *
+ *   To send data back to the reader, passive RFID tags can selectively
+ *   attenuate the reader's carrier wave. Most RFID tags do that with a
+ *   transistor which shorts their coil. We accomplish this by driving the
+ *   coil I/O pins to ground, by toggling the DDRB register. Since the I/O
+ *   drivers on the AVR are weaker than the RF signal, we still get enough
+ *   of a pulse to provide the CLKI input.
+ *
+ *   And that's about all there is to it. The software is quite simple- we
+ *   are mostly just using assembler macros to convert the desired RFID tag
+ *   code into sequences of subroutine calls which output bits. We can't
+ *   get too fancy with the software, since it's only executing at 125 kHz.
+ *
+ */
+ 
+/************ Configuration *****************************************/
+ 
+// Uncomment exactly one format:
+
+//#define FORMAT_IS_EM4102
+#define FORMAT_IS_HID
+
+// For the EM4102: An 8-bit manufacturer ID and 32-bit unique ID.
+
+#define EM4102_MFR_ID		0x12
+#define EM4102_UNIQUE_ID	0x3456789A
+
+/*
+ * For the HID card:
+ *   A 20-bit manufacturer code, 8-bit site code, and 16-bit unique ID, 1-bit odd parity.
+ *
+ * Manufacturer code is fixed. If modified, HID readers do not recognise the tag.
+ * (This may also be a kind of fixed header.) Tested on HID readers with 26-bit wiegand output.
+ */
+	
+#define HID_MFG_CODE        0x01002  // Do not modify
+#define HID_SITE_CODE       42
+#define HID_UNIQUE_ID       23946     // May be written on the back of the card
+
+/************ Common ************************************************/
+
+#ifndef __ASSEMBLER__
+#define __ASSEMBLER__
+#endif
+#include <avr/io.h>
+
+.global main
+
+#define OUT_PINS       _BV(PINB3) | _BV(PINB4)
+
+    .macro	delay cycles
+    .if \cycles > 1
+    rjmp	.+0
+    delay	(\cycles - 2)
+    .elseif \cycles > 0
+    nop
+    delay	(\cycles - 1)
+    .endif
+    .endm
+
+    .macro	manchester bit, count=1
+    .if		\count
+    manchester (\bit >> 1), (\count - 1)
+    .if		\bit & 1
+    baseband_1
+    baseband_0
+    .else
+    baseband_0
+    baseband_1
+    .endif
+    .endif
+    .endm
+
+    .macro	stop_bit
+    baseband_0
+    baseband_1_last
+    .endm
+    
+
+
+/************ HID Implementation *********************************/
+
+/*
+ * This works with the HID 125 kHz prox cards I've tested it with,
+ * but there are undoubtedly other formats used by HID. My cards are
+ * marked with the model number "HID 0004H".
+ *
+ * These cards use both manchester encoding and FSK modulation. The FSK
+ * modulation represents zeroes and ones using 4 and 5 full RF cycles, respectively.
+ * An entire baseband bit lasts 50 RF cycles.
+ *
+ * Each packet begins with a header consisting of the baseband bit pattern "000111".
+ * After that, we have 45 manchester-encoded bits before the packet repeats. The
+ * last bit appears to be a stop bit, always zero. The previous 20 bits encode the
+ * 6-digit unique ID, which is printed on the back of the card. The other 24 bits
+ * have an unknown use. They could be a site code or manufacturing code. In the cards
+ * I've examined, these bits are constant.
+ */
+ 
+#ifdef FORMAT_IS_HID
+
+#define ODD_PARITY(n)  ((( ((n) >> 0 ) ^ ((n) >> 1 ) ^ ((n) >> 2 ) ^ ((n) >> 3 ) ^ \
+                           ((n) >> 4 ) ^ ((n) >> 5 ) ^ ((n) >> 6 ) ^ ((n) >> 7 ) ^ \
+                           ((n) >> 8 ) ^ ((n) >> 9 ) ^ ((n) >> 10) ^ ((n) >> 11) ^ \
+                           ((n) >> 12) ^ ((n) >> 13) ^ ((n) >> 14) ^ ((n) >> 15) ^ \
+                           ((n) >> 16) ^ ((n) >> 17) ^ ((n) >> 18) ^ ((n) >> 19) ^ \
+                           ((n) >> 20) ^ ((n) >> 21) ^ ((n) >> 22) ^ ((n) >> 23) ^ \
+                           ((n) >> 24) ^ ((n) >> 25) ^ ((n) >> 26) ^ ((n) >> 27) ^ \
+                           ((n) >> 28) ^ ((n) >> 29) ^ ((n) >> 30) ^ ((n) >> 31) ) & 1) ^ 1)
+main:
+        eor	r16, r16
+        ldi	r17, OUT_PINS
+loop:
+	rcall	hid_send
+	rjmp	loop
+
+hid_send:
+        /*
+         * Toggle the output modulation, in the specified number
+         * of total clock cycles.
+         */        
+        .macro toggle clocks
+        delay	(\clocks - 2)
+        eor	r16, r17
+        out	_SFR_IO_ADDR(DDRB), r16
+        .endm
+        
+        /*
+         * Emit a 0 at the baseband layer. (Toggle every 4 cycles, for 50 cycles)
+	 * There was an rjmp that got us to the beginning of the loop, so drop
+	 * 2 cycles from the delay if this is the first bit.  That will give the
+	 * appropriate delay before the toggle.
+	 *
+	 * From observing the HID card, each 0 bit is either 48 or 52 cycles.
+	 * The length alternates to keep the average at 50.  This keeps the
+	 * waveform smooth, and keeps each bit in its 50 cycle time slot.
+	 *
+         * We don't have time for a function call, so we just chew
+         * up lots of flash...
+         */
+        .macro	baseband_0
+	.if startloop
+	toggle	2		// 4
+	.equ startloop, 0
+	.else
+        toggle	4		// 4
+	.endif
+        toggle	4		// 8
+        toggle	4		// 12
+        toggle	4		// 16
+        toggle	4		// 20
+        toggle	4		// 24
+        toggle	4		// 28
+        toggle	4		// 32
+        toggle	4		// 36
+        toggle	4		// 40
+        toggle	4		// 44
+        toggle	4		// 48
+	.if evenzero
+	.equ evenzero, 0
+	.else
+	toggle	4		// 52
+	.equ evenzero, 1
+	.endif
+        .endm
+
+        /*
+         * Emit a 1 at the baseband layer. (Toggle every 5 cycles, for 50 cycles)
+         */	
+        .macro	baseband_1
+	.if startloop
+	toggle	3		// 4
+	.equ startloop, 0
+	.else
+        toggle	5		// 4
+	.endif
+        toggle	5		// 10
+        toggle	5		// 15
+        toggle	5		// 20
+        toggle	5		// 25
+        toggle	5		// 30
+        toggle	5		// 35
+        toggle	5		// 40
+        toggle	5		// 45
+        toggle	5		// 50
+        .endm
+
+        .macro header
+	.equ evenzero, 0
+	.equ startloop, 1
+        baseband_0
+        baseband_0
+        baseband_0
+        baseband_1
+        baseband_1
+        baseband_1
+        .endm
+
+
+	/*
+	 * This should add up to 45 bits.
+	 *
+	 * Some cards may use different 45-bit codes: For example,
+	 * a Wiegand code, or something more site-specific. But the
+	 * cards that I've seen use a 20-bit manufacturer code,
+	 * 8-bit site code, 16-bit unique ID, and a single parity bit.
+	 *
+	 * If your card uses ad ifferent coding scheme, you can add,
+	 * remove, and modify these 'manchester' macros. Just make sure
+	 * the result adds up to the right number of bits.
+	 */
+        header
+        manchester	HID_MFG_CODE, 20
+	manchester	HID_SITE_CODE, 8
+	manchester	HID_UNIQUE_ID, 16
+	manchester	ODD_PARITY(HID_MFG_CODE ^ HID_SITE_CODE ^ HID_UNIQUE_ID), 1
+
+        ret
+
+
+#endif /* FORMAT_IS_HID */
+
+/*****************************************************************/
+ 
+/*
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+ 
 /**
- * \file Generic serial and other probe for a Teensy
+ * \file HID ProxPro Wiegand reader.
  *
  */
 
 	// "AT command", which can still be buffered.
 	usb_serial_flush_input();
 
-#if 1
+	// configure D7 as a output clock
+	// it is just toggled every time through the loop,
+	// not quite a real clock
+	ddr(0xD7, 1);
+	
+
 	out(0xB0, 1);
 	ddr(0xB0, 0); // pull up
 	out(0xB1, 1);
 
 	while (1)
 	{
+		// hack to generate a recovery clock
+		out(0xD7, !in(0xD7));
+
 		uint8_t d = ~PINB & 0x3;
 		if (d == 0)
 		{
 			usb_serial_putchar('1');
 		bits++;
 	}
-#else
-
-#if 0
-	// F0 should be pull-up
-	ddr(0xF0, 0);
-	out(0xF0, 1);
-
-	// Read the analog input F0 continuously
-        ADMUX = 0
-                | (1 << REFS0)
-                ;
-        ADCSRA = 0
-                | (1 << ADEN)
-                | (1 << ADSC)
-                | (1 << ADPS2) // clk over 128
-                | (1 << ADPS1)
-                | (1 << ADPS0)
-                ;
-
-	char buf[8];
-
-	while (1)
-	{
-		if (!bit_is_set(ADCSRA, ADIF))
-			continue;
-
-		const uint8_t val = ADC;
-		sbi(ADCSRA, ADIF);
-		sbi(ADCSRA, ADSC);
-
-		uint8_t i = 0;
-		buf[i++] = hexdigit(ADC >> 8);
-		buf[i++] = hexdigit(ADC >> 4);
-		buf[i++] = hexdigit(ADC >> 0);
-
-		buf[i++] = '\r';
-		buf[i++] = '\n';
-
-		usb_serial_write(buf, i);
-	}
-
-#elsif 0
-	// Configure the uart in 38400 mode
-	ddr(0xD2, 0); // rx
-	out(0xD2, 0); // no pull up
-
-	ddr(0xD3, 1); // tx
-	out(0xD3, 1); // set high for now
-
-	// 38400 == 25
-	// 57600 == 16
-	// 115200 == 8
-	UBRR1 = 8;
-	sbi(UCSR1B, RXEN1);
-	sbi(UCSR1B, TXEN1);
-
-	send_str(PSTR("serial bridge\r\n"));
-
-	while (1)
-	{
-		int c = usb_serial_getchar();
-		if (c != -1)
-		{
-			while (bit_is_clear(UCSR1A, UDRE1))
-				;
-			UDR1 = c;
-		}
-
-		if (bit_is_set(UCSR1A, RXC1))
-		{
-			c = UDR1;
-			usb_serial_putchar(c);
-		}
-	}
-#else
-	// bit bang SPI on the pins, no pull up
-#define SPI_SCLK 0xB1
-#define SPI_DATA 0xB2
-
-	ddr(SPI_SCLK, 0);
-	ddr(SPI_DATA, 0);
-	out(SPI_SCLK, 1); // pull up?
-	out(SPI_DATA, 1);
-
-	send_str(PSTR("spi\r\n"));
-
-	uint8_t val = 0;
-	uint8_t bits = 0;
-	uint8_t bytes = 0;
-	char buf[8];
-	uint16_t spin = 65535;
-
-	while (1)
-	{
-		// wait for it go back high
-		while (in(SPI_SCLK) == 0)
-			;
-
-		// wait for a falling edge on clock
-		while (in(SPI_SCLK) != 0)
-		{
-			if (--spin == 0)
-				break;
-		}
-
-		if (spin == 0)
-		{
-			spin = 65535;
-			val = bits = 0;
-			bytes = 0;
-			continue;
-		}
-
-		// read a bit from the stream
-		if (in(SPI_DATA))
-			val = (val >> 1) | 0x08;
-		else
-			val >>= 1;
-
-		bits++;
-		if (bits < 4)
-			continue;
-
-		buf[6 - ++bytes] = hexdigit(val);
-		val = bits = 0;
-
-		// Looks like 24-bits of data on the scope
-		if (bytes < 6)
-			continue;
-
-		buf[bytes++] = '\r';
-		buf[bytes++] = '\n';
-
-		usb_serial_write(buf, bytes);
-		bytes = 0;
-	}
-#endif
-#endif
 }