-#include <proxmark3.h>\r
-#include "apps.h"\r
-#include "LCD.h"\r
-\r
-void LCDSend(unsigned int data)\r
-{\r
- // 9th bit set for data, clear for command\r
- while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0); // wait for the transfer to complete\r
- // For clarity's sake we pass data with 9th bit clear and commands with 9th\r
- // bit set since they're implemented as defines, se we need to invert bit\r
- AT91C_BASE_SPI->SPI_TDR = data^0x100; // Send the data/command\r
-}\r
-\r
-void LCDSetXY(unsigned char x, unsigned char y)\r
-{\r
- LCDSend(PPASET); // page start/end ram\r
- LCDSend(y); // Start Page to display to\r
- LCDSend(131); // End Page to display to\r
-\r
- LCDSend(PCASET); // column start/end ram\r
- LCDSend(x); // Start Column to display to\r
- LCDSend(131); // End Column to display to\r
-}\r
-\r
-void LCDSetPixel(unsigned char x, unsigned char y, unsigned char color)\r
-{\r
- LCDSetXY(x,y); // Set position\r
- LCDSend(PRAMWR); // Now write the pixel to the display\r
- LCDSend(color); // Write the data in the specified Color\r
-}\r
-\r
-void LCDFill (unsigned char xs,unsigned char ys,unsigned char width,unsigned char height, unsigned char color)\r
-{\r
- unsigned char i,j;\r
-\r
- for (i=0;i < height;i++) // Number of horizontal lines\r
- {\r
- LCDSetXY(xs,ys+i); // Goto start of fill area (Top Left)\r
- LCDSend(PRAMWR); // Write to display\r
-\r
- for (j=0;j < width;j++) // pixels per line\r
- LCDSend(color);\r
- }\r
-}\r
-\r
-void LCDString (char *lcd_string, const char *font_style,unsigned char x, unsigned char y, unsigned char fcolor, unsigned char bcolor)\r
-{\r
- unsigned int i;\r
- unsigned char mask=0, px, py, xme, yme, offset;\r
- const char *data;\r
-\r
- data = font_style; // point to the start of the font table\r
-\r
- xme = *data; // get font x width\r
- data++;\r
- yme = *data; // get font y length\r
- data++;\r
- offset = *data; // get data bytes per font\r
-\r
- do\r
- {\r
- // point to data in table to be loaded\r
- data = (font_style + offset) + (offset * (int)(*lcd_string - 32));\r
-\r
- for (i=0;i < yme;i++) {\r
- mask |=0x80;\r
-\r
- for (px=x; px < (x + xme); px++) {\r
- py= y + i;\r
-\r
- if (*data & mask) LCDSetPixel (px,py,fcolor);\r
- else LCDSetPixel (px,py,bcolor);\r
-\r
- mask>>=1;\r
- }\r
- data++;\r
- }\r
- x+=xme;\r
-\r
- lcd_string++; // next character in string\r
-\r
- } while(*lcd_string !='\0'); // keep spitting chars out until end of string\r
-}\r
-\r
-void LCDReset(void)\r
-{\r
- LED_A_ON();\r
- SetupSpi(SPI_LCD_MODE);\r
- LOW(GPIO_LRST);\r
- SpinDelay(100);\r
-\r
- HIGH(GPIO_LRST);\r
- SpinDelay(100);\r
- LED_A_OFF();\r
-}\r
-\r
-void LCDInit(void)\r
-{\r
- int i;\r
-\r
- LCDReset();\r
-\r
- LCDSend(PSWRESET); // software reset\r
- SpinDelay(100);\r
- LCDSend(PSLEEPOUT); // exit sleep mode\r
- LCDSend(PBSTRON); // booster on\r
- LCDSend(PDISPON); // display on\r
- LCDSend(PNORON); // normal on\r
- LCDSend(PMADCTL); // rotate display 180 deg\r
- LCDSend(0xC0);\r
-\r
- LCDSend(PCOLMOD); // color mode\r
- LCDSend(0x02); // 8bpp color mode\r
-\r
- LCDSend(PSETCON); // set contrast\r
- LCDSend(0xDC);\r
- \r
- // clear display\r
- LCDSetXY(0,0);\r
- LCDSend(PRAMWR); // Write to display\r
- i=LCD_XRES*LCD_YRES;\r
- while(i--) LCDSend(WHITE);\r
-}\r
+#include <proxmark3.h>
+#include "apps.h"
+#include "LCD.h"
+
+void LCDSend(unsigned int data)
+{
+ // 9th bit set for data, clear for command
+ while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0); // wait for the transfer to complete
+ // For clarity's sake we pass data with 9th bit clear and commands with 9th
+ // bit set since they're implemented as defines, se we need to invert bit
+ AT91C_BASE_SPI->SPI_TDR = data^0x100; // Send the data/command
+}
+
+void LCDSetXY(unsigned char x, unsigned char y)
+{
+ LCDSend(PPASET); // page start/end ram
+ LCDSend(y); // Start Page to display to
+ LCDSend(131); // End Page to display to
+
+ LCDSend(PCASET); // column start/end ram
+ LCDSend(x); // Start Column to display to
+ LCDSend(131); // End Column to display to
+}
+
+void LCDSetPixel(unsigned char x, unsigned char y, unsigned char color)
+{
+ LCDSetXY(x,y); // Set position
+ LCDSend(PRAMWR); // Now write the pixel to the display
+ LCDSend(color); // Write the data in the specified Color
+}
+
+void LCDFill (unsigned char xs,unsigned char ys,unsigned char width,unsigned char height, unsigned char color)
+{
+ unsigned char i,j;
+
+ for (i=0;i < height;i++) // Number of horizontal lines
+ {
+ LCDSetXY(xs,ys+i); // Goto start of fill area (Top Left)
+ LCDSend(PRAMWR); // Write to display
+
+ for (j=0;j < width;j++) // pixels per line
+ LCDSend(color);
+ }
+}
+
+void LCDString (char *lcd_string, const char *font_style,unsigned char x, unsigned char y, unsigned char fcolor, unsigned char bcolor)
+{
+ unsigned int i;
+ unsigned char mask=0, px, py, xme, yme, offset;
+ const char *data;
+
+ data = font_style; // point to the start of the font table
+
+ xme = *data; // get font x width
+ data++;
+ yme = *data; // get font y length
+ data++;
+ offset = *data; // get data bytes per font
+
+ do
+ {
+ // point to data in table to be loaded
+ data = (font_style + offset) + (offset * (int)(*lcd_string - 32));
+
+ for (i=0;i < yme;i++) {
+ mask |=0x80;
+
+ for (px=x; px < (x + xme); px++) {
+ py= y + i;
+
+ if (*data & mask) LCDSetPixel (px,py,fcolor);
+ else LCDSetPixel (px,py,bcolor);
+
+ mask>>=1;
+ }
+ data++;
+ }
+ x+=xme;
+
+ lcd_string++; // next character in string
+
+ } while(*lcd_string !='\0'); // keep spitting chars out until end of string
+}
+
+void LCDReset(void)
+{
+ LED_A_ON();
+ SetupSpi(SPI_LCD_MODE);
+ LOW(GPIO_LRST);
+ SpinDelay(100);
+
+ HIGH(GPIO_LRST);
+ SpinDelay(100);
+ LED_A_OFF();
+}
+
+void LCDInit(void)
+{
+ int i;
+
+ LCDReset();
+
+ LCDSend(PSWRESET); // software reset
+ SpinDelay(100);
+ LCDSend(PSLEEPOUT); // exit sleep mode
+ LCDSend(PBSTRON); // booster on
+ LCDSend(PDISPON); // display on
+ LCDSend(PNORON); // normal on
+ LCDSend(PMADCTL); // rotate display 180 deg
+ LCDSend(0xC0);
+
+ LCDSend(PCOLMOD); // color mode
+ LCDSend(0x02); // 8bpp color mode
+
+ LCDSend(PSETCON); // set contrast
+ LCDSend(0xDC);
+
+ // clear display
+ LCDSetXY(0,0);
+ LCDSend(PRAMWR); // Write to display
+ i=LCD_XRES*LCD_YRES;
+ while(i--) LCDSend(WHITE);
+}
-#ifndef __LCD\r
-#define __LCD\r
-\r
-// The resolution of the LCD\r
-#define LCD_XRES 132\r
-#define LCD_YRES 132\r
-\r
-// 8bpp Color Mode - Some basic colors defined for ease of use\r
-// remember 8bpp color = 3xRed, 3xGreen & 2xBlue bits\r
-// organised as RRRGGGBB\r
-\r
-#define BLACK 0x00\r
-#define BLUE 0x03\r
-#define GREEN 0x1C\r
-#define CYAN 0x1F\r
-#define RED 0xE0\r
-#define MAGENTA 0xE3\r
-#define YELLOW 0xFC\r
-#define WHITE 0xFF\r
-\r
-// EPSON LCD command set\r
-#define ECASET 0x115\r
-#define EPWRCTR 0x120\r
-#define ENOP 0x125\r
-#define ERAMWR 0x15C\r
-#define ERAMRD 0x15D\r
-#define EPASET 0x175\r
-#define EEPSRRD1 0x17C\r
-#define EEPSRRD2 0x17D\r
-#define EVOLCTR 0x181\r
-#define ETMPGRD 0x182\r
-#define ESLPOUT 0x194\r
-#define ESLPIN 0x195\r
-#define EDISNOR 0x1A6\r
-#define EDISINV 0x1A7\r
-#define EPTLIN 0x1A8\r
-#define EPTLOUT 0x1A9\r
-#define EASCSET 0x1AA\r
-#define ESCSTART 0x1AB\r
-#define EDISOFF 0x1AE\r
-#define EDISON 0x1AF\r
-#define ECOMSCN 0x1BB\r
-#define EDATCTL 0x1BC\r
-#define EDISCTL 0x1CA\r
-#define EEPCOUT 0x1CC\r
-#define EEPCTIN 0x1CD\r
-#define ERGBSET8 0x1CE\r
-#define EOSCON 0x1D1\r
-#define EOSCOFF 0x1D2\r
-#define EVOLUP 0x1D6\r
-#define EVOLDOWN 0x1D7\r
-#define ERMWIN 0x1E0\r
-#define ERMWOUT 0x1EE\r
-#define EEPMWR 0x1FC\r
-#define EEPMRD 0x1FD\r
-\r
-// PHILIPS LCD command set\r
-#define PNOP 0x100\r
-#define PSWRESET 0x101\r
-#define PBSTROFF 0x102\r
-#define PBSTRON 0x103\r
-#define PRDDIDIF 0x104\r
-#define PRDDST 0x109\r
-#define PSLEEPIN 0x110\r
-#define PSLEEPOUT 0x111\r
-#define PPTLON 0x112\r
-#define PNORON 0x113\r
-#define PINVOFF 0x120\r
-#define PINVON 0x121\r
-#define PDALO 0x122\r
-#define PDAL 0x123\r
-#define PSETCON 0x125\r
-#define PDISPOFF 0x128\r
-#define PDISPON 0x129\r
-#define PCASET 0x12A\r
-#define PPASET 0x12B\r
-#define PRAMWR 0x12C\r
-#define PRGBSET 0x12D\r
-#define PPTLAR 0x130\r
-#define PVSCRDEF 0x133\r
-#define PTEOFF 0x134\r
-#define PTEON 0x135\r
-#define PMADCTL 0x136\r
-#define PSEP 0x137\r
-#define PIDMOFF 0x138\r
-#define PIDMON 0x139\r
-#define PCOLMOD 0x13A\r
-#define PSETVOP 0x1B0\r
-#define PBRS 0x1B4\r
-#define PTRS 0x1B6\r
-#define PFINV 0x1B9\r
-#define PDOR 0x1BA\r
-#define PTCDFE 0x1BD\r
-#define PTCVOPE 0x1BF\r
-#define PEC 0x1C0\r
-#define PSETMUL 0x1C2\r
-#define PTCVOPAB 0x1C3\r
-#define PTCVOPCD 0x1C4\r
-#define PTCDF 0x1C5\r
-#define PDF8C 0x1C6\r
-#define PSETBS 0x1C7\r
-#define PRDTEMP 0x1C8\r
-#define PNLI 0x1C9\r
-#define PRDID1 0x1DA\r
-#define PRDID2 0x1DB\r
-#define PRDID3 0x1DC\r
-#define PSFD 0x1EF\r
-#define PECM 0x1F0\r
-\r
-void LCDSend(unsigned int data);\r
-void LCDInit(void);\r
-void LCDReset(void);\r
-void LCDSetXY(unsigned char x, unsigned char y);\r
-void LCDSetPixel(unsigned char x, unsigned char y, unsigned char color);\r
-void LCDString (char *lcd_string, const char *font_style,unsigned char x, unsigned char y, unsigned char fcolor, unsigned char bcolor);\r
-void LCDFill (unsigned char xs,unsigned char ys,unsigned char width,unsigned char height, unsigned char color);\r
-#endif\r
+#ifndef __LCD
+#define __LCD
+
+// The resolution of the LCD
+#define LCD_XRES 132
+#define LCD_YRES 132
+
+// 8bpp Color Mode - Some basic colors defined for ease of use
+// remember 8bpp color = 3xRed, 3xGreen & 2xBlue bits
+// organised as RRRGGGBB
+
+#define BLACK 0x00
+#define BLUE 0x03
+#define GREEN 0x1C
+#define CYAN 0x1F
+#define RED 0xE0
+#define MAGENTA 0xE3
+#define YELLOW 0xFC
+#define WHITE 0xFF
+
+// EPSON LCD command set
+#define ECASET 0x115
+#define EPWRCTR 0x120
+#define ENOP 0x125
+#define ERAMWR 0x15C
+#define ERAMRD 0x15D
+#define EPASET 0x175
+#define EEPSRRD1 0x17C
+#define EEPSRRD2 0x17D
+#define EVOLCTR 0x181
+#define ETMPGRD 0x182
+#define ESLPOUT 0x194
+#define ESLPIN 0x195
+#define EDISNOR 0x1A6
+#define EDISINV 0x1A7
+#define EPTLIN 0x1A8
+#define EPTLOUT 0x1A9
+#define EASCSET 0x1AA
+#define ESCSTART 0x1AB
+#define EDISOFF 0x1AE
+#define EDISON 0x1AF
+#define ECOMSCN 0x1BB
+#define EDATCTL 0x1BC
+#define EDISCTL 0x1CA
+#define EEPCOUT 0x1CC
+#define EEPCTIN 0x1CD
+#define ERGBSET8 0x1CE
+#define EOSCON 0x1D1
+#define EOSCOFF 0x1D2
+#define EVOLUP 0x1D6
+#define EVOLDOWN 0x1D7
+#define ERMWIN 0x1E0
+#define ERMWOUT 0x1EE
+#define EEPMWR 0x1FC
+#define EEPMRD 0x1FD
+
+// PHILIPS LCD command set
+#define PNOP 0x100
+#define PSWRESET 0x101
+#define PBSTROFF 0x102
+#define PBSTRON 0x103
+#define PRDDIDIF 0x104
+#define PRDDST 0x109
+#define PSLEEPIN 0x110
+#define PSLEEPOUT 0x111
+#define PPTLON 0x112
+#define PNORON 0x113
+#define PINVOFF 0x120
+#define PINVON 0x121
+#define PDALO 0x122
+#define PDAL 0x123
+#define PSETCON 0x125
+#define PDISPOFF 0x128
+#define PDISPON 0x129
+#define PCASET 0x12A
+#define PPASET 0x12B
+#define PRAMWR 0x12C
+#define PRGBSET 0x12D
+#define PPTLAR 0x130
+#define PVSCRDEF 0x133
+#define PTEOFF 0x134
+#define PTEON 0x135
+#define PMADCTL 0x136
+#define PSEP 0x137
+#define PIDMOFF 0x138
+#define PIDMON 0x139
+#define PCOLMOD 0x13A
+#define PSETVOP 0x1B0
+#define PBRS 0x1B4
+#define PTRS 0x1B6
+#define PFINV 0x1B9
+#define PDOR 0x1BA
+#define PTCDFE 0x1BD
+#define PTCVOPE 0x1BF
+#define PEC 0x1C0
+#define PSETMUL 0x1C2
+#define PTCVOPAB 0x1C3
+#define PTCVOPCD 0x1C4
+#define PTCDF 0x1C5
+#define PDF8C 0x1C6
+#define PSETBS 0x1C7
+#define PRDTEMP 0x1C8
+#define PNLI 0x1C9
+#define PRDID1 0x1DA
+#define PRDID2 0x1DB
+#define PRDID3 0x1DC
+#define PSFD 0x1EF
+#define PECM 0x1F0
+
+void LCDSend(unsigned int data);
+void LCDInit(void);
+void LCDReset(void);
+void LCDSetXY(unsigned char x, unsigned char y);
+void LCDSetPixel(unsigned char x, unsigned char y, unsigned char color);
+void LCDString (char *lcd_string, const char *font_style,unsigned char x, unsigned char y, unsigned char fcolor, unsigned char bcolor);
+void LCDFill (unsigned char xs,unsigned char ys,unsigned char width,unsigned char height, unsigned char color);
+#endif
-# Makefile for armsrc, see ../common/Makefile.common for common settings\r
-\r
-APP_INCLUDES = apps.h\r
-\r
-#remove one of the following defines and comment out the relevant line\r
-#in the next section to remove that particular feature from compilation \r
-APP_CFLAGS = -O6 -DWITH_LF -DWITH_ISO15693 -DWITH_ISO14443a -DWITH_ISO14443b\r
-#-DWITH_LCD \r
-\r
-#SRC_LCD = fonts.c LCD.c\r
-SRC_LF = lfops.c hitag2.c\r
-SRC_ISO15693 = iso15693.c\r
-SRC_ISO14443a = iso14443a.c\r
-SRC_ISO14443b = iso14443.c\r
-\r
-THUMBSRC = start.c \\r
- $(SRC_LCD) \\r
- $(SRC_ISO15693) \\r
- $(SRC_LF) \\r
- appmain.c printf.c \\r
- util.c \\r
- usb.c\r
-\r
-# These are to be compiled in ARM mode\r
-ARMSRC = fpgaloader.c \\r
- legicrf.c \\r
- iso14443crc.c \\r
- crc16.c \\r
- $(SRC_ISO14443a) \\r
- $(SRC_ISO14443b) \\r
- legic_prng.c \\r
- crc.c\r
-\r
-# stdint.h provided locally until GCC 4.5 becomes C99 compliant\r
-APP_CFLAGS += -I.\r
-\r
-# Do not move this inclusion before the definition of {THUMB,ASM,ARM}SRC\r
-include ../common/Makefile.common\r
-\r
-all: $(OBJDIR)/osimage.s19 $(OBJDIR)/fpgaimage.s19\r
-\r
-$(OBJDIR)/fpga.o: fpga.bit\r
- $(OBJCOPY) -O elf32-littlearm -I binary -B arm --redefine-sym _binary____fpga_fpga_bit_start=_binary_fpga_bit_start --redefine-sym _binary____fpga_fpga_bit_end=_binary_fpga_bit_end --prefix-sections=fpga_bit $^ $@\r
-\r
-$(OBJDIR)/fullimage.elf: $(VERSIONOBJ) $(OBJDIR)/fpga.o $(THUMBOBJ) $(ARMOBJ) $(LIBGCC)\r
- $(LD) -g -Tldscript -Map=$(patsubst %.elf,%.map,$@) -o $@ $^\r
-\r
-$(OBJDIR)/fpgaimage.elf: $(OBJDIR)/fullimage.elf\r
- $(OBJCOPY) -F elf32-littlearm --only-section .fpgaimage $^ $@ \r
-\r
-$(OBJDIR)/osimage.elf: $(OBJDIR)/fullimage.elf\r
- $(OBJCOPY) -F elf32-littlearm --remove-section .fpgaimage $^ $@\r
-\r
-clean:\r
- $(DELETE) $(OBJDIR)$(PATHSEP)*.o\r
- $(DELETE) $(OBJDIR)$(PATHSEP)*.elf\r
- $(DELETE) $(OBJDIR)$(PATHSEP)*.s19\r
- $(DELETE) $(OBJDIR)$(PATHSEP)*.map\r
- $(DELETE) $(OBJDIR)$(PATHSEP)*.d\r
- $(DELETE) version.c\r
-\r
-.PHONY: all clean help\r
-help:\r
- @echo Multi-OS Makefile, you are running on $(DETECTED_OS)\r
- @echo Possible targets:\r
- @echo + all - Make both:\r
- @echo + $(OBJDIR)/osimage.s19 - The OS image\r
- @echo + $(OBJDIR)/fpgaimage.s19 - The FPGA image\r
- @echo + clean - Clean $(OBJDIR)\r
-\r
+# Makefile for armsrc, see ../common/Makefile.common for common settings
+
+APP_INCLUDES = apps.h
+
+#remove one of the following defines and comment out the relevant line
+#in the next section to remove that particular feature from compilation
+APP_CFLAGS = -O6 -DWITH_LF -DWITH_ISO15693 -DWITH_ISO14443a -DWITH_ISO14443b
+#-DWITH_LCD
+
+#SRC_LCD = fonts.c LCD.c
+SRC_LF = lfops.c hitag2.c
+SRC_ISO15693 = iso15693.c
+SRC_ISO14443a = iso14443a.c
+SRC_ISO14443b = iso14443.c
+
+THUMBSRC = start.c \
+ $(SRC_LCD) \
+ $(SRC_ISO15693) \
+ $(SRC_LF) \
+ appmain.c printf.c \
+ util.c \
+ usb.c
+
+# These are to be compiled in ARM mode
+ARMSRC = fpgaloader.c \
+ legicrf.c \
+ iso14443crc.c \
+ crc16.c \
+ $(SRC_ISO14443a) \
+ $(SRC_ISO14443b) \
+ legic_prng.c \
+ crc.c
+
+# stdint.h provided locally until GCC 4.5 becomes C99 compliant
+APP_CFLAGS += -I.
+
+# Do not move this inclusion before the definition of {THUMB,ASM,ARM}SRC
+include ../common/Makefile.common
+
+all: $(OBJDIR)/osimage.s19 $(OBJDIR)/fpgaimage.s19
+
+$(OBJDIR)/fpga.o: fpga.bit
+ $(OBJCOPY) -O elf32-littlearm -I binary -B arm --redefine-sym _binary____fpga_fpga_bit_start=_binary_fpga_bit_start --redefine-sym _binary____fpga_fpga_bit_end=_binary_fpga_bit_end --prefix-sections=fpga_bit $^ $@
+
+$(OBJDIR)/fullimage.elf: $(VERSIONOBJ) $(OBJDIR)/fpga.o $(THUMBOBJ) $(ARMOBJ) $(LIBGCC)
+ $(LD) -g -Tldscript -Map=$(patsubst %.elf,%.map,$@) -o $@ $^
+
+$(OBJDIR)/fpgaimage.elf: $(OBJDIR)/fullimage.elf
+ $(OBJCOPY) -F elf32-littlearm --only-section .fpgaimage $^ $@
+
+$(OBJDIR)/osimage.elf: $(OBJDIR)/fullimage.elf
+ $(OBJCOPY) -F elf32-littlearm --remove-section .fpgaimage $^ $@
+
+clean:
+ $(DELETE) $(OBJDIR)$(PATHSEP)*.o
+ $(DELETE) $(OBJDIR)$(PATHSEP)*.elf
+ $(DELETE) $(OBJDIR)$(PATHSEP)*.s19
+ $(DELETE) $(OBJDIR)$(PATHSEP)*.map
+ $(DELETE) $(OBJDIR)$(PATHSEP)*.d
+ $(DELETE) version.c
+
+.PHONY: all clean help
+help:
+ @echo Multi-OS Makefile, you are running on $(DETECTED_OS)
+ @echo Possible targets:
+ @echo + all - Make both:
+ @echo + $(OBJDIR)/osimage.s19 - The OS image
+ @echo + $(OBJDIR)/fpgaimage.s19 - The FPGA image
+ @echo + clean - Clean $(OBJDIR)
+
-//-----------------------------------------------------------------------------\r
-// The main application code. This is the first thing called after start.c\r
-// executes.\r
-// Jonathan Westhues, Mar 2006\r
-// Edits by Gerhard de Koning Gans, Sep 2007 (##)\r
-//-----------------------------------------------------------------------------\r
-\r
-#include <proxmark3.h>\r
-#include "apps.h"\r
-#include "legicrf.h"\r
-#ifdef WITH_LCD\r
-#include "fonts.h"\r
-#include "LCD.h"\r
-#endif\r
-\r
-#define va_list __builtin_va_list\r
-#define va_start __builtin_va_start\r
-#define va_arg __builtin_va_arg\r
-#define va_end __builtin_va_end\r
-int kvsprintf(char const *fmt, void *arg, int radix, va_list ap);\r
- \r
-\r
-#define abs(x) ( ((x)<0) ? -(x) : (x) )\r
-\r
-//=============================================================================\r
-// A buffer where we can queue things up to be sent through the FPGA, for\r
-// any purpose (fake tag, as reader, whatever). We go MSB first, since that\r
-// is the order in which they go out on the wire.\r
-//=============================================================================\r
-\r
-BYTE ToSend[512];\r
-int ToSendMax;\r
-static int ToSendBit;\r
-struct common_area common_area __attribute__((section(".commonarea")));\r
-\r
-void BufferClear(void)\r
-{\r
- memset(BigBuf,0,sizeof(BigBuf));\r
- Dbprintf("Buffer cleared (%i bytes)",sizeof(BigBuf));\r
-}\r
-\r
-void ToSendReset(void)\r
-{\r
- ToSendMax = -1;\r
- ToSendBit = 8;\r
-}\r
-\r
-void ToSendStuffBit(int b)\r
-{\r
- if(ToSendBit >= 8) {\r
- ToSendMax++;\r
- ToSend[ToSendMax] = 0;\r
- ToSendBit = 0;\r
- }\r
-\r
- if(b) {\r
- ToSend[ToSendMax] |= (1 << (7 - ToSendBit));\r
- }\r
-\r
- ToSendBit++;\r
-\r
- if(ToSendBit >= sizeof(ToSend)) {\r
- ToSendBit = 0;\r
- DbpString("ToSendStuffBit overflowed!");\r
- }\r
-}\r
-\r
-//=============================================================================\r
-// Debug print functions, to go out over USB, to the usual PC-side client.\r
-//=============================================================================\r
-\r
-void DbpString(char *str)\r
-{\r
- /* this holds up stuff unless we're connected to usb */\r
- if (!UsbConnected())\r
- return;\r
-\r
- UsbCommand c;\r
- c.cmd = CMD_DEBUG_PRINT_STRING;\r
- c.arg[0] = strlen(str);\r
- if(c.arg[0] > sizeof(c.d.asBytes)) {\r
- c.arg[0] = sizeof(c.d.asBytes);\r
- }\r
- memcpy(c.d.asBytes, str, c.arg[0]);\r
-\r
- UsbSendPacket((BYTE *)&c, sizeof(c));\r
- // TODO fix USB so stupid things like this aren't req'd\r
- SpinDelay(50);\r
-}\r
-\r
-#if 0\r
-void DbpIntegers(int x1, int x2, int x3)\r
-{\r
- /* this holds up stuff unless we're connected to usb */\r
- if (!UsbConnected())\r
- return;\r
-\r
- UsbCommand c;\r
- c.cmd = CMD_DEBUG_PRINT_INTEGERS;\r
- c.arg[0] = x1;\r
- c.arg[1] = x2;\r
- c.arg[2] = x3;\r
-\r
- UsbSendPacket((BYTE *)&c, sizeof(c));\r
- // XXX\r
- SpinDelay(50);\r
-}\r
-#endif\r
-\r
-void Dbprintf(const char *fmt, ...) {\r
-// should probably limit size here; oh well, let's just use a big buffer\r
- char output_string[128];\r
- va_list ap;\r
-\r
- va_start(ap, fmt);\r
- kvsprintf(fmt, output_string, 10, ap);\r
- va_end(ap);\r
- \r
- DbpString(output_string);\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-// Read an ADC channel and block till it completes, then return the result\r
-// in ADC units (0 to 1023). Also a routine to average 32 samples and\r
-// return that.\r
-//-----------------------------------------------------------------------------\r
-static int ReadAdc(int ch)\r
-{\r
- DWORD d;\r
-\r
- AT91C_BASE_ADC->ADC_CR = AT91C_ADC_SWRST;\r
- AT91C_BASE_ADC->ADC_MR =\r
- ADC_MODE_PRESCALE(32) |\r
- ADC_MODE_STARTUP_TIME(16) |\r
- ADC_MODE_SAMPLE_HOLD_TIME(8);\r
- AT91C_BASE_ADC->ADC_CHER = ADC_CHANNEL(ch);\r
-\r
- AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START;\r
- while(!(AT91C_BASE_ADC->ADC_SR & ADC_END_OF_CONVERSION(ch)))\r
- ;\r
- d = AT91C_BASE_ADC->ADC_CDR[ch];\r
-\r
- return d;\r
-}\r
-\r
-static int AvgAdc(int ch)\r
-{\r
- int i;\r
- int a = 0;\r
-\r
- for(i = 0; i < 32; i++) {\r
- a += ReadAdc(ch);\r
- }\r
-\r
- return (a + 15) >> 5;\r
-}\r
-\r
-void MeasureAntennaTuning(void)\r
-{\r
- BYTE *dest = (BYTE *)BigBuf;\r
- int i, ptr = 0, adcval = 0, peak = 0, peakv = 0, peakf = 0;;\r
- int vLf125 = 0, vLf134 = 0, vHf = 0; // in mV\r
-\r
- UsbCommand c;\r
-\r
- DbpString("Measuring antenna characteristics, please wait.");\r
- memset(BigBuf,0,sizeof(BigBuf));\r
-\r
-/*\r
- * Sweeps the useful LF range of the proxmark from\r
- * 46.8kHz (divisor=255) to 600kHz (divisor=19) and\r
- * read the voltage in the antenna, the result left\r
- * in the buffer is a graph which should clearly show\r
- * the resonating frequency of your LF antenna\r
- * ( hopefully around 95 if it is tuned to 125kHz!)\r
- */\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);\r
- for (i=255; i>19; i--) {\r
- FpgaSendCommand(FPGA_CMD_SET_DIVISOR, i);\r
- SpinDelay(20);\r
- // Vref = 3.3V, and a 10000:240 voltage divider on the input\r
- // can measure voltages up to 137500 mV\r
- adcval = ((137500 * AvgAdc(ADC_CHAN_LF)) >> 10);\r
- if (i==95) vLf125 = adcval; // voltage at 125Khz\r
- if (i==89) vLf134 = adcval; // voltage at 134Khz\r
-\r
- dest[i] = adcval>>8; // scale int to fit in byte for graphing purposes\r
- if(dest[i] > peak) {\r
- peakv = adcval;\r
- peak = dest[i];\r
- peakf = i;\r
- ptr = i;\r
- }\r
- }\r
-\r
- // Let the FPGA drive the high-frequency antenna around 13.56 MHz.\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);\r
- SpinDelay(20);\r
- // Vref = 3300mV, and an 10:1 voltage divider on the input\r
- // can measure voltages up to 33000 mV\r
- vHf = (33000 * AvgAdc(ADC_CHAN_HF)) >> 10;\r
-\r
- c.cmd = CMD_MEASURED_ANTENNA_TUNING;\r
- c.arg[0] = (vLf125 << 0) | (vLf134 << 16);\r
- c.arg[1] = vHf;\r
- c.arg[2] = peakf | (peakv << 16);\r
- UsbSendPacket((BYTE *)&c, sizeof(c));\r
-}\r
-\r
-void MeasureAntennaTuningHf(void)\r
-{\r
- int vHf = 0; // in mV\r
-\r
- DbpString("Measuring HF antenna, press button to exit");\r
-\r
- for (;;) {\r
- // Let the FPGA drive the high-frequency antenna around 13.56 MHz.\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);\r
- SpinDelay(20);\r
- // Vref = 3300mV, and an 10:1 voltage divider on the input\r
- // can measure voltages up to 33000 mV\r
- vHf = (33000 * AvgAdc(ADC_CHAN_HF)) >> 10;\r
- \r
- Dbprintf("%d mV",vHf);\r
- if (BUTTON_PRESS()) break;\r
- }\r
- DbpString("cancelled");\r
-}\r
-\r
-\r
-void SimulateTagHfListen(void)\r
-{\r
- BYTE *dest = (BYTE *)BigBuf;\r
- int n = sizeof(BigBuf);\r
- BYTE v = 0;\r
- int i;\r
- int p = 0;\r
-\r
- // We're using this mode just so that I can test it out; the simulated\r
- // tag mode would work just as well and be simpler.\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ | FPGA_HF_READER_RX_XCORR_SNOOP);\r
-\r
- // We need to listen to the high-frequency, peak-detected path.\r
- SetAdcMuxFor(GPIO_MUXSEL_HIPKD);\r
-\r
- FpgaSetupSsc();\r
-\r
- i = 0;\r
- for(;;) {\r
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {\r
- AT91C_BASE_SSC->SSC_THR = 0xff;\r
- }\r
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {\r
- BYTE r = (BYTE)AT91C_BASE_SSC->SSC_RHR;\r
-\r
- v <<= 1;\r
- if(r & 1) {\r
- v |= 1;\r
- }\r
- p++;\r
-\r
- if(p >= 8) {\r
- dest[i] = v;\r
- v = 0;\r
- p = 0;\r
- i++;\r
-\r
- if(i >= n) {\r
- break;\r
- }\r
- }\r
- }\r
- }\r
- DbpString("simulate tag (now type bitsamples)");\r
-}\r
-\r
-void ReadMem(int addr)\r
-{\r
- const BYTE *data = ((BYTE *)addr);\r
-\r
- Dbprintf("%x: %02x %02x %02x %02x %02x %02x %02x %02x",\r
- addr, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]);\r
-}\r
-\r
-/* osimage version information is linked in */\r
-extern struct version_information version_information;\r
-/* bootrom version information is pointed to from _bootphase1_version_pointer */\r
-extern char *_bootphase1_version_pointer, _flash_start, _flash_end;\r
-void SendVersion(void)\r
-{\r
- char temp[48]; /* Limited data payload in USB packets */\r
- DbpString("Prox/RFID mark3 RFID instrument");\r
- \r
- /* Try to find the bootrom version information. Expect to find a pointer at \r
- * symbol _bootphase1_version_pointer, perform slight sanity checks on the\r
- * pointer, then use it.\r
- */\r
- char *bootrom_version = *(char**)&_bootphase1_version_pointer;\r
- if( bootrom_version < &_flash_start || bootrom_version >= &_flash_end ) {\r
- DbpString("bootrom version information appears invalid");\r
- } else {\r
- FormatVersionInformation(temp, sizeof(temp), "bootrom: ", bootrom_version);\r
- DbpString(temp);\r
- }\r
- \r
- FormatVersionInformation(temp, sizeof(temp), "os: ", &version_information);\r
- DbpString(temp);\r
- \r
- FpgaGatherVersion(temp, sizeof(temp));\r
- DbpString(temp);\r
-}\r
-\r
-#ifdef WITH_LF\r
-// samy's sniff and repeat routine\r
-void SamyRun()\r
-{\r
- DbpString("Stand-alone mode! No PC necessary.");\r
-\r
- // 3 possible options? no just 2 for now\r
-#define OPTS 2\r
-\r
- int high[OPTS], low[OPTS];\r
-\r
- // Oooh pretty -- notify user we're in elite samy mode now\r
- LED(LED_RED, 200);\r
- LED(LED_ORANGE, 200);\r
- LED(LED_GREEN, 200);\r
- LED(LED_ORANGE, 200);\r
- LED(LED_RED, 200);\r
- LED(LED_ORANGE, 200);\r
- LED(LED_GREEN, 200);\r
- LED(LED_ORANGE, 200);\r
- LED(LED_RED, 200);\r
-\r
- int selected = 0;\r
- int playing = 0;\r
-\r
- // Turn on selected LED\r
- LED(selected + 1, 0);\r
-\r
- for (;;)\r
- {\r
- UsbPoll(FALSE);\r
- WDT_HIT();\r
-\r
- // Was our button held down or pressed?\r
- int button_pressed = BUTTON_HELD(1000);\r
- SpinDelay(300);\r
-\r
- // Button was held for a second, begin recording\r
- if (button_pressed > 0)\r
- {\r
- LEDsoff();\r
- LED(selected + 1, 0);\r
- LED(LED_RED2, 0);\r
-\r
- // record\r
- DbpString("Starting recording");\r
-\r
- // wait for button to be released\r
- while(BUTTON_PRESS())\r
- WDT_HIT();\r
-\r
- /* need this delay to prevent catching some weird data */\r
- SpinDelay(500);\r
-\r
- CmdHIDdemodFSK(1, &high[selected], &low[selected], 0);\r
- Dbprintf("Recorded %x %x %x", selected, high[selected], low[selected]);\r
-\r
- LEDsoff();\r
- LED(selected + 1, 0);\r
- // Finished recording\r
-\r
- // If we were previously playing, set playing off\r
- // so next button push begins playing what we recorded\r
- playing = 0;\r
- }\r
-\r
- // Change where to record (or begin playing)\r
- else if (button_pressed)\r
- {\r
- // Next option if we were previously playing\r
- if (playing)\r
- selected = (selected + 1) % OPTS;\r
- playing = !playing;\r
-\r
- LEDsoff();\r
- LED(selected + 1, 0);\r
-\r
- // Begin transmitting\r
- if (playing)\r
- {\r
- LED(LED_GREEN, 0);\r
- DbpString("Playing");\r
- // wait for button to be released\r
- while(BUTTON_PRESS())\r
- WDT_HIT();\r
- Dbprintf("%x %x %x", selected, high[selected], low[selected]);\r
- CmdHIDsimTAG(high[selected], low[selected], 0);\r
- DbpString("Done playing");\r
- if (BUTTON_HELD(1000) > 0)\r
- {\r
- DbpString("Exiting");\r
- LEDsoff();\r
- return;\r
- }\r
-\r
- /* We pressed a button so ignore it here with a delay */\r
- SpinDelay(300);\r
-\r
- // when done, we're done playing, move to next option\r
- selected = (selected + 1) % OPTS;\r
- playing = !playing;\r
- LEDsoff();\r
- LED(selected + 1, 0);\r
- }\r
- else\r
- while(BUTTON_PRESS())\r
- WDT_HIT();\r
- }\r
- }\r
-}\r
-#endif\r
-\r
-/*\r
-OBJECTIVE\r
-Listen and detect an external reader. Determine the best location\r
-for the antenna.\r
-\r
-INSTRUCTIONS:\r
-Inside the ListenReaderField() function, there is two mode.\r
-By default, when you call the function, you will enter mode 1.\r
-If you press the PM3 button one time, you will enter mode 2.\r
-If you press the PM3 button a second time, you will exit the function.\r
-\r
-DESCRIPTION OF MODE 1:\r
-This mode just listens for an external reader field and lights up green\r
-for HF and/or red for LF. This is the original mode of the detectreader\r
-function.\r
-\r
-DESCRIPTION OF MODE 2:\r
-This mode will visually represent, using the LEDs, the actual strength of the\r
-current compared to the maximum current detected. Basically, once you know\r
-what kind of external reader is present, it will help you spot the best location to place\r
-your antenna. You will probably not get some good results if there is a LF and a HF reader\r
-at the same place! :-)\r
-\r
-LIGHT SCHEME USED:\r
-*/\r
-static const char LIGHT_SCHEME[] = {\r
- 0x0, /* ---- | No field detected */\r
- 0x1, /* X--- | 14% of maximum current detected */\r
- 0x2, /* -X-- | 29% of maximum current detected */\r
- 0x4, /* --X- | 43% of maximum current detected */\r
- 0x8, /* ---X | 57% of maximum current detected */\r
- 0xC, /* --XX | 71% of maximum current detected */\r
- 0xE, /* -XXX | 86% of maximum current detected */\r
- 0xF, /* XXXX | 100% of maximum current detected */\r
-};\r
-static const int LIGHT_LEN = sizeof(LIGHT_SCHEME)/sizeof(LIGHT_SCHEME[0]);\r
-\r
-void ListenReaderField(int limit)\r
-{\r
- int lf_av, lf_av_new, lf_baseline= 0, lf_count= 0, lf_max;\r
- int hf_av, hf_av_new, hf_baseline= 0, hf_count= 0, hf_max;\r
- int mode=1, display_val, display_max, i;\r
-\r
-#define LF_ONLY 1\r
-#define HF_ONLY 2\r
-\r
- LEDsoff();\r
-\r
- lf_av=lf_max=ReadAdc(ADC_CHAN_LF);\r
-\r
- if(limit != HF_ONLY) {\r
- Dbprintf("LF 125/134 Baseline: %d", lf_av);\r
- lf_baseline = lf_av;\r
- }\r
-\r
- hf_av=hf_max=ReadAdc(ADC_CHAN_HF);\r
-\r
- if (limit != LF_ONLY) {\r
- Dbprintf("HF 13.56 Baseline: %d", hf_av);\r
- hf_baseline = hf_av;\r
- }\r
-\r
- for(;;) {\r
- if (BUTTON_PRESS()) {\r
- SpinDelay(500);\r
- switch (mode) {\r
- case 1:\r
- mode=2;\r
- DbpString("Signal Strength Mode");\r
- break;\r
- case 2:\r
- default:\r
- DbpString("Stopped");\r
- LEDsoff();\r
- return;\r
- break;\r
- }\r
- }\r
- WDT_HIT();\r
-\r
- if (limit != HF_ONLY) {\r
- if(mode==1) {\r
- if (abs(lf_av - lf_baseline) > 10) LED_D_ON();\r
- else LED_D_OFF();\r
- }\r
- \r
- ++lf_count;\r
- lf_av_new= ReadAdc(ADC_CHAN_LF);\r
- // see if there's a significant change\r
- if(abs(lf_av - lf_av_new) > 10) {\r
- Dbprintf("LF 125/134 Field Change: %x %x %x", lf_av, lf_av_new, lf_count);\r
- lf_av = lf_av_new;\r
- if (lf_av > lf_max)\r
- lf_max = lf_av;\r
- lf_count= 0;\r
- }\r
- }\r
-\r
- if (limit != LF_ONLY) {\r
- if (mode == 1){\r
- if (abs(hf_av - hf_baseline) > 10) LED_B_ON();\r
- else LED_B_OFF();\r
- }\r
- \r
- ++hf_count;\r
- hf_av_new= ReadAdc(ADC_CHAN_HF);\r
- // see if there's a significant change\r
- if(abs(hf_av - hf_av_new) > 10) {\r
- Dbprintf("HF 13.56 Field Change: %x %x %x", hf_av, hf_av_new, hf_count);\r
- hf_av = hf_av_new;\r
- if (hf_av > hf_max)\r
- hf_max = hf_av;\r
- hf_count= 0;\r
- }\r
- }\r
- \r
- if(mode == 2) {\r
- if (limit == LF_ONLY) {\r
- display_val = lf_av;\r
- display_max = lf_max;\r
- } else if (limit == HF_ONLY) {\r
- display_val = hf_av;\r
- display_max = hf_max;\r
- } else { /* Pick one at random */\r
- if( (hf_max - hf_baseline) > (lf_max - lf_baseline) ) {\r
- display_val = hf_av;\r
- display_max = hf_max;\r
- } else {\r
- display_val = lf_av;\r
- display_max = lf_max;\r
- }\r
- }\r
- for (i=0; i<LIGHT_LEN; i++) {\r
- if (display_val >= ((display_max/LIGHT_LEN)*i) && display_val <= ((display_max/LIGHT_LEN)*(i+1))) {\r
- if (LIGHT_SCHEME[i] & 0x1) LED_C_ON(); else LED_C_OFF();\r
- if (LIGHT_SCHEME[i] & 0x2) LED_A_ON(); else LED_A_OFF();\r
- if (LIGHT_SCHEME[i] & 0x4) LED_B_ON(); else LED_B_OFF();\r
- if (LIGHT_SCHEME[i] & 0x8) LED_D_ON(); else LED_D_OFF();\r
- break;\r
- }\r
- }\r
- }\r
- }\r
-}\r
-\r
-void UsbPacketReceived(BYTE *packet, int len)\r
-{\r
- UsbCommand *c = (UsbCommand *)packet;\r
- UsbCommand ack;\r
- ack.cmd = CMD_ACK;\r
-\r
- switch(c->cmd) {\r
-#ifdef WITH_LF\r
- case CMD_ACQUIRE_RAW_ADC_SAMPLES_125K:\r
- AcquireRawAdcSamples125k(c->arg[0]);\r
- UsbSendPacket((BYTE*)&ack, sizeof(ack));\r
- break;\r
-#endif\r
-\r
-#ifdef WITH_LF\r
- case CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K:\r
- ModThenAcquireRawAdcSamples125k(c->arg[0],c->arg[1],c->arg[2],c->d.asBytes);\r
- break;\r
-#endif\r
-\r
-#ifdef WITH_ISO15693\r
- case CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693:\r
- AcquireRawAdcSamplesIso15693();\r
- break;\r
-#endif\r
-\r
- case CMD_BUFF_CLEAR:\r
- BufferClear();\r
- break;\r
-\r
-#ifdef WITH_ISO15693\r
- case CMD_READER_ISO_15693:\r
- ReaderIso15693(c->arg[0]);\r
- break;\r
-#endif\r
-\r
- case CMD_READER_LEGIC_RF:\r
- LegicRfReader(c->arg[0], c->arg[1]);\r
- break;
-\r
-#ifdef WITH_ISO15693\r
- case CMD_SIMTAG_ISO_15693:\r
- SimTagIso15693(c->arg[0]);\r
- break;\r
-#endif\r
-\r
-#ifdef WITH_ISO14443b\r
- case CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443:\r
- AcquireRawAdcSamplesIso14443(c->arg[0]);\r
- break;\r
-#endif\r
-\r
-#ifdef WITH_ISO14443b\r
- case CMD_READ_SRI512_TAG:\r
- ReadSRI512Iso14443(c->arg[0]);\r
- break;\r
- case CMD_READ_SRIX4K_TAG:\r
- ReadSRIX4KIso14443(c->arg[0]);\r
- break;\r
-#endif\r
-\r
-#ifdef WITH_ISO14443a\r
- case CMD_READER_ISO_14443a:\r
- ReaderIso14443a(c->arg[0]);\r
- break;\r
-#endif\r
-\r
-#ifdef WITH_ISO14443a\r
- case CMD_READER_MIFARE:\r
- ReaderMifare(c->arg[0]);\r
- break;\r
-#endif\r
- \r
-#ifdef WITH_ISO14443b\r
- case CMD_SNOOP_ISO_14443:\r
- SnoopIso14443();\r
- break;\r
-#endif\r
-\r
-#ifdef WITH_ISO14443a\r
- case CMD_SNOOP_ISO_14443a:\r
- SnoopIso14443a();\r
- break;\r
-#endif\r
-\r
- case CMD_SIMULATE_TAG_HF_LISTEN:\r
- SimulateTagHfListen();\r
- break;\r
-\r
-#ifdef WITH_ISO14443b\r
- case CMD_SIMULATE_TAG_ISO_14443:\r
- SimulateIso14443Tag();\r
- break;\r
-#endif\r
- \r
-#ifdef WITH_ISO14443a\r
- case CMD_SIMULATE_TAG_ISO_14443a:\r
- SimulateIso14443aTag(c->arg[0], c->arg[1]); // ## Simulate iso14443a tag - pass tag type & UID\r
- break;\r
-#endif\r
-\r
- case CMD_MEASURE_ANTENNA_TUNING:\r
- MeasureAntennaTuning();\r
- break;\r
-\r
- case CMD_MEASURE_ANTENNA_TUNING_HF:\r
- MeasureAntennaTuningHf();\r
- break;\r
-\r
- case CMD_LISTEN_READER_FIELD:\r
- ListenReaderField(c->arg[0]);\r
- break;\r
-\r
-#ifdef WITH_LF\r
- case CMD_HID_DEMOD_FSK:\r
- CmdHIDdemodFSK(0, 0, 0, 1); // Demodulate HID tag\r
- break;\r
-#endif\r
-\r
-#ifdef WITH_LF\r
- case CMD_HID_SIM_TAG:\r
- CmdHIDsimTAG(c->arg[0], c->arg[1], 1); // Simulate HID tag by ID\r
- break;\r
-#endif\r
-\r
- case CMD_FPGA_MAJOR_MODE_OFF: // ## FPGA Control\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
- SpinDelay(200);\r
- LED_D_OFF(); // LED D indicates field ON or OFF\r
- break;\r
-\r
-#ifdef WITH_LF\r
- case CMD_READ_TI_TYPE:\r
- ReadTItag();\r
- break;\r
-#endif\r
-\r
-#ifdef WITH_LF\r
- case CMD_WRITE_TI_TYPE:\r
- WriteTItag(c->arg[0],c->arg[1],c->arg[2]);\r
- break;\r
-#endif\r
-\r
- case CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K: {\r
- UsbCommand n;\r
- if(c->cmd == CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K) {\r
- n.cmd = CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K;\r
- } else {\r
- n.cmd = CMD_DOWNLOADED_RAW_BITS_TI_TYPE;\r
- }\r
- n.arg[0] = c->arg[0];\r
- memcpy(n.d.asDwords, BigBuf+c->arg[0], 12*sizeof(DWORD));\r
- UsbSendPacket((BYTE *)&n, sizeof(n));\r
- break;\r
- }\r
-\r
- case CMD_DOWNLOADED_SIM_SAMPLES_125K: {\r
- BYTE *b = (BYTE *)BigBuf;\r
- memcpy(b+c->arg[0], c->d.asBytes, 48);\r
- //Dbprintf("copied 48 bytes to %i",b+c->arg[0]);\r
- UsbSendPacket((BYTE*)&ack, sizeof(ack));\r
- break;\r
- }\r
-\r
-#ifdef WITH_LF\r
- case CMD_SIMULATE_TAG_125K:\r
- LED_A_ON();\r
- SimulateTagLowFrequency(c->arg[0], c->arg[1], 1);\r
- LED_A_OFF();\r
- break;\r
-#endif\r
-\r
- case CMD_READ_MEM:\r
- ReadMem(c->arg[0]);\r
- break;\r
-\r
- case CMD_SET_LF_DIVISOR:\r
- FpgaSendCommand(FPGA_CMD_SET_DIVISOR, c->arg[0]);\r
- break;\r
-\r
- case CMD_SET_ADC_MUX:\r
- switch(c->arg[0]) {\r
- case 0: SetAdcMuxFor(GPIO_MUXSEL_LOPKD); break;\r
- case 1: SetAdcMuxFor(GPIO_MUXSEL_LORAW); break;\r
- case 2: SetAdcMuxFor(GPIO_MUXSEL_HIPKD); break;\r
- case 3: SetAdcMuxFor(GPIO_MUXSEL_HIRAW); break;\r
- }\r
- break;\r
-\r
- case CMD_VERSION:\r
- SendVersion();\r
- break;\r
-\r
-#ifdef WITH_LF\r
- case CMD_LF_SIMULATE_BIDIR:\r
- SimulateTagLowFrequencyBidir(c->arg[0], c->arg[1]);\r
- break;\r
-#endif\r
-\r
-#ifdef WITH_LCD\r
- case CMD_LCD_RESET:\r
- LCDReset();\r
- break;\r
- case CMD_LCD:\r
- LCDSend(c->arg[0]);\r
- break;\r
-#endif\r
- case CMD_SETUP_WRITE:\r
- case CMD_FINISH_WRITE:\r
- case CMD_HARDWARE_RESET:\r
- USB_D_PLUS_PULLUP_OFF();\r
- SpinDelay(1000);\r
- SpinDelay(1000);\r
- AT91C_BASE_RSTC->RSTC_RCR = RST_CONTROL_KEY | AT91C_RSTC_PROCRST;\r
- for(;;) {\r
- // We're going to reset, and the bootrom will take control.\r
- }\r
- break;\r
-\r
- case CMD_START_FLASH:\r
- if(common_area.flags.bootrom_present) {\r
- common_area.command = COMMON_AREA_COMMAND_ENTER_FLASH_MODE;\r
- }\r
- USB_D_PLUS_PULLUP_OFF();\r
- AT91C_BASE_RSTC->RSTC_RCR = RST_CONTROL_KEY | AT91C_RSTC_PROCRST;\r
- for(;;);\r
- break;\r
- \r
- case CMD_DEVICE_INFO: {\r
- UsbCommand c;\r
- c.cmd = CMD_DEVICE_INFO;\r
- c.arg[0] = DEVICE_INFO_FLAG_OSIMAGE_PRESENT | DEVICE_INFO_FLAG_CURRENT_MODE_OS;\r
- if(common_area.flags.bootrom_present) c.arg[0] |= DEVICE_INFO_FLAG_BOOTROM_PRESENT;\r
- UsbSendPacket((BYTE*)&c, sizeof(c));\r
- }\r
- break;\r
- default:\r
- Dbprintf("%s: 0x%04x","unknown command:",c->cmd);\r
- break;\r
- }\r
-}\r
-\r
-void __attribute__((noreturn)) AppMain(void)\r
-{\r
- SpinDelay(100);\r
- \r
- if(common_area.magic != COMMON_AREA_MAGIC || common_area.version != 1) {\r
- /* Initialize common area */\r
- memset(&common_area, 0, sizeof(common_area));\r
- common_area.magic = COMMON_AREA_MAGIC;\r
- common_area.version = 1;\r
- }\r
- common_area.flags.osimage_present = 1;\r
-\r
- LED_D_OFF();\r
- LED_C_OFF();\r
- LED_B_OFF();\r
- LED_A_OFF();\r
-\r
- UsbStart();\r
-\r
- // The FPGA gets its clock from us from PCK0 output, so set that up.\r
- AT91C_BASE_PIOA->PIO_BSR = GPIO_PCK0;\r
- AT91C_BASE_PIOA->PIO_PDR = GPIO_PCK0;\r
- AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_PCK0;\r
- // PCK0 is PLL clock / 4 = 96Mhz / 4 = 24Mhz\r
- AT91C_BASE_PMC->PMC_PCKR[0] = AT91C_PMC_CSS_PLL_CLK |\r
- AT91C_PMC_PRES_CLK_4;\r
- AT91C_BASE_PIOA->PIO_OER = GPIO_PCK0;\r
-\r
- // Reset SPI\r
- AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SWRST;\r
- // Reset SSC\r
- AT91C_BASE_SSC->SSC_CR = AT91C_SSC_SWRST;\r
-\r
- // Load the FPGA image, which we have stored in our flash.\r
- FpgaDownloadAndGo();\r
-\r
-#ifdef WITH_LCD\r
-\r
- LCDInit();\r
-\r
- // test text on different colored backgrounds\r
- LCDString(" The quick brown fox ", (char *)&FONT6x8,1,1+8*0,WHITE ,BLACK );\r
- LCDString(" jumped over the ", (char *)&FONT6x8,1,1+8*1,BLACK ,WHITE );\r
- LCDString(" lazy dog. ", (char *)&FONT6x8,1,1+8*2,YELLOW ,RED );\r
- LCDString(" AaBbCcDdEeFfGgHhIiJj ", (char *)&FONT6x8,1,1+8*3,RED ,GREEN );\r
- LCDString(" KkLlMmNnOoPpQqRrSsTt ", (char *)&FONT6x8,1,1+8*4,MAGENTA,BLUE );\r
- LCDString("UuVvWwXxYyZz0123456789", (char *)&FONT6x8,1,1+8*5,BLUE ,YELLOW);\r
- LCDString("`-=[]_;',./~!@#$%^&*()", (char *)&FONT6x8,1,1+8*6,BLACK ,CYAN );\r
- LCDString(" _+{}|:\\\"<>? ",(char *)&FONT6x8,1,1+8*7,BLUE ,MAGENTA);\r
-\r
- // color bands\r
- LCDFill(0, 1+8* 8, 132, 8, BLACK);\r
- LCDFill(0, 1+8* 9, 132, 8, WHITE);\r
- LCDFill(0, 1+8*10, 132, 8, RED);\r
- LCDFill(0, 1+8*11, 132, 8, GREEN);\r
- LCDFill(0, 1+8*12, 132, 8, BLUE);\r
- LCDFill(0, 1+8*13, 132, 8, YELLOW);\r
- LCDFill(0, 1+8*14, 132, 8, CYAN);\r
- LCDFill(0, 1+8*15, 132, 8, MAGENTA);\r
-\r
-#endif\r
-\r
- for(;;) {\r
- UsbPoll(FALSE);\r
- WDT_HIT();\r
-\r
-#ifdef WITH_LF\r
- if (BUTTON_HELD(1000) > 0)\r
- SamyRun();\r
-#endif\r
- }\r
-}\r
+//-----------------------------------------------------------------------------
+// The main application code. This is the first thing called after start.c
+// executes.
+// Jonathan Westhues, Mar 2006
+// Edits by Gerhard de Koning Gans, Sep 2007 (##)
+//-----------------------------------------------------------------------------
+
+#include <proxmark3.h>
+#include "apps.h"
+#include "legicrf.h"
+#ifdef WITH_LCD
+#include "fonts.h"
+#include "LCD.h"
+#endif
+
+#define va_list __builtin_va_list
+#define va_start __builtin_va_start
+#define va_arg __builtin_va_arg
+#define va_end __builtin_va_end
+int kvsprintf(char const *fmt, void *arg, int radix, va_list ap);
+
+
+#define abs(x) ( ((x)<0) ? -(x) : (x) )
+
+//=============================================================================
+// A buffer where we can queue things up to be sent through the FPGA, for
+// any purpose (fake tag, as reader, whatever). We go MSB first, since that
+// is the order in which they go out on the wire.
+//=============================================================================
+
+BYTE ToSend[512];
+int ToSendMax;
+static int ToSendBit;
+struct common_area common_area __attribute__((section(".commonarea")));
+
+void BufferClear(void)
+{
+ memset(BigBuf,0,sizeof(BigBuf));
+ Dbprintf("Buffer cleared (%i bytes)",sizeof(BigBuf));
+}
+
+void ToSendReset(void)
+{
+ ToSendMax = -1;
+ ToSendBit = 8;
+}
+
+void ToSendStuffBit(int b)
+{
+ if(ToSendBit >= 8) {
+ ToSendMax++;
+ ToSend[ToSendMax] = 0;
+ ToSendBit = 0;
+ }
+
+ if(b) {
+ ToSend[ToSendMax] |= (1 << (7 - ToSendBit));
+ }
+
+ ToSendBit++;
+
+ if(ToSendBit >= sizeof(ToSend)) {
+ ToSendBit = 0;
+ DbpString("ToSendStuffBit overflowed!");
+ }
+}
+
+//=============================================================================
+// Debug print functions, to go out over USB, to the usual PC-side client.
+//=============================================================================
+
+void DbpString(char *str)
+{
+ /* this holds up stuff unless we're connected to usb */
+ if (!UsbConnected())
+ return;
+
+ UsbCommand c;
+ c.cmd = CMD_DEBUG_PRINT_STRING;
+ c.arg[0] = strlen(str);
+ if(c.arg[0] > sizeof(c.d.asBytes)) {
+ c.arg[0] = sizeof(c.d.asBytes);
+ }
+ memcpy(c.d.asBytes, str, c.arg[0]);
+
+ UsbSendPacket((BYTE *)&c, sizeof(c));
+ // TODO fix USB so stupid things like this aren't req'd
+ SpinDelay(50);
+}
+
+#if 0
+void DbpIntegers(int x1, int x2, int x3)
+{
+ /* this holds up stuff unless we're connected to usb */
+ if (!UsbConnected())
+ return;
+
+ UsbCommand c;
+ c.cmd = CMD_DEBUG_PRINT_INTEGERS;
+ c.arg[0] = x1;
+ c.arg[1] = x2;
+ c.arg[2] = x3;
+
+ UsbSendPacket((BYTE *)&c, sizeof(c));
+ // XXX
+ SpinDelay(50);
+}
+#endif
+
+void Dbprintf(const char *fmt, ...) {
+// should probably limit size here; oh well, let's just use a big buffer
+ char output_string[128];
+ va_list ap;
+
+ va_start(ap, fmt);
+ kvsprintf(fmt, output_string, 10, ap);
+ va_end(ap);
+
+ DbpString(output_string);
+}
+
+//-----------------------------------------------------------------------------
+// Read an ADC channel and block till it completes, then return the result
+// in ADC units (0 to 1023). Also a routine to average 32 samples and
+// return that.
+//-----------------------------------------------------------------------------
+static int ReadAdc(int ch)
+{
+ DWORD d;
+
+ AT91C_BASE_ADC->ADC_CR = AT91C_ADC_SWRST;
+ AT91C_BASE_ADC->ADC_MR =
+ ADC_MODE_PRESCALE(32) |
+ ADC_MODE_STARTUP_TIME(16) |
+ ADC_MODE_SAMPLE_HOLD_TIME(8);
+ AT91C_BASE_ADC->ADC_CHER = ADC_CHANNEL(ch);
+
+ AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START;
+ while(!(AT91C_BASE_ADC->ADC_SR & ADC_END_OF_CONVERSION(ch)))
+ ;
+ d = AT91C_BASE_ADC->ADC_CDR[ch];
+
+ return d;
+}
+
+static int AvgAdc(int ch)
+{
+ int i;
+ int a = 0;
+
+ for(i = 0; i < 32; i++) {
+ a += ReadAdc(ch);
+ }
+
+ return (a + 15) >> 5;
+}
+
+void MeasureAntennaTuning(void)
+{
+ BYTE *dest = (BYTE *)BigBuf;
+ int i, ptr = 0, adcval = 0, peak = 0, peakv = 0, peakf = 0;;
+ int vLf125 = 0, vLf134 = 0, vHf = 0; // in mV
+
+ UsbCommand c;
+
+ DbpString("Measuring antenna characteristics, please wait.");
+ memset(BigBuf,0,sizeof(BigBuf));
+
+/*
+ * Sweeps the useful LF range of the proxmark from
+ * 46.8kHz (divisor=255) to 600kHz (divisor=19) and
+ * read the voltage in the antenna, the result left
+ * in the buffer is a graph which should clearly show
+ * the resonating frequency of your LF antenna
+ * ( hopefully around 95 if it is tuned to 125kHz!)
+ */
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);
+ for (i=255; i>19; i--) {
+ FpgaSendCommand(FPGA_CMD_SET_DIVISOR, i);
+ SpinDelay(20);
+ // Vref = 3.3V, and a 10000:240 voltage divider on the input
+ // can measure voltages up to 137500 mV
+ adcval = ((137500 * AvgAdc(ADC_CHAN_LF)) >> 10);
+ if (i==95) vLf125 = adcval; // voltage at 125Khz
+ if (i==89) vLf134 = adcval; // voltage at 134Khz
+
+ dest[i] = adcval>>8; // scale int to fit in byte for graphing purposes
+ if(dest[i] > peak) {
+ peakv = adcval;
+ peak = dest[i];
+ peakf = i;
+ ptr = i;
+ }
+ }
+
+ // Let the FPGA drive the high-frequency antenna around 13.56 MHz.
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
+ SpinDelay(20);
+ // Vref = 3300mV, and an 10:1 voltage divider on the input
+ // can measure voltages up to 33000 mV
+ vHf = (33000 * AvgAdc(ADC_CHAN_HF)) >> 10;
+
+ c.cmd = CMD_MEASURED_ANTENNA_TUNING;
+ c.arg[0] = (vLf125 << 0) | (vLf134 << 16);
+ c.arg[1] = vHf;
+ c.arg[2] = peakf | (peakv << 16);
+ UsbSendPacket((BYTE *)&c, sizeof(c));
+}
+
+void MeasureAntennaTuningHf(void)
+{
+ int vHf = 0; // in mV
+
+ DbpString("Measuring HF antenna, press button to exit");
+
+ for (;;) {
+ // Let the FPGA drive the high-frequency antenna around 13.56 MHz.
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
+ SpinDelay(20);
+ // Vref = 3300mV, and an 10:1 voltage divider on the input
+ // can measure voltages up to 33000 mV
+ vHf = (33000 * AvgAdc(ADC_CHAN_HF)) >> 10;
+
+ Dbprintf("%d mV",vHf);
+ if (BUTTON_PRESS()) break;
+ }
+ DbpString("cancelled");
+}
+
+
+void SimulateTagHfListen(void)
+{
+ BYTE *dest = (BYTE *)BigBuf;
+ int n = sizeof(BigBuf);
+ BYTE v = 0;
+ int i;
+ int p = 0;
+
+ // We're using this mode just so that I can test it out; the simulated
+ // tag mode would work just as well and be simpler.
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ | FPGA_HF_READER_RX_XCORR_SNOOP);
+
+ // We need to listen to the high-frequency, peak-detected path.
+ SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
+
+ FpgaSetupSsc();
+
+ i = 0;
+ for(;;) {
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
+ AT91C_BASE_SSC->SSC_THR = 0xff;
+ }
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
+ BYTE r = (BYTE)AT91C_BASE_SSC->SSC_RHR;
+
+ v <<= 1;
+ if(r & 1) {
+ v |= 1;
+ }
+ p++;
+
+ if(p >= 8) {
+ dest[i] = v;
+ v = 0;
+ p = 0;
+ i++;
+
+ if(i >= n) {
+ break;
+ }
+ }
+ }
+ }
+ DbpString("simulate tag (now type bitsamples)");
+}
+
+void ReadMem(int addr)
+{
+ const BYTE *data = ((BYTE *)addr);
+
+ Dbprintf("%x: %02x %02x %02x %02x %02x %02x %02x %02x",
+ addr, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]);
+}
+
+/* osimage version information is linked in */
+extern struct version_information version_information;
+/* bootrom version information is pointed to from _bootphase1_version_pointer */
+extern char *_bootphase1_version_pointer, _flash_start, _flash_end;
+void SendVersion(void)
+{
+ char temp[48]; /* Limited data payload in USB packets */
+ DbpString("Prox/RFID mark3 RFID instrument");
+
+ /* Try to find the bootrom version information. Expect to find a pointer at
+ * symbol _bootphase1_version_pointer, perform slight sanity checks on the
+ * pointer, then use it.
+ */
+ char *bootrom_version = *(char**)&_bootphase1_version_pointer;
+ if( bootrom_version < &_flash_start || bootrom_version >= &_flash_end ) {
+ DbpString("bootrom version information appears invalid");
+ } else {
+ FormatVersionInformation(temp, sizeof(temp), "bootrom: ", bootrom_version);
+ DbpString(temp);
+ }
+
+ FormatVersionInformation(temp, sizeof(temp), "os: ", &version_information);
+ DbpString(temp);
+
+ FpgaGatherVersion(temp, sizeof(temp));
+ DbpString(temp);
+}
+
+#ifdef WITH_LF
+// samy's sniff and repeat routine
+void SamyRun()
+{
+ DbpString("Stand-alone mode! No PC necessary.");
+
+ // 3 possible options? no just 2 for now
+#define OPTS 2
+
+ int high[OPTS], low[OPTS];
+
+ // Oooh pretty -- notify user we're in elite samy mode now
+ LED(LED_RED, 200);
+ LED(LED_ORANGE, 200);
+ LED(LED_GREEN, 200);
+ LED(LED_ORANGE, 200);
+ LED(LED_RED, 200);
+ LED(LED_ORANGE, 200);
+ LED(LED_GREEN, 200);
+ LED(LED_ORANGE, 200);
+ LED(LED_RED, 200);
+
+ int selected = 0;
+ int playing = 0;
+
+ // Turn on selected LED
+ LED(selected + 1, 0);
+
+ for (;;)
+ {
+ UsbPoll(FALSE);
+ WDT_HIT();
+
+ // Was our button held down or pressed?
+ int button_pressed = BUTTON_HELD(1000);
+ SpinDelay(300);
+
+ // Button was held for a second, begin recording
+ if (button_pressed > 0)
+ {
+ LEDsoff();
+ LED(selected + 1, 0);
+ LED(LED_RED2, 0);
+
+ // record
+ DbpString("Starting recording");
+
+ // wait for button to be released
+ while(BUTTON_PRESS())
+ WDT_HIT();
+
+ /* need this delay to prevent catching some weird data */
+ SpinDelay(500);
+
+ CmdHIDdemodFSK(1, &high[selected], &low[selected], 0);
+ Dbprintf("Recorded %x %x %x", selected, high[selected], low[selected]);
+
+ LEDsoff();
+ LED(selected + 1, 0);
+ // Finished recording
+
+ // If we were previously playing, set playing off
+ // so next button push begins playing what we recorded
+ playing = 0;
+ }
+
+ // Change where to record (or begin playing)
+ else if (button_pressed)
+ {
+ // Next option if we were previously playing
+ if (playing)
+ selected = (selected + 1) % OPTS;
+ playing = !playing;
+
+ LEDsoff();
+ LED(selected + 1, 0);
+
+ // Begin transmitting
+ if (playing)
+ {
+ LED(LED_GREEN, 0);
+ DbpString("Playing");
+ // wait for button to be released
+ while(BUTTON_PRESS())
+ WDT_HIT();
+ Dbprintf("%x %x %x", selected, high[selected], low[selected]);
+ CmdHIDsimTAG(high[selected], low[selected], 0);
+ DbpString("Done playing");
+ if (BUTTON_HELD(1000) > 0)
+ {
+ DbpString("Exiting");
+ LEDsoff();
+ return;
+ }
+
+ /* We pressed a button so ignore it here with a delay */
+ SpinDelay(300);
+
+ // when done, we're done playing, move to next option
+ selected = (selected + 1) % OPTS;
+ playing = !playing;
+ LEDsoff();
+ LED(selected + 1, 0);
+ }
+ else
+ while(BUTTON_PRESS())
+ WDT_HIT();
+ }
+ }
+}
+#endif
+
+/*
+OBJECTIVE
+Listen and detect an external reader. Determine the best location
+for the antenna.
+
+INSTRUCTIONS:
+Inside the ListenReaderField() function, there is two mode.
+By default, when you call the function, you will enter mode 1.
+If you press the PM3 button one time, you will enter mode 2.
+If you press the PM3 button a second time, you will exit the function.
+
+DESCRIPTION OF MODE 1:
+This mode just listens for an external reader field and lights up green
+for HF and/or red for LF. This is the original mode of the detectreader
+function.
+
+DESCRIPTION OF MODE 2:
+This mode will visually represent, using the LEDs, the actual strength of the
+current compared to the maximum current detected. Basically, once you know
+what kind of external reader is present, it will help you spot the best location to place
+your antenna. You will probably not get some good results if there is a LF and a HF reader
+at the same place! :-)
+
+LIGHT SCHEME USED:
+*/
+static const char LIGHT_SCHEME[] = {
+ 0x0, /* ---- | No field detected */
+ 0x1, /* X--- | 14% of maximum current detected */
+ 0x2, /* -X-- | 29% of maximum current detected */
+ 0x4, /* --X- | 43% of maximum current detected */
+ 0x8, /* ---X | 57% of maximum current detected */
+ 0xC, /* --XX | 71% of maximum current detected */
+ 0xE, /* -XXX | 86% of maximum current detected */
+ 0xF, /* XXXX | 100% of maximum current detected */
+};
+static const int LIGHT_LEN = sizeof(LIGHT_SCHEME)/sizeof(LIGHT_SCHEME[0]);
+
+void ListenReaderField(int limit)
+{
+ int lf_av, lf_av_new, lf_baseline= 0, lf_count= 0, lf_max;
+ int hf_av, hf_av_new, hf_baseline= 0, hf_count= 0, hf_max;
+ int mode=1, display_val, display_max, i;
+
+#define LF_ONLY 1
+#define HF_ONLY 2
+
+ LEDsoff();
+
+ lf_av=lf_max=ReadAdc(ADC_CHAN_LF);
+
+ if(limit != HF_ONLY) {
+ Dbprintf("LF 125/134 Baseline: %d", lf_av);
+ lf_baseline = lf_av;
+ }
+
+ hf_av=hf_max=ReadAdc(ADC_CHAN_HF);
+
+ if (limit != LF_ONLY) {
+ Dbprintf("HF 13.56 Baseline: %d", hf_av);
+ hf_baseline = hf_av;
+ }
+
+ for(;;) {
+ if (BUTTON_PRESS()) {
+ SpinDelay(500);
+ switch (mode) {
+ case 1:
+ mode=2;
+ DbpString("Signal Strength Mode");
+ break;
+ case 2:
+ default:
+ DbpString("Stopped");
+ LEDsoff();
+ return;
+ break;
+ }
+ }
+ WDT_HIT();
+
+ if (limit != HF_ONLY) {
+ if(mode==1) {
+ if (abs(lf_av - lf_baseline) > 10) LED_D_ON();
+ else LED_D_OFF();
+ }
+
+ ++lf_count;
+ lf_av_new= ReadAdc(ADC_CHAN_LF);
+ // see if there's a significant change
+ if(abs(lf_av - lf_av_new) > 10) {
+ Dbprintf("LF 125/134 Field Change: %x %x %x", lf_av, lf_av_new, lf_count);
+ lf_av = lf_av_new;
+ if (lf_av > lf_max)
+ lf_max = lf_av;
+ lf_count= 0;
+ }
+ }
+
+ if (limit != LF_ONLY) {
+ if (mode == 1){
+ if (abs(hf_av - hf_baseline) > 10) LED_B_ON();
+ else LED_B_OFF();
+ }
+
+ ++hf_count;
+ hf_av_new= ReadAdc(ADC_CHAN_HF);
+ // see if there's a significant change
+ if(abs(hf_av - hf_av_new) > 10) {
+ Dbprintf("HF 13.56 Field Change: %x %x %x", hf_av, hf_av_new, hf_count);
+ hf_av = hf_av_new;
+ if (hf_av > hf_max)
+ hf_max = hf_av;
+ hf_count= 0;
+ }
+ }
+
+ if(mode == 2) {
+ if (limit == LF_ONLY) {
+ display_val = lf_av;
+ display_max = lf_max;
+ } else if (limit == HF_ONLY) {
+ display_val = hf_av;
+ display_max = hf_max;
+ } else { /* Pick one at random */
+ if( (hf_max - hf_baseline) > (lf_max - lf_baseline) ) {
+ display_val = hf_av;
+ display_max = hf_max;
+ } else {
+ display_val = lf_av;
+ display_max = lf_max;
+ }
+ }
+ for (i=0; i<LIGHT_LEN; i++) {
+ if (display_val >= ((display_max/LIGHT_LEN)*i) && display_val <= ((display_max/LIGHT_LEN)*(i+1))) {
+ if (LIGHT_SCHEME[i] & 0x1) LED_C_ON(); else LED_C_OFF();
+ if (LIGHT_SCHEME[i] & 0x2) LED_A_ON(); else LED_A_OFF();
+ if (LIGHT_SCHEME[i] & 0x4) LED_B_ON(); else LED_B_OFF();
+ if (LIGHT_SCHEME[i] & 0x8) LED_D_ON(); else LED_D_OFF();
+ break;
+ }
+ }
+ }
+ }
+}
+
+void UsbPacketReceived(BYTE *packet, int len)
+{
+ UsbCommand *c = (UsbCommand *)packet;
+ UsbCommand ack;
+ ack.cmd = CMD_ACK;
+
+ switch(c->cmd) {
+#ifdef WITH_LF
+ case CMD_ACQUIRE_RAW_ADC_SAMPLES_125K:
+ AcquireRawAdcSamples125k(c->arg[0]);
+ UsbSendPacket((BYTE*)&ack, sizeof(ack));
+ break;
+#endif
+
+#ifdef WITH_LF
+ case CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K:
+ ModThenAcquireRawAdcSamples125k(c->arg[0],c->arg[1],c->arg[2],c->d.asBytes);
+ break;
+#endif
+
+#ifdef WITH_ISO15693
+ case CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693:
+ AcquireRawAdcSamplesIso15693();
+ break;
+#endif
+
+ case CMD_BUFF_CLEAR:
+ BufferClear();
+ break;
+
+#ifdef WITH_ISO15693
+ case CMD_READER_ISO_15693:
+ ReaderIso15693(c->arg[0]);
+ break;
+#endif
+
+ case CMD_READER_LEGIC_RF:
+ LegicRfReader(c->arg[0], c->arg[1]);
+ break;
+
+#ifdef WITH_ISO15693
+ case CMD_SIMTAG_ISO_15693:
+ SimTagIso15693(c->arg[0]);
+ break;
+#endif
+
+#ifdef WITH_ISO14443b
+ case CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443:
+ AcquireRawAdcSamplesIso14443(c->arg[0]);
+ break;
+#endif
+
+#ifdef WITH_ISO14443b
+ case CMD_READ_SRI512_TAG:
+ ReadSRI512Iso14443(c->arg[0]);
+ break;
+ case CMD_READ_SRIX4K_TAG:
+ ReadSRIX4KIso14443(c->arg[0]);
+ break;
+#endif
+
+#ifdef WITH_ISO14443a
+ case CMD_READER_ISO_14443a:
+ ReaderIso14443a(c->arg[0]);
+ break;
+#endif
+
+#ifdef WITH_ISO14443a
+ case CMD_READER_MIFARE:
+ ReaderMifare(c->arg[0]);
+ break;
+#endif
+
+#ifdef WITH_ISO14443b
+ case CMD_SNOOP_ISO_14443:
+ SnoopIso14443();
+ break;
+#endif
+
+#ifdef WITH_ISO14443a
+ case CMD_SNOOP_ISO_14443a:
+ SnoopIso14443a();
+ break;
+#endif
+
+ case CMD_SIMULATE_TAG_HF_LISTEN:
+ SimulateTagHfListen();
+ break;
+
+#ifdef WITH_ISO14443b
+ case CMD_SIMULATE_TAG_ISO_14443:
+ SimulateIso14443Tag();
+ break;
+#endif
+
+#ifdef WITH_ISO14443a
+ case CMD_SIMULATE_TAG_ISO_14443a:
+ SimulateIso14443aTag(c->arg[0], c->arg[1]); // ## Simulate iso14443a tag - pass tag type & UID
+ break;
+#endif
+
+ case CMD_MEASURE_ANTENNA_TUNING:
+ MeasureAntennaTuning();
+ break;
+
+ case CMD_MEASURE_ANTENNA_TUNING_HF:
+ MeasureAntennaTuningHf();
+ break;
+
+ case CMD_LISTEN_READER_FIELD:
+ ListenReaderField(c->arg[0]);
+ break;
+
+#ifdef WITH_LF
+ case CMD_HID_DEMOD_FSK:
+ CmdHIDdemodFSK(0, 0, 0, 1); // Demodulate HID tag
+ break;
+#endif
+
+#ifdef WITH_LF
+ case CMD_HID_SIM_TAG:
+ CmdHIDsimTAG(c->arg[0], c->arg[1], 1); // Simulate HID tag by ID
+ break;
+#endif
+
+ case CMD_FPGA_MAJOR_MODE_OFF: // ## FPGA Control
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+ SpinDelay(200);
+ LED_D_OFF(); // LED D indicates field ON or OFF
+ break;
+
+#ifdef WITH_LF
+ case CMD_READ_TI_TYPE:
+ ReadTItag();
+ break;
+#endif
+
+#ifdef WITH_LF
+ case CMD_WRITE_TI_TYPE:
+ WriteTItag(c->arg[0],c->arg[1],c->arg[2]);
+ break;
+#endif
+
+ case CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K: {
+ UsbCommand n;
+ if(c->cmd == CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K) {
+ n.cmd = CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K;
+ } else {
+ n.cmd = CMD_DOWNLOADED_RAW_BITS_TI_TYPE;
+ }
+ n.arg[0] = c->arg[0];
+ memcpy(n.d.asDwords, BigBuf+c->arg[0], 12*sizeof(DWORD));
+ UsbSendPacket((BYTE *)&n, sizeof(n));
+ break;
+ }
+
+ case CMD_DOWNLOADED_SIM_SAMPLES_125K: {
+ BYTE *b = (BYTE *)BigBuf;
+ memcpy(b+c->arg[0], c->d.asBytes, 48);
+ //Dbprintf("copied 48 bytes to %i",b+c->arg[0]);
+ UsbSendPacket((BYTE*)&ack, sizeof(ack));
+ break;
+ }
+
+#ifdef WITH_LF
+ case CMD_SIMULATE_TAG_125K:
+ LED_A_ON();
+ SimulateTagLowFrequency(c->arg[0], c->arg[1], 1);
+ LED_A_OFF();
+ break;
+#endif
+
+ case CMD_READ_MEM:
+ ReadMem(c->arg[0]);
+ break;
+
+ case CMD_SET_LF_DIVISOR:
+ FpgaSendCommand(FPGA_CMD_SET_DIVISOR, c->arg[0]);
+ break;
+
+ case CMD_SET_ADC_MUX:
+ switch(c->arg[0]) {
+ case 0: SetAdcMuxFor(GPIO_MUXSEL_LOPKD); break;
+ case 1: SetAdcMuxFor(GPIO_MUXSEL_LORAW); break;
+ case 2: SetAdcMuxFor(GPIO_MUXSEL_HIPKD); break;
+ case 3: SetAdcMuxFor(GPIO_MUXSEL_HIRAW); break;
+ }
+ break;
+
+ case CMD_VERSION:
+ SendVersion();
+ break;
+
+#ifdef WITH_LF
+ case CMD_LF_SIMULATE_BIDIR:
+ SimulateTagLowFrequencyBidir(c->arg[0], c->arg[1]);
+ break;
+#endif
+
+#ifdef WITH_LCD
+ case CMD_LCD_RESET:
+ LCDReset();
+ break;
+ case CMD_LCD:
+ LCDSend(c->arg[0]);
+ break;
+#endif
+ case CMD_SETUP_WRITE:
+ case CMD_FINISH_WRITE:
+ case CMD_HARDWARE_RESET:
+ USB_D_PLUS_PULLUP_OFF();
+ SpinDelay(1000);
+ SpinDelay(1000);
+ AT91C_BASE_RSTC->RSTC_RCR = RST_CONTROL_KEY | AT91C_RSTC_PROCRST;
+ for(;;) {
+ // We're going to reset, and the bootrom will take control.
+ }
+ break;
+
+ case CMD_START_FLASH:
+ if(common_area.flags.bootrom_present) {
+ common_area.command = COMMON_AREA_COMMAND_ENTER_FLASH_MODE;
+ }
+ USB_D_PLUS_PULLUP_OFF();
+ AT91C_BASE_RSTC->RSTC_RCR = RST_CONTROL_KEY | AT91C_RSTC_PROCRST;
+ for(;;);
+ break;
+
+ case CMD_DEVICE_INFO: {
+ UsbCommand c;
+ c.cmd = CMD_DEVICE_INFO;
+ c.arg[0] = DEVICE_INFO_FLAG_OSIMAGE_PRESENT | DEVICE_INFO_FLAG_CURRENT_MODE_OS;
+ if(common_area.flags.bootrom_present) c.arg[0] |= DEVICE_INFO_FLAG_BOOTROM_PRESENT;
+ UsbSendPacket((BYTE*)&c, sizeof(c));
+ }
+ break;
+ default:
+ Dbprintf("%s: 0x%04x","unknown command:",c->cmd);
+ break;
+ }
+}
+
+void __attribute__((noreturn)) AppMain(void)
+{
+ SpinDelay(100);
+
+ if(common_area.magic != COMMON_AREA_MAGIC || common_area.version != 1) {
+ /* Initialize common area */
+ memset(&common_area, 0, sizeof(common_area));
+ common_area.magic = COMMON_AREA_MAGIC;
+ common_area.version = 1;
+ }
+ common_area.flags.osimage_present = 1;
+
+ LED_D_OFF();
+ LED_C_OFF();
+ LED_B_OFF();
+ LED_A_OFF();
+
+ UsbStart();
+
+ // The FPGA gets its clock from us from PCK0 output, so set that up.
+ AT91C_BASE_PIOA->PIO_BSR = GPIO_PCK0;
+ AT91C_BASE_PIOA->PIO_PDR = GPIO_PCK0;
+ AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_PCK0;
+ // PCK0 is PLL clock / 4 = 96Mhz / 4 = 24Mhz
+ AT91C_BASE_PMC->PMC_PCKR[0] = AT91C_PMC_CSS_PLL_CLK |
+ AT91C_PMC_PRES_CLK_4;
+ AT91C_BASE_PIOA->PIO_OER = GPIO_PCK0;
+
+ // Reset SPI
+ AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SWRST;
+ // Reset SSC
+ AT91C_BASE_SSC->SSC_CR = AT91C_SSC_SWRST;
+
+ // Load the FPGA image, which we have stored in our flash.
+ FpgaDownloadAndGo();
+
+#ifdef WITH_LCD
+
+ LCDInit();
+
+ // test text on different colored backgrounds
+ LCDString(" The quick brown fox ", (char *)&FONT6x8,1,1+8*0,WHITE ,BLACK );
+ LCDString(" jumped over the ", (char *)&FONT6x8,1,1+8*1,BLACK ,WHITE );
+ LCDString(" lazy dog. ", (char *)&FONT6x8,1,1+8*2,YELLOW ,RED );
+ LCDString(" AaBbCcDdEeFfGgHhIiJj ", (char *)&FONT6x8,1,1+8*3,RED ,GREEN );
+ LCDString(" KkLlMmNnOoPpQqRrSsTt ", (char *)&FONT6x8,1,1+8*4,MAGENTA,BLUE );
+ LCDString("UuVvWwXxYyZz0123456789", (char *)&FONT6x8,1,1+8*5,BLUE ,YELLOW);
+ LCDString("`-=[]_;',./~!@#$%^&*()", (char *)&FONT6x8,1,1+8*6,BLACK ,CYAN );
+ LCDString(" _+{}|:\\\"<>? ",(char *)&FONT6x8,1,1+8*7,BLUE ,MAGENTA);
+
+ // color bands
+ LCDFill(0, 1+8* 8, 132, 8, BLACK);
+ LCDFill(0, 1+8* 9, 132, 8, WHITE);
+ LCDFill(0, 1+8*10, 132, 8, RED);
+ LCDFill(0, 1+8*11, 132, 8, GREEN);
+ LCDFill(0, 1+8*12, 132, 8, BLUE);
+ LCDFill(0, 1+8*13, 132, 8, YELLOW);
+ LCDFill(0, 1+8*14, 132, 8, CYAN);
+ LCDFill(0, 1+8*15, 132, 8, MAGENTA);
+
+#endif
+
+ for(;;) {
+ UsbPoll(FALSE);
+ WDT_HIT();
+
+#ifdef WITH_LF
+ if (BUTTON_HELD(1000) > 0)
+ SamyRun();
+#endif
+ }
+}
-//-----------------------------------------------------------------------------\r
-// Definitions internal to the app source.\r
-// Jonathan Westhues, Aug 2005\r
-// Added ISO14443-A support by Gerhard de Koning Gans, April 2008\r
-//-----------------------------------------------------------------------------\r
-\r
-#ifndef __APPS_H\r
-#define __APPS_H\r
-\r
-#include "stdint.h"\r
-#include "stddef.h"\r
-typedef unsigned char byte_t;\r
-\r
-// The large multi-purpose buffer, typically used to hold A/D samples,\r
-// maybe processed in some way.\r
-DWORD BigBuf[8000];\r
-\r
-/// appmain.h\r
-void ReadMem(int addr);\r
-void __attribute__((noreturn)) AppMain(void);\r
-void SamyRun(void);\r
-//void DbpIntegers(int a, int b, int c);\r
-void DbpString(char *str);\r
-void Dbprintf(const char *fmt, ...);\r
-\r
-void ToSendStuffBit(int b);\r
-void ToSendReset(void);\r
-void ListenReaderField(int limit);\r
-void AcquireRawAdcSamples125k(BOOL at134khz);\r
-void DoAcquisition125k(void);\r
-extern int ToSendMax;\r
-extern BYTE ToSend[];\r
-extern DWORD BigBuf[];\r
-\r
-/// fpga.h\r
-void FpgaSendCommand(WORD cmd, WORD v);\r
-void FpgaWriteConfWord(BYTE v);\r
-void FpgaDownloadAndGo(void);\r
-void FpgaGatherVersion(char *dst, int len);\r
-void FpgaSetupSsc(void);\r
-void SetupSpi(int mode);\r
-void FpgaSetupSscDma(BYTE *buf, int len);\r
-void SetAdcMuxFor(DWORD whichGpio);\r
-\r
-// Definitions for the FPGA commands.\r
-#define FPGA_CMD_SET_CONFREG (1<<12)\r
-#define FPGA_CMD_SET_DIVISOR (2<<12)\r
-// Definitions for the FPGA configuration word.\r
-#define FPGA_MAJOR_MODE_LF_READER (0<<5)\r
-#define FPGA_MAJOR_MODE_LF_SIMULATOR (1<<5)\r
-#define FPGA_MAJOR_MODE_HF_READER_TX (2<<5)\r
-#define FPGA_MAJOR_MODE_HF_READER_RX_XCORR (3<<5)\r
-#define FPGA_MAJOR_MODE_HF_SIMULATOR (4<<5)\r
-#define FPGA_MAJOR_MODE_HF_ISO14443A (5<<5)\r
-#define FPGA_MAJOR_MODE_LF_PASSTHRU (6<<5)\r
-#define FPGA_MAJOR_MODE_OFF (7<<5)\r
-// Options for the HF reader, tx to tag\r
-#define FPGA_HF_READER_TX_SHALLOW_MOD (1<<0)\r
-// Options for the HF reader, correlating against rx from tag\r
-#define FPGA_HF_READER_RX_XCORR_848_KHZ (1<<0)\r
-#define FPGA_HF_READER_RX_XCORR_SNOOP (1<<1)\r
-#define FPGA_HF_READER_RX_XCORR_QUARTER_FREQ (1<<2)\r
-// Options for the HF simulated tag, how to modulate\r
-#define FPGA_HF_SIMULATOR_NO_MODULATION (0<<0)\r
-#define FPGA_HF_SIMULATOR_MODULATE_BPSK (1<<0)\r
-#define FPGA_HF_SIMULATOR_MODULATE_212K (2<<0)\r
-// Options for ISO14443A\r
-#define FPGA_HF_ISO14443A_SNIFFER (0<<0)\r
-#define FPGA_HF_ISO14443A_TAGSIM_LISTEN (1<<0)\r
-#define FPGA_HF_ISO14443A_TAGSIM_MOD (2<<0)\r
-#define FPGA_HF_ISO14443A_READER_LISTEN (3<<0)\r
-#define FPGA_HF_ISO14443A_READER_MOD (4<<0)\r
-\r
-/// lfops.h\r
-void AcquireRawAdcSamples125k(BOOL at134khz);\r
-void ModThenAcquireRawAdcSamples125k(int delay_off,int period_0,int period_1,BYTE *command);\r
-void ReadTItag(void);\r
-void WriteTItag(DWORD idhi, DWORD idlo, WORD crc);\r
-void AcquireTiType(void);\r
-void AcquireRawBitsTI(void);\r
-void SimulateTagLowFrequency(int period, int gap, int ledcontrol);\r
-void CmdHIDsimTAG(int hi, int lo, int ledcontrol);\r
-void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol);\r
-void SimulateTagLowFrequencyBidir(int divisor, int max_bitlen);\r
-\r
-/// iso14443.h\r
-void SimulateIso14443Tag(void);\r
-void AcquireRawAdcSamplesIso14443(DWORD parameter);\r
-void ReadSRI512Iso14443(DWORD parameter);\r
-void ReadSRIX4KIso14443(DWORD parameter);\r
-void ReadSTMemoryIso14443(DWORD parameter,DWORD dwLast);\r
-void SnoopIso14443(void);\r
-\r
-/// iso14443a.h\r
-void SnoopIso14443a(void);\r
-void SimulateIso14443aTag(int tagType, int TagUid); // ## simulate iso14443a tag\r
-void ReaderIso14443a(DWORD parameter);\r
-void ReaderMifare(DWORD parameter);\r
-\r
-/// iso15693.h\r
-void AcquireRawAdcSamplesIso15693(void);\r
-void ReaderIso15693(DWORD parameter); // Simulate an ISO15693 reader - greg\r
-void SimTagIso15693(DWORD parameter); // simulate an ISO15693 tag - greg\r
-\r
-/// util.h\r
-#define LED_RED 1\r
-#define LED_ORANGE 2\r
-#define LED_GREEN 4\r
-#define LED_RED2 8\r
-#define BUTTON_HOLD 1\r
-#define BUTTON_NO_CLICK 0\r
-#define BUTTON_SINGLE_CLICK -1\r
-#define BUTTON_DOUBLE_CLICK -2\r
-#define BUTTON_ERROR -99\r
-int strlen(char *str);\r
-void *memcpy(void *dest, const void *src, int len);\r
-void *memset(void *dest, int c, int len);\r
-int memcmp(const void *av, const void *bv, int len);\r
-char *strncat(char *dest, const char *src, unsigned int n);\r
-void num_to_bytes(uint64_t n, size_t len, byte_t* dest);\r
-uint64_t bytes_to_num(byte_t* src, size_t len);\r
-\r
-void SpinDelay(int ms);\r
-void SpinDelayUs(int us);\r
-void LED(int led, int ms);\r
-void LEDsoff();\r
-int BUTTON_CLICKED(int ms);\r
-int BUTTON_HELD(int ms);\r
-void FormatVersionInformation(char *dst, int len, const char *prefix, void *version_information);\r
-\r
-#endif\r
+//-----------------------------------------------------------------------------
+// Definitions internal to the app source.
+// Jonathan Westhues, Aug 2005
+// Added ISO14443-A support by Gerhard de Koning Gans, April 2008
+//-----------------------------------------------------------------------------
+
+#ifndef __APPS_H
+#define __APPS_H
+
+#include "stdint.h"
+#include "stddef.h"
+typedef unsigned char byte_t;
+
+// The large multi-purpose buffer, typically used to hold A/D samples,
+// maybe processed in some way.
+DWORD BigBuf[8000];
+
+/// appmain.h
+void ReadMem(int addr);
+void __attribute__((noreturn)) AppMain(void);
+void SamyRun(void);
+//void DbpIntegers(int a, int b, int c);
+void DbpString(char *str);
+void Dbprintf(const char *fmt, ...);
+
+void ToSendStuffBit(int b);
+void ToSendReset(void);
+void ListenReaderField(int limit);
+void AcquireRawAdcSamples125k(BOOL at134khz);
+void DoAcquisition125k(void);
+extern int ToSendMax;
+extern BYTE ToSend[];
+extern DWORD BigBuf[];
+
+/// fpga.h
+void FpgaSendCommand(WORD cmd, WORD v);
+void FpgaWriteConfWord(BYTE v);
+void FpgaDownloadAndGo(void);
+void FpgaGatherVersion(char *dst, int len);
+void FpgaSetupSsc(void);
+void SetupSpi(int mode);
+void FpgaSetupSscDma(BYTE *buf, int len);
+void SetAdcMuxFor(DWORD whichGpio);
+
+// Definitions for the FPGA commands.
+#define FPGA_CMD_SET_CONFREG (1<<12)
+#define FPGA_CMD_SET_DIVISOR (2<<12)
+// Definitions for the FPGA configuration word.
+#define FPGA_MAJOR_MODE_LF_READER (0<<5)
+#define FPGA_MAJOR_MODE_LF_SIMULATOR (1<<5)
+#define FPGA_MAJOR_MODE_HF_READER_TX (2<<5)
+#define FPGA_MAJOR_MODE_HF_READER_RX_XCORR (3<<5)
+#define FPGA_MAJOR_MODE_HF_SIMULATOR (4<<5)
+#define FPGA_MAJOR_MODE_HF_ISO14443A (5<<5)
+#define FPGA_MAJOR_MODE_LF_PASSTHRU (6<<5)
+#define FPGA_MAJOR_MODE_OFF (7<<5)
+// Options for the HF reader, tx to tag
+#define FPGA_HF_READER_TX_SHALLOW_MOD (1<<0)
+// Options for the HF reader, correlating against rx from tag
+#define FPGA_HF_READER_RX_XCORR_848_KHZ (1<<0)
+#define FPGA_HF_READER_RX_XCORR_SNOOP (1<<1)
+#define FPGA_HF_READER_RX_XCORR_QUARTER_FREQ (1<<2)
+// Options for the HF simulated tag, how to modulate
+#define FPGA_HF_SIMULATOR_NO_MODULATION (0<<0)
+#define FPGA_HF_SIMULATOR_MODULATE_BPSK (1<<0)
+#define FPGA_HF_SIMULATOR_MODULATE_212K (2<<0)
+// Options for ISO14443A
+#define FPGA_HF_ISO14443A_SNIFFER (0<<0)
+#define FPGA_HF_ISO14443A_TAGSIM_LISTEN (1<<0)
+#define FPGA_HF_ISO14443A_TAGSIM_MOD (2<<0)
+#define FPGA_HF_ISO14443A_READER_LISTEN (3<<0)
+#define FPGA_HF_ISO14443A_READER_MOD (4<<0)
+
+/// lfops.h
+void AcquireRawAdcSamples125k(BOOL at134khz);
+void ModThenAcquireRawAdcSamples125k(int delay_off,int period_0,int period_1,BYTE *command);
+void ReadTItag(void);
+void WriteTItag(DWORD idhi, DWORD idlo, WORD crc);
+void AcquireTiType(void);
+void AcquireRawBitsTI(void);
+void SimulateTagLowFrequency(int period, int gap, int ledcontrol);
+void CmdHIDsimTAG(int hi, int lo, int ledcontrol);
+void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol);
+void SimulateTagLowFrequencyBidir(int divisor, int max_bitlen);
+
+/// iso14443.h
+void SimulateIso14443Tag(void);
+void AcquireRawAdcSamplesIso14443(DWORD parameter);
+void ReadSRI512Iso14443(DWORD parameter);
+void ReadSRIX4KIso14443(DWORD parameter);
+void ReadSTMemoryIso14443(DWORD parameter,DWORD dwLast);
+void SnoopIso14443(void);
+
+/// iso14443a.h
+void SnoopIso14443a(void);
+void SimulateIso14443aTag(int tagType, int TagUid); // ## simulate iso14443a tag
+void ReaderIso14443a(DWORD parameter);
+void ReaderMifare(DWORD parameter);
+
+/// iso15693.h
+void AcquireRawAdcSamplesIso15693(void);
+void ReaderIso15693(DWORD parameter); // Simulate an ISO15693 reader - greg
+void SimTagIso15693(DWORD parameter); // simulate an ISO15693 tag - greg
+
+/// util.h
+#define LED_RED 1
+#define LED_ORANGE 2
+#define LED_GREEN 4
+#define LED_RED2 8
+#define BUTTON_HOLD 1
+#define BUTTON_NO_CLICK 0
+#define BUTTON_SINGLE_CLICK -1
+#define BUTTON_DOUBLE_CLICK -2
+#define BUTTON_ERROR -99
+int strlen(char *str);
+void *memcpy(void *dest, const void *src, int len);
+void *memset(void *dest, int c, int len);
+int memcmp(const void *av, const void *bv, int len);
+char *strncat(char *dest, const char *src, unsigned int n);
+void num_to_bytes(uint64_t n, size_t len, byte_t* dest);
+uint64_t bytes_to_num(byte_t* src, size_t len);
+
+void SpinDelay(int ms);
+void SpinDelayUs(int us);
+void LED(int led, int ms);
+void LEDsoff();
+int BUTTON_CLICKED(int ms);
+int BUTTON_HELD(int ms);
+void FormatVersionInformation(char *dst, int len, const char *prefix, void *version_information);
+
+#endif
-const char FONT6x8[97][8] = {\r
- {0x06,0x08,0x08,0x00,0x00,0x00,0x00,0x00}, // columns, rows, bytes per char\r
- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // space\r
- {0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x00}, // !\r
- {0x50,0x50,0x50,0x00,0x00,0x00,0x00,0x00}, // "\r
- {0x50,0x50,0xF8,0x50,0xF8,0x50,0x50,0x00}, // #\r
- {0x20,0x78,0xA0,0x70,0x28,0xF0,0x20,0x00}, // $\r
- {0xC0,0xC8,0x10,0x20,0x40,0x98,0x18,0x00}, // %\r
- {0x40,0xA0,0xA0,0x40,0xA8,0x90,0x68,0x00}, // &\r
- {0x30,0x30,0x20,0x40,0x00,0x00,0x00,0x00}, // '\r
- {0x10,0x20,0x40,0x40,0x40,0x20,0x10,0x00}, // (\r
- {0x40,0x20,0x10,0x10,0x10,0x20,0x40,0x00}, // )\r
- {0x00,0x20,0xA8,0x70,0x70,0xA8,0x20,0x00}, // *\r
- {0x00,0x20,0x20,0xF8,0x20,0x20,0x00,0x00}, // +\r
- {0x00,0x00,0x00,0x00,0x30,0x30,0x20,0x40}, // ,\r
- {0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00}, // -\r
- {0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00}, // .\r
- {0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00}, // /\r
- {0x70,0x88,0x88,0xA8,0x88,0x88,0x70,0x00}, // 0\r
- {0x20,0x60,0x20,0x20,0x20,0x20,0x70,0x00}, // 1\r
- {0x70,0x88,0x08,0x70,0x80,0x80,0xF8,0x00}, // 2\r
- {0xF8,0x08,0x10,0x30,0x08,0x88,0x70,0x00}, // 3\r
- {0x10,0x30,0x50,0x90,0xF8,0x10,0x10,0x00}, // 4\r
- {0xF8,0x80,0xF0,0x08,0x08,0x88,0x70,0x00}, // 5\r
- {0x38,0x40,0x80,0xF0,0x88,0x88,0x70,0x00}, // 6\r
- {0xF8,0x08,0x08,0x10,0x20,0x40,0x80,0x00}, // 7\r
- {0x70,0x88,0x88,0x70,0x88,0x88,0x70,0x00}, // 8\r
- {0x70,0x88,0x88,0x78,0x08,0x10,0xE0,0x00}, // 9\r
- {0x00,0x00,0x20,0x00,0x20,0x00,0x00,0x00}, // :\r
- {0x00,0x00,0x20,0x00,0x20,0x20,0x40,0x00}, // ;\r
- {0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x00}, // <\r
- {0x00,0x00,0xF8,0x00,0xF8,0x00,0x00,0x00}, // =\r
- {0x40,0x20,0x10,0x08,0x10,0x20,0x40,0x00}, // >\r
- {0x70,0x88,0x08,0x30,0x20,0x00,0x20,0x00}, // ?\r
- {0x70,0x88,0xA8,0xB8,0xB0,0x80,0x78,0x00}, // @\r
- {0x20,0x50,0x88,0x88,0xF8,0x88,0x88,0x00}, // A\r
- {0xF0,0x88,0x88,0xF0,0x88,0x88,0xF0,0x00}, // B\r
- {0x70,0x88,0x80,0x80,0x80,0x88,0x70,0x00}, // C\r
- {0xF0,0x88,0x88,0x88,0x88,0x88,0xF0,0x00}, // D\r
- {0xF8,0x80,0x80,0xF0,0x80,0x80,0xF8,0x00}, // E\r
- {0xF8,0x80,0x80,0xF0,0x80,0x80,0x80,0x00}, // F\r
- {0x78,0x88,0x80,0x80,0x98,0x88,0x78,0x00}, // G\r
- {0x88,0x88,0x88,0xF8,0x88,0x88,0x88,0x00}, // H\r
- {0x70,0x20,0x20,0x20,0x20,0x20,0x70,0x00}, // I\r
- {0x38,0x10,0x10,0x10,0x10,0x90,0x60,0x00}, // J\r
- {0x88,0x90,0xA0,0xC0,0xA0,0x90,0x88,0x00}, // K\r
- {0x80,0x80,0x80,0x80,0x80,0x80,0xF8,0x00}, // L\r
- {0x88,0xD8,0xA8,0xA8,0xA8,0x88,0x88,0x00}, // M\r
- {0x88,0x88,0xC8,0xA8,0x98,0x88,0x88,0x00}, // N\r
- {0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00}, // O\r
- {0xF0,0x88,0x88,0xF0,0x80,0x80,0x80,0x00}, // P\r
- {0x70,0x88,0x88,0x88,0xA8,0x90,0x68,0x00}, // Q\r
- {0xF0,0x88,0x88,0xF0,0xA0,0x90,0x88,0x00}, // R\r
- {0x70,0x88,0x80,0x70,0x08,0x88,0x70,0x00}, // S\r
- {0xF8,0xA8,0x20,0x20,0x20,0x20,0x20,0x00}, // T\r
- {0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00}, // U\r
- {0x88,0x88,0x88,0x88,0x88,0x50,0x20,0x00}, // V\r
- {0x88,0x88,0x88,0xA8,0xA8,0xA8,0x50,0x00}, // W\r
- {0x88,0x88,0x50,0x20,0x50,0x88,0x88,0x00}, // X\r
- {0x88,0x88,0x50,0x20,0x20,0x20,0x20,0x00}, // Y\r
- {0xF8,0x08,0x10,0x70,0x40,0x80,0xF8,0x00}, // Z\r
- {0x78,0x40,0x40,0x40,0x40,0x40,0x78,0x00}, // [\r
- {0x00,0x80,0x40,0x20,0x10,0x08,0x00,0x00}, // backslash\r
- {0x78,0x08,0x08,0x08,0x08,0x08,0x78,0x00}, // ]\r
- {0x20,0x50,0x88,0x00,0x00,0x00,0x00,0x00}, // ^\r
- {0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x00}, // _\r
- {0x60,0x60,0x20,0x10,0x00,0x00,0x00,0x00}, // `\r
- {0x00,0x00,0x60,0x10,0x70,0x90,0x78,0x00}, // a\r
- {0x80,0x80,0xB0,0xC8,0x88,0xC8,0xB0,0x00}, // b\r
- {0x00,0x00,0x70,0x88,0x80,0x88,0x70,0x00}, // c\r
- {0x08,0x08,0x68,0x98,0x88,0x98,0x68,0x00}, // d\r
- {0x00,0x00,0x70,0x88,0xF8,0x80,0x70,0x00}, // e\r
- {0x10,0x28,0x20,0x70,0x20,0x20,0x20,0x00}, // f\r
- {0x00,0x00,0x70,0x98,0x98,0x68,0x08,0x70}, // g\r
- {0x80,0x80,0xB0,0xC8,0x88,0x88,0x88,0x00}, // h\r
- {0x20,0x00,0x60,0x20,0x20,0x20,0x70,0x00}, // i\r
- {0x10,0x00,0x10,0x10,0x10,0x90,0x60,0x00}, // j\r
- {0x80,0x80,0x90,0xA0,0xC0,0xA0,0x90,0x00}, // k\r
- {0x60,0x20,0x20,0x20,0x20,0x20,0x70,0x00}, // l\r
- {0x00,0x00,0xD0,0xA8,0xA8,0xA8,0xA8,0x00}, // m\r
- {0x00,0x00,0xB0,0xC8,0x88,0x88,0x88,0x00}, // n\r
- {0x00,0x00,0x70,0x88,0x88,0x88,0x70,0x00}, // o\r
- {0x00,0x00,0xB0,0xC8,0xC8,0xB0,0x80,0x80}, // p\r
- {0x00,0x00,0x68,0x98,0x98,0x68,0x08,0x08}, // q\r
- {0x00,0x00,0xB0,0xC8,0x80,0x80,0x80,0x00}, // r\r
- {0x00,0x00,0x78,0x80,0x70,0x08,0xF0,0x00}, // s\r
- {0x20,0x20,0xF8,0x20,0x20,0x28,0x10,0x00}, // t\r
- {0x00,0x00,0x88,0x88,0x88,0x98,0x68,0x00}, // u\r
- {0x00,0x00,0x88,0x88,0x88,0x50,0x20,0x00}, // v\r
- {0x00,0x00,0x88,0x88,0xA8,0xA8,0x50,0x00}, // w\r
- {0x00,0x00,0x88,0x50,0x20,0x50,0x88,0x00}, // x\r
- {0x00,0x00,0x88,0x88,0x78,0x08,0x88,0x70}, // y\r
- {0x00,0x00,0xF8,0x10,0x20,0x40,0xF8,0x00}, // z\r
- {0x10,0x20,0x20,0x40,0x20,0x20,0x10,0x00}, // {\r
- {0x20,0x20,0x20,0x00,0x20,0x20,0x20,0x00}, // |\r
- {0x40,0x20,0x20,0x10,0x20,0x20,0x40,0x00}, // }\r
- {0x40,0xA8,0x10,0x00,0x00,0x00,0x00,0x00}, // ~\r
- {0x70,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00} // DEL\r
-};\r
-/*\r
-const char FONT8x8F[97][8] = {\r
- {0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00}, // columns, rows, bytes per char\r
- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // space\r
- {0x30,0x78,0x78,0x30,0x30,0x00,0x30,0x00}, // !\r
- {0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00}, // "\r
- {0x6C,0x6C,0xFE,0x6C,0xFE,0x6C,0x6C,0x00}, // #\r
- {0x18,0x3E,0x60,0x3C,0x06,0x7C,0x18,0x00}, // $\r
- {0x00,0x63,0x66,0x0C,0x18,0x33,0x63,0x00}, // %\r
- {0x1C,0x36,0x1C,0x3B,0x6E,0x66,0x3B,0x00}, // &\r
- {0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00}, // '\r
- {0x0C,0x18,0x30,0x30,0x30,0x18,0x0C,0x00}, // (\r
- {0x30,0x18,0x0C,0x0C,0x0C,0x18,0x30,0x00}, // )\r
- {0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00}, // *\r
- {0x00,0x30,0x30,0xFC,0x30,0x30,0x00,0x00}, // +\r
- {0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x30}, // ,\r
- {0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00}, // -\r
- {0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00}, // .\r
- {0x03,0x06,0x0C,0x18,0x30,0x60,0x40,0x00}, // /\r
- {0x3E,0x63,0x63,0x6B,0x63,0x63,0x3E,0x00}, // 0\r
- {0x18,0x38,0x58,0x18,0x18,0x18,0x7E,0x00}, // 1\r
- {0x3C,0x66,0x06,0x1C,0x30,0x66,0x7E,0x00}, // 2\r
- {0x3C,0x66,0x06,0x1C,0x06,0x66,0x3C,0x00}, // 3\r
- {0x0E,0x1E,0x36,0x66,0x7F,0x06,0x0F,0x00}, // 4\r
- {0x7E,0x60,0x7C,0x06,0x06,0x66,0x3C,0x00}, // 5\r
- {0x1C,0x30,0x60,0x7C,0x66,0x66,0x3C,0x00}, // 6\r
- {0x7E,0x66,0x06,0x0C,0x18,0x18,0x18,0x00}, // 7\r
- {0x3C,0x66,0x66,0x3C,0x66,0x66,0x3C,0x00}, // 8\r
- {0x3C,0x66,0x66,0x3E,0x06,0x0C,0x38,0x00}, // 9\r
- {0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x00}, // :\r
- {0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x30}, // ;\r
- {0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x00}, // <\r
- {0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00}, // =\r
- {0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x00}, // >\r
- {0x3C,0x66,0x06,0x0C,0x18,0x00,0x18,0x00}, // ?\r
- {0x3E,0x63,0x6F,0x69,0x6F,0x60,0x3E,0x00}, // @\r
- {0x18,0x3C,0x66,0x66,0x7E,0x66,0x66,0x00}, // A\r
- {0x7E,0x33,0x33,0x3E,0x33,0x33,0x7E,0x00}, // B\r
- {0x1E,0x33,0x60,0x60,0x60,0x33,0x1E,0x00}, // C\r
- {0x7C,0x36,0x33,0x33,0x33,0x36,0x7C,0x00}, // D\r
- {0x7F,0x31,0x34,0x3C,0x34,0x31,0x7F,0x00}, // E\r
- {0x7F,0x31,0x34,0x3C,0x34,0x30,0x78,0x00}, // F\r
- {0x1E,0x33,0x60,0x60,0x67,0x33,0x1F,0x00}, // G\r
- {0x66,0x66,0x66,0x7E,0x66,0x66,0x66,0x00}, // H\r
- {0x3C,0x18,0x18,0x18,0x18,0x18,0x3C,0x00}, // I\r
- {0x0F,0x06,0x06,0x06,0x66,0x66,0x3C,0x00}, // J\r
- {0x73,0x33,0x36,0x3C,0x36,0x33,0x73,0x00}, // K\r
- {0x78,0x30,0x30,0x30,0x31,0x33,0x7F,0x00}, // L\r
- {0x63,0x77,0x7F,0x7F,0x6B,0x63,0x63,0x00}, // M\r
- {0x63,0x73,0x7B,0x6F,0x67,0x63,0x63,0x00}, // N\r
- {0x3E,0x63,0x63,0x63,0x63,0x63,0x3E,0x00}, // O\r
- {0x7E,0x33,0x33,0x3E,0x30,0x30,0x78,0x00}, // P\r
- {0x3C,0x66,0x66,0x66,0x6E,0x3C,0x0E,0x00}, // Q\r
- {0x7E,0x33,0x33,0x3E,0x36,0x33,0x73,0x00}, // R\r
- {0x3C,0x66,0x30,0x18,0x0C,0x66,0x3C,0x00}, // S\r
- {0x7E,0x5A,0x18,0x18,0x18,0x18,0x3C,0x00}, // T\r
- {0x66,0x66,0x66,0x66,0x66,0x66,0x7E,0x00}, // U\r
- {0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x00}, // V\r
- {0x63,0x63,0x63,0x6B,0x7F,0x77,0x63,0x00}, // W\r
- {0x63,0x63,0x36,0x1C,0x1C,0x36,0x63,0x00}, // X\r
- {0x66,0x66,0x66,0x3C,0x18,0x18,0x3C,0x00}, // Y\r
- {0x7F,0x63,0x46,0x0C,0x19,0x33,0x7F,0x00}, // Z\r
- {0x3C,0x30,0x30,0x30,0x30,0x30,0x3C,0x00}, // [\r
- {0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x00}, // backslash\r
- {0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00}, // ]\r
- {0x08,0x1C,0x36,0x63,0x00,0x00,0x00,0x00}, // ^\r
- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF}, // _\r
- {0x18,0x18,0x0C,0x00,0x00,0x00,0x00,0x00}, // `\r
- {0x00,0x00,0x3C,0x06,0x3E,0x66,0x3B,0x00}, // a\r
- {0x70,0x30,0x3E,0x33,0x33,0x33,0x6E,0x00}, // b\r
- {0x00,0x00,0x3C,0x66,0x60,0x66,0x3C,0x00}, // c\r
- {0x0E,0x06,0x3E,0x66,0x66,0x66,0x3B,0x00}, // d\r
- {0x00,0x00,0x3C,0x66,0x7E,0x60,0x3C,0x00}, // e\r
- {0x1C,0x36,0x30,0x78,0x30,0x30,0x78,0x00}, // f\r
- {0x00,0x00,0x3B,0x66,0x66,0x3E,0x06,0x7C}, // g\r
- {0x70,0x30,0x36,0x3B,0x33,0x33,0x73,0x00}, // h\r
- {0x18,0x00,0x38,0x18,0x18,0x18,0x3C,0x00}, // i\r
- {0x06,0x00,0x06,0x06,0x06,0x66,0x66,0x3C}, // j\r
- {0x70,0x30,0x33,0x36,0x3C,0x36,0x73,0x00}, // k\r
- {0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00}, // l\r
- {0x00,0x00,0x66,0x7F,0x7F,0x6B,0x63,0x00}, // m\r
- {0x00,0x00,0x7C,0x66,0x66,0x66,0x66,0x00}, // n\r
- {0x00,0x00,0x3C,0x66,0x66,0x66,0x3C,0x00}, // o\r
- {0x00,0x00,0x6E,0x33,0x33,0x3E,0x30,0x78}, // p\r
- {0x00,0x00,0x3B,0x66,0x66,0x3E,0x06,0x0F}, // q\r
- {0x00,0x00,0x6E,0x3B,0x33,0x30,0x78,0x00}, // r\r
- {0x00,0x00,0x3E,0x60,0x3C,0x06,0x7C,0x00}, // s\r
- {0x08,0x18,0x3E,0x18,0x18,0x1A,0x0C,0x00}, // t\r
- {0x00,0x00,0x66,0x66,0x66,0x66,0x3B,0x00}, // u\r
- {0x00,0x00,0x66,0x66,0x66,0x3C,0x18,0x00}, // v\r
- {0x00,0x00,0x63,0x6B,0x7F,0x7F,0x36,0x00}, // w\r
- {0x00,0x00,0x63,0x36,0x1C,0x36,0x63,0x00}, // x\r
- {0x00,0x00,0x66,0x66,0x66,0x3E,0x06,0x7C}, // y\r
- {0x00,0x00,0x7E,0x4C,0x18,0x32,0x7E,0x00}, // z\r
- {0x0E,0x18,0x18,0x70,0x18,0x18,0x0E,0x00}, // {\r
- {0x0C,0x0C,0x0C,0x00,0x0C,0x0C,0x0C,0x00}, // |\r
- {0x70,0x18,0x18,0x0E,0x18,0x18,0x70,0x00}, // }\r
- {0x3B,0x6E,0x00,0x00,0x00,0x00,0x00,0x00}, // ~\r
- {0x1C,0x36,0x36,0x1C,0x00,0x00,0x00,0x00} // DEL\r
-};\r
-\r
-const char FONT8x16[97][16] = {\r
- {0x08,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // columns, rows, bytes per char\r
- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // space\r
- {0x00,0x00,0x18,0x3C,0x3C,0x3C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00}, // !\r
- {0x00,0x63,0x63,0x63,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // "\r
- {0x00,0x00,0x00,0x36,0x36,0x7F,0x36,0x36,0x36,0x7F,0x36,0x36,0x00,0x00,0x00,0x00}, // #\r
- {0x0C,0x0C,0x3E,0x63,0x61,0x60,0x3E,0x03,0x03,0x43,0x63,0x3E,0x0C,0x0C,0x00,0x00}, // $\r
- {0x00,0x00,0x00,0x00,0x00,0x61,0x63,0x06,0x0C,0x18,0x33,0x63,0x00,0x00,0x00,0x00}, // %\r
- {0x00,0x00,0x00,0x1C,0x36,0x36,0x1C,0x3B,0x6E,0x66,0x66,0x3B,0x00,0x00,0x00,0x00}, // &\r
- {0x00,0x30,0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // '\r
- {0x00,0x00,0x0C,0x18,0x18,0x30,0x30,0x30,0x30,0x18,0x18,0x0C,0x00,0x00,0x00,0x00}, // (\r
- {0x00,0x00,0x18,0x0C,0x0C,0x06,0x06,0x06,0x06,0x0C,0x0C,0x18,0x00,0x00,0x00,0x00}, // )\r
- {0x00,0x00,0x00,0x00,0x42,0x66,0x3C,0xFF,0x3C,0x66,0x42,0x00,0x00,0x00,0x00,0x00}, // *\r
- {0x00,0x00,0x00,0x00,0x18,0x18,0x18,0xFF,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00}, // +\r
- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00}, // ,\r
- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // -\r
- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00}, // .\r
- {0x00,0x00,0x01,0x03,0x07,0x0E,0x1C,0x38,0x70,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00}, // /\r
- {0x00,0x00,0x3E,0x63,0x63,0x63,0x6B,0x6B,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // 0\r
- {0x00,0x00,0x0C,0x1C,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3F,0x00,0x00,0x00,0x00}, // 1\r
- {0x00,0x00,0x3E,0x63,0x03,0x06,0x0C,0x18,0x30,0x61,0x63,0x7F,0x00,0x00,0x00,0x00}, // 2\r
- {0x00,0x00,0x3E,0x63,0x03,0x03,0x1E,0x03,0x03,0x03,0x63,0x3E,0x00,0x00,0x00,0x00}, // 3\r
- {0x00,0x00,0x06,0x0E,0x1E,0x36,0x66,0x66,0x7F,0x06,0x06,0x0F,0x00,0x00,0x00,0x00}, // 4\r
- {0x00,0x00,0x7F,0x60,0x60,0x60,0x7E,0x03,0x03,0x63,0x73,0x3E,0x00,0x00,0x00,0x00}, // 5\r
- {0x00,0x00,0x1C,0x30,0x60,0x60,0x7E,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // 6\r
- {0x00,0x00,0x7F,0x63,0x03,0x06,0x06,0x0C,0x0C,0x18,0x18,0x18,0x00,0x00,0x00,0x00}, // 7\r
- {0x00,0x00,0x3E,0x63,0x63,0x63,0x3E,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // 8\r
- {0x00,0x00,0x3E,0x63,0x63,0x63,0x63,0x3F,0x03,0x03,0x06,0x3C,0x00,0x00,0x00,0x00}, // 9\r
- {0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00}, // :\r
- {0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00}, // ;\r
- {0x00,0x00,0x00,0x06,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x06,0x00,0x00,0x00,0x00}, // <\r
- {0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00}, // =\r
- {0x00,0x00,0x00,0x60,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00}, // >\r
- {0x00,0x00,0x3E,0x63,0x63,0x06,0x0C,0x0C,0x0C,0x00,0x0C,0x0C,0x00,0x00,0x00,0x00}, // ?\r
- {0x00,0x00,0x3E,0x63,0x63,0x6F,0x6B,0x6B,0x6E,0x60,0x60,0x3E,0x00,0x00,0x00,0x00}, // @\r
- {0x00,0x00,0x08,0x1C,0x36,0x63,0x63,0x63,0x7F,0x63,0x63,0x63,0x00,0x00,0x00,0x00}, // A\r
- {0x00,0x00,0x7E,0x33,0x33,0x33,0x3E,0x33,0x33,0x33,0x33,0x7E,0x00,0x00,0x00,0x00}, // B\r
- {0x00,0x00,0x1E,0x33,0x61,0x60,0x60,0x60,0x60,0x61,0x33,0x1E,0x00,0x00,0x00,0x00}, // C\r
- {0x00,0x00,0x7C,0x36,0x33,0x33,0x33,0x33,0x33,0x33,0x36,0x7C,0x00,0x00,0x00,0x00}, // D\r
- {0x00,0x00,0x7F,0x33,0x31,0x34,0x3C,0x34,0x30,0x31,0x33,0x7F,0x00,0x00,0x00,0x00}, // E\r
- {0x00,0x00,0x7F,0x33,0x31,0x34,0x3C,0x34,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00}, // F\r
- {0x00,0x00,0x1E,0x33,0x61,0x60,0x60,0x6F,0x63,0x63,0x37,0x1D,0x00,0x00,0x00,0x00}, // G\r
- {0x00,0x00,0x63,0x63,0x63,0x63,0x7F,0x63,0x63,0x63,0x63,0x63,0x00,0x00,0x00,0x00}, // H\r
- {0x00,0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}, // I\r
- {0x00,0x00,0x0F,0x06,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3C,0x00,0x00,0x00,0x00}, // J\r
- {0x00,0x00,0x73,0x33,0x36,0x36,0x3C,0x36,0x36,0x33,0x33,0x73,0x00,0x00,0x00,0x00}, // K\r
- {0x00,0x00,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x31,0x33,0x7F,0x00,0x00,0x00,0x00}, // L\r
- {0x00,0x00,0x63,0x77,0x7F,0x6B,0x63,0x63,0x63,0x63,0x63,0x63,0x00,0x00,0x00,0x00}, // M\r
- {0x00,0x00,0x63,0x63,0x73,0x7B,0x7F,0x6F,0x67,0x63,0x63,0x63,0x00,0x00,0x00,0x00}, // N\r
- {0x00,0x00,0x1C,0x36,0x63,0x63,0x63,0x63,0x63,0x63,0x36,0x1C,0x00,0x00,0x00,0x00}, // O\r
- {0x00,0x00,0x7E,0x33,0x33,0x33,0x3E,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00}, // P\r
- {0x00,0x00,0x3E,0x63,0x63,0x63,0x63,0x63,0x63,0x6B,0x6F,0x3E,0x06,0x07,0x00,0x00}, // Q\r
- {0x00,0x00,0x7E,0x33,0x33,0x33,0x3E,0x36,0x36,0x33,0x33,0x73,0x00,0x00,0x00,0x00}, // R\r
- {0x00,0x00,0x3E,0x63,0x63,0x30,0x1C,0x06,0x03,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // S\r
- {0x00,0x00,0xFF,0xDB,0x99,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}, // T\r
- {0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // U\r
- {0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x36,0x1C,0x08,0x00,0x00,0x00,0x00}, // V\r
- {0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x6B,0x6B,0x7F,0x36,0x36,0x00,0x00,0x00,0x00}, // W\r
- {0x00,0x00,0xC3,0xC3,0x66,0x3C,0x18,0x18,0x3C,0x66,0xC3,0xC3,0x00,0x00,0x00,0x00}, // X\r
- {0x00,0x00,0xC3,0xC3,0xC3,0x66,0x3C,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}, // Y\r
- {0x00,0x00,0x7F,0x63,0x43,0x06,0x0C,0x18,0x30,0x61,0x63,0x7F,0x00,0x00,0x00,0x00}, // Z\r
- {0x00,0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,0x00,0x00,0x00}, // [\r
- {0x00,0x00,0x80,0xC0,0xE0,0x70,0x38,0x1C,0x0E,0x07,0x03,0x01,0x00,0x00,0x00,0x00}, // backslash\r
- {0x00,0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00,0x00,0x00,0x00}, // ]\r
- {0x08,0x1C,0x36,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // ^\r
- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00}, // _\r
- {0x18,0x18,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // `\r
- {0x00,0x00,0x00,0x00,0x00,0x3C,0x46,0x06,0x3E,0x66,0x66,0x3B,0x00,0x00,0x00,0x00}, // a\r
- {0x00,0x00,0x70,0x30,0x30,0x3C,0x36,0x33,0x33,0x33,0x33,0x6E,0x00,0x00,0x00,0x00}, // b\r
- {0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x60,0x60,0x60,0x63,0x3E,0x00,0x00,0x00,0x00}, // c\r
- {0x00,0x00,0x0E,0x06,0x06,0x1E,0x36,0x66,0x66,0x66,0x66,0x3B,0x00,0x00,0x00,0x00}, // d\r
- {0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x63,0x7E,0x60,0x63,0x3E,0x00,0x00,0x00,0x00}, // e\r
- {0x00,0x00,0x1C,0x36,0x32,0x30,0x7C,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00}, // f\r
- {0x00,0x00,0x00,0x00,0x00,0x3B,0x66,0x66,0x66,0x66,0x3E,0x06,0x66,0x3C,0x00,0x00}, // g\r
- {0x00,0x00,0x70,0x30,0x30,0x36,0x3B,0x33,0x33,0x33,0x33,0x73,0x00,0x00,0x00,0x00}, // h\r
- {0x00,0x00,0x0C,0x0C,0x00,0x1C,0x0C,0x0C,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00}, // i\r
- {0x00,0x00,0x06,0x06,0x00,0x0E,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3C,0x00,0x00}, // j\r
- {0x00,0x00,0x70,0x30,0x30,0x33,0x33,0x36,0x3C,0x36,0x33,0x73,0x00,0x00,0x00,0x00}, // k\r
- {0x00,0x00,0x1C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00}, // l\r
- {0x00,0x00,0x00,0x00,0x00,0x6E,0x7F,0x6B,0x6B,0x6B,0x6B,0x6B,0x00,0x00,0x00,0x00}, // m\r
- {0x00,0x00,0x00,0x00,0x00,0x6E,0x33,0x33,0x33,0x33,0x33,0x33,0x00,0x00,0x00,0x00}, // n\r
- {0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // o\r
- {0x00,0x00,0x00,0x00,0x00,0x6E,0x33,0x33,0x33,0x33,0x3E,0x30,0x30,0x78,0x00,0x00}, // p\r
- {0x00,0x00,0x00,0x00,0x00,0x3B,0x66,0x66,0x66,0x66,0x3E,0x06,0x06,0x0F,0x00,0x00}, // q\r
- {0x00,0x00,0x00,0x00,0x00,0x6E,0x3B,0x33,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00}, // r\r
- {0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x38,0x0E,0x03,0x63,0x3E,0x00,0x00,0x00,0x00}, // s\r
- {0x00,0x00,0x08,0x18,0x18,0x7E,0x18,0x18,0x18,0x18,0x1B,0x0E,0x00,0x00,0x00,0x00}, // t\r
- {0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x3B,0x00,0x00,0x00,0x00}, // u\r
- {0x00,0x00,0x00,0x00,0x00,0x63,0x63,0x36,0x36,0x1C,0x1C,0x08,0x00,0x00,0x00,0x00}, // v\r
- {0x00,0x00,0x00,0x00,0x00,0x63,0x63,0x63,0x6B,0x6B,0x7F,0x36,0x00,0x00,0x00,0x00}, // w\r
- {0x00,0x00,0x00,0x00,0x00,0x63,0x36,0x1C,0x1C,0x1C,0x36,0x63,0x00,0x00,0x00,0x00}, // x\r
- {0x00,0x00,0x00,0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x3F,0x03,0x06,0x3C,0x00,0x00}, // y\r
- {0x00,0x00,0x00,0x00,0x00,0x7F,0x66,0x0C,0x18,0x30,0x63,0x7F,0x00,0x00,0x00,0x00}, // z\r
- {0x00,0x00,0x0E,0x18,0x18,0x18,0x70,0x18,0x18,0x18,0x18,0x0E,0x00,0x00,0x00,0x00}, // {\r
- {0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00}, // |\r
- {0x00,0x00,0x70,0x18,0x18,0x18,0x0E,0x18,0x18,0x18,0x18,0x70,0x00,0x00,0x00,0x00}, // }\r
- {0x00,0x00,0x3B,0x6E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // ~\r
- {0x00,0x70,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} // DEL\r
-};\r
-*/\r
+const char FONT6x8[97][8] = {
+ {0x06,0x08,0x08,0x00,0x00,0x00,0x00,0x00}, // columns, rows, bytes per char
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // space
+ {0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x00}, // !
+ {0x50,0x50,0x50,0x00,0x00,0x00,0x00,0x00}, // "
+ {0x50,0x50,0xF8,0x50,0xF8,0x50,0x50,0x00}, // #
+ {0x20,0x78,0xA0,0x70,0x28,0xF0,0x20,0x00}, // $
+ {0xC0,0xC8,0x10,0x20,0x40,0x98,0x18,0x00}, // %
+ {0x40,0xA0,0xA0,0x40,0xA8,0x90,0x68,0x00}, // &
+ {0x30,0x30,0x20,0x40,0x00,0x00,0x00,0x00}, // '
+ {0x10,0x20,0x40,0x40,0x40,0x20,0x10,0x00}, // (
+ {0x40,0x20,0x10,0x10,0x10,0x20,0x40,0x00}, // )
+ {0x00,0x20,0xA8,0x70,0x70,0xA8,0x20,0x00}, // *
+ {0x00,0x20,0x20,0xF8,0x20,0x20,0x00,0x00}, // +
+ {0x00,0x00,0x00,0x00,0x30,0x30,0x20,0x40}, // ,
+ {0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00}, // -
+ {0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00}, // .
+ {0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00}, // /
+ {0x70,0x88,0x88,0xA8,0x88,0x88,0x70,0x00}, // 0
+ {0x20,0x60,0x20,0x20,0x20,0x20,0x70,0x00}, // 1
+ {0x70,0x88,0x08,0x70,0x80,0x80,0xF8,0x00}, // 2
+ {0xF8,0x08,0x10,0x30,0x08,0x88,0x70,0x00}, // 3
+ {0x10,0x30,0x50,0x90,0xF8,0x10,0x10,0x00}, // 4
+ {0xF8,0x80,0xF0,0x08,0x08,0x88,0x70,0x00}, // 5
+ {0x38,0x40,0x80,0xF0,0x88,0x88,0x70,0x00}, // 6
+ {0xF8,0x08,0x08,0x10,0x20,0x40,0x80,0x00}, // 7
+ {0x70,0x88,0x88,0x70,0x88,0x88,0x70,0x00}, // 8
+ {0x70,0x88,0x88,0x78,0x08,0x10,0xE0,0x00}, // 9
+ {0x00,0x00,0x20,0x00,0x20,0x00,0x00,0x00}, // :
+ {0x00,0x00,0x20,0x00,0x20,0x20,0x40,0x00}, // ;
+ {0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x00}, // <
+ {0x00,0x00,0xF8,0x00,0xF8,0x00,0x00,0x00}, // =
+ {0x40,0x20,0x10,0x08,0x10,0x20,0x40,0x00}, // >
+ {0x70,0x88,0x08,0x30,0x20,0x00,0x20,0x00}, // ?
+ {0x70,0x88,0xA8,0xB8,0xB0,0x80,0x78,0x00}, // @
+ {0x20,0x50,0x88,0x88,0xF8,0x88,0x88,0x00}, // A
+ {0xF0,0x88,0x88,0xF0,0x88,0x88,0xF0,0x00}, // B
+ {0x70,0x88,0x80,0x80,0x80,0x88,0x70,0x00}, // C
+ {0xF0,0x88,0x88,0x88,0x88,0x88,0xF0,0x00}, // D
+ {0xF8,0x80,0x80,0xF0,0x80,0x80,0xF8,0x00}, // E
+ {0xF8,0x80,0x80,0xF0,0x80,0x80,0x80,0x00}, // F
+ {0x78,0x88,0x80,0x80,0x98,0x88,0x78,0x00}, // G
+ {0x88,0x88,0x88,0xF8,0x88,0x88,0x88,0x00}, // H
+ {0x70,0x20,0x20,0x20,0x20,0x20,0x70,0x00}, // I
+ {0x38,0x10,0x10,0x10,0x10,0x90,0x60,0x00}, // J
+ {0x88,0x90,0xA0,0xC0,0xA0,0x90,0x88,0x00}, // K
+ {0x80,0x80,0x80,0x80,0x80,0x80,0xF8,0x00}, // L
+ {0x88,0xD8,0xA8,0xA8,0xA8,0x88,0x88,0x00}, // M
+ {0x88,0x88,0xC8,0xA8,0x98,0x88,0x88,0x00}, // N
+ {0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00}, // O
+ {0xF0,0x88,0x88,0xF0,0x80,0x80,0x80,0x00}, // P
+ {0x70,0x88,0x88,0x88,0xA8,0x90,0x68,0x00}, // Q
+ {0xF0,0x88,0x88,0xF0,0xA0,0x90,0x88,0x00}, // R
+ {0x70,0x88,0x80,0x70,0x08,0x88,0x70,0x00}, // S
+ {0xF8,0xA8,0x20,0x20,0x20,0x20,0x20,0x00}, // T
+ {0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00}, // U
+ {0x88,0x88,0x88,0x88,0x88,0x50,0x20,0x00}, // V
+ {0x88,0x88,0x88,0xA8,0xA8,0xA8,0x50,0x00}, // W
+ {0x88,0x88,0x50,0x20,0x50,0x88,0x88,0x00}, // X
+ {0x88,0x88,0x50,0x20,0x20,0x20,0x20,0x00}, // Y
+ {0xF8,0x08,0x10,0x70,0x40,0x80,0xF8,0x00}, // Z
+ {0x78,0x40,0x40,0x40,0x40,0x40,0x78,0x00}, // [
+ {0x00,0x80,0x40,0x20,0x10,0x08,0x00,0x00}, // backslash
+ {0x78,0x08,0x08,0x08,0x08,0x08,0x78,0x00}, // ]
+ {0x20,0x50,0x88,0x00,0x00,0x00,0x00,0x00}, // ^
+ {0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x00}, // _
+ {0x60,0x60,0x20,0x10,0x00,0x00,0x00,0x00}, // `
+ {0x00,0x00,0x60,0x10,0x70,0x90,0x78,0x00}, // a
+ {0x80,0x80,0xB0,0xC8,0x88,0xC8,0xB0,0x00}, // b
+ {0x00,0x00,0x70,0x88,0x80,0x88,0x70,0x00}, // c
+ {0x08,0x08,0x68,0x98,0x88,0x98,0x68,0x00}, // d
+ {0x00,0x00,0x70,0x88,0xF8,0x80,0x70,0x00}, // e
+ {0x10,0x28,0x20,0x70,0x20,0x20,0x20,0x00}, // f
+ {0x00,0x00,0x70,0x98,0x98,0x68,0x08,0x70}, // g
+ {0x80,0x80,0xB0,0xC8,0x88,0x88,0x88,0x00}, // h
+ {0x20,0x00,0x60,0x20,0x20,0x20,0x70,0x00}, // i
+ {0x10,0x00,0x10,0x10,0x10,0x90,0x60,0x00}, // j
+ {0x80,0x80,0x90,0xA0,0xC0,0xA0,0x90,0x00}, // k
+ {0x60,0x20,0x20,0x20,0x20,0x20,0x70,0x00}, // l
+ {0x00,0x00,0xD0,0xA8,0xA8,0xA8,0xA8,0x00}, // m
+ {0x00,0x00,0xB0,0xC8,0x88,0x88,0x88,0x00}, // n
+ {0x00,0x00,0x70,0x88,0x88,0x88,0x70,0x00}, // o
+ {0x00,0x00,0xB0,0xC8,0xC8,0xB0,0x80,0x80}, // p
+ {0x00,0x00,0x68,0x98,0x98,0x68,0x08,0x08}, // q
+ {0x00,0x00,0xB0,0xC8,0x80,0x80,0x80,0x00}, // r
+ {0x00,0x00,0x78,0x80,0x70,0x08,0xF0,0x00}, // s
+ {0x20,0x20,0xF8,0x20,0x20,0x28,0x10,0x00}, // t
+ {0x00,0x00,0x88,0x88,0x88,0x98,0x68,0x00}, // u
+ {0x00,0x00,0x88,0x88,0x88,0x50,0x20,0x00}, // v
+ {0x00,0x00,0x88,0x88,0xA8,0xA8,0x50,0x00}, // w
+ {0x00,0x00,0x88,0x50,0x20,0x50,0x88,0x00}, // x
+ {0x00,0x00,0x88,0x88,0x78,0x08,0x88,0x70}, // y
+ {0x00,0x00,0xF8,0x10,0x20,0x40,0xF8,0x00}, // z
+ {0x10,0x20,0x20,0x40,0x20,0x20,0x10,0x00}, // {
+ {0x20,0x20,0x20,0x00,0x20,0x20,0x20,0x00}, // |
+ {0x40,0x20,0x20,0x10,0x20,0x20,0x40,0x00}, // }
+ {0x40,0xA8,0x10,0x00,0x00,0x00,0x00,0x00}, // ~
+ {0x70,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00} // DEL
+};
+/*
+const char FONT8x8F[97][8] = {
+ {0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00}, // columns, rows, bytes per char
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // space
+ {0x30,0x78,0x78,0x30,0x30,0x00,0x30,0x00}, // !
+ {0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00}, // "
+ {0x6C,0x6C,0xFE,0x6C,0xFE,0x6C,0x6C,0x00}, // #
+ {0x18,0x3E,0x60,0x3C,0x06,0x7C,0x18,0x00}, // $
+ {0x00,0x63,0x66,0x0C,0x18,0x33,0x63,0x00}, // %
+ {0x1C,0x36,0x1C,0x3B,0x6E,0x66,0x3B,0x00}, // &
+ {0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00}, // '
+ {0x0C,0x18,0x30,0x30,0x30,0x18,0x0C,0x00}, // (
+ {0x30,0x18,0x0C,0x0C,0x0C,0x18,0x30,0x00}, // )
+ {0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00}, // *
+ {0x00,0x30,0x30,0xFC,0x30,0x30,0x00,0x00}, // +
+ {0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x30}, // ,
+ {0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00}, // -
+ {0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00}, // .
+ {0x03,0x06,0x0C,0x18,0x30,0x60,0x40,0x00}, // /
+ {0x3E,0x63,0x63,0x6B,0x63,0x63,0x3E,0x00}, // 0
+ {0x18,0x38,0x58,0x18,0x18,0x18,0x7E,0x00}, // 1
+ {0x3C,0x66,0x06,0x1C,0x30,0x66,0x7E,0x00}, // 2
+ {0x3C,0x66,0x06,0x1C,0x06,0x66,0x3C,0x00}, // 3
+ {0x0E,0x1E,0x36,0x66,0x7F,0x06,0x0F,0x00}, // 4
+ {0x7E,0x60,0x7C,0x06,0x06,0x66,0x3C,0x00}, // 5
+ {0x1C,0x30,0x60,0x7C,0x66,0x66,0x3C,0x00}, // 6
+ {0x7E,0x66,0x06,0x0C,0x18,0x18,0x18,0x00}, // 7
+ {0x3C,0x66,0x66,0x3C,0x66,0x66,0x3C,0x00}, // 8
+ {0x3C,0x66,0x66,0x3E,0x06,0x0C,0x38,0x00}, // 9
+ {0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x00}, // :
+ {0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x30}, // ;
+ {0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x00}, // <
+ {0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00}, // =
+ {0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x00}, // >
+ {0x3C,0x66,0x06,0x0C,0x18,0x00,0x18,0x00}, // ?
+ {0x3E,0x63,0x6F,0x69,0x6F,0x60,0x3E,0x00}, // @
+ {0x18,0x3C,0x66,0x66,0x7E,0x66,0x66,0x00}, // A
+ {0x7E,0x33,0x33,0x3E,0x33,0x33,0x7E,0x00}, // B
+ {0x1E,0x33,0x60,0x60,0x60,0x33,0x1E,0x00}, // C
+ {0x7C,0x36,0x33,0x33,0x33,0x36,0x7C,0x00}, // D
+ {0x7F,0x31,0x34,0x3C,0x34,0x31,0x7F,0x00}, // E
+ {0x7F,0x31,0x34,0x3C,0x34,0x30,0x78,0x00}, // F
+ {0x1E,0x33,0x60,0x60,0x67,0x33,0x1F,0x00}, // G
+ {0x66,0x66,0x66,0x7E,0x66,0x66,0x66,0x00}, // H
+ {0x3C,0x18,0x18,0x18,0x18,0x18,0x3C,0x00}, // I
+ {0x0F,0x06,0x06,0x06,0x66,0x66,0x3C,0x00}, // J
+ {0x73,0x33,0x36,0x3C,0x36,0x33,0x73,0x00}, // K
+ {0x78,0x30,0x30,0x30,0x31,0x33,0x7F,0x00}, // L
+ {0x63,0x77,0x7F,0x7F,0x6B,0x63,0x63,0x00}, // M
+ {0x63,0x73,0x7B,0x6F,0x67,0x63,0x63,0x00}, // N
+ {0x3E,0x63,0x63,0x63,0x63,0x63,0x3E,0x00}, // O
+ {0x7E,0x33,0x33,0x3E,0x30,0x30,0x78,0x00}, // P
+ {0x3C,0x66,0x66,0x66,0x6E,0x3C,0x0E,0x00}, // Q
+ {0x7E,0x33,0x33,0x3E,0x36,0x33,0x73,0x00}, // R
+ {0x3C,0x66,0x30,0x18,0x0C,0x66,0x3C,0x00}, // S
+ {0x7E,0x5A,0x18,0x18,0x18,0x18,0x3C,0x00}, // T
+ {0x66,0x66,0x66,0x66,0x66,0x66,0x7E,0x00}, // U
+ {0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x00}, // V
+ {0x63,0x63,0x63,0x6B,0x7F,0x77,0x63,0x00}, // W
+ {0x63,0x63,0x36,0x1C,0x1C,0x36,0x63,0x00}, // X
+ {0x66,0x66,0x66,0x3C,0x18,0x18,0x3C,0x00}, // Y
+ {0x7F,0x63,0x46,0x0C,0x19,0x33,0x7F,0x00}, // Z
+ {0x3C,0x30,0x30,0x30,0x30,0x30,0x3C,0x00}, // [
+ {0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x00}, // backslash
+ {0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00}, // ]
+ {0x08,0x1C,0x36,0x63,0x00,0x00,0x00,0x00}, // ^
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF}, // _
+ {0x18,0x18,0x0C,0x00,0x00,0x00,0x00,0x00}, // `
+ {0x00,0x00,0x3C,0x06,0x3E,0x66,0x3B,0x00}, // a
+ {0x70,0x30,0x3E,0x33,0x33,0x33,0x6E,0x00}, // b
+ {0x00,0x00,0x3C,0x66,0x60,0x66,0x3C,0x00}, // c
+ {0x0E,0x06,0x3E,0x66,0x66,0x66,0x3B,0x00}, // d
+ {0x00,0x00,0x3C,0x66,0x7E,0x60,0x3C,0x00}, // e
+ {0x1C,0x36,0x30,0x78,0x30,0x30,0x78,0x00}, // f
+ {0x00,0x00,0x3B,0x66,0x66,0x3E,0x06,0x7C}, // g
+ {0x70,0x30,0x36,0x3B,0x33,0x33,0x73,0x00}, // h
+ {0x18,0x00,0x38,0x18,0x18,0x18,0x3C,0x00}, // i
+ {0x06,0x00,0x06,0x06,0x06,0x66,0x66,0x3C}, // j
+ {0x70,0x30,0x33,0x36,0x3C,0x36,0x73,0x00}, // k
+ {0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00}, // l
+ {0x00,0x00,0x66,0x7F,0x7F,0x6B,0x63,0x00}, // m
+ {0x00,0x00,0x7C,0x66,0x66,0x66,0x66,0x00}, // n
+ {0x00,0x00,0x3C,0x66,0x66,0x66,0x3C,0x00}, // o
+ {0x00,0x00,0x6E,0x33,0x33,0x3E,0x30,0x78}, // p
+ {0x00,0x00,0x3B,0x66,0x66,0x3E,0x06,0x0F}, // q
+ {0x00,0x00,0x6E,0x3B,0x33,0x30,0x78,0x00}, // r
+ {0x00,0x00,0x3E,0x60,0x3C,0x06,0x7C,0x00}, // s
+ {0x08,0x18,0x3E,0x18,0x18,0x1A,0x0C,0x00}, // t
+ {0x00,0x00,0x66,0x66,0x66,0x66,0x3B,0x00}, // u
+ {0x00,0x00,0x66,0x66,0x66,0x3C,0x18,0x00}, // v
+ {0x00,0x00,0x63,0x6B,0x7F,0x7F,0x36,0x00}, // w
+ {0x00,0x00,0x63,0x36,0x1C,0x36,0x63,0x00}, // x
+ {0x00,0x00,0x66,0x66,0x66,0x3E,0x06,0x7C}, // y
+ {0x00,0x00,0x7E,0x4C,0x18,0x32,0x7E,0x00}, // z
+ {0x0E,0x18,0x18,0x70,0x18,0x18,0x0E,0x00}, // {
+ {0x0C,0x0C,0x0C,0x00,0x0C,0x0C,0x0C,0x00}, // |
+ {0x70,0x18,0x18,0x0E,0x18,0x18,0x70,0x00}, // }
+ {0x3B,0x6E,0x00,0x00,0x00,0x00,0x00,0x00}, // ~
+ {0x1C,0x36,0x36,0x1C,0x00,0x00,0x00,0x00} // DEL
+};
+
+const char FONT8x16[97][16] = {
+ {0x08,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // columns, rows, bytes per char
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // space
+ {0x00,0x00,0x18,0x3C,0x3C,0x3C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00}, // !
+ {0x00,0x63,0x63,0x63,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // "
+ {0x00,0x00,0x00,0x36,0x36,0x7F,0x36,0x36,0x36,0x7F,0x36,0x36,0x00,0x00,0x00,0x00}, // #
+ {0x0C,0x0C,0x3E,0x63,0x61,0x60,0x3E,0x03,0x03,0x43,0x63,0x3E,0x0C,0x0C,0x00,0x00}, // $
+ {0x00,0x00,0x00,0x00,0x00,0x61,0x63,0x06,0x0C,0x18,0x33,0x63,0x00,0x00,0x00,0x00}, // %
+ {0x00,0x00,0x00,0x1C,0x36,0x36,0x1C,0x3B,0x6E,0x66,0x66,0x3B,0x00,0x00,0x00,0x00}, // &
+ {0x00,0x30,0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // '
+ {0x00,0x00,0x0C,0x18,0x18,0x30,0x30,0x30,0x30,0x18,0x18,0x0C,0x00,0x00,0x00,0x00}, // (
+ {0x00,0x00,0x18,0x0C,0x0C,0x06,0x06,0x06,0x06,0x0C,0x0C,0x18,0x00,0x00,0x00,0x00}, // )
+ {0x00,0x00,0x00,0x00,0x42,0x66,0x3C,0xFF,0x3C,0x66,0x42,0x00,0x00,0x00,0x00,0x00}, // *
+ {0x00,0x00,0x00,0x00,0x18,0x18,0x18,0xFF,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00}, // +
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00}, // ,
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // -
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00}, // .
+ {0x00,0x00,0x01,0x03,0x07,0x0E,0x1C,0x38,0x70,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00}, // /
+ {0x00,0x00,0x3E,0x63,0x63,0x63,0x6B,0x6B,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // 0
+ {0x00,0x00,0x0C,0x1C,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3F,0x00,0x00,0x00,0x00}, // 1
+ {0x00,0x00,0x3E,0x63,0x03,0x06,0x0C,0x18,0x30,0x61,0x63,0x7F,0x00,0x00,0x00,0x00}, // 2
+ {0x00,0x00,0x3E,0x63,0x03,0x03,0x1E,0x03,0x03,0x03,0x63,0x3E,0x00,0x00,0x00,0x00}, // 3
+ {0x00,0x00,0x06,0x0E,0x1E,0x36,0x66,0x66,0x7F,0x06,0x06,0x0F,0x00,0x00,0x00,0x00}, // 4
+ {0x00,0x00,0x7F,0x60,0x60,0x60,0x7E,0x03,0x03,0x63,0x73,0x3E,0x00,0x00,0x00,0x00}, // 5
+ {0x00,0x00,0x1C,0x30,0x60,0x60,0x7E,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // 6
+ {0x00,0x00,0x7F,0x63,0x03,0x06,0x06,0x0C,0x0C,0x18,0x18,0x18,0x00,0x00,0x00,0x00}, // 7
+ {0x00,0x00,0x3E,0x63,0x63,0x63,0x3E,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // 8
+ {0x00,0x00,0x3E,0x63,0x63,0x63,0x63,0x3F,0x03,0x03,0x06,0x3C,0x00,0x00,0x00,0x00}, // 9
+ {0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00}, // :
+ {0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00}, // ;
+ {0x00,0x00,0x00,0x06,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x06,0x00,0x00,0x00,0x00}, // <
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00}, // =
+ {0x00,0x00,0x00,0x60,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00}, // >
+ {0x00,0x00,0x3E,0x63,0x63,0x06,0x0C,0x0C,0x0C,0x00,0x0C,0x0C,0x00,0x00,0x00,0x00}, // ?
+ {0x00,0x00,0x3E,0x63,0x63,0x6F,0x6B,0x6B,0x6E,0x60,0x60,0x3E,0x00,0x00,0x00,0x00}, // @
+ {0x00,0x00,0x08,0x1C,0x36,0x63,0x63,0x63,0x7F,0x63,0x63,0x63,0x00,0x00,0x00,0x00}, // A
+ {0x00,0x00,0x7E,0x33,0x33,0x33,0x3E,0x33,0x33,0x33,0x33,0x7E,0x00,0x00,0x00,0x00}, // B
+ {0x00,0x00,0x1E,0x33,0x61,0x60,0x60,0x60,0x60,0x61,0x33,0x1E,0x00,0x00,0x00,0x00}, // C
+ {0x00,0x00,0x7C,0x36,0x33,0x33,0x33,0x33,0x33,0x33,0x36,0x7C,0x00,0x00,0x00,0x00}, // D
+ {0x00,0x00,0x7F,0x33,0x31,0x34,0x3C,0x34,0x30,0x31,0x33,0x7F,0x00,0x00,0x00,0x00}, // E
+ {0x00,0x00,0x7F,0x33,0x31,0x34,0x3C,0x34,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00}, // F
+ {0x00,0x00,0x1E,0x33,0x61,0x60,0x60,0x6F,0x63,0x63,0x37,0x1D,0x00,0x00,0x00,0x00}, // G
+ {0x00,0x00,0x63,0x63,0x63,0x63,0x7F,0x63,0x63,0x63,0x63,0x63,0x00,0x00,0x00,0x00}, // H
+ {0x00,0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}, // I
+ {0x00,0x00,0x0F,0x06,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3C,0x00,0x00,0x00,0x00}, // J
+ {0x00,0x00,0x73,0x33,0x36,0x36,0x3C,0x36,0x36,0x33,0x33,0x73,0x00,0x00,0x00,0x00}, // K
+ {0x00,0x00,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x31,0x33,0x7F,0x00,0x00,0x00,0x00}, // L
+ {0x00,0x00,0x63,0x77,0x7F,0x6B,0x63,0x63,0x63,0x63,0x63,0x63,0x00,0x00,0x00,0x00}, // M
+ {0x00,0x00,0x63,0x63,0x73,0x7B,0x7F,0x6F,0x67,0x63,0x63,0x63,0x00,0x00,0x00,0x00}, // N
+ {0x00,0x00,0x1C,0x36,0x63,0x63,0x63,0x63,0x63,0x63,0x36,0x1C,0x00,0x00,0x00,0x00}, // O
+ {0x00,0x00,0x7E,0x33,0x33,0x33,0x3E,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00}, // P
+ {0x00,0x00,0x3E,0x63,0x63,0x63,0x63,0x63,0x63,0x6B,0x6F,0x3E,0x06,0x07,0x00,0x00}, // Q
+ {0x00,0x00,0x7E,0x33,0x33,0x33,0x3E,0x36,0x36,0x33,0x33,0x73,0x00,0x00,0x00,0x00}, // R
+ {0x00,0x00,0x3E,0x63,0x63,0x30,0x1C,0x06,0x03,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // S
+ {0x00,0x00,0xFF,0xDB,0x99,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}, // T
+ {0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // U
+ {0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x36,0x1C,0x08,0x00,0x00,0x00,0x00}, // V
+ {0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x6B,0x6B,0x7F,0x36,0x36,0x00,0x00,0x00,0x00}, // W
+ {0x00,0x00,0xC3,0xC3,0x66,0x3C,0x18,0x18,0x3C,0x66,0xC3,0xC3,0x00,0x00,0x00,0x00}, // X
+ {0x00,0x00,0xC3,0xC3,0xC3,0x66,0x3C,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}, // Y
+ {0x00,0x00,0x7F,0x63,0x43,0x06,0x0C,0x18,0x30,0x61,0x63,0x7F,0x00,0x00,0x00,0x00}, // Z
+ {0x00,0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,0x00,0x00,0x00}, // [
+ {0x00,0x00,0x80,0xC0,0xE0,0x70,0x38,0x1C,0x0E,0x07,0x03,0x01,0x00,0x00,0x00,0x00}, // backslash
+ {0x00,0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00,0x00,0x00,0x00}, // ]
+ {0x08,0x1C,0x36,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // ^
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00}, // _
+ {0x18,0x18,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // `
+ {0x00,0x00,0x00,0x00,0x00,0x3C,0x46,0x06,0x3E,0x66,0x66,0x3B,0x00,0x00,0x00,0x00}, // a
+ {0x00,0x00,0x70,0x30,0x30,0x3C,0x36,0x33,0x33,0x33,0x33,0x6E,0x00,0x00,0x00,0x00}, // b
+ {0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x60,0x60,0x60,0x63,0x3E,0x00,0x00,0x00,0x00}, // c
+ {0x00,0x00,0x0E,0x06,0x06,0x1E,0x36,0x66,0x66,0x66,0x66,0x3B,0x00,0x00,0x00,0x00}, // d
+ {0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x63,0x7E,0x60,0x63,0x3E,0x00,0x00,0x00,0x00}, // e
+ {0x00,0x00,0x1C,0x36,0x32,0x30,0x7C,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00}, // f
+ {0x00,0x00,0x00,0x00,0x00,0x3B,0x66,0x66,0x66,0x66,0x3E,0x06,0x66,0x3C,0x00,0x00}, // g
+ {0x00,0x00,0x70,0x30,0x30,0x36,0x3B,0x33,0x33,0x33,0x33,0x73,0x00,0x00,0x00,0x00}, // h
+ {0x00,0x00,0x0C,0x0C,0x00,0x1C,0x0C,0x0C,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00}, // i
+ {0x00,0x00,0x06,0x06,0x00,0x0E,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3C,0x00,0x00}, // j
+ {0x00,0x00,0x70,0x30,0x30,0x33,0x33,0x36,0x3C,0x36,0x33,0x73,0x00,0x00,0x00,0x00}, // k
+ {0x00,0x00,0x1C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00}, // l
+ {0x00,0x00,0x00,0x00,0x00,0x6E,0x7F,0x6B,0x6B,0x6B,0x6B,0x6B,0x00,0x00,0x00,0x00}, // m
+ {0x00,0x00,0x00,0x00,0x00,0x6E,0x33,0x33,0x33,0x33,0x33,0x33,0x00,0x00,0x00,0x00}, // n
+ {0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // o
+ {0x00,0x00,0x00,0x00,0x00,0x6E,0x33,0x33,0x33,0x33,0x3E,0x30,0x30,0x78,0x00,0x00}, // p
+ {0x00,0x00,0x00,0x00,0x00,0x3B,0x66,0x66,0x66,0x66,0x3E,0x06,0x06,0x0F,0x00,0x00}, // q
+ {0x00,0x00,0x00,0x00,0x00,0x6E,0x3B,0x33,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00}, // r
+ {0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x38,0x0E,0x03,0x63,0x3E,0x00,0x00,0x00,0x00}, // s
+ {0x00,0x00,0x08,0x18,0x18,0x7E,0x18,0x18,0x18,0x18,0x1B,0x0E,0x00,0x00,0x00,0x00}, // t
+ {0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x3B,0x00,0x00,0x00,0x00}, // u
+ {0x00,0x00,0x00,0x00,0x00,0x63,0x63,0x36,0x36,0x1C,0x1C,0x08,0x00,0x00,0x00,0x00}, // v
+ {0x00,0x00,0x00,0x00,0x00,0x63,0x63,0x63,0x6B,0x6B,0x7F,0x36,0x00,0x00,0x00,0x00}, // w
+ {0x00,0x00,0x00,0x00,0x00,0x63,0x36,0x1C,0x1C,0x1C,0x36,0x63,0x00,0x00,0x00,0x00}, // x
+ {0x00,0x00,0x00,0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x3F,0x03,0x06,0x3C,0x00,0x00}, // y
+ {0x00,0x00,0x00,0x00,0x00,0x7F,0x66,0x0C,0x18,0x30,0x63,0x7F,0x00,0x00,0x00,0x00}, // z
+ {0x00,0x00,0x0E,0x18,0x18,0x18,0x70,0x18,0x18,0x18,0x18,0x0E,0x00,0x00,0x00,0x00}, // {
+ {0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00}, // |
+ {0x00,0x00,0x70,0x18,0x18,0x18,0x0E,0x18,0x18,0x18,0x18,0x70,0x00,0x00,0x00,0x00}, // }
+ {0x00,0x00,0x3B,0x6E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // ~
+ {0x00,0x70,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} // DEL
+};
+*/
-#ifndef __FONTS_H\r
-#define __FONTS_H\r
-extern const char FONT6x8[97][8];\r
-extern const char FONT8x8F[97][8];\r
-extern const char FONT8x16[97][16];\r
-#endif\r
+#ifndef __FONTS_H
+#define __FONTS_H
+extern const char FONT6x8[97][8];
+extern const char FONT8x8F[97][8];
+extern const char FONT8x16[97][16];
+#endif
-//-----------------------------------------------------------------------------\r
-// Routines to load the FPGA image, and then to configure the FPGA's major\r
-// mode once it is configured.\r
-//\r
-// Jonathan Westhues, April 2006\r
-//-----------------------------------------------------------------------------\r
-#include <proxmark3.h>\r
-#include "apps.h"\r
-\r
-//-----------------------------------------------------------------------------\r
-// Set up the Serial Peripheral Interface as master\r
-// Used to write the FPGA config word\r
-// May also be used to write to other SPI attached devices like an LCD\r
-//-----------------------------------------------------------------------------\r
-void SetupSpi(int mode)\r
-{\r
- // PA10 -> SPI_NCS2 chip select (LCD)\r
- // PA11 -> SPI_NCS0 chip select (FPGA)\r
- // PA12 -> SPI_MISO Master-In Slave-Out\r
- // PA13 -> SPI_MOSI Master-Out Slave-In\r
- // PA14 -> SPI_SPCK Serial Clock\r
-\r
- // Disable PIO control of the following pins, allows use by the SPI peripheral\r
- AT91C_BASE_PIOA->PIO_PDR =\r
- GPIO_NCS0 |\r
- GPIO_NCS2 |\r
- GPIO_MISO |\r
- GPIO_MOSI |\r
- GPIO_SPCK;\r
-\r
- AT91C_BASE_PIOA->PIO_ASR =\r
- GPIO_NCS0 |\r
- GPIO_MISO |\r
- GPIO_MOSI |\r
- GPIO_SPCK;\r
-\r
- AT91C_BASE_PIOA->PIO_BSR = GPIO_NCS2;\r
-\r
- //enable the SPI Peripheral clock\r
- AT91C_BASE_PMC->PMC_PCER = (1<<AT91C_ID_SPI);\r
- // Enable SPI\r
- AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIEN;\r
-\r
- switch (mode) {\r
- case SPI_FPGA_MODE:\r
- AT91C_BASE_SPI->SPI_MR =\r
- ( 0 << 24) | // Delay between chip selects (take default: 6 MCK periods)\r
- (14 << 16) | // Peripheral Chip Select (selects FPGA SPI_NCS0 or PA11)\r
- ( 0 << 7) | // Local Loopback Disabled\r
- ( 1 << 4) | // Mode Fault Detection disabled\r
- ( 0 << 2) | // Chip selects connected directly to peripheral\r
- ( 0 << 1) | // Fixed Peripheral Select\r
- ( 1 << 0); // Master Mode\r
- AT91C_BASE_SPI->SPI_CSR[0] =\r
- ( 1 << 24) | // Delay between Consecutive Transfers (32 MCK periods)\r
- ( 1 << 16) | // Delay Before SPCK (1 MCK period)\r
- ( 6 << 8) | // Serial Clock Baud Rate (baudrate = MCK/6 = 24Mhz/6 = 4M baud\r
- ( 8 << 4) | // Bits per Transfer (16 bits)\r
- ( 0 << 3) | // Chip Select inactive after transfer\r
- ( 1 << 1) | // Clock Phase data captured on leading edge, changes on following edge\r
- ( 0 << 0); // Clock Polarity inactive state is logic 0\r
- break;\r
- case SPI_LCD_MODE:\r
- AT91C_BASE_SPI->SPI_MR =\r
- ( 0 << 24) | // Delay between chip selects (take default: 6 MCK periods)\r
- (11 << 16) | // Peripheral Chip Select (selects LCD SPI_NCS2 or PA10)\r
- ( 0 << 7) | // Local Loopback Disabled\r
- ( 1 << 4) | // Mode Fault Detection disabled\r
- ( 0 << 2) | // Chip selects connected directly to peripheral\r
- ( 0 << 1) | // Fixed Peripheral Select\r
- ( 1 << 0); // Master Mode\r
- AT91C_BASE_SPI->SPI_CSR[2] =\r
- ( 1 << 24) | // Delay between Consecutive Transfers (32 MCK periods)\r
- ( 1 << 16) | // Delay Before SPCK (1 MCK period)\r
- ( 6 << 8) | // Serial Clock Baud Rate (baudrate = MCK/6 = 24Mhz/6 = 4M baud\r
- ( 1 << 4) | // Bits per Transfer (9 bits)\r
- ( 0 << 3) | // Chip Select inactive after transfer\r
- ( 1 << 1) | // Clock Phase data captured on leading edge, changes on following edge\r
- ( 0 << 0); // Clock Polarity inactive state is logic 0\r
- break;\r
- default: // Disable SPI\r
- AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIDIS;\r
- break;\r
- }\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-// Set up the synchronous serial port, with the one set of options that we\r
-// always use when we are talking to the FPGA. Both RX and TX are enabled.\r
-//-----------------------------------------------------------------------------\r
-void FpgaSetupSsc(void)\r
-{\r
- // First configure the GPIOs, and get ourselves a clock.\r
- AT91C_BASE_PIOA->PIO_ASR =\r
- GPIO_SSC_FRAME |\r
- GPIO_SSC_DIN |\r
- GPIO_SSC_DOUT |\r
- GPIO_SSC_CLK;\r
- AT91C_BASE_PIOA->PIO_PDR = GPIO_SSC_DOUT;\r
-\r
- AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_SSC);\r
-\r
- // Now set up the SSC proper, starting from a known state.\r
- AT91C_BASE_SSC->SSC_CR = AT91C_SSC_SWRST;\r
-\r
- // RX clock comes from TX clock, RX starts when TX starts, data changes\r
- // on RX clock rising edge, sampled on falling edge\r
- AT91C_BASE_SSC->SSC_RCMR = SSC_CLOCK_MODE_SELECT(1) | SSC_CLOCK_MODE_START(1);\r
-\r
- // 8 bits per transfer, no loopback, MSB first, 1 transfer per sync\r
- // pulse, no output sync, start on positive-going edge of sync\r
- AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) |\r
- AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0);\r
-\r
- // clock comes from TK pin, no clock output, outputs change on falling\r
- // edge of TK, start on rising edge of TF\r
- AT91C_BASE_SSC->SSC_TCMR = SSC_CLOCK_MODE_SELECT(2) |\r
- SSC_CLOCK_MODE_START(5);\r
-\r
- // tx framing is the same as the rx framing\r
- AT91C_BASE_SSC->SSC_TFMR = AT91C_BASE_SSC->SSC_RFMR;\r
-\r
- AT91C_BASE_SSC->SSC_CR = AT91C_SSC_RXEN | AT91C_SSC_TXEN;\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-// Set up DMA to receive samples from the FPGA. We will use the PDC, with\r
-// a single buffer as a circular buffer (so that we just chain back to\r
-// ourselves, not to another buffer). The stuff to manipulate those buffers\r
-// is in apps.h, because it should be inlined, for speed.\r
-//-----------------------------------------------------------------------------\r
-void FpgaSetupSscDma(BYTE *buf, int len)\r
-{\r
- AT91C_BASE_PDC_SSC->PDC_RPR = (DWORD)buf;\r
- AT91C_BASE_PDC_SSC->PDC_RCR = len;\r
- AT91C_BASE_PDC_SSC->PDC_RNPR = (DWORD)buf;\r
- AT91C_BASE_PDC_SSC->PDC_RNCR = len;\r
- AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTEN;\r
-}\r
-\r
-static void DownloadFPGA_byte(unsigned char w)\r
-{\r
-#define SEND_BIT(x) { if(w & (1<<x) ) HIGH(GPIO_FPGA_DIN); else LOW(GPIO_FPGA_DIN); HIGH(GPIO_FPGA_CCLK); LOW(GPIO_FPGA_CCLK); }\r
- SEND_BIT(7);\r
- SEND_BIT(6);\r
- SEND_BIT(5);\r
- SEND_BIT(4);\r
- SEND_BIT(3);\r
- SEND_BIT(2);\r
- SEND_BIT(1);\r
- SEND_BIT(0);\r
-}\r
-\r
-// Download the fpga image starting at FpgaImage and with length FpgaImageLen bytes\r
-// If bytereversal is set: reverse the byte order in each 4-byte word\r
-static void DownloadFPGA(const char *FpgaImage, int FpgaImageLen, int bytereversal)\r
-{\r
- int i=0;\r
-\r
- AT91C_BASE_PIOA->PIO_OER = GPIO_FPGA_ON;\r
- AT91C_BASE_PIOA->PIO_PER = GPIO_FPGA_ON;\r
- HIGH(GPIO_FPGA_ON); // ensure everything is powered on\r
-\r
- SpinDelay(50);\r
-\r
- LED_D_ON();\r
-\r
- // These pins are inputs\r
- AT91C_BASE_PIOA->PIO_ODR =\r
- GPIO_FPGA_NINIT |\r
- GPIO_FPGA_DONE;\r
- // PIO controls the following pins\r
- AT91C_BASE_PIOA->PIO_PER =\r
- GPIO_FPGA_NINIT |\r
- GPIO_FPGA_DONE;\r
- // Enable pull-ups\r
- AT91C_BASE_PIOA->PIO_PPUER =\r
- GPIO_FPGA_NINIT |\r
- GPIO_FPGA_DONE;\r
-\r
- // setup initial logic state\r
- HIGH(GPIO_FPGA_NPROGRAM);\r
- LOW(GPIO_FPGA_CCLK);\r
- LOW(GPIO_FPGA_DIN);\r
- // These pins are outputs\r
- AT91C_BASE_PIOA->PIO_OER =\r
- GPIO_FPGA_NPROGRAM |\r
- GPIO_FPGA_CCLK |\r
- GPIO_FPGA_DIN;\r
-\r
- // enter FPGA configuration mode\r
- LOW(GPIO_FPGA_NPROGRAM);\r
- SpinDelay(50);\r
- HIGH(GPIO_FPGA_NPROGRAM);\r
-\r
- i=100000;\r
- // wait for FPGA ready to accept data signal\r
- while ((i) && ( !(AT91C_BASE_PIOA->PIO_PDSR & GPIO_FPGA_NINIT ) ) ) {\r
- i--;\r
- }\r
-\r
- // crude error indicator, leave both red LEDs on and return\r
- if (i==0){\r
- LED_C_ON();\r
- LED_D_ON();\r
- return;\r
- }\r
-\r
- if(bytereversal) {\r
- /* This is only supported for DWORD aligned images */\r
- if( ((int)FpgaImage % sizeof(DWORD)) == 0 ) {\r
- i=0;\r
- while(FpgaImageLen-->0)\r
- DownloadFPGA_byte(FpgaImage[(i++)^0x3]);\r
- /* Explanation of the magic in the above line: \r
- * i^0x3 inverts the lower two bits of the integer i, counting backwards\r
- * for each 4 byte increment. The generated sequence of (i++)^3 is\r
- * 3 2 1 0 7 6 5 4 11 10 9 8 15 14 13 12 etc. pp. \r
- */\r
- }\r
- } else {\r
- while(FpgaImageLen-->0)\r
- DownloadFPGA_byte(*FpgaImage++);\r
- }\r
-\r
- // continue to clock FPGA until ready signal goes high\r
- i=100000;\r
- while ( (i--) && ( !(AT91C_BASE_PIOA->PIO_PDSR & GPIO_FPGA_DONE ) ) ) {\r
- HIGH(GPIO_FPGA_CCLK);\r
- LOW(GPIO_FPGA_CCLK);\r
- }\r
- // crude error indicator, leave both red LEDs on and return\r
- if (i==0){\r
- LED_C_ON();\r
- LED_D_ON();\r
- return;\r
- }\r
- LED_D_OFF();\r
-}\r
-\r
-static char *bitparse_headers_start;\r
-static char *bitparse_bitstream_end;\r
-static int bitparse_initialized;\r
-/* Simple Xilinx .bit parser. The file starts with the fixed opaque byte sequence\r
- * 00 09 0f f0 0f f0 0f f0 0f f0 00 00 01\r
- * After that the format is 1 byte section type (ASCII character), 2 byte length\r
- * (big endian), <length> bytes content. Except for section 'e' which has 4 bytes\r
- * length.\r
- */\r
-static const char _bitparse_fixed_header[] = {0x00, 0x09, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x00, 0x00, 0x01};\r
-static int bitparse_init(void * start_address, void *end_address)\r
-{\r
- bitparse_initialized = 0;\r
- \r
- if(memcmp(_bitparse_fixed_header, start_address, sizeof(_bitparse_fixed_header)) != 0) {\r
- return 0; /* Not matched */\r
- } else {\r
- bitparse_headers_start= ((char*)start_address) + sizeof(_bitparse_fixed_header);\r
- bitparse_bitstream_end= (char*)end_address;\r
- bitparse_initialized = 1;\r
- return 1;\r
- }\r
-}\r
-\r
-int bitparse_find_section(char section_name, char **section_start, unsigned int *section_length)\r
-{\r
- char *pos = bitparse_headers_start;\r
- int result = 0;\r
-\r
- if(!bitparse_initialized) return 0;\r
-\r
- while(pos < bitparse_bitstream_end) {\r
- char current_name = *pos++;\r
- unsigned int current_length = 0;\r
- if(current_name < 'a' || current_name > 'e') {\r
- /* Strange section name, abort */\r
- break;\r
- }\r
- current_length = 0;\r
- switch(current_name) {\r
- case 'e':\r
- /* Four byte length field */\r
- current_length += (*pos++) << 24;\r
- current_length += (*pos++) << 16;\r
- default: /* Fall through, two byte length field */\r
- current_length += (*pos++) << 8;\r
- current_length += (*pos++) << 0;\r
- }\r
- \r
- if(current_name != 'e' && current_length > 255) {\r
- /* Maybe a parse error */\r
- break;\r
- }\r
- \r
- if(current_name == section_name) {\r
- /* Found it */\r
- *section_start = pos;\r
- *section_length = current_length;\r
- result = 1;\r
- break;\r
- }\r
- \r
- pos += current_length; /* Skip section */\r
- }\r
- \r
- return result;\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-// Find out which FPGA image format is stored in flash, then call DownloadFPGA\r
-// with the right parameters to download the image\r
-//-----------------------------------------------------------------------------\r
-extern char _binary_fpga_bit_start, _binary_fpga_bit_end;\r
-void FpgaDownloadAndGo(void)\r
-{\r
- /* Check for the new flash image format: Should have the .bit file at &_binary_fpga_bit_start\r
- */\r
- if(bitparse_init(&_binary_fpga_bit_start, &_binary_fpga_bit_end)) {\r
- /* Successfully initialized the .bit parser. Find the 'e' section and\r
- * send its contents to the FPGA.\r
- */\r
- char *bitstream_start;\r
- unsigned int bitstream_length;\r
- if(bitparse_find_section('e', &bitstream_start, &bitstream_length)) {\r
- DownloadFPGA(bitstream_start, bitstream_length, 0);\r
- \r
- return; /* All done */\r
- }\r
- }\r
- \r
- /* Fallback for the old flash image format: Check for the magic marker 0xFFFFFFFF\r
- * 0xAA995566 at address 0x102000. This is raw bitstream with a size of 336,768 bits \r
- * = 10,524 DWORDs, stored as DWORDS e.g. little-endian in memory, but each DWORD\r
- * is still to be transmitted in MSBit first order. Set the invert flag to indicate\r
- * that the DownloadFPGA function should invert every 4 byte sequence when doing\r
- * the bytewise download.\r
- */\r
- if( *(DWORD*)0x102000 == 0xFFFFFFFF && *(DWORD*)0x102004 == 0xAA995566 )\r
- DownloadFPGA((char*)0x102000, 10524*4, 1);\r
-}\r
-\r
-void FpgaGatherVersion(char *dst, int len)\r
-{\r
- char *fpga_info; \r
- unsigned int fpga_info_len;\r
- dst[0] = 0;\r
- if(!bitparse_find_section('e', &fpga_info, &fpga_info_len)) {\r
- strncat(dst, "FPGA image: legacy image without version information", len-1);\r
- } else {\r
- strncat(dst, "FPGA image built", len-1);\r
- /* USB packets only have 48 bytes data payload, so be terse */\r
-#if 0\r
- if(bitparse_find_section('a', &fpga_info, &fpga_info_len) && fpga_info[fpga_info_len-1] == 0 ) {\r
- strncat(dst, " from ", len-1);\r
- strncat(dst, fpga_info, len-1);\r
- }\r
- if(bitparse_find_section('b', &fpga_info, &fpga_info_len) && fpga_info[fpga_info_len-1] == 0 ) {\r
- strncat(dst, " for ", len-1);\r
- strncat(dst, fpga_info, len-1);\r
- }\r
-#endif\r
- if(bitparse_find_section('c', &fpga_info, &fpga_info_len) && fpga_info[fpga_info_len-1] == 0 ) {\r
- strncat(dst, " on ", len-1);\r
- strncat(dst, fpga_info, len-1);\r
- }\r
- if(bitparse_find_section('d', &fpga_info, &fpga_info_len) && fpga_info[fpga_info_len-1] == 0 ) {\r
- strncat(dst, " at ", len-1);\r
- strncat(dst, fpga_info, len-1);\r
- }\r
- }\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-// Send a 16 bit command/data pair to the FPGA.\r
-// The bit format is: C3 C2 C1 C0 D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0\r
-// where C is the 4 bit command and D is the 12 bit data\r
-//-----------------------------------------------------------------------------\r
-void FpgaSendCommand(WORD cmd, WORD v)\r
-{\r
- SetupSpi(SPI_FPGA_MODE);\r
- while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0); // wait for the transfer to complete\r
- AT91C_BASE_SPI->SPI_TDR = AT91C_SPI_LASTXFER | cmd | v; // send the data\r
-}\r
-//-----------------------------------------------------------------------------\r
-// Write the FPGA setup word (that determines what mode the logic is in, read\r
-// vs. clone vs. etc.). This is now a special case of FpgaSendCommand() to\r
-// avoid changing this function's occurence everywhere in the source code.\r
-//-----------------------------------------------------------------------------\r
-void FpgaWriteConfWord(BYTE v)\r
-{\r
- FpgaSendCommand(FPGA_CMD_SET_CONFREG, v);\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-// Set up the CMOS switches that mux the ADC: four switches, independently\r
-// closable, but should only close one at a time. Not an FPGA thing, but\r
-// the samples from the ADC always flow through the FPGA.\r
-//-----------------------------------------------------------------------------\r
-void SetAdcMuxFor(DWORD whichGpio)\r
-{\r
- AT91C_BASE_PIOA->PIO_OER =\r
- GPIO_MUXSEL_HIPKD |\r
- GPIO_MUXSEL_LOPKD |\r
- GPIO_MUXSEL_LORAW |\r
- GPIO_MUXSEL_HIRAW;\r
-\r
- AT91C_BASE_PIOA->PIO_PER =\r
- GPIO_MUXSEL_HIPKD |\r
- GPIO_MUXSEL_LOPKD |\r
- GPIO_MUXSEL_LORAW |\r
- GPIO_MUXSEL_HIRAW;\r
-\r
- LOW(GPIO_MUXSEL_HIPKD);\r
- LOW(GPIO_MUXSEL_HIRAW);\r
- LOW(GPIO_MUXSEL_LORAW);\r
- LOW(GPIO_MUXSEL_LOPKD);\r
-\r
- HIGH(whichGpio);\r
-}\r
+//-----------------------------------------------------------------------------
+// Routines to load the FPGA image, and then to configure the FPGA's major
+// mode once it is configured.
+//
+// Jonathan Westhues, April 2006
+//-----------------------------------------------------------------------------
+#include <proxmark3.h>
+#include "apps.h"
+
+//-----------------------------------------------------------------------------
+// Set up the Serial Peripheral Interface as master
+// Used to write the FPGA config word
+// May also be used to write to other SPI attached devices like an LCD
+//-----------------------------------------------------------------------------
+void SetupSpi(int mode)
+{
+ // PA10 -> SPI_NCS2 chip select (LCD)
+ // PA11 -> SPI_NCS0 chip select (FPGA)
+ // PA12 -> SPI_MISO Master-In Slave-Out
+ // PA13 -> SPI_MOSI Master-Out Slave-In
+ // PA14 -> SPI_SPCK Serial Clock
+
+ // Disable PIO control of the following pins, allows use by the SPI peripheral
+ AT91C_BASE_PIOA->PIO_PDR =
+ GPIO_NCS0 |
+ GPIO_NCS2 |
+ GPIO_MISO |
+ GPIO_MOSI |
+ GPIO_SPCK;
+
+ AT91C_BASE_PIOA->PIO_ASR =
+ GPIO_NCS0 |
+ GPIO_MISO |
+ GPIO_MOSI |
+ GPIO_SPCK;
+
+ AT91C_BASE_PIOA->PIO_BSR = GPIO_NCS2;
+
+ //enable the SPI Peripheral clock
+ AT91C_BASE_PMC->PMC_PCER = (1<<AT91C_ID_SPI);
+ // Enable SPI
+ AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIEN;
+
+ switch (mode) {
+ case SPI_FPGA_MODE:
+ AT91C_BASE_SPI->SPI_MR =
+ ( 0 << 24) | // Delay between chip selects (take default: 6 MCK periods)
+ (14 << 16) | // Peripheral Chip Select (selects FPGA SPI_NCS0 or PA11)
+ ( 0 << 7) | // Local Loopback Disabled
+ ( 1 << 4) | // Mode Fault Detection disabled
+ ( 0 << 2) | // Chip selects connected directly to peripheral
+ ( 0 << 1) | // Fixed Peripheral Select
+ ( 1 << 0); // Master Mode
+ AT91C_BASE_SPI->SPI_CSR[0] =
+ ( 1 << 24) | // Delay between Consecutive Transfers (32 MCK periods)
+ ( 1 << 16) | // Delay Before SPCK (1 MCK period)
+ ( 6 << 8) | // Serial Clock Baud Rate (baudrate = MCK/6 = 24Mhz/6 = 4M baud
+ ( 8 << 4) | // Bits per Transfer (16 bits)
+ ( 0 << 3) | // Chip Select inactive after transfer
+ ( 1 << 1) | // Clock Phase data captured on leading edge, changes on following edge
+ ( 0 << 0); // Clock Polarity inactive state is logic 0
+ break;
+ case SPI_LCD_MODE:
+ AT91C_BASE_SPI->SPI_MR =
+ ( 0 << 24) | // Delay between chip selects (take default: 6 MCK periods)
+ (11 << 16) | // Peripheral Chip Select (selects LCD SPI_NCS2 or PA10)
+ ( 0 << 7) | // Local Loopback Disabled
+ ( 1 << 4) | // Mode Fault Detection disabled
+ ( 0 << 2) | // Chip selects connected directly to peripheral
+ ( 0 << 1) | // Fixed Peripheral Select
+ ( 1 << 0); // Master Mode
+ AT91C_BASE_SPI->SPI_CSR[2] =
+ ( 1 << 24) | // Delay between Consecutive Transfers (32 MCK periods)
+ ( 1 << 16) | // Delay Before SPCK (1 MCK period)
+ ( 6 << 8) | // Serial Clock Baud Rate (baudrate = MCK/6 = 24Mhz/6 = 4M baud
+ ( 1 << 4) | // Bits per Transfer (9 bits)
+ ( 0 << 3) | // Chip Select inactive after transfer
+ ( 1 << 1) | // Clock Phase data captured on leading edge, changes on following edge
+ ( 0 << 0); // Clock Polarity inactive state is logic 0
+ break;
+ default: // Disable SPI
+ AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIDIS;
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Set up the synchronous serial port, with the one set of options that we
+// always use when we are talking to the FPGA. Both RX and TX are enabled.
+//-----------------------------------------------------------------------------
+void FpgaSetupSsc(void)
+{
+ // First configure the GPIOs, and get ourselves a clock.
+ AT91C_BASE_PIOA->PIO_ASR =
+ GPIO_SSC_FRAME |
+ GPIO_SSC_DIN |
+ GPIO_SSC_DOUT |
+ GPIO_SSC_CLK;
+ AT91C_BASE_PIOA->PIO_PDR = GPIO_SSC_DOUT;
+
+ AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_SSC);
+
+ // Now set up the SSC proper, starting from a known state.
+ AT91C_BASE_SSC->SSC_CR = AT91C_SSC_SWRST;
+
+ // RX clock comes from TX clock, RX starts when TX starts, data changes
+ // on RX clock rising edge, sampled on falling edge
+ AT91C_BASE_SSC->SSC_RCMR = SSC_CLOCK_MODE_SELECT(1) | SSC_CLOCK_MODE_START(1);
+
+ // 8 bits per transfer, no loopback, MSB first, 1 transfer per sync
+ // pulse, no output sync, start on positive-going edge of sync
+ AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) |
+ AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0);
+
+ // clock comes from TK pin, no clock output, outputs change on falling
+ // edge of TK, start on rising edge of TF
+ AT91C_BASE_SSC->SSC_TCMR = SSC_CLOCK_MODE_SELECT(2) |
+ SSC_CLOCK_MODE_START(5);
+
+ // tx framing is the same as the rx framing
+ AT91C_BASE_SSC->SSC_TFMR = AT91C_BASE_SSC->SSC_RFMR;
+
+ AT91C_BASE_SSC->SSC_CR = AT91C_SSC_RXEN | AT91C_SSC_TXEN;
+}
+
+//-----------------------------------------------------------------------------
+// Set up DMA to receive samples from the FPGA. We will use the PDC, with
+// a single buffer as a circular buffer (so that we just chain back to
+// ourselves, not to another buffer). The stuff to manipulate those buffers
+// is in apps.h, because it should be inlined, for speed.
+//-----------------------------------------------------------------------------
+void FpgaSetupSscDma(BYTE *buf, int len)
+{
+ AT91C_BASE_PDC_SSC->PDC_RPR = (DWORD)buf;
+ AT91C_BASE_PDC_SSC->PDC_RCR = len;
+ AT91C_BASE_PDC_SSC->PDC_RNPR = (DWORD)buf;
+ AT91C_BASE_PDC_SSC->PDC_RNCR = len;
+ AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTEN;
+}
+
+static void DownloadFPGA_byte(unsigned char w)
+{
+#define SEND_BIT(x) { if(w & (1<<x) ) HIGH(GPIO_FPGA_DIN); else LOW(GPIO_FPGA_DIN); HIGH(GPIO_FPGA_CCLK); LOW(GPIO_FPGA_CCLK); }
+ SEND_BIT(7);
+ SEND_BIT(6);
+ SEND_BIT(5);
+ SEND_BIT(4);
+ SEND_BIT(3);
+ SEND_BIT(2);
+ SEND_BIT(1);
+ SEND_BIT(0);
+}
+
+// Download the fpga image starting at FpgaImage and with length FpgaImageLen bytes
+// If bytereversal is set: reverse the byte order in each 4-byte word
+static void DownloadFPGA(const char *FpgaImage, int FpgaImageLen, int bytereversal)
+{
+ int i=0;
+
+ AT91C_BASE_PIOA->PIO_OER = GPIO_FPGA_ON;
+ AT91C_BASE_PIOA->PIO_PER = GPIO_FPGA_ON;
+ HIGH(GPIO_FPGA_ON); // ensure everything is powered on
+
+ SpinDelay(50);
+
+ LED_D_ON();
+
+ // These pins are inputs
+ AT91C_BASE_PIOA->PIO_ODR =
+ GPIO_FPGA_NINIT |
+ GPIO_FPGA_DONE;
+ // PIO controls the following pins
+ AT91C_BASE_PIOA->PIO_PER =
+ GPIO_FPGA_NINIT |
+ GPIO_FPGA_DONE;
+ // Enable pull-ups
+ AT91C_BASE_PIOA->PIO_PPUER =
+ GPIO_FPGA_NINIT |
+ GPIO_FPGA_DONE;
+
+ // setup initial logic state
+ HIGH(GPIO_FPGA_NPROGRAM);
+ LOW(GPIO_FPGA_CCLK);
+ LOW(GPIO_FPGA_DIN);
+ // These pins are outputs
+ AT91C_BASE_PIOA->PIO_OER =
+ GPIO_FPGA_NPROGRAM |
+ GPIO_FPGA_CCLK |
+ GPIO_FPGA_DIN;
+
+ // enter FPGA configuration mode
+ LOW(GPIO_FPGA_NPROGRAM);
+ SpinDelay(50);
+ HIGH(GPIO_FPGA_NPROGRAM);
+
+ i=100000;
+ // wait for FPGA ready to accept data signal
+ while ((i) && ( !(AT91C_BASE_PIOA->PIO_PDSR & GPIO_FPGA_NINIT ) ) ) {
+ i--;
+ }
+
+ // crude error indicator, leave both red LEDs on and return
+ if (i==0){
+ LED_C_ON();
+ LED_D_ON();
+ return;
+ }
+
+ if(bytereversal) {
+ /* This is only supported for DWORD aligned images */
+ if( ((int)FpgaImage % sizeof(DWORD)) == 0 ) {
+ i=0;
+ while(FpgaImageLen-->0)
+ DownloadFPGA_byte(FpgaImage[(i++)^0x3]);
+ /* Explanation of the magic in the above line:
+ * i^0x3 inverts the lower two bits of the integer i, counting backwards
+ * for each 4 byte increment. The generated sequence of (i++)^3 is
+ * 3 2 1 0 7 6 5 4 11 10 9 8 15 14 13 12 etc. pp.
+ */
+ }
+ } else {
+ while(FpgaImageLen-->0)
+ DownloadFPGA_byte(*FpgaImage++);
+ }
+
+ // continue to clock FPGA until ready signal goes high
+ i=100000;
+ while ( (i--) && ( !(AT91C_BASE_PIOA->PIO_PDSR & GPIO_FPGA_DONE ) ) ) {
+ HIGH(GPIO_FPGA_CCLK);
+ LOW(GPIO_FPGA_CCLK);
+ }
+ // crude error indicator, leave both red LEDs on and return
+ if (i==0){
+ LED_C_ON();
+ LED_D_ON();
+ return;
+ }
+ LED_D_OFF();
+}
+
+static char *bitparse_headers_start;
+static char *bitparse_bitstream_end;
+static int bitparse_initialized;
+/* Simple Xilinx .bit parser. The file starts with the fixed opaque byte sequence
+ * 00 09 0f f0 0f f0 0f f0 0f f0 00 00 01
+ * After that the format is 1 byte section type (ASCII character), 2 byte length
+ * (big endian), <length> bytes content. Except for section 'e' which has 4 bytes
+ * length.
+ */
+static const char _bitparse_fixed_header[] = {0x00, 0x09, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x00, 0x00, 0x01};
+static int bitparse_init(void * start_address, void *end_address)
+{
+ bitparse_initialized = 0;
+
+ if(memcmp(_bitparse_fixed_header, start_address, sizeof(_bitparse_fixed_header)) != 0) {
+ return 0; /* Not matched */
+ } else {
+ bitparse_headers_start= ((char*)start_address) + sizeof(_bitparse_fixed_header);
+ bitparse_bitstream_end= (char*)end_address;
+ bitparse_initialized = 1;
+ return 1;
+ }
+}
+
+int bitparse_find_section(char section_name, char **section_start, unsigned int *section_length)
+{
+ char *pos = bitparse_headers_start;
+ int result = 0;
+
+ if(!bitparse_initialized) return 0;
+
+ while(pos < bitparse_bitstream_end) {
+ char current_name = *pos++;
+ unsigned int current_length = 0;
+ if(current_name < 'a' || current_name > 'e') {
+ /* Strange section name, abort */
+ break;
+ }
+ current_length = 0;
+ switch(current_name) {
+ case 'e':
+ /* Four byte length field */
+ current_length += (*pos++) << 24;
+ current_length += (*pos++) << 16;
+ default: /* Fall through, two byte length field */
+ current_length += (*pos++) << 8;
+ current_length += (*pos++) << 0;
+ }
+
+ if(current_name != 'e' && current_length > 255) {
+ /* Maybe a parse error */
+ break;
+ }
+
+ if(current_name == section_name) {
+ /* Found it */
+ *section_start = pos;
+ *section_length = current_length;
+ result = 1;
+ break;
+ }
+
+ pos += current_length; /* Skip section */
+ }
+
+ return result;
+}
+
+//-----------------------------------------------------------------------------
+// Find out which FPGA image format is stored in flash, then call DownloadFPGA
+// with the right parameters to download the image
+//-----------------------------------------------------------------------------
+extern char _binary_fpga_bit_start, _binary_fpga_bit_end;
+void FpgaDownloadAndGo(void)
+{
+ /* Check for the new flash image format: Should have the .bit file at &_binary_fpga_bit_start
+ */
+ if(bitparse_init(&_binary_fpga_bit_start, &_binary_fpga_bit_end)) {
+ /* Successfully initialized the .bit parser. Find the 'e' section and
+ * send its contents to the FPGA.
+ */
+ char *bitstream_start;
+ unsigned int bitstream_length;
+ if(bitparse_find_section('e', &bitstream_start, &bitstream_length)) {
+ DownloadFPGA(bitstream_start, bitstream_length, 0);
+
+ return; /* All done */
+ }
+ }
+
+ /* Fallback for the old flash image format: Check for the magic marker 0xFFFFFFFF
+ * 0xAA995566 at address 0x102000. This is raw bitstream with a size of 336,768 bits
+ * = 10,524 DWORDs, stored as DWORDS e.g. little-endian in memory, but each DWORD
+ * is still to be transmitted in MSBit first order. Set the invert flag to indicate
+ * that the DownloadFPGA function should invert every 4 byte sequence when doing
+ * the bytewise download.
+ */
+ if( *(DWORD*)0x102000 == 0xFFFFFFFF && *(DWORD*)0x102004 == 0xAA995566 )
+ DownloadFPGA((char*)0x102000, 10524*4, 1);
+}
+
+void FpgaGatherVersion(char *dst, int len)
+{
+ char *fpga_info;
+ unsigned int fpga_info_len;
+ dst[0] = 0;
+ if(!bitparse_find_section('e', &fpga_info, &fpga_info_len)) {
+ strncat(dst, "FPGA image: legacy image without version information", len-1);
+ } else {
+ strncat(dst, "FPGA image built", len-1);
+ /* USB packets only have 48 bytes data payload, so be terse */
+#if 0
+ if(bitparse_find_section('a', &fpga_info, &fpga_info_len) && fpga_info[fpga_info_len-1] == 0 ) {
+ strncat(dst, " from ", len-1);
+ strncat(dst, fpga_info, len-1);
+ }
+ if(bitparse_find_section('b', &fpga_info, &fpga_info_len) && fpga_info[fpga_info_len-1] == 0 ) {
+ strncat(dst, " for ", len-1);
+ strncat(dst, fpga_info, len-1);
+ }
+#endif
+ if(bitparse_find_section('c', &fpga_info, &fpga_info_len) && fpga_info[fpga_info_len-1] == 0 ) {
+ strncat(dst, " on ", len-1);
+ strncat(dst, fpga_info, len-1);
+ }
+ if(bitparse_find_section('d', &fpga_info, &fpga_info_len) && fpga_info[fpga_info_len-1] == 0 ) {
+ strncat(dst, " at ", len-1);
+ strncat(dst, fpga_info, len-1);
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Send a 16 bit command/data pair to the FPGA.
+// The bit format is: C3 C2 C1 C0 D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0
+// where C is the 4 bit command and D is the 12 bit data
+//-----------------------------------------------------------------------------
+void FpgaSendCommand(WORD cmd, WORD v)
+{
+ SetupSpi(SPI_FPGA_MODE);
+ while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0); // wait for the transfer to complete
+ AT91C_BASE_SPI->SPI_TDR = AT91C_SPI_LASTXFER | cmd | v; // send the data
+}
+//-----------------------------------------------------------------------------
+// Write the FPGA setup word (that determines what mode the logic is in, read
+// vs. clone vs. etc.). This is now a special case of FpgaSendCommand() to
+// avoid changing this function's occurence everywhere in the source code.
+//-----------------------------------------------------------------------------
+void FpgaWriteConfWord(BYTE v)
+{
+ FpgaSendCommand(FPGA_CMD_SET_CONFREG, v);
+}
+
+//-----------------------------------------------------------------------------
+// Set up the CMOS switches that mux the ADC: four switches, independently
+// closable, but should only close one at a time. Not an FPGA thing, but
+// the samples from the ADC always flow through the FPGA.
+//-----------------------------------------------------------------------------
+void SetAdcMuxFor(DWORD whichGpio)
+{
+ AT91C_BASE_PIOA->PIO_OER =
+ GPIO_MUXSEL_HIPKD |
+ GPIO_MUXSEL_LOPKD |
+ GPIO_MUXSEL_LORAW |
+ GPIO_MUXSEL_HIRAW;
+
+ AT91C_BASE_PIOA->PIO_PER =
+ GPIO_MUXSEL_HIPKD |
+ GPIO_MUXSEL_LOPKD |
+ GPIO_MUXSEL_LORAW |
+ GPIO_MUXSEL_HIRAW;
+
+ LOW(GPIO_MUXSEL_HIPKD);
+ LOW(GPIO_MUXSEL_HIRAW);
+ LOW(GPIO_MUXSEL_LORAW);
+ LOW(GPIO_MUXSEL_LOPKD);
+
+ HIGH(whichGpio);
+}
-//-----------------------------------------------------------------------------\r
-// Routines to support ISO 14443. This includes both the reader software and\r
-// the `fake tag' modes. At the moment only the Type B modulation is\r
-// supported.\r
-// Jonathan Westhues, split Nov 2006\r
-//-----------------------------------------------------------------------------\r
-#include <proxmark3.h>\r
-#include "apps.h"\r
-#include "iso14443crc.h"\r
-\r
-\r
-//static void GetSamplesFor14443(BOOL weTx, int n);\r
-\r
-#define DEMOD_TRACE_SIZE 4096\r
-#define READER_TAG_BUFFER_SIZE 2048\r
-#define TAG_READER_BUFFER_SIZE 2048\r
-#define DMA_BUFFER_SIZE 1024\r
-\r
-//=============================================================================\r
-// An ISO 14443 Type B tag. We listen for commands from the reader, using\r
-// a UART kind of thing that's implemented in software. When we get a\r
-// frame (i.e., a group of bytes between SOF and EOF), we check the CRC.\r
-// If it's good, then we can do something appropriate with it, and send\r
-// a response.\r
-//=============================================================================\r
-\r
-//-----------------------------------------------------------------------------\r
-// Code up a string of octets at layer 2 (including CRC, we don't generate\r
-// that here) so that they can be transmitted to the reader. Doesn't transmit\r
-// them yet, just leaves them ready to send in ToSend[].\r
-//-----------------------------------------------------------------------------\r
-static void CodeIso14443bAsTag(const BYTE *cmd, int len)\r
-{\r
- int i;\r
-\r
- ToSendReset();\r
-\r
- // Transmit a burst of ones, as the initial thing that lets the\r
- // reader get phase sync. This (TR1) must be > 80/fs, per spec,\r
- // but tag that I've tried (a Paypass) exceeds that by a fair bit,\r
- // so I will too.\r
- for(i = 0; i < 20; i++) {\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- }\r
-\r
- // Send SOF.\r
- for(i = 0; i < 10; i++) {\r
- ToSendStuffBit(0);\r
- ToSendStuffBit(0);\r
- ToSendStuffBit(0);\r
- ToSendStuffBit(0);\r
- }\r
- for(i = 0; i < 2; i++) {\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- }\r
-\r
- for(i = 0; i < len; i++) {\r
- int j;\r
- BYTE b = cmd[i];\r
-\r
- // Start bit\r
- ToSendStuffBit(0);\r
- ToSendStuffBit(0);\r
- ToSendStuffBit(0);\r
- ToSendStuffBit(0);\r
-\r
- // Data bits\r
- for(j = 0; j < 8; j++) {\r
- if(b & 1) {\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- } else {\r
- ToSendStuffBit(0);\r
- ToSendStuffBit(0);\r
- ToSendStuffBit(0);\r
- ToSendStuffBit(0);\r
- }\r
- b >>= 1;\r
- }\r
-\r
- // Stop bit\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- }\r
-\r
- // Send SOF.\r
- for(i = 0; i < 10; i++) {\r
- ToSendStuffBit(0);\r
- ToSendStuffBit(0);\r
- ToSendStuffBit(0);\r
- ToSendStuffBit(0);\r
- }\r
- for(i = 0; i < 10; i++) {\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- }\r
-\r
- // Convert from last byte pos to length\r
- ToSendMax++;\r
-\r
- // Add a few more for slop\r
- ToSendMax += 2;\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-// The software UART that receives commands from the reader, and its state\r
-// variables.\r
-//-----------------------------------------------------------------------------\r
-static struct {\r
- enum {\r
- STATE_UNSYNCD,\r
- STATE_GOT_FALLING_EDGE_OF_SOF,\r
- STATE_AWAITING_START_BIT,\r
- STATE_RECEIVING_DATA,\r
- STATE_ERROR_WAIT\r
- } state;\r
- WORD shiftReg;\r
- int bitCnt;\r
- int byteCnt;\r
- int byteCntMax;\r
- int posCnt;\r
- BYTE *output;\r
-} Uart;\r
-\r
-/* Receive & handle a bit coming from the reader.\r
- *\r
- * LED handling:\r
- * LED A -> ON once we have received the SOF and are expecting the rest.\r
- * LED A -> OFF once we have received EOF or are in error state or unsynced\r
- *\r
- * Returns: true if we received a EOF\r
- * false if we are still waiting for some more\r
- */\r
-static BOOL Handle14443UartBit(int bit)\r
-{\r
- switch(Uart.state) {\r
- case STATE_UNSYNCD:\r
- LED_A_OFF();\r
- if(!bit) {\r
- // we went low, so this could be the beginning\r
- // of an SOF\r
- Uart.state = STATE_GOT_FALLING_EDGE_OF_SOF;\r
- Uart.posCnt = 0;\r
- Uart.bitCnt = 0;\r
- }\r
- break;\r
-\r
- case STATE_GOT_FALLING_EDGE_OF_SOF:\r
- Uart.posCnt++;\r
- if(Uart.posCnt == 2) {\r
- if(bit) {\r
- if(Uart.bitCnt >= 10) {\r
- // we've seen enough consecutive\r
- // zeros that it's a valid SOF\r
- Uart.posCnt = 0;\r
- Uart.byteCnt = 0;\r
- Uart.state = STATE_AWAITING_START_BIT;\r
- LED_A_ON(); // Indicate we got a valid SOF\r
- } else {\r
- // didn't stay down long enough\r
- // before going high, error\r
- Uart.state = STATE_ERROR_WAIT;\r
- }\r
- } else {\r
- // do nothing, keep waiting\r
- }\r
- Uart.bitCnt++;\r
- }\r
- if(Uart.posCnt >= 4) Uart.posCnt = 0;\r
- if(Uart.bitCnt > 14) {\r
- // Give up if we see too many zeros without\r
- // a one, too.\r
- Uart.state = STATE_ERROR_WAIT;\r
- }\r
- break;\r
-\r
- case STATE_AWAITING_START_BIT:\r
- Uart.posCnt++;\r
- if(bit) {\r
- if(Uart.posCnt > 25) {\r
- // stayed high for too long between\r
- // characters, error\r
- Uart.state = STATE_ERROR_WAIT;\r
- }\r
- } else {\r
- // falling edge, this starts the data byte\r
- Uart.posCnt = 0;\r
- Uart.bitCnt = 0;\r
- Uart.shiftReg = 0;\r
- Uart.state = STATE_RECEIVING_DATA;\r
- LED_A_ON(); // Indicate we're receiving\r
- }\r
- break;\r
-\r
- case STATE_RECEIVING_DATA:\r
- Uart.posCnt++;\r
- if(Uart.posCnt == 2) {\r
- // time to sample a bit\r
- Uart.shiftReg >>= 1;\r
- if(bit) {\r
- Uart.shiftReg |= 0x200;\r
- }\r
- Uart.bitCnt++;\r
- }\r
- if(Uart.posCnt >= 4) {\r
- Uart.posCnt = 0;\r
- }\r
- if(Uart.bitCnt == 10) {\r
- if((Uart.shiftReg & 0x200) && !(Uart.shiftReg & 0x001))\r
- {\r
- // this is a data byte, with correct\r
- // start and stop bits\r
- Uart.output[Uart.byteCnt] = (Uart.shiftReg >> 1) & 0xff;\r
- Uart.byteCnt++;\r
-\r
- if(Uart.byteCnt >= Uart.byteCntMax) {\r
- // Buffer overflowed, give up\r
- Uart.posCnt = 0;\r
- Uart.state = STATE_ERROR_WAIT;\r
- } else {\r
- // so get the next byte now\r
- Uart.posCnt = 0;\r
- Uart.state = STATE_AWAITING_START_BIT;\r
- }\r
- } else if(Uart.shiftReg == 0x000) {\r
- // this is an EOF byte\r
- LED_A_OFF(); // Finished receiving\r
- return TRUE;\r
- } else {\r
- // this is an error\r
- Uart.posCnt = 0;\r
- Uart.state = STATE_ERROR_WAIT;\r
- }\r
- }\r
- break;\r
-\r
- case STATE_ERROR_WAIT:\r
- // We're all screwed up, so wait a little while\r
- // for whatever went wrong to finish, and then\r
- // start over.\r
- Uart.posCnt++;\r
- if(Uart.posCnt > 10) {\r
- Uart.state = STATE_UNSYNCD;\r
- }\r
- break;\r
-\r
- default:\r
- Uart.state = STATE_UNSYNCD;\r
- break;\r
- }\r
-\r
- if (Uart.state == STATE_ERROR_WAIT) LED_A_OFF(); // Error\r
-\r
- return FALSE;\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-// Receive a command (from the reader to us, where we are the simulated tag),\r
-// and store it in the given buffer, up to the given maximum length. Keeps\r
-// spinning, waiting for a well-framed command, until either we get one\r
-// (returns TRUE) or someone presses the pushbutton on the board (FALSE).\r
-//\r
-// Assume that we're called with the SSC (to the FPGA) and ADC path set\r
-// correctly.\r
-//-----------------------------------------------------------------------------\r
-static BOOL GetIso14443CommandFromReader(BYTE *received, int *len, int maxLen)\r
-{\r
- BYTE mask;\r
- int i, bit;\r
-\r
- // Set FPGA mode to "simulated ISO 14443 tag", no modulation (listen\r
- // only, since we are receiving, not transmitting).\r
- // Signal field is off with the appropriate LED\r
- LED_D_OFF();\r
- FpgaWriteConfWord(\r
- FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION);\r
-\r
-\r
- // Now run a `software UART' on the stream of incoming samples.\r
- Uart.output = received;\r
- Uart.byteCntMax = maxLen;\r
- Uart.state = STATE_UNSYNCD;\r
-\r
- for(;;) {\r
- WDT_HIT();\r
-\r
- if(BUTTON_PRESS()) return FALSE;\r
-\r
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {\r
- AT91C_BASE_SSC->SSC_THR = 0x00;\r
- }\r
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {\r
- BYTE b = (BYTE)AT91C_BASE_SSC->SSC_RHR;\r
-\r
- mask = 0x80;\r
- for(i = 0; i < 8; i++, mask >>= 1) {\r
- bit = (b & mask);\r
- if(Handle14443UartBit(bit)) {\r
- *len = Uart.byteCnt;\r
- return TRUE;\r
- }\r
- }\r
- }\r
- }\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-// Main loop of simulated tag: receive commands from reader, decide what\r
-// response to send, and send it.\r
-//-----------------------------------------------------------------------------\r
-void SimulateIso14443Tag(void)\r
-{\r
- static const BYTE cmd1[] = { 0x05, 0x00, 0x08, 0x39, 0x73 };\r
- static const BYTE response1[] = {\r
- 0x50, 0x82, 0x0d, 0xe1, 0x74, 0x20, 0x38, 0x19, 0x22,\r
- 0x00, 0x21, 0x85, 0x5e, 0xd7\r
- };\r
-\r
- BYTE *resp;\r
- int respLen;\r
-\r
- BYTE *resp1 = (((BYTE *)BigBuf) + 800);\r
- int resp1Len;\r
-\r
- BYTE *receivedCmd = (BYTE *)BigBuf;\r
- int len;\r
-\r
- int i;\r
-\r
- int cmdsRecvd = 0;\r
-\r
- memset(receivedCmd, 0x44, 400);\r
-\r
- CodeIso14443bAsTag(response1, sizeof(response1));\r
- memcpy(resp1, ToSend, ToSendMax); resp1Len = ToSendMax;\r
-\r
- // We need to listen to the high-frequency, peak-detected path.\r
- SetAdcMuxFor(GPIO_MUXSEL_HIPKD);\r
- FpgaSetupSsc();\r
-\r
- cmdsRecvd = 0;\r
-\r
- for(;;) {\r
- BYTE b1, b2;\r
-\r
- if(!GetIso14443CommandFromReader(receivedCmd, &len, 100)) {\r
- Dbprintf("button pressed, received %d commands", cmdsRecvd);\r
- break;\r
- }\r
-\r
- // Good, look at the command now.\r
-\r
- if(len == sizeof(cmd1) && memcmp(receivedCmd, cmd1, len)==0) {\r
- resp = resp1; respLen = resp1Len;\r
- } else {\r
- Dbprintf("new cmd from reader: len=%d, cmdsRecvd=%d", len, cmdsRecvd);\r
- // And print whether the CRC fails, just for good measure\r
- ComputeCrc14443(CRC_14443_B, receivedCmd, len-2, &b1, &b2);\r
- if(b1 != receivedCmd[len-2] || b2 != receivedCmd[len-1]) {\r
- // Not so good, try again.\r
- DbpString("+++CRC fail");\r
- } else {\r
- DbpString("CRC passes");\r
- }\r
- break;\r
- }\r
-\r
- memset(receivedCmd, 0x44, 32);\r
-\r
- cmdsRecvd++;\r
-\r
- if(cmdsRecvd > 0x30) {\r
- DbpString("many commands later...");\r
- break;\r
- }\r
-\r
- if(respLen <= 0) continue;\r
-\r
- // Modulate BPSK\r
- // Signal field is off with the appropriate LED\r
- LED_D_OFF();\r
- FpgaWriteConfWord(\r
- FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_BPSK);\r
- AT91C_BASE_SSC->SSC_THR = 0xff;\r
- FpgaSetupSsc();\r
-\r
- // Transmit the response.\r
- i = 0;\r
- for(;;) {\r
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {\r
- BYTE b = resp[i];\r
-\r
- AT91C_BASE_SSC->SSC_THR = b;\r
-\r
- i++;\r
- if(i > respLen) {\r
- break;\r
- }\r
- }\r
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {\r
- volatile BYTE b = (BYTE)AT91C_BASE_SSC->SSC_RHR;\r
- (void)b;\r
- }\r
- }\r
- }\r
-}\r
-\r
-//=============================================================================\r
-// An ISO 14443 Type B reader. We take layer two commands, code them\r
-// appropriately, and then send them to the tag. We then listen for the\r
-// tag's response, which we leave in the buffer to be demodulated on the\r
-// PC side.\r
-//=============================================================================\r
-\r
-static struct {\r
- enum {\r
- DEMOD_UNSYNCD,\r
- DEMOD_PHASE_REF_TRAINING,\r
- DEMOD_AWAITING_FALLING_EDGE_OF_SOF,\r
- DEMOD_GOT_FALLING_EDGE_OF_SOF,\r
- DEMOD_AWAITING_START_BIT,\r
- DEMOD_RECEIVING_DATA,\r
- DEMOD_ERROR_WAIT\r
- } state;\r
- int bitCount;\r
- int posCount;\r
- int thisBit;\r
- int metric;\r
- int metricN;\r
- WORD shiftReg;\r
- BYTE *output;\r
- int len;\r
- int sumI;\r
- int sumQ;\r
-} Demod;\r
-\r
-/*\r
- * Handles reception of a bit from the tag\r
- *\r
- * LED handling:\r
- * LED C -> ON once we have received the SOF and are expecting the rest.\r
- * LED C -> OFF once we have received EOF or are unsynced\r
- *\r
- * Returns: true if we received a EOF\r
- * false if we are still waiting for some more\r
- *\r
- */\r
-static BOOL Handle14443SamplesDemod(int ci, int cq)\r
-{\r
- int v;\r
-\r
- // The soft decision on the bit uses an estimate of just the\r
- // quadrant of the reference angle, not the exact angle.\r
-#define MAKE_SOFT_DECISION() { \\r
- if(Demod.sumI > 0) { \\r
- v = ci; \\r
- } else { \\r
- v = -ci; \\r
- } \\r
- if(Demod.sumQ > 0) { \\r
- v += cq; \\r
- } else { \\r
- v -= cq; \\r
- } \\r
- }\r
-\r
- switch(Demod.state) {\r
- case DEMOD_UNSYNCD:\r
- v = ci;\r
- if(v < 0) v = -v;\r
- if(cq > 0) {\r
- v += cq;\r
- } else {\r
- v -= cq;\r
- }\r
- if(v > 40) {\r
- Demod.posCount = 0;\r
- Demod.state = DEMOD_PHASE_REF_TRAINING;\r
- Demod.sumI = 0;\r
- Demod.sumQ = 0;\r
- }\r
- break;\r
-\r
- case DEMOD_PHASE_REF_TRAINING:\r
- if(Demod.posCount < 8) {\r
- Demod.sumI += ci;\r
- Demod.sumQ += cq;\r
- } else if(Demod.posCount > 100) {\r
- // error, waited too long\r
- Demod.state = DEMOD_UNSYNCD;\r
- } else {\r
- MAKE_SOFT_DECISION();\r
- if(v < 0) {\r
- Demod.state = DEMOD_AWAITING_FALLING_EDGE_OF_SOF;\r
- Demod.posCount = 0;\r
- }\r
- }\r
- Demod.posCount++;\r
- break;\r
-\r
- case DEMOD_AWAITING_FALLING_EDGE_OF_SOF:\r
- MAKE_SOFT_DECISION();\r
- if(v < 0) {\r
- Demod.state = DEMOD_GOT_FALLING_EDGE_OF_SOF;\r
- Demod.posCount = 0;\r
- } else {\r
- if(Demod.posCount > 100) {\r
- Demod.state = DEMOD_UNSYNCD;\r
- }\r
- }\r
- Demod.posCount++;\r
- break;\r
-\r
- case DEMOD_GOT_FALLING_EDGE_OF_SOF:\r
- MAKE_SOFT_DECISION();\r
- if(v > 0) {\r
- if(Demod.posCount < 12) {\r
- Demod.state = DEMOD_UNSYNCD;\r
- } else {\r
- LED_C_ON(); // Got SOF\r
- Demod.state = DEMOD_AWAITING_START_BIT;\r
- Demod.posCount = 0;\r
- Demod.len = 0;\r
- Demod.metricN = 0;\r
- Demod.metric = 0;\r
- }\r
- } else {\r
- if(Demod.posCount > 100) {\r
- Demod.state = DEMOD_UNSYNCD;\r
- }\r
- }\r
- Demod.posCount++;\r
- break;\r
-\r
- case DEMOD_AWAITING_START_BIT:\r
- MAKE_SOFT_DECISION();\r
- if(v > 0) {\r
- if(Demod.posCount > 10) {\r
- Demod.state = DEMOD_UNSYNCD;\r
- }\r
- } else {\r
- Demod.bitCount = 0;\r
- Demod.posCount = 1;\r
- Demod.thisBit = v;\r
- Demod.shiftReg = 0;\r
- Demod.state = DEMOD_RECEIVING_DATA;\r
- }\r
- break;\r
-\r
- case DEMOD_RECEIVING_DATA:\r
- MAKE_SOFT_DECISION();\r
- if(Demod.posCount == 0) {\r
- Demod.thisBit = v;\r
- Demod.posCount = 1;\r
- } else {\r
- Demod.thisBit += v;\r
-\r
- if(Demod.thisBit > 0) {\r
- Demod.metric += Demod.thisBit;\r
- } else {\r
- Demod.metric -= Demod.thisBit;\r
- }\r
- (Demod.metricN)++;\r
-\r
- Demod.shiftReg >>= 1;\r
- if(Demod.thisBit > 0) {\r
- Demod.shiftReg |= 0x200;\r
- }\r
-\r
- Demod.bitCount++;\r
- if(Demod.bitCount == 10) {\r
- WORD s = Demod.shiftReg;\r
- if((s & 0x200) && !(s & 0x001)) {\r
- BYTE b = (s >> 1);\r
- Demod.output[Demod.len] = b;\r
- Demod.len++;\r
- Demod.state = DEMOD_AWAITING_START_BIT;\r
- } else if(s == 0x000) {\r
- // This is EOF\r
- LED_C_OFF();\r
- return TRUE;\r
- Demod.state = DEMOD_UNSYNCD;\r
- } else {\r
- Demod.state = DEMOD_UNSYNCD;\r
- }\r
- }\r
- Demod.posCount = 0;\r
- }\r
- break;\r
-\r
- default:\r
- Demod.state = DEMOD_UNSYNCD;\r
- break;\r
- }\r
-\r
- if (Demod.state == DEMOD_UNSYNCD) LED_C_OFF(); // Not synchronized...\r
- return FALSE;\r
-}\r
-\r
-/*\r
- * Demodulate the samples we received from the tag\r
- * weTx: set to 'TRUE' if we behave like a reader\r
- * set to 'FALSE' if we behave like a snooper\r
- * quiet: set to 'TRUE' to disable debug output\r
- */\r
-static void GetSamplesFor14443Demod(BOOL weTx, int n, BOOL quiet)\r
-{\r
- int max = 0;\r
- BOOL gotFrame = FALSE;\r
-\r
-//# define DMA_BUFFER_SIZE 8\r
- SBYTE *dmaBuf;\r
-\r
- int lastRxCounter;\r
- SBYTE *upTo;\r
-\r
- int ci, cq;\r
-\r
- int samples = 0;\r
-\r
- // Clear out the state of the "UART" that receives from the tag.\r
- memset(BigBuf, 0x44, 400);\r
- Demod.output = (BYTE *)BigBuf;\r
- Demod.len = 0;\r
- Demod.state = DEMOD_UNSYNCD;\r
-\r
- // And the UART that receives from the reader\r
- Uart.output = (((BYTE *)BigBuf) + 1024);\r
- Uart.byteCntMax = 100;\r
- Uart.state = STATE_UNSYNCD;\r
-\r
- // Setup for the DMA.\r
- dmaBuf = (SBYTE *)(BigBuf + 32);\r
- upTo = dmaBuf;\r
- lastRxCounter = DMA_BUFFER_SIZE;\r
- FpgaSetupSscDma((BYTE *)dmaBuf, DMA_BUFFER_SIZE);\r
-\r
- // Signal field is ON with the appropriate LED:\r
- if (weTx) LED_D_ON(); else LED_D_OFF();\r
- // And put the FPGA in the appropriate mode\r
- FpgaWriteConfWord(\r
- FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ |\r
- (weTx ? 0 : FPGA_HF_READER_RX_XCORR_SNOOP));\r
-\r
- for(;;) {\r
- int behindBy = lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR;\r
- if(behindBy > max) max = behindBy;\r
-\r
- while(((lastRxCounter-AT91C_BASE_PDC_SSC->PDC_RCR) & (DMA_BUFFER_SIZE-1))\r
- > 2)\r
- {\r
- ci = upTo[0];\r
- cq = upTo[1];\r
- upTo += 2;\r
- if(upTo - dmaBuf > DMA_BUFFER_SIZE) {\r
- upTo -= DMA_BUFFER_SIZE;\r
- AT91C_BASE_PDC_SSC->PDC_RNPR = (DWORD)upTo;\r
- AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE;\r
- }\r
- lastRxCounter -= 2;\r
- if(lastRxCounter <= 0) {\r
- lastRxCounter += DMA_BUFFER_SIZE;\r
- }\r
-\r
- samples += 2;\r
-\r
- Handle14443UartBit(1);\r
- Handle14443UartBit(1);\r
-\r
- if(Handle14443SamplesDemod(ci, cq)) {\r
- gotFrame = 1;\r
- }\r
- }\r
-\r
- if(samples > 2000) {\r
- break;\r
- }\r
- }\r
- AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS;\r
- if (!quiet) Dbprintf("%x %x %x", max, gotFrame, Demod.len);\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-// Read the tag's response. We just receive a stream of slightly-processed\r
-// samples from the FPGA, which we will later do some signal processing on,\r
-// to get the bits.\r
-//-----------------------------------------------------------------------------\r
-/*static void GetSamplesFor14443(BOOL weTx, int n)\r
-{\r
- BYTE *dest = (BYTE *)BigBuf;\r
- int c;\r
-\r
- FpgaWriteConfWord(\r
- FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ |\r
- (weTx ? 0 : FPGA_HF_READER_RX_XCORR_SNOOP));\r
-\r
- c = 0;\r
- for(;;) {\r
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {\r
- AT91C_BASE_SSC->SSC_THR = 0x43;\r
- }\r
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {\r
- SBYTE b;\r
- b = (SBYTE)AT91C_BASE_SSC->SSC_RHR;\r
-\r
- dest[c++] = (BYTE)b;\r
-\r
- if(c >= n) {\r
- break;\r
- }\r
- }\r
- }\r
-}*/\r
-\r
-//-----------------------------------------------------------------------------\r
-// Transmit the command (to the tag) that was placed in ToSend[].\r
-//-----------------------------------------------------------------------------\r
-static void TransmitFor14443(void)\r
-{\r
- int c;\r
-\r
- FpgaSetupSsc();\r
-\r
- while(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {\r
- AT91C_BASE_SSC->SSC_THR = 0xff;\r
- }\r
-\r
- // Signal field is ON with the appropriate Red LED\r
- LED_D_ON();\r
- // Signal we are transmitting with the Green LED\r
- LED_B_ON();\r
- FpgaWriteConfWord(\r
- FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD);\r
-\r
- for(c = 0; c < 10;) {\r
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {\r
- AT91C_BASE_SSC->SSC_THR = 0xff;\r
- c++;\r
- }\r
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {\r
- volatile DWORD r = AT91C_BASE_SSC->SSC_RHR;\r
- (void)r;\r
- }\r
- WDT_HIT();\r
- }\r
-\r
- c = 0;\r
- for(;;) {\r
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {\r
- AT91C_BASE_SSC->SSC_THR = ToSend[c];\r
- c++;\r
- if(c >= ToSendMax) {\r
- break;\r
- }\r
- }\r
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {\r
- volatile DWORD r = AT91C_BASE_SSC->SSC_RHR;\r
- (void)r;\r
- }\r
- WDT_HIT();\r
- }\r
- LED_B_OFF(); // Finished sending\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-// Code a layer 2 command (string of octets, including CRC) into ToSend[],\r
-// so that it is ready to transmit to the tag using TransmitFor14443().\r
-//-----------------------------------------------------------------------------\r
-void CodeIso14443bAsReader(const BYTE *cmd, int len)\r
-{\r
- int i, j;\r
- BYTE b;\r
-\r
- ToSendReset();\r
-\r
- // Establish initial reference level\r
- for(i = 0; i < 40; i++) {\r
- ToSendStuffBit(1);\r
- }\r
- // Send SOF\r
- for(i = 0; i < 10; i++) {\r
- ToSendStuffBit(0);\r
- }\r
-\r
- for(i = 0; i < len; i++) {\r
- // Stop bits/EGT\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- // Start bit\r
- ToSendStuffBit(0);\r
- // Data bits\r
- b = cmd[i];\r
- for(j = 0; j < 8; j++) {\r
- if(b & 1) {\r
- ToSendStuffBit(1);\r
- } else {\r
- ToSendStuffBit(0);\r
- }\r
- b >>= 1;\r
- }\r
- }\r
- // Send EOF\r
- ToSendStuffBit(1);\r
- for(i = 0; i < 10; i++) {\r
- ToSendStuffBit(0);\r
- }\r
- for(i = 0; i < 8; i++) {\r
- ToSendStuffBit(1);\r
- }\r
-\r
- // And then a little more, to make sure that the last character makes\r
- // it out before we switch to rx mode.\r
- for(i = 0; i < 24; i++) {\r
- ToSendStuffBit(1);\r
- }\r
-\r
- // Convert from last character reference to length\r
- ToSendMax++;\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-// Read an ISO 14443 tag. We send it some set of commands, and record the\r
-// responses.\r
-// The command name is misleading, it actually decodes the reponse in HEX\r
-// into the output buffer (read the result using hexsamples, not hisamples)\r
-//-----------------------------------------------------------------------------\r
-void AcquireRawAdcSamplesIso14443(DWORD parameter)\r
-{\r
- BYTE cmd1[] = { 0x05, 0x00, 0x08, 0x39, 0x73 };\r
-\r
- // Make sure that we start from off, since the tags are stateful;\r
- // confusing things will happen if we don't reset them between reads.\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
- LED_D_OFF();\r
- SpinDelay(200);\r
-\r
- SetAdcMuxFor(GPIO_MUXSEL_HIPKD);\r
- FpgaSetupSsc();\r
-\r
- // Now give it time to spin up.\r
- // Signal field is on with the appropriate LED\r
- LED_D_ON();\r
- FpgaWriteConfWord(\r
- FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ);\r
- SpinDelay(200);\r
-\r
- CodeIso14443bAsReader(cmd1, sizeof(cmd1));\r
- TransmitFor14443();\r
-// LED_A_ON();\r
- GetSamplesFor14443Demod(TRUE, 2000, FALSE);\r
-// LED_A_OFF();\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-// Read a SRI512 ISO 14443 tag.\r
-//\r
-// SRI512 tags are just simple memory tags, here we're looking at making a dump\r
-// of the contents of the memory. No anticollision algorithm is done, we assume\r
-// we have a single tag in the field.\r
-//\r
-// I tried to be systematic and check every answer of the tag, every CRC, etc...\r
-//-----------------------------------------------------------------------------\r
-void ReadSRI512Iso14443(DWORD parameter)\r
-{\r
- ReadSTMemoryIso14443(parameter,0x0F);\r
-}\r
-void ReadSRIX4KIso14443(DWORD parameter)\r
-{\r
- ReadSTMemoryIso14443(parameter,0x7F);\r
-}\r
-\r
-void ReadSTMemoryIso14443(DWORD parameter,DWORD dwLast)\r
-{\r
- BYTE i = 0x00;\r
-\r
- // Make sure that we start from off, since the tags are stateful;\r
- // confusing things will happen if we don't reset them between reads.\r
- LED_D_OFF();\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
- SpinDelay(200);\r
-\r
- SetAdcMuxFor(GPIO_MUXSEL_HIPKD);\r
- FpgaSetupSsc();\r
-\r
- // Now give it time to spin up.\r
- // Signal field is on with the appropriate LED\r
- LED_D_ON();\r
- FpgaWriteConfWord(\r
- FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ);\r
- SpinDelay(200);\r
-\r
- // First command: wake up the tag using the INITIATE command\r
- BYTE cmd1[] = { 0x06, 0x00, 0x97, 0x5b};\r
- CodeIso14443bAsReader(cmd1, sizeof(cmd1));\r
- TransmitFor14443();\r
-// LED_A_ON();\r
- GetSamplesFor14443Demod(TRUE, 2000,TRUE);\r
-// LED_A_OFF();\r
-\r
- if (Demod.len == 0) {\r
- DbpString("No response from tag");\r
- return;\r
- } else {\r
- Dbprintf("Randomly generated UID from tag (+ 2 byte CRC): %x %x %x",\r
- Demod.output[0], Demod.output[1],Demod.output[2]);\r
- }\r
- // There is a response, SELECT the uid\r
- DbpString("Now SELECT tag:");\r
- cmd1[0] = 0x0E; // 0x0E is SELECT\r
- cmd1[1] = Demod.output[0];\r
- ComputeCrc14443(CRC_14443_B, cmd1, 2, &cmd1[2], &cmd1[3]);\r
- CodeIso14443bAsReader(cmd1, sizeof(cmd1));\r
- TransmitFor14443();\r
-// LED_A_ON();\r
- GetSamplesFor14443Demod(TRUE, 2000,TRUE);\r
-// LED_A_OFF();\r
- if (Demod.len != 3) {\r
- Dbprintf("Expected 3 bytes from tag, got %d", Demod.len);\r
- return;\r
- }\r
- // Check the CRC of the answer:\r
- ComputeCrc14443(CRC_14443_B, Demod.output, 1 , &cmd1[2], &cmd1[3]);\r
- if(cmd1[2] != Demod.output[1] || cmd1[3] != Demod.output[2]) {\r
- DbpString("CRC Error reading select response.");\r
- return;\r
- }\r
- // Check response from the tag: should be the same UID as the command we just sent:\r
- if (cmd1[1] != Demod.output[0]) {\r
- Dbprintf("Bad response to SELECT from Tag, aborting: %x %x", cmd1[1], Demod.output[0]);\r
- return;\r
- }\r
- // Tag is now selected,\r
- // First get the tag's UID:\r
- cmd1[0] = 0x0B;\r
- ComputeCrc14443(CRC_14443_B, cmd1, 1 , &cmd1[1], &cmd1[2]);\r
- CodeIso14443bAsReader(cmd1, 3); // Only first three bytes for this one\r
- TransmitFor14443();\r
-// LED_A_ON();\r
- GetSamplesFor14443Demod(TRUE, 2000,TRUE);\r
-// LED_A_OFF();\r
- if (Demod.len != 10) {\r
- Dbprintf("Expected 10 bytes from tag, got %d", Demod.len);\r
- return;\r
- }\r
- // The check the CRC of the answer (use cmd1 as temporary variable):\r
- ComputeCrc14443(CRC_14443_B, Demod.output, 8, &cmd1[2], &cmd1[3]);\r
- if(cmd1[2] != Demod.output[8] || cmd1[3] != Demod.output[9]) {\r
- Dbprintf("CRC Error reading block! - Below: expected, got %x %x",\r
- (cmd1[2]<<8)+cmd1[3], (Demod.output[8]<<8)+Demod.output[9]);\r
- // Do not return;, let's go on... (we should retry, maybe ?)\r
- }\r
- Dbprintf("Tag UID (64 bits): %08x %08x",\r
- (Demod.output[7]<<24) + (Demod.output[6]<<16) + (Demod.output[5]<<8) + Demod.output[4],\r
- (Demod.output[3]<<24) + (Demod.output[2]<<16) + (Demod.output[1]<<8) + Demod.output[0]);\r
-\r
- // Now loop to read all 16 blocks, address from 0 to 15\r
- DbpString("Tag memory dump, block 0 to 15");\r
- cmd1[0] = 0x08;\r
- i = 0x00;\r
- dwLast++;\r
- for (;;) {\r
- if (i == dwLast) {\r
- DbpString("System area block (0xff):");\r
- i = 0xff;\r
- }\r
- cmd1[1] = i;\r
- ComputeCrc14443(CRC_14443_B, cmd1, 2, &cmd1[2], &cmd1[3]);\r
- CodeIso14443bAsReader(cmd1, sizeof(cmd1));\r
- TransmitFor14443();\r
-// LED_A_ON();\r
- GetSamplesFor14443Demod(TRUE, 2000,TRUE);\r
-// LED_A_OFF();\r
- if (Demod.len != 6) { // Check if we got an answer from the tag\r
- DbpString("Expected 6 bytes from tag, got less...");\r
- return;\r
- }\r
- // The check the CRC of the answer (use cmd1 as temporary variable):\r
- ComputeCrc14443(CRC_14443_B, Demod.output, 4, &cmd1[2], &cmd1[3]);\r
- if(cmd1[2] != Demod.output[4] || cmd1[3] != Demod.output[5]) {\r
- Dbprintf("CRC Error reading block! - Below: expected, got %x %x",\r
- (cmd1[2]<<8)+cmd1[3], (Demod.output[4]<<8)+Demod.output[5]);\r
- // Do not return;, let's go on... (we should retry, maybe ?)\r
- }\r
- // Now print out the memory location:\r
- Dbprintf("Address=%x, Contents=%x, CRC=%x", i,\r
- (Demod.output[3]<<24) + (Demod.output[2]<<16) + (Demod.output[1]<<8) + Demod.output[0],\r
- (Demod.output[4]<<8)+Demod.output[5]);\r
- if (i == 0xff) {\r
- break;\r
- }\r
- i++;\r
- }\r
-}\r
-\r
-\r
-//=============================================================================\r
-// Finally, the `sniffer' combines elements from both the reader and\r
-// simulated tag, to show both sides of the conversation.\r
-//=============================================================================\r
-\r
-//-----------------------------------------------------------------------------\r
-// Record the sequence of commands sent by the reader to the tag, with\r
-// triggering so that we start recording at the point that the tag is moved\r
-// near the reader.\r
-//-----------------------------------------------------------------------------\r
-/*\r
- * Memory usage for this function, (within BigBuf)\r
- * 0-4095 : Demodulated samples receive (4096 bytes) - DEMOD_TRACE_SIZE\r
- * 4096-6143 : Last Received command, 2048 bytes (reader->tag) - READER_TAG_BUFFER_SIZE\r
- * 6144-8191 : Last Received command, 2048 bytes(tag->reader) - TAG_READER_BUFFER_SIZE\r
- * 8192-9215 : DMA Buffer, 1024 bytes (samples) - DMA_BUFFER_SIZE\r
- */\r
-void SnoopIso14443(void)\r
-{\r
- // We won't start recording the frames that we acquire until we trigger;\r
- // a good trigger condition to get started is probably when we see a\r
- // response from the tag.\r
- BOOL triggered = FALSE;\r
-\r
- // The command (reader -> tag) that we're working on receiving.\r
- BYTE *receivedCmd = (BYTE *)(BigBuf) + DEMOD_TRACE_SIZE;\r
- // The response (tag -> reader) that we're working on receiving.\r
- BYTE *receivedResponse = (BYTE *)(BigBuf) + DEMOD_TRACE_SIZE + READER_TAG_BUFFER_SIZE;\r
-\r
- // As we receive stuff, we copy it from receivedCmd or receivedResponse\r
- // into trace, along with its length and other annotations.\r
- BYTE *trace = (BYTE *)BigBuf;\r
- int traceLen = 0;\r
-\r
- // The DMA buffer, used to stream samples from the FPGA.\r
- SBYTE *dmaBuf = (SBYTE *)(BigBuf) + DEMOD_TRACE_SIZE + READER_TAG_BUFFER_SIZE + TAG_READER_BUFFER_SIZE;\r
- int lastRxCounter;\r
- SBYTE *upTo;\r
- int ci, cq;\r
- int maxBehindBy = 0;\r
-\r
- // Count of samples received so far, so that we can include timing\r
- // information in the trace buffer.\r
- int samples = 0;\r
-\r
- // Initialize the trace buffer\r
- memset(trace, 0x44, DEMOD_TRACE_SIZE);\r
-\r
- // Set up the demodulator for tag -> reader responses.\r
- Demod.output = receivedResponse;\r
- Demod.len = 0;\r
- Demod.state = DEMOD_UNSYNCD;\r
-\r
- // And the reader -> tag commands\r
- memset(&Uart, 0, sizeof(Uart));\r
- Uart.output = receivedCmd;\r
- Uart.byteCntMax = 100;\r
- Uart.state = STATE_UNSYNCD;\r
-\r
- // Print some debug information about the buffer sizes\r
- Dbprintf("Snooping buffers initialized:");\r
- Dbprintf(" Trace: %i bytes", DEMOD_TRACE_SIZE);\r
- Dbprintf(" Reader -> tag: %i bytes", READER_TAG_BUFFER_SIZE);\r
- Dbprintf(" tag -> Reader: %i bytes", TAG_READER_BUFFER_SIZE);\r
- Dbprintf(" DMA: %i bytes", DMA_BUFFER_SIZE);\r
- \r
- // Use a counter for blinking the LED\r
- long ledCount=0;\r
- long ledFlashAt=200000;\r
- \r
- // And put the FPGA in the appropriate mode\r
- // Signal field is off with the appropriate LED\r
- LED_D_OFF();\r
- FpgaWriteConfWord(\r
- FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ |\r
- FPGA_HF_READER_RX_XCORR_SNOOP);\r
- SetAdcMuxFor(GPIO_MUXSEL_HIPKD);\r
-\r
- // Setup for the DMA.\r
- FpgaSetupSsc();\r
- upTo = dmaBuf;\r
- lastRxCounter = DMA_BUFFER_SIZE;\r
- FpgaSetupSscDma((BYTE *)dmaBuf, DMA_BUFFER_SIZE);\r
- // And now we loop, receiving samples.\r
- for(;;) {\r
- // Blink the LED while Snooping\r
- ledCount++;\r
- if (ledCount == ledFlashAt) {\r
- LED_D_ON();\r
- }\r
- if (ledCount >= 2*ledFlashAt) {\r
- LED_D_OFF();\r
- ledCount=0;\r
- }\r
- \r
- int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) &\r
- (DMA_BUFFER_SIZE-1);\r
- if(behindBy > maxBehindBy) {\r
- maxBehindBy = behindBy;\r
- if(behindBy > (DMA_BUFFER_SIZE-2)) { // TODO: understand whether we can increase/decrease as we want or not?\r
- Dbprintf("blew circular buffer! behindBy=%x", behindBy);\r
- goto done;\r
- }\r
- }\r
- if(behindBy < 2) continue;\r
-\r
- ci = upTo[0];\r
- cq = upTo[1];\r
- upTo += 2;\r
- lastRxCounter -= 2;\r
- if(upTo - dmaBuf > DMA_BUFFER_SIZE) {\r
- upTo -= DMA_BUFFER_SIZE;\r
- lastRxCounter += DMA_BUFFER_SIZE;\r
- AT91C_BASE_PDC_SSC->PDC_RNPR = (DWORD) upTo;\r
- AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE;\r
- }\r
-\r
- samples += 2;\r
-\r
-#define HANDLE_BIT_IF_BODY \\r
- if(triggered) { \\r
- ledFlashAt=30000; \\r
- trace[traceLen++] = ((samples >> 0) & 0xff); \\r
- trace[traceLen++] = ((samples >> 8) & 0xff); \\r
- trace[traceLen++] = ((samples >> 16) & 0xff); \\r
- trace[traceLen++] = ((samples >> 24) & 0xff); \\r
- trace[traceLen++] = 0; \\r
- trace[traceLen++] = 0; \\r
- trace[traceLen++] = 0; \\r
- trace[traceLen++] = 0; \\r
- trace[traceLen++] = Uart.byteCnt; \\r
- memcpy(trace+traceLen, receivedCmd, Uart.byteCnt); \\r
- traceLen += Uart.byteCnt; \\r
- if(traceLen > 1000) break; \\r
- } \\r
- /* And ready to receive another command. */ \\r
- memset(&Uart, 0, sizeof(Uart)); \\r
- Uart.output = receivedCmd; \\r
- Uart.byteCntMax = 100; \\r
- Uart.state = STATE_UNSYNCD; \\r
- /* And also reset the demod code, which might have been */ \\r
- /* false-triggered by the commands from the reader. */ \\r
- memset(&Demod, 0, sizeof(Demod)); \\r
- Demod.output = receivedResponse; \\r
- Demod.state = DEMOD_UNSYNCD; \\r
-\r
- if(Handle14443UartBit(ci & 1)) {\r
- HANDLE_BIT_IF_BODY\r
- }\r
- if(Handle14443UartBit(cq & 1)) {\r
- HANDLE_BIT_IF_BODY\r
- }\r
-\r
- if(Handle14443SamplesDemod(ci, cq)) {\r
- // timestamp, as a count of samples\r
- trace[traceLen++] = ((samples >> 0) & 0xff);\r
- trace[traceLen++] = ((samples >> 8) & 0xff);\r
- trace[traceLen++] = ((samples >> 16) & 0xff);\r
- trace[traceLen++] = 0x80 | ((samples >> 24) & 0xff);\r
- // correlation metric (~signal strength estimate)\r
- if(Demod.metricN != 0) {\r
- Demod.metric /= Demod.metricN;\r
- }\r
- trace[traceLen++] = ((Demod.metric >> 0) & 0xff);\r
- trace[traceLen++] = ((Demod.metric >> 8) & 0xff);\r
- trace[traceLen++] = ((Demod.metric >> 16) & 0xff);\r
- trace[traceLen++] = ((Demod.metric >> 24) & 0xff);\r
- // length\r
- trace[traceLen++] = Demod.len;\r
- memcpy(trace+traceLen, receivedResponse, Demod.len);\r
- traceLen += Demod.len;\r
- if(traceLen > DEMOD_TRACE_SIZE) { \r
- DbpString("Reached trace limit");\r
- goto done;\r
- }\r
-\r
- triggered = TRUE;\r
-\r
- // And ready to receive another response.\r
- memset(&Demod, 0, sizeof(Demod));\r
- Demod.output = receivedResponse;\r
- Demod.state = DEMOD_UNSYNCD;\r
- }\r
- WDT_HIT();\r
-\r
- if(BUTTON_PRESS()) {\r
- DbpString("cancelled");\r
- goto done;\r
- }\r
- }\r
-\r
-done:\r
- LED_D_OFF();\r
- AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS;\r
- DbpString("Snoop statistics:");\r
- Dbprintf(" Max behind by: %i", maxBehindBy);\r
- Dbprintf(" Uart State: %x", Uart.state);\r
- Dbprintf(" Uart ByteCnt: %i", Uart.byteCnt);\r
- Dbprintf(" Uart ByteCntMax: %i", Uart.byteCntMax);\r
- Dbprintf(" Trace length: %i", traceLen);\r
-}\r
+//-----------------------------------------------------------------------------
+// Routines to support ISO 14443. This includes both the reader software and
+// the `fake tag' modes. At the moment only the Type B modulation is
+// supported.
+// Jonathan Westhues, split Nov 2006
+//-----------------------------------------------------------------------------
+#include <proxmark3.h>
+#include "apps.h"
+#include "iso14443crc.h"
+
+
+//static void GetSamplesFor14443(BOOL weTx, int n);
+
+#define DEMOD_TRACE_SIZE 4096
+#define READER_TAG_BUFFER_SIZE 2048
+#define TAG_READER_BUFFER_SIZE 2048
+#define DMA_BUFFER_SIZE 1024
+
+//=============================================================================
+// An ISO 14443 Type B tag. We listen for commands from the reader, using
+// a UART kind of thing that's implemented in software. When we get a
+// frame (i.e., a group of bytes between SOF and EOF), we check the CRC.
+// If it's good, then we can do something appropriate with it, and send
+// a response.
+//=============================================================================
+
+//-----------------------------------------------------------------------------
+// Code up a string of octets at layer 2 (including CRC, we don't generate
+// that here) so that they can be transmitted to the reader. Doesn't transmit
+// them yet, just leaves them ready to send in ToSend[].
+//-----------------------------------------------------------------------------
+static void CodeIso14443bAsTag(const BYTE *cmd, int len)
+{
+ int i;
+
+ ToSendReset();
+
+ // Transmit a burst of ones, as the initial thing that lets the
+ // reader get phase sync. This (TR1) must be > 80/fs, per spec,
+ // but tag that I've tried (a Paypass) exceeds that by a fair bit,
+ // so I will too.
+ for(i = 0; i < 20; i++) {
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ }
+
+ // Send SOF.
+ for(i = 0; i < 10; i++) {
+ ToSendStuffBit(0);
+ ToSendStuffBit(0);
+ ToSendStuffBit(0);
+ ToSendStuffBit(0);
+ }
+ for(i = 0; i < 2; i++) {
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ }
+
+ for(i = 0; i < len; i++) {
+ int j;
+ BYTE b = cmd[i];
+
+ // Start bit
+ ToSendStuffBit(0);
+ ToSendStuffBit(0);
+ ToSendStuffBit(0);
+ ToSendStuffBit(0);
+
+ // Data bits
+ for(j = 0; j < 8; j++) {
+ if(b & 1) {
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ } else {
+ ToSendStuffBit(0);
+ ToSendStuffBit(0);
+ ToSendStuffBit(0);
+ ToSendStuffBit(0);
+ }
+ b >>= 1;
+ }
+
+ // Stop bit
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ }
+
+ // Send SOF.
+ for(i = 0; i < 10; i++) {
+ ToSendStuffBit(0);
+ ToSendStuffBit(0);
+ ToSendStuffBit(0);
+ ToSendStuffBit(0);
+ }
+ for(i = 0; i < 10; i++) {
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ }
+
+ // Convert from last byte pos to length
+ ToSendMax++;
+
+ // Add a few more for slop
+ ToSendMax += 2;
+}
+
+//-----------------------------------------------------------------------------
+// The software UART that receives commands from the reader, and its state
+// variables.
+//-----------------------------------------------------------------------------
+static struct {
+ enum {
+ STATE_UNSYNCD,
+ STATE_GOT_FALLING_EDGE_OF_SOF,
+ STATE_AWAITING_START_BIT,
+ STATE_RECEIVING_DATA,
+ STATE_ERROR_WAIT
+ } state;
+ WORD shiftReg;
+ int bitCnt;
+ int byteCnt;
+ int byteCntMax;
+ int posCnt;
+ BYTE *output;
+} Uart;
+
+/* Receive & handle a bit coming from the reader.
+ *
+ * LED handling:
+ * LED A -> ON once we have received the SOF and are expecting the rest.
+ * LED A -> OFF once we have received EOF or are in error state or unsynced
+ *
+ * Returns: true if we received a EOF
+ * false if we are still waiting for some more
+ */
+static BOOL Handle14443UartBit(int bit)
+{
+ switch(Uart.state) {
+ case STATE_UNSYNCD:
+ LED_A_OFF();
+ if(!bit) {
+ // we went low, so this could be the beginning
+ // of an SOF
+ Uart.state = STATE_GOT_FALLING_EDGE_OF_SOF;
+ Uart.posCnt = 0;
+ Uart.bitCnt = 0;
+ }
+ break;
+
+ case STATE_GOT_FALLING_EDGE_OF_SOF:
+ Uart.posCnt++;
+ if(Uart.posCnt == 2) {
+ if(bit) {
+ if(Uart.bitCnt >= 10) {
+ // we've seen enough consecutive
+ // zeros that it's a valid SOF
+ Uart.posCnt = 0;
+ Uart.byteCnt = 0;
+ Uart.state = STATE_AWAITING_START_BIT;
+ LED_A_ON(); // Indicate we got a valid SOF
+ } else {
+ // didn't stay down long enough
+ // before going high, error
+ Uart.state = STATE_ERROR_WAIT;
+ }
+ } else {
+ // do nothing, keep waiting
+ }
+ Uart.bitCnt++;
+ }
+ if(Uart.posCnt >= 4) Uart.posCnt = 0;
+ if(Uart.bitCnt > 14) {
+ // Give up if we see too many zeros without
+ // a one, too.
+ Uart.state = STATE_ERROR_WAIT;
+ }
+ break;
+
+ case STATE_AWAITING_START_BIT:
+ Uart.posCnt++;
+ if(bit) {
+ if(Uart.posCnt > 25) {
+ // stayed high for too long between
+ // characters, error
+ Uart.state = STATE_ERROR_WAIT;
+ }
+ } else {
+ // falling edge, this starts the data byte
+ Uart.posCnt = 0;
+ Uart.bitCnt = 0;
+ Uart.shiftReg = 0;
+ Uart.state = STATE_RECEIVING_DATA;
+ LED_A_ON(); // Indicate we're receiving
+ }
+ break;
+
+ case STATE_RECEIVING_DATA:
+ Uart.posCnt++;
+ if(Uart.posCnt == 2) {
+ // time to sample a bit
+ Uart.shiftReg >>= 1;
+ if(bit) {
+ Uart.shiftReg |= 0x200;
+ }
+ Uart.bitCnt++;
+ }
+ if(Uart.posCnt >= 4) {
+ Uart.posCnt = 0;
+ }
+ if(Uart.bitCnt == 10) {
+ if((Uart.shiftReg & 0x200) && !(Uart.shiftReg & 0x001))
+ {
+ // this is a data byte, with correct
+ // start and stop bits
+ Uart.output[Uart.byteCnt] = (Uart.shiftReg >> 1) & 0xff;
+ Uart.byteCnt++;
+
+ if(Uart.byteCnt >= Uart.byteCntMax) {
+ // Buffer overflowed, give up
+ Uart.posCnt = 0;
+ Uart.state = STATE_ERROR_WAIT;
+ } else {
+ // so get the next byte now
+ Uart.posCnt = 0;
+ Uart.state = STATE_AWAITING_START_BIT;
+ }
+ } else if(Uart.shiftReg == 0x000) {
+ // this is an EOF byte
+ LED_A_OFF(); // Finished receiving
+ return TRUE;
+ } else {
+ // this is an error
+ Uart.posCnt = 0;
+ Uart.state = STATE_ERROR_WAIT;
+ }
+ }
+ break;
+
+ case STATE_ERROR_WAIT:
+ // We're all screwed up, so wait a little while
+ // for whatever went wrong to finish, and then
+ // start over.
+ Uart.posCnt++;
+ if(Uart.posCnt > 10) {
+ Uart.state = STATE_UNSYNCD;
+ }
+ break;
+
+ default:
+ Uart.state = STATE_UNSYNCD;
+ break;
+ }
+
+ if (Uart.state == STATE_ERROR_WAIT) LED_A_OFF(); // Error
+
+ return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// Receive a command (from the reader to us, where we are the simulated tag),
+// and store it in the given buffer, up to the given maximum length. Keeps
+// spinning, waiting for a well-framed command, until either we get one
+// (returns TRUE) or someone presses the pushbutton on the board (FALSE).
+//
+// Assume that we're called with the SSC (to the FPGA) and ADC path set
+// correctly.
+//-----------------------------------------------------------------------------
+static BOOL GetIso14443CommandFromReader(BYTE *received, int *len, int maxLen)
+{
+ BYTE mask;
+ int i, bit;
+
+ // Set FPGA mode to "simulated ISO 14443 tag", no modulation (listen
+ // only, since we are receiving, not transmitting).
+ // Signal field is off with the appropriate LED
+ LED_D_OFF();
+ FpgaWriteConfWord(
+ FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION);
+
+
+ // Now run a `software UART' on the stream of incoming samples.
+ Uart.output = received;
+ Uart.byteCntMax = maxLen;
+ Uart.state = STATE_UNSYNCD;
+
+ for(;;) {
+ WDT_HIT();
+
+ if(BUTTON_PRESS()) return FALSE;
+
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
+ AT91C_BASE_SSC->SSC_THR = 0x00;
+ }
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
+ BYTE b = (BYTE)AT91C_BASE_SSC->SSC_RHR;
+
+ mask = 0x80;
+ for(i = 0; i < 8; i++, mask >>= 1) {
+ bit = (b & mask);
+ if(Handle14443UartBit(bit)) {
+ *len = Uart.byteCnt;
+ return TRUE;
+ }
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Main loop of simulated tag: receive commands from reader, decide what
+// response to send, and send it.
+//-----------------------------------------------------------------------------
+void SimulateIso14443Tag(void)
+{
+ static const BYTE cmd1[] = { 0x05, 0x00, 0x08, 0x39, 0x73 };
+ static const BYTE response1[] = {
+ 0x50, 0x82, 0x0d, 0xe1, 0x74, 0x20, 0x38, 0x19, 0x22,
+ 0x00, 0x21, 0x85, 0x5e, 0xd7
+ };
+
+ BYTE *resp;
+ int respLen;
+
+ BYTE *resp1 = (((BYTE *)BigBuf) + 800);
+ int resp1Len;
+
+ BYTE *receivedCmd = (BYTE *)BigBuf;
+ int len;
+
+ int i;
+
+ int cmdsRecvd = 0;
+
+ memset(receivedCmd, 0x44, 400);
+
+ CodeIso14443bAsTag(response1, sizeof(response1));
+ memcpy(resp1, ToSend, ToSendMax); resp1Len = ToSendMax;
+
+ // We need to listen to the high-frequency, peak-detected path.
+ SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
+ FpgaSetupSsc();
+
+ cmdsRecvd = 0;
+
+ for(;;) {
+ BYTE b1, b2;
+
+ if(!GetIso14443CommandFromReader(receivedCmd, &len, 100)) {
+ Dbprintf("button pressed, received %d commands", cmdsRecvd);
+ break;
+ }
+
+ // Good, look at the command now.
+
+ if(len == sizeof(cmd1) && memcmp(receivedCmd, cmd1, len)==0) {
+ resp = resp1; respLen = resp1Len;
+ } else {
+ Dbprintf("new cmd from reader: len=%d, cmdsRecvd=%d", len, cmdsRecvd);
+ // And print whether the CRC fails, just for good measure
+ ComputeCrc14443(CRC_14443_B, receivedCmd, len-2, &b1, &b2);
+ if(b1 != receivedCmd[len-2] || b2 != receivedCmd[len-1]) {
+ // Not so good, try again.
+ DbpString("+++CRC fail");
+ } else {
+ DbpString("CRC passes");
+ }
+ break;
+ }
+
+ memset(receivedCmd, 0x44, 32);
+
+ cmdsRecvd++;
+
+ if(cmdsRecvd > 0x30) {
+ DbpString("many commands later...");
+ break;
+ }
+
+ if(respLen <= 0) continue;
+
+ // Modulate BPSK
+ // Signal field is off with the appropriate LED
+ LED_D_OFF();
+ FpgaWriteConfWord(
+ FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_BPSK);
+ AT91C_BASE_SSC->SSC_THR = 0xff;
+ FpgaSetupSsc();
+
+ // Transmit the response.
+ i = 0;
+ for(;;) {
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
+ BYTE b = resp[i];
+
+ AT91C_BASE_SSC->SSC_THR = b;
+
+ i++;
+ if(i > respLen) {
+ break;
+ }
+ }
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
+ volatile BYTE b = (BYTE)AT91C_BASE_SSC->SSC_RHR;
+ (void)b;
+ }
+ }
+ }
+}
+
+//=============================================================================
+// An ISO 14443 Type B reader. We take layer two commands, code them
+// appropriately, and then send them to the tag. We then listen for the
+// tag's response, which we leave in the buffer to be demodulated on the
+// PC side.
+//=============================================================================
+
+static struct {
+ enum {
+ DEMOD_UNSYNCD,
+ DEMOD_PHASE_REF_TRAINING,
+ DEMOD_AWAITING_FALLING_EDGE_OF_SOF,
+ DEMOD_GOT_FALLING_EDGE_OF_SOF,
+ DEMOD_AWAITING_START_BIT,
+ DEMOD_RECEIVING_DATA,
+ DEMOD_ERROR_WAIT
+ } state;
+ int bitCount;
+ int posCount;
+ int thisBit;
+ int metric;
+ int metricN;
+ WORD shiftReg;
+ BYTE *output;
+ int len;
+ int sumI;
+ int sumQ;
+} Demod;
+
+/*
+ * Handles reception of a bit from the tag
+ *
+ * LED handling:
+ * LED C -> ON once we have received the SOF and are expecting the rest.
+ * LED C -> OFF once we have received EOF or are unsynced
+ *
+ * Returns: true if we received a EOF
+ * false if we are still waiting for some more
+ *
+ */
+static BOOL Handle14443SamplesDemod(int ci, int cq)
+{
+ int v;
+
+ // The soft decision on the bit uses an estimate of just the
+ // quadrant of the reference angle, not the exact angle.
+#define MAKE_SOFT_DECISION() { \
+ if(Demod.sumI > 0) { \
+ v = ci; \
+ } else { \
+ v = -ci; \
+ } \
+ if(Demod.sumQ > 0) { \
+ v += cq; \
+ } else { \
+ v -= cq; \
+ } \
+ }
+
+ switch(Demod.state) {
+ case DEMOD_UNSYNCD:
+ v = ci;
+ if(v < 0) v = -v;
+ if(cq > 0) {
+ v += cq;
+ } else {
+ v -= cq;
+ }
+ if(v > 40) {
+ Demod.posCount = 0;
+ Demod.state = DEMOD_PHASE_REF_TRAINING;
+ Demod.sumI = 0;
+ Demod.sumQ = 0;
+ }
+ break;
+
+ case DEMOD_PHASE_REF_TRAINING:
+ if(Demod.posCount < 8) {
+ Demod.sumI += ci;
+ Demod.sumQ += cq;
+ } else if(Demod.posCount > 100) {
+ // error, waited too long
+ Demod.state = DEMOD_UNSYNCD;
+ } else {
+ MAKE_SOFT_DECISION();
+ if(v < 0) {
+ Demod.state = DEMOD_AWAITING_FALLING_EDGE_OF_SOF;
+ Demod.posCount = 0;
+ }
+ }
+ Demod.posCount++;
+ break;
+
+ case DEMOD_AWAITING_FALLING_EDGE_OF_SOF:
+ MAKE_SOFT_DECISION();
+ if(v < 0) {
+ Demod.state = DEMOD_GOT_FALLING_EDGE_OF_SOF;
+ Demod.posCount = 0;
+ } else {
+ if(Demod.posCount > 100) {
+ Demod.state = DEMOD_UNSYNCD;
+ }
+ }
+ Demod.posCount++;
+ break;
+
+ case DEMOD_GOT_FALLING_EDGE_OF_SOF:
+ MAKE_SOFT_DECISION();
+ if(v > 0) {
+ if(Demod.posCount < 12) {
+ Demod.state = DEMOD_UNSYNCD;
+ } else {
+ LED_C_ON(); // Got SOF
+ Demod.state = DEMOD_AWAITING_START_BIT;
+ Demod.posCount = 0;
+ Demod.len = 0;
+ Demod.metricN = 0;
+ Demod.metric = 0;
+ }
+ } else {
+ if(Demod.posCount > 100) {
+ Demod.state = DEMOD_UNSYNCD;
+ }
+ }
+ Demod.posCount++;
+ break;
+
+ case DEMOD_AWAITING_START_BIT:
+ MAKE_SOFT_DECISION();
+ if(v > 0) {
+ if(Demod.posCount > 10) {
+ Demod.state = DEMOD_UNSYNCD;
+ }
+ } else {
+ Demod.bitCount = 0;
+ Demod.posCount = 1;
+ Demod.thisBit = v;
+ Demod.shiftReg = 0;
+ Demod.state = DEMOD_RECEIVING_DATA;
+ }
+ break;
+
+ case DEMOD_RECEIVING_DATA:
+ MAKE_SOFT_DECISION();
+ if(Demod.posCount == 0) {
+ Demod.thisBit = v;
+ Demod.posCount = 1;
+ } else {
+ Demod.thisBit += v;
+
+ if(Demod.thisBit > 0) {
+ Demod.metric += Demod.thisBit;
+ } else {
+ Demod.metric -= Demod.thisBit;
+ }
+ (Demod.metricN)++;
+
+ Demod.shiftReg >>= 1;
+ if(Demod.thisBit > 0) {
+ Demod.shiftReg |= 0x200;
+ }
+
+ Demod.bitCount++;
+ if(Demod.bitCount == 10) {
+ WORD s = Demod.shiftReg;
+ if((s & 0x200) && !(s & 0x001)) {
+ BYTE b = (s >> 1);
+ Demod.output[Demod.len] = b;
+ Demod.len++;
+ Demod.state = DEMOD_AWAITING_START_BIT;
+ } else if(s == 0x000) {
+ // This is EOF
+ LED_C_OFF();
+ return TRUE;
+ Demod.state = DEMOD_UNSYNCD;
+ } else {
+ Demod.state = DEMOD_UNSYNCD;
+ }
+ }
+ Demod.posCount = 0;
+ }
+ break;
+
+ default:
+ Demod.state = DEMOD_UNSYNCD;
+ break;
+ }
+
+ if (Demod.state == DEMOD_UNSYNCD) LED_C_OFF(); // Not synchronized...
+ return FALSE;
+}
+
+/*
+ * Demodulate the samples we received from the tag
+ * weTx: set to 'TRUE' if we behave like a reader
+ * set to 'FALSE' if we behave like a snooper
+ * quiet: set to 'TRUE' to disable debug output
+ */
+static void GetSamplesFor14443Demod(BOOL weTx, int n, BOOL quiet)
+{
+ int max = 0;
+ BOOL gotFrame = FALSE;
+
+//# define DMA_BUFFER_SIZE 8
+ SBYTE *dmaBuf;
+
+ int lastRxCounter;
+ SBYTE *upTo;
+
+ int ci, cq;
+
+ int samples = 0;
+
+ // Clear out the state of the "UART" that receives from the tag.
+ memset(BigBuf, 0x44, 400);
+ Demod.output = (BYTE *)BigBuf;
+ Demod.len = 0;
+ Demod.state = DEMOD_UNSYNCD;
+
+ // And the UART that receives from the reader
+ Uart.output = (((BYTE *)BigBuf) + 1024);
+ Uart.byteCntMax = 100;
+ Uart.state = STATE_UNSYNCD;
+
+ // Setup for the DMA.
+ dmaBuf = (SBYTE *)(BigBuf + 32);
+ upTo = dmaBuf;
+ lastRxCounter = DMA_BUFFER_SIZE;
+ FpgaSetupSscDma((BYTE *)dmaBuf, DMA_BUFFER_SIZE);
+
+ // Signal field is ON with the appropriate LED:
+ if (weTx) LED_D_ON(); else LED_D_OFF();
+ // And put the FPGA in the appropriate mode
+ FpgaWriteConfWord(
+ FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ |
+ (weTx ? 0 : FPGA_HF_READER_RX_XCORR_SNOOP));
+
+ for(;;) {
+ int behindBy = lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR;
+ if(behindBy > max) max = behindBy;
+
+ while(((lastRxCounter-AT91C_BASE_PDC_SSC->PDC_RCR) & (DMA_BUFFER_SIZE-1))
+ > 2)
+ {
+ ci = upTo[0];
+ cq = upTo[1];
+ upTo += 2;
+ if(upTo - dmaBuf > DMA_BUFFER_SIZE) {
+ upTo -= DMA_BUFFER_SIZE;
+ AT91C_BASE_PDC_SSC->PDC_RNPR = (DWORD)upTo;
+ AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE;
+ }
+ lastRxCounter -= 2;
+ if(lastRxCounter <= 0) {
+ lastRxCounter += DMA_BUFFER_SIZE;
+ }
+
+ samples += 2;
+
+ Handle14443UartBit(1);
+ Handle14443UartBit(1);
+
+ if(Handle14443SamplesDemod(ci, cq)) {
+ gotFrame = 1;
+ }
+ }
+
+ if(samples > 2000) {
+ break;
+ }
+ }
+ AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS;
+ if (!quiet) Dbprintf("%x %x %x", max, gotFrame, Demod.len);
+}
+
+//-----------------------------------------------------------------------------
+// Read the tag's response. We just receive a stream of slightly-processed
+// samples from the FPGA, which we will later do some signal processing on,
+// to get the bits.
+//-----------------------------------------------------------------------------
+/*static void GetSamplesFor14443(BOOL weTx, int n)
+{
+ BYTE *dest = (BYTE *)BigBuf;
+ int c;
+
+ FpgaWriteConfWord(
+ FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ |
+ (weTx ? 0 : FPGA_HF_READER_RX_XCORR_SNOOP));
+
+ c = 0;
+ for(;;) {
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
+ AT91C_BASE_SSC->SSC_THR = 0x43;
+ }
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
+ SBYTE b;
+ b = (SBYTE)AT91C_BASE_SSC->SSC_RHR;
+
+ dest[c++] = (BYTE)b;
+
+ if(c >= n) {
+ break;
+ }
+ }
+ }
+}*/
+
+//-----------------------------------------------------------------------------
+// Transmit the command (to the tag) that was placed in ToSend[].
+//-----------------------------------------------------------------------------
+static void TransmitFor14443(void)
+{
+ int c;
+
+ FpgaSetupSsc();
+
+ while(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
+ AT91C_BASE_SSC->SSC_THR = 0xff;
+ }
+
+ // Signal field is ON with the appropriate Red LED
+ LED_D_ON();
+ // Signal we are transmitting with the Green LED
+ LED_B_ON();
+ FpgaWriteConfWord(
+ FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD);
+
+ for(c = 0; c < 10;) {
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
+ AT91C_BASE_SSC->SSC_THR = 0xff;
+ c++;
+ }
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
+ volatile DWORD r = AT91C_BASE_SSC->SSC_RHR;
+ (void)r;
+ }
+ WDT_HIT();
+ }
+
+ c = 0;
+ for(;;) {
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
+ AT91C_BASE_SSC->SSC_THR = ToSend[c];
+ c++;
+ if(c >= ToSendMax) {
+ break;
+ }
+ }
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
+ volatile DWORD r = AT91C_BASE_SSC->SSC_RHR;
+ (void)r;
+ }
+ WDT_HIT();
+ }
+ LED_B_OFF(); // Finished sending
+}
+
+//-----------------------------------------------------------------------------
+// Code a layer 2 command (string of octets, including CRC) into ToSend[],
+// so that it is ready to transmit to the tag using TransmitFor14443().
+//-----------------------------------------------------------------------------
+void CodeIso14443bAsReader(const BYTE *cmd, int len)
+{
+ int i, j;
+ BYTE b;
+
+ ToSendReset();
+
+ // Establish initial reference level
+ for(i = 0; i < 40; i++) {
+ ToSendStuffBit(1);
+ }
+ // Send SOF
+ for(i = 0; i < 10; i++) {
+ ToSendStuffBit(0);
+ }
+
+ for(i = 0; i < len; i++) {
+ // Stop bits/EGT
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ // Start bit
+ ToSendStuffBit(0);
+ // Data bits
+ b = cmd[i];
+ for(j = 0; j < 8; j++) {
+ if(b & 1) {
+ ToSendStuffBit(1);
+ } else {
+ ToSendStuffBit(0);
+ }
+ b >>= 1;
+ }
+ }
+ // Send EOF
+ ToSendStuffBit(1);
+ for(i = 0; i < 10; i++) {
+ ToSendStuffBit(0);
+ }
+ for(i = 0; i < 8; i++) {
+ ToSendStuffBit(1);
+ }
+
+ // And then a little more, to make sure that the last character makes
+ // it out before we switch to rx mode.
+ for(i = 0; i < 24; i++) {
+ ToSendStuffBit(1);
+ }
+
+ // Convert from last character reference to length
+ ToSendMax++;
+}
+
+//-----------------------------------------------------------------------------
+// Read an ISO 14443 tag. We send it some set of commands, and record the
+// responses.
+// The command name is misleading, it actually decodes the reponse in HEX
+// into the output buffer (read the result using hexsamples, not hisamples)
+//-----------------------------------------------------------------------------
+void AcquireRawAdcSamplesIso14443(DWORD parameter)
+{
+ BYTE cmd1[] = { 0x05, 0x00, 0x08, 0x39, 0x73 };
+
+ // Make sure that we start from off, since the tags are stateful;
+ // confusing things will happen if we don't reset them between reads.
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+ LED_D_OFF();
+ SpinDelay(200);
+
+ SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
+ FpgaSetupSsc();
+
+ // Now give it time to spin up.
+ // Signal field is on with the appropriate LED
+ LED_D_ON();
+ FpgaWriteConfWord(
+ FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ);
+ SpinDelay(200);
+
+ CodeIso14443bAsReader(cmd1, sizeof(cmd1));
+ TransmitFor14443();
+// LED_A_ON();
+ GetSamplesFor14443Demod(TRUE, 2000, FALSE);
+// LED_A_OFF();
+}
+
+//-----------------------------------------------------------------------------
+// Read a SRI512 ISO 14443 tag.
+//
+// SRI512 tags are just simple memory tags, here we're looking at making a dump
+// of the contents of the memory. No anticollision algorithm is done, we assume
+// we have a single tag in the field.
+//
+// I tried to be systematic and check every answer of the tag, every CRC, etc...
+//-----------------------------------------------------------------------------
+void ReadSRI512Iso14443(DWORD parameter)
+{
+ ReadSTMemoryIso14443(parameter,0x0F);
+}
+void ReadSRIX4KIso14443(DWORD parameter)
+{
+ ReadSTMemoryIso14443(parameter,0x7F);
+}
+
+void ReadSTMemoryIso14443(DWORD parameter,DWORD dwLast)
+{
+ BYTE i = 0x00;
+
+ // Make sure that we start from off, since the tags are stateful;
+ // confusing things will happen if we don't reset them between reads.
+ LED_D_OFF();
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+ SpinDelay(200);
+
+ SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
+ FpgaSetupSsc();
+
+ // Now give it time to spin up.
+ // Signal field is on with the appropriate LED
+ LED_D_ON();
+ FpgaWriteConfWord(
+ FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ);
+ SpinDelay(200);
+
+ // First command: wake up the tag using the INITIATE command
+ BYTE cmd1[] = { 0x06, 0x00, 0x97, 0x5b};
+ CodeIso14443bAsReader(cmd1, sizeof(cmd1));
+ TransmitFor14443();
+// LED_A_ON();
+ GetSamplesFor14443Demod(TRUE, 2000,TRUE);
+// LED_A_OFF();
+
+ if (Demod.len == 0) {
+ DbpString("No response from tag");
+ return;
+ } else {
+ Dbprintf("Randomly generated UID from tag (+ 2 byte CRC): %x %x %x",
+ Demod.output[0], Demod.output[1],Demod.output[2]);
+ }
+ // There is a response, SELECT the uid
+ DbpString("Now SELECT tag:");
+ cmd1[0] = 0x0E; // 0x0E is SELECT
+ cmd1[1] = Demod.output[0];
+ ComputeCrc14443(CRC_14443_B, cmd1, 2, &cmd1[2], &cmd1[3]);
+ CodeIso14443bAsReader(cmd1, sizeof(cmd1));
+ TransmitFor14443();
+// LED_A_ON();
+ GetSamplesFor14443Demod(TRUE, 2000,TRUE);
+// LED_A_OFF();
+ if (Demod.len != 3) {
+ Dbprintf("Expected 3 bytes from tag, got %d", Demod.len);
+ return;
+ }
+ // Check the CRC of the answer:
+ ComputeCrc14443(CRC_14443_B, Demod.output, 1 , &cmd1[2], &cmd1[3]);
+ if(cmd1[2] != Demod.output[1] || cmd1[3] != Demod.output[2]) {
+ DbpString("CRC Error reading select response.");
+ return;
+ }
+ // Check response from the tag: should be the same UID as the command we just sent:
+ if (cmd1[1] != Demod.output[0]) {
+ Dbprintf("Bad response to SELECT from Tag, aborting: %x %x", cmd1[1], Demod.output[0]);
+ return;
+ }
+ // Tag is now selected,
+ // First get the tag's UID:
+ cmd1[0] = 0x0B;
+ ComputeCrc14443(CRC_14443_B, cmd1, 1 , &cmd1[1], &cmd1[2]);
+ CodeIso14443bAsReader(cmd1, 3); // Only first three bytes for this one
+ TransmitFor14443();
+// LED_A_ON();
+ GetSamplesFor14443Demod(TRUE, 2000,TRUE);
+// LED_A_OFF();
+ if (Demod.len != 10) {
+ Dbprintf("Expected 10 bytes from tag, got %d", Demod.len);
+ return;
+ }
+ // The check the CRC of the answer (use cmd1 as temporary variable):
+ ComputeCrc14443(CRC_14443_B, Demod.output, 8, &cmd1[2], &cmd1[3]);
+ if(cmd1[2] != Demod.output[8] || cmd1[3] != Demod.output[9]) {
+ Dbprintf("CRC Error reading block! - Below: expected, got %x %x",
+ (cmd1[2]<<8)+cmd1[3], (Demod.output[8]<<8)+Demod.output[9]);
+ // Do not return;, let's go on... (we should retry, maybe ?)
+ }
+ Dbprintf("Tag UID (64 bits): %08x %08x",
+ (Demod.output[7]<<24) + (Demod.output[6]<<16) + (Demod.output[5]<<8) + Demod.output[4],
+ (Demod.output[3]<<24) + (Demod.output[2]<<16) + (Demod.output[1]<<8) + Demod.output[0]);
+
+ // Now loop to read all 16 blocks, address from 0 to 15
+ DbpString("Tag memory dump, block 0 to 15");
+ cmd1[0] = 0x08;
+ i = 0x00;
+ dwLast++;
+ for (;;) {
+ if (i == dwLast) {
+ DbpString("System area block (0xff):");
+ i = 0xff;
+ }
+ cmd1[1] = i;
+ ComputeCrc14443(CRC_14443_B, cmd1, 2, &cmd1[2], &cmd1[3]);
+ CodeIso14443bAsReader(cmd1, sizeof(cmd1));
+ TransmitFor14443();
+// LED_A_ON();
+ GetSamplesFor14443Demod(TRUE, 2000,TRUE);
+// LED_A_OFF();
+ if (Demod.len != 6) { // Check if we got an answer from the tag
+ DbpString("Expected 6 bytes from tag, got less...");
+ return;
+ }
+ // The check the CRC of the answer (use cmd1 as temporary variable):
+ ComputeCrc14443(CRC_14443_B, Demod.output, 4, &cmd1[2], &cmd1[3]);
+ if(cmd1[2] != Demod.output[4] || cmd1[3] != Demod.output[5]) {
+ Dbprintf("CRC Error reading block! - Below: expected, got %x %x",
+ (cmd1[2]<<8)+cmd1[3], (Demod.output[4]<<8)+Demod.output[5]);
+ // Do not return;, let's go on... (we should retry, maybe ?)
+ }
+ // Now print out the memory location:
+ Dbprintf("Address=%x, Contents=%x, CRC=%x", i,
+ (Demod.output[3]<<24) + (Demod.output[2]<<16) + (Demod.output[1]<<8) + Demod.output[0],
+ (Demod.output[4]<<8)+Demod.output[5]);
+ if (i == 0xff) {
+ break;
+ }
+ i++;
+ }
+}
+
+
+//=============================================================================
+// Finally, the `sniffer' combines elements from both the reader and
+// simulated tag, to show both sides of the conversation.
+//=============================================================================
+
+//-----------------------------------------------------------------------------
+// Record the sequence of commands sent by the reader to the tag, with
+// triggering so that we start recording at the point that the tag is moved
+// near the reader.
+//-----------------------------------------------------------------------------
+/*
+ * Memory usage for this function, (within BigBuf)
+ * 0-4095 : Demodulated samples receive (4096 bytes) - DEMOD_TRACE_SIZE
+ * 4096-6143 : Last Received command, 2048 bytes (reader->tag) - READER_TAG_BUFFER_SIZE
+ * 6144-8191 : Last Received command, 2048 bytes(tag->reader) - TAG_READER_BUFFER_SIZE
+ * 8192-9215 : DMA Buffer, 1024 bytes (samples) - DMA_BUFFER_SIZE
+ */
+void SnoopIso14443(void)
+{
+ // We won't start recording the frames that we acquire until we trigger;
+ // a good trigger condition to get started is probably when we see a
+ // response from the tag.
+ BOOL triggered = FALSE;
+
+ // The command (reader -> tag) that we're working on receiving.
+ BYTE *receivedCmd = (BYTE *)(BigBuf) + DEMOD_TRACE_SIZE;
+ // The response (tag -> reader) that we're working on receiving.
+ BYTE *receivedResponse = (BYTE *)(BigBuf) + DEMOD_TRACE_SIZE + READER_TAG_BUFFER_SIZE;
+
+ // As we receive stuff, we copy it from receivedCmd or receivedResponse
+ // into trace, along with its length and other annotations.
+ BYTE *trace = (BYTE *)BigBuf;
+ int traceLen = 0;
+
+ // The DMA buffer, used to stream samples from the FPGA.
+ SBYTE *dmaBuf = (SBYTE *)(BigBuf) + DEMOD_TRACE_SIZE + READER_TAG_BUFFER_SIZE + TAG_READER_BUFFER_SIZE;
+ int lastRxCounter;
+ SBYTE *upTo;
+ int ci, cq;
+ int maxBehindBy = 0;
+
+ // Count of samples received so far, so that we can include timing
+ // information in the trace buffer.
+ int samples = 0;
+
+ // Initialize the trace buffer
+ memset(trace, 0x44, DEMOD_TRACE_SIZE);
+
+ // Set up the demodulator for tag -> reader responses.
+ Demod.output = receivedResponse;
+ Demod.len = 0;
+ Demod.state = DEMOD_UNSYNCD;
+
+ // And the reader -> tag commands
+ memset(&Uart, 0, sizeof(Uart));
+ Uart.output = receivedCmd;
+ Uart.byteCntMax = 100;
+ Uart.state = STATE_UNSYNCD;
+
+ // Print some debug information about the buffer sizes
+ Dbprintf("Snooping buffers initialized:");
+ Dbprintf(" Trace: %i bytes", DEMOD_TRACE_SIZE);
+ Dbprintf(" Reader -> tag: %i bytes", READER_TAG_BUFFER_SIZE);
+ Dbprintf(" tag -> Reader: %i bytes", TAG_READER_BUFFER_SIZE);
+ Dbprintf(" DMA: %i bytes", DMA_BUFFER_SIZE);
+
+ // Use a counter for blinking the LED
+ long ledCount=0;
+ long ledFlashAt=200000;
+
+ // And put the FPGA in the appropriate mode
+ // Signal field is off with the appropriate LED
+ LED_D_OFF();
+ FpgaWriteConfWord(
+ FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ |
+ FPGA_HF_READER_RX_XCORR_SNOOP);
+ SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
+
+ // Setup for the DMA.
+ FpgaSetupSsc();
+ upTo = dmaBuf;
+ lastRxCounter = DMA_BUFFER_SIZE;
+ FpgaSetupSscDma((BYTE *)dmaBuf, DMA_BUFFER_SIZE);
+ // And now we loop, receiving samples.
+ for(;;) {
+ // Blink the LED while Snooping
+ ledCount++;
+ if (ledCount == ledFlashAt) {
+ LED_D_ON();
+ }
+ if (ledCount >= 2*ledFlashAt) {
+ LED_D_OFF();
+ ledCount=0;
+ }
+
+ int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) &
+ (DMA_BUFFER_SIZE-1);
+ if(behindBy > maxBehindBy) {
+ maxBehindBy = behindBy;
+ if(behindBy > (DMA_BUFFER_SIZE-2)) { // TODO: understand whether we can increase/decrease as we want or not?
+ Dbprintf("blew circular buffer! behindBy=%x", behindBy);
+ goto done;
+ }
+ }
+ if(behindBy < 2) continue;
+
+ ci = upTo[0];
+ cq = upTo[1];
+ upTo += 2;
+ lastRxCounter -= 2;
+ if(upTo - dmaBuf > DMA_BUFFER_SIZE) {
+ upTo -= DMA_BUFFER_SIZE;
+ lastRxCounter += DMA_BUFFER_SIZE;
+ AT91C_BASE_PDC_SSC->PDC_RNPR = (DWORD) upTo;
+ AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE;
+ }
+
+ samples += 2;
+
+#define HANDLE_BIT_IF_BODY \
+ if(triggered) { \
+ ledFlashAt=30000; \
+ trace[traceLen++] = ((samples >> 0) & 0xff); \
+ trace[traceLen++] = ((samples >> 8) & 0xff); \
+ trace[traceLen++] = ((samples >> 16) & 0xff); \
+ trace[traceLen++] = ((samples >> 24) & 0xff); \
+ trace[traceLen++] = 0; \
+ trace[traceLen++] = 0; \
+ trace[traceLen++] = 0; \
+ trace[traceLen++] = 0; \
+ trace[traceLen++] = Uart.byteCnt; \
+ memcpy(trace+traceLen, receivedCmd, Uart.byteCnt); \
+ traceLen += Uart.byteCnt; \
+ if(traceLen > 1000) break; \
+ } \
+ /* And ready to receive another command. */ \
+ memset(&Uart, 0, sizeof(Uart)); \
+ Uart.output = receivedCmd; \
+ Uart.byteCntMax = 100; \
+ Uart.state = STATE_UNSYNCD; \
+ /* And also reset the demod code, which might have been */ \
+ /* false-triggered by the commands from the reader. */ \
+ memset(&Demod, 0, sizeof(Demod)); \
+ Demod.output = receivedResponse; \
+ Demod.state = DEMOD_UNSYNCD; \
+
+ if(Handle14443UartBit(ci & 1)) {
+ HANDLE_BIT_IF_BODY
+ }
+ if(Handle14443UartBit(cq & 1)) {
+ HANDLE_BIT_IF_BODY
+ }
+
+ if(Handle14443SamplesDemod(ci, cq)) {
+ // timestamp, as a count of samples
+ trace[traceLen++] = ((samples >> 0) & 0xff);
+ trace[traceLen++] = ((samples >> 8) & 0xff);
+ trace[traceLen++] = ((samples >> 16) & 0xff);
+ trace[traceLen++] = 0x80 | ((samples >> 24) & 0xff);
+ // correlation metric (~signal strength estimate)
+ if(Demod.metricN != 0) {
+ Demod.metric /= Demod.metricN;
+ }
+ trace[traceLen++] = ((Demod.metric >> 0) & 0xff);
+ trace[traceLen++] = ((Demod.metric >> 8) & 0xff);
+ trace[traceLen++] = ((Demod.metric >> 16) & 0xff);
+ trace[traceLen++] = ((Demod.metric >> 24) & 0xff);
+ // length
+ trace[traceLen++] = Demod.len;
+ memcpy(trace+traceLen, receivedResponse, Demod.len);
+ traceLen += Demod.len;
+ if(traceLen > DEMOD_TRACE_SIZE) {
+ DbpString("Reached trace limit");
+ goto done;
+ }
+
+ triggered = TRUE;
+
+ // And ready to receive another response.
+ memset(&Demod, 0, sizeof(Demod));
+ Demod.output = receivedResponse;
+ Demod.state = DEMOD_UNSYNCD;
+ }
+ WDT_HIT();
+
+ if(BUTTON_PRESS()) {
+ DbpString("cancelled");
+ goto done;
+ }
+ }
+
+done:
+ LED_D_OFF();
+ AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS;
+ DbpString("Snoop statistics:");
+ Dbprintf(" Max behind by: %i", maxBehindBy);
+ Dbprintf(" Uart State: %x", Uart.state);
+ Dbprintf(" Uart ByteCnt: %i", Uart.byteCnt);
+ Dbprintf(" Uart ByteCntMax: %i", Uart.byteCntMax);
+ Dbprintf(" Trace length: %i", traceLen);
+}
-//-----------------------------------------------------------------------------\r
-// Routines to support ISO 14443 type A.\r
-//\r
-// Gerhard de Koning Gans - May 2008\r
-//-----------------------------------------------------------------------------\r
-#include <proxmark3.h>\r
-#include "apps.h"\r
-#include "iso14443crc.h"\r
-\r
-static BYTE *trace = (BYTE *) BigBuf;\r
-static int traceLen = 0;\r
-static int rsamples = 0;\r
-static BOOL tracing = TRUE;\r
-\r
-typedef enum {\r
- SEC_D = 1,\r
- SEC_E = 2,\r
- SEC_F = 3,\r
- SEC_X = 4,\r
- SEC_Y = 5,\r
- SEC_Z = 6\r
-} SecType;\r
-\r
-static const BYTE OddByteParity[256] = {\r
- 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,\r
- 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,\r
- 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,\r
- 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,\r
- 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,\r
- 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,\r
- 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,\r
- 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,\r
- 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,\r
- 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,\r
- 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,\r
- 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,\r
- 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,\r
- 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,\r
- 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,\r
- 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1\r
-};\r
-\r
-// BIG CHANGE - UNDERSTAND THIS BEFORE WE COMMIT\r
-#define RECV_CMD_OFFSET 3032\r
-#define RECV_RES_OFFSET 3096\r
-#define DMA_BUFFER_OFFSET 3160\r
-#define DMA_BUFFER_SIZE 4096\r
-#define TRACE_LENGTH 3000\r
-\r
-//-----------------------------------------------------------------------------\r
-// Generate the parity value for a byte sequence\r
-// \r
-//-----------------------------------------------------------------------------\r
-DWORD GetParity(const BYTE * pbtCmd, int iLen)\r
-{\r
- int i;\r
- DWORD dwPar = 0;\r
- \r
- // Generate the encrypted data\r
- for (i = 0; i < iLen; i++) {\r
- // Save the encrypted parity bit\r
- dwPar |= ((OddByteParity[pbtCmd[i]]) << i);\r
- }\r
- return dwPar;\r
-}\r
-\r
-static void AppendCrc14443a(BYTE* data, int len)\r
-{\r
- ComputeCrc14443(CRC_14443_A,data,len,data+len,data+len+1);\r
-}\r
-\r
-BOOL LogTrace(const BYTE * btBytes, int iLen, int iSamples, DWORD dwParity, BOOL bReader)\r
-{\r
- // Return when trace is full\r
- if (traceLen >= TRACE_LENGTH) return FALSE;\r
- \r
- // Trace the random, i'm curious\r
- rsamples += iSamples;\r
- trace[traceLen++] = ((rsamples >> 0) & 0xff);\r
- trace[traceLen++] = ((rsamples >> 8) & 0xff);\r
- trace[traceLen++] = ((rsamples >> 16) & 0xff);\r
- trace[traceLen++] = ((rsamples >> 24) & 0xff);\r
- if (!bReader) {\r
- trace[traceLen - 1] |= 0x80;\r
- }\r
- trace[traceLen++] = ((dwParity >> 0) & 0xff);\r
- trace[traceLen++] = ((dwParity >> 8) & 0xff);\r
- trace[traceLen++] = ((dwParity >> 16) & 0xff);\r
- trace[traceLen++] = ((dwParity >> 24) & 0xff);\r
- trace[traceLen++] = iLen;\r
- memcpy(trace + traceLen, btBytes, iLen);\r
- traceLen += iLen;\r
- return TRUE;\r
-}\r
-\r
-BOOL LogTraceInfo(byte_t* data, size_t len)\r
-{\r
- return LogTrace(data,len,0,GetParity(data,len),TRUE);\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-// The software UART that receives commands from the reader, and its state\r
-// variables.\r
-//-----------------------------------------------------------------------------\r
-static struct {\r
- enum {\r
- STATE_UNSYNCD,\r
- STATE_START_OF_COMMUNICATION,\r
- STATE_MILLER_X,\r
- STATE_MILLER_Y,\r
- STATE_MILLER_Z,\r
- STATE_ERROR_WAIT\r
- } state;\r
- WORD shiftReg;\r
- int bitCnt;\r
- int byteCnt;\r
- int byteCntMax;\r
- int posCnt;\r
- int syncBit;\r
- int parityBits;\r
- int samples;\r
- int highCnt;\r
- int bitBuffer;\r
- enum {\r
- DROP_NONE,\r
- DROP_FIRST_HALF,\r
- DROP_SECOND_HALF\r
- } drop;\r
- BYTE *output;\r
-} Uart;\r
-\r
-static BOOL MillerDecoding(int bit)\r
-{\r
- int error = 0;\r
- int bitright;\r
-\r
- if(!Uart.bitBuffer) {\r
- Uart.bitBuffer = bit ^ 0xFF0;\r
- return FALSE;\r
- }\r
- else {\r
- Uart.bitBuffer <<= 4;\r
- Uart.bitBuffer ^= bit;\r
- }\r
-\r
- BOOL EOC = FALSE;\r
-\r
- if(Uart.state != STATE_UNSYNCD) {\r
- Uart.posCnt++;\r
-\r
- if((Uart.bitBuffer & Uart.syncBit) ^ Uart.syncBit) {\r
- bit = 0x00;\r
- }\r
- else {\r
- bit = 0x01;\r
- }\r
- if(((Uart.bitBuffer << 1) & Uart.syncBit) ^ Uart.syncBit) {\r
- bitright = 0x00;\r
- }\r
- else {\r
- bitright = 0x01;\r
- }\r
- if(bit != bitright) { bit = bitright; }\r
-\r
- if(Uart.posCnt == 1) {\r
- // measurement first half bitperiod\r
- if(!bit) {\r
- Uart.drop = DROP_FIRST_HALF;\r
- }\r
- }\r
- else {\r
- // measurement second half bitperiod\r
- if(!bit & (Uart.drop == DROP_NONE)) {\r
- Uart.drop = DROP_SECOND_HALF;\r
- }\r
- else if(!bit) {\r
- // measured a drop in first and second half\r
- // which should not be possible\r
- Uart.state = STATE_ERROR_WAIT;\r
- error = 0x01;\r
- }\r
-\r
- Uart.posCnt = 0;\r
-\r
- switch(Uart.state) {\r
- case STATE_START_OF_COMMUNICATION:\r
- Uart.shiftReg = 0;\r
- if(Uart.drop == DROP_SECOND_HALF) {\r
- // error, should not happen in SOC\r
- Uart.state = STATE_ERROR_WAIT;\r
- error = 0x02;\r
- }\r
- else {\r
- // correct SOC\r
- Uart.state = STATE_MILLER_Z;\r
- }\r
- break;\r
-\r
- case STATE_MILLER_Z:\r
- Uart.bitCnt++;\r
- Uart.shiftReg >>= 1;\r
- if(Uart.drop == DROP_NONE) {\r
- // logic '0' followed by sequence Y\r
- // end of communication\r
- Uart.state = STATE_UNSYNCD;\r
- EOC = TRUE;\r
- }\r
- // if(Uart.drop == DROP_FIRST_HALF) {\r
- // Uart.state = STATE_MILLER_Z; stay the same\r
- // we see a logic '0' }\r
- if(Uart.drop == DROP_SECOND_HALF) {\r
- // we see a logic '1'\r
- Uart.shiftReg |= 0x100;\r
- Uart.state = STATE_MILLER_X;\r
- }\r
- break;\r
-\r
- case STATE_MILLER_X:\r
- Uart.shiftReg >>= 1;\r
- if(Uart.drop == DROP_NONE) {\r
- // sequence Y, we see a '0'\r
- Uart.state = STATE_MILLER_Y;\r
- Uart.bitCnt++;\r
- }\r
- if(Uart.drop == DROP_FIRST_HALF) {\r
- // Would be STATE_MILLER_Z\r
- // but Z does not follow X, so error\r
- Uart.state = STATE_ERROR_WAIT;\r
- error = 0x03;\r
- }\r
- if(Uart.drop == DROP_SECOND_HALF) {\r
- // We see a '1' and stay in state X\r
- Uart.shiftReg |= 0x100;\r
- Uart.bitCnt++;\r
- }\r
- break;\r
-\r
- case STATE_MILLER_Y:\r
- Uart.bitCnt++;\r
- Uart.shiftReg >>= 1;\r
- if(Uart.drop == DROP_NONE) {\r
- // logic '0' followed by sequence Y\r
- // end of communication\r
- Uart.state = STATE_UNSYNCD;\r
- EOC = TRUE;\r
- }\r
- if(Uart.drop == DROP_FIRST_HALF) {\r
- // we see a '0'\r
- Uart.state = STATE_MILLER_Z;\r
- }\r
- if(Uart.drop == DROP_SECOND_HALF) {\r
- // We see a '1' and go to state X\r
- Uart.shiftReg |= 0x100;\r
- Uart.state = STATE_MILLER_X;\r
- }\r
- break;\r
-\r
- case STATE_ERROR_WAIT:\r
- // That went wrong. Now wait for at least two bit periods\r
- // and try to sync again\r
- if(Uart.drop == DROP_NONE) {\r
- Uart.highCnt = 6;\r
- Uart.state = STATE_UNSYNCD;\r
- }\r
- break;\r
-\r
- default:\r
- Uart.state = STATE_UNSYNCD;\r
- Uart.highCnt = 0;\r
- break;\r
- }\r
-\r
- Uart.drop = DROP_NONE;\r
-\r
- // should have received at least one whole byte...\r
- if((Uart.bitCnt == 2) && EOC && (Uart.byteCnt > 0)) {\r
- return TRUE;\r
- }\r
-\r
- if(Uart.bitCnt == 9) {\r
- Uart.output[Uart.byteCnt] = (Uart.shiftReg & 0xff);\r
- Uart.byteCnt++;\r
-\r
- Uart.parityBits <<= 1;\r
- Uart.parityBits ^= ((Uart.shiftReg >> 8) & 0x01);\r
-\r
- if(EOC) {\r
- // when End of Communication received and\r
- // all data bits processed..\r
- return TRUE;\r
- }\r
- Uart.bitCnt = 0;\r
- }\r
-\r
- /*if(error) {\r
- Uart.output[Uart.byteCnt] = 0xAA;\r
- Uart.byteCnt++;\r
- Uart.output[Uart.byteCnt] = error & 0xFF;\r
- Uart.byteCnt++;\r
- Uart.output[Uart.byteCnt] = 0xAA;\r
- Uart.byteCnt++;\r
- Uart.output[Uart.byteCnt] = (Uart.bitBuffer >> 8) & 0xFF;\r
- Uart.byteCnt++;\r
- Uart.output[Uart.byteCnt] = Uart.bitBuffer & 0xFF;\r
- Uart.byteCnt++;\r
- Uart.output[Uart.byteCnt] = (Uart.syncBit >> 3) & 0xFF;\r
- Uart.byteCnt++;\r
- Uart.output[Uart.byteCnt] = 0xAA;\r
- Uart.byteCnt++;\r
- return TRUE;\r
- }*/\r
- }\r
-\r
- }\r
- else {\r
- bit = Uart.bitBuffer & 0xf0;\r
- bit >>= 4;\r
- bit ^= 0x0F;\r
- if(bit) {\r
- // should have been high or at least (4 * 128) / fc\r
- // according to ISO this should be at least (9 * 128 + 20) / fc\r
- if(Uart.highCnt == 8) {\r
- // we went low, so this could be start of communication\r
- // it turns out to be safer to choose a less significant\r
- // syncbit... so we check whether the neighbour also represents the drop\r
- Uart.posCnt = 1; // apparently we are busy with our first half bit period\r
- Uart.syncBit = bit & 8;\r
- Uart.samples = 3;\r
- if(!Uart.syncBit) { Uart.syncBit = bit & 4; Uart.samples = 2; }\r
- else if(bit & 4) { Uart.syncBit = bit & 4; Uart.samples = 2; bit <<= 2; }\r
- if(!Uart.syncBit) { Uart.syncBit = bit & 2; Uart.samples = 1; }\r
- else if(bit & 2) { Uart.syncBit = bit & 2; Uart.samples = 1; bit <<= 1; }\r
- if(!Uart.syncBit) { Uart.syncBit = bit & 1; Uart.samples = 0;\r
- if(Uart.syncBit & (Uart.bitBuffer & 8)) {\r
- Uart.syncBit = 8;\r
-\r
- // the first half bit period is expected in next sample\r
- Uart.posCnt = 0;\r
- Uart.samples = 3;\r
- }\r
- }\r
- else if(bit & 1) { Uart.syncBit = bit & 1; Uart.samples = 0; }\r
-\r
- Uart.syncBit <<= 4;\r
- Uart.state = STATE_START_OF_COMMUNICATION;\r
- Uart.drop = DROP_FIRST_HALF;\r
- Uart.bitCnt = 0;\r
- Uart.byteCnt = 0;\r
- Uart.parityBits = 0;\r
- error = 0;\r
- }\r
- else {\r
- Uart.highCnt = 0;\r
- }\r
- }\r
- else {\r
- if(Uart.highCnt < 8) {\r
- Uart.highCnt++;\r
- }\r
- }\r
- }\r
-\r
- return FALSE;\r
-}\r
-\r
-//=============================================================================\r
-// ISO 14443 Type A - Manchester\r
-//=============================================================================\r
-\r
-static struct {\r
- enum {\r
- DEMOD_UNSYNCD,\r
- DEMOD_START_OF_COMMUNICATION,\r
- DEMOD_MANCHESTER_D,\r
- DEMOD_MANCHESTER_E,\r
- DEMOD_MANCHESTER_F,\r
- DEMOD_ERROR_WAIT\r
- } state;\r
- int bitCount;\r
- int posCount;\r
- int syncBit;\r
- int parityBits;\r
- WORD shiftReg;\r
- int buffer;\r
- int buff;\r
- int samples;\r
- int len;\r
- enum {\r
- SUB_NONE,\r
- SUB_FIRST_HALF,\r
- SUB_SECOND_HALF\r
- } sub;\r
- BYTE *output;\r
-} Demod;\r
-\r
-static BOOL ManchesterDecoding(int v)\r
-{\r
- int bit;\r
- int modulation;\r
- int error = 0;\r
-\r
- if(!Demod.buff) {\r
- Demod.buff = 1;\r
- Demod.buffer = v;\r
- return FALSE;\r
- }\r
- else {\r
- bit = Demod.buffer;\r
- Demod.buffer = v;\r
- }\r
-\r
- if(Demod.state==DEMOD_UNSYNCD) {\r
- Demod.output[Demod.len] = 0xfa;\r
- Demod.syncBit = 0;\r
- //Demod.samples = 0;\r
- Demod.posCount = 1; // This is the first half bit period, so after syncing handle the second part\r
- if(bit & 0x08) { Demod.syncBit = 0x08; }\r
- if(!Demod.syncBit) {\r
- if(bit & 0x04) { Demod.syncBit = 0x04; }\r
- }\r
- else if(bit & 0x04) { Demod.syncBit = 0x04; bit <<= 4; }\r
- if(!Demod.syncBit) {\r
- if(bit & 0x02) { Demod.syncBit = 0x02; }\r
- }\r
- else if(bit & 0x02) { Demod.syncBit = 0x02; bit <<= 4; }\r
- if(!Demod.syncBit) {\r
- if(bit & 0x01) { Demod.syncBit = 0x01; }\r
-\r
- if(Demod.syncBit & (Demod.buffer & 0x08)) {\r
- Demod.syncBit = 0x08;\r
-\r
- // The first half bitperiod is expected in next sample\r
- Demod.posCount = 0;\r
- Demod.output[Demod.len] = 0xfb;\r
- }\r
- }\r
- else if(bit & 0x01) { Demod.syncBit = 0x01; }\r
-\r
- if(Demod.syncBit) {\r
- Demod.len = 0;\r
- Demod.state = DEMOD_START_OF_COMMUNICATION;\r
- Demod.sub = SUB_FIRST_HALF;\r
- Demod.bitCount = 0;\r
- Demod.shiftReg = 0;\r
- Demod.parityBits = 0;\r
- Demod.samples = 0;\r
- if(Demod.posCount) {\r
- switch(Demod.syncBit) {\r
- case 0x08: Demod.samples = 3; break;\r
- case 0x04: Demod.samples = 2; break;\r
- case 0x02: Demod.samples = 1; break;\r
- case 0x01: Demod.samples = 0; break;\r
- }\r
- }\r
- error = 0;\r
- }\r
- }\r
- else {\r
- //modulation = bit & Demod.syncBit;\r
- modulation = ((bit << 1) ^ ((Demod.buffer & 0x08) >> 3)) & Demod.syncBit;\r
-\r
- Demod.samples += 4;\r
-\r
- if(Demod.posCount==0) {\r
- Demod.posCount = 1;\r
- if(modulation) {\r
- Demod.sub = SUB_FIRST_HALF;\r
- }\r
- else {\r
- Demod.sub = SUB_NONE;\r
- }\r
- }\r
- else {\r
- Demod.posCount = 0;\r
- if(modulation && (Demod.sub == SUB_FIRST_HALF)) {\r
- if(Demod.state!=DEMOD_ERROR_WAIT) {\r
- Demod.state = DEMOD_ERROR_WAIT;\r
- Demod.output[Demod.len] = 0xaa;\r
- error = 0x01;\r
- }\r
- }\r
- else if(modulation) {\r
- Demod.sub = SUB_SECOND_HALF;\r
- }\r
-\r
- switch(Demod.state) {\r
- case DEMOD_START_OF_COMMUNICATION:\r
- if(Demod.sub == SUB_FIRST_HALF) {\r
- Demod.state = DEMOD_MANCHESTER_D;\r
- }\r
- else {\r
- Demod.output[Demod.len] = 0xab;\r
- Demod.state = DEMOD_ERROR_WAIT;\r
- error = 0x02;\r
- }\r
- break;\r
-\r
- case DEMOD_MANCHESTER_D:\r
- case DEMOD_MANCHESTER_E:\r
- if(Demod.sub == SUB_FIRST_HALF) {\r
- Demod.bitCount++;\r
- Demod.shiftReg = (Demod.shiftReg >> 1) ^ 0x100;\r
- Demod.state = DEMOD_MANCHESTER_D;\r
- }\r
- else if(Demod.sub == SUB_SECOND_HALF) {\r
- Demod.bitCount++;\r
- Demod.shiftReg >>= 1;\r
- Demod.state = DEMOD_MANCHESTER_E;\r
- }\r
- else {\r
- Demod.state = DEMOD_MANCHESTER_F;\r
- }\r
- break;\r
-\r
- case DEMOD_MANCHESTER_F:\r
- // Tag response does not need to be a complete byte!\r
- if(Demod.len > 0 || Demod.bitCount > 0) {\r
- if(Demod.bitCount > 0) {\r
- Demod.shiftReg >>= (9 - Demod.bitCount);\r
- Demod.output[Demod.len] = Demod.shiftReg & 0xff;\r
- Demod.len++;\r
- // No parity bit, so just shift a 0\r
- Demod.parityBits <<= 1;\r
- }\r
-\r
- Demod.state = DEMOD_UNSYNCD;\r
- return TRUE;\r
- }\r
- else {\r
- Demod.output[Demod.len] = 0xad;\r
- Demod.state = DEMOD_ERROR_WAIT;\r
- error = 0x03;\r
- }\r
- break;\r
-\r
- case DEMOD_ERROR_WAIT:\r
- Demod.state = DEMOD_UNSYNCD;\r
- break;\r
-\r
- default:\r
- Demod.output[Demod.len] = 0xdd;\r
- Demod.state = DEMOD_UNSYNCD;\r
- break;\r
- }\r
-\r
- if(Demod.bitCount>=9) {\r
- Demod.output[Demod.len] = Demod.shiftReg & 0xff;\r
- Demod.len++;\r
-\r
- Demod.parityBits <<= 1;\r
- Demod.parityBits ^= ((Demod.shiftReg >> 8) & 0x01);\r
-\r
- Demod.bitCount = 0;\r
- Demod.shiftReg = 0;\r
- }\r
-\r
- /*if(error) {\r
- Demod.output[Demod.len] = 0xBB;\r
- Demod.len++;\r
- Demod.output[Demod.len] = error & 0xFF;\r
- Demod.len++;\r
- Demod.output[Demod.len] = 0xBB;\r
- Demod.len++;\r
- Demod.output[Demod.len] = bit & 0xFF;\r
- Demod.len++;\r
- Demod.output[Demod.len] = Demod.buffer & 0xFF;\r
- Demod.len++;\r
- Demod.output[Demod.len] = Demod.syncBit & 0xFF;\r
- Demod.len++;\r
- Demod.output[Demod.len] = 0xBB;\r
- Demod.len++;\r
- return TRUE;\r
- }*/\r
-\r
- }\r
-\r
- } // end (state != UNSYNCED)\r
-\r
- return FALSE;\r
-}\r
-\r
-//=============================================================================\r
-// Finally, a `sniffer' for ISO 14443 Type A\r
-// Both sides of communication!\r
-//=============================================================================\r
-\r
-//-----------------------------------------------------------------------------\r
-// Record the sequence of commands sent by the reader to the tag, with\r
-// triggering so that we start recording at the point that the tag is moved\r
-// near the reader.\r
-//-----------------------------------------------------------------------------\r
-void SnoopIso14443a(void)\r
-{\r
-// #define RECV_CMD_OFFSET 2032 // original (working as of 21/2/09) values\r
-// #define RECV_RES_OFFSET 2096 // original (working as of 21/2/09) values\r
-// #define DMA_BUFFER_OFFSET 2160 // original (working as of 21/2/09) values\r
-// #define DMA_BUFFER_SIZE 4096 // original (working as of 21/2/09) values\r
-// #define TRACE_LENGTH 2000 // original (working as of 21/2/09) values\r
-\r
- // We won't start recording the frames that we acquire until we trigger;\r
- // a good trigger condition to get started is probably when we see a\r
- // response from the tag.\r
- BOOL triggered = TRUE; // FALSE to wait first for card\r
-\r
- // The command (reader -> tag) that we're receiving.\r
- // The length of a received command will in most cases be no more than 18 bytes.\r
- // So 32 should be enough!\r
- BYTE *receivedCmd = (((BYTE *)BigBuf) + RECV_CMD_OFFSET);\r
- // The response (tag -> reader) that we're receiving.\r
- BYTE *receivedResponse = (((BYTE *)BigBuf) + RECV_RES_OFFSET);\r
-\r
- // As we receive stuff, we copy it from receivedCmd or receivedResponse\r
- // into trace, along with its length and other annotations.\r
- //BYTE *trace = (BYTE *)BigBuf;\r
- //int traceLen = 0;\r
-\r
- // The DMA buffer, used to stream samples from the FPGA\r
- SBYTE *dmaBuf = ((SBYTE *)BigBuf) + DMA_BUFFER_OFFSET;\r
- int lastRxCounter;\r
- SBYTE *upTo;\r
- int smpl;\r
- int maxBehindBy = 0;\r
-\r
- // Count of samples received so far, so that we can include timing\r
- // information in the trace buffer.\r
- int samples = 0;\r
- int rsamples = 0;\r
-\r
- memset(trace, 0x44, RECV_CMD_OFFSET);\r
-\r
- // Set up the demodulator for tag -> reader responses.\r
- Demod.output = receivedResponse;\r
- Demod.len = 0;\r
- Demod.state = DEMOD_UNSYNCD;\r
-\r
- // And the reader -> tag commands\r
- memset(&Uart, 0, sizeof(Uart));\r
- Uart.output = receivedCmd;\r
- Uart.byteCntMax = 32; // was 100 (greg)////////////////////////////////////////////////////////////////////////\r
- Uart.state = STATE_UNSYNCD;\r
-\r
- // And put the FPGA in the appropriate mode\r
- // Signal field is off with the appropriate LED\r
- LED_D_OFF();\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_SNIFFER);\r
- SetAdcMuxFor(GPIO_MUXSEL_HIPKD);\r
-\r
- // Setup for the DMA.\r
- FpgaSetupSsc();\r
- upTo = dmaBuf;\r
- lastRxCounter = DMA_BUFFER_SIZE;\r
- FpgaSetupSscDma((BYTE *)dmaBuf, DMA_BUFFER_SIZE);\r
-\r
- LED_A_ON();\r
-\r
- // And now we loop, receiving samples.\r
- for(;;) {\r
- WDT_HIT();\r
- int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) &\r
- (DMA_BUFFER_SIZE-1);\r
- if(behindBy > maxBehindBy) {\r
- maxBehindBy = behindBy;\r
- if(behindBy > 400) {\r
- DbpString("blew circular buffer!");\r
- goto done;\r
- }\r
- }\r
- if(behindBy < 1) continue;\r
-\r
- smpl = upTo[0];\r
- upTo++;\r
- lastRxCounter -= 1;\r
- if(upTo - dmaBuf > DMA_BUFFER_SIZE) {\r
- upTo -= DMA_BUFFER_SIZE;\r
- lastRxCounter += DMA_BUFFER_SIZE;\r
- AT91C_BASE_PDC_SSC->PDC_RNPR = (DWORD)upTo;\r
- AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE;\r
- }\r
-\r
- samples += 4;\r
-#define HANDLE_BIT_IF_BODY \\r
- LED_C_ON(); \\r
- if(triggered) { \\r
- trace[traceLen++] = ((rsamples >> 0) & 0xff); \\r
- trace[traceLen++] = ((rsamples >> 8) & 0xff); \\r
- trace[traceLen++] = ((rsamples >> 16) & 0xff); \\r
- trace[traceLen++] = ((rsamples >> 24) & 0xff); \\r
- trace[traceLen++] = ((Uart.parityBits >> 0) & 0xff); \\r
- trace[traceLen++] = ((Uart.parityBits >> 8) & 0xff); \\r
- trace[traceLen++] = ((Uart.parityBits >> 16) & 0xff); \\r
- trace[traceLen++] = ((Uart.parityBits >> 24) & 0xff); \\r
- trace[traceLen++] = Uart.byteCnt; \\r
- memcpy(trace+traceLen, receivedCmd, Uart.byteCnt); \\r
- traceLen += Uart.byteCnt; \\r
- if(traceLen > TRACE_LENGTH) break; \\r
- } \\r
- /* And ready to receive another command. */ \\r
- Uart.state = STATE_UNSYNCD; \\r
- /* And also reset the demod code, which might have been */ \\r
- /* false-triggered by the commands from the reader. */ \\r
- Demod.state = DEMOD_UNSYNCD; \\r
- LED_B_OFF(); \\r
-\r
- if(MillerDecoding((smpl & 0xF0) >> 4)) {\r
- rsamples = samples - Uart.samples;\r
- HANDLE_BIT_IF_BODY\r
- }\r
- if(ManchesterDecoding(smpl & 0x0F)) {\r
- rsamples = samples - Demod.samples;\r
- LED_B_ON();\r
-\r
- // timestamp, as a count of samples\r
- trace[traceLen++] = ((rsamples >> 0) & 0xff);\r
- trace[traceLen++] = ((rsamples >> 8) & 0xff);\r
- trace[traceLen++] = ((rsamples >> 16) & 0xff);\r
- trace[traceLen++] = 0x80 | ((rsamples >> 24) & 0xff);\r
- trace[traceLen++] = ((Demod.parityBits >> 0) & 0xff);\r
- trace[traceLen++] = ((Demod.parityBits >> 8) & 0xff);\r
- trace[traceLen++] = ((Demod.parityBits >> 16) & 0xff);\r
- trace[traceLen++] = ((Demod.parityBits >> 24) & 0xff);\r
- // length\r
- trace[traceLen++] = Demod.len;\r
- memcpy(trace+traceLen, receivedResponse, Demod.len);\r
- traceLen += Demod.len;\r
- if(traceLen > TRACE_LENGTH) break;\r
-\r
- triggered = TRUE;\r
-\r
- // And ready to receive another response.\r
- memset(&Demod, 0, sizeof(Demod));\r
- Demod.output = receivedResponse;\r
- Demod.state = DEMOD_UNSYNCD;\r
- LED_C_OFF();\r
- }\r
-\r
- if(BUTTON_PRESS()) {\r
- DbpString("cancelled_a");\r
- goto done;\r
- }\r
- }\r
-\r
- DbpString("COMMAND FINISHED");\r
-\r
- Dbprintf("%x %x %x", maxBehindBy, Uart.state, Uart.byteCnt);\r
- Dbprintf("%x %x %x", Uart.byteCntMax, traceLen, (int)Uart.output[0]);\r
-\r
-done:\r
- AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS;\r
- Dbprintf("%x %x %x", maxBehindBy, Uart.state, Uart.byteCnt);\r
- Dbprintf("%x %x %x", Uart.byteCntMax, traceLen, (int)Uart.output[0]);\r
- LED_A_OFF();\r
- LED_B_OFF();\r
- LED_C_OFF();\r
- LED_D_OFF();\r
-}\r
-\r
-// Prepare communication bits to send to FPGA\r
-void Sequence(SecType seq)\r
-{\r
- ToSendMax++;\r
- switch(seq) {\r
- // CARD TO READER\r
- case SEC_D:\r
- // Sequence D: 11110000\r
- // modulation with subcarrier during first half\r
- ToSend[ToSendMax] = 0xf0;\r
- break;\r
- case SEC_E:\r
- // Sequence E: 00001111\r
- // modulation with subcarrier during second half\r
- ToSend[ToSendMax] = 0x0f;\r
- break;\r
- case SEC_F:\r
- // Sequence F: 00000000\r
- // no modulation with subcarrier\r
- ToSend[ToSendMax] = 0x00;\r
- break;\r
- // READER TO CARD\r
- case SEC_X:\r
- // Sequence X: 00001100\r
- // drop after half a period\r
- ToSend[ToSendMax] = 0x0c;\r
- break;\r
- case SEC_Y:\r
- default:\r
- // Sequence Y: 00000000\r
- // no drop\r
- ToSend[ToSendMax] = 0x00;\r
- break;\r
- case SEC_Z:\r
- // Sequence Z: 11000000\r
- // drop at start\r
- ToSend[ToSendMax] = 0xc0;\r
- break;\r
- }\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-// Prepare tag messages\r
-//-----------------------------------------------------------------------------\r
-static void CodeIso14443aAsTag(const BYTE *cmd, int len)\r
-{\r
- int i;\r
- int oddparity;\r
-\r
- ToSendReset();\r
-\r
- // Correction bit, might be removed when not needed\r
- ToSendStuffBit(0);\r
- ToSendStuffBit(0);\r
- ToSendStuffBit(0);\r
- ToSendStuffBit(0);\r
- ToSendStuffBit(1); // 1\r
- ToSendStuffBit(0);\r
- ToSendStuffBit(0);\r
- ToSendStuffBit(0);\r
-\r
- // Send startbit\r
- Sequence(SEC_D);\r
-\r
- for(i = 0; i < len; i++) {\r
- int j;\r
- BYTE b = cmd[i];\r
-\r
- // Data bits\r
- oddparity = 0x01;\r
- for(j = 0; j < 8; j++) {\r
- oddparity ^= (b & 1);\r
- if(b & 1) {\r
- Sequence(SEC_D);\r
- } else {\r
- Sequence(SEC_E);\r
- }\r
- b >>= 1;\r
- }\r
-\r
- // Parity bit\r
- if(oddparity) {\r
- Sequence(SEC_D);\r
- } else {\r
- Sequence(SEC_E);\r
- }\r
- }\r
-\r
- // Send stopbit\r
- Sequence(SEC_F);\r
-\r
- // Flush the buffer in FPGA!!\r
- for(i = 0; i < 5; i++) {\r
- Sequence(SEC_F);\r
- }\r
-\r
- // Convert from last byte pos to length\r
- ToSendMax++;\r
-\r
- // Add a few more for slop\r
- ToSend[ToSendMax++] = 0x00;\r
- ToSend[ToSendMax++] = 0x00;\r
- //ToSendMax += 2;\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-// This is to send a NACK kind of answer, its only 3 bits, I know it should be 4\r
-//-----------------------------------------------------------------------------\r
-static void CodeStrangeAnswer()\r
-{\r
- int i;\r
-\r
- ToSendReset();\r
-\r
- // Correction bit, might be removed when not needed\r
- ToSendStuffBit(0);\r
- ToSendStuffBit(0);\r
- ToSendStuffBit(0);\r
- ToSendStuffBit(0);\r
- ToSendStuffBit(1); // 1\r
- ToSendStuffBit(0);\r
- ToSendStuffBit(0);\r
- ToSendStuffBit(0);\r
-\r
- // Send startbit\r
- Sequence(SEC_D);\r
-\r
- // 0\r
- Sequence(SEC_E);\r
-\r
- // 0\r
- Sequence(SEC_E);\r
-\r
- // 1\r
- Sequence(SEC_D);\r
-\r
- // Send stopbit\r
- Sequence(SEC_F);\r
-\r
- // Flush the buffer in FPGA!!\r
- for(i = 0; i < 5; i++) {\r
- Sequence(SEC_F);\r
- }\r
-\r
- // Convert from last byte pos to length\r
- ToSendMax++;\r
-\r
- // Add a few more for slop\r
- ToSend[ToSendMax++] = 0x00;\r
- ToSend[ToSendMax++] = 0x00;\r
- //ToSendMax += 2;\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-// Wait for commands from reader\r
-// Stop when button is pressed\r
-// Or return TRUE when command is captured\r
-//-----------------------------------------------------------------------------\r
-static BOOL GetIso14443aCommandFromReader(BYTE *received, int *len, int maxLen)\r
-{\r
- // Set FPGA mode to "simulated ISO 14443 tag", no modulation (listen\r
- // only, since we are receiving, not transmitting).\r
- // Signal field is off with the appropriate LED\r
- LED_D_OFF();\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN);\r
-\r
- // Now run a `software UART' on the stream of incoming samples.\r
- Uart.output = received;\r
- Uart.byteCntMax = maxLen;\r
- Uart.state = STATE_UNSYNCD;\r
-\r
- for(;;) {\r
- WDT_HIT();\r
-\r
- if(BUTTON_PRESS()) return FALSE;\r
-\r
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {\r
- AT91C_BASE_SSC->SSC_THR = 0x00;\r
- }\r
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {\r
- BYTE b = (BYTE)AT91C_BASE_SSC->SSC_RHR;\r
- if(MillerDecoding((b & 0xf0) >> 4)) {\r
- *len = Uart.byteCnt;\r
- return TRUE;\r
- }\r
- if(MillerDecoding(b & 0x0f)) {\r
- *len = Uart.byteCnt;\r
- return TRUE;\r
- }\r
- }\r
- }\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-// Main loop of simulated tag: receive commands from reader, decide what\r
-// response to send, and send it.\r
-//-----------------------------------------------------------------------------\r
-void SimulateIso14443aTag(int tagType, int TagUid)\r
-{\r
- // This function contains the tag emulation\r
-\r
- // Prepare protocol messages\r
- // static const BYTE cmd1[] = { 0x26 };\r
-// static const BYTE response1[] = { 0x02, 0x00 }; // Says: I am Mifare 4k - original line - greg\r
-//\r
- static const BYTE response1[] = { 0x44, 0x03 }; // Says: I am a DESFire Tag, ph33r me\r
-// static const BYTE response1[] = { 0x44, 0x00 }; // Says: I am a ULTRALITE Tag, 0wn me\r
-\r
- // UID response\r
- // static const BYTE cmd2[] = { 0x93, 0x20 };\r
- //static const BYTE response2[] = { 0x9a, 0xe5, 0xe4, 0x43, 0xd8 }; // original value - greg\r
-\r
-\r
-\r
-// my desfire\r
- static const BYTE response2[] = { 0x88, 0x04, 0x21, 0x3f, 0x4d }; // known uid - note cascade (0x88), 2nd byte (0x04) = NXP/Phillips\r
-\r
-\r
-// When reader selects us during cascade1 it will send cmd3\r
-//BYTE response3[] = { 0x04, 0x00, 0x00 }; // SAK Select (cascade1) successful response (ULTRALITE)\r
-BYTE response3[] = { 0x24, 0x00, 0x00 }; // SAK Select (cascade1) successful response (DESFire)\r
-ComputeCrc14443(CRC_14443_A, response3, 1, &response3[1], &response3[2]);\r
-\r
-// send cascade2 2nd half of UID\r
-static const BYTE response2a[] = { 0x51, 0x48, 0x1d, 0x80, 0x84 }; // uid - cascade2 - 2nd half (4 bytes) of UID+ BCCheck\r
-// NOTE : THE CRC on the above may be wrong as I have obfuscated the actual UID\r
-\r
-\r
-// When reader selects us during cascade2 it will send cmd3a\r
-//BYTE response3a[] = { 0x00, 0x00, 0x00 }; // SAK Select (cascade2) successful response (ULTRALITE)\r
-BYTE response3a[] = { 0x20, 0x00, 0x00 }; // SAK Select (cascade2) successful response (DESFire)\r
-ComputeCrc14443(CRC_14443_A, response3a, 1, &response3a[1], &response3a[2]);\r
-\r
- static const BYTE response5[] = { 0x00, 0x00, 0x00, 0x00 }; // Very random tag nonce\r
-\r
- BYTE *resp;\r
- int respLen;\r
-\r
- // Longest possible response will be 16 bytes + 2 CRC = 18 bytes\r
- // This will need\r
- // 144 data bits (18 * 8)\r
- // 18 parity bits\r
- // 2 Start and stop\r
- // 1 Correction bit (Answer in 1172 or 1236 periods, see FPGA)\r
- // 1 just for the case\r
- // ----------- +\r
- // 166\r
- //\r
- // 166 bytes, since every bit that needs to be send costs us a byte\r
- //\r
-\r
-\r
- // Respond with card type\r
- BYTE *resp1 = (((BYTE *)BigBuf) + 800);\r
- int resp1Len;\r
-\r
- // Anticollision cascade1 - respond with uid\r
- BYTE *resp2 = (((BYTE *)BigBuf) + 970);\r
- int resp2Len;\r
-\r
- // Anticollision cascade2 - respond with 2nd half of uid if asked\r
- // we're only going to be asked if we set the 1st byte of the UID (during cascade1) to 0x88\r
- BYTE *resp2a = (((BYTE *)BigBuf) + 1140);\r
- int resp2aLen;\r
-\r
- // Acknowledge select - cascade 1\r
- BYTE *resp3 = (((BYTE *)BigBuf) + 1310);\r
- int resp3Len;\r
-\r
- // Acknowledge select - cascade 2\r
- BYTE *resp3a = (((BYTE *)BigBuf) + 1480);\r
- int resp3aLen;\r
-\r
- // Response to a read request - not implemented atm\r
- BYTE *resp4 = (((BYTE *)BigBuf) + 1550);\r
- int resp4Len;\r
-\r
- // Authenticate response - nonce\r
- BYTE *resp5 = (((BYTE *)BigBuf) + 1720);\r
- int resp5Len;\r
-\r
- BYTE *receivedCmd = (BYTE *)BigBuf;\r
- int len;\r
-\r
- int i;\r
- int u;\r
- BYTE b;\r
-\r
- // To control where we are in the protocol\r
- int order = 0;\r
- int lastorder;\r
-\r
- // Just to allow some checks\r
- int happened = 0;\r
- int happened2 = 0;\r
-\r
- int cmdsRecvd = 0;\r
-\r
- BOOL fdt_indicator;\r
-\r
- memset(receivedCmd, 0x44, 400);\r
-\r
- // Prepare the responses of the anticollision phase\r
- // there will be not enough time to do this at the moment the reader sends it REQA\r
-\r
- // Answer to request\r
- CodeIso14443aAsTag(response1, sizeof(response1));\r
- memcpy(resp1, ToSend, ToSendMax); resp1Len = ToSendMax;\r
-\r
- // Send our UID (cascade 1)\r
- CodeIso14443aAsTag(response2, sizeof(response2));\r
- memcpy(resp2, ToSend, ToSendMax); resp2Len = ToSendMax;\r
-\r
- // Answer to select (cascade1)\r
- CodeIso14443aAsTag(response3, sizeof(response3));\r
- memcpy(resp3, ToSend, ToSendMax); resp3Len = ToSendMax;\r
-\r
- // Send the cascade 2 2nd part of the uid\r
- CodeIso14443aAsTag(response2a, sizeof(response2a));\r
- memcpy(resp2a, ToSend, ToSendMax); resp2aLen = ToSendMax;\r
-\r
- // Answer to select (cascade 2)\r
- CodeIso14443aAsTag(response3a, sizeof(response3a));\r
- memcpy(resp3a, ToSend, ToSendMax); resp3aLen = ToSendMax;\r
-\r
- // Strange answer is an example of rare message size (3 bits)\r
- CodeStrangeAnswer();\r
- memcpy(resp4, ToSend, ToSendMax); resp4Len = ToSendMax;\r
-\r
- // Authentication answer (random nonce)\r
- CodeIso14443aAsTag(response5, sizeof(response5));\r
- memcpy(resp5, ToSend, ToSendMax); resp5Len = ToSendMax;\r
-\r
- // We need to listen to the high-frequency, peak-detected path.\r
- SetAdcMuxFor(GPIO_MUXSEL_HIPKD);\r
- FpgaSetupSsc();\r
-\r
- cmdsRecvd = 0;\r
-\r
- LED_A_ON();\r
- for(;;) {\r
-\r
- if(!GetIso14443aCommandFromReader(receivedCmd, &len, 100)) {\r
- DbpString("button press");\r
- break;\r
- }\r
- // doob - added loads of debug strings so we can see what the reader is saying to us during the sim as hi14alist is not populated\r
- // Okay, look at the command now.\r
- lastorder = order;\r
- i = 1; // first byte transmitted\r
- if(receivedCmd[0] == 0x26) {\r
- // Received a REQUEST\r
- resp = resp1; respLen = resp1Len; order = 1;\r
- //DbpString("Hello request from reader:");\r
- } else if(receivedCmd[0] == 0x52) {\r
- // Received a WAKEUP\r
- resp = resp1; respLen = resp1Len; order = 6;\r
-// //DbpString("Wakeup request from reader:");\r
-\r
- } else if(receivedCmd[1] == 0x20 && receivedCmd[0] == 0x93) { // greg - cascade 1 anti-collision\r
- // Received request for UID (cascade 1)\r
- resp = resp2; respLen = resp2Len; order = 2;\r
-// DbpString("UID (cascade 1) request from reader:");\r
-// DbpIntegers(receivedCmd[0], receivedCmd[1], receivedCmd[2]);\r
-\r
-\r
- } else if(receivedCmd[1] == 0x20 && receivedCmd[0] ==0x95) { // greg - cascade 2 anti-collision\r
- // Received request for UID (cascade 2)\r
- resp = resp2a; respLen = resp2aLen; order = 20;\r
-// DbpString("UID (cascade 2) request from reader:");\r
-// DbpIntegers(receivedCmd[0], receivedCmd[1], receivedCmd[2]);\r
-\r
-\r
- } else if(receivedCmd[1] == 0x70 && receivedCmd[0] ==0x93) { // greg - cascade 1 select\r
- // Received a SELECT\r
- resp = resp3; respLen = resp3Len; order = 3;\r
-// DbpString("Select (cascade 1) request from reader:");\r
-// DbpIntegers(receivedCmd[0], receivedCmd[1], receivedCmd[2]);\r
-\r
-\r
- } else if(receivedCmd[1] == 0x70 && receivedCmd[0] ==0x95) { // greg - cascade 2 select\r
- // Received a SELECT\r
- resp = resp3a; respLen = resp3aLen; order = 30;\r
-// DbpString("Select (cascade 2) request from reader:");\r
-// DbpIntegers(receivedCmd[0], receivedCmd[1], receivedCmd[2]);\r
-\r
-\r
- } else if(receivedCmd[0] == 0x30) {\r
- // Received a READ\r
- resp = resp4; respLen = resp4Len; order = 4; // Do nothing\r
- Dbprintf("Read request from reader: %x %x %x",\r
- receivedCmd[0], receivedCmd[1], receivedCmd[2]);\r
-\r
-\r
- } else if(receivedCmd[0] == 0x50) {\r
- // Received a HALT\r
- resp = resp1; respLen = 0; order = 5; // Do nothing\r
- DbpString("Reader requested we HALT!:");\r
-\r
- } else if(receivedCmd[0] == 0x60) {\r
- // Received an authentication request\r
- resp = resp5; respLen = resp5Len; order = 7;\r
- Dbprintf("Authenticate request from reader: %x %x %x",\r
- receivedCmd[0], receivedCmd[1], receivedCmd[2]);\r
-\r
- } else if(receivedCmd[0] == 0xE0) {\r
- // Received a RATS request\r
- resp = resp1; respLen = 0;order = 70;\r
- Dbprintf("RATS request from reader: %x %x %x",\r
- receivedCmd[0], receivedCmd[1], receivedCmd[2]);\r
- } else {\r
- // Never seen this command before\r
- Dbprintf("Unknown command received from reader: %x %x %x %x %x %x %x %x %x",\r
- receivedCmd[0], receivedCmd[1], receivedCmd[2],\r
- receivedCmd[3], receivedCmd[3], receivedCmd[4],\r
- receivedCmd[5], receivedCmd[6], receivedCmd[7]);\r
- // Do not respond\r
- resp = resp1; respLen = 0; order = 0;\r
- }\r
-\r
- // Count number of wakeups received after a halt\r
- if(order == 6 && lastorder == 5) { happened++; }\r
-\r
- // Count number of other messages after a halt\r
- if(order != 6 && lastorder == 5) { happened2++; }\r
-\r
- // Look at last parity bit to determine timing of answer\r
- if((Uart.parityBits & 0x01) || receivedCmd[0] == 0x52) {\r
- // 1236, so correction bit needed\r
- i = 0;\r
- }\r
-\r
- memset(receivedCmd, 0x44, 32);\r
-\r
- if(cmdsRecvd > 999) {\r
- DbpString("1000 commands later...");\r
- break;\r
- }\r
- else {\r
- cmdsRecvd++;\r
- }\r
-\r
- if(respLen <= 0) continue;\r
-\r
- // Modulate Manchester\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_MOD);\r
- AT91C_BASE_SSC->SSC_THR = 0x00;\r
- FpgaSetupSsc();\r
-\r
- // ### Transmit the response ###\r
- u = 0;\r
- b = 0x00;\r
- fdt_indicator = FALSE;\r
- for(;;) {\r
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {\r
- volatile BYTE b = (BYTE)AT91C_BASE_SSC->SSC_RHR;\r
- (void)b;\r
- }\r
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {\r
- if(i > respLen) {\r
- b = 0x00;\r
- u++;\r
- } else {\r
- b = resp[i];\r
- i++;\r
- }\r
- AT91C_BASE_SSC->SSC_THR = b;\r
-\r
- if(u > 4) {\r
- break;\r
- }\r
- }\r
- if(BUTTON_PRESS()) {\r
- break;\r
- }\r
- }\r
-\r
- }\r
-\r
- Dbprintf("%x %x %x", happened, happened2, cmdsRecvd);\r
- LED_A_OFF();\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-// Transmit the command (to the tag) that was placed in ToSend[].\r
-//-----------------------------------------------------------------------------\r
-static void TransmitFor14443a(const BYTE *cmd, int len, int *samples, int *wait)\r
-{\r
- int c;\r
- \r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);\r
- \r
- if (wait)\r
- if(*wait < 10)\r
- *wait = 10;\r
- \r
- for(c = 0; c < *wait;) {\r
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {\r
- AT91C_BASE_SSC->SSC_THR = 0x00; // For exact timing!\r
- c++;\r
- }\r
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {\r
- volatile DWORD r = AT91C_BASE_SSC->SSC_RHR;\r
- (void)r;\r
- }\r
- WDT_HIT();\r
- }\r
- \r
- c = 0;\r
- for(;;) {\r
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {\r
- AT91C_BASE_SSC->SSC_THR = cmd[c];\r
- c++;\r
- if(c >= len) {\r
- break;\r
- }\r
- }\r
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {\r
- volatile DWORD r = AT91C_BASE_SSC->SSC_RHR;\r
- (void)r;\r
- }\r
- WDT_HIT();\r
- }\r
- if (samples) *samples = (c + *wait) << 3;\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-// To generate an arbitrary stream from reader\r
-//\r
-//-----------------------------------------------------------------------------\r
-void ArbitraryFromReader(const BYTE *cmd, int parity, int len)\r
-{\r
- int i;\r
- int j;\r
- int last;\r
- BYTE b;\r
-\r
- ToSendReset();\r
-\r
- // Start of Communication (Seq. Z)\r
- Sequence(SEC_Z);\r
- last = 0;\r
-\r
- for(i = 0; i < len; i++) {\r
- // Data bits\r
- b = cmd[i];\r
- for(j = 0; j < 8; j++) {\r
- if(b & 1) {\r
- // Sequence X\r
- Sequence(SEC_X);\r
- last = 1;\r
- } else {\r
- if(last == 0) {\r
- // Sequence Z\r
- Sequence(SEC_Z);\r
- }\r
- else {\r
- // Sequence Y\r
- Sequence(SEC_Y);\r
- last = 0;\r
- }\r
- }\r
- b >>= 1;\r
-\r
- }\r
-\r
- // Predefined parity bit, the flipper flips when needed, because of flips in byte sent\r
- if(((parity >> (len - i - 1)) & 1)) {\r
- // Sequence X\r
- Sequence(SEC_X);\r
- last = 1;\r
- } else {\r
- if(last == 0) {\r
- // Sequence Z\r
- Sequence(SEC_Z);\r
- }\r
- else {\r
- // Sequence Y\r
- Sequence(SEC_Y);\r
- last = 0;\r
- }\r
- }\r
- }\r
-\r
- // End of Communication\r
- if(last == 0) {\r
- // Sequence Z\r
- Sequence(SEC_Z);\r
- }\r
- else {\r
- // Sequence Y\r
- Sequence(SEC_Y);\r
- last = 0;\r
- }\r
- // Sequence Y\r
- Sequence(SEC_Y);\r
-\r
- // Just to be sure!\r
- Sequence(SEC_Y);\r
- Sequence(SEC_Y);\r
- Sequence(SEC_Y);\r
-\r
- // Convert from last character reference to length\r
- ToSendMax++;\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-// Code a 7-bit command without parity bit\r
-// This is especially for 0x26 and 0x52 (REQA and WUPA)\r
-//-----------------------------------------------------------------------------\r
-void ShortFrameFromReader(const BYTE bt)\r
-{\r
- int j;\r
- int last;\r
- BYTE b;\r
-\r
- ToSendReset();\r
-\r
- // Start of Communication (Seq. Z)\r
- Sequence(SEC_Z);\r
- last = 0;\r
-\r
- b = bt;\r
- for(j = 0; j < 7; j++) {\r
- if(b & 1) {\r
- // Sequence X\r
- Sequence(SEC_X);\r
- last = 1;\r
- } else {\r
- if(last == 0) {\r
- // Sequence Z\r
- Sequence(SEC_Z);\r
- }\r
- else {\r
- // Sequence Y\r
- Sequence(SEC_Y);\r
- last = 0;\r
- }\r
- }\r
- b >>= 1;\r
- }\r
-\r
- // End of Communication\r
- if(last == 0) {\r
- // Sequence Z\r
- Sequence(SEC_Z);\r
- }\r
- else {\r
- // Sequence Y\r
- Sequence(SEC_Y);\r
- last = 0;\r
- }\r
- // Sequence Y\r
- Sequence(SEC_Y);\r
-\r
- // Just to be sure!\r
- Sequence(SEC_Y);\r
- Sequence(SEC_Y);\r
- Sequence(SEC_Y);\r
-\r
- // Convert from last character reference to length\r
- ToSendMax++;\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-// Prepare reader command to send to FPGA\r
-// \r
-//-----------------------------------------------------------------------------\r
-void CodeIso14443aAsReaderPar(const BYTE * cmd, int len, DWORD dwParity)\r
-{\r
- int i, j;\r
- int last;\r
- BYTE b;\r
- \r
- ToSendReset();\r
- \r
- // Start of Communication (Seq. Z)\r
- Sequence(SEC_Z);\r
- last = 0;\r
- \r
- // Generate send structure for the data bits\r
- for (i = 0; i < len; i++) {\r
- // Get the current byte to send\r
- b = cmd[i];\r
- \r
- for (j = 0; j < 8; j++) {\r
- if (b & 1) {\r
- // Sequence X\r
- Sequence(SEC_X);\r
- last = 1;\r
- } else {\r
- if (last == 0) {\r
- // Sequence Z\r
- Sequence(SEC_Z);\r
- } else {\r
- // Sequence Y\r
- Sequence(SEC_Y);\r
- last = 0;\r
- }\r
- }\r
- b >>= 1;\r
- }\r
- \r
- // Get the parity bit\r
- if ((dwParity >> i) & 0x01) {\r
- // Sequence X\r
- Sequence(SEC_X);\r
- last = 1;\r
- } else {\r
- if (last == 0) {\r
- // Sequence Z\r
- Sequence(SEC_Z);\r
- } else {\r
- // Sequence Y\r
- Sequence(SEC_Y);\r
- last = 0;\r
- }\r
- }\r
- }\r
- \r
- // End of Communication\r
- if (last == 0) {\r
- // Sequence Z\r
- Sequence(SEC_Z);\r
- } else {\r
- // Sequence Y\r
- Sequence(SEC_Y);\r
- last = 0;\r
- }\r
- // Sequence Y\r
- Sequence(SEC_Y);\r
- \r
- // Just to be sure!\r
- Sequence(SEC_Y);\r
- Sequence(SEC_Y);\r
- Sequence(SEC_Y);\r
- \r
- // Convert from last character reference to length\r
- ToSendMax++;\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-// Wait a certain time for tag response\r
-// If a response is captured return TRUE\r
-// If it takes to long return FALSE\r
-//-----------------------------------------------------------------------------\r
-static BOOL GetIso14443aAnswerFromTag(BYTE *receivedResponse, int maxLen, int *samples, int *elapsed) //BYTE *buffer\r
-{\r
- // buffer needs to be 512 bytes\r
- int c;\r
-\r
- // Set FPGA mode to "reader listen mode", no modulation (listen\r
- // only, since we are receiving, not transmitting).\r
- // Signal field is on with the appropriate LED\r
- LED_D_ON();\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_LISTEN);\r
-\r
- // Now get the answer from the card\r
- Demod.output = receivedResponse;\r
- Demod.len = 0;\r
- Demod.state = DEMOD_UNSYNCD;\r
-\r
- BYTE b;\r
- if (elapsed) *elapsed = 0;\r
-\r
- c = 0;\r
- for(;;) {\r
- WDT_HIT();\r
-\r
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {\r
- AT91C_BASE_SSC->SSC_THR = 0x00; // To make use of exact timing of next command from reader!!\r
- if (elapsed) (*elapsed)++;\r
- }\r
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {\r
- if(c < 512) { c++; } else { return FALSE; }\r
- b = (BYTE)AT91C_BASE_SSC->SSC_RHR;\r
- if(ManchesterDecoding((b & 0xf0) >> 4)) {\r
- *samples = ((c - 1) << 3) + 4;\r
- return TRUE;\r
- }\r
- if(ManchesterDecoding(b & 0x0f)) {\r
- *samples = c << 3;\r
- return TRUE;\r
- }\r
- }\r
- }\r
-}\r
-\r
-void ReaderTransmitShort(const BYTE* bt)\r
-{\r
- int wait = 0;\r
- int samples = 0;\r
-\r
- ShortFrameFromReader(*bt);\r
- \r
- // Select the card\r
- TransmitFor14443a(ToSend, ToSendMax, &samples, &wait); \r
- \r
- // Store reader command in buffer\r
- if (tracing) LogTrace(bt,1,0,GetParity(bt,1),TRUE);\r
-}\r
-\r
-void ReaderTransmitPar(BYTE* frame, int len, DWORD par)\r
-{\r
- int wait = 0;\r
- int samples = 0;\r
- \r
- // This is tied to other size changes\r
- // BYTE* frame_addr = ((BYTE*)BigBuf) + 2024; \r
- CodeIso14443aAsReaderPar(frame,len,par);\r
- \r
- // Select the card\r
- TransmitFor14443a(ToSend, ToSendMax, &samples, &wait); \r
- \r
- // Store reader command in buffer\r
- if (tracing) LogTrace(frame,len,0,par,TRUE);\r
-}\r
-\r
-\r
-void ReaderTransmit(BYTE* frame, int len)\r
-{\r
- // Generate parity and redirect\r
- ReaderTransmitPar(frame,len,GetParity(frame,len));\r
-}\r
-\r
-BOOL ReaderReceive(BYTE* receivedAnswer)\r
-{\r
- int samples = 0;\r
- if (!GetIso14443aAnswerFromTag(receivedAnswer,100,&samples,0)) return FALSE;\r
- if (tracing) LogTrace(receivedAnswer,Demod.len,samples,Demod.parityBits,FALSE);\r
- return TRUE;\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-// Read an ISO 14443a tag. Send out commands and store answers.\r
-//\r
-//-----------------------------------------------------------------------------\r
-void ReaderIso14443a(DWORD parameter)\r
-{\r
- // Anticollision\r
- BYTE wupa[] = { 0x52 };\r
- BYTE sel_all[] = { 0x93,0x20 };\r
- BYTE sel_uid[] = { 0x93,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };\r
- BYTE sel_all_c2[] = { 0x95,0x20 };\r
- BYTE sel_uid_c2[] = { 0x95,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };\r
-\r
- // Mifare AUTH\r
- BYTE mf_auth[] = { 0x60,0x00,0xf5,0x7b };\r
-// BYTE mf_nr_ar[] = { 0x00,0x00,0x00,0x00 };\r
- \r
- BYTE* receivedAnswer = (((BYTE *)BigBuf) + 3560); // was 3560 - tied to other size changes\r
- traceLen = 0;\r
-\r
- // Setup SSC\r
- FpgaSetupSsc();\r
-\r
- // Start from off (no field generated)\r
- // Signal field is off with the appropriate LED\r
- LED_D_OFF();\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
- SpinDelay(200);\r
-\r
- SetAdcMuxFor(GPIO_MUXSEL_HIPKD);\r
- FpgaSetupSsc();\r
-\r
- // Now give it time to spin up.\r
- // Signal field is on with the appropriate LED\r
- LED_D_ON();\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);\r
- SpinDelay(200);\r
-\r
- LED_A_ON();\r
- LED_B_OFF();\r
- LED_C_OFF();\r
-\r
- while(traceLen < TRACE_LENGTH)\r
- {\r
- // Broadcast for a card, WUPA (0x52) will force response from all cards in the field\r
- ReaderTransmitShort(wupa);\r
- \r
- // Test if the action was cancelled\r
- if(BUTTON_PRESS()) {\r
- break;\r
- }\r
- \r
- // Receive the ATQA\r
- if (!ReaderReceive(receivedAnswer)) continue;\r
-\r
- // Transmit SELECT_ALL\r
- ReaderTransmit(sel_all,sizeof(sel_all));\r
-\r
- // Receive the UID\r
- if (!ReaderReceive(receivedAnswer)) continue;\r
- \r
- // Construct SELECT UID command\r
- // First copy the 5 bytes (Mifare Classic) after the 93 70\r
- memcpy(sel_uid+2,receivedAnswer,5);\r
- // Secondly compute the two CRC bytes at the end\r
- AppendCrc14443a(sel_uid,7);\r
-\r
- // Transmit SELECT_UID\r
- ReaderTransmit(sel_uid,sizeof(sel_uid));\r
- \r
- // Receive the SAK\r
- if (!ReaderReceive(receivedAnswer)) continue;\r
-\r
- // OK we have selected at least at cascade 1, lets see if first byte of UID was 0x88 in\r
- // which case we need to make a cascade 2 request and select - this is a long UID\r
- // When the UID is not complete, the 3nd bit (from the right) is set in the SAK. \r
- if (receivedAnswer[0] &= 0x04)\r
- {\r
- // Transmit SELECT_ALL\r
- ReaderTransmit(sel_all_c2,sizeof(sel_all_c2));\r
- \r
- // Receive the UID\r
- if (!ReaderReceive(receivedAnswer)) continue;\r
- \r
- // Construct SELECT UID command\r
- memcpy(sel_uid_c2+2,receivedAnswer,5);\r
- // Secondly compute the two CRC bytes at the end\r
- AppendCrc14443a(sel_uid_c2,7);\r
- \r
- // Transmit SELECT_UID\r
- ReaderTransmit(sel_uid_c2,sizeof(sel_uid_c2));\r
- \r
- // Receive the SAK\r
- if (!ReaderReceive(receivedAnswer)) continue;\r
- }\r
-\r
- // Transmit MIFARE_CLASSIC_AUTH\r
- ReaderTransmit(mf_auth,sizeof(mf_auth));\r
-\r
- // Receive the (16 bit) "random" nonce\r
- if (!ReaderReceive(receivedAnswer)) continue;\r
- }\r
-\r
- // Thats it...\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
- LEDsoff();\r
- Dbprintf("%x %x %x", rsamples, 0xCC, 0xCC);\r
- DbpString("ready..");\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-// Read an ISO 14443a tag. Send out commands and store answers.\r
-//\r
-//-----------------------------------------------------------------------------\r
-void ReaderMifare(DWORD parameter)\r
-{\r
- \r
- // Anticollision\r
- BYTE wupa[] = { 0x52 };\r
- BYTE sel_all[] = { 0x93,0x20 };\r
- BYTE sel_uid[] = { 0x93,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };\r
- \r
- // Mifare AUTH\r
- BYTE mf_auth[] = { 0x60,0x00,0xf5,0x7b };\r
- BYTE mf_nr_ar[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };\r
- \r
- BYTE* receivedAnswer = (((BYTE *)BigBuf) + 3560); // was 3560 - tied to other size changes\r
- traceLen = 0;\r
- tracing = false;\r
- \r
- // Setup SSC\r
- FpgaSetupSsc();\r
- \r
- // Start from off (no field generated)\r
- // Signal field is off with the appropriate LED\r
- LED_D_OFF();\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
- SpinDelay(200);\r
- \r
- SetAdcMuxFor(GPIO_MUXSEL_HIPKD);\r
- FpgaSetupSsc();\r
- \r
- // Now give it time to spin up.\r
- // Signal field is on with the appropriate LED\r
- LED_D_ON();\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);\r
- SpinDelay(200);\r
- \r
- LED_A_ON();\r
- LED_B_OFF();\r
- LED_C_OFF();\r
- \r
- // Broadcast for a card, WUPA (0x52) will force response from all cards in the field\r
- ReaderTransmitShort(wupa);\r
- // Receive the ATQA\r
- ReaderReceive(receivedAnswer);\r
- // Transmit SELECT_ALL\r
- ReaderTransmit(sel_all,sizeof(sel_all));\r
- // Receive the UID\r
- ReaderReceive(receivedAnswer);\r
- // Construct SELECT UID command\r
- // First copy the 5 bytes (Mifare Classic) after the 93 70\r
- memcpy(sel_uid+2,receivedAnswer,5);\r
- // Secondly compute the two CRC bytes at the end\r
- AppendCrc14443a(sel_uid,7);\r
- \r
- byte_t nt_diff = 0;\r
- LED_A_OFF();\r
- byte_t par = 0;\r
- byte_t par_mask = 0xff;\r
- byte_t par_low = 0;\r
- BOOL led_on = TRUE;\r
- \r
- tracing = FALSE;\r
- byte_t nt[4];\r
- byte_t nt_attacked[4];\r
- byte_t par_list[8];\r
- byte_t ks_list[8];\r
- num_to_bytes(parameter,4,nt_attacked);\r
-\r
- while(TRUE)\r
- {\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
- SpinDelay(200);\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);\r
- \r
- // Broadcast for a card, WUPA (0x52) will force response from all cards in the field\r
- ReaderTransmitShort(wupa);\r
- \r
- // Test if the action was cancelled\r
- if(BUTTON_PRESS()) {\r
- break;\r
- }\r
- \r
- // Receive the ATQA\r
- if (!ReaderReceive(receivedAnswer)) continue;\r
- \r
- // Transmit SELECT_ALL\r
- ReaderTransmit(sel_all,sizeof(sel_all));\r
- \r
- // Receive the UID\r
- if (!ReaderReceive(receivedAnswer)) continue;\r
- \r
- // Transmit SELECT_UID\r
- ReaderTransmit(sel_uid,sizeof(sel_uid));\r
- \r
- // Receive the SAK\r
- if (!ReaderReceive(receivedAnswer)) continue;\r
- \r
- // Transmit MIFARE_CLASSIC_AUTH\r
- ReaderTransmit(mf_auth,sizeof(mf_auth));\r
- \r
- // Receive the (16 bit) "random" nonce\r
- if (!ReaderReceive(receivedAnswer)) continue;\r
- memcpy(nt,receivedAnswer,4);\r
-\r
- // Transmit reader nonce and reader answer\r
- ReaderTransmitPar(mf_nr_ar,sizeof(mf_nr_ar),par);\r
- \r
- // Receive 4 bit answer\r
- if (ReaderReceive(receivedAnswer))\r
- {\r
- if (nt_diff == 0) \r
- {\r
- LED_A_ON();\r
- memcpy(nt_attacked,nt,4);\r
- par_mask = 0xf8;\r
- par_low = par & 0x07;\r
- }\r
-\r
- if (memcmp(nt,nt_attacked,4) != 0) continue;\r
-\r
- led_on = !led_on;\r
- if(led_on) LED_B_ON(); else LED_B_OFF();\r
- par_list[nt_diff] = par;\r
- ks_list[nt_diff] = receivedAnswer[0]^0x05;\r
- \r
- // Test if the information is complete\r
- if (nt_diff == 0x07) break;\r
- \r
- nt_diff = (nt_diff+1) & 0x07;\r
- mf_nr_ar[3] = nt_diff << 5;\r
- par = par_low;\r
- } else {\r
- if (nt_diff == 0)\r
- {\r
- par++;\r
- } else {\r
- par = (((par>>3)+1) << 3) | par_low;\r
- }\r
- }\r
- }\r
- \r
- LogTraceInfo(sel_uid+2,4);\r
- LogTraceInfo(nt,4);\r
- LogTraceInfo(par_list,8);\r
- LogTraceInfo(ks_list,8);\r
- \r
- // Thats it...\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
- LEDsoff();\r
- tracing = TRUE;\r
-}\r
+//-----------------------------------------------------------------------------
+// Routines to support ISO 14443 type A.
+//
+// Gerhard de Koning Gans - May 2008
+//-----------------------------------------------------------------------------
+#include <proxmark3.h>
+#include "apps.h"
+#include "iso14443crc.h"
+
+static BYTE *trace = (BYTE *) BigBuf;
+static int traceLen = 0;
+static int rsamples = 0;
+static BOOL tracing = TRUE;
+
+typedef enum {
+ SEC_D = 1,
+ SEC_E = 2,
+ SEC_F = 3,
+ SEC_X = 4,
+ SEC_Y = 5,
+ SEC_Z = 6
+} SecType;
+
+static const BYTE OddByteParity[256] = {
+ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1
+};
+
+// BIG CHANGE - UNDERSTAND THIS BEFORE WE COMMIT
+#define RECV_CMD_OFFSET 3032
+#define RECV_RES_OFFSET 3096
+#define DMA_BUFFER_OFFSET 3160
+#define DMA_BUFFER_SIZE 4096
+#define TRACE_LENGTH 3000
+
+//-----------------------------------------------------------------------------
+// Generate the parity value for a byte sequence
+//
+//-----------------------------------------------------------------------------
+DWORD GetParity(const BYTE * pbtCmd, int iLen)
+{
+ int i;
+ DWORD dwPar = 0;
+
+ // Generate the encrypted data
+ for (i = 0; i < iLen; i++) {
+ // Save the encrypted parity bit
+ dwPar |= ((OddByteParity[pbtCmd[i]]) << i);
+ }
+ return dwPar;
+}
+
+static void AppendCrc14443a(BYTE* data, int len)
+{
+ ComputeCrc14443(CRC_14443_A,data,len,data+len,data+len+1);
+}
+
+BOOL LogTrace(const BYTE * btBytes, int iLen, int iSamples, DWORD dwParity, BOOL bReader)
+{
+ // Return when trace is full
+ if (traceLen >= TRACE_LENGTH) return FALSE;
+
+ // Trace the random, i'm curious
+ rsamples += iSamples;
+ trace[traceLen++] = ((rsamples >> 0) & 0xff);
+ trace[traceLen++] = ((rsamples >> 8) & 0xff);
+ trace[traceLen++] = ((rsamples >> 16) & 0xff);
+ trace[traceLen++] = ((rsamples >> 24) & 0xff);
+ if (!bReader) {
+ trace[traceLen - 1] |= 0x80;
+ }
+ trace[traceLen++] = ((dwParity >> 0) & 0xff);
+ trace[traceLen++] = ((dwParity >> 8) & 0xff);
+ trace[traceLen++] = ((dwParity >> 16) & 0xff);
+ trace[traceLen++] = ((dwParity >> 24) & 0xff);
+ trace[traceLen++] = iLen;
+ memcpy(trace + traceLen, btBytes, iLen);
+ traceLen += iLen;
+ return TRUE;
+}
+
+BOOL LogTraceInfo(byte_t* data, size_t len)
+{
+ return LogTrace(data,len,0,GetParity(data,len),TRUE);
+}
+
+//-----------------------------------------------------------------------------
+// The software UART that receives commands from the reader, and its state
+// variables.
+//-----------------------------------------------------------------------------
+static struct {
+ enum {
+ STATE_UNSYNCD,
+ STATE_START_OF_COMMUNICATION,
+ STATE_MILLER_X,
+ STATE_MILLER_Y,
+ STATE_MILLER_Z,
+ STATE_ERROR_WAIT
+ } state;
+ WORD shiftReg;
+ int bitCnt;
+ int byteCnt;
+ int byteCntMax;
+ int posCnt;
+ int syncBit;
+ int parityBits;
+ int samples;
+ int highCnt;
+ int bitBuffer;
+ enum {
+ DROP_NONE,
+ DROP_FIRST_HALF,
+ DROP_SECOND_HALF
+ } drop;
+ BYTE *output;
+} Uart;
+
+static BOOL MillerDecoding(int bit)
+{
+ int error = 0;
+ int bitright;
+
+ if(!Uart.bitBuffer) {
+ Uart.bitBuffer = bit ^ 0xFF0;
+ return FALSE;
+ }
+ else {
+ Uart.bitBuffer <<= 4;
+ Uart.bitBuffer ^= bit;
+ }
+
+ BOOL EOC = FALSE;
+
+ if(Uart.state != STATE_UNSYNCD) {
+ Uart.posCnt++;
+
+ if((Uart.bitBuffer & Uart.syncBit) ^ Uart.syncBit) {
+ bit = 0x00;
+ }
+ else {
+ bit = 0x01;
+ }
+ if(((Uart.bitBuffer << 1) & Uart.syncBit) ^ Uart.syncBit) {
+ bitright = 0x00;
+ }
+ else {
+ bitright = 0x01;
+ }
+ if(bit != bitright) { bit = bitright; }
+
+ if(Uart.posCnt == 1) {
+ // measurement first half bitperiod
+ if(!bit) {
+ Uart.drop = DROP_FIRST_HALF;
+ }
+ }
+ else {
+ // measurement second half bitperiod
+ if(!bit & (Uart.drop == DROP_NONE)) {
+ Uart.drop = DROP_SECOND_HALF;
+ }
+ else if(!bit) {
+ // measured a drop in first and second half
+ // which should not be possible
+ Uart.state = STATE_ERROR_WAIT;
+ error = 0x01;
+ }
+
+ Uart.posCnt = 0;
+
+ switch(Uart.state) {
+ case STATE_START_OF_COMMUNICATION:
+ Uart.shiftReg = 0;
+ if(Uart.drop == DROP_SECOND_HALF) {
+ // error, should not happen in SOC
+ Uart.state = STATE_ERROR_WAIT;
+ error = 0x02;
+ }
+ else {
+ // correct SOC
+ Uart.state = STATE_MILLER_Z;
+ }
+ break;
+
+ case STATE_MILLER_Z:
+ Uart.bitCnt++;
+ Uart.shiftReg >>= 1;
+ if(Uart.drop == DROP_NONE) {
+ // logic '0' followed by sequence Y
+ // end of communication
+ Uart.state = STATE_UNSYNCD;
+ EOC = TRUE;
+ }
+ // if(Uart.drop == DROP_FIRST_HALF) {
+ // Uart.state = STATE_MILLER_Z; stay the same
+ // we see a logic '0' }
+ if(Uart.drop == DROP_SECOND_HALF) {
+ // we see a logic '1'
+ Uart.shiftReg |= 0x100;
+ Uart.state = STATE_MILLER_X;
+ }
+ break;
+
+ case STATE_MILLER_X:
+ Uart.shiftReg >>= 1;
+ if(Uart.drop == DROP_NONE) {
+ // sequence Y, we see a '0'
+ Uart.state = STATE_MILLER_Y;
+ Uart.bitCnt++;
+ }
+ if(Uart.drop == DROP_FIRST_HALF) {
+ // Would be STATE_MILLER_Z
+ // but Z does not follow X, so error
+ Uart.state = STATE_ERROR_WAIT;
+ error = 0x03;
+ }
+ if(Uart.drop == DROP_SECOND_HALF) {
+ // We see a '1' and stay in state X
+ Uart.shiftReg |= 0x100;
+ Uart.bitCnt++;
+ }
+ break;
+
+ case STATE_MILLER_Y:
+ Uart.bitCnt++;
+ Uart.shiftReg >>= 1;
+ if(Uart.drop == DROP_NONE) {
+ // logic '0' followed by sequence Y
+ // end of communication
+ Uart.state = STATE_UNSYNCD;
+ EOC = TRUE;
+ }
+ if(Uart.drop == DROP_FIRST_HALF) {
+ // we see a '0'
+ Uart.state = STATE_MILLER_Z;
+ }
+ if(Uart.drop == DROP_SECOND_HALF) {
+ // We see a '1' and go to state X
+ Uart.shiftReg |= 0x100;
+ Uart.state = STATE_MILLER_X;
+ }
+ break;
+
+ case STATE_ERROR_WAIT:
+ // That went wrong. Now wait for at least two bit periods
+ // and try to sync again
+ if(Uart.drop == DROP_NONE) {
+ Uart.highCnt = 6;
+ Uart.state = STATE_UNSYNCD;
+ }
+ break;
+
+ default:
+ Uart.state = STATE_UNSYNCD;
+ Uart.highCnt = 0;
+ break;
+ }
+
+ Uart.drop = DROP_NONE;
+
+ // should have received at least one whole byte...
+ if((Uart.bitCnt == 2) && EOC && (Uart.byteCnt > 0)) {
+ return TRUE;
+ }
+
+ if(Uart.bitCnt == 9) {
+ Uart.output[Uart.byteCnt] = (Uart.shiftReg & 0xff);
+ Uart.byteCnt++;
+
+ Uart.parityBits <<= 1;
+ Uart.parityBits ^= ((Uart.shiftReg >> 8) & 0x01);
+
+ if(EOC) {
+ // when End of Communication received and
+ // all data bits processed..
+ return TRUE;
+ }
+ Uart.bitCnt = 0;
+ }
+
+ /*if(error) {
+ Uart.output[Uart.byteCnt] = 0xAA;
+ Uart.byteCnt++;
+ Uart.output[Uart.byteCnt] = error & 0xFF;
+ Uart.byteCnt++;
+ Uart.output[Uart.byteCnt] = 0xAA;
+ Uart.byteCnt++;
+ Uart.output[Uart.byteCnt] = (Uart.bitBuffer >> 8) & 0xFF;
+ Uart.byteCnt++;
+ Uart.output[Uart.byteCnt] = Uart.bitBuffer & 0xFF;
+ Uart.byteCnt++;
+ Uart.output[Uart.byteCnt] = (Uart.syncBit >> 3) & 0xFF;
+ Uart.byteCnt++;
+ Uart.output[Uart.byteCnt] = 0xAA;
+ Uart.byteCnt++;
+ return TRUE;
+ }*/
+ }
+
+ }
+ else {
+ bit = Uart.bitBuffer & 0xf0;
+ bit >>= 4;
+ bit ^= 0x0F;
+ if(bit) {
+ // should have been high or at least (4 * 128) / fc
+ // according to ISO this should be at least (9 * 128 + 20) / fc
+ if(Uart.highCnt == 8) {
+ // we went low, so this could be start of communication
+ // it turns out to be safer to choose a less significant
+ // syncbit... so we check whether the neighbour also represents the drop
+ Uart.posCnt = 1; // apparently we are busy with our first half bit period
+ Uart.syncBit = bit & 8;
+ Uart.samples = 3;
+ if(!Uart.syncBit) { Uart.syncBit = bit & 4; Uart.samples = 2; }
+ else if(bit & 4) { Uart.syncBit = bit & 4; Uart.samples = 2; bit <<= 2; }
+ if(!Uart.syncBit) { Uart.syncBit = bit & 2; Uart.samples = 1; }
+ else if(bit & 2) { Uart.syncBit = bit & 2; Uart.samples = 1; bit <<= 1; }
+ if(!Uart.syncBit) { Uart.syncBit = bit & 1; Uart.samples = 0;
+ if(Uart.syncBit & (Uart.bitBuffer & 8)) {
+ Uart.syncBit = 8;
+
+ // the first half bit period is expected in next sample
+ Uart.posCnt = 0;
+ Uart.samples = 3;
+ }
+ }
+ else if(bit & 1) { Uart.syncBit = bit & 1; Uart.samples = 0; }
+
+ Uart.syncBit <<= 4;
+ Uart.state = STATE_START_OF_COMMUNICATION;
+ Uart.drop = DROP_FIRST_HALF;
+ Uart.bitCnt = 0;
+ Uart.byteCnt = 0;
+ Uart.parityBits = 0;
+ error = 0;
+ }
+ else {
+ Uart.highCnt = 0;
+ }
+ }
+ else {
+ if(Uart.highCnt < 8) {
+ Uart.highCnt++;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+//=============================================================================
+// ISO 14443 Type A - Manchester
+//=============================================================================
+
+static struct {
+ enum {
+ DEMOD_UNSYNCD,
+ DEMOD_START_OF_COMMUNICATION,
+ DEMOD_MANCHESTER_D,
+ DEMOD_MANCHESTER_E,
+ DEMOD_MANCHESTER_F,
+ DEMOD_ERROR_WAIT
+ } state;
+ int bitCount;
+ int posCount;
+ int syncBit;
+ int parityBits;
+ WORD shiftReg;
+ int buffer;
+ int buff;
+ int samples;
+ int len;
+ enum {
+ SUB_NONE,
+ SUB_FIRST_HALF,
+ SUB_SECOND_HALF
+ } sub;
+ BYTE *output;
+} Demod;
+
+static BOOL ManchesterDecoding(int v)
+{
+ int bit;
+ int modulation;
+ int error = 0;
+
+ if(!Demod.buff) {
+ Demod.buff = 1;
+ Demod.buffer = v;
+ return FALSE;
+ }
+ else {
+ bit = Demod.buffer;
+ Demod.buffer = v;
+ }
+
+ if(Demod.state==DEMOD_UNSYNCD) {
+ Demod.output[Demod.len] = 0xfa;
+ Demod.syncBit = 0;
+ //Demod.samples = 0;
+ Demod.posCount = 1; // This is the first half bit period, so after syncing handle the second part
+ if(bit & 0x08) { Demod.syncBit = 0x08; }
+ if(!Demod.syncBit) {
+ if(bit & 0x04) { Demod.syncBit = 0x04; }
+ }
+ else if(bit & 0x04) { Demod.syncBit = 0x04; bit <<= 4; }
+ if(!Demod.syncBit) {
+ if(bit & 0x02) { Demod.syncBit = 0x02; }
+ }
+ else if(bit & 0x02) { Demod.syncBit = 0x02; bit <<= 4; }
+ if(!Demod.syncBit) {
+ if(bit & 0x01) { Demod.syncBit = 0x01; }
+
+ if(Demod.syncBit & (Demod.buffer & 0x08)) {
+ Demod.syncBit = 0x08;
+
+ // The first half bitperiod is expected in next sample
+ Demod.posCount = 0;
+ Demod.output[Demod.len] = 0xfb;
+ }
+ }
+ else if(bit & 0x01) { Demod.syncBit = 0x01; }
+
+ if(Demod.syncBit) {
+ Demod.len = 0;
+ Demod.state = DEMOD_START_OF_COMMUNICATION;
+ Demod.sub = SUB_FIRST_HALF;
+ Demod.bitCount = 0;
+ Demod.shiftReg = 0;
+ Demod.parityBits = 0;
+ Demod.samples = 0;
+ if(Demod.posCount) {
+ switch(Demod.syncBit) {
+ case 0x08: Demod.samples = 3; break;
+ case 0x04: Demod.samples = 2; break;
+ case 0x02: Demod.samples = 1; break;
+ case 0x01: Demod.samples = 0; break;
+ }
+ }
+ error = 0;
+ }
+ }
+ else {
+ //modulation = bit & Demod.syncBit;
+ modulation = ((bit << 1) ^ ((Demod.buffer & 0x08) >> 3)) & Demod.syncBit;
+
+ Demod.samples += 4;
+
+ if(Demod.posCount==0) {
+ Demod.posCount = 1;
+ if(modulation) {
+ Demod.sub = SUB_FIRST_HALF;
+ }
+ else {
+ Demod.sub = SUB_NONE;
+ }
+ }
+ else {
+ Demod.posCount = 0;
+ if(modulation && (Demod.sub == SUB_FIRST_HALF)) {
+ if(Demod.state!=DEMOD_ERROR_WAIT) {
+ Demod.state = DEMOD_ERROR_WAIT;
+ Demod.output[Demod.len] = 0xaa;
+ error = 0x01;
+ }
+ }
+ else if(modulation) {
+ Demod.sub = SUB_SECOND_HALF;
+ }
+
+ switch(Demod.state) {
+ case DEMOD_START_OF_COMMUNICATION:
+ if(Demod.sub == SUB_FIRST_HALF) {
+ Demod.state = DEMOD_MANCHESTER_D;
+ }
+ else {
+ Demod.output[Demod.len] = 0xab;
+ Demod.state = DEMOD_ERROR_WAIT;
+ error = 0x02;
+ }
+ break;
+
+ case DEMOD_MANCHESTER_D:
+ case DEMOD_MANCHESTER_E:
+ if(Demod.sub == SUB_FIRST_HALF) {
+ Demod.bitCount++;
+ Demod.shiftReg = (Demod.shiftReg >> 1) ^ 0x100;
+ Demod.state = DEMOD_MANCHESTER_D;
+ }
+ else if(Demod.sub == SUB_SECOND_HALF) {
+ Demod.bitCount++;
+ Demod.shiftReg >>= 1;
+ Demod.state = DEMOD_MANCHESTER_E;
+ }
+ else {
+ Demod.state = DEMOD_MANCHESTER_F;
+ }
+ break;
+
+ case DEMOD_MANCHESTER_F:
+ // Tag response does not need to be a complete byte!
+ if(Demod.len > 0 || Demod.bitCount > 0) {
+ if(Demod.bitCount > 0) {
+ Demod.shiftReg >>= (9 - Demod.bitCount);
+ Demod.output[Demod.len] = Demod.shiftReg & 0xff;
+ Demod.len++;
+ // No parity bit, so just shift a 0
+ Demod.parityBits <<= 1;
+ }
+
+ Demod.state = DEMOD_UNSYNCD;
+ return TRUE;
+ }
+ else {
+ Demod.output[Demod.len] = 0xad;
+ Demod.state = DEMOD_ERROR_WAIT;
+ error = 0x03;
+ }
+ break;
+
+ case DEMOD_ERROR_WAIT:
+ Demod.state = DEMOD_UNSYNCD;
+ break;
+
+ default:
+ Demod.output[Demod.len] = 0xdd;
+ Demod.state = DEMOD_UNSYNCD;
+ break;
+ }
+
+ if(Demod.bitCount>=9) {
+ Demod.output[Demod.len] = Demod.shiftReg & 0xff;
+ Demod.len++;
+
+ Demod.parityBits <<= 1;
+ Demod.parityBits ^= ((Demod.shiftReg >> 8) & 0x01);
+
+ Demod.bitCount = 0;
+ Demod.shiftReg = 0;
+ }
+
+ /*if(error) {
+ Demod.output[Demod.len] = 0xBB;
+ Demod.len++;
+ Demod.output[Demod.len] = error & 0xFF;
+ Demod.len++;
+ Demod.output[Demod.len] = 0xBB;
+ Demod.len++;
+ Demod.output[Demod.len] = bit & 0xFF;
+ Demod.len++;
+ Demod.output[Demod.len] = Demod.buffer & 0xFF;
+ Demod.len++;
+ Demod.output[Demod.len] = Demod.syncBit & 0xFF;
+ Demod.len++;
+ Demod.output[Demod.len] = 0xBB;
+ Demod.len++;
+ return TRUE;
+ }*/
+
+ }
+
+ } // end (state != UNSYNCED)
+
+ return FALSE;
+}
+
+//=============================================================================
+// Finally, a `sniffer' for ISO 14443 Type A
+// Both sides of communication!
+//=============================================================================
+
+//-----------------------------------------------------------------------------
+// Record the sequence of commands sent by the reader to the tag, with
+// triggering so that we start recording at the point that the tag is moved
+// near the reader.
+//-----------------------------------------------------------------------------
+void SnoopIso14443a(void)
+{
+// #define RECV_CMD_OFFSET 2032 // original (working as of 21/2/09) values
+// #define RECV_RES_OFFSET 2096 // original (working as of 21/2/09) values
+// #define DMA_BUFFER_OFFSET 2160 // original (working as of 21/2/09) values
+// #define DMA_BUFFER_SIZE 4096 // original (working as of 21/2/09) values
+// #define TRACE_LENGTH 2000 // original (working as of 21/2/09) values
+
+ // We won't start recording the frames that we acquire until we trigger;
+ // a good trigger condition to get started is probably when we see a
+ // response from the tag.
+ BOOL triggered = TRUE; // FALSE to wait first for card
+
+ // The command (reader -> tag) that we're receiving.
+ // The length of a received command will in most cases be no more than 18 bytes.
+ // So 32 should be enough!
+ BYTE *receivedCmd = (((BYTE *)BigBuf) + RECV_CMD_OFFSET);
+ // The response (tag -> reader) that we're receiving.
+ BYTE *receivedResponse = (((BYTE *)BigBuf) + RECV_RES_OFFSET);
+
+ // As we receive stuff, we copy it from receivedCmd or receivedResponse
+ // into trace, along with its length and other annotations.
+ //BYTE *trace = (BYTE *)BigBuf;
+ //int traceLen = 0;
+
+ // The DMA buffer, used to stream samples from the FPGA
+ SBYTE *dmaBuf = ((SBYTE *)BigBuf) + DMA_BUFFER_OFFSET;
+ int lastRxCounter;
+ SBYTE *upTo;
+ int smpl;
+ int maxBehindBy = 0;
+
+ // Count of samples received so far, so that we can include timing
+ // information in the trace buffer.
+ int samples = 0;
+ int rsamples = 0;
+
+ memset(trace, 0x44, RECV_CMD_OFFSET);
+
+ // Set up the demodulator for tag -> reader responses.
+ Demod.output = receivedResponse;
+ Demod.len = 0;
+ Demod.state = DEMOD_UNSYNCD;
+
+ // And the reader -> tag commands
+ memset(&Uart, 0, sizeof(Uart));
+ Uart.output = receivedCmd;
+ Uart.byteCntMax = 32; // was 100 (greg)////////////////////////////////////////////////////////////////////////
+ Uart.state = STATE_UNSYNCD;
+
+ // And put the FPGA in the appropriate mode
+ // Signal field is off with the appropriate LED
+ LED_D_OFF();
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_SNIFFER);
+ SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
+
+ // Setup for the DMA.
+ FpgaSetupSsc();
+ upTo = dmaBuf;
+ lastRxCounter = DMA_BUFFER_SIZE;
+ FpgaSetupSscDma((BYTE *)dmaBuf, DMA_BUFFER_SIZE);
+
+ LED_A_ON();
+
+ // And now we loop, receiving samples.
+ for(;;) {
+ WDT_HIT();
+ int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) &
+ (DMA_BUFFER_SIZE-1);
+ if(behindBy > maxBehindBy) {
+ maxBehindBy = behindBy;
+ if(behindBy > 400) {
+ DbpString("blew circular buffer!");
+ goto done;
+ }
+ }
+ if(behindBy < 1) continue;
+
+ smpl = upTo[0];
+ upTo++;
+ lastRxCounter -= 1;
+ if(upTo - dmaBuf > DMA_BUFFER_SIZE) {
+ upTo -= DMA_BUFFER_SIZE;
+ lastRxCounter += DMA_BUFFER_SIZE;
+ AT91C_BASE_PDC_SSC->PDC_RNPR = (DWORD)upTo;
+ AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE;
+ }
+
+ samples += 4;
+#define HANDLE_BIT_IF_BODY \
+ LED_C_ON(); \
+ if(triggered) { \
+ trace[traceLen++] = ((rsamples >> 0) & 0xff); \
+ trace[traceLen++] = ((rsamples >> 8) & 0xff); \
+ trace[traceLen++] = ((rsamples >> 16) & 0xff); \
+ trace[traceLen++] = ((rsamples >> 24) & 0xff); \
+ trace[traceLen++] = ((Uart.parityBits >> 0) & 0xff); \
+ trace[traceLen++] = ((Uart.parityBits >> 8) & 0xff); \
+ trace[traceLen++] = ((Uart.parityBits >> 16) & 0xff); \
+ trace[traceLen++] = ((Uart.parityBits >> 24) & 0xff); \
+ trace[traceLen++] = Uart.byteCnt; \
+ memcpy(trace+traceLen, receivedCmd, Uart.byteCnt); \
+ traceLen += Uart.byteCnt; \
+ if(traceLen > TRACE_LENGTH) break; \
+ } \
+ /* And ready to receive another command. */ \
+ Uart.state = STATE_UNSYNCD; \
+ /* And also reset the demod code, which might have been */ \
+ /* false-triggered by the commands from the reader. */ \
+ Demod.state = DEMOD_UNSYNCD; \
+ LED_B_OFF(); \
+
+ if(MillerDecoding((smpl & 0xF0) >> 4)) {
+ rsamples = samples - Uart.samples;
+ HANDLE_BIT_IF_BODY
+ }
+ if(ManchesterDecoding(smpl & 0x0F)) {
+ rsamples = samples - Demod.samples;
+ LED_B_ON();
+
+ // timestamp, as a count of samples
+ trace[traceLen++] = ((rsamples >> 0) & 0xff);
+ trace[traceLen++] = ((rsamples >> 8) & 0xff);
+ trace[traceLen++] = ((rsamples >> 16) & 0xff);
+ trace[traceLen++] = 0x80 | ((rsamples >> 24) & 0xff);
+ trace[traceLen++] = ((Demod.parityBits >> 0) & 0xff);
+ trace[traceLen++] = ((Demod.parityBits >> 8) & 0xff);
+ trace[traceLen++] = ((Demod.parityBits >> 16) & 0xff);
+ trace[traceLen++] = ((Demod.parityBits >> 24) & 0xff);
+ // length
+ trace[traceLen++] = Demod.len;
+ memcpy(trace+traceLen, receivedResponse, Demod.len);
+ traceLen += Demod.len;
+ if(traceLen > TRACE_LENGTH) break;
+
+ triggered = TRUE;
+
+ // And ready to receive another response.
+ memset(&Demod, 0, sizeof(Demod));
+ Demod.output = receivedResponse;
+ Demod.state = DEMOD_UNSYNCD;
+ LED_C_OFF();
+ }
+
+ if(BUTTON_PRESS()) {
+ DbpString("cancelled_a");
+ goto done;
+ }
+ }
+
+ DbpString("COMMAND FINISHED");
+
+ Dbprintf("%x %x %x", maxBehindBy, Uart.state, Uart.byteCnt);
+ Dbprintf("%x %x %x", Uart.byteCntMax, traceLen, (int)Uart.output[0]);
+
+done:
+ AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS;
+ Dbprintf("%x %x %x", maxBehindBy, Uart.state, Uart.byteCnt);
+ Dbprintf("%x %x %x", Uart.byteCntMax, traceLen, (int)Uart.output[0]);
+ LED_A_OFF();
+ LED_B_OFF();
+ LED_C_OFF();
+ LED_D_OFF();
+}
+
+// Prepare communication bits to send to FPGA
+void Sequence(SecType seq)
+{
+ ToSendMax++;
+ switch(seq) {
+ // CARD TO READER
+ case SEC_D:
+ // Sequence D: 11110000
+ // modulation with subcarrier during first half
+ ToSend[ToSendMax] = 0xf0;
+ break;
+ case SEC_E:
+ // Sequence E: 00001111
+ // modulation with subcarrier during second half
+ ToSend[ToSendMax] = 0x0f;
+ break;
+ case SEC_F:
+ // Sequence F: 00000000
+ // no modulation with subcarrier
+ ToSend[ToSendMax] = 0x00;
+ break;
+ // READER TO CARD
+ case SEC_X:
+ // Sequence X: 00001100
+ // drop after half a period
+ ToSend[ToSendMax] = 0x0c;
+ break;
+ case SEC_Y:
+ default:
+ // Sequence Y: 00000000
+ // no drop
+ ToSend[ToSendMax] = 0x00;
+ break;
+ case SEC_Z:
+ // Sequence Z: 11000000
+ // drop at start
+ ToSend[ToSendMax] = 0xc0;
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Prepare tag messages
+//-----------------------------------------------------------------------------
+static void CodeIso14443aAsTag(const BYTE *cmd, int len)
+{
+ int i;
+ int oddparity;
+
+ ToSendReset();
+
+ // Correction bit, might be removed when not needed
+ ToSendStuffBit(0);
+ ToSendStuffBit(0);
+ ToSendStuffBit(0);
+ ToSendStuffBit(0);
+ ToSendStuffBit(1); // 1
+ ToSendStuffBit(0);
+ ToSendStuffBit(0);
+ ToSendStuffBit(0);
+
+ // Send startbit
+ Sequence(SEC_D);
+
+ for(i = 0; i < len; i++) {
+ int j;
+ BYTE b = cmd[i];
+
+ // Data bits
+ oddparity = 0x01;
+ for(j = 0; j < 8; j++) {
+ oddparity ^= (b & 1);
+ if(b & 1) {
+ Sequence(SEC_D);
+ } else {
+ Sequence(SEC_E);
+ }
+ b >>= 1;
+ }
+
+ // Parity bit
+ if(oddparity) {
+ Sequence(SEC_D);
+ } else {
+ Sequence(SEC_E);
+ }
+ }
+
+ // Send stopbit
+ Sequence(SEC_F);
+
+ // Flush the buffer in FPGA!!
+ for(i = 0; i < 5; i++) {
+ Sequence(SEC_F);
+ }
+
+ // Convert from last byte pos to length
+ ToSendMax++;
+
+ // Add a few more for slop
+ ToSend[ToSendMax++] = 0x00;
+ ToSend[ToSendMax++] = 0x00;
+ //ToSendMax += 2;
+}
+
+//-----------------------------------------------------------------------------
+// This is to send a NACK kind of answer, its only 3 bits, I know it should be 4
+//-----------------------------------------------------------------------------
+static void CodeStrangeAnswer()
+{
+ int i;
+
+ ToSendReset();
+
+ // Correction bit, might be removed when not needed
+ ToSendStuffBit(0);
+ ToSendStuffBit(0);
+ ToSendStuffBit(0);
+ ToSendStuffBit(0);
+ ToSendStuffBit(1); // 1
+ ToSendStuffBit(0);
+ ToSendStuffBit(0);
+ ToSendStuffBit(0);
+
+ // Send startbit
+ Sequence(SEC_D);
+
+ // 0
+ Sequence(SEC_E);
+
+ // 0
+ Sequence(SEC_E);
+
+ // 1
+ Sequence(SEC_D);
+
+ // Send stopbit
+ Sequence(SEC_F);
+
+ // Flush the buffer in FPGA!!
+ for(i = 0; i < 5; i++) {
+ Sequence(SEC_F);
+ }
+
+ // Convert from last byte pos to length
+ ToSendMax++;
+
+ // Add a few more for slop
+ ToSend[ToSendMax++] = 0x00;
+ ToSend[ToSendMax++] = 0x00;
+ //ToSendMax += 2;
+}
+
+//-----------------------------------------------------------------------------
+// Wait for commands from reader
+// Stop when button is pressed
+// Or return TRUE when command is captured
+//-----------------------------------------------------------------------------
+static BOOL GetIso14443aCommandFromReader(BYTE *received, int *len, int maxLen)
+{
+ // Set FPGA mode to "simulated ISO 14443 tag", no modulation (listen
+ // only, since we are receiving, not transmitting).
+ // Signal field is off with the appropriate LED
+ LED_D_OFF();
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN);
+
+ // Now run a `software UART' on the stream of incoming samples.
+ Uart.output = received;
+ Uart.byteCntMax = maxLen;
+ Uart.state = STATE_UNSYNCD;
+
+ for(;;) {
+ WDT_HIT();
+
+ if(BUTTON_PRESS()) return FALSE;
+
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
+ AT91C_BASE_SSC->SSC_THR = 0x00;
+ }
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
+ BYTE b = (BYTE)AT91C_BASE_SSC->SSC_RHR;
+ if(MillerDecoding((b & 0xf0) >> 4)) {
+ *len = Uart.byteCnt;
+ return TRUE;
+ }
+ if(MillerDecoding(b & 0x0f)) {
+ *len = Uart.byteCnt;
+ return TRUE;
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Main loop of simulated tag: receive commands from reader, decide what
+// response to send, and send it.
+//-----------------------------------------------------------------------------
+void SimulateIso14443aTag(int tagType, int TagUid)
+{
+ // This function contains the tag emulation
+
+ // Prepare protocol messages
+ // static const BYTE cmd1[] = { 0x26 };
+// static const BYTE response1[] = { 0x02, 0x00 }; // Says: I am Mifare 4k - original line - greg
+//
+ static const BYTE response1[] = { 0x44, 0x03 }; // Says: I am a DESFire Tag, ph33r me
+// static const BYTE response1[] = { 0x44, 0x00 }; // Says: I am a ULTRALITE Tag, 0wn me
+
+ // UID response
+ // static const BYTE cmd2[] = { 0x93, 0x20 };
+ //static const BYTE response2[] = { 0x9a, 0xe5, 0xe4, 0x43, 0xd8 }; // original value - greg
+
+
+
+// my desfire
+ static const BYTE response2[] = { 0x88, 0x04, 0x21, 0x3f, 0x4d }; // known uid - note cascade (0x88), 2nd byte (0x04) = NXP/Phillips
+
+
+// When reader selects us during cascade1 it will send cmd3
+//BYTE response3[] = { 0x04, 0x00, 0x00 }; // SAK Select (cascade1) successful response (ULTRALITE)
+BYTE response3[] = { 0x24, 0x00, 0x00 }; // SAK Select (cascade1) successful response (DESFire)
+ComputeCrc14443(CRC_14443_A, response3, 1, &response3[1], &response3[2]);
+
+// send cascade2 2nd half of UID
+static const BYTE response2a[] = { 0x51, 0x48, 0x1d, 0x80, 0x84 }; // uid - cascade2 - 2nd half (4 bytes) of UID+ BCCheck
+// NOTE : THE CRC on the above may be wrong as I have obfuscated the actual UID
+
+
+// When reader selects us during cascade2 it will send cmd3a
+//BYTE response3a[] = { 0x00, 0x00, 0x00 }; // SAK Select (cascade2) successful response (ULTRALITE)
+BYTE response3a[] = { 0x20, 0x00, 0x00 }; // SAK Select (cascade2) successful response (DESFire)
+ComputeCrc14443(CRC_14443_A, response3a, 1, &response3a[1], &response3a[2]);
+
+ static const BYTE response5[] = { 0x00, 0x00, 0x00, 0x00 }; // Very random tag nonce
+
+ BYTE *resp;
+ int respLen;
+
+ // Longest possible response will be 16 bytes + 2 CRC = 18 bytes
+ // This will need
+ // 144 data bits (18 * 8)
+ // 18 parity bits
+ // 2 Start and stop
+ // 1 Correction bit (Answer in 1172 or 1236 periods, see FPGA)
+ // 1 just for the case
+ // ----------- +
+ // 166
+ //
+ // 166 bytes, since every bit that needs to be send costs us a byte
+ //
+
+
+ // Respond with card type
+ BYTE *resp1 = (((BYTE *)BigBuf) + 800);
+ int resp1Len;
+
+ // Anticollision cascade1 - respond with uid
+ BYTE *resp2 = (((BYTE *)BigBuf) + 970);
+ int resp2Len;
+
+ // Anticollision cascade2 - respond with 2nd half of uid if asked
+ // we're only going to be asked if we set the 1st byte of the UID (during cascade1) to 0x88
+ BYTE *resp2a = (((BYTE *)BigBuf) + 1140);
+ int resp2aLen;
+
+ // Acknowledge select - cascade 1
+ BYTE *resp3 = (((BYTE *)BigBuf) + 1310);
+ int resp3Len;
+
+ // Acknowledge select - cascade 2
+ BYTE *resp3a = (((BYTE *)BigBuf) + 1480);
+ int resp3aLen;
+
+ // Response to a read request - not implemented atm
+ BYTE *resp4 = (((BYTE *)BigBuf) + 1550);
+ int resp4Len;
+
+ // Authenticate response - nonce
+ BYTE *resp5 = (((BYTE *)BigBuf) + 1720);
+ int resp5Len;
+
+ BYTE *receivedCmd = (BYTE *)BigBuf;
+ int len;
+
+ int i;
+ int u;
+ BYTE b;
+
+ // To control where we are in the protocol
+ int order = 0;
+ int lastorder;
+
+ // Just to allow some checks
+ int happened = 0;
+ int happened2 = 0;
+
+ int cmdsRecvd = 0;
+
+ BOOL fdt_indicator;
+
+ memset(receivedCmd, 0x44, 400);
+
+ // Prepare the responses of the anticollision phase
+ // there will be not enough time to do this at the moment the reader sends it REQA
+
+ // Answer to request
+ CodeIso14443aAsTag(response1, sizeof(response1));
+ memcpy(resp1, ToSend, ToSendMax); resp1Len = ToSendMax;
+
+ // Send our UID (cascade 1)
+ CodeIso14443aAsTag(response2, sizeof(response2));
+ memcpy(resp2, ToSend, ToSendMax); resp2Len = ToSendMax;
+
+ // Answer to select (cascade1)
+ CodeIso14443aAsTag(response3, sizeof(response3));
+ memcpy(resp3, ToSend, ToSendMax); resp3Len = ToSendMax;
+
+ // Send the cascade 2 2nd part of the uid
+ CodeIso14443aAsTag(response2a, sizeof(response2a));
+ memcpy(resp2a, ToSend, ToSendMax); resp2aLen = ToSendMax;
+
+ // Answer to select (cascade 2)
+ CodeIso14443aAsTag(response3a, sizeof(response3a));
+ memcpy(resp3a, ToSend, ToSendMax); resp3aLen = ToSendMax;
+
+ // Strange answer is an example of rare message size (3 bits)
+ CodeStrangeAnswer();
+ memcpy(resp4, ToSend, ToSendMax); resp4Len = ToSendMax;
+
+ // Authentication answer (random nonce)
+ CodeIso14443aAsTag(response5, sizeof(response5));
+ memcpy(resp5, ToSend, ToSendMax); resp5Len = ToSendMax;
+
+ // We need to listen to the high-frequency, peak-detected path.
+ SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
+ FpgaSetupSsc();
+
+ cmdsRecvd = 0;
+
+ LED_A_ON();
+ for(;;) {
+
+ if(!GetIso14443aCommandFromReader(receivedCmd, &len, 100)) {
+ DbpString("button press");
+ break;
+ }
+ // doob - added loads of debug strings so we can see what the reader is saying to us during the sim as hi14alist is not populated
+ // Okay, look at the command now.
+ lastorder = order;
+ i = 1; // first byte transmitted
+ if(receivedCmd[0] == 0x26) {
+ // Received a REQUEST
+ resp = resp1; respLen = resp1Len; order = 1;
+ //DbpString("Hello request from reader:");
+ } else if(receivedCmd[0] == 0x52) {
+ // Received a WAKEUP
+ resp = resp1; respLen = resp1Len; order = 6;
+// //DbpString("Wakeup request from reader:");
+
+ } else if(receivedCmd[1] == 0x20 && receivedCmd[0] == 0x93) { // greg - cascade 1 anti-collision
+ // Received request for UID (cascade 1)
+ resp = resp2; respLen = resp2Len; order = 2;
+// DbpString("UID (cascade 1) request from reader:");
+// DbpIntegers(receivedCmd[0], receivedCmd[1], receivedCmd[2]);
+
+
+ } else if(receivedCmd[1] == 0x20 && receivedCmd[0] ==0x95) { // greg - cascade 2 anti-collision
+ // Received request for UID (cascade 2)
+ resp = resp2a; respLen = resp2aLen; order = 20;
+// DbpString("UID (cascade 2) request from reader:");
+// DbpIntegers(receivedCmd[0], receivedCmd[1], receivedCmd[2]);
+
+
+ } else if(receivedCmd[1] == 0x70 && receivedCmd[0] ==0x93) { // greg - cascade 1 select
+ // Received a SELECT
+ resp = resp3; respLen = resp3Len; order = 3;
+// DbpString("Select (cascade 1) request from reader:");
+// DbpIntegers(receivedCmd[0], receivedCmd[1], receivedCmd[2]);
+
+
+ } else if(receivedCmd[1] == 0x70 && receivedCmd[0] ==0x95) { // greg - cascade 2 select
+ // Received a SELECT
+ resp = resp3a; respLen = resp3aLen; order = 30;
+// DbpString("Select (cascade 2) request from reader:");
+// DbpIntegers(receivedCmd[0], receivedCmd[1], receivedCmd[2]);
+
+
+ } else if(receivedCmd[0] == 0x30) {
+ // Received a READ
+ resp = resp4; respLen = resp4Len; order = 4; // Do nothing
+ Dbprintf("Read request from reader: %x %x %x",
+ receivedCmd[0], receivedCmd[1], receivedCmd[2]);
+
+
+ } else if(receivedCmd[0] == 0x50) {
+ // Received a HALT
+ resp = resp1; respLen = 0; order = 5; // Do nothing
+ DbpString("Reader requested we HALT!:");
+
+ } else if(receivedCmd[0] == 0x60) {
+ // Received an authentication request
+ resp = resp5; respLen = resp5Len; order = 7;
+ Dbprintf("Authenticate request from reader: %x %x %x",
+ receivedCmd[0], receivedCmd[1], receivedCmd[2]);
+
+ } else if(receivedCmd[0] == 0xE0) {
+ // Received a RATS request
+ resp = resp1; respLen = 0;order = 70;
+ Dbprintf("RATS request from reader: %x %x %x",
+ receivedCmd[0], receivedCmd[1], receivedCmd[2]);
+ } else {
+ // Never seen this command before
+ Dbprintf("Unknown command received from reader: %x %x %x %x %x %x %x %x %x",
+ receivedCmd[0], receivedCmd[1], receivedCmd[2],
+ receivedCmd[3], receivedCmd[3], receivedCmd[4],
+ receivedCmd[5], receivedCmd[6], receivedCmd[7]);
+ // Do not respond
+ resp = resp1; respLen = 0; order = 0;
+ }
+
+ // Count number of wakeups received after a halt
+ if(order == 6 && lastorder == 5) { happened++; }
+
+ // Count number of other messages after a halt
+ if(order != 6 && lastorder == 5) { happened2++; }
+
+ // Look at last parity bit to determine timing of answer
+ if((Uart.parityBits & 0x01) || receivedCmd[0] == 0x52) {
+ // 1236, so correction bit needed
+ i = 0;
+ }
+
+ memset(receivedCmd, 0x44, 32);
+
+ if(cmdsRecvd > 999) {
+ DbpString("1000 commands later...");
+ break;
+ }
+ else {
+ cmdsRecvd++;
+ }
+
+ if(respLen <= 0) continue;
+
+ // Modulate Manchester
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_MOD);
+ AT91C_BASE_SSC->SSC_THR = 0x00;
+ FpgaSetupSsc();
+
+ // ### Transmit the response ###
+ u = 0;
+ b = 0x00;
+ fdt_indicator = FALSE;
+ for(;;) {
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
+ volatile BYTE b = (BYTE)AT91C_BASE_SSC->SSC_RHR;
+ (void)b;
+ }
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
+ if(i > respLen) {
+ b = 0x00;
+ u++;
+ } else {
+ b = resp[i];
+ i++;
+ }
+ AT91C_BASE_SSC->SSC_THR = b;
+
+ if(u > 4) {
+ break;
+ }
+ }
+ if(BUTTON_PRESS()) {
+ break;
+ }
+ }
+
+ }
+
+ Dbprintf("%x %x %x", happened, happened2, cmdsRecvd);
+ LED_A_OFF();
+}
+
+//-----------------------------------------------------------------------------
+// Transmit the command (to the tag) that was placed in ToSend[].
+//-----------------------------------------------------------------------------
+static void TransmitFor14443a(const BYTE *cmd, int len, int *samples, int *wait)
+{
+ int c;
+
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);
+
+ if (wait)
+ if(*wait < 10)
+ *wait = 10;
+
+ for(c = 0; c < *wait;) {
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
+ AT91C_BASE_SSC->SSC_THR = 0x00; // For exact timing!
+ c++;
+ }
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
+ volatile DWORD r = AT91C_BASE_SSC->SSC_RHR;
+ (void)r;
+ }
+ WDT_HIT();
+ }
+
+ c = 0;
+ for(;;) {
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
+ AT91C_BASE_SSC->SSC_THR = cmd[c];
+ c++;
+ if(c >= len) {
+ break;
+ }
+ }
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
+ volatile DWORD r = AT91C_BASE_SSC->SSC_RHR;
+ (void)r;
+ }
+ WDT_HIT();
+ }
+ if (samples) *samples = (c + *wait) << 3;
+}
+
+//-----------------------------------------------------------------------------
+// To generate an arbitrary stream from reader
+//
+//-----------------------------------------------------------------------------
+void ArbitraryFromReader(const BYTE *cmd, int parity, int len)
+{
+ int i;
+ int j;
+ int last;
+ BYTE b;
+
+ ToSendReset();
+
+ // Start of Communication (Seq. Z)
+ Sequence(SEC_Z);
+ last = 0;
+
+ for(i = 0; i < len; i++) {
+ // Data bits
+ b = cmd[i];
+ for(j = 0; j < 8; j++) {
+ if(b & 1) {
+ // Sequence X
+ Sequence(SEC_X);
+ last = 1;
+ } else {
+ if(last == 0) {
+ // Sequence Z
+ Sequence(SEC_Z);
+ }
+ else {
+ // Sequence Y
+ Sequence(SEC_Y);
+ last = 0;
+ }
+ }
+ b >>= 1;
+
+ }
+
+ // Predefined parity bit, the flipper flips when needed, because of flips in byte sent
+ if(((parity >> (len - i - 1)) & 1)) {
+ // Sequence X
+ Sequence(SEC_X);
+ last = 1;
+ } else {
+ if(last == 0) {
+ // Sequence Z
+ Sequence(SEC_Z);
+ }
+ else {
+ // Sequence Y
+ Sequence(SEC_Y);
+ last = 0;
+ }
+ }
+ }
+
+ // End of Communication
+ if(last == 0) {
+ // Sequence Z
+ Sequence(SEC_Z);
+ }
+ else {
+ // Sequence Y
+ Sequence(SEC_Y);
+ last = 0;
+ }
+ // Sequence Y
+ Sequence(SEC_Y);
+
+ // Just to be sure!
+ Sequence(SEC_Y);
+ Sequence(SEC_Y);
+ Sequence(SEC_Y);
+
+ // Convert from last character reference to length
+ ToSendMax++;
+}
+
+//-----------------------------------------------------------------------------
+// Code a 7-bit command without parity bit
+// This is especially for 0x26 and 0x52 (REQA and WUPA)
+//-----------------------------------------------------------------------------
+void ShortFrameFromReader(const BYTE bt)
+{
+ int j;
+ int last;
+ BYTE b;
+
+ ToSendReset();
+
+ // Start of Communication (Seq. Z)
+ Sequence(SEC_Z);
+ last = 0;
+
+ b = bt;
+ for(j = 0; j < 7; j++) {
+ if(b & 1) {
+ // Sequence X
+ Sequence(SEC_X);
+ last = 1;
+ } else {
+ if(last == 0) {
+ // Sequence Z
+ Sequence(SEC_Z);
+ }
+ else {
+ // Sequence Y
+ Sequence(SEC_Y);
+ last = 0;
+ }
+ }
+ b >>= 1;
+ }
+
+ // End of Communication
+ if(last == 0) {
+ // Sequence Z
+ Sequence(SEC_Z);
+ }
+ else {
+ // Sequence Y
+ Sequence(SEC_Y);
+ last = 0;
+ }
+ // Sequence Y
+ Sequence(SEC_Y);
+
+ // Just to be sure!
+ Sequence(SEC_Y);
+ Sequence(SEC_Y);
+ Sequence(SEC_Y);
+
+ // Convert from last character reference to length
+ ToSendMax++;
+}
+
+//-----------------------------------------------------------------------------
+// Prepare reader command to send to FPGA
+//
+//-----------------------------------------------------------------------------
+void CodeIso14443aAsReaderPar(const BYTE * cmd, int len, DWORD dwParity)
+{
+ int i, j;
+ int last;
+ BYTE b;
+
+ ToSendReset();
+
+ // Start of Communication (Seq. Z)
+ Sequence(SEC_Z);
+ last = 0;
+
+ // Generate send structure for the data bits
+ for (i = 0; i < len; i++) {
+ // Get the current byte to send
+ b = cmd[i];
+
+ for (j = 0; j < 8; j++) {
+ if (b & 1) {
+ // Sequence X
+ Sequence(SEC_X);
+ last = 1;
+ } else {
+ if (last == 0) {
+ // Sequence Z
+ Sequence(SEC_Z);
+ } else {
+ // Sequence Y
+ Sequence(SEC_Y);
+ last = 0;
+ }
+ }
+ b >>= 1;
+ }
+
+ // Get the parity bit
+ if ((dwParity >> i) & 0x01) {
+ // Sequence X
+ Sequence(SEC_X);
+ last = 1;
+ } else {
+ if (last == 0) {
+ // Sequence Z
+ Sequence(SEC_Z);
+ } else {
+ // Sequence Y
+ Sequence(SEC_Y);
+ last = 0;
+ }
+ }
+ }
+
+ // End of Communication
+ if (last == 0) {
+ // Sequence Z
+ Sequence(SEC_Z);
+ } else {
+ // Sequence Y
+ Sequence(SEC_Y);
+ last = 0;
+ }
+ // Sequence Y
+ Sequence(SEC_Y);
+
+ // Just to be sure!
+ Sequence(SEC_Y);
+ Sequence(SEC_Y);
+ Sequence(SEC_Y);
+
+ // Convert from last character reference to length
+ ToSendMax++;
+}
+
+//-----------------------------------------------------------------------------
+// Wait a certain time for tag response
+// If a response is captured return TRUE
+// If it takes to long return FALSE
+//-----------------------------------------------------------------------------
+static BOOL GetIso14443aAnswerFromTag(BYTE *receivedResponse, int maxLen, int *samples, int *elapsed) //BYTE *buffer
+{
+ // buffer needs to be 512 bytes
+ int c;
+
+ // Set FPGA mode to "reader listen mode", no modulation (listen
+ // only, since we are receiving, not transmitting).
+ // Signal field is on with the appropriate LED
+ LED_D_ON();
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_LISTEN);
+
+ // Now get the answer from the card
+ Demod.output = receivedResponse;
+ Demod.len = 0;
+ Demod.state = DEMOD_UNSYNCD;
+
+ BYTE b;
+ if (elapsed) *elapsed = 0;
+
+ c = 0;
+ for(;;) {
+ WDT_HIT();
+
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
+ AT91C_BASE_SSC->SSC_THR = 0x00; // To make use of exact timing of next command from reader!!
+ if (elapsed) (*elapsed)++;
+ }
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
+ if(c < 512) { c++; } else { return FALSE; }
+ b = (BYTE)AT91C_BASE_SSC->SSC_RHR;
+ if(ManchesterDecoding((b & 0xf0) >> 4)) {
+ *samples = ((c - 1) << 3) + 4;
+ return TRUE;
+ }
+ if(ManchesterDecoding(b & 0x0f)) {
+ *samples = c << 3;
+ return TRUE;
+ }
+ }
+ }
+}
+
+void ReaderTransmitShort(const BYTE* bt)
+{
+ int wait = 0;
+ int samples = 0;
+
+ ShortFrameFromReader(*bt);
+
+ // Select the card
+ TransmitFor14443a(ToSend, ToSendMax, &samples, &wait);
+
+ // Store reader command in buffer
+ if (tracing) LogTrace(bt,1,0,GetParity(bt,1),TRUE);
+}
+
+void ReaderTransmitPar(BYTE* frame, int len, DWORD par)
+{
+ int wait = 0;
+ int samples = 0;
+
+ // This is tied to other size changes
+ // BYTE* frame_addr = ((BYTE*)BigBuf) + 2024;
+ CodeIso14443aAsReaderPar(frame,len,par);
+
+ // Select the card
+ TransmitFor14443a(ToSend, ToSendMax, &samples, &wait);
+
+ // Store reader command in buffer
+ if (tracing) LogTrace(frame,len,0,par,TRUE);
+}
+
+
+void ReaderTransmit(BYTE* frame, int len)
+{
+ // Generate parity and redirect
+ ReaderTransmitPar(frame,len,GetParity(frame,len));
+}
+
+BOOL ReaderReceive(BYTE* receivedAnswer)
+{
+ int samples = 0;
+ if (!GetIso14443aAnswerFromTag(receivedAnswer,100,&samples,0)) return FALSE;
+ if (tracing) LogTrace(receivedAnswer,Demod.len,samples,Demod.parityBits,FALSE);
+ return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// Read an ISO 14443a tag. Send out commands and store answers.
+//
+//-----------------------------------------------------------------------------
+void ReaderIso14443a(DWORD parameter)
+{
+ // Anticollision
+ BYTE wupa[] = { 0x52 };
+ BYTE sel_all[] = { 0x93,0x20 };
+ BYTE sel_uid[] = { 0x93,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
+ BYTE sel_all_c2[] = { 0x95,0x20 };
+ BYTE sel_uid_c2[] = { 0x95,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
+
+ // Mifare AUTH
+ BYTE mf_auth[] = { 0x60,0x00,0xf5,0x7b };
+// BYTE mf_nr_ar[] = { 0x00,0x00,0x00,0x00 };
+
+ BYTE* receivedAnswer = (((BYTE *)BigBuf) + 3560); // was 3560 - tied to other size changes
+ traceLen = 0;
+
+ // Setup SSC
+ FpgaSetupSsc();
+
+ // Start from off (no field generated)
+ // Signal field is off with the appropriate LED
+ LED_D_OFF();
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+ SpinDelay(200);
+
+ SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
+ FpgaSetupSsc();
+
+ // Now give it time to spin up.
+ // Signal field is on with the appropriate LED
+ LED_D_ON();
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);
+ SpinDelay(200);
+
+ LED_A_ON();
+ LED_B_OFF();
+ LED_C_OFF();
+
+ while(traceLen < TRACE_LENGTH)
+ {
+ // Broadcast for a card, WUPA (0x52) will force response from all cards in the field
+ ReaderTransmitShort(wupa);
+
+ // Test if the action was cancelled
+ if(BUTTON_PRESS()) {
+ break;
+ }
+
+ // Receive the ATQA
+ if (!ReaderReceive(receivedAnswer)) continue;
+
+ // Transmit SELECT_ALL
+ ReaderTransmit(sel_all,sizeof(sel_all));
+
+ // Receive the UID
+ if (!ReaderReceive(receivedAnswer)) continue;
+
+ // Construct SELECT UID command
+ // First copy the 5 bytes (Mifare Classic) after the 93 70
+ memcpy(sel_uid+2,receivedAnswer,5);
+ // Secondly compute the two CRC bytes at the end
+ AppendCrc14443a(sel_uid,7);
+
+ // Transmit SELECT_UID
+ ReaderTransmit(sel_uid,sizeof(sel_uid));
+
+ // Receive the SAK
+ if (!ReaderReceive(receivedAnswer)) continue;
+
+ // OK we have selected at least at cascade 1, lets see if first byte of UID was 0x88 in
+ // which case we need to make a cascade 2 request and select - this is a long UID
+ // When the UID is not complete, the 3nd bit (from the right) is set in the SAK.
+ if (receivedAnswer[0] &= 0x04)
+ {
+ // Transmit SELECT_ALL
+ ReaderTransmit(sel_all_c2,sizeof(sel_all_c2));
+
+ // Receive the UID
+ if (!ReaderReceive(receivedAnswer)) continue;
+
+ // Construct SELECT UID command
+ memcpy(sel_uid_c2+2,receivedAnswer,5);
+ // Secondly compute the two CRC bytes at the end
+ AppendCrc14443a(sel_uid_c2,7);
+
+ // Transmit SELECT_UID
+ ReaderTransmit(sel_uid_c2,sizeof(sel_uid_c2));
+
+ // Receive the SAK
+ if (!ReaderReceive(receivedAnswer)) continue;
+ }
+
+ // Transmit MIFARE_CLASSIC_AUTH
+ ReaderTransmit(mf_auth,sizeof(mf_auth));
+
+ // Receive the (16 bit) "random" nonce
+ if (!ReaderReceive(receivedAnswer)) continue;
+ }
+
+ // Thats it...
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+ LEDsoff();
+ Dbprintf("%x %x %x", rsamples, 0xCC, 0xCC);
+ DbpString("ready..");
+}
+
+//-----------------------------------------------------------------------------
+// Read an ISO 14443a tag. Send out commands and store answers.
+//
+//-----------------------------------------------------------------------------
+void ReaderMifare(DWORD parameter)
+{
+
+ // Anticollision
+ BYTE wupa[] = { 0x52 };
+ BYTE sel_all[] = { 0x93,0x20 };
+ BYTE sel_uid[] = { 0x93,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
+
+ // Mifare AUTH
+ BYTE mf_auth[] = { 0x60,0x00,0xf5,0x7b };
+ BYTE mf_nr_ar[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
+
+ BYTE* receivedAnswer = (((BYTE *)BigBuf) + 3560); // was 3560 - tied to other size changes
+ traceLen = 0;
+ tracing = false;
+
+ // Setup SSC
+ FpgaSetupSsc();
+
+ // Start from off (no field generated)
+ // Signal field is off with the appropriate LED
+ LED_D_OFF();
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+ SpinDelay(200);
+
+ SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
+ FpgaSetupSsc();
+
+ // Now give it time to spin up.
+ // Signal field is on with the appropriate LED
+ LED_D_ON();
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);
+ SpinDelay(200);
+
+ LED_A_ON();
+ LED_B_OFF();
+ LED_C_OFF();
+
+ // Broadcast for a card, WUPA (0x52) will force response from all cards in the field
+ ReaderTransmitShort(wupa);
+ // Receive the ATQA
+ ReaderReceive(receivedAnswer);
+ // Transmit SELECT_ALL
+ ReaderTransmit(sel_all,sizeof(sel_all));
+ // Receive the UID
+ ReaderReceive(receivedAnswer);
+ // Construct SELECT UID command
+ // First copy the 5 bytes (Mifare Classic) after the 93 70
+ memcpy(sel_uid+2,receivedAnswer,5);
+ // Secondly compute the two CRC bytes at the end
+ AppendCrc14443a(sel_uid,7);
+
+ byte_t nt_diff = 0;
+ LED_A_OFF();
+ byte_t par = 0;
+ byte_t par_mask = 0xff;
+ byte_t par_low = 0;
+ BOOL led_on = TRUE;
+
+ tracing = FALSE;
+ byte_t nt[4];
+ byte_t nt_attacked[4];
+ byte_t par_list[8];
+ byte_t ks_list[8];
+ num_to_bytes(parameter,4,nt_attacked);
+
+ while(TRUE)
+ {
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+ SpinDelay(200);
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);
+
+ // Broadcast for a card, WUPA (0x52) will force response from all cards in the field
+ ReaderTransmitShort(wupa);
+
+ // Test if the action was cancelled
+ if(BUTTON_PRESS()) {
+ break;
+ }
+
+ // Receive the ATQA
+ if (!ReaderReceive(receivedAnswer)) continue;
+
+ // Transmit SELECT_ALL
+ ReaderTransmit(sel_all,sizeof(sel_all));
+
+ // Receive the UID
+ if (!ReaderReceive(receivedAnswer)) continue;
+
+ // Transmit SELECT_UID
+ ReaderTransmit(sel_uid,sizeof(sel_uid));
+
+ // Receive the SAK
+ if (!ReaderReceive(receivedAnswer)) continue;
+
+ // Transmit MIFARE_CLASSIC_AUTH
+ ReaderTransmit(mf_auth,sizeof(mf_auth));
+
+ // Receive the (16 bit) "random" nonce
+ if (!ReaderReceive(receivedAnswer)) continue;
+ memcpy(nt,receivedAnswer,4);
+
+ // Transmit reader nonce and reader answer
+ ReaderTransmitPar(mf_nr_ar,sizeof(mf_nr_ar),par);
+
+ // Receive 4 bit answer
+ if (ReaderReceive(receivedAnswer))
+ {
+ if (nt_diff == 0)
+ {
+ LED_A_ON();
+ memcpy(nt_attacked,nt,4);
+ par_mask = 0xf8;
+ par_low = par & 0x07;
+ }
+
+ if (memcmp(nt,nt_attacked,4) != 0) continue;
+
+ led_on = !led_on;
+ if(led_on) LED_B_ON(); else LED_B_OFF();
+ par_list[nt_diff] = par;
+ ks_list[nt_diff] = receivedAnswer[0]^0x05;
+
+ // Test if the information is complete
+ if (nt_diff == 0x07) break;
+
+ nt_diff = (nt_diff+1) & 0x07;
+ mf_nr_ar[3] = nt_diff << 5;
+ par = par_low;
+ } else {
+ if (nt_diff == 0)
+ {
+ par++;
+ } else {
+ par = (((par>>3)+1) << 3) | par_low;
+ }
+ }
+ }
+
+ LogTraceInfo(sel_uid+2,4);
+ LogTraceInfo(nt,4);
+ LogTraceInfo(par_list,8);
+ LogTraceInfo(ks_list,8);
+
+ // Thats it...
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+ LEDsoff();
+ tracing = TRUE;
+}
-//-----------------------------------------------------------------------------\r
-// Routines to support ISO 15693. This includes both the reader software and\r
-// the `fake tag' modes, but at the moment I've implemented only the reader\r
-// stuff, and that barely.\r
-// Jonathan Westhues, split Nov 2006\r
-\r
-// Modified by Greg Jones, Jan 2009 to perform modulation onboard in arm rather than on PC\r
-// Also added additional reader commands (SELECT, READ etc.)\r
-\r
-//-----------------------------------------------------------------------------\r
-#include <proxmark3.h>\r
-#include "apps.h"\r
-\r
-// FROM winsrc\prox.h //////////////////////////////////\r
-#define arraylen(x) (sizeof(x)/sizeof((x)[0]))\r
-\r
-//-----------------------------------------------------------------------------\r
-// Map a sequence of octets (~layer 2 command) into the set of bits to feed\r
-// to the FPGA, to transmit that command to the tag.\r
-//-----------------------------------------------------------------------------\r
-\r
- // The sampling rate is 106.353 ksps/s, for T = 18.8 us\r
-\r
- // SOF defined as\r
- // 1) Unmodulated time of 56.64us\r
- // 2) 24 pulses of 423.75khz\r
- // 3) logic '1' (unmodulated for 18.88us followed by 8 pulses of 423.75khz)\r
-\r
- static const int FrameSOF[] = {\r
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
- -1, -1, -1, -1,\r
- -1, -1, -1, -1,\r
- 1, 1, 1, 1,\r
- 1, 1, 1, 1\r
- };\r
- static const int Logic0[] = {\r
- 1, 1, 1, 1,\r
- 1, 1, 1, 1,\r
- -1, -1, -1, -1,\r
- -1, -1, -1, -1\r
- };\r
- static const int Logic1[] = {\r
- -1, -1, -1, -1,\r
- -1, -1, -1, -1,\r
- 1, 1, 1, 1,\r
- 1, 1, 1, 1\r
- };\r
-\r
- // EOF defined as\r
- // 1) logic '0' (8 pulses of 423.75khz followed by unmodulated for 18.88us)\r
- // 2) 24 pulses of 423.75khz\r
- // 3) Unmodulated time of 56.64us\r
-\r
- static const int FrameEOF[] = {\r
- 1, 1, 1, 1,\r
- 1, 1, 1, 1,\r
- -1, -1, -1, -1,\r
- -1, -1, -1, -1,\r
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1\r
- };\r
-\r
-static void CodeIso15693AsReader(BYTE *cmd, int n)\r
-{\r
- int i, j;\r
-\r
- ToSendReset();\r
-\r
- // Give it a bit of slack at the beginning\r
- for(i = 0; i < 24; i++) {\r
- ToSendStuffBit(1);\r
- }\r
-\r
- ToSendStuffBit(0);\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(0);\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- for(i = 0; i < n; i++) {\r
- for(j = 0; j < 8; j += 2) {\r
- int these = (cmd[i] >> j) & 3;\r
- switch(these) {\r
- case 0:\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(0);\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- break;\r
- case 1:\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(0);\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- break;\r
- case 2:\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(0);\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- break;\r
- case 3:\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(0);\r
- break;\r
- }\r
- }\r
- }\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(1);\r
- ToSendStuffBit(0);\r
- ToSendStuffBit(1);\r
-\r
- // And slack at the end, too.\r
- for(i = 0; i < 24; i++) {\r
- ToSendStuffBit(1);\r
- }\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-// The CRC used by ISO 15693.\r
-//-----------------------------------------------------------------------------\r
-static WORD Crc(BYTE *v, int n)\r
-{\r
- DWORD reg;\r
- int i, j;\r
-\r
- reg = 0xffff;\r
- for(i = 0; i < n; i++) {\r
- reg = reg ^ ((DWORD)v[i]);\r
- for (j = 0; j < 8; j++) {\r
- if (reg & 0x0001) {\r
- reg = (reg >> 1) ^ 0x8408;\r
- } else {\r
- reg = (reg >> 1);\r
- }\r
- }\r
- }\r
-\r
- return ~reg;\r
-}\r
-\r
-char *strcat(char *dest, const char *src)\r
-{\r
- size_t dest_len = strlen(dest);\r
- size_t i;\r
- \r
- for (i = 0 ; src[i] != '\0' ; i++)\r
- dest[dest_len + i] = src[i];\r
- dest[dest_len + i] = '\0';\r
- \r
- return dest;\r
-}\r
-\r
-////////////////////////////////////////// code to do 'itoa'\r
-\r
-/* reverse: reverse string s in place */\r
-void reverse(char s[])\r
-{\r
- int c, i, j;\r
-\r
- for (i = 0, j = strlen(s)-1; i<j; i++, j--) {\r
- c = s[i];\r
- s[i] = s[j];\r
- s[j] = c;\r
- }\r
-}\r
-\r
-/* itoa: convert n to characters in s */\r
-void itoa(int n, char s[])\r
-{\r
- int i, sign;\r
-\r
- if ((sign = n) < 0) /* record sign */\r
- n = -n; /* make n positive */\r
- i = 0;\r
- do { /* generate digits in reverse order */\r
- s[i++] = n % 10 + '0'; /* get next digit */\r
- } while ((n /= 10) > 0); /* delete it */\r
- if (sign < 0)\r
- s[i++] = '-';\r
- s[i] = '\0';\r
- reverse(s);\r
-}\r
-\r
-//////////////////////////////////////// END 'itoa' CODE\r
-\r
-//-----------------------------------------------------------------------------\r
-// Encode (into the ToSend buffers) an identify request, which is the first\r
-// thing that you must send to a tag to get a response.\r
-//-----------------------------------------------------------------------------\r
-static void BuildIdentifyRequest(void)\r
-{\r
- BYTE cmd[5];\r
-\r
- WORD crc;\r
- // one sub-carrier, inventory, 1 slot, fast rate\r
- // AFI is at bit 5 (1<<4) when doing an INVENTORY\r
- cmd[0] = (1 << 2) | (1 << 5) | (1 << 1);\r
- // inventory command code\r
- cmd[1] = 0x01;\r
- // no mask\r
- cmd[2] = 0x00;\r
- //Now the CRC\r
- crc = Crc(cmd, 3);\r
- cmd[3] = crc & 0xff;\r
- cmd[4] = crc >> 8;\r
-\r
- CodeIso15693AsReader(cmd, sizeof(cmd));\r
-}\r
-\r
-static void __attribute__((unused)) BuildSysInfoRequest(BYTE *uid)\r
-{\r
- BYTE cmd[12];\r
-\r
- WORD crc;\r
- // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block\r
- // followed by teh block data\r
- // one sub-carrier, inventory, 1 slot, fast rate\r
- cmd[0] = (1 << 5) | (1 << 1); // no SELECT bit\r
- // System Information command code\r
- cmd[1] = 0x2B;\r
- // UID may be optionally specified here\r
- // 64-bit UID\r
- cmd[2] = 0x32;\r
- cmd[3]= 0x4b;\r
- cmd[4] = 0x03;\r
- cmd[5] = 0x01;\r
- cmd[6] = 0x00;\r
- cmd[7] = 0x10;\r
- cmd[8] = 0x05;\r
- cmd[9]= 0xe0; // always e0 (not exactly unique)\r
- //Now the CRC\r
- crc = Crc(cmd, 10); // the crc needs to be calculated over 2 bytes\r
- cmd[10] = crc & 0xff;\r
- cmd[11] = crc >> 8;\r
-\r
- CodeIso15693AsReader(cmd, sizeof(cmd));\r
-}\r
-\r
-static void BuildSelectRequest( BYTE uid[])\r
-{\r
-\r
-// uid[6]=0x31; // this is getting ignored - the uid array is not happening...\r
- BYTE cmd[12];\r
-\r
- WORD crc;\r
- // one sub-carrier, inventory, 1 slot, fast rate\r
- //cmd[0] = (1 << 2) | (1 << 5) | (1 << 1); // INVENTROY FLAGS\r
- cmd[0] = (1 << 4) | (1 << 5) | (1 << 1); // Select and addressed FLAGS\r
- // SELECT command code\r
- cmd[1] = 0x25;\r
- // 64-bit UID\r
-// cmd[2] = uid[0];//0x32;\r
-// cmd[3]= uid[1];//0x4b;\r
-// cmd[4] = uid[2];//0x03;\r
-// cmd[5] = uid[3];//0x01;\r
-// cmd[6] = uid[4];//0x00;\r
-// cmd[7] = uid[5];//0x10;\r
-// cmd[8] = uid[6];//0x05;\r
- cmd[2] = 0x32;//\r
- cmd[3] = 0x4b;\r
- cmd[4] = 0x03;\r
- cmd[5] = 0x01;\r
- cmd[6] = 0x00;\r
- cmd[7] = 0x10;\r
- cmd[8] = 0x05; // infineon?\r
-\r
- cmd[9]= 0xe0; // always e0 (not exactly unique)\r
-\r
-// DbpIntegers(cmd[8],cmd[7],cmd[6]);\r
- // Now the CRC\r
- crc = Crc(cmd, 10); // the crc needs to be calculated over 10 bytes\r
- cmd[10] = crc & 0xff;\r
- cmd[11] = crc >> 8;\r
-\r
- CodeIso15693AsReader(cmd, sizeof(cmd));\r
-}\r
-\r
-static void __attribute__((unused)) BuildReadBlockRequest(BYTE *uid, BYTE blockNumber )\r
-{\r
- BYTE cmd[13];\r
-\r
- WORD crc;\r
- // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block\r
- // followed by teh block data\r
- // one sub-carrier, inventory, 1 slot, fast rate\r
- cmd[0] = (1 << 6)| (1 << 5) | (1 << 1); // no SELECT bit\r
- // READ BLOCK command code\r
- cmd[1] = 0x20;\r
- // UID may be optionally specified here\r
- // 64-bit UID\r
- cmd[2] = 0x32;\r
- cmd[3]= 0x4b;\r
- cmd[4] = 0x03;\r
- cmd[5] = 0x01;\r
- cmd[6] = 0x00;\r
- cmd[7] = 0x10;\r
- cmd[8] = 0x05;\r
- cmd[9]= 0xe0; // always e0 (not exactly unique)\r
- // Block number to read\r
- cmd[10] = blockNumber;//0x00;\r
- //Now the CRC\r
- crc = Crc(cmd, 11); // the crc needs to be calculated over 2 bytes\r
- cmd[11] = crc & 0xff;\r
- cmd[12] = crc >> 8;\r
-\r
- CodeIso15693AsReader(cmd, sizeof(cmd));\r
-}\r
-\r
-static void __attribute__((unused)) BuildReadMultiBlockRequest(BYTE *uid)\r
-{\r
- BYTE cmd[14];\r
-\r
- WORD crc;\r
- // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block\r
- // followed by teh block data\r
- // one sub-carrier, inventory, 1 slot, fast rate\r
- cmd[0] = (1 << 5) | (1 << 1); // no SELECT bit\r
- // READ Multi BLOCK command code\r
- cmd[1] = 0x23;\r
- // UID may be optionally specified here\r
- // 64-bit UID\r
- cmd[2] = 0x32;\r
- cmd[3]= 0x4b;\r
- cmd[4] = 0x03;\r
- cmd[5] = 0x01;\r
- cmd[6] = 0x00;\r
- cmd[7] = 0x10;\r
- cmd[8] = 0x05;\r
- cmd[9]= 0xe0; // always e0 (not exactly unique)\r
- // First Block number to read\r
- cmd[10] = 0x00;\r
- // Number of Blocks to read\r
- cmd[11] = 0x2f; // read quite a few\r
- //Now the CRC\r
- crc = Crc(cmd, 12); // the crc needs to be calculated over 2 bytes\r
- cmd[12] = crc & 0xff;\r
- cmd[13] = crc >> 8;\r
-\r
- CodeIso15693AsReader(cmd, sizeof(cmd));\r
-}\r
-\r
-static void __attribute__((unused)) BuildArbitraryRequest(BYTE *uid,BYTE CmdCode)\r
-{\r
- BYTE cmd[14];\r
-\r
- WORD crc;\r
- // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block\r
- // followed by teh block data\r
- // one sub-carrier, inventory, 1 slot, fast rate\r
- cmd[0] = (1 << 5) | (1 << 1); // no SELECT bit\r
- // READ BLOCK command code\r
- cmd[1] = CmdCode;\r
- // UID may be optionally specified here\r
- // 64-bit UID\r
- cmd[2] = 0x32;\r
- cmd[3]= 0x4b;\r
- cmd[4] = 0x03;\r
- cmd[5] = 0x01;\r
- cmd[6] = 0x00;\r
- cmd[7] = 0x10;\r
- cmd[8] = 0x05;\r
- cmd[9]= 0xe0; // always e0 (not exactly unique)\r
- // Parameter\r
- cmd[10] = 0x00;\r
- cmd[11] = 0x0a;\r
-\r
-// cmd[12] = 0x00;\r
-// cmd[13] = 0x00; //Now the CRC\r
- crc = Crc(cmd, 12); // the crc needs to be calculated over 2 bytes\r
- cmd[12] = crc & 0xff;\r
- cmd[13] = crc >> 8;\r
-\r
- CodeIso15693AsReader(cmd, sizeof(cmd));\r
-}\r
-\r
-static void __attribute__((unused)) BuildArbitraryCustomRequest(BYTE uid[], BYTE CmdCode)\r
-{\r
- BYTE cmd[14];\r
-\r
- WORD crc;\r
- // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block\r
- // followed by teh block data\r
- // one sub-carrier, inventory, 1 slot, fast rate\r
- cmd[0] = (1 << 5) | (1 << 1); // no SELECT bit\r
- // READ BLOCK command code\r
- cmd[1] = CmdCode;\r
- // UID may be optionally specified here\r
- // 64-bit UID\r
- cmd[2] = 0x32;\r
- cmd[3]= 0x4b;\r
- cmd[4] = 0x03;\r
- cmd[5] = 0x01;\r
- cmd[6] = 0x00;\r
- cmd[7] = 0x10;\r
- cmd[8] = 0x05;\r
- cmd[9]= 0xe0; // always e0 (not exactly unique)\r
- // Parameter\r
- cmd[10] = 0x05; // for custom codes this must be manufcturer code\r
- cmd[11] = 0x00;\r
-\r
-// cmd[12] = 0x00;\r
-// cmd[13] = 0x00; //Now the CRC\r
- crc = Crc(cmd, 12); // the crc needs to be calculated over 2 bytes\r
- cmd[12] = crc & 0xff;\r
- cmd[13] = crc >> 8;\r
-\r
- CodeIso15693AsReader(cmd, sizeof(cmd));\r
-}\r
-\r
-/////////////////////////////////////////////////////////////////////////\r
-// Now the VICC>VCD responses when we are simulating a tag\r
-////////////////////////////////////////////////////////////////////\r
-\r
- static void BuildInventoryResponse(void)\r
-{\r
- BYTE cmd[12];\r
-\r
- WORD crc;\r
- // one sub-carrier, inventory, 1 slot, fast rate\r
- // AFI is at bit 5 (1<<4) when doing an INVENTORY\r
- cmd[0] = 0; //(1 << 2) | (1 << 5) | (1 << 1);\r
- cmd[1] = 0;\r
- // 64-bit UID\r
- cmd[2] = 0x32;\r
- cmd[3]= 0x4b;\r
- cmd[4] = 0x03;\r
- cmd[5] = 0x01;\r
- cmd[6] = 0x00;\r
- cmd[7] = 0x10;\r
- cmd[8] = 0x05;\r
- cmd[9]= 0xe0;\r
- //Now the CRC\r
- crc = Crc(cmd, 10);\r
- cmd[10] = crc & 0xff;\r
- cmd[11] = crc >> 8;\r
-\r
- CodeIso15693AsReader(cmd, sizeof(cmd));\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-// Transmit the command (to the tag) that was placed in ToSend[].\r
-//-----------------------------------------------------------------------------\r
-static void TransmitTo15693Tag(const BYTE *cmd, int len, int *samples, int *wait)\r
-{\r
- int c;\r
-\r
-// FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX);\r
- if(*wait < 10) { *wait = 10; }\r
-\r
-// for(c = 0; c < *wait;) {\r
-// if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {\r
-// AT91C_BASE_SSC->SSC_THR = 0x00; // For exact timing!\r
-// c++;\r
-// }\r
-// if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {\r
-// volatile DWORD r = AT91C_BASE_SSC->SSC_RHR;\r
-// (void)r;\r
-// }\r
-// WDT_HIT();\r
-// }\r
-\r
- c = 0;\r
- for(;;) {\r
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {\r
- AT91C_BASE_SSC->SSC_THR = cmd[c];\r
- c++;\r
- if(c >= len) {\r
- break;\r
- }\r
- }\r
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {\r
- volatile DWORD r = AT91C_BASE_SSC->SSC_RHR;\r
- (void)r;\r
- }\r
- WDT_HIT();\r
- }\r
- *samples = (c + *wait) << 3;\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-// Transmit the command (to the reader) that was placed in ToSend[].\r
-//-----------------------------------------------------------------------------\r
-static void TransmitTo15693Reader(const BYTE *cmd, int len, int *samples, int *wait)\r
-{\r
- int c;\r
-\r
-// FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX);\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR); // No requirement to energise my coils\r
- if(*wait < 10) { *wait = 10; }\r
-\r
- c = 0;\r
- for(;;) {\r
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {\r
- AT91C_BASE_SSC->SSC_THR = cmd[c];\r
- c++;\r
- if(c >= len) {\r
- break;\r
- }\r
- }\r
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {\r
- volatile DWORD r = AT91C_BASE_SSC->SSC_RHR;\r
- (void)r;\r
- }\r
- WDT_HIT();\r
- }\r
- *samples = (c + *wait) << 3;\r
-}\r
-\r
-static int GetIso15693AnswerFromTag(BYTE *receivedResponse, int maxLen, int *samples, int *elapsed)\r
-{\r
- int c = 0;\r
- BYTE *dest = (BYTE *)BigBuf;\r
- int getNext = 0;\r
-\r
- SBYTE prev = 0;\r
-\r
-// NOW READ RESPONSE\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);\r
- //spindelay(60); // greg - experiment to get rid of some of the 0 byte/failed reads\r
- c = 0;\r
- getNext = FALSE;\r
- for(;;) {\r
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {\r
- AT91C_BASE_SSC->SSC_THR = 0x43;\r
- }\r
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {\r
- SBYTE b;\r
- b = (SBYTE)AT91C_BASE_SSC->SSC_RHR;\r
-\r
- // The samples are correlations against I and Q versions of the\r
- // tone that the tag AM-modulates, so every other sample is I,\r
- // every other is Q. We just want power, so abs(I) + abs(Q) is\r
- // close to what we want.\r
- if(getNext) {\r
- SBYTE r;\r
-\r
- if(b < 0) {\r
- r = -b;\r
- } else {\r
- r = b;\r
- }\r
- if(prev < 0) {\r
- r -= prev;\r
- } else {\r
- r += prev;\r
- }\r
-\r
- dest[c++] = (BYTE)r;\r
-\r
- if(c >= 2000) {\r
- break;\r
- }\r
- } else {\r
- prev = b;\r
- }\r
-\r
- getNext = !getNext;\r
- }\r
- }\r
-\r
-//////////////////////////////////////////\r
-/////////// DEMODULATE ///////////////////\r
-//////////////////////////////////////////\r
-\r
- int i, j;\r
- int max = 0, maxPos=0;\r
-\r
- int skip = 4;\r
-\r
-// if(GraphTraceLen < 1000) return; // THIS CHECKS FOR A BUFFER TO SMALL\r
-\r
- // First, correlate for SOF\r
- for(i = 0; i < 100; i++) {\r
- int corr = 0;\r
- for(j = 0; j < arraylen(FrameSOF); j += skip) {\r
- corr += FrameSOF[j]*dest[i+(j/skip)];\r
- }\r
- if(corr > max) {\r
- max = corr;\r
- maxPos = i;\r
- }\r
- }\r
-// DbpString("SOF at %d, correlation %d", maxPos,max/(arraylen(FrameSOF)/skip));\r
-\r
- int k = 0; // this will be our return value\r
-\r
- // greg - If correlation is less than 1 then there's little point in continuing\r
- if ((max/(arraylen(FrameSOF)/skip)) >= 1)\r
- {\r
-\r
- i = maxPos + arraylen(FrameSOF)/skip;\r
-\r
- BYTE outBuf[20];\r
- memset(outBuf, 0, sizeof(outBuf));\r
- BYTE mask = 0x01;\r
- for(;;) {\r
- int corr0 = 0, corr1 = 0, corrEOF = 0;\r
- for(j = 0; j < arraylen(Logic0); j += skip) {\r
- corr0 += Logic0[j]*dest[i+(j/skip)];\r
- }\r
- for(j = 0; j < arraylen(Logic1); j += skip) {\r
- corr1 += Logic1[j]*dest[i+(j/skip)];\r
- }\r
- for(j = 0; j < arraylen(FrameEOF); j += skip) {\r
- corrEOF += FrameEOF[j]*dest[i+(j/skip)];\r
- }\r
- // Even things out by the length of the target waveform.\r
- corr0 *= 4;\r
- corr1 *= 4;\r
-\r
- if(corrEOF > corr1 && corrEOF > corr0) {\r
-// DbpString("EOF at %d", i);\r
- break;\r
- } else if(corr1 > corr0) {\r
- i += arraylen(Logic1)/skip;\r
- outBuf[k] |= mask;\r
- } else {\r
- i += arraylen(Logic0)/skip;\r
- }\r
- mask <<= 1;\r
- if(mask == 0) {\r
- k++;\r
- mask = 0x01;\r
- }\r
- if((i+(int)arraylen(FrameEOF)) >= 2000) {\r
- DbpString("ran off end!");\r
- break;\r
- }\r
- }\r
- if(mask != 0x01) {\r
- DbpString("error, uneven octet! (discard extra bits!)");\r
-/// DbpString(" mask=%02x", mask);\r
- }\r
-// BYTE str1 [8];\r
-// itoa(k,str1);\r
-// strcat(str1," octets read");\r
-\r
-// DbpString( str1); // DbpString("%d octets", k);\r
-\r
-// for(i = 0; i < k; i+=3) {\r
-// //DbpString("# %2d: %02x ", i, outBuf[i]);\r
-// DbpIntegers(outBuf[i],outBuf[i+1],outBuf[i+2]);\r
-// }\r
-\r
- for(i = 0; i < k; i++) {\r
- receivedResponse[i] = outBuf[i];\r
- }\r
- } // "end if correlation > 0" (max/(arraylen(FrameSOF)/skip))\r
- return k; // return the number of bytes demodulated\r
-\r
-/// DbpString("CRC=%04x", Iso15693Crc(outBuf, k-2));\r
-\r
-}\r
-\r
-// Now the GetISO15693 message from sniffing command\r
-static int GetIso15693AnswerFromSniff(BYTE *receivedResponse, int maxLen, int *samples, int *elapsed)\r
-{\r
- int c = 0;\r
- BYTE *dest = (BYTE *)BigBuf;\r
- int getNext = 0;\r
-\r
- SBYTE prev = 0;\r
-\r
-// NOW READ RESPONSE\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);\r
- //spindelay(60); // greg - experiment to get rid of some of the 0 byte/failed reads\r
- c = 0;\r
- getNext = FALSE;\r
- for(;;) {\r
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {\r
- AT91C_BASE_SSC->SSC_THR = 0x43;\r
- }\r
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {\r
- SBYTE b;\r
- b = (SBYTE)AT91C_BASE_SSC->SSC_RHR;\r
-\r
- // The samples are correlations against I and Q versions of the\r
- // tone that the tag AM-modulates, so every other sample is I,\r
- // every other is Q. We just want power, so abs(I) + abs(Q) is\r
- // close to what we want.\r
- if(getNext) {\r
- SBYTE r;\r
-\r
- if(b < 0) {\r
- r = -b;\r
- } else {\r
- r = b;\r
- }\r
- if(prev < 0) {\r
- r -= prev;\r
- } else {\r
- r += prev;\r
- }\r
-\r
- dest[c++] = (BYTE)r;\r
-\r
- if(c >= 20000) {\r
- break;\r
- }\r
- } else {\r
- prev = b;\r
- }\r
-\r
- getNext = !getNext;\r
- }\r
- }\r
-\r
-//////////////////////////////////////////\r
-/////////// DEMODULATE ///////////////////\r
-//////////////////////////////////////////\r
-\r
- int i, j;\r
- int max = 0, maxPos=0;\r
-\r
- int skip = 4;\r
-\r
-// if(GraphTraceLen < 1000) return; // THIS CHECKS FOR A BUFFER TO SMALL\r
-\r
- // First, correlate for SOF\r
- for(i = 0; i < 19000; i++) {\r
- int corr = 0;\r
- for(j = 0; j < arraylen(FrameSOF); j += skip) {\r
- corr += FrameSOF[j]*dest[i+(j/skip)];\r
- }\r
- if(corr > max) {\r
- max = corr;\r
- maxPos = i;\r
- }\r
- }\r
-// DbpString("SOF at %d, correlation %d", maxPos,max/(arraylen(FrameSOF)/skip));\r
-\r
- int k = 0; // this will be our return value\r
-\r
- // greg - If correlation is less than 1 then there's little point in continuing\r
- if ((max/(arraylen(FrameSOF)/skip)) >= 1) // THIS SHOULD BE 1\r
- {\r
-\r
- i = maxPos + arraylen(FrameSOF)/skip;\r
-\r
- BYTE outBuf[20];\r
- memset(outBuf, 0, sizeof(outBuf));\r
- BYTE mask = 0x01;\r
- for(;;) {\r
- int corr0 = 0, corr1 = 0, corrEOF = 0;\r
- for(j = 0; j < arraylen(Logic0); j += skip) {\r
- corr0 += Logic0[j]*dest[i+(j/skip)];\r
- }\r
- for(j = 0; j < arraylen(Logic1); j += skip) {\r
- corr1 += Logic1[j]*dest[i+(j/skip)];\r
- }\r
- for(j = 0; j < arraylen(FrameEOF); j += skip) {\r
- corrEOF += FrameEOF[j]*dest[i+(j/skip)];\r
- }\r
- // Even things out by the length of the target waveform.\r
- corr0 *= 4;\r
- corr1 *= 4;\r
-\r
- if(corrEOF > corr1 && corrEOF > corr0) {\r
-// DbpString("EOF at %d", i);\r
- break;\r
- } else if(corr1 > corr0) {\r
- i += arraylen(Logic1)/skip;\r
- outBuf[k] |= mask;\r
- } else {\r
- i += arraylen(Logic0)/skip;\r
- }\r
- mask <<= 1;\r
- if(mask == 0) {\r
- k++;\r
- mask = 0x01;\r
- }\r
- if((i+(int)arraylen(FrameEOF)) >= 2000) {\r
- DbpString("ran off end!");\r
- break;\r
- }\r
- }\r
- if(mask != 0x01) {\r
- DbpString("error, uneven octet! (discard extra bits!)");\r
-/// DbpString(" mask=%02x", mask);\r
- }\r
-// BYTE str1 [8];\r
-// itoa(k,str1);\r
-// strcat(str1," octets read");\r
-\r
-// DbpString( str1); // DbpString("%d octets", k);\r
-\r
-// for(i = 0; i < k; i+=3) {\r
-// //DbpString("# %2d: %02x ", i, outBuf[i]);\r
-// DbpIntegers(outBuf[i],outBuf[i+1],outBuf[i+2]);\r
-// }\r
-\r
- for(i = 0; i < k; i++) {\r
- receivedResponse[i] = outBuf[i];\r
- }\r
- } // "end if correlation > 0" (max/(arraylen(FrameSOF)/skip))\r
- return k; // return the number of bytes demodulated\r
-\r
-/// DbpString("CRC=%04x", Iso15693Crc(outBuf, k-2));\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-// Start to read an ISO 15693 tag. We send an identify request, then wait\r
-// for the response. The response is not demodulated, just left in the buffer\r
-// so that it can be downloaded to a PC and processed there.\r
-//-----------------------------------------------------------------------------\r
-void AcquireRawAdcSamplesIso15693(void)\r
-{\r
- int c = 0;\r
- BYTE *dest = (BYTE *)BigBuf;\r
- int getNext = 0;\r
-\r
- SBYTE prev = 0;\r
-\r
- BuildIdentifyRequest();\r
-\r
- SetAdcMuxFor(GPIO_MUXSEL_HIPKD);\r
-\r
- // Give the tags time to energize\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);\r
- SpinDelay(100);\r
-\r
- // Now send the command\r
- FpgaSetupSsc();\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX);\r
-\r
- c = 0;\r
- for(;;) {\r
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {\r
- AT91C_BASE_SSC->SSC_THR = ToSend[c];\r
- c++;\r
- if(c == ToSendMax+3) {\r
- break;\r
- }\r
- }\r
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {\r
- volatile DWORD r = AT91C_BASE_SSC->SSC_RHR;\r
- (void)r;\r
- }\r
- WDT_HIT();\r
- }\r
-\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);\r
-\r
- c = 0;\r
- getNext = FALSE;\r
- for(;;) {\r
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {\r
- AT91C_BASE_SSC->SSC_THR = 0x43;\r
- }\r
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {\r
- SBYTE b;\r
- b = (SBYTE)AT91C_BASE_SSC->SSC_RHR;\r
-\r
- // The samples are correlations against I and Q versions of the\r
- // tone that the tag AM-modulates, so every other sample is I,\r
- // every other is Q. We just want power, so abs(I) + abs(Q) is\r
- // close to what we want.\r
- if(getNext) {\r
- SBYTE r;\r
-\r
- if(b < 0) {\r
- r = -b;\r
- } else {\r
- r = b;\r
- }\r
- if(prev < 0) {\r
- r -= prev;\r
- } else {\r
- r += prev;\r
- }\r
-\r
- dest[c++] = (BYTE)r;\r
-\r
- if(c >= 2000) {\r
- break;\r
- }\r
- } else {\r
- prev = b;\r
- }\r
-\r
- getNext = !getNext;\r
- }\r
- }\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-// Simulate an ISO15693 reader, perform anti-collision and then attempt to read a sector\r
-// all demodulation performed in arm rather than host. - greg\r
-//-----------------------------------------------------------------------------\r
-void ReaderIso15693(DWORD parameter)\r
-{\r
- LED_A_ON();\r
- LED_B_ON();\r
- LED_C_OFF();\r
- LED_D_OFF();\r
-\r
-//DbpString(parameter);\r
-\r
- //BYTE *answer0 = (((BYTE *)BigBuf) + 3560); // allow 100 bytes per reponse (way too much)\r
- BYTE *answer1 = (((BYTE *)BigBuf) + 3660); //\r
- BYTE *answer2 = (((BYTE *)BigBuf) + 3760);\r
- BYTE *answer3 = (((BYTE *)BigBuf) + 3860);\r
- //BYTE *TagUID= (((BYTE *)BigBuf) + 3960); // where we hold the uid for hi15reader\r
-// int answerLen0 = 0;\r
- int answerLen1 = 0;\r
- int answerLen2 = 0;\r
- int answerLen3 = 0;\r
-\r
- // Blank arrays\r
- memset(BigBuf + 3660, 0, 300);\r
-\r
- // Setup SSC\r
- FpgaSetupSsc();\r
-\r
- // Start from off (no field generated)\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
- SpinDelay(200);\r
-\r
- SetAdcMuxFor(GPIO_MUXSEL_HIPKD);\r
- FpgaSetupSsc();\r
-\r
- // Give the tags time to energize\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);\r
- SpinDelay(200);\r
-\r
- LED_A_ON();\r
- LED_B_OFF();\r
- LED_C_OFF();\r
- LED_D_OFF();\r
-\r
- int samples = 0;\r
- int tsamples = 0;\r
- int wait = 0;\r
- int elapsed = 0;\r
-\r
- // FIRST WE RUN AN INVENTORY TO GET THE TAG UID\r
- // THIS MEANS WE CAN PRE-BUILD REQUESTS TO SAVE CPU TIME\r
- BYTE TagUID[7]; // where we hold the uid for hi15reader\r
-\r
-// BuildIdentifyRequest();\r
-// //TransmitTo15693Tag(ToSend,ToSendMax+3,&tsamples, &wait);\r
-// TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); // No longer ToSendMax+3\r
-// // Now wait for a response\r
-// responseLen0 = GetIso15693AnswerFromTag(receivedAnswer0, 100, &samples, &elapsed) ;\r
-// if (responseLen0 >=12) // we should do a better check than this\r
-// {\r
-// // really we should check it is a valid mesg\r
-// // but for now just grab what we think is the uid\r
-// TagUID[0] = receivedAnswer0[2];\r
-// TagUID[1] = receivedAnswer0[3];\r
-// TagUID[2] = receivedAnswer0[4];\r
-// TagUID[3] = receivedAnswer0[5];\r
-// TagUID[4] = receivedAnswer0[6];\r
-// TagUID[5] = receivedAnswer0[7];\r
-// TagUID[6] = receivedAnswer0[8]; // IC Manufacturer code\r
-// DbpIntegers(TagUID[6],TagUID[5],TagUID[4]);\r
-//}\r
-\r
- // Now send the IDENTIFY command\r
- BuildIdentifyRequest();\r
- //TransmitTo15693Tag(ToSend,ToSendMax+3,&tsamples, &wait);\r
- TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); // No longer ToSendMax+3\r
- // Now wait for a response\r
- answerLen1 = GetIso15693AnswerFromTag(answer1, 100, &samples, &elapsed) ;\r
-\r
- if (answerLen1 >=12) // we should do a better check than this\r
- {\r
-\r
- TagUID[0] = answer1[2];\r
- TagUID[1] = answer1[3];\r
- TagUID[2] = answer1[4];\r
- TagUID[3] = answer1[5];\r
- TagUID[4] = answer1[6];\r
- TagUID[5] = answer1[7];\r
- TagUID[6] = answer1[8]; // IC Manufacturer code\r
-\r
- // Now send the SELECT command\r
- BuildSelectRequest(TagUID);\r
- TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); // No longer ToSendMax+3\r
- // Now wait for a response\r
- answerLen2 = GetIso15693AnswerFromTag(answer2, 100, &samples, &elapsed);\r
-\r
- // Now send the MULTI READ command\r
-// BuildArbitraryRequest(*TagUID,parameter);\r
- BuildArbitraryCustomRequest(TagUID,parameter);\r
-// BuildReadBlockRequest(*TagUID,parameter);\r
-// BuildSysInfoRequest(*TagUID);\r
- //TransmitTo15693Tag(ToSend,ToSendMax+3,&tsamples, &wait);\r
- TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); // No longer ToSendMax+3\r
- // Now wait for a response\r
- answerLen3 = GetIso15693AnswerFromTag(answer3, 100, &samples, &elapsed) ;\r
-\r
- }\r
-\r
- Dbprintf("%d octets read from IDENTIFY request: %x %x %x %x %x %x %x %x %x", answerLen1,\r
- answer1[0], answer1[1], answer1[2],\r
- answer1[3], answer1[4], answer1[5],\r
- answer1[6], answer1[7], answer1[8]);\r
-\r
- Dbprintf("%d octets read from SELECT request: %x %x %x %x %x %x %x %x %x", answerLen2,\r
- answer2[0], answer2[1], answer2[2],\r
- answer2[3], answer2[4], answer2[5],\r
- answer2[6], answer2[7], answer2[8]);\r
-\r
- Dbprintf("%d octets read from XXX request: %x %x %x %x %x %x %x %x %x", answerLen3,\r
- answer3[0], answer3[1], answer3[2],\r
- answer3[3], answer3[4], answer3[5],\r
- answer3[6], answer3[7], answer3[8]);\r
-\r
-\r
-// str2[0]=0;\r
-// for(i = 0; i < responseLen3; i++) {\r
-// itoa(str1,receivedAnswer3[i]);\r
-// strcat(str2,str1);\r
-// }\r
-// DbpString(str2);\r
-\r
- LED_A_OFF();\r
- LED_B_OFF();\r
- LED_C_OFF();\r
- LED_D_OFF();\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-// Simulate an ISO15693 TAG, perform anti-collision and then print any reader commands\r
-// all demodulation performed in arm rather than host. - greg\r
-//-----------------------------------------------------------------------------\r
-void SimTagIso15693(DWORD parameter)\r
-{\r
- LED_A_ON();\r
- LED_B_ON();\r
- LED_C_OFF();\r
- LED_D_OFF();\r
-\r
- BYTE *answer1 = (((BYTE *)BigBuf) + 3660); //\r
- int answerLen1 = 0;\r
-\r
- // Blank arrays\r
- memset(answer1, 0, 100);\r
-\r
- // Setup SSC\r
- FpgaSetupSsc();\r
-\r
- // Start from off (no field generated)\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
- SpinDelay(200);\r
-\r
- SetAdcMuxFor(GPIO_MUXSEL_HIPKD);\r
- FpgaSetupSsc();\r
-\r
- // Give the tags time to energize\r
-// FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); // NO GOOD FOR SIM TAG!!!!\r
- SpinDelay(200);\r
-\r
- LED_A_OFF();\r
- LED_B_OFF();\r
- LED_C_ON();\r
- LED_D_OFF();\r
-\r
- int samples = 0;\r
- int tsamples = 0;\r
- int wait = 0;\r
- int elapsed = 0;\r
-\r
- answerLen1 = GetIso15693AnswerFromSniff(answer1, 100, &samples, &elapsed) ;\r
-\r
- if (answerLen1 >=1) // we should do a better check than this\r
- {\r
- // Build a suitable reponse to the reader INVENTORY cocmmand\r
- BuildInventoryResponse();\r
- TransmitTo15693Reader(ToSend,ToSendMax, &tsamples, &wait);\r
- }\r
-\r
- Dbprintf("%d octets read from reader command: %x %x %x %x %x %x %x %x %x", answerLen1,\r
- answer1[0], answer1[1], answer1[2],\r
- answer1[3], answer1[4], answer1[5],\r
- answer1[6], answer1[7], answer1[8]);\r
-\r
- LED_A_OFF();\r
- LED_B_OFF();\r
- LED_C_OFF();\r
- LED_D_OFF();\r
-}\r
+//-----------------------------------------------------------------------------
+// Routines to support ISO 15693. This includes both the reader software and
+// the `fake tag' modes, but at the moment I've implemented only the reader
+// stuff, and that barely.
+// Jonathan Westhues, split Nov 2006
+
+// Modified by Greg Jones, Jan 2009 to perform modulation onboard in arm rather than on PC
+// Also added additional reader commands (SELECT, READ etc.)
+
+//-----------------------------------------------------------------------------
+#include <proxmark3.h>
+#include "apps.h"
+
+// FROM winsrc\prox.h //////////////////////////////////
+#define arraylen(x) (sizeof(x)/sizeof((x)[0]))
+
+//-----------------------------------------------------------------------------
+// Map a sequence of octets (~layer 2 command) into the set of bits to feed
+// to the FPGA, to transmit that command to the tag.
+//-----------------------------------------------------------------------------
+
+ // The sampling rate is 106.353 ksps/s, for T = 18.8 us
+
+ // SOF defined as
+ // 1) Unmodulated time of 56.64us
+ // 2) 24 pulses of 423.75khz
+ // 3) logic '1' (unmodulated for 18.88us followed by 8 pulses of 423.75khz)
+
+ static const int FrameSOF[] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ 1, 1, 1, 1,
+ 1, 1, 1, 1
+ };
+ static const int Logic0[] = {
+ 1, 1, 1, 1,
+ 1, 1, 1, 1,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1
+ };
+ static const int Logic1[] = {
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ 1, 1, 1, 1,
+ 1, 1, 1, 1
+ };
+
+ // EOF defined as
+ // 1) logic '0' (8 pulses of 423.75khz followed by unmodulated for 18.88us)
+ // 2) 24 pulses of 423.75khz
+ // 3) Unmodulated time of 56.64us
+
+ static const int FrameEOF[] = {
+ 1, 1, 1, 1,
+ 1, 1, 1, 1,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+ };
+
+static void CodeIso15693AsReader(BYTE *cmd, int n)
+{
+ int i, j;
+
+ ToSendReset();
+
+ // Give it a bit of slack at the beginning
+ for(i = 0; i < 24; i++) {
+ ToSendStuffBit(1);
+ }
+
+ ToSendStuffBit(0);
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ ToSendStuffBit(0);
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ for(i = 0; i < n; i++) {
+ for(j = 0; j < 8; j += 2) {
+ int these = (cmd[i] >> j) & 3;
+ switch(these) {
+ case 0:
+ ToSendStuffBit(1);
+ ToSendStuffBit(0);
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ break;
+ case 1:
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ ToSendStuffBit(0);
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ break;
+ case 2:
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ ToSendStuffBit(0);
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ break;
+ case 3:
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ ToSendStuffBit(0);
+ break;
+ }
+ }
+ }
+ ToSendStuffBit(1);
+ ToSendStuffBit(1);
+ ToSendStuffBit(0);
+ ToSendStuffBit(1);
+
+ // And slack at the end, too.
+ for(i = 0; i < 24; i++) {
+ ToSendStuffBit(1);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// The CRC used by ISO 15693.
+//-----------------------------------------------------------------------------
+static WORD Crc(BYTE *v, int n)
+{
+ DWORD reg;
+ int i, j;
+
+ reg = 0xffff;
+ for(i = 0; i < n; i++) {
+ reg = reg ^ ((DWORD)v[i]);
+ for (j = 0; j < 8; j++) {
+ if (reg & 0x0001) {
+ reg = (reg >> 1) ^ 0x8408;
+ } else {
+ reg = (reg >> 1);
+ }
+ }
+ }
+
+ return ~reg;
+}
+
+char *strcat(char *dest, const char *src)
+{
+ size_t dest_len = strlen(dest);
+ size_t i;
+
+ for (i = 0 ; src[i] != '\0' ; i++)
+ dest[dest_len + i] = src[i];
+ dest[dest_len + i] = '\0';
+
+ return dest;
+}
+
+////////////////////////////////////////// code to do 'itoa'
+
+/* reverse: reverse string s in place */
+void reverse(char s[])
+{
+ int c, i, j;
+
+ for (i = 0, j = strlen(s)-1; i<j; i++, j--) {
+ c = s[i];
+ s[i] = s[j];
+ s[j] = c;
+ }
+}
+
+/* itoa: convert n to characters in s */
+void itoa(int n, char s[])
+{
+ int i, sign;
+
+ if ((sign = n) < 0) /* record sign */
+ n = -n; /* make n positive */
+ i = 0;
+ do { /* generate digits in reverse order */
+ s[i++] = n % 10 + '0'; /* get next digit */
+ } while ((n /= 10) > 0); /* delete it */
+ if (sign < 0)
+ s[i++] = '-';
+ s[i] = '\0';
+ reverse(s);
+}
+
+//////////////////////////////////////// END 'itoa' CODE
+
+//-----------------------------------------------------------------------------
+// Encode (into the ToSend buffers) an identify request, which is the first
+// thing that you must send to a tag to get a response.
+//-----------------------------------------------------------------------------
+static void BuildIdentifyRequest(void)
+{
+ BYTE cmd[5];
+
+ WORD crc;
+ // one sub-carrier, inventory, 1 slot, fast rate
+ // AFI is at bit 5 (1<<4) when doing an INVENTORY
+ cmd[0] = (1 << 2) | (1 << 5) | (1 << 1);
+ // inventory command code
+ cmd[1] = 0x01;
+ // no mask
+ cmd[2] = 0x00;
+ //Now the CRC
+ crc = Crc(cmd, 3);
+ cmd[3] = crc & 0xff;
+ cmd[4] = crc >> 8;
+
+ CodeIso15693AsReader(cmd, sizeof(cmd));
+}
+
+static void __attribute__((unused)) BuildSysInfoRequest(BYTE *uid)
+{
+ BYTE cmd[12];
+
+ WORD crc;
+ // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block
+ // followed by teh block data
+ // one sub-carrier, inventory, 1 slot, fast rate
+ cmd[0] = (1 << 5) | (1 << 1); // no SELECT bit
+ // System Information command code
+ cmd[1] = 0x2B;
+ // UID may be optionally specified here
+ // 64-bit UID
+ cmd[2] = 0x32;
+ cmd[3]= 0x4b;
+ cmd[4] = 0x03;
+ cmd[5] = 0x01;
+ cmd[6] = 0x00;
+ cmd[7] = 0x10;
+ cmd[8] = 0x05;
+ cmd[9]= 0xe0; // always e0 (not exactly unique)
+ //Now the CRC
+ crc = Crc(cmd, 10); // the crc needs to be calculated over 2 bytes
+ cmd[10] = crc & 0xff;
+ cmd[11] = crc >> 8;
+
+ CodeIso15693AsReader(cmd, sizeof(cmd));
+}
+
+static void BuildSelectRequest( BYTE uid[])
+{
+
+// uid[6]=0x31; // this is getting ignored - the uid array is not happening...
+ BYTE cmd[12];
+
+ WORD crc;
+ // one sub-carrier, inventory, 1 slot, fast rate
+ //cmd[0] = (1 << 2) | (1 << 5) | (1 << 1); // INVENTROY FLAGS
+ cmd[0] = (1 << 4) | (1 << 5) | (1 << 1); // Select and addressed FLAGS
+ // SELECT command code
+ cmd[1] = 0x25;
+ // 64-bit UID
+// cmd[2] = uid[0];//0x32;
+// cmd[3]= uid[1];//0x4b;
+// cmd[4] = uid[2];//0x03;
+// cmd[5] = uid[3];//0x01;
+// cmd[6] = uid[4];//0x00;
+// cmd[7] = uid[5];//0x10;
+// cmd[8] = uid[6];//0x05;
+ cmd[2] = 0x32;//
+ cmd[3] = 0x4b;
+ cmd[4] = 0x03;
+ cmd[5] = 0x01;
+ cmd[6] = 0x00;
+ cmd[7] = 0x10;
+ cmd[8] = 0x05; // infineon?
+
+ cmd[9]= 0xe0; // always e0 (not exactly unique)
+
+// DbpIntegers(cmd[8],cmd[7],cmd[6]);
+ // Now the CRC
+ crc = Crc(cmd, 10); // the crc needs to be calculated over 10 bytes
+ cmd[10] = crc & 0xff;
+ cmd[11] = crc >> 8;
+
+ CodeIso15693AsReader(cmd, sizeof(cmd));
+}
+
+static void __attribute__((unused)) BuildReadBlockRequest(BYTE *uid, BYTE blockNumber )
+{
+ BYTE cmd[13];
+
+ WORD crc;
+ // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block
+ // followed by teh block data
+ // one sub-carrier, inventory, 1 slot, fast rate
+ cmd[0] = (1 << 6)| (1 << 5) | (1 << 1); // no SELECT bit
+ // READ BLOCK command code
+ cmd[1] = 0x20;
+ // UID may be optionally specified here
+ // 64-bit UID
+ cmd[2] = 0x32;
+ cmd[3]= 0x4b;
+ cmd[4] = 0x03;
+ cmd[5] = 0x01;
+ cmd[6] = 0x00;
+ cmd[7] = 0x10;
+ cmd[8] = 0x05;
+ cmd[9]= 0xe0; // always e0 (not exactly unique)
+ // Block number to read
+ cmd[10] = blockNumber;//0x00;
+ //Now the CRC
+ crc = Crc(cmd, 11); // the crc needs to be calculated over 2 bytes
+ cmd[11] = crc & 0xff;
+ cmd[12] = crc >> 8;
+
+ CodeIso15693AsReader(cmd, sizeof(cmd));
+}
+
+static void __attribute__((unused)) BuildReadMultiBlockRequest(BYTE *uid)
+{
+ BYTE cmd[14];
+
+ WORD crc;
+ // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block
+ // followed by teh block data
+ // one sub-carrier, inventory, 1 slot, fast rate
+ cmd[0] = (1 << 5) | (1 << 1); // no SELECT bit
+ // READ Multi BLOCK command code
+ cmd[1] = 0x23;
+ // UID may be optionally specified here
+ // 64-bit UID
+ cmd[2] = 0x32;
+ cmd[3]= 0x4b;
+ cmd[4] = 0x03;
+ cmd[5] = 0x01;
+ cmd[6] = 0x00;
+ cmd[7] = 0x10;
+ cmd[8] = 0x05;
+ cmd[9]= 0xe0; // always e0 (not exactly unique)
+ // First Block number to read
+ cmd[10] = 0x00;
+ // Number of Blocks to read
+ cmd[11] = 0x2f; // read quite a few
+ //Now the CRC
+ crc = Crc(cmd, 12); // the crc needs to be calculated over 2 bytes
+ cmd[12] = crc & 0xff;
+ cmd[13] = crc >> 8;
+
+ CodeIso15693AsReader(cmd, sizeof(cmd));
+}
+
+static void __attribute__((unused)) BuildArbitraryRequest(BYTE *uid,BYTE CmdCode)
+{
+ BYTE cmd[14];
+
+ WORD crc;
+ // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block
+ // followed by teh block data
+ // one sub-carrier, inventory, 1 slot, fast rate
+ cmd[0] = (1 << 5) | (1 << 1); // no SELECT bit
+ // READ BLOCK command code
+ cmd[1] = CmdCode;
+ // UID may be optionally specified here
+ // 64-bit UID
+ cmd[2] = 0x32;
+ cmd[3]= 0x4b;
+ cmd[4] = 0x03;
+ cmd[5] = 0x01;
+ cmd[6] = 0x00;
+ cmd[7] = 0x10;
+ cmd[8] = 0x05;
+ cmd[9]= 0xe0; // always e0 (not exactly unique)
+ // Parameter
+ cmd[10] = 0x00;
+ cmd[11] = 0x0a;
+
+// cmd[12] = 0x00;
+// cmd[13] = 0x00; //Now the CRC
+ crc = Crc(cmd, 12); // the crc needs to be calculated over 2 bytes
+ cmd[12] = crc & 0xff;
+ cmd[13] = crc >> 8;
+
+ CodeIso15693AsReader(cmd, sizeof(cmd));
+}
+
+static void __attribute__((unused)) BuildArbitraryCustomRequest(BYTE uid[], BYTE CmdCode)
+{
+ BYTE cmd[14];
+
+ WORD crc;
+ // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block
+ // followed by teh block data
+ // one sub-carrier, inventory, 1 slot, fast rate
+ cmd[0] = (1 << 5) | (1 << 1); // no SELECT bit
+ // READ BLOCK command code
+ cmd[1] = CmdCode;
+ // UID may be optionally specified here
+ // 64-bit UID
+ cmd[2] = 0x32;
+ cmd[3]= 0x4b;
+ cmd[4] = 0x03;
+ cmd[5] = 0x01;
+ cmd[6] = 0x00;
+ cmd[7] = 0x10;
+ cmd[8] = 0x05;
+ cmd[9]= 0xe0; // always e0 (not exactly unique)
+ // Parameter
+ cmd[10] = 0x05; // for custom codes this must be manufcturer code
+ cmd[11] = 0x00;
+
+// cmd[12] = 0x00;
+// cmd[13] = 0x00; //Now the CRC
+ crc = Crc(cmd, 12); // the crc needs to be calculated over 2 bytes
+ cmd[12] = crc & 0xff;
+ cmd[13] = crc >> 8;
+
+ CodeIso15693AsReader(cmd, sizeof(cmd));
+}
+
+/////////////////////////////////////////////////////////////////////////
+// Now the VICC>VCD responses when we are simulating a tag
+////////////////////////////////////////////////////////////////////
+
+ static void BuildInventoryResponse(void)
+{
+ BYTE cmd[12];
+
+ WORD crc;
+ // one sub-carrier, inventory, 1 slot, fast rate
+ // AFI is at bit 5 (1<<4) when doing an INVENTORY
+ cmd[0] = 0; //(1 << 2) | (1 << 5) | (1 << 1);
+ cmd[1] = 0;
+ // 64-bit UID
+ cmd[2] = 0x32;
+ cmd[3]= 0x4b;
+ cmd[4] = 0x03;
+ cmd[5] = 0x01;
+ cmd[6] = 0x00;
+ cmd[7] = 0x10;
+ cmd[8] = 0x05;
+ cmd[9]= 0xe0;
+ //Now the CRC
+ crc = Crc(cmd, 10);
+ cmd[10] = crc & 0xff;
+ cmd[11] = crc >> 8;
+
+ CodeIso15693AsReader(cmd, sizeof(cmd));
+}
+
+//-----------------------------------------------------------------------------
+// Transmit the command (to the tag) that was placed in ToSend[].
+//-----------------------------------------------------------------------------
+static void TransmitTo15693Tag(const BYTE *cmd, int len, int *samples, int *wait)
+{
+ int c;
+
+// FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX);
+ if(*wait < 10) { *wait = 10; }
+
+// for(c = 0; c < *wait;) {
+// if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
+// AT91C_BASE_SSC->SSC_THR = 0x00; // For exact timing!
+// c++;
+// }
+// if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
+// volatile DWORD r = AT91C_BASE_SSC->SSC_RHR;
+// (void)r;
+// }
+// WDT_HIT();
+// }
+
+ c = 0;
+ for(;;) {
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
+ AT91C_BASE_SSC->SSC_THR = cmd[c];
+ c++;
+ if(c >= len) {
+ break;
+ }
+ }
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
+ volatile DWORD r = AT91C_BASE_SSC->SSC_RHR;
+ (void)r;
+ }
+ WDT_HIT();
+ }
+ *samples = (c + *wait) << 3;
+}
+
+//-----------------------------------------------------------------------------
+// Transmit the command (to the reader) that was placed in ToSend[].
+//-----------------------------------------------------------------------------
+static void TransmitTo15693Reader(const BYTE *cmd, int len, int *samples, int *wait)
+{
+ int c;
+
+// FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX);
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR); // No requirement to energise my coils
+ if(*wait < 10) { *wait = 10; }
+
+ c = 0;
+ for(;;) {
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
+ AT91C_BASE_SSC->SSC_THR = cmd[c];
+ c++;
+ if(c >= len) {
+ break;
+ }
+ }
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
+ volatile DWORD r = AT91C_BASE_SSC->SSC_RHR;
+ (void)r;
+ }
+ WDT_HIT();
+ }
+ *samples = (c + *wait) << 3;
+}
+
+static int GetIso15693AnswerFromTag(BYTE *receivedResponse, int maxLen, int *samples, int *elapsed)
+{
+ int c = 0;
+ BYTE *dest = (BYTE *)BigBuf;
+ int getNext = 0;
+
+ SBYTE prev = 0;
+
+// NOW READ RESPONSE
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
+ //spindelay(60); // greg - experiment to get rid of some of the 0 byte/failed reads
+ c = 0;
+ getNext = FALSE;
+ for(;;) {
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
+ AT91C_BASE_SSC->SSC_THR = 0x43;
+ }
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
+ SBYTE b;
+ b = (SBYTE)AT91C_BASE_SSC->SSC_RHR;
+
+ // The samples are correlations against I and Q versions of the
+ // tone that the tag AM-modulates, so every other sample is I,
+ // every other is Q. We just want power, so abs(I) + abs(Q) is
+ // close to what we want.
+ if(getNext) {
+ SBYTE r;
+
+ if(b < 0) {
+ r = -b;
+ } else {
+ r = b;
+ }
+ if(prev < 0) {
+ r -= prev;
+ } else {
+ r += prev;
+ }
+
+ dest[c++] = (BYTE)r;
+
+ if(c >= 2000) {
+ break;
+ }
+ } else {
+ prev = b;
+ }
+
+ getNext = !getNext;
+ }
+ }
+
+//////////////////////////////////////////
+/////////// DEMODULATE ///////////////////
+//////////////////////////////////////////
+
+ int i, j;
+ int max = 0, maxPos=0;
+
+ int skip = 4;
+
+// if(GraphTraceLen < 1000) return; // THIS CHECKS FOR A BUFFER TO SMALL
+
+ // First, correlate for SOF
+ for(i = 0; i < 100; i++) {
+ int corr = 0;
+ for(j = 0; j < arraylen(FrameSOF); j += skip) {
+ corr += FrameSOF[j]*dest[i+(j/skip)];
+ }
+ if(corr > max) {
+ max = corr;
+ maxPos = i;
+ }
+ }
+// DbpString("SOF at %d, correlation %d", maxPos,max/(arraylen(FrameSOF)/skip));
+
+ int k = 0; // this will be our return value
+
+ // greg - If correlation is less than 1 then there's little point in continuing
+ if ((max/(arraylen(FrameSOF)/skip)) >= 1)
+ {
+
+ i = maxPos + arraylen(FrameSOF)/skip;
+
+ BYTE outBuf[20];
+ memset(outBuf, 0, sizeof(outBuf));
+ BYTE mask = 0x01;
+ for(;;) {
+ int corr0 = 0, corr1 = 0, corrEOF = 0;
+ for(j = 0; j < arraylen(Logic0); j += skip) {
+ corr0 += Logic0[j]*dest[i+(j/skip)];
+ }
+ for(j = 0; j < arraylen(Logic1); j += skip) {
+ corr1 += Logic1[j]*dest[i+(j/skip)];
+ }
+ for(j = 0; j < arraylen(FrameEOF); j += skip) {
+ corrEOF += FrameEOF[j]*dest[i+(j/skip)];
+ }
+ // Even things out by the length of the target waveform.
+ corr0 *= 4;
+ corr1 *= 4;
+
+ if(corrEOF > corr1 && corrEOF > corr0) {
+// DbpString("EOF at %d", i);
+ break;
+ } else if(corr1 > corr0) {
+ i += arraylen(Logic1)/skip;
+ outBuf[k] |= mask;
+ } else {
+ i += arraylen(Logic0)/skip;
+ }
+ mask <<= 1;
+ if(mask == 0) {
+ k++;
+ mask = 0x01;
+ }
+ if((i+(int)arraylen(FrameEOF)) >= 2000) {
+ DbpString("ran off end!");
+ break;
+ }
+ }
+ if(mask != 0x01) {
+ DbpString("error, uneven octet! (discard extra bits!)");
+/// DbpString(" mask=%02x", mask);
+ }
+// BYTE str1 [8];
+// itoa(k,str1);
+// strcat(str1," octets read");
+
+// DbpString( str1); // DbpString("%d octets", k);
+
+// for(i = 0; i < k; i+=3) {
+// //DbpString("# %2d: %02x ", i, outBuf[i]);
+// DbpIntegers(outBuf[i],outBuf[i+1],outBuf[i+2]);
+// }
+
+ for(i = 0; i < k; i++) {
+ receivedResponse[i] = outBuf[i];
+ }
+ } // "end if correlation > 0" (max/(arraylen(FrameSOF)/skip))
+ return k; // return the number of bytes demodulated
+
+/// DbpString("CRC=%04x", Iso15693Crc(outBuf, k-2));
+
+}
+
+// Now the GetISO15693 message from sniffing command
+static int GetIso15693AnswerFromSniff(BYTE *receivedResponse, int maxLen, int *samples, int *elapsed)
+{
+ int c = 0;
+ BYTE *dest = (BYTE *)BigBuf;
+ int getNext = 0;
+
+ SBYTE prev = 0;
+
+// NOW READ RESPONSE
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
+ //spindelay(60); // greg - experiment to get rid of some of the 0 byte/failed reads
+ c = 0;
+ getNext = FALSE;
+ for(;;) {
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
+ AT91C_BASE_SSC->SSC_THR = 0x43;
+ }
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
+ SBYTE b;
+ b = (SBYTE)AT91C_BASE_SSC->SSC_RHR;
+
+ // The samples are correlations against I and Q versions of the
+ // tone that the tag AM-modulates, so every other sample is I,
+ // every other is Q. We just want power, so abs(I) + abs(Q) is
+ // close to what we want.
+ if(getNext) {
+ SBYTE r;
+
+ if(b < 0) {
+ r = -b;
+ } else {
+ r = b;
+ }
+ if(prev < 0) {
+ r -= prev;
+ } else {
+ r += prev;
+ }
+
+ dest[c++] = (BYTE)r;
+
+ if(c >= 20000) {
+ break;
+ }
+ } else {
+ prev = b;
+ }
+
+ getNext = !getNext;
+ }
+ }
+
+//////////////////////////////////////////
+/////////// DEMODULATE ///////////////////
+//////////////////////////////////////////
+
+ int i, j;
+ int max = 0, maxPos=0;
+
+ int skip = 4;
+
+// if(GraphTraceLen < 1000) return; // THIS CHECKS FOR A BUFFER TO SMALL
+
+ // First, correlate for SOF
+ for(i = 0; i < 19000; i++) {
+ int corr = 0;
+ for(j = 0; j < arraylen(FrameSOF); j += skip) {
+ corr += FrameSOF[j]*dest[i+(j/skip)];
+ }
+ if(corr > max) {
+ max = corr;
+ maxPos = i;
+ }
+ }
+// DbpString("SOF at %d, correlation %d", maxPos,max/(arraylen(FrameSOF)/skip));
+
+ int k = 0; // this will be our return value
+
+ // greg - If correlation is less than 1 then there's little point in continuing
+ if ((max/(arraylen(FrameSOF)/skip)) >= 1) // THIS SHOULD BE 1
+ {
+
+ i = maxPos + arraylen(FrameSOF)/skip;
+
+ BYTE outBuf[20];
+ memset(outBuf, 0, sizeof(outBuf));
+ BYTE mask = 0x01;
+ for(;;) {
+ int corr0 = 0, corr1 = 0, corrEOF = 0;
+ for(j = 0; j < arraylen(Logic0); j += skip) {
+ corr0 += Logic0[j]*dest[i+(j/skip)];
+ }
+ for(j = 0; j < arraylen(Logic1); j += skip) {
+ corr1 += Logic1[j]*dest[i+(j/skip)];
+ }
+ for(j = 0; j < arraylen(FrameEOF); j += skip) {
+ corrEOF += FrameEOF[j]*dest[i+(j/skip)];
+ }
+ // Even things out by the length of the target waveform.
+ corr0 *= 4;
+ corr1 *= 4;
+
+ if(corrEOF > corr1 && corrEOF > corr0) {
+// DbpString("EOF at %d", i);
+ break;
+ } else if(corr1 > corr0) {
+ i += arraylen(Logic1)/skip;
+ outBuf[k] |= mask;
+ } else {
+ i += arraylen(Logic0)/skip;
+ }
+ mask <<= 1;
+ if(mask == 0) {
+ k++;
+ mask = 0x01;
+ }
+ if((i+(int)arraylen(FrameEOF)) >= 2000) {
+ DbpString("ran off end!");
+ break;
+ }
+ }
+ if(mask != 0x01) {
+ DbpString("error, uneven octet! (discard extra bits!)");
+/// DbpString(" mask=%02x", mask);
+ }
+// BYTE str1 [8];
+// itoa(k,str1);
+// strcat(str1," octets read");
+
+// DbpString( str1); // DbpString("%d octets", k);
+
+// for(i = 0; i < k; i+=3) {
+// //DbpString("# %2d: %02x ", i, outBuf[i]);
+// DbpIntegers(outBuf[i],outBuf[i+1],outBuf[i+2]);
+// }
+
+ for(i = 0; i < k; i++) {
+ receivedResponse[i] = outBuf[i];
+ }
+ } // "end if correlation > 0" (max/(arraylen(FrameSOF)/skip))
+ return k; // return the number of bytes demodulated
+
+/// DbpString("CRC=%04x", Iso15693Crc(outBuf, k-2));
+}
+
+//-----------------------------------------------------------------------------
+// Start to read an ISO 15693 tag. We send an identify request, then wait
+// for the response. The response is not demodulated, just left in the buffer
+// so that it can be downloaded to a PC and processed there.
+//-----------------------------------------------------------------------------
+void AcquireRawAdcSamplesIso15693(void)
+{
+ int c = 0;
+ BYTE *dest = (BYTE *)BigBuf;
+ int getNext = 0;
+
+ SBYTE prev = 0;
+
+ BuildIdentifyRequest();
+
+ SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
+
+ // Give the tags time to energize
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
+ SpinDelay(100);
+
+ // Now send the command
+ FpgaSetupSsc();
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX);
+
+ c = 0;
+ for(;;) {
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
+ AT91C_BASE_SSC->SSC_THR = ToSend[c];
+ c++;
+ if(c == ToSendMax+3) {
+ break;
+ }
+ }
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
+ volatile DWORD r = AT91C_BASE_SSC->SSC_RHR;
+ (void)r;
+ }
+ WDT_HIT();
+ }
+
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
+
+ c = 0;
+ getNext = FALSE;
+ for(;;) {
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
+ AT91C_BASE_SSC->SSC_THR = 0x43;
+ }
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
+ SBYTE b;
+ b = (SBYTE)AT91C_BASE_SSC->SSC_RHR;
+
+ // The samples are correlations against I and Q versions of the
+ // tone that the tag AM-modulates, so every other sample is I,
+ // every other is Q. We just want power, so abs(I) + abs(Q) is
+ // close to what we want.
+ if(getNext) {
+ SBYTE r;
+
+ if(b < 0) {
+ r = -b;
+ } else {
+ r = b;
+ }
+ if(prev < 0) {
+ r -= prev;
+ } else {
+ r += prev;
+ }
+
+ dest[c++] = (BYTE)r;
+
+ if(c >= 2000) {
+ break;
+ }
+ } else {
+ prev = b;
+ }
+
+ getNext = !getNext;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Simulate an ISO15693 reader, perform anti-collision and then attempt to read a sector
+// all demodulation performed in arm rather than host. - greg
+//-----------------------------------------------------------------------------
+void ReaderIso15693(DWORD parameter)
+{
+ LED_A_ON();
+ LED_B_ON();
+ LED_C_OFF();
+ LED_D_OFF();
+
+//DbpString(parameter);
+
+ //BYTE *answer0 = (((BYTE *)BigBuf) + 3560); // allow 100 bytes per reponse (way too much)
+ BYTE *answer1 = (((BYTE *)BigBuf) + 3660); //
+ BYTE *answer2 = (((BYTE *)BigBuf) + 3760);
+ BYTE *answer3 = (((BYTE *)BigBuf) + 3860);
+ //BYTE *TagUID= (((BYTE *)BigBuf) + 3960); // where we hold the uid for hi15reader
+// int answerLen0 = 0;
+ int answerLen1 = 0;
+ int answerLen2 = 0;
+ int answerLen3 = 0;
+
+ // Blank arrays
+ memset(BigBuf + 3660, 0, 300);
+
+ // Setup SSC
+ FpgaSetupSsc();
+
+ // Start from off (no field generated)
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+ SpinDelay(200);
+
+ SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
+ FpgaSetupSsc();
+
+ // Give the tags time to energize
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
+ SpinDelay(200);
+
+ LED_A_ON();
+ LED_B_OFF();
+ LED_C_OFF();
+ LED_D_OFF();
+
+ int samples = 0;
+ int tsamples = 0;
+ int wait = 0;
+ int elapsed = 0;
+
+ // FIRST WE RUN AN INVENTORY TO GET THE TAG UID
+ // THIS MEANS WE CAN PRE-BUILD REQUESTS TO SAVE CPU TIME
+ BYTE TagUID[7]; // where we hold the uid for hi15reader
+
+// BuildIdentifyRequest();
+// //TransmitTo15693Tag(ToSend,ToSendMax+3,&tsamples, &wait);
+// TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); // No longer ToSendMax+3
+// // Now wait for a response
+// responseLen0 = GetIso15693AnswerFromTag(receivedAnswer0, 100, &samples, &elapsed) ;
+// if (responseLen0 >=12) // we should do a better check than this
+// {
+// // really we should check it is a valid mesg
+// // but for now just grab what we think is the uid
+// TagUID[0] = receivedAnswer0[2];
+// TagUID[1] = receivedAnswer0[3];
+// TagUID[2] = receivedAnswer0[4];
+// TagUID[3] = receivedAnswer0[5];
+// TagUID[4] = receivedAnswer0[6];
+// TagUID[5] = receivedAnswer0[7];
+// TagUID[6] = receivedAnswer0[8]; // IC Manufacturer code
+// DbpIntegers(TagUID[6],TagUID[5],TagUID[4]);
+//}
+
+ // Now send the IDENTIFY command
+ BuildIdentifyRequest();
+ //TransmitTo15693Tag(ToSend,ToSendMax+3,&tsamples, &wait);
+ TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); // No longer ToSendMax+3
+ // Now wait for a response
+ answerLen1 = GetIso15693AnswerFromTag(answer1, 100, &samples, &elapsed) ;
+
+ if (answerLen1 >=12) // we should do a better check than this
+ {
+
+ TagUID[0] = answer1[2];
+ TagUID[1] = answer1[3];
+ TagUID[2] = answer1[4];
+ TagUID[3] = answer1[5];
+ TagUID[4] = answer1[6];
+ TagUID[5] = answer1[7];
+ TagUID[6] = answer1[8]; // IC Manufacturer code
+
+ // Now send the SELECT command
+ BuildSelectRequest(TagUID);
+ TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); // No longer ToSendMax+3
+ // Now wait for a response
+ answerLen2 = GetIso15693AnswerFromTag(answer2, 100, &samples, &elapsed);
+
+ // Now send the MULTI READ command
+// BuildArbitraryRequest(*TagUID,parameter);
+ BuildArbitraryCustomRequest(TagUID,parameter);
+// BuildReadBlockRequest(*TagUID,parameter);
+// BuildSysInfoRequest(*TagUID);
+ //TransmitTo15693Tag(ToSend,ToSendMax+3,&tsamples, &wait);
+ TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); // No longer ToSendMax+3
+ // Now wait for a response
+ answerLen3 = GetIso15693AnswerFromTag(answer3, 100, &samples, &elapsed) ;
+
+ }
+
+ Dbprintf("%d octets read from IDENTIFY request: %x %x %x %x %x %x %x %x %x", answerLen1,
+ answer1[0], answer1[1], answer1[2],
+ answer1[3], answer1[4], answer1[5],
+ answer1[6], answer1[7], answer1[8]);
+
+ Dbprintf("%d octets read from SELECT request: %x %x %x %x %x %x %x %x %x", answerLen2,
+ answer2[0], answer2[1], answer2[2],
+ answer2[3], answer2[4], answer2[5],
+ answer2[6], answer2[7], answer2[8]);
+
+ Dbprintf("%d octets read from XXX request: %x %x %x %x %x %x %x %x %x", answerLen3,
+ answer3[0], answer3[1], answer3[2],
+ answer3[3], answer3[4], answer3[5],
+ answer3[6], answer3[7], answer3[8]);
+
+
+// str2[0]=0;
+// for(i = 0; i < responseLen3; i++) {
+// itoa(str1,receivedAnswer3[i]);
+// strcat(str2,str1);
+// }
+// DbpString(str2);
+
+ LED_A_OFF();
+ LED_B_OFF();
+ LED_C_OFF();
+ LED_D_OFF();
+}
+
+//-----------------------------------------------------------------------------
+// Simulate an ISO15693 TAG, perform anti-collision and then print any reader commands
+// all demodulation performed in arm rather than host. - greg
+//-----------------------------------------------------------------------------
+void SimTagIso15693(DWORD parameter)
+{
+ LED_A_ON();
+ LED_B_ON();
+ LED_C_OFF();
+ LED_D_OFF();
+
+ BYTE *answer1 = (((BYTE *)BigBuf) + 3660); //
+ int answerLen1 = 0;
+
+ // Blank arrays
+ memset(answer1, 0, 100);
+
+ // Setup SSC
+ FpgaSetupSsc();
+
+ // Start from off (no field generated)
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+ SpinDelay(200);
+
+ SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
+ FpgaSetupSsc();
+
+ // Give the tags time to energize
+// FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); // NO GOOD FOR SIM TAG!!!!
+ SpinDelay(200);
+
+ LED_A_OFF();
+ LED_B_OFF();
+ LED_C_ON();
+ LED_D_OFF();
+
+ int samples = 0;
+ int tsamples = 0;
+ int wait = 0;
+ int elapsed = 0;
+
+ answerLen1 = GetIso15693AnswerFromSniff(answer1, 100, &samples, &elapsed) ;
+
+ if (answerLen1 >=1) // we should do a better check than this
+ {
+ // Build a suitable reponse to the reader INVENTORY cocmmand
+ BuildInventoryResponse();
+ TransmitTo15693Reader(ToSend,ToSendMax, &tsamples, &wait);
+ }
+
+ Dbprintf("%d octets read from reader command: %x %x %x %x %x %x %x %x %x", answerLen1,
+ answer1[0], answer1[1], answer1[2],
+ answer1[3], answer1[4], answer1[5],
+ answer1[6], answer1[7], answer1[8]);
+
+ LED_A_OFF();
+ LED_B_OFF();
+ LED_C_OFF();
+ LED_D_OFF();
+}
-INCLUDE ../common/ldscript.common\r
-\r
-ENTRY(Vector)\r
-SECTIONS\r
-{\r
- .fpgaimage : {\r
- *(fpga_bit.data)\r
- } >fpgaimage\r
- .start : { *(.startos) } >osimage\r
- .text : { \r
- *(.text)\r
- *(.text.*)\r
- *(.eh_frame)\r
- *(.glue_7)\r
- *(.glue_7t)\r
- *(.rodata) \r
- *(.rodata*) \r
- *(.version_information)\r
- } >osimage\r
- __end_of_text__ = .;\r
- \r
- .data : {\r
- __data_start__ = .;\r
- __data_src_start__ = __end_of_text__; \r
- *(.data)\r
- *(.data.*)\r
- __data_end__ = .;\r
- } >ram AT>osimage\r
- \r
- .bss : {\r
- __bss_start__ = .; \r
- *(.bss)\r
- *(.bss.*) \r
- } >ram\r
- . = ALIGN(32 / 8);\r
- __bss_end__ = .;\r
-\r
- .commonarea (NOLOAD) : {\r
- *(.commonarea)\r
- } >commonarea\r
-}\r
+INCLUDE ../common/ldscript.common
+
+ENTRY(Vector)
+SECTIONS
+{
+ .fpgaimage : {
+ *(fpga_bit.data)
+ } >fpgaimage
+ .start : { *(.startos) } >osimage
+ .text : {
+ *(.text)
+ *(.text.*)
+ *(.eh_frame)
+ *(.glue_7)
+ *(.glue_7t)
+ *(.rodata)
+ *(.rodata*)
+ *(.version_information)
+ } >osimage
+ __end_of_text__ = .;
+
+ .data : {
+ __data_start__ = .;
+ __data_src_start__ = __end_of_text__;
+ *(.data)
+ *(.data.*)
+ __data_end__ = .;
+ } >ram AT>osimage
+
+ .bss : {
+ __bss_start__ = .;
+ *(.bss)
+ *(.bss.*)
+ } >ram
+ . = ALIGN(32 / 8);
+ __bss_end__ = .;
+
+ .commonarea (NOLOAD) : {
+ *(.commonarea)
+ } >commonarea
+}
-//-----------------------------------------------------------------------------\r
-// Miscellaneous routines for low frequency tag operations.\r
-// Tags supported here so far are Texas Instruments (TI), HID\r
-// Also routines for raw mode reading/simulating of LF waveform\r
-//\r
-//-----------------------------------------------------------------------------\r
-#include <proxmark3.h>\r
-#include "apps.h"\r
-#include "hitag2.h"\r
-#include "crc16.h"\r
-\r
-void AcquireRawAdcSamples125k(BOOL at134khz)\r
-{\r
- if (at134khz)\r
- FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz\r
- else\r
- FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz\r
-\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);\r
-\r
- // Connect the A/D to the peak-detected low-frequency path.\r
- SetAdcMuxFor(GPIO_MUXSEL_LOPKD);\r
-\r
- // Give it a bit of time for the resonant antenna to settle.\r
- SpinDelay(50);\r
-\r
- // Now set up the SSC to get the ADC samples that are now streaming at us.\r
- FpgaSetupSsc();\r
-\r
- // Now call the acquisition routine\r
- DoAcquisition125k();\r
-}\r
-\r
-// split into two routines so we can avoid timing issues after sending commands //\r
-void DoAcquisition125k(void)\r
-{\r
- BYTE *dest = (BYTE *)BigBuf;\r
- int n = sizeof(BigBuf);\r
- int i;\r
- \r
- memset(dest, 0, n);\r
- i = 0;\r
- for(;;) {\r
- if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) {\r
- AT91C_BASE_SSC->SSC_THR = 0x43;\r
- LED_D_ON();\r
- }\r
- if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {\r
- dest[i] = (BYTE)AT91C_BASE_SSC->SSC_RHR;\r
- i++;\r
- LED_D_OFF();\r
- if (i >= n) break;\r
- }\r
- }\r
- Dbprintf("buffer samples: %02x %02x %02x %02x %02x %02x %02x %02x ...",\r
- dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]);\r
-}\r
-\r
-void ModThenAcquireRawAdcSamples125k(int delay_off, int period_0, int period_1, BYTE *command)\r
-{\r
- BOOL at134khz;\r
-\r
- /* Make sure the tag is reset */\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
- SpinDelay(2500);\r
- \r
- // see if 'h' was specified\r
- if (command[strlen((char *) command) - 1] == 'h')\r
- at134khz = TRUE;\r
- else\r
- at134khz = FALSE;\r
-\r
- if (at134khz)\r
- FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz\r
- else\r
- FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz\r
-\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);\r
-\r
- // Give it a bit of time for the resonant antenna to settle.\r
- SpinDelay(50);\r
- // And a little more time for the tag to fully power up\r
- SpinDelay(2000);\r
-\r
- // Now set up the SSC to get the ADC samples that are now streaming at us.\r
- FpgaSetupSsc();\r
-\r
- // now modulate the reader field\r
- while(*command != '\0' && *command != ' ') {\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
- LED_D_OFF();\r
- SpinDelayUs(delay_off);\r
- if (at134khz)\r
- FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz\r
- else\r
- FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz\r
-\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);\r
- LED_D_ON();\r
- if(*(command++) == '0')\r
- SpinDelayUs(period_0);\r
- else\r
- SpinDelayUs(period_1);\r
- }\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
- LED_D_OFF();\r
- SpinDelayUs(delay_off);\r
- if (at134khz)\r
- FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz\r
- else\r
- FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz\r
-\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);\r
-\r
- // now do the read\r
- DoAcquisition125k();\r
-}\r
-\r
-/* blank r/w tag data stream\r
-...0000000000000000 01111111\r
-1010101010101010101010101010101010101010101010101010101010101010\r
-0011010010100001\r
-01111111\r
-101010101010101[0]000...\r
-\r
-[5555fe852c5555555555555555fe0000]\r
-*/\r
-void ReadTItag(void)\r
-{\r
- // some hardcoded initial params\r
- // when we read a TI tag we sample the zerocross line at 2Mhz\r
- // TI tags modulate a 1 as 16 cycles of 123.2Khz\r
- // TI tags modulate a 0 as 16 cycles of 134.2Khz\r
- #define FSAMPLE 2000000\r
- #define FREQLO 123200\r
- #define FREQHI 134200\r
-\r
- signed char *dest = (signed char *)BigBuf;\r
- int n = sizeof(BigBuf);\r
-// int *dest = GraphBuffer;\r
-// int n = GraphTraceLen;\r
-\r
- // 128 bit shift register [shift3:shift2:shift1:shift0]\r
- DWORD shift3 = 0, shift2 = 0, shift1 = 0, shift0 = 0;\r
-\r
- int i, cycles=0, samples=0;\r
- // how many sample points fit in 16 cycles of each frequency\r
- DWORD sampleslo = (FSAMPLE<<4)/FREQLO, sampleshi = (FSAMPLE<<4)/FREQHI;\r
- // when to tell if we're close enough to one freq or another\r
- DWORD threshold = (sampleslo - sampleshi + 1)>>1;\r
-\r
- // TI tags charge at 134.2Khz\r
- FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz\r
-\r
- // Place FPGA in passthrough mode, in this mode the CROSS_LO line\r
- // connects to SSP_DIN and the SSP_DOUT logic level controls\r
- // whether we're modulating the antenna (high)\r
- // or listening to the antenna (low)\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU);\r
-\r
- // get TI tag data into the buffer\r
- AcquireTiType();\r
-\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
-\r
- for (i=0; i<n-1; i++) {\r
- // count cycles by looking for lo to hi zero crossings\r
- if ( (dest[i]<0) && (dest[i+1]>0) ) {\r
- cycles++;\r
- // after 16 cycles, measure the frequency\r
- if (cycles>15) {\r
- cycles=0;\r
- samples=i-samples; // number of samples in these 16 cycles\r
-\r
- // TI bits are coming to us lsb first so shift them\r
- // right through our 128 bit right shift register\r
- shift0 = (shift0>>1) | (shift1 << 31);\r
- shift1 = (shift1>>1) | (shift2 << 31);\r
- shift2 = (shift2>>1) | (shift3 << 31);\r
- shift3 >>= 1;\r
-\r
- // check if the cycles fall close to the number\r
- // expected for either the low or high frequency\r
- if ( (samples>(sampleslo-threshold)) && (samples<(sampleslo+threshold)) ) {\r
- // low frequency represents a 1\r
- shift3 |= (1<<31);\r
- } else if ( (samples>(sampleshi-threshold)) && (samples<(sampleshi+threshold)) ) {\r
- // high frequency represents a 0\r
- } else {\r
- // probably detected a gay waveform or noise\r
- // use this as gaydar or discard shift register and start again\r
- shift3 = shift2 = shift1 = shift0 = 0;\r
- }\r
- samples = i;\r
-\r
- // for each bit we receive, test if we've detected a valid tag\r
-\r
- // if we see 17 zeroes followed by 6 ones, we might have a tag\r
- // remember the bits are backwards\r
- if ( ((shift0 & 0x7fffff) == 0x7e0000) ) {\r
- // if start and end bytes match, we have a tag so break out of the loop\r
- if ( ((shift0>>16)&0xff) == ((shift3>>8)&0xff) ) {\r
- cycles = 0xF0B; //use this as a flag (ugly but whatever)\r
- break;\r
- }\r
- }\r
- }\r
- }\r
- }\r
-\r
- // if flag is set we have a tag\r
- if (cycles!=0xF0B) {\r
- DbpString("Info: No valid tag detected.");\r
- } else {\r
- // put 64 bit data into shift1 and shift0\r
- shift0 = (shift0>>24) | (shift1 << 8);\r
- shift1 = (shift1>>24) | (shift2 << 8);\r
-\r
- // align 16 bit crc into lower half of shift2\r
- shift2 = ((shift2>>24) | (shift3 << 8)) & 0x0ffff;\r
-\r
- // if r/w tag, check ident match\r
- if ( shift3&(1<<15) ) {\r
- DbpString("Info: TI tag is rewriteable");\r
- // only 15 bits compare, last bit of ident is not valid\r
- if ( ((shift3>>16)^shift0)&0x7fff ) {\r
- DbpString("Error: Ident mismatch!");\r
- } else {\r
- DbpString("Info: TI tag ident is valid");\r
- }\r
- } else {\r
- DbpString("Info: TI tag is readonly");\r
- }\r
-\r
- // WARNING the order of the bytes in which we calc crc below needs checking\r
- // i'm 99% sure the crc algorithm is correct, but it may need to eat the\r
- // bytes in reverse or something\r
- // calculate CRC\r
- DWORD crc=0;\r
-\r
- crc = update_crc16(crc, (shift0)&0xff);\r
- crc = update_crc16(crc, (shift0>>8)&0xff);\r
- crc = update_crc16(crc, (shift0>>16)&0xff);\r
- crc = update_crc16(crc, (shift0>>24)&0xff);\r
- crc = update_crc16(crc, (shift1)&0xff);\r
- crc = update_crc16(crc, (shift1>>8)&0xff);\r
- crc = update_crc16(crc, (shift1>>16)&0xff);\r
- crc = update_crc16(crc, (shift1>>24)&0xff);\r
-\r
- Dbprintf("Info: Tag data: %x%08x, crc=%x",\r
- (unsigned int)shift1, (unsigned int)shift0, (unsigned int)shift2 & 0xFFFF);\r
- if (crc != (shift2&0xffff)) {\r
- Dbprintf("Error: CRC mismatch, expected %x", (unsigned int)crc);\r
- } else {\r
- DbpString("Info: CRC is good");\r
- }\r
- }\r
-}\r
-\r
-void WriteTIbyte(BYTE b)\r
-{\r
- int i = 0;\r
-\r
- // modulate 8 bits out to the antenna\r
- for (i=0; i<8; i++)\r
- {\r
- if (b&(1<<i)) {\r
- // stop modulating antenna\r
- LOW(GPIO_SSC_DOUT);\r
- SpinDelayUs(1000);\r
- // modulate antenna\r
- HIGH(GPIO_SSC_DOUT);\r
- SpinDelayUs(1000);\r
- } else {\r
- // stop modulating antenna\r
- LOW(GPIO_SSC_DOUT);\r
- SpinDelayUs(300);\r
- // modulate antenna\r
- HIGH(GPIO_SSC_DOUT);\r
- SpinDelayUs(1700);\r
- }\r
- }\r
-}\r
-\r
-void AcquireTiType(void)\r
-{\r
- int i, j, n;\r
- // tag transmission is <20ms, sampling at 2M gives us 40K samples max\r
- // each sample is 1 bit stuffed into a DWORD so we need 1250 DWORDS\r
- #define TIBUFLEN 1250\r
-\r
- // clear buffer\r
- memset(BigBuf,0,sizeof(BigBuf));\r
-\r
- // Set up the synchronous serial port\r
- AT91C_BASE_PIOA->PIO_PDR = GPIO_SSC_DIN;\r
- AT91C_BASE_PIOA->PIO_ASR = GPIO_SSC_DIN;\r
-\r
- // steal this pin from the SSP and use it to control the modulation\r
- AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT;\r
- AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;\r
-\r
- AT91C_BASE_SSC->SSC_CR = AT91C_SSC_SWRST;\r
- AT91C_BASE_SSC->SSC_CR = AT91C_SSC_RXEN | AT91C_SSC_TXEN;\r
-\r
- // Sample at 2 Mbit/s, so TI tags are 16.2 vs. 14.9 clocks long\r
- // 48/2 = 24 MHz clock must be divided by 12\r
- AT91C_BASE_SSC->SSC_CMR = 12;\r
-\r
- AT91C_BASE_SSC->SSC_RCMR = SSC_CLOCK_MODE_SELECT(0);\r
- AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(32) | AT91C_SSC_MSBF;\r
- AT91C_BASE_SSC->SSC_TCMR = 0;\r
- AT91C_BASE_SSC->SSC_TFMR = 0;\r
-\r
- LED_D_ON();\r
-\r
- // modulate antenna\r
- HIGH(GPIO_SSC_DOUT);\r
-\r
- // Charge TI tag for 50ms.\r
- SpinDelay(50);\r
-\r
- // stop modulating antenna and listen\r
- LOW(GPIO_SSC_DOUT);\r
-\r
- LED_D_OFF();\r
-\r
- i = 0;\r
- for(;;) {\r
- if(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {\r
- BigBuf[i] = AT91C_BASE_SSC->SSC_RHR; // store 32 bit values in buffer\r
- i++; if(i >= TIBUFLEN) break;\r
- }\r
- WDT_HIT();\r
- }\r
-\r
- // return stolen pin to SSP\r
- AT91C_BASE_PIOA->PIO_PDR = GPIO_SSC_DOUT;\r
- AT91C_BASE_PIOA->PIO_ASR = GPIO_SSC_DIN | GPIO_SSC_DOUT;\r
-\r
- char *dest = (char *)BigBuf;\r
- n = TIBUFLEN*32;\r
- // unpack buffer\r
- for (i=TIBUFLEN-1; i>=0; i--) {\r
- for (j=0; j<32; j++) {\r
- if(BigBuf[i] & (1 << j)) {\r
- dest[--n] = 1;\r
- } else {\r
- dest[--n] = -1;\r
- }\r
- }\r
- }\r
-}\r
-\r
-// arguments: 64bit data split into 32bit idhi:idlo and optional 16bit crc\r
-// if crc provided, it will be written with the data verbatim (even if bogus)\r
-// if not provided a valid crc will be computed from the data and written.\r
-void WriteTItag(DWORD idhi, DWORD idlo, WORD crc)\r
-{\r
- if(crc == 0) {\r
- crc = update_crc16(crc, (idlo)&0xff);\r
- crc = update_crc16(crc, (idlo>>8)&0xff);\r
- crc = update_crc16(crc, (idlo>>16)&0xff);\r
- crc = update_crc16(crc, (idlo>>24)&0xff);\r
- crc = update_crc16(crc, (idhi)&0xff);\r
- crc = update_crc16(crc, (idhi>>8)&0xff);\r
- crc = update_crc16(crc, (idhi>>16)&0xff);\r
- crc = update_crc16(crc, (idhi>>24)&0xff);\r
- }\r
- Dbprintf("Writing to tag: %x%08x, crc=%x",\r
- (unsigned int) idhi, (unsigned int) idlo, crc);\r
-\r
- // TI tags charge at 134.2Khz\r
- FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz\r
- // Place FPGA in passthrough mode, in this mode the CROSS_LO line\r
- // connects to SSP_DIN and the SSP_DOUT logic level controls\r
- // whether we're modulating the antenna (high)\r
- // or listening to the antenna (low)\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU);\r
- LED_A_ON();\r
-\r
- // steal this pin from the SSP and use it to control the modulation\r
- AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT;\r
- AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;\r
-\r
- // writing algorithm:\r
- // a high bit consists of a field off for 1ms and field on for 1ms\r
- // a low bit consists of a field off for 0.3ms and field on for 1.7ms\r
- // initiate a charge time of 50ms (field on) then immediately start writing bits\r
- // start by writing 0xBB (keyword) and 0xEB (password)\r
- // then write 80 bits of data (or 64 bit data + 16 bit crc if you prefer)\r
- // finally end with 0x0300 (write frame)\r
- // all data is sent lsb firts\r
- // finish with 15ms programming time\r
-\r
- // modulate antenna\r
- HIGH(GPIO_SSC_DOUT);\r
- SpinDelay(50); // charge time\r
-\r
- WriteTIbyte(0xbb); // keyword\r
- WriteTIbyte(0xeb); // password\r
- WriteTIbyte( (idlo )&0xff );\r
- WriteTIbyte( (idlo>>8 )&0xff );\r
- WriteTIbyte( (idlo>>16)&0xff );\r
- WriteTIbyte( (idlo>>24)&0xff );\r
- WriteTIbyte( (idhi )&0xff );\r
- WriteTIbyte( (idhi>>8 )&0xff );\r
- WriteTIbyte( (idhi>>16)&0xff );\r
- WriteTIbyte( (idhi>>24)&0xff ); // data hi to lo\r
- WriteTIbyte( (crc )&0xff ); // crc lo\r
- WriteTIbyte( (crc>>8 )&0xff ); // crc hi\r
- WriteTIbyte(0x00); // write frame lo\r
- WriteTIbyte(0x03); // write frame hi\r
- HIGH(GPIO_SSC_DOUT);\r
- SpinDelay(50); // programming time\r
-\r
- LED_A_OFF();\r
-\r
- // get TI tag data into the buffer\r
- AcquireTiType();\r
-\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
- DbpString("Now use tiread to check");\r
-}\r
-\r
-void SimulateTagLowFrequency(int period, int gap, int ledcontrol)\r
-{\r
- int i;\r
- BYTE *tab = (BYTE *)BigBuf;\r
-\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_SIMULATOR);\r
-\r
- AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT | GPIO_SSC_CLK;\r
-\r
- AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;\r
- AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_CLK;\r
-\r
-#define SHORT_COIL() LOW(GPIO_SSC_DOUT)\r
-#define OPEN_COIL() HIGH(GPIO_SSC_DOUT)\r
-\r
- i = 0;\r
- for(;;) {\r
- while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) {\r
- if(BUTTON_PRESS()) {\r
- DbpString("Stopped");\r
- return;\r
- }\r
- WDT_HIT();\r
- }\r
-\r
- if (ledcontrol)\r
- LED_D_ON();\r
-\r
- if(tab[i])\r
- OPEN_COIL();\r
- else\r
- SHORT_COIL();\r
-\r
- if (ledcontrol)\r
- LED_D_OFF();\r
-\r
- while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) {\r
- if(BUTTON_PRESS()) {\r
- DbpString("Stopped");\r
- return;\r
- }\r
- WDT_HIT();\r
- }\r
-\r
- i++;\r
- if(i == period) {\r
- i = 0;\r
- if (gap) { \r
- SHORT_COIL();\r
- SpinDelayUs(gap);\r
- }\r
- }\r
- }\r
-}\r
-\r
-/* Provides a framework for bidirectional LF tag communication\r
- * Encoding is currently Hitag2, but the general idea can probably\r
- * be transferred to other encodings.\r
- * \r
- * The new FPGA code will, for the LF simulator mode, give on SSC_FRAME\r
- * (PA15) a thresholded version of the signal from the ADC. Setting the\r
- * ADC path to the low frequency peak detection signal, will enable a\r
- * somewhat reasonable receiver for modulation on the carrier signal\r
- * that is generated by the reader. The signal is low when the reader\r
- * field is switched off, and high when the reader field is active. Due\r
- * to the way that the signal looks like, mostly only the rising edge is\r
- * useful, your mileage may vary.\r
- * \r
- * Neat perk: PA15 can not only be used as a bit-banging GPIO, but is also\r
- * TIOA1, which can be used as the capture input for timer 1. This should\r
- * make it possible to measure the exact edge-to-edge time, without processor\r
- * intervention.\r
- * \r
- * Arguments: divisor is the divisor to be sent to the FPGA (e.g. 95 for 125kHz)\r
- * t0 is the carrier frequency cycle duration in terms of MCK (384 for 125kHz)\r
- * \r
- * The following defines are in carrier periods: \r
- */\r
-#define HITAG_T_0_MIN 15 /* T[0] should be 18..22 */ \r
-#define HITAG_T_1_MIN 24 /* T[1] should be 26..30 */\r
-#define HITAG_T_EOF 40 /* T_EOF should be > 36 */\r
-#define HITAG_T_WRESP 208 /* T_wresp should be 204..212 */\r
-\r
-static void hitag_handle_frame(int t0, int frame_len, char *frame);\r
-//#define DEBUG_RA_VALUES 1\r
-#define DEBUG_FRAME_CONTENTS 1\r
-void SimulateTagLowFrequencyBidir(int divisor, int t0)\r
-{\r
-#if DEBUG_RA_VALUES || DEBUG_FRAME_CONTENTS\r
- int i = 0;\r
-#endif\r
- char frame[10];\r
- int frame_pos=0;\r
- \r
- DbpString("Starting Hitag2 emulator, press button to end");\r
- hitag2_init();\r
- \r
- /* Set up simulator mode, frequency divisor which will drive the FPGA\r
- * and analog mux selection.\r
- */\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_SIMULATOR);\r
- FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor);\r
- SetAdcMuxFor(GPIO_MUXSEL_LOPKD);\r
- RELAY_OFF();\r
- \r
- /* Set up Timer 1:\r
- * Capture mode, timer source MCK/2 (TIMER_CLOCK1), TIOA is external trigger,\r
- * external trigger rising edge, load RA on rising edge of TIOA, load RB on rising\r
- * edge of TIOA. Assign PA15 to TIOA1 (peripheral B)\r
- */\r
- \r
- AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1);\r
- AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME;\r
- AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;\r
- AT91C_BASE_TC1->TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK1 |\r
- AT91C_TC_ETRGEDG_RISING |\r
- AT91C_TC_ABETRG |\r
- AT91C_TC_LDRA_RISING |\r
- AT91C_TC_LDRB_RISING;\r
- AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN |\r
- AT91C_TC_SWTRG;\r
- \r
- /* calculate the new value for the carrier period in terms of TC1 values */\r
- t0 = t0/2;\r
- \r
- int overflow = 0;\r
- while(!BUTTON_PRESS()) {\r
- WDT_HIT();\r
- if(AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) {\r
- int ra = AT91C_BASE_TC1->TC_RA;\r
- if((ra > t0*HITAG_T_EOF) | overflow) ra = t0*HITAG_T_EOF+1;\r
-#if DEBUG_RA_VALUES\r
- if(ra > 255 || overflow) ra = 255;\r
- ((char*)BigBuf)[i] = ra;\r
- i = (i+1) % 8000;\r
-#endif\r
- \r
- if(overflow || (ra > t0*HITAG_T_EOF) || (ra < t0*HITAG_T_0_MIN)) {\r
- /* Ignore */\r
- } else if(ra >= t0*HITAG_T_1_MIN ) {\r
- /* '1' bit */\r
- if(frame_pos < 8*sizeof(frame)) {\r
- frame[frame_pos / 8] |= 1<<( 7-(frame_pos%8) );\r
- frame_pos++;\r
- }\r
- } else if(ra >= t0*HITAG_T_0_MIN) {\r
- /* '0' bit */\r
- if(frame_pos < 8*sizeof(frame)) {\r
- frame[frame_pos / 8] |= 0<<( 7-(frame_pos%8) );\r
- frame_pos++;\r
- }\r
- }\r
- \r
- overflow = 0;\r
- LED_D_ON();\r
- } else {\r
- if(AT91C_BASE_TC1->TC_CV > t0*HITAG_T_EOF) {\r
- /* Minor nuisance: In Capture mode, the timer can not be\r
- * stopped by a Compare C. There's no way to stop the clock\r
- * in software, so we'll just have to note the fact that an\r
- * overflow happened and the next loaded timer value might\r
- * have wrapped. Also, this marks the end of frame, and the\r
- * still running counter can be used to determine the correct\r
- * time for the start of the reply.\r
- */ \r
- overflow = 1;\r
- \r
- if(frame_pos > 0) {\r
- /* Have a frame, do something with it */\r
-#if DEBUG_FRAME_CONTENTS\r
- ((char*)BigBuf)[i++] = frame_pos;\r
- memcpy( ((char*)BigBuf)+i, frame, 7);\r
- i+=7;\r
- i = i % sizeof(BigBuf);\r
-#endif\r
- hitag_handle_frame(t0, frame_pos, frame);\r
- memset(frame, 0, sizeof(frame));\r
- }\r
- frame_pos = 0;\r
-\r
- }\r
- LED_D_OFF();\r
- }\r
- }\r
- DbpString("All done");\r
-}\r
-\r
-static void hitag_send_bit(int t0, int bit) {\r
- if(bit == 1) {\r
- /* Manchester: Loaded, then unloaded */\r
- LED_A_ON();\r
- SHORT_COIL();\r
- while(AT91C_BASE_TC1->TC_CV < t0*15);\r
- OPEN_COIL();\r
- while(AT91C_BASE_TC1->TC_CV < t0*31);\r
- LED_A_OFF();\r
- } else if(bit == 0) {\r
- /* Manchester: Unloaded, then loaded */\r
- LED_B_ON();\r
- OPEN_COIL();\r
- while(AT91C_BASE_TC1->TC_CV < t0*15);\r
- SHORT_COIL();\r
- while(AT91C_BASE_TC1->TC_CV < t0*31);\r
- LED_B_OFF();\r
- }\r
- AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; /* Reset clock for the next bit */\r
- \r
-}\r
-static void hitag_send_frame(int t0, int frame_len, const char const * frame, int fdt)\r
-{\r
- OPEN_COIL();\r
- AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;\r
- \r
- /* Wait for HITAG_T_WRESP carrier periods after the last reader bit,\r
- * not that since the clock counts since the rising edge, but T_wresp is\r
- * with respect to the falling edge, we need to wait actually (T_wresp - T_g)\r
- * periods. The gap time T_g varies (4..10).\r
- */\r
- while(AT91C_BASE_TC1->TC_CV < t0*(fdt-8));\r
-\r
- int saved_cmr = AT91C_BASE_TC1->TC_CMR;\r
- AT91C_BASE_TC1->TC_CMR &= ~AT91C_TC_ETRGEDG; /* Disable external trigger for the clock */\r
- AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; /* Reset the clock and use it for response timing */\r
- \r
- int i;\r
- for(i=0; i<5; i++)\r
- hitag_send_bit(t0, 1); /* Start of frame */\r
- \r
- for(i=0; i<frame_len; i++) {\r
- hitag_send_bit(t0, !!(frame[i/ 8] & (1<<( 7-(i%8) ))) );\r
- }\r
- \r
- OPEN_COIL();\r
- AT91C_BASE_TC1->TC_CMR = saved_cmr;\r
-}\r
-\r
-/* Callback structure to cleanly separate tag emulation code from the radio layer. */\r
-static int hitag_cb(const char* response_data, const int response_length, const int fdt, void *cb_cookie)\r
-{\r
- hitag_send_frame(*(int*)cb_cookie, response_length, response_data, fdt);\r
- return 0;\r
-}\r
-/* Frame length in bits, frame contents in MSBit first format */\r
-static void hitag_handle_frame(int t0, int frame_len, char *frame)\r
-{\r
- hitag2_handle_command(frame, frame_len, hitag_cb, &t0);\r
-}\r
-\r
-// compose fc/8 fc/10 waveform\r
-static void fc(int c, int *n) {\r
- BYTE *dest = (BYTE *)BigBuf;\r
- int idx;\r
-\r
- // for when we want an fc8 pattern every 4 logical bits\r
- if(c==0) {\r
- dest[((*n)++)]=1;\r
- dest[((*n)++)]=1;\r
- dest[((*n)++)]=0;\r
- dest[((*n)++)]=0;\r
- dest[((*n)++)]=0;\r
- dest[((*n)++)]=0;\r
- dest[((*n)++)]=0;\r
- dest[((*n)++)]=0;\r
- }\r
- // an fc/8 encoded bit is a bit pattern of 11000000 x6 = 48 samples\r
- if(c==8) {\r
- for (idx=0; idx<6; idx++) {\r
- dest[((*n)++)]=1;\r
- dest[((*n)++)]=1;\r
- dest[((*n)++)]=0;\r
- dest[((*n)++)]=0;\r
- dest[((*n)++)]=0;\r
- dest[((*n)++)]=0;\r
- dest[((*n)++)]=0;\r
- dest[((*n)++)]=0;\r
- }\r
- }\r
-\r
- // an fc/10 encoded bit is a bit pattern of 1110000000 x5 = 50 samples\r
- if(c==10) {\r
- for (idx=0; idx<5; idx++) {\r
- dest[((*n)++)]=1;\r
- dest[((*n)++)]=1;\r
- dest[((*n)++)]=1;\r
- dest[((*n)++)]=0;\r
- dest[((*n)++)]=0;\r
- dest[((*n)++)]=0;\r
- dest[((*n)++)]=0;\r
- dest[((*n)++)]=0;\r
- dest[((*n)++)]=0;\r
- dest[((*n)++)]=0;\r
- }\r
- }\r
-}\r
-\r
-// prepare a waveform pattern in the buffer based on the ID given then\r
-// simulate a HID tag until the button is pressed\r
-void CmdHIDsimTAG(int hi, int lo, int ledcontrol)\r
-{\r
- int n=0, i=0;\r
- /*\r
- HID tag bitstream format\r
- The tag contains a 44bit unique code. This is sent out MSB first in sets of 4 bits\r
- A 1 bit is represented as 6 fc8 and 5 fc10 patterns\r
- A 0 bit is represented as 5 fc10 and 6 fc8 patterns\r
- A fc8 is inserted before every 4 bits\r
- A special start of frame pattern is used consisting a0b0 where a and b are neither 0\r
- nor 1 bits, they are special patterns (a = set of 12 fc8 and b = set of 10 fc10)\r
- */\r
-\r
- if (hi>0xFFF) {\r
- DbpString("Tags can only have 44 bits.");\r
- return;\r
- }\r
- fc(0,&n);\r
- // special start of frame marker containing invalid bit sequences\r
- fc(8, &n); fc(8, &n); // invalid\r
- fc(8, &n); fc(10, &n); // logical 0\r
- fc(10, &n); fc(10, &n); // invalid\r
- fc(8, &n); fc(10, &n); // logical 0\r
-\r
- WDT_HIT();\r
- // manchester encode bits 43 to 32\r
- for (i=11; i>=0; i--) {\r
- if ((i%4)==3) fc(0,&n);\r
- if ((hi>>i)&1) {\r
- fc(10, &n); fc(8, &n); // low-high transition\r
- } else {\r
- fc(8, &n); fc(10, &n); // high-low transition\r
- }\r
- }\r
-\r
- WDT_HIT();\r
- // manchester encode bits 31 to 0\r
- for (i=31; i>=0; i--) {\r
- if ((i%4)==3) fc(0,&n);\r
- if ((lo>>i)&1) {\r
- fc(10, &n); fc(8, &n); // low-high transition\r
- } else {\r
- fc(8, &n); fc(10, &n); // high-low transition\r
- }\r
- }\r
-\r
- if (ledcontrol)\r
- LED_A_ON();\r
- SimulateTagLowFrequency(n, 0, ledcontrol);\r
-\r
- if (ledcontrol)\r
- LED_A_OFF();\r
-}\r
-\r
-\r
-// loop to capture raw HID waveform then FSK demodulate the TAG ID from it\r
-void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol)\r
-{\r
- BYTE *dest = (BYTE *)BigBuf;\r
- int m=0, n=0, i=0, idx=0, found=0, lastval=0;\r
- DWORD hi=0, lo=0;\r
-\r
- FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);\r
-\r
- // Connect the A/D to the peak-detected low-frequency path.\r
- SetAdcMuxFor(GPIO_MUXSEL_LOPKD);\r
-\r
- // Give it a bit of time for the resonant antenna to settle.\r
- SpinDelay(50);\r
-\r
- // Now set up the SSC to get the ADC samples that are now streaming at us.\r
- FpgaSetupSsc();\r
-\r
- for(;;) {\r
- WDT_HIT();\r
- if (ledcontrol)\r
- LED_A_ON();\r
- if(BUTTON_PRESS()) {\r
- DbpString("Stopped");\r
- if (ledcontrol)\r
- LED_A_OFF();\r
- return;\r
- }\r
-\r
- i = 0;\r
- m = sizeof(BigBuf);\r
- memset(dest,128,m);\r
- for(;;) {\r
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {\r
- AT91C_BASE_SSC->SSC_THR = 0x43;\r
- if (ledcontrol)\r
- LED_D_ON();\r
- }\r
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {\r
- dest[i] = (BYTE)AT91C_BASE_SSC->SSC_RHR;\r
- // we don't care about actual value, only if it's more or less than a\r
- // threshold essentially we capture zero crossings for later analysis\r
- if(dest[i] < 127) dest[i] = 0; else dest[i] = 1;\r
- i++;\r
- if (ledcontrol)\r
- LED_D_OFF();\r
- if(i >= m) {\r
- break;\r
- }\r
- }\r
- }\r
-\r
- // FSK demodulator\r
-\r
- // sync to first lo-hi transition\r
- for( idx=1; idx<m; idx++) {\r
- if (dest[idx-1]<dest[idx])\r
- lastval=idx;\r
- break;\r
- }\r
- WDT_HIT();\r
-\r
- // count cycles between consecutive lo-hi transitions, there should be either 8 (fc/8)\r
- // or 10 (fc/10) cycles but in practice due to noise etc we may end up with with anywhere\r
- // between 7 to 11 cycles so fuzz it by treat anything <9 as 8 and anything else as 10\r
- for( i=0; idx<m; idx++) {\r
- if (dest[idx-1]<dest[idx]) {\r
- dest[i]=idx-lastval;\r
- if (dest[i] <= 8) {\r
- dest[i]=1;\r
- } else {\r
- dest[i]=0;\r
- }\r
-\r
- lastval=idx;\r
- i++;\r
- }\r
- }\r
- m=i;\r
- WDT_HIT();\r
-\r
- // we now have a set of cycle counts, loop over previous results and aggregate data into bit patterns\r
- lastval=dest[0];\r
- idx=0;\r
- i=0;\r
- n=0;\r
- for( idx=0; idx<m; idx++) {\r
- if (dest[idx]==lastval) {\r
- n++;\r
- } else {\r
- // a bit time is five fc/10 or six fc/8 cycles so figure out how many bits a pattern width represents,\r
- // an extra fc/8 pattern preceeds every 4 bits (about 200 cycles) just to complicate things but it gets\r
- // swallowed up by rounding\r
- // expected results are 1 or 2 bits, any more and it's an invalid manchester encoding\r
- // special start of frame markers use invalid manchester states (no transitions) by using sequences\r
- // like 111000\r
- if (dest[idx-1]) {\r
- n=(n+1)/6; // fc/8 in sets of 6\r
- } else {\r
- n=(n+1)/5; // fc/10 in sets of 5\r
- }\r
- switch (n) { // stuff appropriate bits in buffer\r
- case 0:\r
- case 1: // one bit\r
- dest[i++]=dest[idx-1];\r
- break;\r
- case 2: // two bits\r
- dest[i++]=dest[idx-1];\r
- dest[i++]=dest[idx-1];\r
- break;\r
- case 3: // 3 bit start of frame markers\r
- dest[i++]=dest[idx-1];\r
- dest[i++]=dest[idx-1];\r
- dest[i++]=dest[idx-1];\r
- break;\r
- // When a logic 0 is immediately followed by the start of the next transmisson\r
- // (special pattern) a pattern of 4 bit duration lengths is created.\r
- case 4:\r
- dest[i++]=dest[idx-1];\r
- dest[i++]=dest[idx-1];\r
- dest[i++]=dest[idx-1];\r
- dest[i++]=dest[idx-1];\r
- break;\r
- default: // this shouldn't happen, don't stuff any bits\r
- break;\r
- }\r
- n=0;\r
- lastval=dest[idx];\r
- }\r
- }\r
- m=i;\r
- WDT_HIT();\r
-\r
- // final loop, go over previously decoded manchester data and decode into usable tag ID\r
- // 111000 bit pattern represent start of frame, 01 pattern represents a 1 and 10 represents a 0\r
- for( idx=0; idx<m-6; idx++) {\r
- // search for a start of frame marker\r
- if ( dest[idx] && dest[idx+1] && dest[idx+2] && (!dest[idx+3]) && (!dest[idx+4]) && (!dest[idx+5]) )\r
- {\r
- found=1;\r
- idx+=6;\r
- if (found && (hi|lo)) {\r
- Dbprintf("TAG ID: %x%08x (%d)",\r
- (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF);\r
- /* if we're only looking for one tag */\r
- if (findone)\r
- {\r
- *high = hi;\r
- *low = lo;\r
- return;\r
- }\r
- hi=0;\r
- lo=0;\r
- found=0;\r
- }\r
- }\r
- if (found) {\r
- if (dest[idx] && (!dest[idx+1]) ) {\r
- hi=(hi<<1)|(lo>>31);\r
- lo=(lo<<1)|0;\r
- } else if ( (!dest[idx]) && dest[idx+1]) {\r
- hi=(hi<<1)|(lo>>31);\r
- lo=(lo<<1)|1;\r
- } else {\r
- found=0;\r
- hi=0;\r
- lo=0;\r
- }\r
- idx++;\r
- }\r
- if ( dest[idx] && dest[idx+1] && dest[idx+2] && (!dest[idx+3]) && (!dest[idx+4]) && (!dest[idx+5]) )\r
- {\r
- found=1;\r
- idx+=6;\r
- if (found && (hi|lo)) {\r
- Dbprintf("TAG ID: %x%08x (%d)",\r
- (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF);\r
- /* if we're only looking for one tag */\r
- if (findone)\r
- {\r
- *high = hi;\r
- *low = lo;\r
- return;\r
- }\r
- hi=0;\r
- lo=0;\r
- found=0;\r
- }\r
- }\r
- }\r
- WDT_HIT();\r
- }\r
-}\r
+//-----------------------------------------------------------------------------
+// Miscellaneous routines for low frequency tag operations.
+// Tags supported here so far are Texas Instruments (TI), HID
+// Also routines for raw mode reading/simulating of LF waveform
+//
+//-----------------------------------------------------------------------------
+#include <proxmark3.h>
+#include "apps.h"
+#include "hitag2.h"
+#include "crc16.h"
+
+void AcquireRawAdcSamples125k(BOOL at134khz)
+{
+ if (at134khz)
+ FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz
+ else
+ FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
+
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);
+
+ // Connect the A/D to the peak-detected low-frequency path.
+ SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
+
+ // Give it a bit of time for the resonant antenna to settle.
+ SpinDelay(50);
+
+ // Now set up the SSC to get the ADC samples that are now streaming at us.
+ FpgaSetupSsc();
+
+ // Now call the acquisition routine
+ DoAcquisition125k();
+}
+
+// split into two routines so we can avoid timing issues after sending commands //
+void DoAcquisition125k(void)
+{
+ BYTE *dest = (BYTE *)BigBuf;
+ int n = sizeof(BigBuf);
+ int i;
+
+ memset(dest, 0, n);
+ i = 0;
+ for(;;) {
+ if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) {
+ AT91C_BASE_SSC->SSC_THR = 0x43;
+ LED_D_ON();
+ }
+ if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
+ dest[i] = (BYTE)AT91C_BASE_SSC->SSC_RHR;
+ i++;
+ LED_D_OFF();
+ if (i >= n) break;
+ }
+ }
+ Dbprintf("buffer samples: %02x %02x %02x %02x %02x %02x %02x %02x ...",
+ dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]);
+}
+
+void ModThenAcquireRawAdcSamples125k(int delay_off, int period_0, int period_1, BYTE *command)
+{
+ BOOL at134khz;
+
+ /* Make sure the tag is reset */
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+ SpinDelay(2500);
+
+ // see if 'h' was specified
+ if (command[strlen((char *) command) - 1] == 'h')
+ at134khz = TRUE;
+ else
+ at134khz = FALSE;
+
+ if (at134khz)
+ FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz
+ else
+ FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
+
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);
+
+ // Give it a bit of time for the resonant antenna to settle.
+ SpinDelay(50);
+ // And a little more time for the tag to fully power up
+ SpinDelay(2000);
+
+ // Now set up the SSC to get the ADC samples that are now streaming at us.
+ FpgaSetupSsc();
+
+ // now modulate the reader field
+ while(*command != '\0' && *command != ' ') {
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+ LED_D_OFF();
+ SpinDelayUs(delay_off);
+ if (at134khz)
+ FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz
+ else
+ FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
+
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);
+ LED_D_ON();
+ if(*(command++) == '0')
+ SpinDelayUs(period_0);
+ else
+ SpinDelayUs(period_1);
+ }
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+ LED_D_OFF();
+ SpinDelayUs(delay_off);
+ if (at134khz)
+ FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz
+ else
+ FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
+
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);
+
+ // now do the read
+ DoAcquisition125k();
+}
+
+/* blank r/w tag data stream
+...0000000000000000 01111111
+1010101010101010101010101010101010101010101010101010101010101010
+0011010010100001
+01111111
+101010101010101[0]000...
+
+[5555fe852c5555555555555555fe0000]
+*/
+void ReadTItag(void)
+{
+ // some hardcoded initial params
+ // when we read a TI tag we sample the zerocross line at 2Mhz
+ // TI tags modulate a 1 as 16 cycles of 123.2Khz
+ // TI tags modulate a 0 as 16 cycles of 134.2Khz
+ #define FSAMPLE 2000000
+ #define FREQLO 123200
+ #define FREQHI 134200
+
+ signed char *dest = (signed char *)BigBuf;
+ int n = sizeof(BigBuf);
+// int *dest = GraphBuffer;
+// int n = GraphTraceLen;
+
+ // 128 bit shift register [shift3:shift2:shift1:shift0]
+ DWORD shift3 = 0, shift2 = 0, shift1 = 0, shift0 = 0;
+
+ int i, cycles=0, samples=0;
+ // how many sample points fit in 16 cycles of each frequency
+ DWORD sampleslo = (FSAMPLE<<4)/FREQLO, sampleshi = (FSAMPLE<<4)/FREQHI;
+ // when to tell if we're close enough to one freq or another
+ DWORD threshold = (sampleslo - sampleshi + 1)>>1;
+
+ // TI tags charge at 134.2Khz
+ FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz
+
+ // Place FPGA in passthrough mode, in this mode the CROSS_LO line
+ // connects to SSP_DIN and the SSP_DOUT logic level controls
+ // whether we're modulating the antenna (high)
+ // or listening to the antenna (low)
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU);
+
+ // get TI tag data into the buffer
+ AcquireTiType();
+
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+
+ for (i=0; i<n-1; i++) {
+ // count cycles by looking for lo to hi zero crossings
+ if ( (dest[i]<0) && (dest[i+1]>0) ) {
+ cycles++;
+ // after 16 cycles, measure the frequency
+ if (cycles>15) {
+ cycles=0;
+ samples=i-samples; // number of samples in these 16 cycles
+
+ // TI bits are coming to us lsb first so shift them
+ // right through our 128 bit right shift register
+ shift0 = (shift0>>1) | (shift1 << 31);
+ shift1 = (shift1>>1) | (shift2 << 31);
+ shift2 = (shift2>>1) | (shift3 << 31);
+ shift3 >>= 1;
+
+ // check if the cycles fall close to the number
+ // expected for either the low or high frequency
+ if ( (samples>(sampleslo-threshold)) && (samples<(sampleslo+threshold)) ) {
+ // low frequency represents a 1
+ shift3 |= (1<<31);
+ } else if ( (samples>(sampleshi-threshold)) && (samples<(sampleshi+threshold)) ) {
+ // high frequency represents a 0
+ } else {
+ // probably detected a gay waveform or noise
+ // use this as gaydar or discard shift register and start again
+ shift3 = shift2 = shift1 = shift0 = 0;
+ }
+ samples = i;
+
+ // for each bit we receive, test if we've detected a valid tag
+
+ // if we see 17 zeroes followed by 6 ones, we might have a tag
+ // remember the bits are backwards
+ if ( ((shift0 & 0x7fffff) == 0x7e0000) ) {
+ // if start and end bytes match, we have a tag so break out of the loop
+ if ( ((shift0>>16)&0xff) == ((shift3>>8)&0xff) ) {
+ cycles = 0xF0B; //use this as a flag (ugly but whatever)
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // if flag is set we have a tag
+ if (cycles!=0xF0B) {
+ DbpString("Info: No valid tag detected.");
+ } else {
+ // put 64 bit data into shift1 and shift0
+ shift0 = (shift0>>24) | (shift1 << 8);
+ shift1 = (shift1>>24) | (shift2 << 8);
+
+ // align 16 bit crc into lower half of shift2
+ shift2 = ((shift2>>24) | (shift3 << 8)) & 0x0ffff;
+
+ // if r/w tag, check ident match
+ if ( shift3&(1<<15) ) {
+ DbpString("Info: TI tag is rewriteable");
+ // only 15 bits compare, last bit of ident is not valid
+ if ( ((shift3>>16)^shift0)&0x7fff ) {
+ DbpString("Error: Ident mismatch!");
+ } else {
+ DbpString("Info: TI tag ident is valid");
+ }
+ } else {
+ DbpString("Info: TI tag is readonly");
+ }
+
+ // WARNING the order of the bytes in which we calc crc below needs checking
+ // i'm 99% sure the crc algorithm is correct, but it may need to eat the
+ // bytes in reverse or something
+ // calculate CRC
+ DWORD crc=0;
+
+ crc = update_crc16(crc, (shift0)&0xff);
+ crc = update_crc16(crc, (shift0>>8)&0xff);
+ crc = update_crc16(crc, (shift0>>16)&0xff);
+ crc = update_crc16(crc, (shift0>>24)&0xff);
+ crc = update_crc16(crc, (shift1)&0xff);
+ crc = update_crc16(crc, (shift1>>8)&0xff);
+ crc = update_crc16(crc, (shift1>>16)&0xff);
+ crc = update_crc16(crc, (shift1>>24)&0xff);
+
+ Dbprintf("Info: Tag data: %x%08x, crc=%x",
+ (unsigned int)shift1, (unsigned int)shift0, (unsigned int)shift2 & 0xFFFF);
+ if (crc != (shift2&0xffff)) {
+ Dbprintf("Error: CRC mismatch, expected %x", (unsigned int)crc);
+ } else {
+ DbpString("Info: CRC is good");
+ }
+ }
+}
+
+void WriteTIbyte(BYTE b)
+{
+ int i = 0;
+
+ // modulate 8 bits out to the antenna
+ for (i=0; i<8; i++)
+ {
+ if (b&(1<<i)) {
+ // stop modulating antenna
+ LOW(GPIO_SSC_DOUT);
+ SpinDelayUs(1000);
+ // modulate antenna
+ HIGH(GPIO_SSC_DOUT);
+ SpinDelayUs(1000);
+ } else {
+ // stop modulating antenna
+ LOW(GPIO_SSC_DOUT);
+ SpinDelayUs(300);
+ // modulate antenna
+ HIGH(GPIO_SSC_DOUT);
+ SpinDelayUs(1700);
+ }
+ }
+}
+
+void AcquireTiType(void)
+{
+ int i, j, n;
+ // tag transmission is <20ms, sampling at 2M gives us 40K samples max
+ // each sample is 1 bit stuffed into a DWORD so we need 1250 DWORDS
+ #define TIBUFLEN 1250
+
+ // clear buffer
+ memset(BigBuf,0,sizeof(BigBuf));
+
+ // Set up the synchronous serial port
+ AT91C_BASE_PIOA->PIO_PDR = GPIO_SSC_DIN;
+ AT91C_BASE_PIOA->PIO_ASR = GPIO_SSC_DIN;
+
+ // steal this pin from the SSP and use it to control the modulation
+ AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT;
+ AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;
+
+ AT91C_BASE_SSC->SSC_CR = AT91C_SSC_SWRST;
+ AT91C_BASE_SSC->SSC_CR = AT91C_SSC_RXEN | AT91C_SSC_TXEN;
+
+ // Sample at 2 Mbit/s, so TI tags are 16.2 vs. 14.9 clocks long
+ // 48/2 = 24 MHz clock must be divided by 12
+ AT91C_BASE_SSC->SSC_CMR = 12;
+
+ AT91C_BASE_SSC->SSC_RCMR = SSC_CLOCK_MODE_SELECT(0);
+ AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(32) | AT91C_SSC_MSBF;
+ AT91C_BASE_SSC->SSC_TCMR = 0;
+ AT91C_BASE_SSC->SSC_TFMR = 0;
+
+ LED_D_ON();
+
+ // modulate antenna
+ HIGH(GPIO_SSC_DOUT);
+
+ // Charge TI tag for 50ms.
+ SpinDelay(50);
+
+ // stop modulating antenna and listen
+ LOW(GPIO_SSC_DOUT);
+
+ LED_D_OFF();
+
+ i = 0;
+ for(;;) {
+ if(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
+ BigBuf[i] = AT91C_BASE_SSC->SSC_RHR; // store 32 bit values in buffer
+ i++; if(i >= TIBUFLEN) break;
+ }
+ WDT_HIT();
+ }
+
+ // return stolen pin to SSP
+ AT91C_BASE_PIOA->PIO_PDR = GPIO_SSC_DOUT;
+ AT91C_BASE_PIOA->PIO_ASR = GPIO_SSC_DIN | GPIO_SSC_DOUT;
+
+ char *dest = (char *)BigBuf;
+ n = TIBUFLEN*32;
+ // unpack buffer
+ for (i=TIBUFLEN-1; i>=0; i--) {
+ for (j=0; j<32; j++) {
+ if(BigBuf[i] & (1 << j)) {
+ dest[--n] = 1;
+ } else {
+ dest[--n] = -1;
+ }
+ }
+ }
+}
+
+// arguments: 64bit data split into 32bit idhi:idlo and optional 16bit crc
+// if crc provided, it will be written with the data verbatim (even if bogus)
+// if not provided a valid crc will be computed from the data and written.
+void WriteTItag(DWORD idhi, DWORD idlo, WORD crc)
+{
+ if(crc == 0) {
+ crc = update_crc16(crc, (idlo)&0xff);
+ crc = update_crc16(crc, (idlo>>8)&0xff);
+ crc = update_crc16(crc, (idlo>>16)&0xff);
+ crc = update_crc16(crc, (idlo>>24)&0xff);
+ crc = update_crc16(crc, (idhi)&0xff);
+ crc = update_crc16(crc, (idhi>>8)&0xff);
+ crc = update_crc16(crc, (idhi>>16)&0xff);
+ crc = update_crc16(crc, (idhi>>24)&0xff);
+ }
+ Dbprintf("Writing to tag: %x%08x, crc=%x",
+ (unsigned int) idhi, (unsigned int) idlo, crc);
+
+ // TI tags charge at 134.2Khz
+ FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz
+ // Place FPGA in passthrough mode, in this mode the CROSS_LO line
+ // connects to SSP_DIN and the SSP_DOUT logic level controls
+ // whether we're modulating the antenna (high)
+ // or listening to the antenna (low)
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU);
+ LED_A_ON();
+
+ // steal this pin from the SSP and use it to control the modulation
+ AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT;
+ AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;
+
+ // writing algorithm:
+ // a high bit consists of a field off for 1ms and field on for 1ms
+ // a low bit consists of a field off for 0.3ms and field on for 1.7ms
+ // initiate a charge time of 50ms (field on) then immediately start writing bits
+ // start by writing 0xBB (keyword) and 0xEB (password)
+ // then write 80 bits of data (or 64 bit data + 16 bit crc if you prefer)
+ // finally end with 0x0300 (write frame)
+ // all data is sent lsb firts
+ // finish with 15ms programming time
+
+ // modulate antenna
+ HIGH(GPIO_SSC_DOUT);
+ SpinDelay(50); // charge time
+
+ WriteTIbyte(0xbb); // keyword
+ WriteTIbyte(0xeb); // password
+ WriteTIbyte( (idlo )&0xff );
+ WriteTIbyte( (idlo>>8 )&0xff );
+ WriteTIbyte( (idlo>>16)&0xff );
+ WriteTIbyte( (idlo>>24)&0xff );
+ WriteTIbyte( (idhi )&0xff );
+ WriteTIbyte( (idhi>>8 )&0xff );
+ WriteTIbyte( (idhi>>16)&0xff );
+ WriteTIbyte( (idhi>>24)&0xff ); // data hi to lo
+ WriteTIbyte( (crc )&0xff ); // crc lo
+ WriteTIbyte( (crc>>8 )&0xff ); // crc hi
+ WriteTIbyte(0x00); // write frame lo
+ WriteTIbyte(0x03); // write frame hi
+ HIGH(GPIO_SSC_DOUT);
+ SpinDelay(50); // programming time
+
+ LED_A_OFF();
+
+ // get TI tag data into the buffer
+ AcquireTiType();
+
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+ DbpString("Now use tiread to check");
+}
+
+void SimulateTagLowFrequency(int period, int gap, int ledcontrol)
+{
+ int i;
+ BYTE *tab = (BYTE *)BigBuf;
+
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_SIMULATOR);
+
+ AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT | GPIO_SSC_CLK;
+
+ AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;
+ AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_CLK;
+
+#define SHORT_COIL() LOW(GPIO_SSC_DOUT)
+#define OPEN_COIL() HIGH(GPIO_SSC_DOUT)
+
+ i = 0;
+ for(;;) {
+ while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) {
+ if(BUTTON_PRESS()) {
+ DbpString("Stopped");
+ return;
+ }
+ WDT_HIT();
+ }
+
+ if (ledcontrol)
+ LED_D_ON();
+
+ if(tab[i])
+ OPEN_COIL();
+ else
+ SHORT_COIL();
+
+ if (ledcontrol)
+ LED_D_OFF();
+
+ while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) {
+ if(BUTTON_PRESS()) {
+ DbpString("Stopped");
+ return;
+ }
+ WDT_HIT();
+ }
+
+ i++;
+ if(i == period) {
+ i = 0;
+ if (gap) {
+ SHORT_COIL();
+ SpinDelayUs(gap);
+ }
+ }
+ }
+}
+
+/* Provides a framework for bidirectional LF tag communication
+ * Encoding is currently Hitag2, but the general idea can probably
+ * be transferred to other encodings.
+ *
+ * The new FPGA code will, for the LF simulator mode, give on SSC_FRAME
+ * (PA15) a thresholded version of the signal from the ADC. Setting the
+ * ADC path to the low frequency peak detection signal, will enable a
+ * somewhat reasonable receiver for modulation on the carrier signal
+ * that is generated by the reader. The signal is low when the reader
+ * field is switched off, and high when the reader field is active. Due
+ * to the way that the signal looks like, mostly only the rising edge is
+ * useful, your mileage may vary.
+ *
+ * Neat perk: PA15 can not only be used as a bit-banging GPIO, but is also
+ * TIOA1, which can be used as the capture input for timer 1. This should
+ * make it possible to measure the exact edge-to-edge time, without processor
+ * intervention.
+ *
+ * Arguments: divisor is the divisor to be sent to the FPGA (e.g. 95 for 125kHz)
+ * t0 is the carrier frequency cycle duration in terms of MCK (384 for 125kHz)
+ *
+ * The following defines are in carrier periods:
+ */
+#define HITAG_T_0_MIN 15 /* T[0] should be 18..22 */
+#define HITAG_T_1_MIN 24 /* T[1] should be 26..30 */
+#define HITAG_T_EOF 40 /* T_EOF should be > 36 */
+#define HITAG_T_WRESP 208 /* T_wresp should be 204..212 */
+
+static void hitag_handle_frame(int t0, int frame_len, char *frame);
+//#define DEBUG_RA_VALUES 1
+#define DEBUG_FRAME_CONTENTS 1
+void SimulateTagLowFrequencyBidir(int divisor, int t0)
+{
+#if DEBUG_RA_VALUES || DEBUG_FRAME_CONTENTS
+ int i = 0;
+#endif
+ char frame[10];
+ int frame_pos=0;
+
+ DbpString("Starting Hitag2 emulator, press button to end");
+ hitag2_init();
+
+ /* Set up simulator mode, frequency divisor which will drive the FPGA
+ * and analog mux selection.
+ */
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_SIMULATOR);
+ FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor);
+ SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
+ RELAY_OFF();
+
+ /* Set up Timer 1:
+ * Capture mode, timer source MCK/2 (TIMER_CLOCK1), TIOA is external trigger,
+ * external trigger rising edge, load RA on rising edge of TIOA, load RB on rising
+ * edge of TIOA. Assign PA15 to TIOA1 (peripheral B)
+ */
+
+ AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1);
+ AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME;
+ AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
+ AT91C_BASE_TC1->TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK1 |
+ AT91C_TC_ETRGEDG_RISING |
+ AT91C_TC_ABETRG |
+ AT91C_TC_LDRA_RISING |
+ AT91C_TC_LDRB_RISING;
+ AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN |
+ AT91C_TC_SWTRG;
+
+ /* calculate the new value for the carrier period in terms of TC1 values */
+ t0 = t0/2;
+
+ int overflow = 0;
+ while(!BUTTON_PRESS()) {
+ WDT_HIT();
+ if(AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) {
+ int ra = AT91C_BASE_TC1->TC_RA;
+ if((ra > t0*HITAG_T_EOF) | overflow) ra = t0*HITAG_T_EOF+1;
+#if DEBUG_RA_VALUES
+ if(ra > 255 || overflow) ra = 255;
+ ((char*)BigBuf)[i] = ra;
+ i = (i+1) % 8000;
+#endif
+
+ if(overflow || (ra > t0*HITAG_T_EOF) || (ra < t0*HITAG_T_0_MIN)) {
+ /* Ignore */
+ } else if(ra >= t0*HITAG_T_1_MIN ) {
+ /* '1' bit */
+ if(frame_pos < 8*sizeof(frame)) {
+ frame[frame_pos / 8] |= 1<<( 7-(frame_pos%8) );
+ frame_pos++;
+ }
+ } else if(ra >= t0*HITAG_T_0_MIN) {
+ /* '0' bit */
+ if(frame_pos < 8*sizeof(frame)) {
+ frame[frame_pos / 8] |= 0<<( 7-(frame_pos%8) );
+ frame_pos++;
+ }
+ }
+
+ overflow = 0;
+ LED_D_ON();
+ } else {
+ if(AT91C_BASE_TC1->TC_CV > t0*HITAG_T_EOF) {
+ /* Minor nuisance: In Capture mode, the timer can not be
+ * stopped by a Compare C. There's no way to stop the clock
+ * in software, so we'll just have to note the fact that an
+ * overflow happened and the next loaded timer value might
+ * have wrapped. Also, this marks the end of frame, and the
+ * still running counter can be used to determine the correct
+ * time for the start of the reply.
+ */
+ overflow = 1;
+
+ if(frame_pos > 0) {
+ /* Have a frame, do something with it */
+#if DEBUG_FRAME_CONTENTS
+ ((char*)BigBuf)[i++] = frame_pos;
+ memcpy( ((char*)BigBuf)+i, frame, 7);
+ i+=7;
+ i = i % sizeof(BigBuf);
+#endif
+ hitag_handle_frame(t0, frame_pos, frame);
+ memset(frame, 0, sizeof(frame));
+ }
+ frame_pos = 0;
+
+ }
+ LED_D_OFF();
+ }
+ }
+ DbpString("All done");
+}
+
+static void hitag_send_bit(int t0, int bit) {
+ if(bit == 1) {
+ /* Manchester: Loaded, then unloaded */
+ LED_A_ON();
+ SHORT_COIL();
+ while(AT91C_BASE_TC1->TC_CV < t0*15);
+ OPEN_COIL();
+ while(AT91C_BASE_TC1->TC_CV < t0*31);
+ LED_A_OFF();
+ } else if(bit == 0) {
+ /* Manchester: Unloaded, then loaded */
+ LED_B_ON();
+ OPEN_COIL();
+ while(AT91C_BASE_TC1->TC_CV < t0*15);
+ SHORT_COIL();
+ while(AT91C_BASE_TC1->TC_CV < t0*31);
+ LED_B_OFF();
+ }
+ AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; /* Reset clock for the next bit */
+
+}
+static void hitag_send_frame(int t0, int frame_len, const char const * frame, int fdt)
+{
+ OPEN_COIL();
+ AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;
+
+ /* Wait for HITAG_T_WRESP carrier periods after the last reader bit,
+ * not that since the clock counts since the rising edge, but T_wresp is
+ * with respect to the falling edge, we need to wait actually (T_wresp - T_g)
+ * periods. The gap time T_g varies (4..10).
+ */
+ while(AT91C_BASE_TC1->TC_CV < t0*(fdt-8));
+
+ int saved_cmr = AT91C_BASE_TC1->TC_CMR;
+ AT91C_BASE_TC1->TC_CMR &= ~AT91C_TC_ETRGEDG; /* Disable external trigger for the clock */
+ AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; /* Reset the clock and use it for response timing */
+
+ int i;
+ for(i=0; i<5; i++)
+ hitag_send_bit(t0, 1); /* Start of frame */
+
+ for(i=0; i<frame_len; i++) {
+ hitag_send_bit(t0, !!(frame[i/ 8] & (1<<( 7-(i%8) ))) );
+ }
+
+ OPEN_COIL();
+ AT91C_BASE_TC1->TC_CMR = saved_cmr;
+}
+
+/* Callback structure to cleanly separate tag emulation code from the radio layer. */
+static int hitag_cb(const char* response_data, const int response_length, const int fdt, void *cb_cookie)
+{
+ hitag_send_frame(*(int*)cb_cookie, response_length, response_data, fdt);
+ return 0;
+}
+/* Frame length in bits, frame contents in MSBit first format */
+static void hitag_handle_frame(int t0, int frame_len, char *frame)
+{
+ hitag2_handle_command(frame, frame_len, hitag_cb, &t0);
+}
+
+// compose fc/8 fc/10 waveform
+static void fc(int c, int *n) {
+ BYTE *dest = (BYTE *)BigBuf;
+ int idx;
+
+ // for when we want an fc8 pattern every 4 logical bits
+ if(c==0) {
+ dest[((*n)++)]=1;
+ dest[((*n)++)]=1;
+ dest[((*n)++)]=0;
+ dest[((*n)++)]=0;
+ dest[((*n)++)]=0;
+ dest[((*n)++)]=0;
+ dest[((*n)++)]=0;
+ dest[((*n)++)]=0;
+ }
+ // an fc/8 encoded bit is a bit pattern of 11000000 x6 = 48 samples
+ if(c==8) {
+ for (idx=0; idx<6; idx++) {
+ dest[((*n)++)]=1;
+ dest[((*n)++)]=1;
+ dest[((*n)++)]=0;
+ dest[((*n)++)]=0;
+ dest[((*n)++)]=0;
+ dest[((*n)++)]=0;
+ dest[((*n)++)]=0;
+ dest[((*n)++)]=0;
+ }
+ }
+
+ // an fc/10 encoded bit is a bit pattern of 1110000000 x5 = 50 samples
+ if(c==10) {
+ for (idx=0; idx<5; idx++) {
+ dest[((*n)++)]=1;
+ dest[((*n)++)]=1;
+ dest[((*n)++)]=1;
+ dest[((*n)++)]=0;
+ dest[((*n)++)]=0;
+ dest[((*n)++)]=0;
+ dest[((*n)++)]=0;
+ dest[((*n)++)]=0;
+ dest[((*n)++)]=0;
+ dest[((*n)++)]=0;
+ }
+ }
+}
+
+// prepare a waveform pattern in the buffer based on the ID given then
+// simulate a HID tag until the button is pressed
+void CmdHIDsimTAG(int hi, int lo, int ledcontrol)
+{
+ int n=0, i=0;
+ /*
+ HID tag bitstream format
+ The tag contains a 44bit unique code. This is sent out MSB first in sets of 4 bits
+ A 1 bit is represented as 6 fc8 and 5 fc10 patterns
+ A 0 bit is represented as 5 fc10 and 6 fc8 patterns
+ A fc8 is inserted before every 4 bits
+ A special start of frame pattern is used consisting a0b0 where a and b are neither 0
+ nor 1 bits, they are special patterns (a = set of 12 fc8 and b = set of 10 fc10)
+ */
+
+ if (hi>0xFFF) {
+ DbpString("Tags can only have 44 bits.");
+ return;
+ }
+ fc(0,&n);
+ // special start of frame marker containing invalid bit sequences
+ fc(8, &n); fc(8, &n); // invalid
+ fc(8, &n); fc(10, &n); // logical 0
+ fc(10, &n); fc(10, &n); // invalid
+ fc(8, &n); fc(10, &n); // logical 0
+
+ WDT_HIT();
+ // manchester encode bits 43 to 32
+ for (i=11; i>=0; i--) {
+ if ((i%4)==3) fc(0,&n);
+ if ((hi>>i)&1) {
+ fc(10, &n); fc(8, &n); // low-high transition
+ } else {
+ fc(8, &n); fc(10, &n); // high-low transition
+ }
+ }
+
+ WDT_HIT();
+ // manchester encode bits 31 to 0
+ for (i=31; i>=0; i--) {
+ if ((i%4)==3) fc(0,&n);
+ if ((lo>>i)&1) {
+ fc(10, &n); fc(8, &n); // low-high transition
+ } else {
+ fc(8, &n); fc(10, &n); // high-low transition
+ }
+ }
+
+ if (ledcontrol)
+ LED_A_ON();
+ SimulateTagLowFrequency(n, 0, ledcontrol);
+
+ if (ledcontrol)
+ LED_A_OFF();
+}
+
+
+// loop to capture raw HID waveform then FSK demodulate the TAG ID from it
+void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol)
+{
+ BYTE *dest = (BYTE *)BigBuf;
+ int m=0, n=0, i=0, idx=0, found=0, lastval=0;
+ DWORD hi=0, lo=0;
+
+ FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);
+
+ // Connect the A/D to the peak-detected low-frequency path.
+ SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
+
+ // Give it a bit of time for the resonant antenna to settle.
+ SpinDelay(50);
+
+ // Now set up the SSC to get the ADC samples that are now streaming at us.
+ FpgaSetupSsc();
+
+ for(;;) {
+ WDT_HIT();
+ if (ledcontrol)
+ LED_A_ON();
+ if(BUTTON_PRESS()) {
+ DbpString("Stopped");
+ if (ledcontrol)
+ LED_A_OFF();
+ return;
+ }
+
+ i = 0;
+ m = sizeof(BigBuf);
+ memset(dest,128,m);
+ for(;;) {
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
+ AT91C_BASE_SSC->SSC_THR = 0x43;
+ if (ledcontrol)
+ LED_D_ON();
+ }
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
+ dest[i] = (BYTE)AT91C_BASE_SSC->SSC_RHR;
+ // we don't care about actual value, only if it's more or less than a
+ // threshold essentially we capture zero crossings for later analysis
+ if(dest[i] < 127) dest[i] = 0; else dest[i] = 1;
+ i++;
+ if (ledcontrol)
+ LED_D_OFF();
+ if(i >= m) {
+ break;
+ }
+ }
+ }
+
+ // FSK demodulator
+
+ // sync to first lo-hi transition
+ for( idx=1; idx<m; idx++) {
+ if (dest[idx-1]<dest[idx])
+ lastval=idx;
+ break;
+ }
+ WDT_HIT();
+
+ // count cycles between consecutive lo-hi transitions, there should be either 8 (fc/8)
+ // or 10 (fc/10) cycles but in practice due to noise etc we may end up with with anywhere
+ // between 7 to 11 cycles so fuzz it by treat anything <9 as 8 and anything else as 10
+ for( i=0; idx<m; idx++) {
+ if (dest[idx-1]<dest[idx]) {
+ dest[i]=idx-lastval;
+ if (dest[i] <= 8) {
+ dest[i]=1;
+ } else {
+ dest[i]=0;
+ }
+
+ lastval=idx;
+ i++;
+ }
+ }
+ m=i;
+ WDT_HIT();
+
+ // we now have a set of cycle counts, loop over previous results and aggregate data into bit patterns
+ lastval=dest[0];
+ idx=0;
+ i=0;
+ n=0;
+ for( idx=0; idx<m; idx++) {
+ if (dest[idx]==lastval) {
+ n++;
+ } else {
+ // a bit time is five fc/10 or six fc/8 cycles so figure out how many bits a pattern width represents,
+ // an extra fc/8 pattern preceeds every 4 bits (about 200 cycles) just to complicate things but it gets
+ // swallowed up by rounding
+ // expected results are 1 or 2 bits, any more and it's an invalid manchester encoding
+ // special start of frame markers use invalid manchester states (no transitions) by using sequences
+ // like 111000
+ if (dest[idx-1]) {
+ n=(n+1)/6; // fc/8 in sets of 6
+ } else {
+ n=(n+1)/5; // fc/10 in sets of 5
+ }
+ switch (n) { // stuff appropriate bits in buffer
+ case 0:
+ case 1: // one bit
+ dest[i++]=dest[idx-1];
+ break;
+ case 2: // two bits
+ dest[i++]=dest[idx-1];
+ dest[i++]=dest[idx-1];
+ break;
+ case 3: // 3 bit start of frame markers
+ dest[i++]=dest[idx-1];
+ dest[i++]=dest[idx-1];
+ dest[i++]=dest[idx-1];
+ break;
+ // When a logic 0 is immediately followed by the start of the next transmisson
+ // (special pattern) a pattern of 4 bit duration lengths is created.
+ case 4:
+ dest[i++]=dest[idx-1];
+ dest[i++]=dest[idx-1];
+ dest[i++]=dest[idx-1];
+ dest[i++]=dest[idx-1];
+ break;
+ default: // this shouldn't happen, don't stuff any bits
+ break;
+ }
+ n=0;
+ lastval=dest[idx];
+ }
+ }
+ m=i;
+ WDT_HIT();
+
+ // final loop, go over previously decoded manchester data and decode into usable tag ID
+ // 111000 bit pattern represent start of frame, 01 pattern represents a 1 and 10 represents a 0
+ for( idx=0; idx<m-6; idx++) {
+ // search for a start of frame marker
+ if ( dest[idx] && dest[idx+1] && dest[idx+2] && (!dest[idx+3]) && (!dest[idx+4]) && (!dest[idx+5]) )
+ {
+ found=1;
+ idx+=6;
+ if (found && (hi|lo)) {
+ Dbprintf("TAG ID: %x%08x (%d)",
+ (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF);
+ /* if we're only looking for one tag */
+ if (findone)
+ {
+ *high = hi;
+ *low = lo;
+ return;
+ }
+ hi=0;
+ lo=0;
+ found=0;
+ }
+ }
+ if (found) {
+ if (dest[idx] && (!dest[idx+1]) ) {
+ hi=(hi<<1)|(lo>>31);
+ lo=(lo<<1)|0;
+ } else if ( (!dest[idx]) && dest[idx+1]) {
+ hi=(hi<<1)|(lo>>31);
+ lo=(lo<<1)|1;
+ } else {
+ found=0;
+ hi=0;
+ lo=0;
+ }
+ idx++;
+ }
+ if ( dest[idx] && dest[idx+1] && dest[idx+2] && (!dest[idx+3]) && (!dest[idx+4]) && (!dest[idx+5]) )
+ {
+ found=1;
+ idx+=6;
+ if (found && (hi|lo)) {
+ Dbprintf("TAG ID: %x%08x (%d)",
+ (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF);
+ /* if we're only looking for one tag */
+ if (findone)
+ {
+ *high = hi;
+ *low = lo;
+ return;
+ }
+ hi=0;
+ lo=0;
+ found=0;
+ }
+ }
+ }
+ WDT_HIT();
+ }
+}
-# Makefile for bootrom, see ../common/Makefile.common for common settings\r
-\r
-# DO NOT use thumb mode in the phase 1 bootloader since that generates a section with glue code\r
-ARMSRC = fromflash.c \r
-THUMBSRC = usb.c bootrom.c\r
-ASMSRC = ram-reset.s flash-reset.s\r
-\r
-## There is a strange bug with the linker: Sometimes it will not emit the glue to call\r
-## BootROM from ARM mode. The symbol is emitted, but the section will be filled with\r
-## zeroes. As a temporary workaround, do not use thumb for the phase 2 bootloader\r
-## -- Henryk Plötz <henryk@ploetzli.ch> 2009-09-01\r
-ARMSRC := $(ARMSRC) $(THUMBSRC)\r
-THUMBSRC := \r
-\r
-# stdint.h provided locally until GCC 4.5 becomes C99 compliant\r
-APP_CFLAGS = -I.\r
-\r
-# Do not move this inclusion before the definition of {THUMB,ASM,ARM}SRC\r
-include ../common/Makefile.common\r
-\r
-all: $(OBJDIR)/bootrom.s19\r
-\r
-$(OBJDIR)/bootrom.elf: $(VERSIONOBJ) $(ASMOBJ) $(ARMOBJ) $(THUMBOBJ)\r
- $(LD) -g -Tldscript-flash --oformat elf32-littlearm -Map=$(patsubst %.elf,%.map,$@) -o $@ $^\r
-\r
-clean:\r
- $(DELETE) $(OBJDIR)$(PATHSEP)*.o\r
- $(DELETE) $(OBJDIR)$(PATHSEP)*.elf\r
- $(DELETE) $(OBJDIR)$(PATHSEP)*.s19\r
- $(DELETE) $(OBJDIR)$(PATHSEP)*.map\r
- $(DELETE) $(OBJDIR)$(PATHSEP)*.d\r
- $(DELETE) version.c\r
-\r
-.PHONY: all clean help \r
-help:\r
- @echo Multi-OS Makefile, you are running on $(DETECTED_OS)\r
- @echo Possible targets:\r
- @echo + all - Make $(OBJDIR)/bootrom.s19, the main bootrom\r
- @echo + clean - Clean $(OBJDIR)\r
+# Makefile for bootrom, see ../common/Makefile.common for common settings
+
+# DO NOT use thumb mode in the phase 1 bootloader since that generates a section with glue code
+ARMSRC = fromflash.c
+THUMBSRC = usb.c bootrom.c
+ASMSRC = ram-reset.s flash-reset.s
+
+## There is a strange bug with the linker: Sometimes it will not emit the glue to call
+## BootROM from ARM mode. The symbol is emitted, but the section will be filled with
+## zeroes. As a temporary workaround, do not use thumb for the phase 2 bootloader
+## -- Henryk Plötz <henryk@ploetzli.ch> 2009-09-01
+ARMSRC := $(ARMSRC) $(THUMBSRC)
+THUMBSRC :=
+
+# stdint.h provided locally until GCC 4.5 becomes C99 compliant
+APP_CFLAGS = -I.
+
+# Do not move this inclusion before the definition of {THUMB,ASM,ARM}SRC
+include ../common/Makefile.common
+
+all: $(OBJDIR)/bootrom.s19
+
+$(OBJDIR)/bootrom.elf: $(VERSIONOBJ) $(ASMOBJ) $(ARMOBJ) $(THUMBOBJ)
+ $(LD) -g -Tldscript-flash --oformat elf32-littlearm -Map=$(patsubst %.elf,%.map,$@) -o $@ $^
+
+clean:
+ $(DELETE) $(OBJDIR)$(PATHSEP)*.o
+ $(DELETE) $(OBJDIR)$(PATHSEP)*.elf
+ $(DELETE) $(OBJDIR)$(PATHSEP)*.s19
+ $(DELETE) $(OBJDIR)$(PATHSEP)*.map
+ $(DELETE) $(OBJDIR)$(PATHSEP)*.d
+ $(DELETE) version.c
+
+.PHONY: all clean help
+help:
+ @echo Multi-OS Makefile, you are running on $(DETECTED_OS)
+ @echo Possible targets:
+ @echo + all - Make $(OBJDIR)/bootrom.s19, the main bootrom
+ @echo + clean - Clean $(OBJDIR)
-#include <proxmark3.h>\r
-\r
-struct common_area common_area __attribute__((section(".commonarea")));\r
-unsigned int start_addr, end_addr, bootrom_unlocked;\r
-extern char _bootrom_start, _bootrom_end, _flash_start, _flash_end;\r
-\r
-static void ConfigClocks(void)\r
-{\r
- // we are using a 16 MHz crystal as the basis for everything\r
- // slow clock runs at 32Khz typical regardless of crystal\r
-\r
- // enable system clock and USB clock\r
- AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_PCK | AT91C_PMC_UDP;\r
-\r
- // enable the clock to the following peripherals\r
- AT91C_BASE_PMC->PMC_PCER =\r
- (1<<AT91C_ID_PIOA) |\r
- (1<<AT91C_ID_ADC) |\r
- (1<<AT91C_ID_SPI) |\r
- (1<<AT91C_ID_SSC) |\r
- (1<<AT91C_ID_PWMC) |\r
- (1<<AT91C_ID_UDP);\r
-\r
- // worst case scenario, with 16Mhz xtal startup delay is 14.5ms\r
- // with a slow clock running at it worst case (max) frequency of 42khz\r
- // max startup delay = (14.5ms*42k)/8 = 76 = 0x4C round up to 0x50\r
-\r
- // enable main oscillator and set startup delay\r
- AT91C_BASE_PMC->PMC_MOR =\r
- PMC_MAIN_OSC_ENABLE |\r
- PMC_MAIN_OSC_STARTUP_DELAY(0x50);\r
-\r
- // wait for main oscillator to stabilize\r
- while ( !(AT91C_BASE_PMC->PMC_SR & PMC_MAIN_OSC_STABILIZED) )\r
- ;\r
-\r
- // minimum PLL clock frequency is 80 MHz in range 00 (96 here so okay)\r
- // frequency is crystal * multiplier / divisor = 16Mhz * 12 / 2 = 96Mhz\r
- AT91C_BASE_PMC->PMC_PLLR =\r
- PMC_PLL_DIVISOR(2) |\r
- PMC_PLL_COUNT_BEFORE_LOCK(0x50) |\r
- PMC_PLL_FREQUENCY_RANGE(0) |\r
- PMC_PLL_MULTIPLIER(12) |\r
- PMC_PLL_USB_DIVISOR(1);\r
-\r
- // wait for PLL to lock\r
- while ( !(AT91C_BASE_PMC->PMC_SR & PMC_MAIN_OSC_PLL_LOCK) )\r
- ;\r
-\r
- // we want a master clock (MCK) to be PLL clock / 2 = 96Mhz / 2 = 48Mhz\r
- // as per datasheet, this register must be programmed in two operations\r
- // when changing to PLL, program the prescaler first then the source\r
- AT91C_BASE_PMC->PMC_MCKR = PMC_CLK_PRESCALE_DIV_2;\r
-\r
- // wait for main clock ready signal\r
- while ( !(AT91C_BASE_PMC->PMC_SR & PMC_MAIN_OSC_MCK_READY) )\r
- ;\r
-\r
- // set the source to PLL\r
- AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_CSS_PLL_CLK | PMC_CLK_PRESCALE_DIV_2;\r
-\r
- // wait for main clock ready signal\r
- while ( !(AT91C_BASE_PMC->PMC_SR & PMC_MAIN_OSC_MCK_READY) )\r
- ;\r
-}\r
-\r
-static void Fatal(void)\r
-{\r
- for(;;);\r
-}\r
-\r
-void UsbPacketReceived(BYTE *packet, int len)\r
-{\r
- int i, dont_ack=0;\r
- UsbCommand *c = (UsbCommand *)packet;\r
- volatile DWORD *p;\r
-\r
- if(len != sizeof(*c)) {\r
- Fatal();\r
- }\r
-\r
- switch(c->cmd) {\r
- case CMD_DEVICE_INFO:\r
- dont_ack = 1;\r
- c->cmd = CMD_DEVICE_INFO;\r
- c->arg[0] = DEVICE_INFO_FLAG_BOOTROM_PRESENT | DEVICE_INFO_FLAG_CURRENT_MODE_BOOTROM |\r
- DEVICE_INFO_FLAG_UNDERSTANDS_START_FLASH;\r
- if(common_area.flags.osimage_present) c->arg[0] |= DEVICE_INFO_FLAG_OSIMAGE_PRESENT;\r
- UsbSendPacket(packet, len);\r
- break;\r
-\r
- case CMD_SETUP_WRITE:\r
- /* The temporary write buffer of the embedded flash controller is mapped to the\r
- * whole memory region, only the last 8 bits are decoded.\r
- */\r
- p = (volatile DWORD *)&_flash_start;\r
- for(i = 0; i < 12; i++) {\r
- p[i+c->arg[0]] = c->d.asDwords[i];\r
- }\r
- break;\r
-\r
- case CMD_FINISH_WRITE:\r
- p = (volatile DWORD *)&_flash_start;\r
- for(i = 0; i < 4; i++) {\r
- p[i+60] = c->d.asDwords[i];\r
- }\r
-\r
- /* Check that the address that we are supposed to write to is within our allowed region */\r
- if( ((c->arg[0]+AT91C_IFLASH_PAGE_SIZE-1) >= end_addr) || (c->arg[0] < start_addr) ) {\r
- /* Disallow write */\r
- dont_ack = 1;\r
- c->cmd = CMD_NACK;\r
- UsbSendPacket(packet, len);\r
- } else {\r
- /* Translate address to flash page and do flash, update here for the 512k part */\r
- AT91C_BASE_EFC0->EFC_FCR = MC_FLASH_COMMAND_KEY |\r
- MC_FLASH_COMMAND_PAGEN((c->arg[0]-(int)&_flash_start)/AT91C_IFLASH_PAGE_SIZE) |\r
- AT91C_MC_FCMD_START_PROG;\r
- }\r
- \r
- uint32_t sr;\r
- \r
- while(!((sr = AT91C_BASE_EFC0->EFC_FSR) & MC_FLASH_STATUS_READY))\r
- ;\r
- if(sr & (MC_FLASH_STATUS_LOCKE | MC_FLASH_STATUS_PROGE)) { \r
- dont_ack = 1;\r
- c->cmd = CMD_NACK;\r
- UsbSendPacket(packet, len);\r
- }\r
- break;\r
-\r
- case CMD_HARDWARE_RESET:\r
- USB_D_PLUS_PULLUP_OFF();\r
- AT91C_BASE_RSTC->RSTC_RCR = RST_CONTROL_KEY | AT91C_RSTC_PROCRST;\r
- break;\r
-\r
- case CMD_START_FLASH:\r
- if(c->arg[2] == START_FLASH_MAGIC) bootrom_unlocked = 1;\r
- else bootrom_unlocked = 0;\r
- {\r
- int prot_start = (int)&_bootrom_start;\r
- int prot_end = (int)&_bootrom_end;\r
- int allow_start = (int)&_flash_start;\r
- int allow_end = (int)&_flash_end;\r
- int cmd_start = c->arg[0];\r
- int cmd_end = c->arg[1];\r
-\r
- /* Only allow command if the bootrom is unlocked, or the parameters are outside of the protected\r
- * bootrom area. In any case they must be within the flash area.\r
- */\r
- if( (bootrom_unlocked || ((cmd_start >= prot_end) || (cmd_end < prot_start)))\r
- && (cmd_start >= allow_start) && (cmd_end <= allow_end) ) {\r
- start_addr = cmd_start;\r
- end_addr = cmd_end;\r
- } else {\r
- start_addr = end_addr = 0;\r
- dont_ack = 1;\r
- c->cmd = CMD_NACK;\r
- UsbSendPacket(packet, len);\r
- }\r
- }\r
- break;\r
-\r
- default:\r
- Fatal();\r
- break;\r
- }\r
-\r
- if(!dont_ack) {\r
- c->cmd = CMD_ACK;\r
- UsbSendPacket(packet, len);\r
- }\r
-}\r
-\r
-static void flash_mode(int externally_entered)\r
-{\r
- start_addr = 0;\r
- end_addr = 0;\r
- bootrom_unlocked = 0;\r
-\r
- UsbStart();\r
- for(;;) {\r
- WDT_HIT();\r
-\r
- UsbPoll(TRUE);\r
-\r
- if(!externally_entered && !BUTTON_PRESS()) {\r
- /* Perform a reset to leave flash mode */\r
- USB_D_PLUS_PULLUP_OFF();\r
- LED_B_ON();\r
- AT91C_BASE_RSTC->RSTC_RCR = RST_CONTROL_KEY | AT91C_RSTC_PROCRST;\r
- for(;;);\r
- }\r
- if(externally_entered && BUTTON_PRESS()) {\r
- /* Let the user's button press override the automatic leave */\r
- externally_entered = 0;\r
- }\r
- }\r
-}\r
-\r
-extern char _osimage_entry;\r
-void BootROM(void)\r
-{\r
- //------------\r
- // First set up all the I/O pins; GPIOs configured directly, other ones\r
- // just need to be assigned to the appropriate peripheral.\r
-\r
- // Kill all the pullups, especially the one on USB D+; leave them for\r
- // the unused pins, though.\r
- AT91C_BASE_PIOA->PIO_PPUDR =\r
- GPIO_USB_PU |\r
- GPIO_LED_A |\r
- GPIO_LED_B |\r
- GPIO_LED_C |\r
- GPIO_LED_D |\r
- GPIO_FPGA_DIN |\r
- GPIO_FPGA_DOUT |\r
- GPIO_FPGA_CCLK |\r
- GPIO_FPGA_NINIT |\r
- GPIO_FPGA_NPROGRAM |\r
- GPIO_FPGA_DONE |\r
- GPIO_MUXSEL_HIPKD |\r
- GPIO_MUXSEL_HIRAW |\r
- GPIO_MUXSEL_LOPKD |\r
- GPIO_MUXSEL_LORAW |\r
- GPIO_RELAY |\r
- GPIO_NVDD_ON;\r
- // (and add GPIO_FPGA_ON)\r
- // These pins are outputs\r
- AT91C_BASE_PIOA->PIO_OER =\r
- GPIO_LED_A |\r
- GPIO_LED_B |\r
- GPIO_LED_C |\r
- GPIO_LED_D |\r
- GPIO_RELAY |\r
- GPIO_NVDD_ON;\r
- // PIO controls the following pins\r
- AT91C_BASE_PIOA->PIO_PER =\r
- GPIO_USB_PU |\r
- GPIO_LED_A |\r
- GPIO_LED_B |\r
- GPIO_LED_C |\r
- GPIO_LED_D;\r
-\r
- USB_D_PLUS_PULLUP_OFF();\r
- LED_D_OFF();\r
- LED_C_ON();\r
- LED_B_OFF();\r
- LED_A_OFF();\r
-\r
- // if 512K FLASH part - TODO make some defines :)\r
- if ((AT91C_BASE_DBGU->DBGU_CIDR | 0xf00) == 0xa00) {\r
- AT91C_BASE_EFC0->EFC_FMR =\r
- MC_FLASH_MODE_FLASH_WAIT_STATES(1) |\r
- MC_FLASH_MODE_MASTER_CLK_IN_MHZ(0x48);\r
- AT91C_BASE_EFC1->EFC_FMR =\r
- MC_FLASH_MODE_FLASH_WAIT_STATES(1) |\r
- MC_FLASH_MODE_MASTER_CLK_IN_MHZ(0x48);\r
- } else {\r
- AT91C_BASE_EFC0->EFC_FMR =\r
- MC_FLASH_MODE_FLASH_WAIT_STATES(0) |\r
- MC_FLASH_MODE_MASTER_CLK_IN_MHZ(48);\r
- }\r
-\r
- // Initialize all system clocks\r
- ConfigClocks();\r
-\r
- LED_A_ON();\r
-\r
- int common_area_present = 0;\r
- switch(AT91C_BASE_RSTC->RSTC_RSR & AT91C_RSTC_RSTTYP) {\r
- case AT91C_RSTC_RSTTYP_WATCHDOG:\r
- case AT91C_RSTC_RSTTYP_SOFTWARE:\r
- case AT91C_RSTC_RSTTYP_USER:\r
- /* In these cases the common_area in RAM should be ok, retain it if it's there */\r
- if(common_area.magic == COMMON_AREA_MAGIC && common_area.version == 1) {\r
- common_area_present = 1;\r
- }\r
- break;\r
- default: /* Otherwise, initialize it from scratch */\r
- break;\r
- }\r
-\r
- if(!common_area_present){\r
- /* Common area not ok, initialize it */\r
- int i; for(i=0; i<sizeof(common_area); i++) { /* Makeshift memset, no need to drag util.c into this */\r
- ((char*)&common_area)[i] = 0;\r
- }\r
- common_area.magic = COMMON_AREA_MAGIC;\r
- common_area.version = 1;\r
- common_area.flags.bootrom_present = 1;\r
- }\r
-\r
- common_area.flags.bootrom_present = 1;\r
- if(common_area.command == COMMON_AREA_COMMAND_ENTER_FLASH_MODE) {\r
- common_area.command = COMMON_AREA_COMMAND_NONE;\r
- flash_mode(1);\r
- } else if(BUTTON_PRESS()) {\r
- flash_mode(0);\r
- } else if(*(uint32_t*)&_osimage_entry == 0xffffffffU) {\r
- flash_mode(1);\r
- } else {\r
- // jump to Flash address of the osimage entry point (LSBit set for thumb mode)\r
- asm("bx %0\n" : : "r" ( ((int)&_osimage_entry) | 0x1 ) );\r
- }\r
-}\r
+#include <proxmark3.h>
+
+struct common_area common_area __attribute__((section(".commonarea")));
+unsigned int start_addr, end_addr, bootrom_unlocked;
+extern char _bootrom_start, _bootrom_end, _flash_start, _flash_end;
+
+static void ConfigClocks(void)
+{
+ // we are using a 16 MHz crystal as the basis for everything
+ // slow clock runs at 32Khz typical regardless of crystal
+
+ // enable system clock and USB clock
+ AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_PCK | AT91C_PMC_UDP;
+
+ // enable the clock to the following peripherals
+ AT91C_BASE_PMC->PMC_PCER =
+ (1<<AT91C_ID_PIOA) |
+ (1<<AT91C_ID_ADC) |
+ (1<<AT91C_ID_SPI) |
+ (1<<AT91C_ID_SSC) |
+ (1<<AT91C_ID_PWMC) |
+ (1<<AT91C_ID_UDP);
+
+ // worst case scenario, with 16Mhz xtal startup delay is 14.5ms
+ // with a slow clock running at it worst case (max) frequency of 42khz
+ // max startup delay = (14.5ms*42k)/8 = 76 = 0x4C round up to 0x50
+
+ // enable main oscillator and set startup delay
+ AT91C_BASE_PMC->PMC_MOR =
+ PMC_MAIN_OSC_ENABLE |
+ PMC_MAIN_OSC_STARTUP_DELAY(0x50);
+
+ // wait for main oscillator to stabilize
+ while ( !(AT91C_BASE_PMC->PMC_SR & PMC_MAIN_OSC_STABILIZED) )
+ ;
+
+ // minimum PLL clock frequency is 80 MHz in range 00 (96 here so okay)
+ // frequency is crystal * multiplier / divisor = 16Mhz * 12 / 2 = 96Mhz
+ AT91C_BASE_PMC->PMC_PLLR =
+ PMC_PLL_DIVISOR(2) |
+ PMC_PLL_COUNT_BEFORE_LOCK(0x50) |
+ PMC_PLL_FREQUENCY_RANGE(0) |
+ PMC_PLL_MULTIPLIER(12) |
+ PMC_PLL_USB_DIVISOR(1);
+
+ // wait for PLL to lock
+ while ( !(AT91C_BASE_PMC->PMC_SR & PMC_MAIN_OSC_PLL_LOCK) )
+ ;
+
+ // we want a master clock (MCK) to be PLL clock / 2 = 96Mhz / 2 = 48Mhz
+ // as per datasheet, this register must be programmed in two operations
+ // when changing to PLL, program the prescaler first then the source
+ AT91C_BASE_PMC->PMC_MCKR = PMC_CLK_PRESCALE_DIV_2;
+
+ // wait for main clock ready signal
+ while ( !(AT91C_BASE_PMC->PMC_SR & PMC_MAIN_OSC_MCK_READY) )
+ ;
+
+ // set the source to PLL
+ AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_CSS_PLL_CLK | PMC_CLK_PRESCALE_DIV_2;
+
+ // wait for main clock ready signal
+ while ( !(AT91C_BASE_PMC->PMC_SR & PMC_MAIN_OSC_MCK_READY) )
+ ;
+}
+
+static void Fatal(void)
+{
+ for(;;);
+}
+
+void UsbPacketReceived(BYTE *packet, int len)
+{
+ int i, dont_ack=0;
+ UsbCommand *c = (UsbCommand *)packet;
+ volatile DWORD *p;
+
+ if(len != sizeof(*c)) {
+ Fatal();
+ }
+
+ switch(c->cmd) {
+ case CMD_DEVICE_INFO:
+ dont_ack = 1;
+ c->cmd = CMD_DEVICE_INFO;
+ c->arg[0] = DEVICE_INFO_FLAG_BOOTROM_PRESENT | DEVICE_INFO_FLAG_CURRENT_MODE_BOOTROM |
+ DEVICE_INFO_FLAG_UNDERSTANDS_START_FLASH;
+ if(common_area.flags.osimage_present) c->arg[0] |= DEVICE_INFO_FLAG_OSIMAGE_PRESENT;
+ UsbSendPacket(packet, len);
+ break;
+
+ case CMD_SETUP_WRITE:
+ /* The temporary write buffer of the embedded flash controller is mapped to the
+ * whole memory region, only the last 8 bits are decoded.
+ */
+ p = (volatile DWORD *)&_flash_start;
+ for(i = 0; i < 12; i++) {
+ p[i+c->arg[0]] = c->d.asDwords[i];
+ }
+ break;
+
+ case CMD_FINISH_WRITE:
+ p = (volatile DWORD *)&_flash_start;
+ for(i = 0; i < 4; i++) {
+ p[i+60] = c->d.asDwords[i];
+ }
+
+ /* Check that the address that we are supposed to write to is within our allowed region */
+ if( ((c->arg[0]+AT91C_IFLASH_PAGE_SIZE-1) >= end_addr) || (c->arg[0] < start_addr) ) {
+ /* Disallow write */
+ dont_ack = 1;
+ c->cmd = CMD_NACK;
+ UsbSendPacket(packet, len);
+ } else {
+ /* Translate address to flash page and do flash, update here for the 512k part */
+ AT91C_BASE_EFC0->EFC_FCR = MC_FLASH_COMMAND_KEY |
+ MC_FLASH_COMMAND_PAGEN((c->arg[0]-(int)&_flash_start)/AT91C_IFLASH_PAGE_SIZE) |
+ AT91C_MC_FCMD_START_PROG;
+ }
+
+ uint32_t sr;
+
+ while(!((sr = AT91C_BASE_EFC0->EFC_FSR) & MC_FLASH_STATUS_READY))
+ ;
+ if(sr & (MC_FLASH_STATUS_LOCKE | MC_FLASH_STATUS_PROGE)) {
+ dont_ack = 1;
+ c->cmd = CMD_NACK;
+ UsbSendPacket(packet, len);
+ }
+ break;
+
+ case CMD_HARDWARE_RESET:
+ USB_D_PLUS_PULLUP_OFF();
+ AT91C_BASE_RSTC->RSTC_RCR = RST_CONTROL_KEY | AT91C_RSTC_PROCRST;
+ break;
+
+ case CMD_START_FLASH:
+ if(c->arg[2] == START_FLASH_MAGIC) bootrom_unlocked = 1;
+ else bootrom_unlocked = 0;
+ {
+ int prot_start = (int)&_bootrom_start;
+ int prot_end = (int)&_bootrom_end;
+ int allow_start = (int)&_flash_start;
+ int allow_end = (int)&_flash_end;
+ int cmd_start = c->arg[0];
+ int cmd_end = c->arg[1];
+
+ /* Only allow command if the bootrom is unlocked, or the parameters are outside of the protected
+ * bootrom area. In any case they must be within the flash area.
+ */
+ if( (bootrom_unlocked || ((cmd_start >= prot_end) || (cmd_end < prot_start)))
+ && (cmd_start >= allow_start) && (cmd_end <= allow_end) ) {
+ start_addr = cmd_start;
+ end_addr = cmd_end;
+ } else {
+ start_addr = end_addr = 0;
+ dont_ack = 1;
+ c->cmd = CMD_NACK;
+ UsbSendPacket(packet, len);
+ }
+ }
+ break;
+
+ default:
+ Fatal();
+ break;
+ }
+
+ if(!dont_ack) {
+ c->cmd = CMD_ACK;
+ UsbSendPacket(packet, len);
+ }
+}
+
+static void flash_mode(int externally_entered)
+{
+ start_addr = 0;
+ end_addr = 0;
+ bootrom_unlocked = 0;
+
+ UsbStart();
+ for(;;) {
+ WDT_HIT();
+
+ UsbPoll(TRUE);
+
+ if(!externally_entered && !BUTTON_PRESS()) {
+ /* Perform a reset to leave flash mode */
+ USB_D_PLUS_PULLUP_OFF();
+ LED_B_ON();
+ AT91C_BASE_RSTC->RSTC_RCR = RST_CONTROL_KEY | AT91C_RSTC_PROCRST;
+ for(;;);
+ }
+ if(externally_entered && BUTTON_PRESS()) {
+ /* Let the user's button press override the automatic leave */
+ externally_entered = 0;
+ }
+ }
+}
+
+extern char _osimage_entry;
+void BootROM(void)
+{
+ //------------
+ // First set up all the I/O pins; GPIOs configured directly, other ones
+ // just need to be assigned to the appropriate peripheral.
+
+ // Kill all the pullups, especially the one on USB D+; leave them for
+ // the unused pins, though.
+ AT91C_BASE_PIOA->PIO_PPUDR =
+ GPIO_USB_PU |
+ GPIO_LED_A |
+ GPIO_LED_B |
+ GPIO_LED_C |
+ GPIO_LED_D |
+ GPIO_FPGA_DIN |
+ GPIO_FPGA_DOUT |
+ GPIO_FPGA_CCLK |
+ GPIO_FPGA_NINIT |
+ GPIO_FPGA_NPROGRAM |
+ GPIO_FPGA_DONE |
+ GPIO_MUXSEL_HIPKD |
+ GPIO_MUXSEL_HIRAW |
+ GPIO_MUXSEL_LOPKD |
+ GPIO_MUXSEL_LORAW |
+ GPIO_RELAY |
+ GPIO_NVDD_ON;
+ // (and add GPIO_FPGA_ON)
+ // These pins are outputs
+ AT91C_BASE_PIOA->PIO_OER =
+ GPIO_LED_A |
+ GPIO_LED_B |
+ GPIO_LED_C |
+ GPIO_LED_D |
+ GPIO_RELAY |
+ GPIO_NVDD_ON;
+ // PIO controls the following pins
+ AT91C_BASE_PIOA->PIO_PER =
+ GPIO_USB_PU |
+ GPIO_LED_A |
+ GPIO_LED_B |
+ GPIO_LED_C |
+ GPIO_LED_D;
+
+ USB_D_PLUS_PULLUP_OFF();
+ LED_D_OFF();
+ LED_C_ON();
+ LED_B_OFF();
+ LED_A_OFF();
+
+ // if 512K FLASH part - TODO make some defines :)
+ if ((AT91C_BASE_DBGU->DBGU_CIDR | 0xf00) == 0xa00) {
+ AT91C_BASE_EFC0->EFC_FMR =
+ MC_FLASH_MODE_FLASH_WAIT_STATES(1) |
+ MC_FLASH_MODE_MASTER_CLK_IN_MHZ(0x48);
+ AT91C_BASE_EFC1->EFC_FMR =
+ MC_FLASH_MODE_FLASH_WAIT_STATES(1) |
+ MC_FLASH_MODE_MASTER_CLK_IN_MHZ(0x48);
+ } else {
+ AT91C_BASE_EFC0->EFC_FMR =
+ MC_FLASH_MODE_FLASH_WAIT_STATES(0) |
+ MC_FLASH_MODE_MASTER_CLK_IN_MHZ(48);
+ }
+
+ // Initialize all system clocks
+ ConfigClocks();
+
+ LED_A_ON();
+
+ int common_area_present = 0;
+ switch(AT91C_BASE_RSTC->RSTC_RSR & AT91C_RSTC_RSTTYP) {
+ case AT91C_RSTC_RSTTYP_WATCHDOG:
+ case AT91C_RSTC_RSTTYP_SOFTWARE:
+ case AT91C_RSTC_RSTTYP_USER:
+ /* In these cases the common_area in RAM should be ok, retain it if it's there */
+ if(common_area.magic == COMMON_AREA_MAGIC && common_area.version == 1) {
+ common_area_present = 1;
+ }
+ break;
+ default: /* Otherwise, initialize it from scratch */
+ break;
+ }
+
+ if(!common_area_present){
+ /* Common area not ok, initialize it */
+ int i; for(i=0; i<sizeof(common_area); i++) { /* Makeshift memset, no need to drag util.c into this */
+ ((char*)&common_area)[i] = 0;
+ }
+ common_area.magic = COMMON_AREA_MAGIC;
+ common_area.version = 1;
+ common_area.flags.bootrom_present = 1;
+ }
+
+ common_area.flags.bootrom_present = 1;
+ if(common_area.command == COMMON_AREA_COMMAND_ENTER_FLASH_MODE) {
+ common_area.command = COMMON_AREA_COMMAND_NONE;
+ flash_mode(1);
+ } else if(BUTTON_PRESS()) {
+ flash_mode(0);
+ } else if(*(uint32_t*)&_osimage_entry == 0xffffffffU) {
+ flash_mode(1);
+ } else {
+ // jump to Flash address of the osimage entry point (LSBit set for thumb mode)
+ asm("bx %0\n" : : "r" ( ((int)&_osimage_entry) | 0x1 ) );
+ }
+}
-.extern CopyBootToRAM\r
- \r
-.section .startup,"ax"\r
- .code 32\r
- .align 0\r
-\r
-.global flashstart\r
-flashstart:\r
- b Reset\r
- b UndefinedInstruction\r
- b SoftwareInterrupt\r
- b PrefetchAbort\r
- b DataAbort\r
- b Reserved\r
- b Irq\r
- b Fiq\r
-\r
-Reset:\r
- ldr sp, .stack_end @ initialize stack pointer to top of RAM\r
- bl CopyBootToRAM @ copy bootloader to RAM (in case the\r
- @ user re-flashes the bootloader)\r
- ldr r3, .bootphase2_start @ start address of RAM bootloader\r
- bx r3 @ jump to it\r
-\r
- .stack_end:\r
- .word _stack_end\r
- .bootphase2_start:\r
- .word __bootphase2_start__\r
-\r
-Fiq:\r
- b Fiq\r
-UndefinedInstruction:\r
- b UndefinedInstruction\r
-SoftwareInterrupt:\r
- b SoftwareInterrupt\r
-PrefetchAbort:\r
- b PrefetchAbort\r
-DataAbort:\r
- b DataAbort\r
-Reserved:\r
- b Reserved\r
-Irq:\r
- b Irq\r
+.extern CopyBootToRAM
+
+.section .startup,"ax"
+ .code 32
+ .align 0
+
+.global flashstart
+flashstart:
+ b Reset
+ b UndefinedInstruction
+ b SoftwareInterrupt
+ b PrefetchAbort
+ b DataAbort
+ b Reserved
+ b Irq
+ b Fiq
+
+Reset:
+ ldr sp, .stack_end @ initialize stack pointer to top of RAM
+ bl CopyBootToRAM @ copy bootloader to RAM (in case the
+ @ user re-flashes the bootloader)
+ ldr r3, .bootphase2_start @ start address of RAM bootloader
+ bx r3 @ jump to it
+
+ .stack_end:
+ .word _stack_end
+ .bootphase2_start:
+ .word __bootphase2_start__
+
+Fiq:
+ b Fiq
+UndefinedInstruction:
+ b UndefinedInstruction
+SoftwareInterrupt:
+ b SoftwareInterrupt
+PrefetchAbort:
+ b PrefetchAbort
+DataAbort:
+ b DataAbort
+Reserved:
+ b Reserved
+Irq:
+ b Irq
-#include <proxmark3.h>\r
-\r
-extern char __bootphase2_src_start__, __bootphase2_start__, __bootphase2_end__;\r
-void __attribute__((section(".bootphase1"))) CopyBootToRAM(void)\r
-{\r
- int i;\r
-\r
- volatile DWORD *s = (volatile DWORD *)&__bootphase2_src_start__;\r
- volatile DWORD *d = (volatile DWORD *)&__bootphase2_start__;\r
- unsigned int l = (int)&__bootphase2_end__ - (int)&__bootphase2_start__;\r
-\r
- for(i = 0; i < l/sizeof(DWORD); i++) *d++ = *s++;\r
-}\r
+#include <proxmark3.h>
+
+extern char __bootphase2_src_start__, __bootphase2_start__, __bootphase2_end__;
+void __attribute__((section(".bootphase1"))) CopyBootToRAM(void)
+{
+ int i;
+
+ volatile DWORD *s = (volatile DWORD *)&__bootphase2_src_start__;
+ volatile DWORD *d = (volatile DWORD *)&__bootphase2_start__;
+ unsigned int l = (int)&__bootphase2_end__ - (int)&__bootphase2_start__;
+
+ for(i = 0; i < l/sizeof(DWORD); i++) *d++ = *s++;
+}
-INCLUDE ../common/ldscript.common\r
-\r
-ENTRY(flashstart)\r
-SECTIONS\r
-{\r
- . = 0;\r
- \r
- .bootphase1 : {\r
- *(.startup) \r
- *(.bootphase1)\r
- \r
- /* It seems to be impossible to flush align a section at the\r
- end of a memory segment. Instead, we'll put the version_information\r
- wherever the linker wants it, and then put a pointer to the start\r
- of the version information at the end of the section.\r
- -- Henryk Plötz <henryk@ploetzli.ch> 2009-08-28 */\r
- \r
- _version_information_start = ABSOLUTE(.);\r
- *(.version_information);\r
- \r
- /* Why doesn't this work even though _bootphase1_version_pointer = 0x1001fc?\r
- . = _bootphase1_version_pointer - ORIGIN(bootphase1); */\r
- /* This works, apparently it fools the linker into accepting an absolute address */\r
- . = _bootphase1_version_pointer - ORIGIN(bootphase1) + ORIGIN(bootphase1);\r
- LONG(_version_information_start)\r
- } >bootphase1\r
- \r
- __bootphase2_src_start__ = ORIGIN(bootphase2);\r
- .bootphase2 : {\r
- __bootphase2_start__ = .;\r
- *(.startphase2)\r
- *(.text)\r
- *(.eh_frame)\r
- *(.glue_7)\r
- *(.glue_7t)\r
- *(.rodata)\r
- *(.data)\r
- . = ALIGN( 32 / 8 );\r
- __bootphase2_end__ = .;\r
- } >ram AT>bootphase2\r
- \r
- .bss : {\r
- __bss_start__ = .; \r
- *(.bss)\r
- } >ram\r
- \r
- . = ALIGN( 32 / 8 );\r
- __bss_end__ = .;\r
- \r
- .commonarea (NOLOAD) : {\r
- *(.commonarea)\r
- } >commonarea\r
-}\r
+INCLUDE ../common/ldscript.common
+
+ENTRY(flashstart)
+SECTIONS
+{
+ . = 0;
+
+ .bootphase1 : {
+ *(.startup)
+ *(.bootphase1)
+
+ /* It seems to be impossible to flush align a section at the
+ end of a memory segment. Instead, we'll put the version_information
+ wherever the linker wants it, and then put a pointer to the start
+ of the version information at the end of the section.
+ -- Henryk Plötz <henryk@ploetzli.ch> 2009-08-28 */
+
+ _version_information_start = ABSOLUTE(.);
+ *(.version_information);
+
+ /* Why doesn't this work even though _bootphase1_version_pointer = 0x1001fc?
+ . = _bootphase1_version_pointer - ORIGIN(bootphase1); */
+ /* This works, apparently it fools the linker into accepting an absolute address */
+ . = _bootphase1_version_pointer - ORIGIN(bootphase1) + ORIGIN(bootphase1);
+ LONG(_version_information_start)
+ } >bootphase1
+
+ __bootphase2_src_start__ = ORIGIN(bootphase2);
+ .bootphase2 : {
+ __bootphase2_start__ = .;
+ *(.startphase2)
+ *(.text)
+ *(.eh_frame)
+ *(.glue_7)
+ *(.glue_7t)
+ *(.rodata)
+ *(.data)
+ . = ALIGN( 32 / 8 );
+ __bootphase2_end__ = .;
+ } >ram AT>bootphase2
+
+ .bss : {
+ __bss_start__ = .;
+ *(.bss)
+ } >ram
+
+ . = ALIGN( 32 / 8 );
+ __bss_end__ = .;
+
+ .commonarea (NOLOAD) : {
+ *(.commonarea)
+ } >commonarea
+}