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