Merge remote-tracking branch 'upstream/master' into pm3+reveng
authormarshmellow42 <marshmellowrf@gmail.com>
Mon, 29 Jun 2015 04:06:59 +0000 (00:06 -0400)
committermarshmellow42 <marshmellowrf@gmail.com>
Mon, 29 Jun 2015 04:06:59 +0000 (00:06 -0400)
Conflicts:
client/Makefile

60 files changed:
.gitignore
CHANGELOG.md
COMPILING.txt
Makefile
armsrc/Makefile
armsrc/aes.c
armsrc/appmain.c
armsrc/apps.h
armsrc/epa.c
armsrc/epa.h
armsrc/fpgaloader.c
armsrc/fpgaloader.h [new file with mode: 0644]
armsrc/iso14443.c [deleted file]
armsrc/iso14443b.c [new file with mode: 0644]
armsrc/ldscript
armsrc/lfops.c
armsrc/optimized_cipher.c
armsrc/start.c
armsrc/util.c
client/Makefile
client/cmddata.c
client/cmdhf.c
client/cmdhf14b.c
client/cmdhf14b.h
client/cmdhfepa.c
client/cmdhfmf.c
client/cmdhfmfu.c
client/cmdhfmfu.h
client/cmdhw.c
client/cmdlfem4x.c
client/fpga_compress.c [new file with mode: 0644]
client/hid-flasher/usb_cmd.h
client/lualibs/commands.lua
client/proxmark3.c
common/Makefile.common
common/protocols.c
fpga/fpga_hf.bit
fpga/fpga_hf.v
fpga/hi_read_rx_xcorr.v
include/proxmark3.h
include/usb_cmd.h
zlib/ChangeLog [new file with mode: 0644]
zlib/FAQ [new file with mode: 0644]
zlib/README [new file with mode: 0644]
zlib/adler32.c [new file with mode: 0644]
zlib/deflate.c [new file with mode: 0644]
zlib/deflate.h [new file with mode: 0644]
zlib/inffast.c [new file with mode: 0644]
zlib/inffast.h [new file with mode: 0644]
zlib/inffixed.h [new file with mode: 0644]
zlib/inflate.c [new file with mode: 0644]
zlib/inflate.h [new file with mode: 0644]
zlib/inftrees.c [new file with mode: 0644]
zlib/inftrees.h [new file with mode: 0644]
zlib/trees.c [new file with mode: 0644]
zlib/trees.h [new file with mode: 0644]
zlib/zconf.h [new file with mode: 0644]
zlib/zlib.h [new file with mode: 0644]
zlib/zutil.c [new file with mode: 0644]
zlib/zutil.h [new file with mode: 0644]

index 07669e14a240ae9125fef7ea6cc66387cae3211b..880c092f175fb82959cf11fba62da1985c758a07 100644 (file)
@@ -12,6 +12,7 @@
 *.bin
 *.dll
 *.moc.cpp
+*.z
 *.exe
 proxmark
 proxmark3
index 3c016c3d0c3c3f2bfbb632cda7bde7d786a50dda..3f9546d9856277428b89f0caa355f205e9ac1093 100644 (file)
@@ -3,6 +3,21 @@ All notable changes to this project will be documented in this file.
 This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
 
 ## [Unreleased][unreleased]
+
+### Changed
+- Changed `hf 14b write` to `hf 14b sriwrite` as it only applied to sri tags (marshmellow)
+- Added `hf 14b info` to `hf search` (marshmellow)
+
+### Added
+- Add `hf 14b info` to find and print info about std 14b tags and sri tags (using 14b raw commands in the client)  (marshmellow)
+- Add PACE replay functionality (frederikmoellers)
+
+### Fixed 
+- t55xx write timing (marshmellow)
+
+
+## [2.1.0][2015-06-23]
+
 ### Changed
 - Added ultralight/ntag tag type detection to `hf 14a read` (marshmellow)
 - Improved ultralight dump command to auto detect tag type, take authentication, and dump full memory (or subset specified) of known tag types (iceman1001 / marshmellow)
@@ -14,6 +29,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
 ### Fixed
 - Fixed EM4x50 read/demod of the tags broadcasted memory blocks. 'lf em4x em4x50read' (not page read) (marshmellow)
 - Fixed issue #19, problems with LF T55xx commands (iceman1001, marshmellow)
+- Fixed various problems with iso14443b, issue #103 (piwi, marshmellow)
 
 ### Added
 - Added `hf search` - currently tests for 14443a tags, iclass tags, and 15693 tags (marshmellow) 
index c894f0ff04f14f6d9aa7d61e2502140ce50225b6..1cc34a0fc008309d1376b1755ceeb09e19c9ae3a 100644 (file)
@@ -81,7 +81,31 @@ Download the ProxSpace environment archive and extract it to C:\
 = Mac OS X =
 ============
 
-macport stuff should do ;)
+Tested on OSX 10.10 Yosemite
+
+1 - Install Xcode and Xcode Command Line Tools
+
+2 - Install Homebrew and dependencies
+    brew install readline
+    brew instal libusb
+
+3 - Download DevKitARM for OSX
+    http://sourceforge.net/projects/devkitpro/files/devkitARM/devkitARM_r44/
+    Unpack devkitARM_r44-osx.tar.bz2 to proxmark3 directory.
+
+4 - Edit proxmark3/client/Makefile adding path to readline
+
+    LDLIBS = -L/usr/local/Cellar/readline/6.3.8/lib/ -L/opt/local/lib -L/usr/local/lib ../liblua/liblua.a -lreadline -lpthread -lm
+    CFLAGS = -std=c99 -I/usr/local/Cellar/readline/6.3.8/include/ -I. -I../include -I../common -I/opt/local/include -I../liblua  -Wall $(COMMON_FLAGS) -g -O4
+
+    Replace path /usr/local/Cellar/readline/6.3.8 with your actuall readline path. See homebrew manuals.
+
+5 - Set Environment
+
+    export DEVKITPRO=$HOME/proxmark3/
+    export DEVKITARM=$DEVKITPRO/devkitARM
+    export PATH=${PATH}:${DEVKITARM}/bin
+
 
 ============
 =   Linux  =
index b558da2d74a5dfcdbadd47d3bb37a89ae3eb7b47..0e065b41dc9ee86c6245d421163f66990c0a75e5 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,9 +1,8 @@
 include common/Makefile.common
 
-GZIP=gzip
 FLASH_PORT=/dev/ttyACM0
 
-all clean: %: bootrom/% armsrc/% client/% recovery/%
+all clean: %: client/% bootrom/% armsrc/% recovery/%
 
 bootrom/%: FORCE
        $(MAKE) -C bootrom $(patsubst bootrom/%,%,$@)
@@ -15,8 +14,8 @@ recovery/%: FORCE
        $(MAKE) -C recovery $(patsubst recovery/%,%,$@)
 FORCE: # Dummy target to force remake in the subdirectories, even if files exist (this Makefile doesn't know about the prerequisites)
 
+.PHONY: all clean help _test flash-bootrom flash-os flash-all FORCE
 
-.PHONY: all clean help _test flash-bootrom flash-os flash-fpga flash-both flash-all FORCE
 help:
        @echo Multi-OS Makefile, you are running on $(DETECTED_OS)
        @echo Possible targets:
@@ -24,9 +23,7 @@ help:
        @echo + client        - Make only the OS-specific host directory
        @echo + flash-bootrom - Make bootrom and flash it
        @echo + flash-os      - Make armsrc and flash os (includes fpga)
-       @echo + flash-fpga    - (Deprecated:) Make armsrc and flash fpga
-       @echo + flash-both    - Make armsrc and flash os and fpga image
-       @echo + flash-all     - Make bootrom and armsrc and flash bootrom, os and fpga image
+       @echo + flash-all     - Make bootrom and armsrc and flash bootrom and os image
        @echo + clean         - Clean in bootrom, armsrc and the OS-specific host directory
 
 client: client/all
@@ -34,16 +31,10 @@ client: client/all
 flash-bootrom: bootrom/obj/bootrom.elf $(FLASH_TOOL)
        $(FLASH_TOOL) $(FLASH_PORT) -b $(subst /,$(PATHSEP),$<)
 
-flash-os: armsrc/obj/osimage.elf $(FLASH_TOOL)
+flash-os: armsrc/obj/fullimage.elf $(FLASH_TOOL)
        $(FLASH_TOOL) $(FLASH_PORT) $(subst /,$(PATHSEP),$<)
 
-#flash-fpga: armsrc/obj/fpgaimage.elf $(FLASH_TOOL)
-#      $(FLASH_TOOL) $(FLASH_PORT) $(subst /,$(PATHSEP),$<)
-
-flash-both: armsrc/obj/osimage.elf $(FLASH_TOOL)
-       $(FLASH_TOOL) $(FLASH_PORT) $(subst /,$(PATHSEP),$(filter-out $(FLASH_TOOL),$^))
-
-flash-all: bootrom/obj/bootrom.elf armsrc/obj/osimage.elf $(FLASH_TOOL)
+flash-all: bootrom/obj/bootrom.elf armsrc/obj/fullimage.elf $(FLASH_TOOL)
        $(FLASH_TOOL) $(FLASH_PORT) -b $(subst /,$(PATHSEP),$(filter-out $(FLASH_TOOL),$^))
 
 newtarbin:
index 899b03075af35d1d51a0d61f318d1028959ae09f..1214c949f3755c54833b8969753f8914042367c8 100644 (file)
@@ -10,21 +10,38 @@ 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     = -DWITH_LF -DWITH_ISO15693 -DWITH_ISO14443a -DWITH_ISO14443b -DWITH_ICLASS -DWITH_LEGICRF -DWITH_HITAG  -DWITH_CRC -DON_DEVICE -fno-strict-aliasing -ffunction-sections -fdata-sections
+APP_CFLAGS     = -DWITH_LF -DWITH_ISO15693 -DWITH_ISO14443a -DWITH_ISO14443b -DWITH_ICLASS -DWITH_LEGICRF -DWITH_HITAG  -DWITH_CRC -DON_DEVICE \
+                               -fno-strict-aliasing -ffunction-sections -fdata-sections
 #-DWITH_LCD 
 
 #SRC_LCD = fonts.c LCD.c
 SRC_LF = lfops.c hitag2.c lfsampling.c
 SRC_ISO15693 = iso15693.c iso15693tools.c
 SRC_ISO14443a = epa.c iso14443a.c mifareutil.c mifarecmd.c mifaresniff.c
-SRC_ISO14443b = iso14443.c
+SRC_ISO14443b = iso14443b.c
 SRC_CRAPTO1 = crapto1.c crypto1.c des.c aes.c 
-SRC_CRC = iso14443crc.c crc.c crc16.c crc32.c 
+SRC_CRC = iso14443crc.c crc.c crc16.c crc32.c
 
+#the FPGA bitstream files. Note: order matters!
+FPGA_BITSTREAMS = fpga_lf.bit fpga_hf.bit
+
+#the zlib source files required for decompressing the fpga config at run time
+SRC_ZLIB = inflate.c inffast.c inftrees.c adler32.c zutil.c
+#additional defines required to compile zlib
+ZLIB_CFLAGS = -DZ_SOLO -DZ_PREFIX -DNO_GZIP -DZLIB_PM3_TUNED
+APP_CFLAGS += $(ZLIB_CFLAGS)
+# zlib includes:
+APP_CFLAGS += -I../zlib
+
+# stdint.h provided locally until GCC 4.5 becomes C99 compliant
+APP_CFLAGS += -I.
+
+# Compile these in thumb mode (small size)
 THUMBSRC = start.c \
        $(SRC_LCD) \
        $(SRC_ISO15693) \
        $(SRC_LF) \
+       $(SRC_ZLIB) \
        appmain.c \
        printf.c \
        util.c \
@@ -45,50 +62,63 @@ ARMSRC = fpgaloader.c \
        BigBuf.c \
        optimized_cipher.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
 
-OBJS = $(OBJDIR)/osimage.s19 
-#$(OBJDIR)/fpgaimage.s19
+OBJS = $(OBJDIR)/fullimage.s19 
+FPGA_COMPRESSOR = ../client/fpga_compress
 
 all: $(OBJS)
 
-$(OBJDIR)/fpga_lf.o: fpga_lf.bit
-       $(OBJCOPY) -O elf32-littlearm -I binary -B arm --redefine-sym _binary____fpga_fpga_lf_bit_start=_binary_fpga_lf_bit_start --redefine-sym _binary____fpga_fpga_lf_bit_end=_binary_fpga_lf_bit_end --prefix-sections=fpga_lf_bit  $^ $@
+.DELETE_ON_ERROR:
+
+$(OBJDIR)/fpga_all.o: $(OBJDIR)/fpga_all.bit.z
+       $(OBJCOPY) -O elf32-littlearm -I binary -B arm --prefix-sections=fpga_all_bit $^ $@
 
-$(OBJDIR)/fpga_hf.o: fpga_hf.bit
-       $(OBJCOPY) -O elf32-littlearm -I binary -B arm --redefine-sym _binary____fpga_fpga_hf_bit_start=_binary_fpga_hf_bit_start --redefine-sym _binary____fpga_fpga_hf_bit_end=_binary_fpga_hf_bit_end --prefix-sections=fpga_hf_bit  $^ $@
+$(OBJDIR)/fpga_all.bit.z: $(FPGA_BITSTREAMS) $(FPGA_COMPRESSOR)
+       $(FPGA_COMPRESSOR) $(filter %.bit,$^) $@
 
-$(OBJDIR)/fullimage.elf: $(VERSIONOBJ) $(OBJDIR)/fpga_lf.o $(OBJDIR)/fpga_hf.o $(THUMBOBJ) $(ARMOBJ)
+$(FPGA_COMPRESSOR):
+               make -C ../client $(notdir $(FPGA_COMPRESSOR))
+               
+$(OBJDIR)/fullimage.stage1.elf: $(VERSIONOBJ) $(OBJDIR)/fpga_all.o $(THUMBOBJ) $(ARMOBJ)
        $(CC) $(LDFLAGS) -Wl,-T,ldscript,-Map,$(patsubst %.elf,%.map,$@) -o $@ $^ $(LIBS)
 
-#$(OBJDIR)/fpgaimage.elf: $(OBJDIR)/fullimage.elf
-#      $(OBJCOPY) -F elf32-littlearm --only-section .fpgaimage $^ $@  
+$(OBJDIR)/fullimage.nodata.bin: $(OBJDIR)/fullimage.stage1.elf
+       $(OBJCOPY) -O binary -I elf32-littlearm --remove-section .data $^ $@
+       
+$(OBJDIR)/fullimage.nodata.o: $(OBJDIR)/fullimage.nodata.bin
+       $(OBJCOPY) -O elf32-littlearm -I binary -B arm --rename-section .data=stage1_image $^ $@
 
-$(OBJDIR)/osimage.elf: $(OBJDIR)/fullimage.elf
-       $(OBJCOPY) -F elf32-littlearm $^ $@
+$(OBJDIR)/fullimage.data.bin: $(OBJDIR)/fullimage.stage1.elf
+       $(OBJCOPY) -O binary -I elf32-littlearm --only-section .data $^ $@
 
+$(OBJDIR)/fullimage.data.bin.z: $(OBJDIR)/fullimage.data.bin $(FPGA_COMPRESSOR)
+       $(FPGA_COMPRESSOR) $(filter %.bin,$^) $@  
+       
+$(OBJDIR)/fullimage.data.o: $(OBJDIR)/fullimage.data.bin.z
+       $(OBJCOPY) -O elf32-littlearm -I binary -B arm --rename-section .data=compressed_data $^ $@
+
+$(OBJDIR)/fullimage.elf: $(OBJDIR)/fullimage.nodata.o $(OBJDIR)/fullimage.data.o
+       $(CC) $(LDFLAGS) -Wl,-T,ldscript,-Map,$(patsubst %.elf,%.map,$@) -o $@ $^
+       
 tarbin: $(OBJS)
        $(TAR) $(TARFLAGS) ../proxmark3-$(platform)-bin.tar $(OBJS:%=armsrc/%) $(OBJS:%.s19=armsrc/%.elf)
 
-
 clean:
        $(DELETE) $(OBJDIR)$(PATHSEP)*.o
        $(DELETE) $(OBJDIR)$(PATHSEP)*.elf
        $(DELETE) $(OBJDIR)$(PATHSEP)*.s19
        $(DELETE) $(OBJDIR)$(PATHSEP)*.map
        $(DELETE) $(OBJDIR)$(PATHSEP)*.d
+       $(DELETE) $(OBJDIR)$(PATHSEP)*.z
+       $(DELETE) $(OBJDIR)$(PATHSEP)*.bin
        $(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)
+       @echo + all    - Build the full image $(OBJDIR)/fullimage.s19
+       @echo + clean  - Clean $(OBJDIR)
 
index 3df006bb355f2b0f7db494b36f98c8fd53355868..a199d04b7dc8d48bacbf446de619406385320159 100644 (file)
@@ -1,4 +1,3 @@
-#include "stdio.h"
 #include "aes.h"
 
 static const unsigned int Te0[256] = {
@@ -1138,6 +1137,9 @@ int AesDecrypt(AesCtx *pCtx, unsigned char *pCipher, unsigned char *pData, unsig
 //////////////////////////////////////////////////////////////////////////////
 
 #ifndef EMBEDDED
+
+#include <stdio.h>
+
 int main()
 {
     AesCtx ctx;
index c226c726398dd822b85f287aadb8d47be421e7e3..0cbfa2498e6ca7349f23766af663cd57ab70ac47 100644 (file)
@@ -250,55 +250,6 @@ void MeasureAntennaTuningHf(void)
 }
 
 
-void SimulateTagHfListen(void)
-{
-       // ToDo: historically this used the free buffer, which was 2744 Bytes long. 
-       // There might be a better size to be defined:
-       #define HF_14B_SNOOP_BUFFER_SIZE 2744
-       uint8_t *dest = BigBuf_malloc(HF_14B_SNOOP_BUFFER_SIZE);
-       uint8_t 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.
-       FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
-       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)) {
-                       uint8_t r = (uint8_t)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 >= HF_14B_SNOOP_BUFFER_SIZE) {
-                                       break;
-                               }
-                       }
-               }
-       }
-       DbpString("simulate tag (now type bitsamples)");
-}
-
 void ReadMem(int addr)
 {
        const uint8_t *data = ((uint8_t *)addr);
@@ -310,11 +261,11 @@ void ReadMem(int addr)
 /* 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;
+extern char *_bootphase1_version_pointer, _flash_start, _flash_end, _bootrom_start, _bootrom_end, __data_src_start__;
 void SendVersion(void)
 {
-       char temp[512]; /* Limited data payload in USB packets */
-       DbpString("Prox/RFID mark3 RFID instrument");
+       char temp[USB_CMD_DATA_SIZE]; /* Limited data payload in USB packets */
+       char VersionString[USB_CMD_DATA_SIZE] = { '\0' };
 
        /* Try to find the bootrom version information. Expect to find a pointer at
         * symbol _bootphase1_version_pointer, perform slight sanity checks on the
@@ -322,19 +273,24 @@ void SendVersion(void)
         */
        char *bootrom_version = *(char**)&_bootphase1_version_pointer;
        if( bootrom_version < &_flash_start || bootrom_version >= &_flash_end ) {
-               DbpString("bootrom version information appears invalid");
+               strcat(VersionString, "bootrom version information appears invalid\n");
        } else {
                FormatVersionInformation(temp, sizeof(temp), "bootrom: ", bootrom_version);
-               DbpString(temp);
+               strncat(VersionString, temp, sizeof(VersionString) - strlen(VersionString) - 1);
        }
 
        FormatVersionInformation(temp, sizeof(temp), "os: ", &version_information);
-       DbpString(temp);
+       strncat(VersionString, temp, sizeof(VersionString) - strlen(VersionString) - 1);
+
+       FpgaGatherVersion(FPGA_BITSTREAM_LF, temp, sizeof(temp));
+       strncat(VersionString, temp, sizeof(VersionString) - strlen(VersionString) - 1);
+       FpgaGatherVersion(FPGA_BITSTREAM_HF, temp, sizeof(temp));
+       strncat(VersionString, temp, sizeof(VersionString) - strlen(VersionString) - 1);
 
-       FpgaGatherVersion(temp, sizeof(temp));
-       DbpString(temp);
-       // Send Chip ID
-       cmd_send(CMD_ACK,*(AT91C_DBGU_CIDR),0,0,NULL,0);
+       // Send Chip ID and used flash memory
+       uint32_t text_and_rodata_section_size = (uint32_t)&__data_src_start__ - (uint32_t)&_flash_start;
+       uint32_t compressed_data_section_size = common_area.arg1;
+       cmd_send(CMD_ACK, *(AT91C_DBGU_CIDR), text_and_rodata_section_size + compressed_data_section_size, 0, VersionString, strlen(VersionString));
 }
 
 #ifdef WITH_LF
@@ -782,20 +738,17 @@ void UsbPacketReceived(uint8_t *packet, int len)
 #endif
 
 #ifdef WITH_ISO14443b
-               case CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443:
-                       AcquireRawAdcSamplesIso14443(c->arg[0]);
-                       break;
                case CMD_READ_SRI512_TAG:
-                       ReadSTMemoryIso14443(0x0F);
+                       ReadSTMemoryIso14443b(0x0F);
                        break;
                case CMD_READ_SRIX4K_TAG:
-                       ReadSTMemoryIso14443(0x7F);
+                       ReadSTMemoryIso14443b(0x7F);
                        break;
-               case CMD_SNOOP_ISO_14443:
-                       SnoopIso14443();
+               case CMD_SNOOP_ISO_14443B:
+                       SnoopIso14443b();
                        break;
-               case CMD_SIMULATE_TAG_ISO_14443:
-                       SimulateIso14443Tag();
+               case CMD_SIMULATE_TAG_ISO_14443B:
+                       SimulateIso14443bTag();
                        break;
                case CMD_ISO_14443B_COMMAND:
                        SendRawCommand14443B(c->arg[0],c->arg[1],c->arg[2],c->d.asBytes);
@@ -816,6 +769,9 @@ void UsbPacketReceived(uint8_t *packet, int len)
                case CMD_EPA_PACE_COLLECT_NONCE:
                        EPA_PACE_Collect_Nonce(c);
                        break;
+               case CMD_EPA_PACE_REPLAY:
+                       EPA_PACE_Replay(c);
+                       break;
                        
                case CMD_READER_MIFARE:
                        ReaderMifare(c->arg[0]);
@@ -911,10 +867,6 @@ void UsbPacketReceived(uint8_t *packet, int len)
                        break;
 #endif
 
-               case CMD_SIMULATE_TAG_HF_LISTEN:
-                       SimulateTagHfListen();
-                       break;
-
                case CMD_BUFF_CLEAR:
                        BigBuf_Clear();
                        break;
index 6360b664b82f49528570d2ec00b1f88a93cbd258..bb094b330521b08efbe4b57ff9fa8ee70fd8c250 100644 (file)
@@ -19,6 +19,7 @@
 #include "mifare.h"
 #include "../common/crc32.h"
 #include "BigBuf.h"
+#include "fpgaloader.h"
 
 extern const uint8_t OddByteParity[256];
 extern int rsamples;   // = 0;
@@ -50,60 +51,6 @@ void ListenReaderField(int limit);
 extern int ToSendMax;
 extern uint8_t ToSend[];
 
-/// fpga.h
-void FpgaSendCommand(uint16_t cmd, uint16_t v);
-void FpgaWriteConfWord(uint8_t v);
-void FpgaDownloadAndGo(int bitstream_version);
-int FpgaGatherBitstreamVersion();
-void FpgaGatherVersion(char *dst, int len);
-void FpgaSetupSsc(void);
-void SetupSpi(int mode);
-bool FpgaSetupSscDma(uint8_t *buf, int len);
-#define FpgaDisableSscDma(void)        AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS;
-#define FpgaEnableSscDma(void) AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTEN;
-void SetAdcMuxFor(uint32_t whichGpio);
-
-// Definitions for the FPGA commands.
-#define FPGA_CMD_SET_CONFREG                                   (1<<12)
-#define FPGA_CMD_SET_DIVISOR                                   (2<<12)
-#define FPGA_CMD_SET_USER_BYTE1                                        (3<<12)
-// Definitions for the FPGA configuration word.
-// LF
-#define FPGA_MAJOR_MODE_LF_ADC                                 (0<<5)
-#define FPGA_MAJOR_MODE_LF_EDGE_DETECT                 (1<<5)
-#define FPGA_MAJOR_MODE_LF_PASSTHRU                            (2<<5)
-// HF
-#define FPGA_MAJOR_MODE_HF_READER_TX                           (0<<5)
-#define FPGA_MAJOR_MODE_HF_READER_RX_XCORR                     (1<<5)
-#define FPGA_MAJOR_MODE_HF_SIMULATOR                           (2<<5)
-#define FPGA_MAJOR_MODE_HF_ISO14443A                           (3<<5)
-// BOTH
-#define FPGA_MAJOR_MODE_OFF                                    (7<<5)
-// Options for LF_ADC
-#define FPGA_LF_ADC_READER_FIELD                               (1<<0)
-// Options for LF_EDGE_DETECT
-#define FPGA_CMD_SET_EDGE_DETECT_THRESHOLD                     FPGA_CMD_SET_USER_BYTE1
-#define FPGA_LF_EDGE_DETECT_READER_FIELD                       (1<<0)
-#define FPGA_LF_EDGE_DETECT_TOGGLE_MODE                                (1<<1)
-// 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)
-#define FPGA_HF_SIMULATOR_MODULATE_424K                                (4<<0)
-#define FPGA_HF_SIMULATOR_MODULATE_424K_8BIT           0x5//101
-
-// 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
 extern uint8_t decimation;
@@ -141,10 +88,10 @@ void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode);
 void EM4xWriteWord(uint32_t Data, uint8_t Address, uint32_t Pwd, uint8_t PwdMode);
 
 /// iso14443.h
-void SimulateIso14443Tag(void);
-void AcquireRawAdcSamplesIso14443(uint32_t parameter);
-void ReadSTMemoryIso14443(uint32_t);
-void RAMFUNC SnoopIso14443(void);
+void SimulateIso14443bTag(void);
+void AcquireRawAdcSamplesIso14443b(uint32_t parameter);
+void ReadSTMemoryIso14443b(uint32_t);
+void RAMFUNC SnoopIso14443b(void);
 void SendRawCommand14443B(uint32_t, uint32_t, uint8_t, uint8_t[]);
 
 /// iso14443a.h
@@ -160,6 +107,7 @@ void RAMFUNC SniffMifare(uint8_t param);
 
 /// epa.h
 void EPA_PACE_Collect_Nonce(UsbCommand * c);
+void EPA_PACE_Replay(UsbCommand *c);
 
 // mifarecmd.h
 void ReaderMifare(bool first_try);
index 0006d59d01c03fd4944caefef829771b1b8068fc..6bd8692ecaa52d53c7c18ea3364acac26fdb670a 100644 (file)
@@ -5,7 +5,7 @@
 // at your option, any later version. See the LICENSE.txt file for the text of
 // the license.
 //-----------------------------------------------------------------------------
-// Routines to support the German eletronic "Personalausweis" (ID card)
+// Routines to support the German electronic "Personalausweis" (ID card)
 // Note that the functions which do not implement USB commands do NOT initialize
 // the card (with iso14443a_select_card etc.). If You want to use these
 // functions, You need to do the setup before calling them!
@@ -74,6 +74,32 @@ static const uint8_t oid_pace_start[] = {
     0x04 // id-PACE
 };
 
+// APDUs for replaying:
+// MSE: Set AT (initiate PACE)
+static uint8_t apdu_replay_mse_set_at_pace[41];
+// General Authenticate (Get Nonce)
+static uint8_t apdu_replay_general_authenticate_pace_get_nonce[8];
+// General Authenticate (Map Nonce)
+static uint8_t apdu_replay_general_authenticate_pace_map_nonce[75];
+// General Authenticate (Mutual Authenticate)
+static uint8_t apdu_replay_general_authenticate_pace_mutual_authenticate[75];
+// General Authenticate (Perform Key Agreement)
+static uint8_t apdu_replay_general_authenticate_pace_perform_key_agreement[18];
+// pointers to the APDUs (for iterations)
+static struct {
+       uint8_t len;
+       uint8_t *data;
+} const apdus_replay[] = {
+       {sizeof(apdu_replay_mse_set_at_pace), apdu_replay_mse_set_at_pace},
+       {sizeof(apdu_replay_general_authenticate_pace_get_nonce), apdu_replay_general_authenticate_pace_get_nonce},
+       {sizeof(apdu_replay_general_authenticate_pace_map_nonce), apdu_replay_general_authenticate_pace_map_nonce},
+       {sizeof(apdu_replay_general_authenticate_pace_mutual_authenticate), apdu_replay_general_authenticate_pace_mutual_authenticate},
+       {sizeof(apdu_replay_general_authenticate_pace_perform_key_agreement), apdu_replay_general_authenticate_pace_perform_key_agreement}
+};
+
+// lengths of the replay APDUs
+static uint8_t apdu_lengths_replay[5];
+
 //-----------------------------------------------------------------------------
 // Closes the communication channel and turns off the field
 //-----------------------------------------------------------------------------
@@ -101,7 +127,7 @@ size_t EPA_Parse_CardAccess(uint8_t *data,
                             pace_version_info_t *pace_info)
 {
        size_t index = 0;
-       
+
        while (index <= length - 2) {
                // determine type of element
                // SET or SEQUENCE
@@ -158,7 +184,7 @@ size_t EPA_Parse_CardAccess(uint8_t *data,
                        index += 2 + data[index + 1];
                }
        }
-       
+
        // TODO: We should check whether we reached the end in error, but for that
        //       we need a better parser (e.g. with states like IN_SET or IN_PACE_INFO)
        return 0;
@@ -176,7 +202,7 @@ int EPA_Read_CardAccess(uint8_t *buffer, size_t max_length)
        // we reserve 262 bytes here just to be safe (256-byte APDU + SW + ISO frame)
        uint8_t response_apdu[262];
        int rapdu_length = 0;
-       
+
        // select the file EF.CardAccess
        rapdu_length = iso14_apdu((uint8_t *)apdu_select_binary_cardaccess,
                                  sizeof(apdu_select_binary_cardaccess),
@@ -188,7 +214,7 @@ int EPA_Read_CardAccess(uint8_t *buffer, size_t max_length)
                Dbprintf("epa - no select cardaccess");
                return -1;
        }
-       
+
        // read the file
        rapdu_length = iso14_apdu((uint8_t *)apdu_read_binary,
                                  sizeof(apdu_read_binary),
@@ -200,7 +226,7 @@ int EPA_Read_CardAccess(uint8_t *buffer, size_t max_length)
                Dbprintf("epa - no read cardaccess");
                return -1;
        }
-       
+
        // copy the content into the buffer
        // length of data available: apdu_length - 4 (ISO frame) - 2 (SW)
        size_t to_copy = rapdu_length - 6;
@@ -215,16 +241,11 @@ int EPA_Read_CardAccess(uint8_t *buffer, size_t max_length)
 //-----------------------------------------------------------------------------
 static void EPA_PACE_Collect_Nonce_Abort(uint8_t step, int func_return)
 {
-//     // step in which the failure occured
-//     ack->arg[0] = step;
-//     // last return code
-//     ack->arg[1] = func_return;
-
        // power down the field
        EPA_Finish();
-       
+
        // send the USB packet
-  cmd_send(CMD_ACK,step,func_return,0,0,0);
+       cmd_send(CMD_ACK,step,func_return,0,0,0);
 }
 
 //-----------------------------------------------------------------------------
@@ -246,10 +267,6 @@ void EPA_PACE_Collect_Nonce(UsbCommand *c)
        // return value of a function
        int func_return = 0;
 
-//     // initialize ack with 0s
-//     memset(ack->arg, 0, 12);
-//     memset(ack->d.asBytes, 0, 48);
-       
        // set up communication
        func_return = EPA_Setup();
        if (func_return != 0) {
@@ -277,11 +294,11 @@ void EPA_PACE_Collect_Nonce(UsbCommand *c)
                EPA_PACE_Collect_Nonce_Abort(3, func_return);
                return;
        }
-       
+
        // initiate the PACE protocol
        // use the CAN for the password since that doesn't change
        func_return = EPA_PACE_MSE_Set_AT(pace_version_info, 2);
-       
+
        // now get the nonce
        uint8_t nonce[256] = {0};
        uint8_t requested_size = (uint8_t)c->arg[0];
@@ -292,14 +309,12 @@ void EPA_PACE_Collect_Nonce(UsbCommand *c)
                EPA_PACE_Collect_Nonce_Abort(4, func_return);
                return;
        }
-  
-  // all done, return
+
+       // all done, return
        EPA_Finish();
-       
+
        // save received information
-//     ack->arg[1] = func_return;
-//     memcpy(ack->d.asBytes, nonce, func_return);
-  cmd_send(CMD_ACK,0,func_return,0,nonce,func_return);
+       cmd_send(CMD_ACK,0,func_return,0,nonce,func_return);
 }
 
 //-----------------------------------------------------------------------------
@@ -320,7 +335,7 @@ int EPA_PACE_Get_Nonce(uint8_t requested_length, uint8_t *nonce)
               sizeof(apdu_general_authenticate_pace_get_nonce));
        // append Le (requested length + 2 due to tag/length taking 2 bytes) in RAPDU
        apdu[sizeof(apdu_general_authenticate_pace_get_nonce)] = requested_length + 4;
-       
+
        // send it
        uint8_t response_apdu[262];
        int send_return = iso14_apdu(apdu,
@@ -333,7 +348,7 @@ int EPA_PACE_Get_Nonce(uint8_t requested_length, uint8_t *nonce)
        {
                return -1;
        }
-       
+
        // if there is no nonce in the RAPDU, return here
        if (send_return < 10)
        {
@@ -348,7 +363,7 @@ int EPA_PACE_Get_Nonce(uint8_t requested_length, uint8_t *nonce)
        }
        // copy the nonce
        memcpy(nonce, response_apdu + 6, nonce_length);
-       
+
        return nonce_length;
 }
 
@@ -407,13 +422,79 @@ int EPA_PACE_MSE_Set_AT(pace_version_info_t pace_version_info, uint8_t password)
        return 0;
 }
 
+//-----------------------------------------------------------------------------
+// Perform the PACE protocol by replaying given APDUs
+//-----------------------------------------------------------------------------
+void EPA_PACE_Replay(UsbCommand *c)
+{
+       uint32_t timings[sizeof(apdu_lengths_replay) / sizeof(apdu_lengths_replay[0])] = {0};
+
+       // if an APDU has been passed, save it
+       if (c->arg[0] != 0) {
+               // make sure it's not too big
+               if(c->arg[2] > apdus_replay[c->arg[0] - 1].len)
+               {
+                       cmd_send(CMD_ACK, 1, 0, 0, NULL, 0);
+               }
+               memcpy(apdus_replay[c->arg[0] - 1].data + c->arg[1],
+                  c->d.asBytes,
+                  c->arg[2]);
+               // save/update APDU length
+               if (c->arg[1] == 0) {
+                       apdu_lengths_replay[c->arg[0] - 1] = c->arg[2];
+               } else {
+                       apdu_lengths_replay[c->arg[0] - 1] += c->arg[2];
+               }
+               cmd_send(CMD_ACK, 0, 0, 0, NULL, 0);
+               return;
+       }
+
+       // return value of a function
+       int func_return;
+
+       // set up communication
+       func_return = EPA_Setup();
+       if (func_return != 0) {
+               EPA_Finish();
+               cmd_send(CMD_ACK, 2, func_return, 0, NULL, 0);
+               return;
+       }
+
+       // increase the timeout (at least some cards really do need this!)/////////////
+       // iso14a_set_timeout(0x0003FFFF);
+
+       // response APDU
+       uint8_t response_apdu[300] = {0};
+
+       // now replay the data and measure the timings
+       for (int i = 0; i < sizeof(apdu_lengths_replay); i++) {
+               StartCountUS();
+               func_return = iso14_apdu(apdus_replay[i].data,
+                                        apdu_lengths_replay[i],
+                                        response_apdu);
+               timings[i] = GetCountUS();
+               // every step but the last one should succeed
+               if (i < sizeof(apdu_lengths_replay) - 1
+                   && (func_return < 6
+                       || response_apdu[func_return - 4] != 0x90
+                       || response_apdu[func_return - 3] != 0x00))
+               {
+                       EPA_Finish();
+                       cmd_send(CMD_ACK, 3 + i, func_return, 0, timings, 20);
+                       return;
+               }
+       }
+       EPA_Finish();
+       cmd_send(CMD_ACK,0,0,0,timings,20);
+       return;
+}
+
 //-----------------------------------------------------------------------------
 // Set up a communication channel (Card Select, PPS)
 // Returns 0 on success or a non-zero error code on failure
 //-----------------------------------------------------------------------------
 int EPA_Setup()
 {
-
        int return_code = 0;
        uint8_t uid[10];
        uint8_t pps_response[3];
@@ -422,20 +503,16 @@ int EPA_Setup()
 
        // power up the field
        iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD);
-
        // select the card
        return_code = iso14443a_select_card(uid, &card_select_info, NULL);
        if (return_code != 1) {
-               Dbprintf("Epa: Can't select card");
                return 1;
        }
-
        // send the PPS request
        ReaderTransmit((uint8_t *)pps, sizeof(pps), NULL);
        return_code = ReaderReceive(pps_response, pps_response_par);
        if (return_code != 3 || pps_response[0] != 0xD0) {
                return return_code == 0 ? 2 : return_code;
        }
-       
        return 0;
-}
\ No newline at end of file
+}
index 730652b79ef8b8afd31d0e20523dec6f83965ccf..0c580205da938c80d952a853af16c98cc140614d 100644 (file)
@@ -19,7 +19,7 @@ typedef struct {
        uint8_t parameter_id;
 } pace_version_info_t;
 
-// note: EPA_PACE_GetNonce is declared in apps.h
+// note: EPA_PACE_Collect_Nonce is declared in apps.h
 
 // general functions
 void EPA_Finish();
@@ -33,4 +33,4 @@ int EPA_Setup();
 int EPA_PACE_MSE_Set_AT(pace_version_info_t pace_version_info, uint8_t password);
 int EPA_PACE_Get_Nonce(uint8_t requested_length, uint8_t *nonce);
 
-#endif /* __EPA_H */
\ No newline at end of file
+#endif /* __EPA_H */
index 077b378a918b438cb0dc625642d22a7543eaabbf..16fed7c52469b857437a3d58474a1dd4d892f4b4 100644 (file)
@@ -9,10 +9,32 @@
 // Routines to load the FPGA image, and then to configure the FPGA's major
 // mode once it is configured.
 //-----------------------------------------------------------------------------
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include "fpgaloader.h"
 #include "proxmark3.h"
-#include "apps.h"
 #include "util.h"
 #include "string.h"
+#include "BigBuf.h"
+#include "zlib.h"
+
+extern void Dbprintf(const char *fmt, ...);
+
+// remember which version of the bitstream we have already downloaded to the FPGA
+static int downloaded_bitstream = FPGA_BITSTREAM_ERR;
+
+// this is where the bitstreams are located in memory:
+extern uint8_t _binary_obj_fpga_all_bit_z_start, _binary_obj_fpga_all_bit_z_end;
+
+static uint8_t *fpga_image_ptr = NULL;
+static uint32_t uncompressed_bytes_cnt;
+
+static const uint8_t _bitparse_fixed_header[] = {0x00, 0x09, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x00, 0x00, 0x01};
+#define FPGA_BITSTREAM_FIXED_HEADER_SIZE       sizeof(_bitparse_fixed_header)
+#define OUTPUT_BUFFER_LEN              80
+#define FPGA_INTERLEAVE_SIZE   288
 
 //-----------------------------------------------------------------------------
 // Set up the Serial Peripheral Interface as master
@@ -150,6 +172,94 @@ bool FpgaSetupSscDma(uint8_t *buf, int len)
     return true;
 }
 
+
+//----------------------------------------------------------------------------
+// Uncompress (inflate) the FPGA data. Returns one decompressed byte with
+// each call. 
+//----------------------------------------------------------------------------
+static int get_from_fpga_combined_stream(z_streamp compressed_fpga_stream, uint8_t *output_buffer)
+{
+       if (fpga_image_ptr == compressed_fpga_stream->next_out) {       // need more data
+               compressed_fpga_stream->next_out = output_buffer;
+               compressed_fpga_stream->avail_out = OUTPUT_BUFFER_LEN;
+               fpga_image_ptr = output_buffer;
+               int res = inflate(compressed_fpga_stream, Z_SYNC_FLUSH);
+               if (res != Z_OK) {
+                       Dbprintf("inflate returned: %d, %s", res, compressed_fpga_stream->msg);
+               }
+               if (res < 0) {
+                       return res;
+               }
+       }
+
+       uncompressed_bytes_cnt++;
+       
+       return *fpga_image_ptr++;
+}
+
+//----------------------------------------------------------------------------
+// Undo the interleaving of several FPGA config files. FPGA config files
+// are combined into one big file:
+// 288 bytes from FPGA file 1, followed by 288 bytes from FGPA file 2, etc.
+//----------------------------------------------------------------------------
+static int get_from_fpga_stream(int bitstream_version, z_streamp compressed_fpga_stream, uint8_t *output_buffer)
+{
+       while((uncompressed_bytes_cnt / FPGA_INTERLEAVE_SIZE) % FPGA_BITSTREAM_MAX != (bitstream_version - 1)) {
+               // skip undesired data belonging to other bitstream_versions
+               get_from_fpga_combined_stream(compressed_fpga_stream, output_buffer);
+       }
+
+       return get_from_fpga_combined_stream(compressed_fpga_stream, output_buffer);
+       
+}
+
+
+static voidpf fpga_inflate_malloc(voidpf opaque, uInt items, uInt size)
+{
+       return BigBuf_malloc(items*size);
+}
+
+
+static void fpga_inflate_free(voidpf opaque, voidpf address)
+{
+       BigBuf_free();
+}
+
+
+//----------------------------------------------------------------------------
+// Initialize decompression of the respective (HF or LF) FPGA stream 
+//----------------------------------------------------------------------------
+static bool reset_fpga_stream(int bitstream_version, z_streamp compressed_fpga_stream, uint8_t *output_buffer)
+{
+       uint8_t header[FPGA_BITSTREAM_FIXED_HEADER_SIZE];
+       
+       uncompressed_bytes_cnt = 0;
+       
+       // initialize z_stream structure for inflate:
+       compressed_fpga_stream->next_in = &_binary_obj_fpga_all_bit_z_start;
+       compressed_fpga_stream->avail_in = &_binary_obj_fpga_all_bit_z_start - &_binary_obj_fpga_all_bit_z_end;
+       compressed_fpga_stream->next_out = output_buffer;
+       compressed_fpga_stream->avail_out = OUTPUT_BUFFER_LEN;
+       compressed_fpga_stream->zalloc = &fpga_inflate_malloc;
+       compressed_fpga_stream->zfree = &fpga_inflate_free;
+
+       inflateInit2(compressed_fpga_stream, 0);
+
+       fpga_image_ptr = output_buffer;
+
+       for (uint16_t i = 0; i < FPGA_BITSTREAM_FIXED_HEADER_SIZE; i++) {
+               header[i] = get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer);
+       }
+       
+       // Check for a valid .bit file (starts with _bitparse_fixed_header)
+       if(memcmp(_bitparse_fixed_header, header, FPGA_BITSTREAM_FIXED_HEADER_SIZE) == 0) {
+               return true;
+       } else {
+               return false;
+       }
+}
+
+
 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); }
@@ -163,10 +273,12 @@ static void DownloadFPGA_byte(unsigned char w)
        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)
+// Download the fpga image starting at current stream position with length FpgaImageLen bytes
+static void DownloadFPGA(int bitstream_version, int FpgaImageLen, z_streamp compressed_fpga_stream, uint8_t *output_buffer)
 {
+
+       Dbprintf("DownloadFPGA(len: %d)", FpgaImageLen);
+       
        int i=0;
 
        AT91C_BASE_PIOA->PIO_OER = GPIO_FPGA_ON;
@@ -218,23 +330,15 @@ static void DownloadFPGA(const char *FpgaImage, int FpgaImageLen, int byterevers
                return;
        }
 
-       if(bytereversal) {
-               /* This is only supported for uint32_t aligned images */
-               if( ((int)FpgaImage % sizeof(uint32_t)) == 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.
-                        */
+       for(i = 0; i < FpgaImageLen; i++) {
+               int b = get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer);
+               if (b < 0) {
+                       Dbprintf("Error %d during FpgaDownload", b);
+                       break;
                }
-       } else {
-               while(FpgaImageLen-->0)
-                       DownloadFPGA_byte(*FpgaImage++);
+               DownloadFPGA_byte(b);
        }
-
+       
        // continue to clock FPGA until ready signal goes high
        i=100000;
        while ( (i--) && ( !(AT91C_BASE_PIOA->PIO_PDSR & GPIO_FPGA_DONE ) ) ) {
@@ -250,39 +354,21 @@ static void DownloadFPGA(const char *FpgaImage, int FpgaImageLen, int byterevers
        LED_D_OFF();
 }
 
-static char *bitparse_headers_start;
-static char *bitparse_bitstream_end;
-static int bitparse_initialized = 0;
+
 /* 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)
+static int bitparse_find_section(int bitstream_version, char section_name, unsigned int *section_length, z_streamp compressed_fpga_stream, uint8_t *output_buffer)
 {
-       char *pos = bitparse_headers_start;
        int result = 0;
-
-       if(!bitparse_initialized) return 0;
-
-       while(pos < bitparse_bitstream_end) {
-               char current_name = *pos++;
+       #define MAX_FPGA_BIT_STREAM_HEADER_SEARCH 100  // maximum number of bytes to search for the requested section
+       uint16_t numbytes = 0;
+       while(numbytes < MAX_FPGA_BIT_STREAM_HEADER_SEARCH) {
+               char current_name = get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer);
+               numbytes++;
                unsigned int current_length = 0;
                if(current_name < 'a' || current_name > 'e') {
                        /* Strange section name, abort */
@@ -292,11 +378,13 @@ int bitparse_find_section(char section_name, char **section_start, unsigned int
                switch(current_name) {
                case 'e':
                        /* Four byte length field */
-                       current_length += (*pos++) << 24;
-                       current_length += (*pos++) << 16;
+                       current_length += get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer) << 24;
+                       current_length += get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer) << 16;
+                       numbytes += 2;
                default: /* Fall through, two byte length field */
-                       current_length += (*pos++) << 8;
-                       current_length += (*pos++) << 0;
+                       current_length += get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer) << 8;
+                       current_length += get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer) << 0;
+                       numbytes += 2;
                }
 
                if(current_name != 'e' && current_length > 255) {
@@ -306,111 +394,123 @@ int bitparse_find_section(char section_name, char **section_start, unsigned int
 
                if(current_name == section_name) {
                        /* Found it */
-                       *section_start = pos;
                        *section_length = current_length;
                        result = 1;
                        break;
                }
 
-               pos += current_length; /* Skip section */
+               for (uint16_t i = 0; i < current_length && numbytes < MAX_FPGA_BIT_STREAM_HEADER_SEARCH; i++) {
+                       get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer);
+                       numbytes++;
+               }
        }
 
        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_lf_bit_start, _binary_fpga_lf_bit_end;
-extern char _binary_fpga_hf_bit_start, _binary_fpga_hf_bit_end;
+
+//----------------------------------------------------------------------------
+// Check which FPGA image is currently loaded (if any). If necessary 
+// decompress and load the correct (HF or LF) image to the FPGA
+//----------------------------------------------------------------------------
 void FpgaDownloadAndGo(int bitstream_version)
 {
-       void *bit_start;
-       void *bit_end;
-
+       z_stream compressed_fpga_stream;
+       uint8_t output_buffer[OUTPUT_BUFFER_LEN];
+       
        // check whether or not the bitstream is already loaded
-       if (FpgaGatherBitstreamVersion() == bitstream_version)
+       if (downloaded_bitstream == bitstream_version)
                return;
 
-       if (bitstream_version == FPGA_BITSTREAM_LF) {
-               bit_start = &_binary_fpga_lf_bit_start;
-               bit_end = &_binary_fpga_lf_bit_end;
-       } else if (bitstream_version == FPGA_BITSTREAM_HF) {
-               bit_start = &_binary_fpga_hf_bit_start;
-               bit_end = &_binary_fpga_hf_bit_end;
-       } else
+       // make sure that we have enough memory to decompress
+       BigBuf_free();
+       
+       if (!reset_fpga_stream(bitstream_version, &compressed_fpga_stream, output_buffer)) {
                return;
-       /* Check for the new flash image format: Should have the .bit file at &_binary_fpga_bit_start
-        */
-       if(bitparse_init(bit_start, 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 uint32_t, stored as uint32_t 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( *(uint32_t*)0x102000 == 0xFFFFFFFF && *(uint32_t*)0x102004 == 0xAA995566 )
-               DownloadFPGA((char*)0x102000, 10524*4, 1);
-}
+       unsigned int bitstream_length;
+       if(bitparse_find_section(bitstream_version, 'e', &bitstream_length, &compressed_fpga_stream, output_buffer)) {
+               DownloadFPGA(bitstream_version, bitstream_length, &compressed_fpga_stream, output_buffer);
+               downloaded_bitstream = bitstream_version;
+       }
+
+       inflateEnd(&compressed_fpga_stream);
+}      
 
-int FpgaGatherBitstreamVersion()
-{
-       char temp[256];
-       FpgaGatherVersion(temp, sizeof (temp));
-       if (!memcmp("LF", temp, 2))
-               return FPGA_BITSTREAM_LF;
-       else if (!memcmp("HF", temp, 2))
-               return FPGA_BITSTREAM_HF;
-       return FPGA_BITSTREAM_ERR;
-}
 
-void FpgaGatherVersion(char *dst, int len)
+//-----------------------------------------------------------------------------
+// Gather version information from FPGA image. Needs to decompress the begin 
+// of the respective (HF or LF) image.
+// Note: decompression makes use of (i.e. overwrites) BigBuf[]. It is therefore
+// advisable to call this only once and store the results for later use.
+//-----------------------------------------------------------------------------
+void FpgaGatherVersion(int bitstream_version, 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 {
-               /* USB packets only have 48 bytes data payload, so be terse */
-               if(bitparse_find_section('a', &fpga_info, &fpga_info_len) && fpga_info[fpga_info_len-1] == 0 ) {
-                       if (!memcmp("fpga_lf", fpga_info, 7))
-                               strncat(dst, "LF ", len-1);
-                       else if (!memcmp("fpga_hf", fpga_info, 7))
-                               strncat(dst, "HF ", len-1);
+       char tempstr[40];
+       z_stream compressed_fpga_stream;
+       uint8_t output_buffer[OUTPUT_BUFFER_LEN];
+       
+       dst[0] = '\0';
+
+       // ensure that we can allocate enough memory for decompression:
+       BigBuf_free();
+
+       if (!reset_fpga_stream(bitstream_version, &compressed_fpga_stream, output_buffer)) {
+               return;
+       }
+
+       if(bitparse_find_section(bitstream_version, 'a', &fpga_info_len, &compressed_fpga_stream, output_buffer)) {
+               for (uint16_t i = 0; i < fpga_info_len; i++) {
+                       char c = (char)get_from_fpga_stream(bitstream_version, &compressed_fpga_stream, output_buffer);
+                       if (i < sizeof(tempstr)) {
+                               tempstr[i] = c;
+                       }
                }
-               strncat(dst, "FPGA image built", len-1);
-#if 0
-               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);
+               if (!memcmp("fpga_lf", tempstr, 7))
+                       strncat(dst, "LF ", len-1);
+               else if (!memcmp("fpga_hf", tempstr, 7))
+                       strncat(dst, "HF ", len-1);
+       }
+       strncat(dst, "FPGA image built", len-1);
+       if(bitparse_find_section(bitstream_version, 'b', &fpga_info_len, &compressed_fpga_stream, output_buffer)) {
+               strncat(dst, " for ", len-1);
+               for (uint16_t i = 0; i < fpga_info_len; i++) {
+                       char c = (char)get_from_fpga_stream(bitstream_version, &compressed_fpga_stream, output_buffer);
+                       if (i < sizeof(tempstr)) {
+                               tempstr[i] = c;
+                       }
                }
-#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);
+               strncat(dst, tempstr, len-1);
+       }
+       if(bitparse_find_section(bitstream_version, 'c', &fpga_info_len, &compressed_fpga_stream, output_buffer)) {
+               strncat(dst, " on ", len-1);
+               for (uint16_t i = 0; i < fpga_info_len; i++) {
+                       char c = (char)get_from_fpga_stream(bitstream_version, &compressed_fpga_stream, output_buffer);
+                       if (i < sizeof(tempstr)) {
+                               tempstr[i] = c;
+                       }
                }
-               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);
+               strncat(dst, tempstr, len-1);
+       }
+       if(bitparse_find_section(bitstream_version, 'd', &fpga_info_len, &compressed_fpga_stream, output_buffer)) {
+               strncat(dst, " at ", len-1);
+               for (uint16_t i = 0; i < fpga_info_len; i++) {
+                       char c = (char)get_from_fpga_stream(bitstream_version, &compressed_fpga_stream, output_buffer);
+                       if (i < sizeof(tempstr)) {
+                               tempstr[i] = c;
+                       }
                }
+               strncat(dst, tempstr, len-1);
        }
+       
+       strncat(dst, "\n", len-1);
+
+       inflateEnd(&compressed_fpga_stream);
 }
 
+
 //-----------------------------------------------------------------------------
 // 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
diff --git a/armsrc/fpgaloader.h b/armsrc/fpgaloader.h
new file mode 100644 (file)
index 0000000..0bad380
--- /dev/null
@@ -0,0 +1,71 @@
+//-----------------------------------------------------------------------------
+// Jonathan Westhues, April 2006
+// iZsh <izsh at fail0verflow.com>, 2014
+//
+// This code is licensed to you under the terms of the GNU GPL, version 2 or,
+// at your option, any later version. See the LICENSE.txt file for the text of
+// the license.
+//-----------------------------------------------------------------------------
+// Routines to load the FPGA image, and then to configure the FPGA's major
+// mode once it is configured.
+//-----------------------------------------------------------------------------
+
+void FpgaSendCommand(uint16_t cmd, uint16_t v);
+void FpgaWriteConfWord(uint8_t v);
+void FpgaDownloadAndGo(int bitstream_version);
+void FpgaGatherVersion(int bitstream_version, char *dst, int len);
+void FpgaSetupSsc(void);
+void SetupSpi(int mode);
+bool FpgaSetupSscDma(uint8_t *buf, int len);
+#define FpgaDisableSscDma(void)        AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS;
+#define FpgaEnableSscDma(void) AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTEN;
+void SetAdcMuxFor(uint32_t whichGpio);
+
+// definitions for multiple FPGA config files support
+#define FPGA_BITSTREAM_MAX 2   // the total number of FPGA bitstreams (configs)
+#define FPGA_BITSTREAM_ERR 0
+#define FPGA_BITSTREAM_LF 1
+#define FPGA_BITSTREAM_HF 2
+
+
+// Definitions for the FPGA commands.
+#define FPGA_CMD_SET_CONFREG                                           (1<<12)
+#define FPGA_CMD_SET_DIVISOR                                           (2<<12)
+#define FPGA_CMD_SET_USER_BYTE1                                                (3<<12)
+// Definitions for the FPGA configuration word.
+// LF
+#define FPGA_MAJOR_MODE_LF_ADC                                         (0<<5)
+#define FPGA_MAJOR_MODE_LF_EDGE_DETECT                         (1<<5)
+#define FPGA_MAJOR_MODE_LF_PASSTHRU                                    (2<<5)
+// HF
+#define FPGA_MAJOR_MODE_HF_READER_TX                           (0<<5)
+#define FPGA_MAJOR_MODE_HF_READER_RX_XCORR                     (1<<5)
+#define FPGA_MAJOR_MODE_HF_SIMULATOR                           (2<<5)
+#define FPGA_MAJOR_MODE_HF_ISO14443A                           (3<<5)
+// BOTH
+#define FPGA_MAJOR_MODE_OFF                                                    (7<<5)
+// Options for LF_ADC
+#define FPGA_LF_ADC_READER_FIELD                                       (1<<0)
+// Options for LF_EDGE_DETECT
+#define FPGA_CMD_SET_EDGE_DETECT_THRESHOLD                     FPGA_CMD_SET_USER_BYTE1
+#define FPGA_LF_EDGE_DETECT_READER_FIELD                       (1<<0)
+#define FPGA_LF_EDGE_DETECT_TOGGLE_MODE                                (1<<1)
+// 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)
+#define FPGA_HF_SIMULATOR_MODULATE_424K                                (4<<0)
+#define FPGA_HF_SIMULATOR_MODULATE_424K_8BIT           0x5//101
+
+// 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)
diff --git a/armsrc/iso14443.c b/armsrc/iso14443.c
deleted file mode 100644 (file)
index c7f49f1..0000000
+++ /dev/null
@@ -1,1250 +0,0 @@
-//-----------------------------------------------------------------------------
-// Jonathan Westhues, split Nov 2006
-//
-// This code is licensed to you under the terms of the GNU GPL, version 2 or,
-// at your option, any later version. See the LICENSE.txt file for the text of
-// the license.
-//-----------------------------------------------------------------------------
-// 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.
-//-----------------------------------------------------------------------------
-
-#include "proxmark3.h"
-#include "apps.h"
-#include "util.h"
-#include "string.h"
-
-#include "iso14443crc.h"
-
-//static void GetSamplesFor14443(int weTx, int n);
-
-/*#define DEMOD_TRACE_SIZE 4096
-#define READER_TAG_BUFFER_SIZE 2048
-#define TAG_READER_BUFFER_SIZE 2048
-#define DEMOD_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 uint8_t *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;
-               uint8_t 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;
-       uint16_t    shiftReg;
-       int     bitCnt;
-       int     byteCnt;
-       int     byteCntMax;
-       int     posCnt;
-       uint8_t   *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 int 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;
-       }
-
-       // This row make the error blew circular buffer in hf 14b snoop
-       //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 int GetIso14443CommandFromReader(uint8_t *received, int *len, int maxLen)
-{
-       uint8_t 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)) {
-                       uint8_t b = (uint8_t)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 uint8_t cmd1[] = { 0x05, 0x00, 0x08, 0x39, 0x73 };
-       static const uint8_t response1[] = {
-               0x50, 0x82, 0x0d, 0xe1, 0x74, 0x20, 0x38, 0x19, 0x22,
-               0x00, 0x21, 0x85, 0x5e, 0xd7
-       };
-
-       uint8_t *resp;
-       int respLen;
-
-       uint8_t *resp1 = BigBuf_get_addr() + 800;
-       int resp1Len;
-
-       uint8_t *receivedCmd = BigBuf_get_addr();
-       int len;
-
-       int i;
-
-       int cmdsRecvd = 0;
-
-       FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
-       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(;;) {
-               uint8_t 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)) {
-                               uint8_t b = resp[i];
-
-                               AT91C_BASE_SSC->SSC_THR = b;
-
-                               i++;
-                               if(i > respLen) {
-                                       break;
-                               }
-                       }
-                       if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
-                               volatile uint8_t b = (uint8_t)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;
-       uint16_t    shiftReg;
-       uint8_t   *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 RAMFUNC int 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) {
-                                       uint16_t s = Demod.shiftReg;
-                                       if((s & 0x200) && !(s & 0x001)) {
-                                               uint8_t 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();
-                                               Demod.state = DEMOD_UNSYNCD;
-                                               return TRUE;
-                                       } 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;
-}
-static void DemodReset()
-{
-       // Clear out the state of the "UART" that receives from the tag.
-       Demod.len = 0;
-       Demod.state = DEMOD_UNSYNCD;
-       memset(Demod.output, 0x00, MAX_FRAME_SIZE);
-}
-static void DemodInit(uint8_t *data)
-{
-       Demod.output = data;
-       DemodReset();
-}
-
-static void UartReset()
-{
-       Uart.byteCntMax = MAX_FRAME_SIZE;
-       Uart.state = STATE_UNSYNCD;
-       Uart.byteCnt = 0;
-       Uart.bitCnt = 0;
-}
-static void UartInit(uint8_t *data)
-{
-       Uart.output = data;
-       UartReset();
-}
-
-/*
- *  Demodulate the samples we received from the tag, also log to tracebuffer
- *  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(int weTx, int n, int quiet)
-{
-       int max = 0;
-       int gotFrame = FALSE;
-       int lastRxCounter, ci, cq, samples = 0;
-
-       // Allocate memory from BigBuf for some buffers
-       // free all previous allocations first
-       BigBuf_free();
-       
-       // The command (reader -> tag) that we're receiving.
-       uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE);
-       
-       // The response (tag -> reader) that we're receiving.
-       uint8_t *receivedResponse = BigBuf_malloc(MAX_FRAME_SIZE);
-       
-       // The DMA buffer, used to stream samples from the FPGA
-       uint8_t *dmaBuf = BigBuf_malloc(DMA_BUFFER_SIZE);
-
-       // Set up the demodulator for tag -> reader responses.
-       DemodInit(receivedResponse);
-       // Set up the demodulator for the reader -> tag commands
-       UartInit(receivedCmd);
-
-       // Setup and start DMA.
-       FpgaSetupSscDma(dmaBuf, DMA_BUFFER_SIZE);
-
-       uint8_t *upTo= dmaBuf;
-       lastRxCounter = 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 = (uint32_t) 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);
-       //Tracing
-       if (tracing && Demod.len > 0) {
-               uint8_t parity[MAX_PARITY_SIZE];
-               GetParity(Demod.output , Demod.len, parity);
-               LogTrace(Demod.output,Demod.len, 0, 0, parity, FALSE);
-       }
-}
-
-//-----------------------------------------------------------------------------
-// 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(int weTx, int n)
-{
-       uint8_t *dest = (uint8_t *)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)) {
-                       int8_t b;
-                       b = (int8_t)AT91C_BASE_SSC->SSC_RHR;
-
-                       dest[c++] = (uint8_t)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 uint32_t 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 uint32_t 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().
-//-----------------------------------------------------------------------------
-static void CodeIso14443bAsReader(const uint8_t *cmd, int len)
-{
-       int i, j;
-       uint8_t 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)
-//
-// obsolete function only for test
-//-----------------------------------------------------------------------------
-void AcquireRawAdcSamplesIso14443(uint32_t parameter)
-{
-       uint8_t cmd1[] = { 0x05, 0x00, 0x08, 0x39, 0x73 };
-
-       SendRawCommand14443B(sizeof(cmd1),1,1,cmd1);
-}
-
-/**
-  Convenience function to encode, transmit and trace iso 14443b comms
-  **/
-static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len)
-{
-       CodeIso14443bAsReader(cmd, len);
-       TransmitFor14443();
-       if (tracing) {
-               uint8_t parity[MAX_PARITY_SIZE];
-               GetParity(cmd, len, parity);
-               LogTrace(cmd,len, 0, 0, parity, TRUE);
-       }
-}
-
-//-----------------------------------------------------------------------------
-// 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 ReadSTMemoryIso14443(uint32_t dwLast)
-{
-       clear_trace();
-       set_tracing(TRUE);
-
-       uint8_t i = 0x00;
-
-       FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
-       // 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
-       uint8_t cmd1[] = { 0x06, 0x00, 0x97, 0x5b};
-
-       CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1));
-//    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]);
-       CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1));
-
-//    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]);
-       CodeAndTransmit14443bAsReader(cmd1, 3); // Only first three bytes for this one
-
-//    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 last block
-       Dbprintf("Tag memory dump, block 0 to %d",dwLast);
-       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]);
-               CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1));
-
-//         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) - DEMOD_DMA_BUFFER_SIZE
- */
-void RAMFUNC 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.
-       int triggered = TRUE;
-
-       FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
-       BigBuf_free();
-
-       clear_trace();
-       set_tracing(TRUE);
-
-       // The DMA buffer, used to stream samples from the FPGA
-       uint8_t *dmaBuf = BigBuf_malloc(DMA_BUFFER_SIZE);
-       int lastRxCounter;
-       uint8_t *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;
-
-       DemodInit(BigBuf_malloc(MAX_FRAME_SIZE));
-       UartInit(BigBuf_malloc(MAX_FRAME_SIZE));
-
-       // Print some debug information about the buffer sizes
-       Dbprintf("Snooping buffers initialized:");
-       Dbprintf("  Trace: %i bytes", BigBuf_max_traceLen());
-       Dbprintf("  Reader -> tag: %i bytes", MAX_FRAME_SIZE);
-       Dbprintf("  tag -> Reader: %i bytes", MAX_FRAME_SIZE);
-       Dbprintf("  DMA: %i bytes", DMA_BUFFER_SIZE);
-
-       // Signal field is off with the appropriate LED
-       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 |
-               FPGA_HF_READER_RX_XCORR_SNOOP);
-       SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
-
-       // Setup for the DMA.
-       FpgaSetupSsc();
-       upTo = dmaBuf;
-       lastRxCounter = DMA_BUFFER_SIZE;
-       FpgaSetupSscDma((uint8_t *)dmaBuf, DMA_BUFFER_SIZE);
-       uint8_t parity[MAX_PARITY_SIZE];
-       LED_A_ON();
-               
-       // And now we loop, receiving samples.
-       for(;;) {
-               int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) &
-                                                               (DMA_BUFFER_SIZE-1);
-               if(behindBy > maxBehindBy) {
-                       maxBehindBy = behindBy;
-                       if(behindBy > (9*DMA_BUFFER_SIZE/10)) { // TODO: understand whether we can increase/decrease as we want or not?
-                               Dbprintf("blew circular buffer! behindBy=0x%x", behindBy);
-                               break;
-                       }
-               }
-               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 = (uint32_t) upTo;
-                       AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE;
-               }
-
-               samples += 2;
-
-               if(Handle14443UartBit(ci & 1)) {
-                       if(triggered && tracing) {
-                               GetParity(Uart.output, Uart.byteCnt, parity);
-                               LogTrace(Uart.output,Uart.byteCnt,samples, samples,parity,TRUE);
-                       }
-                       if(Uart.byteCnt==0) Dbprintf("[1] Error, Uart.byteCnt==0, Uart.bitCnt=%d", Uart.bitCnt);
-
-                       /* And ready to receive another command. */
-                       UartReset();
-                       /* And also reset the demod code, which might have been */
-                       /* false-triggered by the commands from the reader. */
-                       DemodReset();
-               }
-               if(Handle14443UartBit(cq & 1)) {
-                       if(triggered && tracing) {
-                               GetParity(Uart.output, Uart.byteCnt, parity);
-                               LogTrace(Uart.output,Uart.byteCnt,samples, samples,parity,TRUE);
-                       }
-                       if(Uart.byteCnt==0) Dbprintf("[2] Error, Uart.byteCnt==0, Uart.bitCnt=%d", Uart.bitCnt);
-
-                       /* And ready to receive another command. */
-                       UartReset();
-                       /* And also reset the demod code, which might have been */
-                       /* false-triggered by the commands from the reader. */
-                       DemodReset();
-               }
-
-               if(Handle14443SamplesDemod(ci, cq)) {
-
-                       //Use samples as a time measurement
-                       if(tracing)
-                       {
-                               uint8_t parity[MAX_PARITY_SIZE];
-                               GetParity(Demod.output, Demod.len, parity);
-                               LogTrace(Demod.output,Demod.len,samples, samples,parity,FALSE);
-                       }
-                       triggered = TRUE;
-                       LED_A_OFF();
-                       LED_B_ON();
-
-                       // And ready to receive another response.
-                       DemodReset();
-               }
-               WDT_HIT();
-
-               if(!tracing) {
-                       DbpString("Reached trace limit");
-                       break;
-               }
-
-               if(BUTTON_PRESS()) {
-                       DbpString("cancelled");
-                       break;
-               }
-       }
-       FpgaDisableSscDma();
-       LED_A_OFF();
-       LED_B_OFF();
-       LED_C_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", BigBuf_get_traceLen());
-}
-
-/*
- * Send raw command to tag ISO14443B
- * @Input
- * datalen     len of buffer data
- * recv        bool when true wait for data from tag and send to client
- * powerfield  bool leave the field on when true
- * data        buffer with byte to send
- *
- * @Output
- * none
- *
- */
-
-void SendRawCommand14443B(uint32_t datalen, uint32_t recv,uint8_t powerfield, uint8_t data[])
-{
-       FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
-       if(!powerfield)
-       {
-               // 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);
-       }
-
-       if(!GETBIT(GPIO_LED_D))
-       {
-               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);
-       }
-
-       CodeAndTransmit14443bAsReader(data, datalen);
-
-       if(recv)
-       {
-               uint16_t iLen = MIN(Demod.len,USB_CMD_DATA_SIZE);
-               GetSamplesFor14443Demod(TRUE, 2000, TRUE);
-               cmd_send(CMD_ACK,iLen,0,0,Demod.output,iLen);
-       }
-       if(!powerfield)
-       {
-               FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
-               LED_D_OFF();
-       }
-}
-
diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c
new file mode 100644 (file)
index 0000000..416c31f
--- /dev/null
@@ -0,0 +1,1218 @@
+//-----------------------------------------------------------------------------
+// Jonathan Westhues, split Nov 2006
+//
+// This code is licensed to you under the terms of the GNU GPL, version 2 or,
+// at your option, any later version. See the LICENSE.txt file for the text of
+// the license.
+//-----------------------------------------------------------------------------
+// Routines to support ISO 14443B. This includes both the reader software and
+// the `fake tag' modes.
+//-----------------------------------------------------------------------------
+
+#include "proxmark3.h"
+#include "apps.h"
+#include "util.h"
+#include "string.h"
+
+#include "iso14443crc.h"
+
+#define RECEIVE_SAMPLES_TIMEOUT 2000
+#define ISO14443B_DMA_BUFFER_SIZE 256
+
+//=============================================================================
+// 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 uint8_t *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;
+               uint8_t 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 EOF.
+       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);
+       }
+
+       // Convert from last byte pos to length
+       ToSendMax++;
+}
+
+//-----------------------------------------------------------------------------
+// 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;
+       uint16_t    shiftReg;
+       int     bitCnt;
+       int     byteCnt;
+       int     byteCntMax;
+       int     posCnt;
+       uint8_t   *output;
+} Uart;
+
+/* Receive & handle a bit coming from the reader.
+ *
+ * This function is called 4 times per bit (every 2 subcarrier cycles).
+ * Subcarrier frequency fs is 848kHz, 1/fs = 1,18us, i.e. function is called every 2,36us
+ *
+ * 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 RAMFUNC int Handle14443bUartBit(uint8_t bit)
+{
+       switch(Uart.state) {
+               case STATE_UNSYNCD:
+                       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) {  // sample every 4 1/fs in the middle of a bit
+                               if(bit) {
+                                       if(Uart.bitCnt > 9) {
+                                               // 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_UNSYNCD;
+                                       }
+                               } else {
+                                       // do nothing, keep waiting
+                               }
+                               Uart.bitCnt++;
+                       }
+                       if(Uart.posCnt >= 4) Uart.posCnt = 0;
+                       if(Uart.bitCnt > 12) {
+                               // Give up if we see too many zeros without
+                               // a one, too.
+                               LED_A_OFF();
+                               Uart.state = STATE_UNSYNCD;
+                       }
+                       break;
+
+               case STATE_AWAITING_START_BIT:
+                       Uart.posCnt++;
+                       if(bit) {
+                               if(Uart.posCnt > 50/2) {        // max 57us between characters = 49 1/fs, max 3 etus after low phase of SOF = 24 1/fs
+                                       // stayed high for too long between
+                                       // characters, error
+                                       Uart.state = STATE_UNSYNCD;
+                               }
+                       } else {
+                               // falling edge, this starts the data byte
+                               Uart.posCnt = 0;
+                               Uart.bitCnt = 0;
+                               Uart.shiftReg = 0;
+                               Uart.state = STATE_RECEIVING_DATA;
+                       }
+                       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
+                                               LED_A_OFF();
+                                               Uart.state = STATE_UNSYNCD;
+                                       } 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
+                                       Uart.state = STATE_UNSYNCD;
+                                       if (Uart.byteCnt != 0) {
+                                               return TRUE;
+                                       }
+                               } else {
+                                       // this is an error
+                                       LED_A_OFF();
+                                       Uart.state = STATE_UNSYNCD;
+                               }
+                       }
+                       break;
+
+               default:
+                       LED_A_OFF();
+                       Uart.state = STATE_UNSYNCD;
+                       break;
+       }
+
+       return FALSE;
+}
+
+
+static void UartReset()
+{
+       Uart.byteCntMax = MAX_FRAME_SIZE;
+       Uart.state = STATE_UNSYNCD;
+       Uart.byteCnt = 0;
+       Uart.bitCnt = 0;
+}
+
+
+static void UartInit(uint8_t *data)
+{
+       Uart.output = data;
+       UartReset();
+}
+
+
+//-----------------------------------------------------------------------------
+// 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 int GetIso14443bCommandFromReader(uint8_t *received, uint16_t *len)
+{
+       // Set FPGA mode to "simulated ISO 14443B 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.
+       UartInit(received);
+
+       for(;;) {
+               WDT_HIT();
+
+               if(BUTTON_PRESS()) return FALSE;
+
+               if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
+                       uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
+                       for(uint8_t mask = 0x80; mask != 0x00; mask >>= 1) {
+                               if(Handle14443bUartBit(b & mask)) {
+                                       *len = Uart.byteCnt;
+                                       return TRUE;
+                               }
+                       }
+               }
+       }
+       
+       return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// Main loop of simulated tag: receive commands from reader, decide what
+// response to send, and send it.
+//-----------------------------------------------------------------------------
+void SimulateIso14443bTag(void)
+{
+       // the only commands we understand is REQB, AFI=0, Select All, N=0:
+       static const uint8_t cmd1[] = { 0x05, 0x00, 0x08, 0x39, 0x73 };
+       // ... and REQB, AFI=0, Normal Request, N=0:
+       static const uint8_t cmd2[] = { 0x05, 0x00, 0x00, 0x71, 0xFF };
+
+       // ... and we always respond with ATQB, PUPI = 820de174, Application Data = 0x20381922,
+       // supports only 106kBit/s in both directions, max frame size = 32Bytes,
+       // supports ISO14443-4, FWI=8 (77ms), NAD supported, CID not supported:
+       static const uint8_t response1[] = {
+               0x50, 0x82, 0x0d, 0xe1, 0x74, 0x20, 0x38, 0x19, 0x22,
+               0x00, 0x21, 0x85, 0x5e, 0xd7
+       };
+
+       clear_trace();
+       set_tracing(TRUE);
+
+       const uint8_t *resp;
+       uint8_t *respCode;
+       uint16_t respLen, respCodeLen;
+
+       // allocate command receive buffer
+       BigBuf_free();
+       uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE);
+
+       uint16_t len;
+       uint16_t cmdsRecvd = 0;
+
+       FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
+
+       // prepare the (only one) tag answer:
+       CodeIso14443bAsTag(response1, sizeof(response1));
+       uint8_t *resp1Code = BigBuf_malloc(ToSendMax);
+       memcpy(resp1Code, ToSend, ToSendMax); 
+       uint16_t resp1CodeLen = ToSendMax;
+
+       // We need to listen to the high-frequency, peak-detected path.
+       SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
+       FpgaSetupSsc();
+
+       cmdsRecvd = 0;
+
+       for(;;) {
+
+               if(!GetIso14443bCommandFromReader(receivedCmd, &len)) {
+                       Dbprintf("button pressed, received %d commands", cmdsRecvd);
+                       break;
+               }
+
+               if (tracing) {
+                       uint8_t parity[MAX_PARITY_SIZE];
+                       LogTrace(receivedCmd, len, 0, 0, parity, TRUE);
+               }
+
+               // Good, look at the command now.
+               if ( (len == sizeof(cmd1) && memcmp(receivedCmd, cmd1, len) == 0)
+                       || (len == sizeof(cmd2) && memcmp(receivedCmd, cmd2, len) == 0) ) {
+                       resp = response1; 
+                       respLen = sizeof(response1);
+                       respCode = resp1Code; 
+                       respCodeLen = resp1CodeLen;
+               } else {
+                       Dbprintf("new cmd from reader: len=%d, cmdsRecvd=%d", len, cmdsRecvd);
+                       // And print whether the CRC fails, just for good measure
+                       uint8_t b1, b2;
+                       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;
+               }
+
+               cmdsRecvd++;
+
+               if(cmdsRecvd > 0x30) {
+                       DbpString("many commands later...");
+                       break;
+               }
+
+               if(respCodeLen <= 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.
+               uint16_t i = 0;
+               for(;;) {
+                       if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
+                               uint8_t b = respCode[i];
+
+                               AT91C_BASE_SSC->SSC_THR = b;
+
+                               i++;
+                               if(i > respCodeLen) {
+                                       break;
+                               }
+                       }
+                       if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
+                               volatile uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
+                               (void)b;
+                       }
+               }
+               
+               // trace the response:
+               if (tracing) {
+                       uint8_t parity[MAX_PARITY_SIZE];
+                       LogTrace(resp, respLen, 0, 0, parity, FALSE);
+               }
+                       
+       }
+}
+
+//=============================================================================
+// 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
+       }       state;
+       int     bitCount;
+       int     posCount;
+       int     thisBit;
+/* this had been used to add RSSI (Received Signal Strength Indication) to traces. Currently not implemented.
+       int     metric;
+       int     metricN;
+*/
+       uint16_t    shiftReg;
+       uint8_t   *output;
+       int     len;
+       int     sumI;
+       int     sumQ;
+} Demod;
+
+/*
+ * Handles reception of a bit from the tag
+ *
+ * This function is called 2 times per bit (every 4 subcarrier cycles).
+ * Subcarrier frequency fs is 848kHz, 1/fs = 1,18us, i.e. function is called every 4,72us
+ *
+ * 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 RAMFUNC int Handle14443bSamplesDemod(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; \
+               } \
+       }
+
+#define SUBCARRIER_DETECT_THRESHOLD    8
+
+// Subcarrier amplitude v = sqrt(ci^2 + cq^2), approximated here by abs(ci) + abs(cq)
+/* #define CHECK_FOR_SUBCARRIER() { \
+               v = ci; \
+               if(v < 0) v = -v; \
+               if(cq > 0) { \
+                       v += cq; \
+               } else { \
+                       v -= cq; \
+               } \
+       }               
+ */
+// Subcarrier amplitude v = sqrt(ci^2 + cq^2), approximated here by max(abs(ci),abs(cq)) + 1/2*min(abs(ci),abs(cq)))
+#define CHECK_FOR_SUBCARRIER() { \
+               if(ci < 0) { \
+                       if(cq < 0) { /* ci < 0, cq < 0 */ \
+                               if (cq < ci) { \
+                                       v = -cq - (ci >> 1); \
+                               } else { \
+                                       v = -ci - (cq >> 1); \
+                               } \
+                       } else {        /* ci < 0, cq >= 0 */ \
+                               if (cq < -ci) { \
+                                       v = -ci + (cq >> 1); \
+                               } else { \
+                                       v = cq - (ci >> 1); \
+                               } \
+                       } \
+               } else { \
+                       if(cq < 0) { /* ci >= 0, cq < 0 */ \
+                               if (-cq < ci) { \
+                                       v = ci - (cq >> 1); \
+                               } else { \
+                                       v = -cq + (ci >> 1); \
+                               } \
+                       } else {        /* ci >= 0, cq >= 0 */ \
+                               if (cq < ci) { \
+                                       v = ci + (cq >> 1); \
+                               } else { \
+                                       v = cq + (ci >> 1); \
+                               } \
+                       } \
+               } \
+       }
+       
+       switch(Demod.state) {
+               case DEMOD_UNSYNCD:
+                       CHECK_FOR_SUBCARRIER();
+                       if(v > SUBCARRIER_DETECT_THRESHOLD) {   // subcarrier detected
+                               Demod.state = DEMOD_PHASE_REF_TRAINING;
+                               Demod.sumI = ci;
+                               Demod.sumQ = cq;
+                               Demod.posCount = 1;
+                               }
+                       break;
+
+               case DEMOD_PHASE_REF_TRAINING:
+                       if(Demod.posCount < 8) {
+                               CHECK_FOR_SUBCARRIER();
+                               if (v > SUBCARRIER_DETECT_THRESHOLD) {
+                                       // set the reference phase (will code a logic '1') by averaging over 32 1/fs.
+                                       // note: synchronization time > 80 1/fs
+                                       Demod.sumI += ci;
+                                       Demod.sumQ += cq;
+                                       Demod.posCount++;
+                               } else {                // subcarrier lost
+                                       Demod.state = DEMOD_UNSYNCD;
+                               }
+                       } else {
+                               Demod.state = DEMOD_AWAITING_FALLING_EDGE_OF_SOF;
+                       }
+                       break;
+
+               case DEMOD_AWAITING_FALLING_EDGE_OF_SOF:
+                       MAKE_SOFT_DECISION();
+                       if(v < 0) {     // logic '0' detected
+                               Demod.state = DEMOD_GOT_FALLING_EDGE_OF_SOF;
+                               Demod.posCount = 0;     // start of SOF sequence
+                       } else {
+                               if(Demod.posCount > 200/4) {    // maximum length of TR1 = 200 1/fs
+                                       Demod.state = DEMOD_UNSYNCD;
+                               }
+                       }
+                       Demod.posCount++;
+                       break;
+
+               case DEMOD_GOT_FALLING_EDGE_OF_SOF:
+                       Demod.posCount++;
+                       MAKE_SOFT_DECISION();
+                       if(v > 0) {
+                               if(Demod.posCount < 9*2) { // low phase of SOF too short (< 9 etu). Note: spec is >= 10, but FPGA tends to "smear" edges
+                                       Demod.state = DEMOD_UNSYNCD;
+                               } else {
+                                       LED_C_ON(); // Got SOF
+                                       Demod.state = DEMOD_AWAITING_START_BIT;
+                                       Demod.posCount = 0;
+                                       Demod.len = 0;
+/* this had been used to add RSSI (Received Signal Strength Indication) to traces. Currently not implemented.
+                                       Demod.metricN = 0;
+                                       Demod.metric = 0;
+*/
+                               }
+                       } else {
+                               if(Demod.posCount > 12*2) { // low phase of SOF too long (> 12 etu)
+                                       Demod.state = DEMOD_UNSYNCD;
+                                       LED_C_OFF();
+                               }
+                       }
+                       break;
+
+               case DEMOD_AWAITING_START_BIT:
+                       Demod.posCount++;
+                       MAKE_SOFT_DECISION();
+                       if(v > 0) {
+                               if(Demod.posCount > 3*2) {              // max 19us between characters = 16 1/fs, max 3 etu after low phase of SOF = 24 1/fs
+                                       Demod.state = DEMOD_UNSYNCD;
+                                       LED_C_OFF();
+                               }
+                       } else {                                                        // start bit detected
+                               Demod.bitCount = 0;
+                               Demod.posCount = 1;                             // this was the first half
+                               Demod.thisBit = v;
+                               Demod.shiftReg = 0;
+                               Demod.state = DEMOD_RECEIVING_DATA;
+                       }
+                       break;
+
+               case DEMOD_RECEIVING_DATA:
+                       MAKE_SOFT_DECISION();
+                       if(Demod.posCount == 0) {                       // first half of bit
+                               Demod.thisBit = v;
+                               Demod.posCount = 1;
+                       } else {                                                        // second half of bit
+                               Demod.thisBit += v;
+
+/* this had been used to add RSSI (Received Signal Strength Indication) to traces. Currently not implemented.
+                               if(Demod.thisBit > 0) {
+                                       Demod.metric += Demod.thisBit;
+                               } else {
+                                       Demod.metric -= Demod.thisBit;
+                               }
+                               (Demod.metricN)++;
+*/                             
+
+                               Demod.shiftReg >>= 1;
+                               if(Demod.thisBit > 0) { // logic '1'
+                                       Demod.shiftReg |= 0x200;
+                               }
+
+                               Demod.bitCount++;
+                               if(Demod.bitCount == 10) {
+                                       uint16_t s = Demod.shiftReg;
+                                       if((s & 0x200) && !(s & 0x001)) { // stop bit == '1', start bit == '0'
+                                               uint8_t b = (s >> 1);
+                                               Demod.output[Demod.len] = b;
+                                               Demod.len++;
+                                               Demod.state = DEMOD_AWAITING_START_BIT;
+                                       } else {
+                                               Demod.state = DEMOD_UNSYNCD;
+                                               LED_C_OFF();
+                                               if(s == 0x000) {
+                                                       // This is EOF (start, stop and all data bits == '0'
+                                                       return TRUE;
+                                               }
+                                       }
+                               }
+                               Demod.posCount = 0;
+                       }
+                       break;
+
+               default:
+                       Demod.state = DEMOD_UNSYNCD;
+                       LED_C_OFF();
+                       break;
+       }
+
+       return FALSE;
+}
+
+
+static void DemodReset()
+{
+       // Clear out the state of the "UART" that receives from the tag.
+       Demod.len = 0;
+       Demod.state = DEMOD_UNSYNCD;
+       Demod.posCount = 0;
+       memset(Demod.output, 0x00, MAX_FRAME_SIZE);
+}
+
+
+static void DemodInit(uint8_t *data)
+{
+       Demod.output = data;
+       DemodReset();
+}
+
+
+/*
+ *  Demodulate the samples we received from the tag, also log to tracebuffer
+ *  quiet: set to 'TRUE' to disable debug output
+ */
+static void GetSamplesFor14443bDemod(int n, bool quiet)
+{
+       int max = 0;
+       bool gotFrame = FALSE;
+       int lastRxCounter, ci, cq, samples = 0;
+
+       // Allocate memory from BigBuf for some buffers
+       // free all previous allocations first
+       BigBuf_free();
+       
+       // The response (tag -> reader) that we're receiving.
+       uint8_t *receivedResponse = BigBuf_malloc(MAX_FRAME_SIZE);
+       
+       // The DMA buffer, used to stream samples from the FPGA
+       int8_t *dmaBuf = (int8_t*) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE);
+
+       // Set up the demodulator for tag -> reader responses.
+       DemodInit(receivedResponse);
+
+       // Setup and start DMA.
+       FpgaSetupSscDma((uint8_t*) dmaBuf, ISO14443B_DMA_BUFFER_SIZE);
+
+       int8_t *upTo = dmaBuf;
+       lastRxCounter = ISO14443B_DMA_BUFFER_SIZE;
+
+       // Signal field is ON with the appropriate LED:
+       LED_D_ON();
+       // And put the FPGA in the appropriate mode
+       FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ);
+
+       for(;;) {
+               int behindBy = lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR;
+               if(behindBy > max) max = behindBy;
+
+               while(((lastRxCounter-AT91C_BASE_PDC_SSC->PDC_RCR) & (ISO14443B_DMA_BUFFER_SIZE-1)) > 2) {
+                       ci = upTo[0];
+                       cq = upTo[1];
+                       upTo += 2;
+                       if(upTo >= dmaBuf + ISO14443B_DMA_BUFFER_SIZE) {
+                               upTo = dmaBuf;
+                               AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) upTo;
+                               AT91C_BASE_PDC_SSC->PDC_RNCR = ISO14443B_DMA_BUFFER_SIZE;
+                       }
+                       lastRxCounter -= 2;
+                       if(lastRxCounter <= 0) {
+                               lastRxCounter += ISO14443B_DMA_BUFFER_SIZE;
+                       }
+
+                       samples += 2;
+
+                       if(Handle14443bSamplesDemod(ci, cq)) {
+                               gotFrame = TRUE;
+                               break;
+                       }
+               }
+
+               if(samples > n || gotFrame) {
+                       break;
+               }
+       }
+
+       AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS;
+
+       if (!quiet) Dbprintf("max behindby = %d, samples = %d, gotFrame = %d, Demod.len = %d, Demod.sumI = %d, Demod.sumQ = %d", max, samples, gotFrame, Demod.len, Demod.sumI, Demod.sumQ);
+       //Tracing
+       if (tracing && Demod.len > 0) {
+               uint8_t parity[MAX_PARITY_SIZE];
+               LogTrace(Demod.output, Demod.len, 0, 0, parity, FALSE);
+       }
+}
+
+
+//-----------------------------------------------------------------------------
+// Transmit the command (to the tag) that was placed in ToSend[].
+//-----------------------------------------------------------------------------
+static void TransmitFor14443b(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 uint32_t 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 uint32_t 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 TransmitFor14443b().
+//-----------------------------------------------------------------------------
+static void CodeIso14443bAsReader(const uint8_t *cmd, int len)
+{
+       int i, j;
+       uint8_t 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++;
+}
+
+
+/**
+  Convenience function to encode, transmit and trace iso 14443b comms
+  **/
+static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len)
+{
+       CodeIso14443bAsReader(cmd, len);
+       TransmitFor14443b();
+       if (tracing) {
+               uint8_t parity[MAX_PARITY_SIZE];
+               LogTrace(cmd,len, 0, 0, parity, TRUE);
+       }
+}
+
+
+//-----------------------------------------------------------------------------
+// Read a SRI512 ISO 14443B 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 ReadSTMemoryIso14443b(uint32_t dwLast)
+{
+       clear_trace();
+       set_tracing(TRUE);
+
+       uint8_t i = 0x00;
+
+       FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
+       // 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
+       uint8_t cmd1[] = {0x06, 0x00, 0x97, 0x5b};
+       CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1));
+       GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, TRUE);
+
+       if (Demod.len == 0) {
+               DbpString("No response from tag");
+               return;
+       } else {
+               Dbprintf("Randomly generated Chip ID (+ 2 byte CRC): %02x %02x %02x",
+                               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]);
+       CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1));
+       GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, TRUE);
+       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: %02x %02x", 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]);
+       CodeAndTransmit14443bAsReader(cmd1, 3); // Only first three bytes for this one
+       GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, TRUE);
+       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! Expected: %04x got: %04x",
+                               (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 last block
+       Dbprintf("Tag memory dump, block 0 to %d", dwLast);
+       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]);
+               CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1));
+               GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, TRUE);
+               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! Expected: %04x got: %04x",
+                                       (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=%02x, Contents=%08x, CRC=%04x", 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)
+ * Last Received command (reader->tag) - MAX_FRAME_SIZE
+ * Last Received command (tag->reader) - MAX_FRAME_SIZE
+ * DMA Buffer - ISO14443B_DMA_BUFFER_SIZE
+ * Demodulated samples received - all the rest
+ */
+void RAMFUNC SnoopIso14443b(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.
+       int triggered = TRUE;                   // TODO: set and evaluate trigger condition
+
+       FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
+       BigBuf_free();
+
+       clear_trace();
+       set_tracing(TRUE);
+
+       // The DMA buffer, used to stream samples from the FPGA
+       int8_t *dmaBuf = (int8_t*) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE);
+       int lastRxCounter;
+       int8_t *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;
+
+       DemodInit(BigBuf_malloc(MAX_FRAME_SIZE));
+       UartInit(BigBuf_malloc(MAX_FRAME_SIZE));
+
+       // Print some debug information about the buffer sizes
+       Dbprintf("Snooping buffers initialized:");
+       Dbprintf("  Trace: %i bytes", BigBuf_max_traceLen());
+       Dbprintf("  Reader -> tag: %i bytes", MAX_FRAME_SIZE);
+       Dbprintf("  tag -> Reader: %i bytes", MAX_FRAME_SIZE);
+       Dbprintf("  DMA: %i bytes", ISO14443B_DMA_BUFFER_SIZE);
+
+       // Signal field is off, no reader signal, no tag signal
+       LEDsoff();
+
+       // And put the FPGA in the appropriate mode
+       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 = ISO14443B_DMA_BUFFER_SIZE;
+       FpgaSetupSscDma((uint8_t*) dmaBuf, ISO14443B_DMA_BUFFER_SIZE);
+       uint8_t parity[MAX_PARITY_SIZE];
+
+       bool TagIsActive = FALSE;
+       bool ReaderIsActive = FALSE;
+       
+       // And now we loop, receiving samples.
+       for(;;) {
+               int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) &
+                                                               (ISO14443B_DMA_BUFFER_SIZE-1);
+               if(behindBy > maxBehindBy) {
+                       maxBehindBy = behindBy;
+               }
+
+               if(behindBy < 2) continue;
+
+               ci = upTo[0];
+               cq = upTo[1];
+               upTo += 2;
+               lastRxCounter -= 2;
+               if(upTo >= dmaBuf + ISO14443B_DMA_BUFFER_SIZE) {
+                       upTo = dmaBuf;
+                       lastRxCounter += ISO14443B_DMA_BUFFER_SIZE;
+                       AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf;
+                       AT91C_BASE_PDC_SSC->PDC_RNCR = ISO14443B_DMA_BUFFER_SIZE;
+                       WDT_HIT();
+                       if(behindBy > (9*ISO14443B_DMA_BUFFER_SIZE/10)) { // TODO: understand whether we can increase/decrease as we want or not?
+                               Dbprintf("blew circular buffer! behindBy=%d", behindBy);
+                               break;
+                       }
+                       if(!tracing) {
+                               DbpString("Reached trace limit");
+                               break;
+                       }
+                       if(BUTTON_PRESS()) {
+                               DbpString("cancelled");
+                               break;
+                       }
+               }
+
+               samples += 2;
+
+               if (!TagIsActive) {                                                     // no need to try decoding reader data if the tag is sending
+                       if(Handle14443bUartBit(ci & 0x01)) {
+                               if(triggered && tracing) {
+                                       LogTrace(Uart.output, Uart.byteCnt, samples, samples, parity, TRUE);
+                               }
+                               /* And ready to receive another command. */
+                               UartReset();
+                               /* And also reset the demod code, which might have been */
+                               /* false-triggered by the commands from the reader. */
+                               DemodReset();
+                       }
+                       if(Handle14443bUartBit(cq & 0x01)) {
+                               if(triggered && tracing) {
+                                       LogTrace(Uart.output, Uart.byteCnt, samples, samples, parity, TRUE);
+                               }
+                               /* And ready to receive another command. */
+                               UartReset();
+                               /* And also reset the demod code, which might have been */
+                               /* false-triggered by the commands from the reader. */
+                               DemodReset();
+                       }
+                       ReaderIsActive = (Uart.state > STATE_GOT_FALLING_EDGE_OF_SOF);
+               }
+
+               if(!ReaderIsActive) {                                           // no need to try decoding tag data if the reader is sending - and we cannot afford the time
+                       if(Handle14443bSamplesDemod(ci | 0x01, cq | 0x01)) {
+
+                               //Use samples as a time measurement
+                               if(tracing)
+                               {
+                                       uint8_t parity[MAX_PARITY_SIZE];
+                                       LogTrace(Demod.output, Demod.len, samples, samples, parity, FALSE);
+                               }
+                               triggered = TRUE;
+
+                               // And ready to receive another response.
+                               DemodReset();
+                       }
+                       TagIsActive = (Demod.state > DEMOD_GOT_FALLING_EDGE_OF_SOF);
+               }
+
+       }
+
+       FpgaDisableSscDma();
+       LEDsoff();
+       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", BigBuf_get_traceLen());
+}
+
+
+/*
+ * Send raw command to tag ISO14443B
+ * @Input
+ * datalen     len of buffer data
+ * recv        bool when true wait for data from tag and send to client
+ * powerfield  bool leave the field on when true
+ * data        buffer with byte to send
+ *
+ * @Output
+ * none
+ *
+ */
+void SendRawCommand14443B(uint32_t datalen, uint32_t recv, uint8_t powerfield, uint8_t data[])
+{
+       FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
+       SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
+       FpgaSetupSsc();
+
+       set_tracing(TRUE);
+       
+       CodeAndTransmit14443bAsReader(data, datalen);
+
+       if(recv) {
+               GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, TRUE);
+               uint16_t iLen = MIN(Demod.len, USB_CMD_DATA_SIZE);
+               cmd_send(CMD_ACK, iLen, 0, 0, Demod.output, iLen);
+       }
+       
+       if(!powerfield) {
+               FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+               LED_D_OFF();
+       }
+}
+
index 840b819643dcb21e49b7fc4159f138706e142fb6..34da26bcdfd8cee58e6bfa99cb6bfb4c57eb59af 100644 (file)
@@ -24,6 +24,7 @@ SECTIONS
        } >osimage :text
 
        .text : {
+               KEEP(*(stage1_image))
                *(.text)
                *(.text.*)
                *(.eh_frame)
@@ -34,14 +35,13 @@ SECTIONS
        .rodata : {
                *(.rodata)
                *(.rodata.*)
-               *(fpga_lf_bit.data)
-               *(fpga_hf_bit.data)
+               *(fpga_all_bit.data)
                KEEP(*(.version_information))
+               . = ALIGN(8);
        } >osimage :text
 
-       . = ALIGN(4);
-
        .data : {
+               KEEP(*(compressed_data))
                *(.data)
                *(.data.*)
                *(.ramfunc)
@@ -51,6 +51,7 @@ SECTIONS
        __data_src_start__ = LOADADDR(.data);
        __data_start__ = ADDR(.data);
        __data_end__ = __data_start__ + SIZEOF(.data);
+       __os_size__ = SIZEOF(.text) + SIZEOF(.data) + SIZEOF(.rodata);
        
        .bss : {
                __bss_start__ = .; 
index c3fa8a0e630f2f743aaedd247b2d711c89610385..7e53d4a566173d97301f9e56ee1e5ad01a1ca15e 100644 (file)
@@ -1024,10 +1024,10 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol)
  * To compensate antenna falling times shorten the write times
  * and enlarge the gap ones.
  */
-#define START_GAP 50*8 // 10 - 50fc 250
-#define WRITE_GAP 20*8 //    - 30fc 160
-#define WRITE_0   24*8 // 16 - 63fc 54fc 144
-#define WRITE_1   54*8 // 48 - 63fc 54fc 432 for T55x7; 448 for E5550 //400
+#define START_GAP 31*8 // was 250 // SPEC:  1*8 to 50*8 - typ 15*8 (or 15fc)
+#define WRITE_GAP 20*8 // was 160 // SPEC:  1*8 to 20*8 - typ 10*8 (or 10fc)
+#define WRITE_0   18*8 // was 144 // SPEC: 16*8 to 32*8 - typ 24*8 (or 24fc)
+#define WRITE_1   50*8 // was 400 // SPEC: 48*8 to 64*8 - typ 56*8 (or 56fc)  432 for T55x7; 448 for E5550
 
 #define T55xx_SAMPLES_SIZE      12000 // 32 x 32 x 10  (32 bit times numofblock (7), times clock skip..)
 
index 444b93d09f688db68b71d152745c3a92f84c6b43..bfaf5088fa4ae7cba28e2cc58a489c81b16c3180 100644 (file)
 **/
 
 #include "optimized_cipher.h"
-#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdbool.h>
 #include <stdint.h>
-#include <time.h>
 
 
 #define opt_T(s) (0x1 & ((s->t >> 15) ^ (s->t >> 14)^ (s->t >> 10)^ (s->t >> 8)^ (s->t >> 5)^ (s->t >> 4)^ (s->t >> 1)^ s->t))
index d7332bda5682255bb03e4d306e87763d97218a51..f1e58ab0ed9359e80714c4be2fd146494b9fa4d4 100644 (file)
 
 #include "proxmark3.h"
 #include "apps.h"
+#include "zlib.h"
+#include "BigBuf.h"
+
+static uint8_t *next_free_memory;
+extern struct common_area common_area;
+extern char __data_src_start__, __data_start__, __data_end__, __bss_start__, __bss_end__;
+
+
+static voidpf inflate_malloc(voidpf opaque, uInt items, uInt size)
+{
+       uint8_t *allocated_memory;
+       
+       allocated_memory = next_free_memory;
+       next_free_memory += items*size;
+       return allocated_memory;
+}
+
+
+static void inflate_free(voidpf opaque, voidpf address)
+{
+       // nothing to do
+       
+}
+
+static void uncompress_data_section(void)
+{
+       z_stream data_section;
+
+       next_free_memory = BigBuf_get_addr();
+       
+       // initialize zstream structure
+       data_section.next_in = (uint8_t *) &__data_src_start__;
+       data_section.avail_in = &__data_end__ - &__data_start__;  // uncompressed size. Wrong but doesn't matter.
+       data_section.next_out = (uint8_t *) &__data_start__;
+       data_section.avail_out = &__data_end__ - &__data_start__;  // uncompressed size. Correct.
+       data_section.zalloc = &inflate_malloc;
+       data_section.zfree = &inflate_free;
+       data_section.opaque = NULL;
+
+       // initialize zlib for inflate
+       inflateInit2(&data_section, 15);
+
+       // uncompress data segment to RAM
+       inflate(&data_section, Z_FINISH);
+       
+       // save the size of the compressed data section
+       common_area.arg1 = data_section.total_in;
+}
+
 
-extern char __data_start__, __data_src_start__,  __data_end__, __bss_start__, __bss_end__;
 void __attribute__((section(".startos"))) Vector(void)
 {
        /* Stack should have been set up by the bootloader */
-       char *src, *dst, *end;
+       // char *src;
+       char *dst, *end;
+       
+       uncompress_data_section();
 
        /* Set up (that is: clear) BSS. */
        dst = &__bss_start__;
        end = &__bss_end__;
        while(dst < end) *dst++ = 0;
 
-       /* Set up data segment: Copy from flash to ram */
-       src = &__data_src_start__;
-       dst = &__data_start__;
-       end = &__data_end__;
-       while(dst < end) *dst++ = *src++;
+       // Set up data segment: Copy from flash to ram
+       // src = &__data_src_start__;
+       // dst = &__data_start__;
+       // end = &__data_end__;
+       // while(dst < end) *dst++ = *src++;
+
 
        AppMain();
 }
index 74fba94b764db748cf6a377ba23b96f5d06bc304..8576ddce5fcb7c641236d214bb224ca3221769b1 100644 (file)
@@ -268,15 +268,15 @@ void FormatVersionInformation(char *dst, int len, const char *prefix, void *vers
        dst[0] = 0;
        strncat(dst, prefix, len-1);
        if(v->magic != VERSION_INFORMATION_MAGIC) {
-               strncat(dst, "Missing/Invalid version information", len - strlen(dst) - 1);
+               strncat(dst, "Missing/Invalid version information\n", len - strlen(dst) - 1);
                return;
        }
        if(v->versionversion != 1) {
-               strncat(dst, "Version information not understood", len - strlen(dst) - 1);
+               strncat(dst, "Version information not understood\n", len - strlen(dst) - 1);
                return;
        }
        if(!v->present) {
-               strncat(dst, "Version information not available", len - strlen(dst) - 1);
+               strncat(dst, "Version information not available\n", len - strlen(dst) - 1);
                return;
        }
 
@@ -289,6 +289,7 @@ void FormatVersionInformation(char *dst, int len, const char *prefix, void *vers
 
        strncat(dst, " ", len - strlen(dst) - 1);
        strncat(dst, v->buildtime, len - strlen(dst) - 1);
+       strncat(dst, "\n", len - strlen(dst) - 1);
 }
 
 //  -------------------------------------------------------------------------
index bd8b891fd5926650ed83ba6209db64f7056a3872..ea532099e5ed6fde8eb89003831a1af72cadb7f4 100644 (file)
@@ -9,12 +9,13 @@ include ../common/Makefile.common
 CC=gcc
 CXX=g++
 #COMMON_FLAGS = -m32
-VPATH = ../common
+VPATH = ../common ../zlib
 OBJDIR = obj
 
-LDLIBS = -L/opt/local/lib -L/usr/local/lib ../liblua/liblua.a -lreadline -lpthread -lm
+LDLIBS = -L/opt/local/lib -L/usr/local/lib -lreadline -lpthread -lm
+LUALIB = ../liblua/liblua.a
 LDFLAGS = $(COMMON_FLAGS)
-CFLAGS = -std=c99 -I. -I../include -I../common -I/opt/local/include -I../liblua -Wall $(COMMON_FLAGS) -g -O4
+CFLAGS = -std=c99 -I. -I../include -I../common -I../zlib -I/opt/local/include -I../liblua -Wall $(COMMON_FLAGS) -g -O4
 LUAPLATFORM = generic
 
 ifneq (,$(findstring MINGW,$(platform)))
@@ -35,14 +36,13 @@ else ifeq ($(platform),Darwin)
 else
     CXXFLAGS = $(shell pkg-config --cflags QtCore QtGui 2>/dev/null) -Wall -O4
     QTLDLIBS = $(shell pkg-config --libs QtCore QtGui 2>/dev/null)
+    LUALIB +=  -ldl
     MOC = $(shell pkg-config --variable=moc_location QtCore)
-    LDLIBS +=  -ldl
     # Below is a variant you can use if you have problems compiling with QT5 on ubuntu. see http://www.proxmark.org/forum/viewtopic.php?id=1661 for more info. 
     #MOC = /usr/lib/x86_64-linux-gnu/qt4/bin/moc
     LUAPLATFORM = linux
 endif
 
-
 ifneq ($(QTLDLIBS),)
     QTGUI = $(OBJDIR)/proxgui.o $(OBJDIR)/proxguiqt.o $(OBJDIR)/proxguiqt.moc.o
     CFLAGS += -DHAVE_GUI
@@ -111,19 +111,25 @@ CMDSRCS =         nonce2key/crapto1.c\
                        reveng/poly.c\
                        reveng/getopt.c\
 
+ZLIBSRCS = deflate.c adler32.c trees.c zutil.c inflate.c inffast.c inftrees.c
+ZLIB_FLAGS = -DZ_SOLO -DZ_PREFIX -DNO_GZIP -DZLIB_PM3_TUNED 
+#-DDEBUG -Dverbose=1
+
+
 COREOBJS = $(CORESRCS:%.c=$(OBJDIR)/%.o)
 CMDOBJS = $(CMDSRCS:%.c=$(OBJDIR)/%.o)
+ZLIBOBJS = $(ZLIBSRCS:%.c=$(OBJDIR)/%.o)
 
 RM = rm -f
-BINS = proxmark3 flasher #snooper cli
-CLEAN = cli cli.exe flasher flasher.exe proxmark3 proxmark3.exe snooper snooper.exe $(CMDOBJS) $(OBJDIR)/*.o *.o *.moc.cpp
+BINS = proxmark3 flasher fpga_compress #snooper cli
+CLEAN = cli cli.exe flasher flasher.exe proxmark3 proxmark3.exe fpga_compress fpga_compress.exe snooper snooper.exe $(CMDOBJS) $(OBJDIR)/*.o *.o *.moc.cpp
 
 all: lua_build $(BINS) 
 
 all-static: LDLIBS:=-static $(LDLIBS)
-all-static: snooper cli flasher
-       
-proxmark3: LDLIBS+=$(QTLDLIBS)
+all-static: snooper cli flasher fpga_compress
+
+proxmark3: LDLIBS+=$(LUALIB) $(QTLDLIBS)
 proxmark3: $(OBJDIR)/proxmark3.o $(COREOBJS) $(CMDOBJS) $(QTGUI)
        $(CXX) $(CXXFLAGS) $^ $(LDLIBS) -o $@
 
@@ -136,8 +142,11 @@ cli: $(OBJDIR)/cli.o $(COREOBJS) $(CMDOBJS) $(OBJDIR)/guidummy.o
 flasher: $(OBJDIR)/flash.o $(OBJDIR)/flasher.o $(COREOBJS)
        $(CXX) $(CXXFLAGS) $^ $(LDLIBS) -o $@
 
+fpga_compress: $(OBJDIR)/fpga_compress.o $(ZLIBOBJS)
+       $(CXX) $(CXXFLAGS) $(ZLIB_FLAGS) $^ $(LDLIBS) -o $@
+
 $(OBJDIR)/%.o: %.c
-       $(CC) $(CFLAGS) -c -o $@ $<
+       $(CC) $(CFLAGS) $(ZLIB_FLAGS) -c -o $@ $<
 
 $(OBJDIR)/%.o: %.cpp
        $(CXX) $(CXXFLAGS) -c -o $@ $<
index cf105f88b993b216741720d675d8cfcbfda3c78d..bec1b5aa3f4d4394f011394fa61edca5b9a06767 100644 (file)
@@ -41,7 +41,7 @@ void setDemodBuf(uint8_t *buff, size_t size, size_t startIdx)
                size = MAX_DEMOD_BUF_LEN;
 
        size_t i = 0;
-for (; i < size; i++){
+       for (; i < size; i++){
                DemodBuffer[i]=buff[startIdx++];
        }
        DemodBufferLen=size;
@@ -344,8 +344,8 @@ int ASKDemod(const char *Cmd, bool verbose, bool emSearch, uint8_t askType)
        setDemodBuf(BitStream,BitLen,0);
        if (verbose || g_debugMode){
                if (errCnt>0) PrintAndLog("# Errors during Demoding (shown as 7 in bit stream): %d",errCnt);
-               if (askType) PrintAndLog("ASK/Manchester decoded bitstream:");
-               else PrintAndLog("ASK/Raw decoded bitstream:");
+               if (askType) PrintAndLog("ASK/Manchester - Clock: %d - Decoded bitstream:",clk);
+               else PrintAndLog("ASK/Raw - Clock: %d - Decoded bitstream:",clk);
                // Now output the bitstream to the scrollback by line of 16 bits
                printDemodBuff();
                
@@ -392,7 +392,7 @@ int Cmdmandecoderaw(const char *Cmd)
        int errCnt=0;
        size_t size=0;
        int invert=0;
-       size_t maxErr = 20;
+       int maxErr = 20;
        char cmdp = param_getchar(Cmd, 0);
        if (strlen(Cmd) > 5 || cmdp == 'h' || cmdp == 'H') {
                PrintAndLog("Usage:  data manrawdecode [invert] [maxErr]");
@@ -498,22 +498,20 @@ int CmdBiphaseDecodeRaw(const char *Cmd)
 int ASKbiphaseDemod(const char *Cmd, bool verbose)
 {
        //ask raw demod GraphBuffer first
-       int offset=0, clk=0, invert=0, maxErr=0, ans=0;
-       ans = sscanf(Cmd, "%i %i 0 %i", &offset, &clk, &maxErr);
-       if (ans>0)
-               ans = ASKDemod(Cmd+2, FALSE, FALSE, 0);
-       else
-               ans = ASKDemod(Cmd, FALSE, FALSE, 0);
-       if (!ans) {
-               if (g_debugMode || verbose) PrintAndLog("Error AskDemod: %d", ans);
-               return 0;
-       }
+       int offset=0, clk=0, invert=0, maxErr=0;
+       sscanf(Cmd, "%i %i %i %i", &offset, &clk, &invert, &maxErr);
+
+       uint8_t BitStream[MAX_DEMOD_BUF_LEN];     
+       size_t size = getFromGraphBuf(BitStream);         
+       //invert here inverts the ask raw demoded bits which has no effect on the demod, but we need the pointer
+       int errCnt = askdemod(BitStream, &size, &clk, &invert, maxErr, 0, 0);  
+       if ( errCnt < 0 || errCnt > maxErr ) {   
+               if (g_debugMode) PrintAndLog("DEBUG: no data or error found %d, clock: %d", errCnt, clk);  
+                       return 0;  
+       } 
 
-       //attempt to Biphase decode DemodBuffer
-       size_t size = DemodBufferLen;
-       uint8_t BitStream[MAX_DEMOD_BUF_LEN];
-       memcpy(BitStream, DemodBuffer, DemodBufferLen); 
-       int errCnt = BiphaseRawDecode(BitStream, &size, offset, invert);
+       //attempt to Biphase decode BitStream
+       errCnt = BiphaseRawDecode(BitStream, &size, offset, invert);
        if (errCnt < 0){
                if (g_debugMode || verbose) PrintAndLog("Error BiphaseRawDecode: %d", errCnt);
                return 0;
@@ -525,7 +523,7 @@ int ASKbiphaseDemod(const char *Cmd, bool verbose)
        //success set DemodBuffer and return
        setDemodBuf(BitStream, size, 0);
        if (g_debugMode || verbose){
-               PrintAndLog("Biphase Decoded using offset: %d - # errors:%d - data:",offset,errCnt);
+               PrintAndLog("Biphase Decoded using offset: %d - clock: %d - # errors:%d - data:",offset,clk,errCnt);
                printDemodBuff();
        }
        return 1;
@@ -1548,12 +1546,12 @@ int PSKDemod(const char *Cmd, bool verbose)
                clk=0;
        }
        if (invert != 0 && invert != 1) {
-               if (verbose) PrintAndLog("Invalid argument: %s", Cmd);
+               if (g_debugMode || verbose) PrintAndLog("Invalid argument: %s", Cmd);
                return 0;
        }
        uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0};
        size_t BitLen = getFromGraphBuf(BitStream);
-       if (BitLen==0) return -1;
+       if (BitLen==0) return 0;
        uint8_t carrier=countFC(BitStream, BitLen, 0);
        if (carrier!=2 && carrier!=4 && carrier!=8){
                //invalid carrier
index 16f7bb0f39f661c180723bd0c52bd1306407f8bd..4c5db58939671992b9b798d4ebc1ddec5e1e0278 100644 (file)
@@ -378,7 +378,7 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui
                        oddparity ^= (((frame[j] & 0xFF) >> k) & 0x01);
                }
                uint8_t parityBits = parityBytes[j>>3];
-               if (isResponse && (oddparity != ((parityBits >> (7-(j&0x0007))) & 0x01))) {
+               if (protocol != ISO_14443B && isResponse && (oddparity != ((parityBits >> (7-(j&0x0007))) & 0x01))) {
                        snprintf(line[j/16]+(( j % 16) * 4),110, "%02x! ", frame[j]);
 
                } else {
@@ -556,7 +556,12 @@ int CmdHFSearch(const char *Cmd){
        if (ans > 0) {
                PrintAndLog("\nValid ISO14443A Tag Found - Quiting Search\n");
                return ans;
-       } 
+       }
+       ans = HF14BInfo(false);
+       if (ans) {
+               PrintAndLog("\nValid ISO14443B Tag Found - Quiting Search\n");
+               return ans;
+       }
        ans = HFiClassReader("", false, false);
        if (ans) {
                PrintAndLog("\nValid iClass Tag (or PicoPass Tag) Found - Quiting Search\n");
@@ -567,12 +572,7 @@ int CmdHFSearch(const char *Cmd){
                PrintAndLog("\nValid ISO15693 Tag Found - Quiting Search\n");
                return ans;
        }
-
-
-       //14b has issues currently...
-       //ans = CmdHF14BRead(Cmd);
-       //if (ans > 0) return ans;
-
+       PrintAndLog("\nno known/supported 13.56 MHz tags found\n");
        return 0;
 }
 
index 525ffcc63d1d62a79c14c1845ff8099fe3390b06..d1d668e9e28fcf1fffa9c40a4c64df5db2796096 100644 (file)
 #include "cmdparser.h"
 #include "cmdhf14b.h"
 #include "cmdmain.h"
+#include "cmdhf14a.h"
 
 static int CmdHelp(const char *Cmd);
 
-int CmdHF14BDemod(const char *Cmd)
-{
-  int i, j, iold;
-  int isum, qsum;
-  int outOfWeakAt;
-  bool negateI, negateQ;
-
-  uint8_t data[256];
-  int dataLen = 0;
-
-  // As received, the samples are pairs, correlations against I and Q
-  // square waves. So estimate angle of initial carrier (or just
-  // quadrant, actually), and then do the demod.
-
-  // First, estimate where the tag starts modulating.
-  for (i = 0; i < GraphTraceLen; i += 2) {
-    if (abs(GraphBuffer[i]) + abs(GraphBuffer[i + 1]) > 40) {
-      break;
-    }
-  }
-  if (i >= GraphTraceLen) {
-    PrintAndLog("too weak to sync");
-    return 0;
-  }
-  PrintAndLog("out of weak at %d", i);
-  outOfWeakAt = i;
-
-  // Now, estimate the phase in the initial modulation of the tag
-  isum = 0;
-  qsum = 0;
-  for (; i < (outOfWeakAt + 16); i += 2) {
-    isum += GraphBuffer[i + 0];
-    qsum += GraphBuffer[i + 1];
-  }
-  negateI = (isum < 0);
-  negateQ = (qsum < 0);
-
-  // Turn the correlation pairs into soft decisions on the bit.
-  j = 0;
-  for (i = 0; i < GraphTraceLen / 2; i++) {
-    int si = GraphBuffer[j];
-    int sq = GraphBuffer[j + 1];
-    if (negateI) si = -si;
-    if (negateQ) sq = -sq;
-    GraphBuffer[i] = si + sq;
-    j += 2;
-  }
-  GraphTraceLen = i;
-
-  i = outOfWeakAt / 2;
-  while (GraphBuffer[i] > 0 && i < GraphTraceLen)
-    i++;
-  if (i >= GraphTraceLen) goto demodError;
-
-  iold = i;
-  while (GraphBuffer[i] < 0 && i < GraphTraceLen)
-    i++;
-  if (i >= GraphTraceLen) goto demodError;
-  if ((i - iold) > 23) goto demodError;
-
-  PrintAndLog("make it to demod loop");
-
-  for (;;) {
-    iold = i;
-    while (GraphBuffer[i] >= 0 && i < GraphTraceLen)
-      i++;
-    if (i >= GraphTraceLen) goto demodError;
-    if ((i - iold) > 6) goto demodError;
-
-    uint16_t shiftReg = 0;
-    if (i + 20 >= GraphTraceLen) goto demodError;
-
-    for (j = 0; j < 10; j++) {
-      int soft = GraphBuffer[i] + GraphBuffer[i + 1];
-
-      if (abs(soft) < (abs(isum) + abs(qsum)) / 20) {
-        PrintAndLog("weak bit");
-      }
-
-      shiftReg >>= 1;
-      if(GraphBuffer[i] + GraphBuffer[i+1] >= 0) {
-        shiftReg |= 0x200;
-      }
-
-      i+= 2;
-    }
-
-    if ((shiftReg & 0x200) && !(shiftReg & 0x001))
-    {
-      // valid data byte, start and stop bits okay
-      PrintAndLog("   %02x", (shiftReg >> 1) & 0xff);
-      data[dataLen++] = (shiftReg >> 1) & 0xff;
-      if (dataLen >= sizeof(data)) {
-        return 0;
-      }
-    } else if (shiftReg == 0x000) {
-      // this is EOF
-      break;
-    } else {
-      goto demodError;
-    }
-  }
-
-  uint8_t first, second;
-  ComputeCrc14443(CRC_14443_B, data, dataLen-2, &first, &second);
-  PrintAndLog("CRC: %02x %02x (%s)\n", first, second,
-    (first == data[dataLen-2] && second == data[dataLen-1]) ?
-      "ok" : "****FAIL****");
-
-  RepaintGraphWindow();
-  return 0;
-
-demodError:
-  PrintAndLog("demod error");
-  RepaintGraphWindow();
-  return 0;
-}
-
 int CmdHF14BList(const char *Cmd)
 {
        PrintAndLog("Deprecated command, use 'hf list 14b' instead");
 
        return 0;
 }
-int CmdHF14BRead(const char *Cmd)
-{
-  UsbCommand c = {CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443, {strtol(Cmd, NULL, 0), 0, 0}};
-  SendCommand(&c);
-  return 0;
-}
 
-int CmdHF14Sim(const char *Cmd)
+int CmdHF14BSim(const char *Cmd)
 {
-  UsbCommand c={CMD_SIMULATE_TAG_ISO_14443};
-  SendCommand(&c);
-  return 0;
-}
-
-int CmdHFSimlisten(const char *Cmd)
-{
-  UsbCommand c = {CMD_SIMULATE_TAG_HF_LISTEN};
+  UsbCommand c={CMD_SIMULATE_TAG_ISO_14443B};
+  clearCommandBuffer();
   SendCommand(&c);
   return 0;
 }
 
 int CmdHF14BSnoop(const char *Cmd)
 {
-  UsbCommand c = {CMD_SNOOP_ISO_14443};
+  UsbCommand c = {CMD_SNOOP_ISO_14443B};
+  clearCommandBuffer();
   SendCommand(&c);
   return 0;
 }
@@ -184,6 +56,7 @@ int CmdHF14BSnoop(const char *Cmd)
 int CmdSri512Read(const char *Cmd)
 {
   UsbCommand c = {CMD_READ_SRI512_TAG, {strtol(Cmd, NULL, 0), 0, 0}};
+  clearCommandBuffer();
   SendCommand(&c);
   return 0;
 }
@@ -195,127 +68,356 @@ int CmdSri512Read(const char *Cmd)
 int CmdSrix4kRead(const char *Cmd)
 {
   UsbCommand c = {CMD_READ_SRIX4K_TAG, {strtol(Cmd, NULL, 0), 0, 0}};
+  clearCommandBuffer();
   SendCommand(&c);
   return 0;
 }
 
-int CmdHF14BCmdRaw (const char *cmd) {
-    UsbCommand resp;
-    uint8_t *recv;
-    UsbCommand c = {CMD_ISO_14443B_COMMAND, {0, 0, 0}}; // len,recv?
-    uint8_t reply=1;
-    uint8_t crc=0;
-    uint8_t power=0;
-    char buf[5]="";
-    int i=0;
-    uint8_t data[100] = {0x00};
-    unsigned int datalen=0, temp;
-    char *hexout;
-    
-    if (strlen(cmd)<3) {
-        PrintAndLog("Usage: hf 14b raw [-r] [-c] [-p] <0A 0B 0C ... hex>");
-        PrintAndLog("       -r    do not read response");
-        PrintAndLog("       -c    calculate and append CRC");
-        PrintAndLog("       -p    leave the field on after receive");
-        return 0;    
-    }
-
-    // strip
-    while (*cmd==' ' || *cmd=='\t') cmd++;
-    
-    while (cmd[i]!='\0') {
-        if (cmd[i]==' ' || cmd[i]=='\t') { i++; continue; }
-        if (cmd[i]=='-') {
-            switch (cmd[i+1]) {
-                case 'r': 
-                case 'R': 
-                    reply=0;
-                    break;
-                case 'c':
-                case 'C':                
-                    crc=1;
-                    break;
-                case 'p': 
-                case 'P': 
-                    power=1;
-                    break;
-                default:
-                    PrintAndLog("Invalid option");
-                    return 0;
-            }
-            i+=2;
-            continue;
-        }
-        if ((cmd[i]>='0' && cmd[i]<='9') ||
-            (cmd[i]>='a' && cmd[i]<='f') ||
-            (cmd[i]>='A' && cmd[i]<='F') ) {
-            buf[strlen(buf)+1]=0;
-            buf[strlen(buf)]=cmd[i];
-            i++;
-            
-            if (strlen(buf)>=2) {
-                sscanf(buf,"%x",&temp);
-                data[datalen]=(uint8_t)(temp & 0xff);
-                datalen++;
-                *buf=0;
-            }
-            continue;
-        }
-        PrintAndLog("Invalid char on input");
-        return 1;
-    }
-    if (datalen == 0)
-    {
-      PrintAndLog("Missing data input");
-      return 0;
-    }
-    if(crc)
-    {
-        uint8_t first, second;
-        ComputeCrc14443(CRC_14443_B, data, datalen, &first, &second);
-        data[datalen++] = first;
-        data[datalen++] = second;
-    }
-    
-    c.arg[0] = datalen;
-    c.arg[1] = reply;
-    c.arg[2] = power;
-    memcpy(c.d.asBytes,data,datalen);
-    
-    SendCommand(&c);
-    
-    if (reply) {
-        if (WaitForResponseTimeout(CMD_ACK,&resp,1000)) {
-            recv = resp.d.asBytes;
-            PrintAndLog("received %i octets",resp.arg[0]);
-            if(!resp.arg[0])
-                return 0;
-            hexout = (char *)malloc(resp.arg[0] * 3 + 1);
-            if (hexout != NULL) {
-                uint8_t first, second;
-                for (int i = 0; i < resp.arg[0]; i++) { // data in hex
-                    sprintf(&hexout[i * 3], "%02X ", recv[i]);
-                }
-                PrintAndLog("%s", hexout);
-                free(hexout);
-                ComputeCrc14443(CRC_14443_B, recv, resp.arg[0]-2, &first, &second);
-                if(recv[resp.arg[0]-2]==first && recv[resp.arg[0]-1]==second) {
-                    PrintAndLog("CRC OK");
-                } else {
-                    PrintAndLog("CRC failed");
-                }
-            } else {
-                PrintAndLog("malloc failed your client has low memory?");
-            }
-        } else {
-            PrintAndLog("timeout while waiting for reply.");
-        }
-    } // if reply
-    return 0;
+int rawClose(void){
+       UsbCommand resp;
+       UsbCommand c = {CMD_ISO_14443B_COMMAND, {0, 0, 0}};
+       clearCommandBuffer();
+       SendCommand(&c);
+       if (!WaitForResponseTimeout(CMD_ACK,&resp,1000)) {
+               return 0;
+       }
+       return 0;
+}
+
+int HF14BCmdRaw(bool reply, bool *crc, bool power, uint8_t *data, uint8_t *datalen, bool verbose){
+       UsbCommand resp;
+       UsbCommand c = {CMD_ISO_14443B_COMMAND, {0, 0, 0}}; // len,recv,power
+       if(*crc)
+       {
+               uint8_t first, second;
+               ComputeCrc14443(CRC_14443_B, data, *datalen, &first, &second);
+               data[*datalen] = first;
+               data[*datalen + 1] = second;
+               *datalen += 2;
+       }
+       
+       c.arg[0] = *datalen;
+       c.arg[1] = reply;
+       c.arg[2] = power;
+       memcpy(c.d.asBytes,data,*datalen);
+       clearCommandBuffer();
+       SendCommand(&c);
+       
+       if (!reply) return 1; 
+
+       if (!WaitForResponseTimeout(CMD_ACK,&resp,1000)) {
+               if (verbose) PrintAndLog("timeout while waiting for reply.");
+               return 0;
+       }
+       *datalen = resp.arg[0];
+       if (verbose) PrintAndLog("received %u octets", *datalen);
+       if(*datalen<2) return 0;
+
+       memcpy(data, resp.d.asBytes, *datalen);
+       if (verbose) PrintAndLog("%s", sprint_hex(data, *datalen));
+
+       uint8_t first, second;
+       ComputeCrc14443(CRC_14443_B, data, *datalen-2, &first, &second);
+       if(data[*datalen-2] == first && data[*datalen-1] == second) {
+               if (verbose) PrintAndLog("CRC OK");
+               *crc = true;
+       } else {
+               if (verbose) PrintAndLog("CRC failed");
+               *crc = false;
+       }
+       return 1;
+}
+
+int CmdHF14BCmdRaw (const char *Cmd) {
+       bool reply = true;
+       bool crc = false;
+       bool power = false;
+       char buf[5] = "";
+       uint8_t data[100] = {0x00};
+       uint8_t datalen = 0;
+       unsigned int temp;
+       int i = 0;
+       if (strlen(Cmd)<3) {
+                       PrintAndLog("Usage: hf 14b raw [-r] [-c] [-p] <0A 0B 0C ... hex>");
+                       PrintAndLog("       -r    do not read response");
+                       PrintAndLog("       -c    calculate and append CRC");
+                       PrintAndLog("       -p    leave the field on after receive");
+                       return 0;    
+       }
+
+       // strip
+       while (*Cmd==' ' || *Cmd=='\t') Cmd++;
+       
+       while (Cmd[i]!='\0') {
+               if (Cmd[i]==' ' || Cmd[i]=='\t') { i++; continue; }
+               if (Cmd[i]=='-') {
+                       switch (Cmd[i+1]) {
+                               case 'r': 
+                               case 'R': 
+                                       reply = false;
+                                       break;
+                               case 'c':
+                               case 'C':                
+                                       crc = true;
+                                       break;
+                               case 'p': 
+                               case 'P': 
+                                       power = true;
+                                       break;
+                               default:
+                                       PrintAndLog("Invalid option");
+                                       return 0;
+                       }
+                       i+=2;
+                       continue;
+               }
+               if ((Cmd[i]>='0' && Cmd[i]<='9') ||
+                   (Cmd[i]>='a' && Cmd[i]<='f') ||
+                   (Cmd[i]>='A' && Cmd[i]<='F') ) {
+                       buf[strlen(buf)+1]=0;
+                       buf[strlen(buf)]=Cmd[i];
+                       i++;
+                       
+                       if (strlen(buf)>=2) {
+                               sscanf(buf,"%x",&temp);
+                               data[datalen++]=(uint8_t)(temp & 0xff);
+                               *buf=0;
+                       }
+                       continue;
+               }
+               PrintAndLog("Invalid char on input");
+               return 1;
+       }
+       if (datalen == 0)
+       {
+               PrintAndLog("Missing data input");
+               return 0;
+       }
+
+       return HF14BCmdRaw(reply, &crc, power, data, &datalen, true);
+}
+
+static void print_atqb_resp(uint8_t *data){
+       PrintAndLog ("           UID: %s", sprint_hex(data+1,4));
+       PrintAndLog ("      App Data: %s", sprint_hex(data+5,4));
+       PrintAndLog ("      Protocol: %s", sprint_hex(data+9,3));
+       uint8_t BitRate = data[9];
+       if (!BitRate) 
+               PrintAndLog ("      Bit Rate: 106 kbit/s only PICC <-> PCD");
+       if (BitRate & 0x10)
+               PrintAndLog ("      Bit Rate: 212 kbit/s PICC -> PCD supported");
+       if (BitRate & 0x20)
+               PrintAndLog ("      Bit Rate: 424 kbit/s PICC -> PCD supported"); 
+       if (BitRate & 0x40)
+               PrintAndLog ("      Bit Rate: 847 kbit/s PICC -> PCD supported"); 
+       if (BitRate & 0x01)
+               PrintAndLog ("      Bit Rate: 212 kbit/s PICC <- PCD supported");
+       if (BitRate & 0x02)
+               PrintAndLog ("      Bit Rate: 424 kbit/s PICC <- PCD supported"); 
+       if (BitRate & 0x04)
+               PrintAndLog ("      Bit Rate: 847 kbit/s PICC <- PCD supported"); 
+       if (BitRate & 0x80) 
+               PrintAndLog ("                Same bit rate <-> required");
+
+       uint16_t maxFrame = data[10]>>4;
+       if (maxFrame < 5) 
+               maxFrame = 8*maxFrame + 16;
+       else if (maxFrame == 5)
+               maxFrame = 64;
+       else if (maxFrame == 6)
+               maxFrame = 96;
+       else if (maxFrame == 7)
+               maxFrame = 128;
+       else if (maxFrame == 8)
+               maxFrame = 256;
+       else
+               maxFrame = 257;
+
+       PrintAndLog ("Max Frame Size: %d%s",maxFrame, (maxFrame == 257) ? "+ RFU" : "");
+
+       uint8_t protocolT = data[10] & 0xF;
+       PrintAndLog (" Protocol Type: Protocol is %scompliant with ISO/IEC 14443-4",(protocolT) ? "" : "not " );
+       PrintAndLog ("Frame Wait Int: %d", data[11]>>4);
+       PrintAndLog (" App Data Code: Application is %s",(data[11]&4) ? "Standard" : "Proprietary");
+       PrintAndLog (" Frame Options: NAD is %ssupported",(data[11]&2) ? "" : "not ");
+       PrintAndLog (" Frame Options: CID is %ssupported",(data[11]&1) ? "" : "not ");
+       
+       return;
+}
+
+char *get_ST_Chip_Model(uint8_t data){
+       static char model[20];
+       char *retStr = model;
+       memset(model,0, sizeof(model));
+
+       switch (data) {
+               case 0x0: sprintf(retStr, "SRIX4K (Special)"); break;
+               case 0x2: sprintf(retStr, "SR176"); break;
+               case 0x3: sprintf(retStr, "SRIX4K"); break;
+               case 0x4: sprintf(retStr, "SRIX512"); break;
+               case 0x6: sprintf(retStr, "SRI512"); break;
+               case 0x7: sprintf(retStr, "SRI4K"); break;
+               case 0xC: sprintf(retStr, "SRT512"); break;
+               default : sprintf(retStr, "Unknown"); break;
+       }
+       return retStr;
+}
+
+static void print_st_info(uint8_t *data){
+       //uid = first 8 bytes in data
+       PrintAndLog(" UID: %s", sprint_hex(SwapEndian64(data,8,8),8));
+       PrintAndLog(" MFG: %02X, %s", data[6], getTagInfo(data[6]));
+       PrintAndLog("Chip: %02X, %s", data[5]>>2, get_ST_Chip_Model(data[5]>>2));
+       return;
+}
+
+int HF14BStdInfo(uint8_t *data, uint8_t *datalen){
+
+       //05 00 00 = find one tag in field
+       //1d xx xx xx xx 20 00 08 01 00 = attrib xx=crc
+       //a3 = ?  (resp 03 e2 c2)
+       //02 = ?  (resp 02 6a d3)
+       // 022b (resp 02 67 00 [29  5b])
+       // 0200a40400 (resp 02 67 00 [29 5b])
+       // 0200a4040c07a0000002480300 (resp 02 67 00 [29 5b])
+       // 0200a4040c07a0000002480200 (resp 02 67 00 [29 5b])
+       // 0200a4040006a0000000010100 (resp 02 6a 82 [4b 4c])
+       // 0200a4040c09d27600002545500200 (resp 02 67 00 [29 5b])
+       // 0200a404000cd2760001354b414e4d30310000 (resp 02 6a 82 [4b 4c])
+       // 0200a404000ca000000063504b43532d313500 (resp 02 6a 82 [4b 4c])
+       // 0200a4040010a000000018300301000000000000000000 (resp 02 6a 82 [4b 4c])
+       //03 = ?  (resp 03 [e3 c2])
+       //c2 = ?  (resp c2 [66 15])
+       //b2 = ?  (resp a3 [e9 67])
+       bool crc = true;
+       *datalen = 3;
+       //std read cmd
+       data[0] = 0x05;
+       data[1] = 0x00;
+       data[2] = 0x00;
+
+       if (HF14BCmdRaw(true, &crc, false, data, datalen, false)==0) return 0;
+
+       if (data[0] != 0x50  || *datalen != 14 || !crc) return 0;
+
+       PrintAndLog ("\n14443-3b tag found:");
+       print_atqb_resp(data);
+
+       return 1;
 }
 
-int CmdHF14BWrite( const char *Cmd){
+int HF14B_ST_Info(uint8_t *data, uint8_t *datalen){
+       bool crc = true;
+       *datalen = 2;
+       //wake cmd
+       data[0] = 0x06;
+       data[1] = 0x00;
+
+       //leave power on
+       // verbose on for now for testing - turn off when functional
+       if (HF14BCmdRaw(true, &crc, true, data, datalen, false)==0) return rawClose();
+
+       if (*datalen != 3 || !crc) return rawClose();
+
+       uint8_t chipID = data[0];
+       // select
+       data[0] = 0x0E;
+       data[1] = chipID;
+       *datalen = 2;
+
+       //leave power on
+       // verbose on for now for testing - turn off when functional
+       if (HF14BCmdRaw(true, &crc, true, data, datalen, false)==0) return rawClose();
+
+       if (*datalen != 3 || !crc || data[0] != chipID) return rawClose();
+
+       // get uid
+       data[0] = 0x0B;
+       *datalen = 1;
+
+       //power off
+       // verbose on for now for testing - turn off when functional
+       if (HF14BCmdRaw(true, &crc, true, data, datalen, false)==0) return 0;
+       rawClose();
+       if (*datalen != 10 || !crc) return 0;
+
+       PrintAndLog("\n14443-3b ST tag found:");
+       print_st_info(data);
+       return 1;
+}
+
+// test for other 14b type tags (mimic another reader - don't have tags to identify)
+int HF14B_Other_Info(uint8_t *data, uint8_t *datalen){
+       bool crc = true;
+       *datalen = 4;
+       //std read cmd
+       data[0] = 0x00;
+       data[1] = 0x0b;
+       data[2] = 0x3f;
+       data[3] = 0x80;
+
+       if (HF14BCmdRaw(true, &crc, false, data, datalen, false)!=0) {
+               if (*datalen > 2 || !crc) {
+                       PrintAndLog ("\n14443-3b tag found:");
+                       PrintAndLog ("Unknown tag type answered to a 0x000b3f80 command ans:");
+                       PrintAndLog ("%s",sprint_hex(data,*datalen));
+                       return 1;
+               }
+       }
+
+       crc = false;
+       *datalen = 1;
+       data[0] = 0x0a;
+
+       if (HF14BCmdRaw(true, &crc, false, data, datalen, false)!=0) {
+               if (*datalen > 0) {
+                       PrintAndLog ("\n14443-3b tag found:");
+                       PrintAndLog ("Unknown tag type answered to a 0x0A command ans:");
+                       PrintAndLog ("%s",sprint_hex(data,*datalen));
+                       return 1;
+               }
+       }
+       
+       crc = false;
+       *datalen = 1;
+       data[0] = 0x0c;
+
+       if (HF14BCmdRaw(true, &crc, false, data, datalen, false)!=0) {
+               if (*datalen > 0) {
+                       PrintAndLog ("\n14443-3b tag found:");
+                       PrintAndLog ("Unknown tag type answered to a 0x0C command ans:");
+                       PrintAndLog ("%s",sprint_hex(data,*datalen));
+                       return 1;
+               }
+       }
+
+       return 0;
+
+}
+
+int HF14BInfo(bool verbose){
+       uint8_t data[100];
+       uint8_t datalen = 5;
+       
+       // try std 14b (atqb)
+       if (HF14BStdInfo(data, &datalen)) return 1;
+
+       // try st 14b
+       if (HF14B_ST_Info(data, &datalen)) return 1;
+
+       // try unknown 14b read commands (to be identified later)
+       //   could be read of calypso, CEPAS, moneo, or pico pass.
+       if (HF14B_Other_Info(data, &datalen)) return 1;
+
+       if (verbose) PrintAndLog("no 14443B tag found");
+       return 0;
+}
+
+int CmdHF14Binfo(const char *Cmd){
+       return HF14BInfo(true);
+}
 
+int CmdSriWrite( const char *Cmd){
 /*
  * For SRIX4K  blocks 00 - 7F
  * hf 14b raw -c -p 09 $srix4kwblock $srix4kwdata
@@ -385,16 +487,14 @@ int CmdHF14BWrite( const char *Cmd){
 static command_t CommandTable[] = 
 {
   {"help",        CmdHelp,        1, "This help"},
-  {"demod",       CmdHF14BDemod,  1, "Demodulate ISO14443 Type B from tag"},
+       {"info",        CmdHF14Binfo,   0, "Find and print info about a 14b type tag (HF ISO 14443b)"},
   {"list",        CmdHF14BList,   0, "[Deprecated] List ISO 14443b history"},
-  {"read",        CmdHF14BRead,   0, "Read HF tag (ISO 14443)"},
-  {"sim",         CmdHF14Sim,     0, "Fake ISO 14443 tag"},
-  {"simlisten",   CmdHFSimlisten, 0, "Get HF samples as fake tag"},
-  {"snoop",       CmdHF14BSnoop,  0, "Eavesdrop ISO 14443"},
+  {"sim",         CmdHF14BSim,    0, "Fake ISO 14443B tag"},
+  {"snoop",       CmdHF14BSnoop,  0, "Eavesdrop ISO 14443B"},
   {"sri512read",  CmdSri512Read,  0, "Read contents of a SRI512 tag"},
   {"srix4kread",  CmdSrix4kRead,  0, "Read contents of a SRIX4K tag"},
+  {"sriwrite",    CmdSriWrite,    0, "Write data to a SRI512 | SRIX4K tag"},
   {"raw",         CmdHF14BCmdRaw, 0, "Send raw hex data to tag"},
-  {"write",       CmdHF14BWrite,  0, "Write data to a SRI512 | SRIX4K tag"},
   {NULL, NULL, 0, NULL}
 };
 
index cc8b9dbd810c15a889c40e406f6d4f980b5c5ca2..a45b74341ced2cd82a733472f7abd4939fc29744 100644 (file)
 #define CMDHF14B_H__
 
 int CmdHF14B(const char *Cmd);
-
-int CmdHF14BDemod(const char *Cmd);
 int CmdHF14BList(const char *Cmd);
-int CmdHF14BRead(const char *Cmd);
-int CmdHF14Sim(const char *Cmd);
-int CmdHFSimlisten(const char *Cmd);
+int CmdHF14BInfo(const char *Cmd);
+int CmdHF14BSim(const char *Cmd);
 int CmdHF14BSnoop(const char *Cmd);
 int CmdSri512Read(const char *Cmd);
 int CmdSrix4kRead(const char *Cmd);
 int CmdHF14BWrite( const char *cmd);
+int HF14BInfo(bool verbose);
 
 #endif
index 3286ceb9cce45a2f9d9738219347044db63a303a..e9c63f20b02f7f88fae741f4e24780a763bff910 100644 (file)
@@ -9,7 +9,7 @@
 //-----------------------------------------------------------------------------
 
 #include "util.h"
-//#include "proxusb.h"
+
 #include "proxmark3.h"
 #include "ui.h"
 #include "cmdparser.h"
@@ -29,9 +29,9 @@ int CmdHFEPACollectPACENonces(const char *Cmd)
        unsigned int n = 0;
        // delay between requests
        unsigned int d = 0;
-       
+
        sscanf(Cmd, "%u %u %u", &m, &n, &d);
-       
+
        // values are expected to be > 0
        m = m > 0 ? m : 1;
        n = n > 0 ? n : 1;
@@ -44,7 +44,7 @@ int CmdHFEPACollectPACENonces(const char *Cmd)
                UsbCommand c = {CMD_EPA_PACE_COLLECT_NONCE, {(int)m, 0, 0}};
                SendCommand(&c);
                UsbCommand resp;
-    
+
                WaitForResponse(CMD_ACK,&resp);
 
                // check if command failed
@@ -68,13 +68,123 @@ int CmdHFEPACollectPACENonces(const char *Cmd)
        return 1;
 }
 
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////The commands lie below here/////////////////////////////////////////////////////////////////////////////////////////
+
+// perform the PACE protocol by replaying APDUs
+int CmdHFEPAPACEReplay(const char *Cmd)
+{
+       // the 4 APDUs which are replayed + their lengths
+       uint8_t msesa_apdu[41], gn_apdu[8], map_apdu[75];
+       uint8_t pka_apdu[75], ma_apdu[18], apdu_lengths[5] = {0};
+       // pointers to the arrays to be able to iterate
+       uint8_t *apdus[] = {msesa_apdu, gn_apdu, map_apdu, pka_apdu, ma_apdu};
+
+       // usage message
+       static const char const *usage_msg =
+               "Please specify 5 APDUs separated by spaces. "
+               "Example:\n preplay 0022C1A4 1068000000 1086000002 1234ABCDEF 1A2B3C4D";
+
+       // Proxmark response
+       UsbCommand resp;
+
+       int skip = 0, skip_add = 0, scan_return = 0;
+       // for each APDU
+       for (int i = 0; i < sizeof(apdu_lengths); i++) {
+               // scan to next space or end of string
+               while (Cmd[skip] != ' ' && Cmd[skip] != '\0') {
+                       // convert
+                       scan_return = sscanf(Cmd + skip, "%2X%n",
+                                            (unsigned int *) (apdus[i] + apdu_lengths[i]),
+                                            &skip_add);
+                       if (scan_return < 1) {
+                               PrintAndLog((char *)usage_msg);
+                               PrintAndLog("Not enough APDUs! Try again!");
+                               return 0;
+                       }
+                       skip += skip_add;
+            apdu_lengths[i]++;
+               }
+
+               // break on EOF
+               if (Cmd[skip] == '\0') {
+                       if (i < sizeof(apdu_lengths) - 1) {
+
+                               PrintAndLog((char *)usage_msg);
+                               return 0;
+                       }
+                       break;
+               }
+               // skip the space
+               skip++;
+       }
+
+       // transfer the APDUs to the Proxmark
+       UsbCommand usb_cmd;
+       usb_cmd.cmd = CMD_EPA_PACE_REPLAY;
+       for (int i = 0; i < sizeof(apdu_lengths); i++) {
+               // APDU number
+               usb_cmd.arg[0] = i + 1;
+               // transfer the APDU in several parts if necessary
+               for (int j = 0; j * sizeof(usb_cmd.d.asBytes) < apdu_lengths[i]; j++) {
+                       // offset into the APDU
+                       usb_cmd.arg[1] = j * sizeof(usb_cmd.d.asBytes);
+                       // amount of data in this packet
+                       int packet_length = apdu_lengths[i] - (j * sizeof(usb_cmd.d.asBytes));
+                       if (packet_length > sizeof(usb_cmd.d.asBytes)) {
+                               packet_length = sizeof(usb_cmd.d.asBytes);
+                       }
+                       usb_cmd.arg[2] = packet_length;
+
+                       memcpy(usb_cmd.d.asBytes, // + (j * sizeof(usb_cmd.d.asBytes)),
+                              apdus[i] + (j * sizeof(usb_cmd.d.asBytes)),
+                              packet_length);
+                       SendCommand(&usb_cmd);
+                       WaitForResponse(CMD_ACK, &resp);
+                       if (resp.arg[0] != 0) {
+                               PrintAndLog("Transfer of APDU #%d Part %d failed!", i, j);
+                               return 0;
+                       }
+               }
+       }
+
+       // now perform the replay
+       usb_cmd.arg[0] = 0;
+       SendCommand(&usb_cmd);
+       WaitForResponse(CMD_ACK, &resp);
+       if (resp.arg[0] != 0) {
+               PrintAndLog("\nPACE replay failed in step %u!", (uint32_t)resp.arg[0]);
+               PrintAndLog("Measured times:");
+               PrintAndLog("MSE Set AT: %u us", resp.d.asDwords[0]);
+               PrintAndLog("GA Get Nonce: %u us", resp.d.asDwords[1]);
+               PrintAndLog("GA Map Nonce: %u us", resp.d.asDwords[2]);
+               PrintAndLog("GA Perform Key Agreement: %u us", resp.d.asDwords[3]);
+               PrintAndLog("GA Mutual Authenticate: %u us", resp.d.asDwords[4]);
+       } else {
+               PrintAndLog("PACE replay successfull!");
+               PrintAndLog("MSE Set AT: %u us", resp.d.asDwords[0]);
+               PrintAndLog("GA Get Nonce: %u us", resp.d.asDwords[1]);
+               PrintAndLog("GA Map Nonce: %u us", resp.d.asDwords[2]);
+               PrintAndLog("GA Perform Key Agreement: %u us", resp.d.asDwords[3]);
+               PrintAndLog("GA Mutual Authenticate: %u us", resp.d.asDwords[4]);
+       }
+
+
+       return 1;
+}
+
+////////////////////////////////The new commands lie above here/////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
 // UI-related stuff
 
-static const command_t CommandTable[] = 
+static const command_t CommandTable[] =
 {
   {"help",    CmdHelp,                   1, "This help"},
   {"cnonces", CmdHFEPACollectPACENonces, 0,
               "<m> <n> <d> Acquire n>0 encrypted PACE nonces of size m>0 with d sec pauses"},
+  {"preplay", CmdHFEPAPACEReplay,        0,
+   "<mse> <get> <map> <pka> <ma> Perform PACE protocol by replaying given APDUs"},
   {NULL, NULL, 0, NULL}
 };
 
@@ -92,4 +202,4 @@ int CmdHFEPA(const char *Cmd)
        // parse
   CmdsParse(CommandTable, Cmd);
   return 0;
-}
\ No newline at end of file
+}
index 2b5a5b87965dd7b36e283e9f94fe876f2e740dc7..5abda060d8e4e40ae83f71977e4d864ad39dfaff 100644 (file)
@@ -1750,10 +1750,13 @@ int CmdHF14AMfCSave(const char *Cmd) {
                        // get filename\r
                        if (mfCGetBlock(0, buf, CSETBLOCK_SINGLE_OPER)) {\r
                                PrintAndLog("Cant get block: %d", 0);\r
-                               return 1;\r
+                               len = sprintf(fnameptr, "dump");\r
+                               fnameptr += len;\r
+                       }\r
+                       else {\r
+                               for (j = 0; j < 7; j++, fnameptr += 2)\r
+                                       sprintf(fnameptr, "%02x", buf[j]); \r
                        }\r
-                       for (j = 0; j < 7; j++, fnameptr += 2)\r
-                               sprintf(fnameptr, "%02x", buf[j]); \r
                } else {\r
                        memcpy(filename, Cmd, len);\r
                        fnameptr += len;\r
index 48f549ba8334f4ecbd0fb97180c120ace6a73993..25a073d34440b2de98b3c56d67597dbc2df14111 100644 (file)
@@ -57,13 +57,13 @@ uint8_t default_pwd_pack[KEYS_PWD_COUNT][4] = {
        {0x32,0x0C,0x16,0x17}, // PACK 0x80,0x80 -- AMiiboo (sniffed) 
 };
 
-#define MAX_UL_TYPES 17
-uint16_t UL_TYPES_ARRAY[MAX_UL_TYPES] = {UNKNOWN, UL, UL_C, UL_EV1_48, UL_EV1_128, NTAG, NTAG_203,
-           NTAG_210, NTAG_212, NTAG_213, NTAG_215, NTAG_216, MY_D, MY_D_NFC, MY_D_MOVE, MY_D_MOVE_NFC, MY_D_MOVE_LEAN};
+#define MAX_UL_TYPES 18
+uint32_t UL_TYPES_ARRAY[MAX_UL_TYPES] = {UNKNOWN, UL, UL_C, UL_EV1_48, UL_EV1_128, NTAG, NTAG_203,
+           NTAG_210, NTAG_212, NTAG_213, NTAG_215, NTAG_216, MY_D, MY_D_NFC, MY_D_MOVE, MY_D_MOVE_NFC, MY_D_MOVE_LEAN, FUDAN_UL};
 
 uint8_t UL_MEMORY_ARRAY[MAX_UL_TYPES] = {MAX_UL_BLOCKS, MAX_UL_BLOCKS, MAX_ULC_BLOCKS, MAX_ULEV1a_BLOCKS,
            MAX_ULEV1b_BLOCKS, MAX_NTAG_203, MAX_NTAG_203, MAX_NTAG_210, MAX_NTAG_212, MAX_NTAG_213,
-           MAX_NTAG_215, MAX_NTAG_216, MAX_UL_BLOCKS, MAX_MY_D_NFC, MAX_MY_D_MOVE, MAX_MY_D_MOVE, MAX_MY_D_MOVE_LEAN};
+           MAX_NTAG_215, MAX_NTAG_216, MAX_UL_BLOCKS, MAX_MY_D_NFC, MAX_MY_D_MOVE, MAX_MY_D_MOVE, MAX_MY_D_MOVE_LEAN, MAX_UL_BLOCKS};
 
 
 static int CmdHelp(const char *Cmd);
@@ -276,6 +276,38 @@ static int ulev1_readSignature( uint8_t *response, uint16_t responseLength ){
        return len;
 }
 
+
+// Fudan check checks for which error is given for a command with incorrect crc
+// NXP UL chip responds with 01, fudan 00.
+// other possible checks:
+//  send a0 + crc 
+//  UL responds with 00, fudan doesn't respond
+//  or
+//  send a200 + crc
+//  UL doesn't respond, fudan responds with 00
+//  or
+//  send 300000 + crc (read with extra byte(s))
+//  UL responds with read of page 0, fudan doesn't respond.
+//
+// make sure field is off before calling this function
+static int ul_fudan_check( void ){
+       iso14a_card_select_t card;
+       if ( !ul_select(&card) ) 
+               return UL_ERROR;
+
+       UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_NO_DISCONNECT, 4, 0}};
+
+       uint8_t cmd[4] = {0x30,0x00,0x02,0xa7}; //wrong crc on purpose  should be 0xa8
+       memcpy(c.d.asBytes, cmd, 4);
+       clearCommandBuffer();
+       SendCommand(&c);
+       UsbCommand resp;
+       if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) return UL_ERROR;
+       if (resp.arg[0] != 1) return UL_ERROR;
+
+       return (!resp.d.asBytes[0]) ? FUDAN_UL : UL; //if response == 0x00 then Fudan, else Genuine NXP
+}
+
 static int ul_print_default( uint8_t *data){
 
        uint8_t uid[7];
@@ -389,6 +421,8 @@ int ul_print_type(uint32_t tagtype, uint8_t spaces){
                PrintAndLog("%sTYPE : INFINEON my-d\x99 move NFC (SLE 66R01P)", spacer);
        else if ( tagtype & MY_D_MOVE_LEAN )
                PrintAndLog("%sTYPE : INFINEON my-d\x99 move lean (SLE 66R01L)", spacer);
+       else if ( tagtype & FUDAN_UL )
+               PrintAndLog("%sTYPE : FUDAN Ultralight Compatible (or other compatible) %s", spacer, (tagtype & MAGIC) ? "<magic>" : "" );
        else
                PrintAndLog("%sTYPE : Unknown %06x", spacer, tagtype);
        return 0;
@@ -622,6 +656,10 @@ uint32_t GetHF14AMfU_Type(void){
                                ul_switch_off_field();
                        }
                }
+               if (tagtype & UL) {
+                       tagtype = ul_fudan_check(); 
+                       ul_switch_off_field();
+               }
        } else {
                ul_switch_off_field();
                // Infinition MY-D tests   Exam high nibble 
@@ -870,10 +908,6 @@ int CmdHF14AMfUWrBl(const char *Cmd){
        uint8_t authenticationkey[16] = {0x00};
        uint8_t *authKeyPtr = authenticationkey;
 
-       // starting with getting tagtype
-       TagTypeUL_t tagtype = GetHF14AMfU_Type();
-       if (tagtype == UL_ERROR) return -1;
-
        while(param_getchar(Cmd, cmdp) != 0x00)
        {
                switch(param_getchar(Cmd, cmdp))
@@ -905,21 +939,10 @@ int CmdHF14AMfUWrBl(const char *Cmd){
                        case 'b':
                        case 'B':
                                blockNo = param_get8(Cmd, cmdp+1);
-                               
-                               uint8_t maxblockno = 0;
-                               for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++){
-                                       if (tagtype & UL_TYPES_ARRAY[idx])
-                                               maxblockno = UL_MEMORY_ARRAY[idx];
-                               }
-               
                                if (blockNo < 0) {
                                        PrintAndLog("Wrong block number");
                                        errors = true;
                                }
-                               if (blockNo > maxblockno){
-                                       PrintAndLog("block number too large. Max block is %u/0x%02X \n", maxblockno,maxblockno);
-                                       errors = true;
-                               }
                                cmdp += 2;
                                break;
                        case 'l':
@@ -946,6 +969,19 @@ int CmdHF14AMfUWrBl(const char *Cmd){
        }
 
        if ( blockNo == -1 ) return usage_hf_mfu_wrbl();
+       // starting with getting tagtype
+       TagTypeUL_t tagtype = GetHF14AMfU_Type();
+       if (tagtype == UL_ERROR) return -1;
+
+       uint8_t maxblockno = 0;
+       for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++){
+               if (tagtype & UL_TYPES_ARRAY[idx])
+                       maxblockno = UL_MEMORY_ARRAY[idx];
+       }
+       if (blockNo > maxblockno){
+               PrintAndLog("block number too large. Max block is %u/0x%02X \n", maxblockno,maxblockno);
+               return usage_hf_mfu_wrbl();
+       }
 
        // Swap endianness 
        if (swapEndian && hasAuthKey) authKeyPtr = SwapEndian64(authenticationkey, 16, 8);
@@ -997,10 +1033,6 @@ int CmdHF14AMfURdBl(const char *Cmd){
        uint8_t authenticationkey[16] = {0x00};
        uint8_t *authKeyPtr = authenticationkey;
 
-       // starting with getting tagtype
-       TagTypeUL_t tagtype = GetHF14AMfU_Type();
-       if (tagtype == UL_ERROR) return -1;
-
        while(param_getchar(Cmd, cmdp) != 0x00)
        {
                switch(param_getchar(Cmd, cmdp))
@@ -1032,21 +1064,10 @@ int CmdHF14AMfURdBl(const char *Cmd){
                        case 'b':
                        case 'B':
                                blockNo = param_get8(Cmd, cmdp+1);
-
-                               uint8_t maxblockno = 0;
-                               for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++){
-                                       if (tagtype & UL_TYPES_ARRAY[idx])
-                                               maxblockno = UL_MEMORY_ARRAY[idx];
-                               }
-
                                if (blockNo < 0) {
                                        PrintAndLog("Wrong block number");
                                        errors = true;
                                }
-                               if (blockNo > maxblockno){
-                                       PrintAndLog("block number to large. Max block is %u/0x%02X \n", maxblockno,maxblockno);
-                                       errors = true;
-                               }
                                cmdp += 2;
                                break;
                        case 'l':
@@ -1064,6 +1085,19 @@ int CmdHF14AMfURdBl(const char *Cmd){
        }
 
        if ( blockNo == -1 ) return usage_hf_mfu_rdbl();
+       // start with getting tagtype
+       TagTypeUL_t tagtype = GetHF14AMfU_Type();
+       if (tagtype == UL_ERROR) return -1;
+
+       uint8_t maxblockno = 0;
+       for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++){
+               if (tagtype & UL_TYPES_ARRAY[idx])
+                       maxblockno = UL_MEMORY_ARRAY[idx];
+       }
+       if (blockNo > maxblockno){
+               PrintAndLog("block number to large. Max block is %u/0x%02X \n", maxblockno,maxblockno);
+               return usage_hf_mfu_rdbl();
+       }
 
        // Swap endianness 
        if (swapEndian && hasAuthKey) authKeyPtr = SwapEndian64(authenticationkey, 16, 8);
index 132e4f9086b1431711cdff020b33dbf65b6c6fb9..6c9e3ea1b66834d54b6e166c51f6e5a4d326b4c7 100644 (file)
@@ -45,7 +45,8 @@ typedef enum TAGTYPE_UL {
        MY_D_MOVE_LEAN= 0x008000,
        NTAG_I2C_1K   = 0x010000,
        NTAG_I2C_2K   = 0x020000,
-       MAGIC         = 0x040000,
+       FUDAN_UL      = 0x040000,
+       MAGIC         = 0x080000,
        UL_MAGIC      = UL | MAGIC,
        UL_C_MAGIC    = UL_C | MAGIC,
        UL_ERROR      = 0xFFFFFF,
index 5ec0aa601eb8024676220ca340a1431930fb861b..05ad0c9f482f5072616cfdb07357a3b6a9fe52b8 100644 (file)
 
 static int CmdHelp(const char *Cmd);
 
-static void lookupChipID(uint32_t iChipID)
+static void lookupChipID(uint32_t iChipID, uint32_t mem_used)
 {
        char asBuff[100];
+       uint32_t mem_avail = 0;
+       
        switch(iChipID)
        {
                case 0x270B0A40:
@@ -103,37 +105,43 @@ static void lookupChipID(uint32_t iChipID)
        switch((iChipID&0xF00)>>8)
        {
                case 0:
-                       sprintf(asBuff,"None");
+                       mem_avail = 0;
                        break;
                case 1:
-                       sprintf(asBuff,"8K bytes");
+                       mem_avail = 8;
                        break;
                case 2:
-                       sprintf(asBuff,"16K bytes");
+                       mem_avail = 16;
                        break;
                case 3:
-                       sprintf(asBuff,"32K bytes");
+                       mem_avail = 32;
                        break;
                case 5:
-                       sprintf(asBuff,"64K bytes");
+                       mem_avail = 64;
                        break;
                case 7:
-                       sprintf(asBuff,"128K bytes");
+                       mem_avail = 128;
                        break;
                case 9:
-                       sprintf(asBuff,"256K bytes");
+                       mem_avail = 256;
                        break;
                case 10:
-                       sprintf(asBuff,"512K bytes");
+                       mem_avail = 512;
                        break;
                case 12:
-                       sprintf(asBuff,"1024K bytes");
+                       mem_avail = 1024;
                        break;
                case 14:
-                       sprintf(asBuff,"2048K bytes");
+                       mem_avail = 2048;
                        break;
        }
-       PrintAndLog("Nonvolatile Program Memory Size: %s",asBuff);
+       PrintAndLog("Nonvolatile Program Memory Size: %dK bytes. Used: %d bytes (%2.0f\%). Free: %d bytes (%2.0f\%).", 
+                               mem_avail, 
+                               mem_used, 
+                               mem_avail == 0 ? 0 : (float)mem_used/(mem_avail*1024)*100,
+                               mem_avail*1024 - mem_used,
+                               mem_avail == 0 ? 0 : (float)(mem_avail*1024-mem_used)/(mem_avail*1024)*100
+                               );
        switch((iChipID&0xF000)>>12)
        {
                case 0:
@@ -396,13 +404,24 @@ int CmdTune(const char *Cmd)
 
 int CmdVersion(const char *Cmd)
 {
-  UsbCommand c = {CMD_VERSION};
-  UsbCommand resp;
-  SendCommand(&c);
-  if (WaitForResponseTimeout(CMD_ACK,&resp,1000)) {
-      lookupChipID(resp.arg[0]);
-  }
-  return 0;
+
+       UsbCommand c = {CMD_VERSION};
+       static UsbCommand resp = {0, {0, 0, 0}};
+       
+       if (resp.arg[0] == 0 && resp.arg[1] == 0) { // no cached information available
+               SendCommand(&c);
+               if (WaitForResponseTimeout(CMD_ACK,&resp,1000) && Cmd != NULL) {
+                       PrintAndLog("Prox/RFID mark3 RFID instrument");
+                       PrintAndLog((char*)resp.d.asBytes);
+                       lookupChipID(resp.arg[0], resp.arg[1]);
+               }
+       } else if (Cmd != NULL) {
+               PrintAndLog("Prox/RFID mark3 RFID instrument");
+               PrintAndLog((char*)resp.d.asBytes);
+               lookupChipID(resp.arg[0], resp.arg[1]);
+       }
+       
+       return 0;
 }
 
 static command_t CommandTable[] = 
index c492a64d52e5c4e056202302142836a2f893ae80..eddeec5604ea68229d68088f409f2193d244259a 100644 (file)
@@ -20,6 +20,9 @@
 #include "cmdlf.h"
 #include "cmdlfem4x.h"
 #include "lfdemod.h"
+
+#define llx PRIx64
+
 char *global_em410xId;
 
 static int CmdHelp(const char *Cmd);
diff --git a/client/fpga_compress.c b/client/fpga_compress.c
new file mode 100644 (file)
index 0000000..2779e83
--- /dev/null
@@ -0,0 +1,287 @@
+//-----------------------------------------------------------------------------
+// This code is licensed to you under the terms of the GNU GPL, version 2 or,
+// at your option, any later version. See the LICENSE.txt file for the text of
+// the license.
+//-----------------------------------------------------------------------------
+// Compression tool for FPGA config files. Compress several *.bit files at
+// compile time. Decompression is done at run time (see fpgaloader.c).
+// This uses the zlib library tuned to this specific case. The small file sizes
+// allow to use "insane" parameters for optimum compression ratio.
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include "zlib.h"
+
+#define MAX(a,b) ((a)>(b)?(a):(b))
+
+// zlib configuration
+#define COMPRESS_LEVEL                 9               // use best possible compression
+#define COMPRESS_WINDOW_BITS   15              // default = max = 15 for a window of 2^15 = 32KBytes
+#define COMPRESS_MEM_LEVEL             9               // determines the amount of memory allocated during compression. Default = 8.
+/* COMPRESS_STRATEGY can be 
+       Z_DEFAULT_STRATEGY (the default), 
+       Z_FILTERED (more huffmann, less string matching),
+       Z_HUFFMAN_ONLY (huffman only, no string matching)
+       Z_RLE (distances limited to one)
+       Z_FIXED (prevents the use of dynamic Huffman codes)
+*/     
+#define        COMPRESS_STRATEGY               Z_DEFAULT_STRATEGY
+// zlib tuning parameters:
+#define COMPRESS_GOOD_LENGTH           258
+#define        COMPRESS_MAX_LAZY                       258     
+#define        COMPRESS_MAX_NICE_LENGTH        258
+#define        COMPRESS_MAX_CHAIN                      8192
+
+#define FPGA_INTERLEAVE_SIZE   288     // (the FPGA's internal config frame size is 288 bits. Interleaving with 288 bytes should give best compression)
+#define FPGA_CONFIG_SIZE               42336   // our current fpga_[lh]f.bit files are 42175 bytes. Rounded up to next multiple of FPGA_INTERLEAVE_SIZE
+
+static void usage(void)
+{
+       fprintf(stderr, "Usage: fpga_compress <infile1> <infile2> ... <infile_n> <outfile>\n");
+       fprintf(stderr, "          Combine n FPGA bitstream files and compress them into one.\n\n");
+       fprintf(stderr, "       fpga_compress -d <infile> <outfile>");
+       fprintf(stderr, "          Decompress <infile>. Write result to <outfile>");
+}
+
+
+static voidpf fpga_deflate_malloc(voidpf opaque, uInt items, uInt size)
+{
+       return malloc(items*size);
+}
+
+
+static void fpga_deflate_free(voidpf opaque, voidpf address)
+{
+       return free(address);
+}
+
+
+static bool all_feof(FILE *infile[], uint8_t num_infiles)
+{
+       for (uint16_t i = 0; i < num_infiles; i++) {
+               if (!feof(infile[i])) {
+                       return false;
+               }
+       }
+       
+       return true;
+}
+
+
+int zlib_compress(FILE *infile[], uint8_t num_infiles, FILE *outfile)
+{
+       uint8_t *fpga_config;
+       uint32_t i;
+       int ret;
+       uint8_t c;              
+       z_stream compressed_fpga_stream;
+
+       fpga_config = malloc(num_infiles * FPGA_CONFIG_SIZE);
+       
+       // read the input files. Interleave them into fpga_config[]
+       i = 0;
+       do {
+
+               if (i >= num_infiles * FPGA_CONFIG_SIZE) {
+                       fprintf(stderr, "Input files too big (total > %lu bytes). These are probably not PM3 FPGA config files.\n", num_infiles*FPGA_CONFIG_SIZE);
+                       for(uint16_t j = 0; j < num_infiles; j++) {
+                               fclose(infile[j]);
+                       }
+                       return(EXIT_FAILURE);
+               }
+
+               for(uint16_t j = 0; j < num_infiles; j++) {
+                       for(uint16_t k = 0; k < FPGA_INTERLEAVE_SIZE; k++) {
+                               c = fgetc(infile[j]);
+                               if (!feof(infile[j])) {
+                                       fpga_config[i++] = c;
+                               } else if (num_infiles > 1) {
+                                       fpga_config[i++] = '\0';
+                               }
+                       }
+               }
+
+       } while (!all_feof(infile, num_infiles));
+
+       // initialize zlib structures
+       compressed_fpga_stream.next_in = fpga_config;
+       compressed_fpga_stream.avail_in = i;
+       compressed_fpga_stream.zalloc = fpga_deflate_malloc;
+       compressed_fpga_stream.zfree = fpga_deflate_free;
+       
+       ret = deflateInit2(&compressed_fpga_stream, 
+                                               COMPRESS_LEVEL,
+                                               Z_DEFLATED,
+                                               COMPRESS_WINDOW_BITS,
+                                               COMPRESS_MEM_LEVEL,
+                                               COMPRESS_STRATEGY);
+
+       // estimate the size of the compressed output
+       unsigned int outsize_max = deflateBound(&compressed_fpga_stream, compressed_fpga_stream.avail_in);
+       uint8_t *outbuf = malloc(outsize_max);
+       compressed_fpga_stream.next_out = outbuf;
+       compressed_fpga_stream.avail_out = outsize_max;
+                                       
+       if (ret == Z_OK) {
+               ret = deflateTune(&compressed_fpga_stream,
+                                                       COMPRESS_GOOD_LENGTH,
+                                                       COMPRESS_MAX_LAZY,
+                                                       COMPRESS_MAX_NICE_LENGTH,
+                                                       COMPRESS_MAX_CHAIN);
+       }
+       
+       if (ret == Z_OK) {
+               ret = deflate(&compressed_fpga_stream, Z_FINISH);
+       }
+       
+       fprintf(stderr, "compressed %lu input bytes to %lu output bytes\n", i, compressed_fpga_stream.total_out);
+
+       if (ret != Z_STREAM_END) {
+               fprintf(stderr, "Error in deflate(): %d %s\n", ret, compressed_fpga_stream.msg);
+               free(outbuf);
+               deflateEnd(&compressed_fpga_stream);
+               for(uint16_t j = 0; j < num_infiles; j++) {
+                       fclose(infile[j]);
+               }
+               fclose(outfile);
+               free(infile);
+               free(fpga_config);
+               return(EXIT_FAILURE);
+               }
+               
+       for (i = 0; i < compressed_fpga_stream.total_out; i++) {
+               fputc(outbuf[i], outfile);
+       }       
+
+       free(outbuf);
+       deflateEnd(&compressed_fpga_stream);
+       for(uint16_t j = 0; j < num_infiles; j++) {
+               fclose(infile[j]);
+       }
+       fclose(outfile);
+       free(infile);
+       free(fpga_config);
+       
+       return(EXIT_SUCCESS);
+       
+}
+
+
+int zlib_decompress(FILE *infile, FILE *outfile)
+{
+       #define DECOMPRESS_BUF_SIZE 1024
+       uint8_t outbuf[DECOMPRESS_BUF_SIZE];
+       uint8_t inbuf[DECOMPRESS_BUF_SIZE];
+       int ret;
+       
+       z_stream compressed_fpga_stream;
+
+       // initialize zlib structures
+       compressed_fpga_stream.next_in = inbuf;
+       compressed_fpga_stream.avail_in = 0;
+       compressed_fpga_stream.next_out = outbuf;
+       compressed_fpga_stream.avail_out = DECOMPRESS_BUF_SIZE;
+       compressed_fpga_stream.zalloc = fpga_deflate_malloc;
+       compressed_fpga_stream.zfree = fpga_deflate_free;
+       
+       ret = inflateInit2(&compressed_fpga_stream, 0);
+       
+       do {
+               if (compressed_fpga_stream.avail_in == 0) {
+                       compressed_fpga_stream.next_in = inbuf;
+                       uint16_t i = 0;
+                       do {
+                               uint8_t c = fgetc(infile);
+                               if (!feof(infile)) {
+                                       inbuf[i++] = c;
+                                       compressed_fpga_stream.avail_in++;
+                               } else {
+                                       break;
+                               }
+                       } while (i < DECOMPRESS_BUF_SIZE);
+               }
+
+               ret = inflate(&compressed_fpga_stream, Z_SYNC_FLUSH);
+
+               if (ret != Z_OK && ret != Z_STREAM_END) {
+                       break;
+               }
+
+               if (compressed_fpga_stream.avail_out == 0) {
+                       for (uint16_t i = 0; i < DECOMPRESS_BUF_SIZE; i++) {
+                               fputc(outbuf[i], outfile);
+                       }
+                       compressed_fpga_stream.avail_out = DECOMPRESS_BUF_SIZE;
+                       compressed_fpga_stream.next_out = outbuf;
+               }
+       } while (ret == Z_OK);
+
+       if (ret == Z_STREAM_END) {  // reached end of input
+               uint16_t i = 0;
+               while (compressed_fpga_stream.avail_out < DECOMPRESS_BUF_SIZE) {
+                       fputc(outbuf[i++], outfile);
+                       compressed_fpga_stream.avail_out++;
+               }
+               fclose(outfile);
+               fclose(infile);
+               return(EXIT_SUCCESS);
+       } else {
+               fprintf(stderr, "Error. Inflate() returned error %d, %s", ret, compressed_fpga_stream.msg);
+               fclose(outfile);
+               fclose(infile);
+               return(EXIT_FAILURE);
+       }
+       
+}
+
+
+int main(int argc, char **argv)
+{
+       FILE **infiles;
+       FILE *outfile;
+       
+       if (argc == 1 || argc == 2) {
+               usage();
+               return(EXIT_FAILURE);
+       }
+       
+       if (!strcmp(argv[1], "-d")) {                   // Decompress
+               infiles = calloc(1, sizeof(FILE*));
+               if (argc != 4) {
+                       usage();
+                       return(EXIT_FAILURE);
+               } 
+               infiles[0] = fopen(argv[2], "rb");
+               if (infiles[0] == NULL) {
+                       fprintf(stderr, "Error. Cannot open input file %s", argv[2]);
+                       return(EXIT_FAILURE);
+               }
+               outfile = fopen(argv[3], "wb");
+               if (outfile == NULL) {
+                       fprintf(stderr, "Error. Cannot open output file %s", argv[3]);
+                       return(EXIT_FAILURE);
+               }
+               return zlib_decompress(infiles[0], outfile);
+
+       } else {                                                                // Compress
+
+               infiles = calloc(argc-2, sizeof(FILE*));
+               for (uint16_t i = 0; i < argc-2; i++) { 
+                       infiles[i] = fopen(argv[i+1], "rb");
+                       if (infiles[i] == NULL) {
+                               fprintf(stderr, "Error. Cannot open input file %s", argv[i+1]);
+                               return(EXIT_FAILURE);
+                       }
+               }
+               outfile = fopen(argv[argc-1], "wb");
+               if (outfile == NULL) {
+                       fprintf(stderr, "Error. Cannot open output file %s", argv[argc-1]);
+                       return(EXIT_FAILURE);
+               }
+               return zlib_compress(infiles, argc-2, outfile);
+       }
+}
index c5b91f99783830e3274d54169aa4ae4a289f02bb..b3a7f4ec94c3e3663fc3db40fb9de301dbb1d065 100644 (file)
@@ -89,7 +89,6 @@ typedef struct {
 
 // For the 13.56 MHz tags
 #define CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693                             0x0300
-#define CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443                             0x0301
 #define CMD_READ_SRI512_TAG                                               0x0303
 #define CMD_READ_SRIX4K_TAG                                               0x0304
 #define CMD_READER_ISO_15693                                              0x0310
@@ -105,9 +104,8 @@ typedef struct {
 #define CMD_SIMULATE_HITAG                                                0x0371
 #define CMD_READER_HITAG                                                  0x0372
 
-#define CMD_SIMULATE_TAG_HF_LISTEN                                        0x0380
-#define CMD_SIMULATE_TAG_ISO_14443                                        0x0381
-#define CMD_SNOOP_ISO_14443                                               0x0382
+#define CMD_SIMULATE_TAG_ISO_14443B                                       0x0381
+#define CMD_SNOOP_ISO_14443B                                              0x0382
 #define CMD_SNOOP_ISO_14443a                                              0x0383
 #define CMD_SIMULATE_TAG_ISO_14443a                                       0x0384
 #define CMD_READER_ISO_14443a                                             0x0385
index 678c745ec65cc2afd8b0583ed99ec3d74489c80f..4c7bc638319d39066227f769c4ee662720a58707 100644 (file)
@@ -59,7 +59,6 @@ local _commands = {
 
        --// For the 13.56 MHz tags
        CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693 =                              0x0300,
-       CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443 =                              0x0301,
        CMD_READ_SRI512_TAG =                                                0x0303,
        CMD_READ_SRIX4K_TAG =                                                0x0304,
        CMD_READER_ISO_15693 =                                               0x0310,
@@ -76,9 +75,8 @@ local _commands = {
        CMD_SIMULATE_HITAG =                                                 0x0371,
        CMD_READER_HITAG =                                                   0x0372,
 
-       CMD_SIMULATE_TAG_HF_LISTEN =                                         0x0380,
-       CMD_SIMULATE_TAG_ISO_14443 =                                         0x0381,
-       CMD_SNOOP_ISO_14443 =                                                0x0382,
+       CMD_SIMULATE_TAG_ISO_14443B =                                        0x0381,
+       CMD_SNOOP_ISO_14443B =                                               0x0382,
        CMD_SNOOP_ISO_14443a =                                               0x0383,
        CMD_SIMULATE_TAG_ISO_14443a =                                        0x0384,
        CMD_READER_ISO_14443a =                                              0x0385,
index 0e2a698c1b8ca3783f2a1bc16d980539c423ce22..2f370308f9cb4bcb3a1d09bcd89fe414161efe6f 100644 (file)
@@ -24,7 +24,7 @@
 #include "ui.h"
 #include "sleep.h"
 #include "cmdparser.h"
-#include "cmdmain.h"
+#include "cmdhw.h"
 
 // a global mutex to prevent interlaced printing from different threads
 pthread_mutex_t print_lock;
@@ -105,6 +105,8 @@ static void *main_loop(void *targ) {
        if (arg->usb_present == 1) {
                rarg.run = 1;
                pthread_create(&reader_thread, NULL, &uart_receiver, &rarg);
+               // cache Version information now:
+               CmdVersion(NULL);
        }
 
        FILE *script_file = NULL;
index 2b2bb2fbd7c47fa514d5d2c05dadd890b9a69400..98ff4d0d8aa2ae64b5caf4d74b63c6d22d0a77f7 100644 (file)
@@ -25,6 +25,7 @@ CC    = $(CROSS)gcc
 AS     = $(CROSS)as
 LD     = $(CROSS)ld
 OBJCOPY = $(CROSS)objcopy
+GZIP=gzip
 
 OBJDIR = obj
 
@@ -61,8 +62,8 @@ DETECTED_OS=Windows
 endif
 
 
-# Also search prerequisites in the common directory (for usb.c), and the fpga directory (for fpga.bit)
-VPATH = . ../common/ ../fpga/
+# Also search prerequisites in the common directory (for usb.c), the fpga directory (for fpga.bit), and the zlib directory
+VPATH = . ../common ../fpga ../zlib
 
 INCLUDES = ../include/proxmark3.h ../include/at91sam7s512.h ../include/config_gpio.h ../include/usb_cmd.h $(APP_INCLUDES)
 
@@ -71,9 +72,9 @@ LDFLAGS = -nostartfiles -nodefaultlibs -Wl,-gc-sections -n
 
 LIBS = -lgcc
 
-THUMBOBJ = $(patsubst %.c,$(OBJDIR)/%.o,$(THUMBSRC))
-ARMOBJ   = $(ARMSRC:%.c=$(OBJDIR)/%.o)
-ASMOBJ   = $(patsubst %.s,$(OBJDIR)/%.o,$(ASMSRC))
+THUMBOBJ = $(patsubst %.c,$(OBJDIR)/%.o,$(notdir $(THUMBSRC)))
+ARMOBJ   = $(patsubst %.c,$(OBJDIR)/%.o,$(notdir $(ARMSRC)))
+ASMOBJ   = $(patsubst %.s,$(OBJDIR)/%.o,$(notdir $(ASMSRC)))
 VERSIONOBJ = $(OBJDIR)/version.o
 
 $(THUMBOBJ): $(OBJDIR)/%.o: %.c $(INCLUDES)
@@ -109,6 +110,7 @@ DEPENDENCY_FILES = $(patsubst %.c,$(OBJDIR)/%.d,$(notdir $(THUMBSRC))) \
        $(patsubst %.s,$(OBJDIR)/%.d,$(notdir $(ASMSRC)))
 
 $(DEPENDENCY_FILES): Makefile ../common/Makefile.common
+
 $(patsubst %.o,%.d,$(THUMBOBJ) $(ARMOBJ)): $(OBJDIR)/%.d: %.c
        @$(CC) -MM -MT "$(@) $(@:.d=.o)" $(CFLAGS) $< > $@
 $(patsubst %.o,%.d,$(ASMOBJ)):$(OBJDIR)/%.d: %.s
index 6a4c9a103bff1a03ebb21215e968b54bc9aa7f09..aa80491b58f2b94d61313e01e1b4b4a2f64ac6a5 100644 (file)
@@ -1,4 +1,3 @@
-#include <stdio.h>
 #include <strings.h>
 #include <string.h>
 #include <stdint.h>
index 20fb2bd4401254d899d6273451bfccbd827f562b..50c7eef97c8b98461b7d8be9e4e643dd85910241 100644 (file)
Binary files a/fpga/fpga_hf.bit and b/fpga/fpga_hf.bit differ
index a2100df65f5212761b03b1f4ba1e7a53d8d67ca0..8a465e75c5304452b598d5d28d5f2f4ae16f8c6f 100644 (file)
@@ -73,9 +73,6 @@ wire hi_read_rx_xcorr_848 = conf_word[0];
 // and whether to drive the coil (reader) or just short it (snooper)
 wire hi_read_rx_xcorr_snoop = conf_word[1];
 
-// Divide the expected subcarrier frequency for hi_read_rx_xcorr by 4
-wire hi_read_rx_xcorr_quarter = conf_word[2];
-
 // For the high-frequency simulated tag: what kind of modulation to use.
 wire [2:0] hi_simulate_mod_type = conf_word[2:0];
 
@@ -102,7 +99,7 @@ hi_read_rx_xcorr hrxc(
        hrxc_ssp_frame, hrxc_ssp_din, ssp_dout, hrxc_ssp_clk,
        cross_hi, cross_lo,
        hrxc_dbg,
-       hi_read_rx_xcorr_848, hi_read_rx_xcorr_snoop, hi_read_rx_xcorr_quarter
+       hi_read_rx_xcorr_848, hi_read_rx_xcorr_snoop
 );
 
 hi_simulate hs(
index dece2db3195844ce9ce2d371d09a1ff7df0069bf..afaf7cb6fb17ae0a1f5687a9b48601ead3d65c23 100644 (file)
@@ -10,7 +10,7 @@ module hi_read_rx_xcorr(
     ssp_frame, ssp_din, ssp_dout, ssp_clk,
     cross_hi, cross_lo,
     dbg,
-    xcorr_is_848, snoop, xcorr_quarter_freq
+    xcorr_is_848, snoop
 );
     input pck0, ck_1356meg, ck_1356megb;
     output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4;
@@ -20,58 +20,24 @@ module hi_read_rx_xcorr(
     output ssp_frame, ssp_din, ssp_clk;
     input cross_hi, cross_lo;
     output dbg;
-    input xcorr_is_848, snoop, xcorr_quarter_freq;
+    input xcorr_is_848, snoop;
 
 // Carrier is steady on through this, unless we're snooping.
 assign pwr_hi = ck_1356megb & (~snoop);
 assign pwr_oe1 = 1'b0;
-assign pwr_oe2 = 1'b0;
 assign pwr_oe3 = 1'b0;
 assign pwr_oe4 = 1'b0;
 
-reg ssp_clk;
-reg ssp_frame;
+wire adc_clk = ck_1356megb;
 
 reg fc_div_2;
-always @(posedge ck_1356meg)
-    fc_div_2 = ~fc_div_2;
-
-reg fc_div_4;
-always @(posedge fc_div_2)
-    fc_div_4 = ~fc_div_4;
-
-reg fc_div_8;
-always @(posedge fc_div_4)
-    fc_div_8 = ~fc_div_8;
-
-reg adc_clk;
-
-always @(xcorr_is_848 or xcorr_quarter_freq or ck_1356meg)
-    if(~xcorr_quarter_freq)
-    begin
-           if(xcorr_is_848)
-               // The subcarrier frequency is fc/16; we will sample at fc, so that 
-               // means the subcarrier is 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 ...
-               adc_clk <= ck_1356meg;
-           else
-               // The subcarrier frequency is fc/32; we will sample at fc/2, and
-               // the subcarrier will look identical.
-               adc_clk <= fc_div_2;
-    end
-    else
-    begin
-           if(xcorr_is_848)
-               // The subcarrier frequency is fc/64
-               adc_clk <= fc_div_4;
-           else
-               // The subcarrier frequency is fc/128
-               adc_clk <= fc_div_8;
-       end
+always @(negedge ck_1356megb)
+    fc_div_2 <= fc_div_2 + 1;
 
 // When we're a reader, we just need to do the BPSK demod; but when we're an
 // eavesdropper, we also need to pick out the commands sent by the reader,
 // using AM. Do this the same way that we do it for the simulated tag.
-reg after_hysteresis, after_hysteresis_prev;
+reg after_hysteresis, after_hysteresis_prev, after_hysteresis_prev_prev;
 reg [11:0] has_been_low_for;
 always @(negedge adc_clk)
 begin
@@ -97,12 +63,24 @@ end
 // Let us report a correlation every 4 subcarrier cycles, or 4*16 samples,
 // so we need a 6-bit counter.
 reg [5:0] corr_i_cnt;
-reg [5:0] corr_q_cnt;
 // And a couple of registers in which to accumulate the correlations.
-reg signed [15:0] corr_i_accum;
-reg signed [15:0] corr_q_accum;
+// we would add at most 32 times adc_d, the result can be held in 13 bits. 
+// Need one additional bit because it can be negative as well
+reg signed [13:0] corr_i_accum;
+reg signed [13:0] corr_q_accum;
 reg signed [7:0] corr_i_out;
 reg signed [7:0] corr_q_out;
+// clock and frame signal for communication to ARM
+reg ssp_clk;
+reg ssp_frame;
+
+
+always @(negedge adc_clk)
+begin
+       if (xcorr_is_848 | fc_div_2)
+               corr_i_cnt <= corr_i_cnt + 1;
+end            
+               
 
 // ADC data appears on the rising edge, so sample it on the falling edge
 always @(negedge adc_clk)
@@ -110,24 +88,24 @@ begin
     // These are the correlators: we correlate against in-phase and quadrature
     // versions of our reference signal, and keep the (signed) result to
     // send out later over the SSP.
-    if(corr_i_cnt == 7'd63)
+    if(corr_i_cnt == 6'd0)
     begin
         if(snoop)
         begin
-            corr_i_out <= {corr_i_accum[12:6], after_hysteresis_prev};
-            corr_q_out <= {corr_q_accum[12:6], after_hysteresis};
+                       // Send only 7 most significant bits of tag signal (signed), LSB is reader signal:
+            corr_i_out <= {corr_i_accum[13:7], after_hysteresis_prev_prev};
+            corr_q_out <= {corr_q_accum[13:7], after_hysteresis_prev};
+                       after_hysteresis_prev_prev <= after_hysteresis;
         end
         else
         begin
-            // Only correlations need to be delivered.
+            // 8 most significant bits of tag signal
             corr_i_out <= corr_i_accum[13:6];
             corr_q_out <= corr_q_accum[13:6];
         end
 
         corr_i_accum <= adc_d;
         corr_q_accum <= adc_d;
-        corr_q_cnt <= 4;
-        corr_i_cnt <= 0;
     end
     else
     begin
@@ -136,18 +114,16 @@ begin
         else
             corr_i_accum <= corr_i_accum + adc_d;
 
-        if(corr_q_cnt[3])
-            corr_q_accum <= corr_q_accum - adc_d;
-        else
+        if(corr_i_cnt[3] == corr_i_cnt[2])                     // phase shifted by pi/2
             corr_q_accum <= corr_q_accum + adc_d;
+        else
+            corr_q_accum <= corr_q_accum - adc_d;
 
-        corr_i_cnt <= corr_i_cnt + 1;
-        corr_q_cnt <= corr_q_cnt + 1;
     end
 
     // The logic in hi_simulate.v reports 4 samples per bit. We report two
     // (I, Q) pairs per bit, so we should do 2 samples per pair.
-    if(corr_i_cnt == 6'd31)
+    if(corr_i_cnt == 6'd32)
         after_hysteresis_prev <= after_hysteresis;
 
     // Then the result from last time is serialized and send out to the ARM.
@@ -168,7 +144,9 @@ begin
         end
     end
 
-    if(corr_i_cnt[5:2] == 4'b000 || corr_i_cnt[5:2] == 4'b1000)
+       // set ssp_frame signal for corr_i_cnt = 0..3 and corr_i_cnt = 32..35
+       // (send two frames with 8 Bits each)
+    if(corr_i_cnt[5:2] == 4'b0000 || corr_i_cnt[5:2] == 4'b1000)
         ssp_frame = 1'b1;
     else
         ssp_frame = 1'b0;
@@ -181,5 +159,6 @@ assign dbg = corr_i_cnt[3];
 
 // Unused.
 assign pwr_lo = 1'b0;
+assign pwr_oe2 = 1'b0;
 
 endmodule
index b3530c64f2ae22b920458e05e4f483340b1baac4..4a59636e7f6cc156e438a332208116ccd3eb9439 100644 (file)
 #define SPI_FPGA_MODE  0
 #define SPI_LCD_MODE   1
 
-#define FPGA_BITSTREAM_ERR 0
-#define FPGA_BITSTREAM_LF 1
-#define FPGA_BITSTREAM_HF 2
-
 #define TRUE 1
 #define FALSE 0
 
index 357395d43f3103eb01a66144648dbd2e97d001e9..524554e9384b1db9c715a182df6bddf08431c3b2 100644 (file)
@@ -100,7 +100,6 @@ typedef struct{
 
 // For the 13.56 MHz tags
 #define CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693                             0x0300
-#define CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443                             0x0301
 #define CMD_READ_SRI512_TAG                                               0x0303
 #define CMD_READ_SRIX4K_TAG                                               0x0304
 #define CMD_ISO_14443B_COMMAND                                            0x0305
@@ -118,9 +117,8 @@ typedef struct{
 #define CMD_SIMULATE_HITAG                                                0x0371
 #define CMD_READER_HITAG                                                  0x0372
 
-#define CMD_SIMULATE_TAG_HF_LISTEN                                        0x0380
-#define CMD_SIMULATE_TAG_ISO_14443                                        0x0381
-#define CMD_SNOOP_ISO_14443                                               0x0382
+#define CMD_SIMULATE_TAG_ISO_14443B                                       0x0381
+#define CMD_SNOOP_ISO_14443B                                              0x0382
 #define CMD_SNOOP_ISO_14443a                                              0x0383
 #define CMD_SIMULATE_TAG_ISO_14443a                                       0x0384
 #define CMD_READER_ISO_14443a                                             0x0385
@@ -128,6 +126,7 @@ typedef struct{
 #define CMD_READER_LEGIC_RF                                               0x0388
 #define CMD_WRITER_LEGIC_RF                                               0x0389
 #define CMD_EPA_PACE_COLLECT_NONCE                                        0x038A
+#define CMD_EPA_PACE_REPLAY                                               0x038B
 
 #define CMD_SNOOP_ICLASS                                                  0x0392
 #define CMD_SIMULATE_TAG_ICLASS                                           0x0393
diff --git a/zlib/ChangeLog b/zlib/ChangeLog
new file mode 100644 (file)
index 0000000..b996515
--- /dev/null
@@ -0,0 +1,1481 @@
+
+                ChangeLog file for zlib
+
+Changes in 1.2.8.f-Proxmark3 (for Proxmark3 project only) (26 May 2015)
+- disable decoding of fixed code blocks in deflate (eliminates the need
+  to store the fixed tree in RAM or ROM)
+- disable generating fixed code blocks in inflate  
+- look harder for local optimum of consecutive matches and single literals
+  in inflate.
+- stripped down version - unnecessary files from original distribution
+  are not included
+
+Changes in 1.2.8 (28 Apr 2013)
+- Update contrib/minizip/iowin32.c for Windows RT [Vollant]
+- Do not force Z_CONST for C++
+- Clean up contrib/vstudio [Ro§]
+- Correct spelling error in zlib.h
+- Fix mixed line endings in contrib/vstudio
+
+Changes in 1.2.7.3 (13 Apr 2013)
+- Fix version numbers and DLL names in contrib/vstudio/*/zlib.rc
+
+Changes in 1.2.7.2 (13 Apr 2013)
+- Change check for a four-byte type back to hexadecimal
+- Fix typo in win32/Makefile.msc
+- Add casts in gzwrite.c for pointer differences
+
+Changes in 1.2.7.1 (24 Mar 2013)
+- Replace use of unsafe string functions with snprintf if available
+- Avoid including stddef.h on Windows for Z_SOLO compile [Niessink]
+- Fix gzgetc undefine when Z_PREFIX set [Turk]
+- Eliminate use of mktemp in Makefile (not always available)
+- Fix bug in 'F' mode for gzopen()
+- Add inflateGetDictionary() function
+- Correct comment in deflate.h
+- Use _snprintf for snprintf in Microsoft C
+- On Darwin, only use /usr/bin/libtool if libtool is not Apple
+- Delete "--version" file if created by "ar --version" [Richard G.]
+- Fix configure check for veracity of compiler error return codes
+- Fix CMake compilation of static lib for MSVC2010 x64
+- Remove unused variable in infback9.c
+- Fix argument checks in gzlog_compress() and gzlog_write()
+- Clean up the usage of z_const and respect const usage within zlib
+- Clean up examples/gzlog.[ch] comparisons of different types
+- Avoid shift equal to bits in type (caused endless loop)
+- Fix unintialized value bug in gzputc() introduced by const patches
+- Fix memory allocation error in examples/zran.c [Nor]
+- Fix bug where gzopen(), gzclose() would write an empty file
+- Fix bug in gzclose() when gzwrite() runs out of memory
+- Check for input buffer malloc failure in examples/gzappend.c
+- Add note to contrib/blast to use binary mode in stdio
+- Fix comparisons of differently signed integers in contrib/blast
+- Check for invalid code length codes in contrib/puff
+- Fix serious but very rare decompression bug in inftrees.c
+- Update inflateBack() comments, since inflate() can be faster
+- Use underscored I/O function names for WINAPI_FAMILY
+- Add _tr_flush_bits to the external symbols prefixed by --zprefix
+- Add contrib/vstudio/vc10 pre-build step for static only
+- Quote --version-script argument in CMakeLists.txt
+- Don't specify --version-script on Apple platforms in CMakeLists.txt
+- Fix casting error in contrib/testzlib/testzlib.c
+- Fix types in contrib/minizip to match result of get_crc_table()
+- Simplify contrib/vstudio/vc10 with 'd' suffix
+- Add TOP support to win32/Makefile.msc
+- Suport i686 and amd64 assembler builds in CMakeLists.txt
+- Fix typos in the use of _LARGEFILE64_SOURCE in zconf.h
+- Add vc11 and vc12 build files to contrib/vstudio
+- Add gzvprintf() as an undocumented function in zlib
+- Fix configure for Sun shell
+- Remove runtime check in configure for four-byte integer type
+- Add casts and consts to ease user conversion to C++
+- Add man pages for minizip and miniunzip
+- In Makefile uninstall, don't rm if preceding cd fails
+- Do not return Z_BUF_ERROR if deflateParam() has nothing to write
+
+Changes in 1.2.7 (2 May 2012)
+- Replace use of memmove() with a simple copy for portability
+- Test for existence of strerror
+- Restore gzgetc_ for backward compatibility with 1.2.6
+- Fix build with non-GNU make on Solaris
+- Require gcc 4.0 or later on Mac OS X to use the hidden attribute
+- Include unistd.h for Watcom C
+- Use __WATCOMC__ instead of __WATCOM__
+- Do not use the visibility attribute if NO_VIZ defined
+- Improve the detection of no hidden visibility attribute
+- Avoid using __int64 for gcc or solo compilation
+- Cast to char * in gzprintf to avoid warnings [Zinser]
+- Fix make_vms.com for VAX [Zinser]
+- Don't use library or built-in byte swaps
+- Simplify test and use of gcc hidden attribute
+- Fix bug in gzclose_w() when gzwrite() fails to allocate memory
+- Add "x" (O_EXCL) and "e" (O_CLOEXEC) modes support to gzopen()
+- Fix bug in test/minigzip.c for configure --solo
+- Fix contrib/vstudio project link errors [Mohanathas]
+- Add ability to choose the builder in make_vms.com [Schweda]
+- Add DESTDIR support to mingw32 win32/Makefile.gcc
+- Fix comments in win32/Makefile.gcc for proper usage
+- Allow overriding the default install locations for cmake
+- Generate and install the pkg-config file with cmake
+- Build both a static and a shared version of zlib with cmake
+- Include version symbols for cmake builds
+- If using cmake with MSVC, add the source directory to the includes
+- Remove unneeded EXTRA_CFLAGS from win32/Makefile.gcc [Truta]
+- Move obsolete emx makefile to old [Truta]
+- Allow the use of -Wundef when compiling or using zlib
+- Avoid the use of the -u option with mktemp
+- Improve inflate() documentation on the use of Z_FINISH
+- Recognize clang as gcc
+- Add gzopen_w() in Windows for wide character path names
+- Rename zconf.h in CMakeLists.txt to move it out of the way
+- Add source directory in CMakeLists.txt for building examples
+- Look in build directory for zlib.pc in CMakeLists.txt
+- Remove gzflags from zlibvc.def in vc9 and vc10
+- Fix contrib/minizip compilation in the MinGW environment
+- Update ./configure for Solaris, support --64 [Mooney]
+- Remove -R. from Solaris shared build (possible security issue)
+- Avoid race condition for parallel make (-j) running example
+- Fix type mismatch between get_crc_table() and crc_table
+- Fix parsing of version with "-" in CMakeLists.txt [Snider, Ziegler]
+- Fix the path to zlib.map in CMakeLists.txt
+- Force the native libtool in Mac OS X to avoid GNU libtool [Beebe]
+- Add instructions to win32/Makefile.gcc for shared install [Torri]
+
+Changes in 1.2.6.1 (12 Feb 2012)
+- Avoid the use of the Objective-C reserved name "id"
+- Include io.h in gzguts.h for Microsoft compilers
+- Fix problem with ./configure --prefix and gzgetc macro
+- Include gz_header definition when compiling zlib solo
+- Put gzflags() functionality back in zutil.c
+- Avoid library header include in crc32.c for Z_SOLO
+- Use name in GCC_CLASSIC as C compiler for coverage testing, if set
+- Minor cleanup in contrib/minizip/zip.c [Vollant]
+- Update make_vms.com [Zinser]
+- Remove unnecessary gzgetc_ function
+- Use optimized byte swap operations for Microsoft and GNU [Snyder]
+- Fix minor typo in zlib.h comments [Rzesniowiecki]
+
+Changes in 1.2.6 (29 Jan 2012)
+- Update the Pascal interface in contrib/pascal
+- Fix function numbers for gzgetc_ in zlibvc.def files
+- Fix configure.ac for contrib/minizip [Schiffer]
+- Fix large-entry detection in minizip on 64-bit systems [Schiffer]
+- Have ./configure use the compiler return code for error indication
+- Fix CMakeLists.txt for cross compilation [McClure]
+- Fix contrib/minizip/zip.c for 64-bit architectures [Dalsnes]
+- Fix compilation of contrib/minizip on FreeBSD [Marquez]
+- Correct suggested usages in win32/Makefile.msc [Shachar, Horvath]
+- Include io.h for Turbo C / Borland C on all platforms [Truta]
+- Make version explicit in contrib/minizip/configure.ac [Bosmans]
+- Avoid warning for no encryption in contrib/minizip/zip.c [Vollant]
+- Minor cleanup up contrib/minizip/unzip.c [Vollant]
+- Fix bug when compiling minizip with C++ [Vollant]
+- Protect for long name and extra fields in contrib/minizip [Vollant]
+- Avoid some warnings in contrib/minizip [Vollant]
+- Add -I../.. -L../.. to CFLAGS for minizip and miniunzip
+- Add missing libs to minizip linker command
+- Add support for VPATH builds in contrib/minizip
+- Add an --enable-demos option to contrib/minizip/configure
+- Add the generation of configure.log by ./configure
+- Exit when required parameters not provided to win32/Makefile.gcc
+- Have gzputc return the character written instead of the argument
+- Use the -m option on ldconfig for BSD systems [Tobias]
+- Correct in zlib.map when deflateResetKeep was added
+
+Changes in 1.2.5.3 (15 Jan 2012)
+- Restore gzgetc function for binary compatibility
+- Do not use _lseeki64 under Borland C++ [Truta]
+- Update win32/Makefile.msc to build test/*.c [Truta]
+- Remove old/visualc6 given CMakefile and other alternatives
+- Update AS400 build files and documentation [Monnerat]
+- Update win32/Makefile.gcc to build test/*.c [Truta]
+- Permit stronger flushes after Z_BLOCK flushes
+- Avoid extraneous empty blocks when doing empty flushes
+- Permit Z_NULL arguments to deflatePending
+- Allow deflatePrime() to insert bits in the middle of a stream
+- Remove second empty static block for Z_PARTIAL_FLUSH
+- Write out all of the available bits when using Z_BLOCK
+- Insert the first two strings in the hash table after a flush
+
+Changes in 1.2.5.2 (17 Dec 2011)
+- fix ld error: unable to find version dependency 'ZLIB_1.2.5'
+- use relative symlinks for shared libs
+- Avoid searching past window for Z_RLE strategy
+- Assure that high-water mark initialization is always applied in deflate
+- Add assertions to fill_window() in deflate.c to match comments
+- Update python link in README
+- Correct spelling error in gzread.c
+- Fix bug in gzgets() for a concatenated empty gzip stream
+- Correct error in comment for gz_make()
+- Change gzread() and related to ignore junk after gzip streams
+- Allow gzread() and related to continue after gzclearerr()
+- Allow gzrewind() and gzseek() after a premature end-of-file
+- Simplify gzseek() now that raw after gzip is ignored
+- Change gzgetc() to a macro for speed (~40% speedup in testing)
+- Fix gzclose() to return the actual error last encountered
+- Always add large file support for windows
+- Include zconf.h for windows large file support
+- Include zconf.h.cmakein for windows large file support
+- Update zconf.h.cmakein on make distclean
+- Merge vestigial vsnprintf determination from zutil.h to gzguts.h
+- Clarify how gzopen() appends in zlib.h comments
+- Correct documentation of gzdirect() since junk at end now ignored
+- Add a transparent write mode to gzopen() when 'T' is in the mode
+- Update python link in zlib man page
+- Get inffixed.h and MAKEFIXED result to match
+- Add a ./config --solo option to make zlib subset with no libary use
+- Add undocumented inflateResetKeep() function for CAB file decoding
+- Add --cover option to ./configure for gcc coverage testing
+- Add #define ZLIB_CONST option to use const in the z_stream interface
+- Add comment to gzdopen() in zlib.h to use dup() when using fileno()
+- Note behavior of uncompress() to provide as much data as it can
+- Add files in contrib/minizip to aid in building libminizip
+- Split off AR options in Makefile.in and configure
+- Change ON macro to Z_ARG to avoid application conflicts
+- Facilitate compilation with Borland C++ for pragmas and vsnprintf
+- Include io.h for Turbo C / Borland C++
+- Move example.c and minigzip.c to test/
+- Simplify incomplete code table filling in inflate_table()
+- Remove code from inflate.c and infback.c that is impossible to execute
+- Test the inflate code with full coverage
+- Allow deflateSetDictionary, inflateSetDictionary at any time (in raw)
+- Add deflateResetKeep and fix inflateResetKeep to retain dictionary
+- Fix gzwrite.c to accommodate reduced memory zlib compilation
+- Have inflate() with Z_FINISH avoid the allocation of a window
+- Do not set strm->adler when doing raw inflate
+- Fix gzeof() to behave just like feof() when read is not past end of file
+- Fix bug in gzread.c when end-of-file is reached
+- Avoid use of Z_BUF_ERROR in gz* functions except for premature EOF
+- Document gzread() capability to read concurrently written files
+- Remove hard-coding of resource compiler in CMakeLists.txt [Blammo]
+
+Changes in 1.2.5.1 (10 Sep 2011)
+- Update FAQ entry on shared builds (#13)
+- Avoid symbolic argument to chmod in Makefile.in
+- Fix bug and add consts in contrib/puff [Oberhumer]
+- Update contrib/puff/zeros.raw test file to have all block types
+- Add full coverage test for puff in contrib/puff/Makefile
+- Fix static-only-build install in Makefile.in
+- Fix bug in unzGetCurrentFileInfo() in contrib/minizip [Kuno]
+- Add libz.a dependency to shared in Makefile.in for parallel builds
+- Spell out "number" (instead of "nb") in zlib.h for total_in, total_out
+- Replace $(...) with `...` in configure for non-bash sh [Bowler]
+- Add darwin* to Darwin* and solaris* to SunOS\ 5* in configure [Groffen]
+- Add solaris* to Linux* in configure to allow gcc use [Groffen]
+- Add *bsd* to Linux* case in configure [Bar-Lev]
+- Add inffast.obj to dependencies in win32/Makefile.msc
+- Correct spelling error in deflate.h [Kohler]
+- Change libzdll.a again to libz.dll.a (!) in win32/Makefile.gcc
+- Add test to configure for GNU C looking for gcc in output of $cc -v
+- Add zlib.pc generation to win32/Makefile.gcc [Weigelt]
+- Fix bug in zlib.h for _FILE_OFFSET_BITS set and _LARGEFILE64_SOURCE not
+- Add comment in zlib.h that adler32_combine with len2 < 0 makes no sense
+- Make NO_DIVIDE option in adler32.c much faster (thanks to John Reiser)
+- Make stronger test in zconf.h to include unistd.h for LFS
+- Apply Darwin patches for 64-bit file offsets to contrib/minizip [Slack]
+- Fix zlib.h LFS support when Z_PREFIX used
+- Add updated as400 support (removed from old) [Monnerat]
+- Avoid deflate sensitivity to volatile input data
+- Avoid division in adler32_combine for NO_DIVIDE
+- Clarify the use of Z_FINISH with deflateBound() amount of space
+- Set binary for output file in puff.c
+- Use u4 type for crc_table to avoid conversion warnings
+- Apply casts in zlib.h to avoid conversion warnings
+- Add OF to prototypes for adler32_combine_ and crc32_combine_ [Miller]
+- Improve inflateSync() documentation to note indeterminancy
+- Add deflatePending() function to return the amount of pending output
+- Correct the spelling of "specification" in FAQ [Randers-Pehrson]
+- Add a check in configure for stdarg.h, use for gzprintf()
+- Check that pointers fit in ints when gzprint() compiled old style
+- Add dummy name before $(SHAREDLIBV) in Makefile [Bar-Lev, Bowler]
+- Delete line in configure that adds -L. libz.a to LDFLAGS [Weigelt]
+- Add debug records in assmebler code [Londer]
+- Update RFC references to use http://tools.ietf.org/html/... [Li]
+- Add --archs option, use of libtool to configure for Mac OS X [Borstel]
+
+Changes in 1.2.5 (19 Apr 2010)
+- Disable visibility attribute in win32/Makefile.gcc [Bar-Lev]
+- Default to libdir as sharedlibdir in configure [Nieder]
+- Update copyright dates on modified source files
+- Update trees.c to be able to generate modified trees.h
+- Exit configure for MinGW, suggesting win32/Makefile.gcc
+- Check for NULL path in gz_open [Homurlu]
+
+Changes in 1.2.4.5 (18 Apr 2010)
+- Set sharedlibdir in configure [Torok]
+- Set LDFLAGS in Makefile.in [Bar-Lev]
+- Avoid mkdir objs race condition in Makefile.in [Bowler]
+- Add ZLIB_INTERNAL in front of internal inter-module functions and arrays
+- Define ZLIB_INTERNAL to hide internal functions and arrays for GNU C
+- Don't use hidden attribute when it is a warning generator (e.g. Solaris)
+
+Changes in 1.2.4.4 (18 Apr 2010)
+- Fix CROSS_PREFIX executable testing, CHOST extract, mingw* [Torok]
+- Undefine _LARGEFILE64_SOURCE in zconf.h if it is zero, but not if empty
+- Try to use bash or ksh regardless of functionality of /bin/sh
+- Fix configure incompatibility with NetBSD sh
+- Remove attempt to run under bash or ksh since have better NetBSD fix
+- Fix win32/Makefile.gcc for MinGW [Bar-Lev]
+- Add diagnostic messages when using CROSS_PREFIX in configure
+- Added --sharedlibdir option to configure [Weigelt]
+- Use hidden visibility attribute when available [Frysinger]
+
+Changes in 1.2.4.3 (10 Apr 2010)
+- Only use CROSS_PREFIX in configure for ar and ranlib if they exist
+- Use CROSS_PREFIX for nm [Bar-Lev]
+- Assume _LARGEFILE64_SOURCE defined is equivalent to true
+- Avoid use of undefined symbols in #if with && and ||
+- Make *64 prototypes in gzguts.h consistent with functions
+- Add -shared load option for MinGW in configure [Bowler]
+- Move z_off64_t to public interface, use instead of off64_t
+- Remove ! from shell test in configure (not portable to Solaris)
+- Change +0 macro tests to -0 for possibly increased portability
+
+Changes in 1.2.4.2 (9 Apr 2010)
+- Add consistent carriage returns to readme.txt's in masmx86 and masmx64
+- Really provide prototypes for *64 functions when building without LFS
+- Only define unlink() in minigzip.c if unistd.h not included
+- Update README to point to contrib/vstudio project files
+- Move projects/vc6 to old/ and remove projects/
+- Include stdlib.h in minigzip.c for setmode() definition under WinCE
+- Clean up assembler builds in win32/Makefile.msc [Rowe]
+- Include sys/types.h for Microsoft for off_t definition
+- Fix memory leak on error in gz_open()
+- Symbolize nm as $NM in configure [Weigelt]
+- Use TEST_LDSHARED instead of LDSHARED to link test programs [Weigelt]
+- Add +0 to _FILE_OFFSET_BITS and _LFS64_LARGEFILE in case not defined
+- Fix bug in gzeof() to take into account unused input data
+- Avoid initialization of structures with variables in puff.c
+- Updated win32/README-WIN32.txt [Rowe]
+
+Changes in 1.2.4.1 (28 Mar 2010)
+- Remove the use of [a-z] constructs for sed in configure [gentoo 310225]
+- Remove $(SHAREDLIB) from LIBS in Makefile.in [Creech]
+- Restore "for debugging" comment on sprintf() in gzlib.c
+- Remove fdopen for MVS from gzguts.h
+- Put new README-WIN32.txt in win32 [Rowe]
+- Add check for shell to configure and invoke another shell if needed
+- Fix big fat stinking bug in gzseek() on uncompressed files
+- Remove vestigial F_OPEN64 define in zutil.h
+- Set and check the value of _LARGEFILE_SOURCE and _LARGEFILE64_SOURCE
+- Avoid errors on non-LFS systems when applications define LFS macros
+- Set EXE to ".exe" in configure for MINGW [Kahle]
+- Match crc32() in crc32.c exactly to the prototype in zlib.h [Sherrill]
+- Add prefix for cross-compilation in win32/makefile.gcc [Bar-Lev]
+- Add DLL install in win32/makefile.gcc [Bar-Lev]
+- Allow Linux* or linux* from uname in configure [Bar-Lev]
+- Allow ldconfig to be redefined in configure and Makefile.in [Bar-Lev]
+- Add cross-compilation prefixes to configure [Bar-Lev]
+- Match type exactly in gz_load() invocation in gzread.c
+- Match type exactly of zcalloc() in zutil.c to zlib.h alloc_func
+- Provide prototypes for *64 functions when building zlib without LFS
+- Don't use -lc when linking shared library on MinGW
+- Remove errno.h check in configure and vestigial errno code in zutil.h
+
+Changes in 1.2.4 (14 Mar 2010)
+- Fix VER3 extraction in configure for no fourth subversion
+- Update zlib.3, add docs to Makefile.in to make .pdf out of it
+- Add zlib.3.pdf to distribution
+- Don't set error code in gzerror() if passed pointer is NULL
+- Apply destination directory fixes to CMakeLists.txt [Lowman]
+- Move #cmakedefine's to a new zconf.in.cmakein
+- Restore zconf.h for builds that don't use configure or cmake
+- Add distclean to dummy Makefile for convenience
+- Update and improve INDEX, README, and FAQ
+- Update CMakeLists.txt for the return of zconf.h [Lowman]
+- Update contrib/vstudio/vc9 and vc10 [Vollant]
+- Change libz.dll.a back to libzdll.a in win32/Makefile.gcc
+- Apply license and readme changes to contrib/asm686 [Raiter]
+- Check file name lengths and add -c option in minigzip.c [Li]
+- Update contrib/amd64 and contrib/masmx86/ [Vollant]
+- Avoid use of "eof" parameter in trees.c to not shadow library variable
+- Update make_vms.com for removal of zlibdefs.h [Zinser]
+- Update assembler code and vstudio projects in contrib [Vollant]
+- Remove outdated assembler code contrib/masm686 and contrib/asm586
+- Remove old vc7 and vc8 from contrib/vstudio
+- Update win32/Makefile.msc, add ZLIB_VER_SUBREVISION [Rowe]
+- Fix memory leaks in gzclose_r() and gzclose_w(), file leak in gz_open()
+- Add contrib/gcc_gvmat64 for longest_match and inflate_fast [Vollant]
+- Remove *64 functions from win32/zlib.def (they're not 64-bit yet)
+- Fix bug in void-returning vsprintf() case in gzwrite.c
+- Fix name change from inflate.h in contrib/inflate86/inffas86.c
+- Check if temporary file exists before removing in make_vms.com [Zinser]
+- Fix make install and uninstall for --static option
+- Fix usage of _MSC_VER in gzguts.h and zutil.h [Truta]
+- Update readme.txt in contrib/masmx64 and masmx86 to assemble
+
+Changes in 1.2.3.9 (21 Feb 2010)
+- Expunge gzio.c
+- Move as400 build information to old
+- Fix updates in contrib/minizip and contrib/vstudio
+- Add const to vsnprintf test in configure to avoid warnings [Weigelt]
+- Delete zconf.h (made by configure) [Weigelt]
+- Change zconf.in.h to zconf.h.in per convention [Weigelt]
+- Check for NULL buf in gzgets()
+- Return empty string for gzgets() with len == 1 (like fgets())
+- Fix description of gzgets() in zlib.h for end-of-file, NULL return
+- Update minizip to 1.1 [Vollant]
+- Avoid MSVC loss of data warnings in gzread.c, gzwrite.c
+- Note in zlib.h that gzerror() should be used to distinguish from EOF
+- Remove use of snprintf() from gzlib.c
+- Fix bug in gzseek()
+- Update contrib/vstudio, adding vc9 and vc10 [Kuno, Vollant]
+- Fix zconf.h generation in CMakeLists.txt [Lowman]
+- Improve comments in zconf.h where modified by configure
+
+Changes in 1.2.3.8 (13 Feb 2010)
+- Clean up text files (tabs, trailing whitespace, etc.) [Oberhumer]
+- Use z_off64_t in gz_zero() and gz_skip() to match state->skip
+- Avoid comparison problem when sizeof(int) == sizeof(z_off64_t)
+- Revert to Makefile.in from 1.2.3.6 (live with the clutter)
+- Fix missing error return in gzflush(), add zlib.h note
+- Add *64 functions to zlib.map [Levin]
+- Fix signed/unsigned comparison in gz_comp()
+- Use SFLAGS when testing shared linking in configure
+- Add --64 option to ./configure to use -m64 with gcc
+- Fix ./configure --help to correctly name options
+- Have make fail if a test fails [Levin]
+- Avoid buffer overrun in contrib/masmx64/gvmat64.asm [Simpson]
+- Remove assembler object files from contrib
+
+Changes in 1.2.3.7 (24 Jan 2010)
+- Always gzopen() with O_LARGEFILE if available
+- Fix gzdirect() to work immediately after gzopen() or gzdopen()
+- Make gzdirect() more precise when the state changes while reading
+- Improve zlib.h documentation in many places
+- Catch memory allocation failure in gz_open()
+- Complete close operation if seek forward in gzclose_w() fails
+- Return Z_ERRNO from gzclose_r() if close() fails
+- Return Z_STREAM_ERROR instead of EOF for gzclose() being passed NULL
+- Return zero for gzwrite() errors to match zlib.h description
+- Return -1 on gzputs() error to match zlib.h description
+- Add zconf.in.h to allow recovery from configure modification [Weigelt]
+- Fix static library permissions in Makefile.in [Weigelt]
+- Avoid warnings in configure tests that hide functionality [Weigelt]
+- Add *BSD and DragonFly to Linux case in configure [gentoo 123571]
+- Change libzdll.a to libz.dll.a in win32/Makefile.gcc [gentoo 288212]
+- Avoid access of uninitialized data for first inflateReset2 call [Gomes]
+- Keep object files in subdirectories to reduce the clutter somewhat
+- Remove default Makefile and zlibdefs.h, add dummy Makefile
+- Add new external functions to Z_PREFIX, remove duplicates, z_z_ -> z_
+- Remove zlibdefs.h completely -- modify zconf.h instead
+
+Changes in 1.2.3.6 (17 Jan 2010)
+- Avoid void * arithmetic in gzread.c and gzwrite.c
+- Make compilers happier with const char * for gz_error message
+- Avoid unused parameter warning in inflate.c
+- Avoid signed-unsigned comparison warning in inflate.c
+- Indent #pragma's for traditional C
+- Fix usage of strwinerror() in glib.c, change to gz_strwinerror()
+- Correct email address in configure for system options
+- Update make_vms.com and add make_vms.com to contrib/minizip [Zinser]
+- Update zlib.map [Brown]
+- Fix Makefile.in for Solaris 10 make of example64 and minizip64 [Torok]
+- Apply various fixes to CMakeLists.txt [Lowman]
+- Add checks on len in gzread() and gzwrite()
+- Add error message for no more room for gzungetc()
+- Remove zlib version check in gzwrite()
+- Defer compression of gzprintf() result until need to
+- Use snprintf() in gzdopen() if available
+- Remove USE_MMAP configuration determination (only used by minigzip)
+- Remove examples/pigz.c (available separately)
+- Update examples/gun.c to 1.6
+
+Changes in 1.2.3.5 (8 Jan 2010)
+- Add space after #if in zutil.h for some compilers
+- Fix relatively harmless bug in deflate_fast() [Exarevsky]
+- Fix same problem in deflate_slow()
+- Add $(SHAREDLIBV) to LIBS in Makefile.in [Brown]
+- Add deflate_rle() for faster Z_RLE strategy run-length encoding
+- Add deflate_huff() for faster Z_HUFFMAN_ONLY encoding
+- Change name of "write" variable in inffast.c to avoid library collisions
+- Fix premature EOF from gzread() in gzio.c [Brown]
+- Use zlib header window size if windowBits is 0 in inflateInit2()
+- Remove compressBound() call in deflate.c to avoid linking compress.o
+- Replace use of errno in gz* with functions, support WinCE [Alves]
+- Provide alternative to perror() in minigzip.c for WinCE [Alves]
+- Don't use _vsnprintf on later versions of MSVC [Lowman]
+- Add CMake build script and input file [Lowman]
+- Update contrib/minizip to 1.1 [Svensson, Vollant]
+- Moved nintendods directory from contrib to .
+- Replace gzio.c with a new set of routines with the same functionality
+- Add gzbuffer(), gzoffset(), gzclose_r(), gzclose_w() as part of above
+- Update contrib/minizip to 1.1b
+- Change gzeof() to return 0 on error instead of -1 to agree with zlib.h
+
+Changes in 1.2.3.4 (21 Dec 2009)
+- Use old school .SUFFIXES in Makefile.in for FreeBSD compatibility
+- Update comments in configure and Makefile.in for default --shared
+- Fix test -z's in configure [Marquess]
+- Build examplesh and minigzipsh when not testing
+- Change NULL's to Z_NULL's in deflate.c and in comments in zlib.h
+- Import LDFLAGS from the environment in configure
+- Fix configure to populate SFLAGS with discovered CFLAGS options
+- Adapt make_vms.com to the new Makefile.in [Zinser]
+- Add zlib2ansi script for C++ compilation [Marquess]
+- Add _FILE_OFFSET_BITS=64 test to make test (when applicable)
+- Add AMD64 assembler code for longest match to contrib [Teterin]
+- Include options from $SFLAGS when doing $LDSHARED
+- Simplify 64-bit file support by introducing z_off64_t type
+- Make shared object files in objs directory to work around old Sun cc
+- Use only three-part version number for Darwin shared compiles
+- Add rc option to ar in Makefile.in for when ./configure not run
+- Add -WI,-rpath,. to LDFLAGS for OSF 1 V4*
+- Set LD_LIBRARYN32_PATH for SGI IRIX shared compile
+- Protect against _FILE_OFFSET_BITS being defined when compiling zlib
+- Rename Makefile.in targets allstatic to static and allshared to shared
+- Fix static and shared Makefile.in targets to be independent
+- Correct error return bug in gz_open() by setting state [Brown]
+- Put spaces before ;;'s in configure for better sh compatibility
+- Add pigz.c (parallel implementation of gzip) to examples/
+- Correct constant in crc32.c to UL [Leventhal]
+- Reject negative lengths in crc32_combine()
+- Add inflateReset2() function to work like inflateEnd()/inflateInit2()
+- Include sys/types.h for _LARGEFILE64_SOURCE [Brown]
+- Correct typo in doc/algorithm.txt [Janik]
+- Fix bug in adler32_combine() [Zhu]
+- Catch missing-end-of-block-code error in all inflates and in puff
+    Assures that random input to inflate eventually results in an error
+- Added enough.c (calculation of ENOUGH for inftrees.h) to examples/
+- Update ENOUGH and its usage to reflect discovered bounds
+- Fix gzerror() error report on empty input file [Brown]
+- Add ush casts in trees.c to avoid pedantic runtime errors
+- Fix typo in zlib.h uncompress() description [Reiss]
+- Correct inflate() comments with regard to automatic header detection
+- Remove deprecation comment on Z_PARTIAL_FLUSH (it stays)
+- Put new version of gzlog (2.0) in examples with interruption recovery
+- Add puff compile option to permit invalid distance-too-far streams
+- Add puff TEST command options, ability to read piped input
+- Prototype the *64 functions in zlib.h when _FILE_OFFSET_BITS == 64, but
+  _LARGEFILE64_SOURCE not defined
+- Fix Z_FULL_FLUSH to truly erase the past by resetting s->strstart
+- Fix deflateSetDictionary() to use all 32K for output consistency
+- Remove extraneous #define MIN_LOOKAHEAD in deflate.c (in deflate.h)
+- Clear bytes after deflate lookahead to avoid use of uninitialized data
+- Change a limit in inftrees.c to be more transparent to Coverity Prevent
+- Update win32/zlib.def with exported symbols from zlib.h
+- Correct spelling errors in zlib.h [Willem, Sobrado]
+- Allow Z_BLOCK for deflate() to force a new block
+- Allow negative bits in inflatePrime() to delete existing bit buffer
+- Add Z_TREES flush option to inflate() to return at end of trees
+- Add inflateMark() to return current state information for random access
+- Add Makefile for NintendoDS to contrib [Costa]
+- Add -w in configure compile tests to avoid spurious warnings [Beucler]
+- Fix typos in zlib.h comments for deflateSetDictionary()
+- Fix EOF detection in transparent gzread() [Maier]
+
+Changes in 1.2.3.3 (2 October 2006)
+- Make --shared the default for configure, add a --static option
+- Add compile option to permit invalid distance-too-far streams
+- Add inflateUndermine() function which is required to enable above
+- Remove use of "this" variable name for C++ compatibility [Marquess]
+- Add testing of shared library in make test, if shared library built
+- Use ftello() and fseeko() if available instead of ftell() and fseek()
+- Provide two versions of all functions that use the z_off_t type for
+  binary compatibility -- a normal version and a 64-bit offset version,
+  per the Large File Support Extension when _LARGEFILE64_SOURCE is
+  defined; use the 64-bit versions by default when _FILE_OFFSET_BITS
+  is defined to be 64
+- Add a --uname= option to configure to perhaps help with cross-compiling
+
+Changes in 1.2.3.2 (3 September 2006)
+- Turn off silly Borland warnings [Hay]
+- Use off64_t and define _LARGEFILE64_SOURCE when present
+- Fix missing dependency on inffixed.h in Makefile.in
+- Rig configure --shared to build both shared and static [Teredesai, Truta]
+- Remove zconf.in.h and instead create a new zlibdefs.h file
+- Fix contrib/minizip/unzip.c non-encrypted after encrypted [Vollant]
+- Add treebuild.xml (see http://treebuild.metux.de/) [Weigelt]
+
+Changes in 1.2.3.1 (16 August 2006)
+- Add watcom directory with OpenWatcom make files [Daniel]
+- Remove #undef of FAR in zconf.in.h for MVS [Fedtke]
+- Update make_vms.com [Zinser]
+- Use -fPIC for shared build in configure [Teredesai, Nicholson]
+- Use only major version number for libz.so on IRIX and OSF1 [Reinholdtsen]
+- Use fdopen() (not _fdopen()) for Interix in zutil.h [B\8ack]
+- Add some FAQ entries about the contrib directory
+- Update the MVS question in the FAQ
+- Avoid extraneous reads after EOF in gzio.c [Brown]
+- Correct spelling of "successfully" in gzio.c [Randers-Pehrson]
+- Add comments to zlib.h about gzerror() usage [Brown]
+- Set extra flags in gzip header in gzopen() like deflate() does
+- Make configure options more compatible with double-dash conventions
+  [Weigelt]
+- Clean up compilation under Solaris SunStudio cc [Rowe, Reinholdtsen]
+- Fix uninstall target in Makefile.in [Truta]
+- Add pkgconfig support [Weigelt]
+- Use $(DESTDIR) macro in Makefile.in [Reinholdtsen, Weigelt]
+- Replace set_data_type() with a more accurate detect_data_type() in
+  trees.c, according to the txtvsbin.txt document [Truta]
+- Swap the order of #include <stdio.h> and #include "zlib.h" in
+  gzio.c, example.c and minigzip.c [Truta]
+- Shut up annoying VS2005 warnings about standard C deprecation [Rowe,
+  Truta] (where?)
+- Fix target "clean" from win32/Makefile.bor [Truta]
+- Create .pdb and .manifest files in win32/makefile.msc [Ziegler, Rowe]
+- Update zlib www home address in win32/DLL_FAQ.txt [Truta]
+- Update contrib/masmx86/inffas32.asm for VS2005 [Vollant, Van Wassenhove]
+- Enable browse info in the "Debug" and "ASM Debug" configurations in
+  the Visual C++ 6 project, and set (non-ASM) "Debug" as default [Truta]
+- Add pkgconfig support [Weigelt]
+- Add ZLIB_VER_MAJOR, ZLIB_VER_MINOR and ZLIB_VER_REVISION in zlib.h,
+  for use in win32/zlib1.rc [Polushin, Rowe, Truta]
+- Add a document that explains the new text detection scheme to
+  doc/txtvsbin.txt [Truta]
+- Add rfc1950.txt, rfc1951.txt and rfc1952.txt to doc/ [Truta]
+- Move algorithm.txt into doc/ [Truta]
+- Synchronize FAQ with website
+- Fix compressBound(), was low for some pathological cases [Fearnley]
+- Take into account wrapper variations in deflateBound()
+- Set examples/zpipe.c input and output to binary mode for Windows
+- Update examples/zlib_how.html with new zpipe.c (also web site)
+- Fix some warnings in examples/gzlog.c and examples/zran.c (it seems
+  that gcc became pickier in 4.0)
+- Add zlib.map for Linux: "All symbols from zlib-1.1.4 remain
+  un-versioned, the patch adds versioning only for symbols introduced in
+  zlib-1.2.0 or later.  It also declares as local those symbols which are
+  not designed to be exported." [Levin]
+- Update Z_PREFIX list in zconf.in.h, add --zprefix option to configure
+- Do not initialize global static by default in trees.c, add a response
+  NO_INIT_GLOBAL_POINTERS to initialize them if needed [Marquess]
+- Don't use strerror() in gzio.c under WinCE [Yakimov]
+- Don't use errno.h in zutil.h under WinCE [Yakimov]
+- Move arguments for AR to its usage to allow replacing ar [Marot]
+- Add HAVE_VISIBILITY_PRAGMA in zconf.in.h for Mozilla [Randers-Pehrson]
+- Improve inflateInit() and inflateInit2() documentation
+- Fix structure size comment in inflate.h
+- Change configure help option from --h* to --help [Santos]
+
+Changes in 1.2.3 (18 July 2005)
+- Apply security vulnerability fixes to contrib/infback9 as well
+- Clean up some text files (carriage returns, trailing space)
+- Update testzlib, vstudio, masmx64, and masmx86 in contrib [Vollant]
+
+Changes in 1.2.2.4 (11 July 2005)
+- Add inflatePrime() function for starting inflation at bit boundary
+- Avoid some Visual C warnings in deflate.c
+- Avoid more silly Visual C warnings in inflate.c and inftrees.c for 64-bit
+  compile
+- Fix some spelling errors in comments [Betts]
+- Correct inflateInit2() error return documentation in zlib.h
+- Add zran.c example of compressed data random access to examples
+  directory, shows use of inflatePrime()
+- Fix cast for assignments to strm->state in inflate.c and infback.c
+- Fix zlibCompileFlags() in zutil.c to use 1L for long shifts [Oberhumer]
+- Move declarations of gf2 functions to right place in crc32.c [Oberhumer]
+- Add cast in trees.c t avoid a warning [Oberhumer]
+- Avoid some warnings in fitblk.c, gun.c, gzjoin.c in examples [Oberhumer]
+- Update make_vms.com [Zinser]
+- Initialize state->write in inflateReset() since copied in inflate_fast()
+- Be more strict on incomplete code sets in inflate_table() and increase
+  ENOUGH and MAXD -- this repairs a possible security vulnerability for
+  invalid inflate input.  Thanks to Tavis Ormandy and Markus Oberhumer for
+  discovering the vulnerability and providing test cases.
+- Add ia64 support to configure for HP-UX [Smith]
+- Add error return to gzread() for format or i/o error [Levin]
+- Use malloc.h for OS/2 [Necasek]
+
+Changes in 1.2.2.3 (27 May 2005)
+- Replace 1U constants in inflate.c and inftrees.c for 64-bit compile
+- Typecast fread() return values in gzio.c [Vollant]
+- Remove trailing space in minigzip.c outmode (VC++ can't deal with it)
+- Fix crc check bug in gzread() after gzungetc() [Heiner]
+- Add the deflateTune() function to adjust internal compression parameters
+- Add a fast gzip decompressor, gun.c, to examples (use of inflateBack)
+- Remove an incorrect assertion in examples/zpipe.c
+- Add C++ wrapper in infback9.h [Donais]
+- Fix bug in inflateCopy() when decoding fixed codes
+- Note in zlib.h how much deflateSetDictionary() actually uses
+- Remove USE_DICT_HEAD in deflate.c (would mess up inflate if used)
+- Add _WIN32_WCE to define WIN32 in zconf.in.h [Spencer]
+- Don't include stderr.h or errno.h for _WIN32_WCE in zutil.h [Spencer]
+- Add gzdirect() function to indicate transparent reads
+- Update contrib/minizip [Vollant]
+- Fix compilation of deflate.c when both ASMV and FASTEST [Oberhumer]
+- Add casts in crc32.c to avoid warnings [Oberhumer]
+- Add contrib/masmx64 [Vollant]
+- Update contrib/asm586, asm686, masmx86, testzlib, vstudio [Vollant]
+
+Changes in 1.2.2.2 (30 December 2004)
+- Replace structure assignments in deflate.c and inflate.c with zmemcpy to
+  avoid implicit memcpy calls (portability for no-library compilation)
+- Increase sprintf() buffer size in gzdopen() to allow for large numbers
+- Add INFLATE_STRICT to check distances against zlib header
+- Improve WinCE errno handling and comments [Chang]
+- Remove comment about no gzip header processing in FAQ
+- Add Z_FIXED strategy option to deflateInit2() to force fixed trees
+- Add updated make_vms.com [Coghlan], update README
+- Create a new "examples" directory, move gzappend.c there, add zpipe.c,
+  fitblk.c, gzlog.[ch], gzjoin.c, and zlib_how.html.
+- Add FAQ entry and comments in deflate.c on uninitialized memory access
+- Add Solaris 9 make options in configure [Gilbert]
+- Allow strerror() usage in gzio.c for STDC
+- Fix DecompressBuf in contrib/delphi/ZLib.pas [ManChesTer]
+- Update contrib/masmx86/inffas32.asm and gvmat32.asm [Vollant]
+- Use z_off_t for adler32_combine() and crc32_combine() lengths
+- Make adler32() much faster for small len
+- Use OS_CODE in deflate() default gzip header
+
+Changes in 1.2.2.1 (31 October 2004)
+- Allow inflateSetDictionary() call for raw inflate
+- Fix inflate header crc check bug for file names and comments
+- Add deflateSetHeader() and gz_header structure for custom gzip headers
+- Add inflateGetheader() to retrieve gzip headers
+- Add crc32_combine() and adler32_combine() functions
+- Add alloc_func, free_func, in_func, out_func to Z_PREFIX list
+- Use zstreamp consistently in zlib.h (inflate_back functions)
+- Remove GUNZIP condition from definition of inflate_mode in inflate.h
+  and in contrib/inflate86/inffast.S [Truta, Anderson]
+- Add support for AMD64 in contrib/inflate86/inffas86.c [Anderson]
+- Update projects/README.projects and projects/visualc6 [Truta]
+- Update win32/DLL_FAQ.txt [Truta]
+- Avoid warning under NO_GZCOMPRESS in gzio.c; fix typo [Truta]
+- Deprecate Z_ASCII; use Z_TEXT instead [Truta]
+- Use a new algorithm for setting strm->data_type in trees.c [Truta]
+- Do not define an exit() prototype in zutil.c unless DEBUG defined
+- Remove prototype of exit() from zutil.c, example.c, minigzip.c [Truta]
+- Add comment in zlib.h for Z_NO_FLUSH parameter to deflate()
+- Fix Darwin build version identification [Peterson]
+
+Changes in 1.2.2 (3 October 2004)
+- Update zlib.h comments on gzip in-memory processing
+- Set adler to 1 in inflateReset() to support Java test suite [Walles]
+- Add contrib/dotzlib [Ravn]
+- Update win32/DLL_FAQ.txt [Truta]
+- Update contrib/minizip [Vollant]
+- Move contrib/visual-basic.txt to old/ [Truta]
+- Fix assembler builds in projects/visualc6/ [Truta]
+
+Changes in 1.2.1.2 (9 September 2004)
+- Update INDEX file
+- Fix trees.c to update strm->data_type (no one ever noticed!)
+- Fix bug in error case in inflate.c, infback.c, and infback9.c [Brown]
+- Add "volatile" to crc table flag declaration (for DYNAMIC_CRC_TABLE)
+- Add limited multitasking protection to DYNAMIC_CRC_TABLE
+- Add NO_vsnprintf for VMS in zutil.h [Mozilla]
+- Don't declare strerror() under VMS [Mozilla]
+- Add comment to DYNAMIC_CRC_TABLE to use get_crc_table() to initialize
+- Update contrib/ada [Anisimkov]
+- Update contrib/minizip [Vollant]
+- Fix configure to not hardcode directories for Darwin [Peterson]
+- Fix gzio.c to not return error on empty files [Brown]
+- Fix indentation; update version in contrib/delphi/ZLib.pas and
+  contrib/pascal/zlibpas.pas [Truta]
+- Update mkasm.bat in contrib/masmx86 [Truta]
+- Update contrib/untgz [Truta]
+- Add projects/README.projects [Truta]
+- Add project for MS Visual C++ 6.0 in projects/visualc6 [Cadieux, Truta]
+- Update win32/DLL_FAQ.txt [Truta]
+- Update list of Z_PREFIX symbols in zconf.h [Randers-Pehrson, Truta]
+- Remove an unnecessary assignment to curr in inftrees.c [Truta]
+- Add OS/2 to exe builds in configure [Poltorak]
+- Remove err dummy parameter in zlib.h [Kientzle]
+
+Changes in 1.2.1.1 (9 January 2004)
+- Update email address in README
+- Several FAQ updates
+- Fix a big fat bug in inftrees.c that prevented decoding valid
+  dynamic blocks with only literals and no distance codes --
+  Thanks to "Hot Emu" for the bug report and sample file
+- Add a note to puff.c on no distance codes case.
+
+Changes in 1.2.1 (17 November 2003)
+- Remove a tab in contrib/gzappend/gzappend.c
+- Update some interfaces in contrib for new zlib functions
+- Update zlib version number in some contrib entries
+- Add Windows CE definition for ptrdiff_t in zutil.h [Mai, Truta]
+- Support shared libraries on Hurd and KFreeBSD [Brown]
+- Fix error in NO_DIVIDE option of adler32.c
+
+Changes in 1.2.0.8 (4 November 2003)
+- Update version in contrib/delphi/ZLib.pas and contrib/pascal/zlibpas.pas
+- Add experimental NO_DIVIDE #define in adler32.c
+    - Possibly faster on some processors (let me know if it is)
+- Correct Z_BLOCK to not return on first inflate call if no wrap
+- Fix strm->data_type on inflate() return to correctly indicate EOB
+- Add deflatePrime() function for appending in the middle of a byte
+- Add contrib/gzappend for an example of appending to a stream
+- Update win32/DLL_FAQ.txt [Truta]
+- Delete Turbo C comment in README [Truta]
+- Improve some indentation in zconf.h [Truta]
+- Fix infinite loop on bad input in configure script [Church]
+- Fix gzeof() for concatenated gzip files [Johnson]
+- Add example to contrib/visual-basic.txt [Michael B.]
+- Add -p to mkdir's in Makefile.in [vda]
+- Fix configure to properly detect presence or lack of printf functions
+- Add AS400 support [Monnerat]
+- Add a little Cygwin support [Wilson]
+
+Changes in 1.2.0.7 (21 September 2003)
+- Correct some debug formats in contrib/infback9
+- Cast a type in a debug statement in trees.c
+- Change search and replace delimiter in configure from % to # [Beebe]
+- Update contrib/untgz to 0.2 with various fixes [Truta]
+- Add build support for Amiga [Nikl]
+- Remove some directories in old that have been updated to 1.2
+- Add dylib building for Mac OS X in configure and Makefile.in
+- Remove old distribution stuff from Makefile
+- Update README to point to DLL_FAQ.txt, and add comment on Mac OS X
+- Update links in README
+
+Changes in 1.2.0.6 (13 September 2003)
+- Minor FAQ updates
+- Update contrib/minizip to 1.00 [Vollant]
+- Remove test of gz functions in example.c when GZ_COMPRESS defined [Truta]
+- Update POSTINC comment for 68060 [Nikl]
+- Add contrib/infback9 with deflate64 decoding (unsupported)
+- For MVS define NO_vsnprintf and undefine FAR [van Burik]
+- Add pragma for fdopen on MVS [van Burik]
+
+Changes in 1.2.0.5 (8 September 2003)
+- Add OF to inflateBackEnd() declaration in zlib.h
+- Remember start when using gzdopen in the middle of a file
+- Use internal off_t counters in gz* functions to properly handle seeks
+- Perform more rigorous check for distance-too-far in inffast.c
+- Add Z_BLOCK flush option to return from inflate at block boundary
+- Set strm->data_type on return from inflate
+    - Indicate bits unused, if at block boundary, and if in last block
+- Replace size_t with ptrdiff_t in crc32.c, and check for correct size
+- Add condition so old NO_DEFLATE define still works for compatibility
+- FAQ update regarding the Windows DLL [Truta]
+- INDEX update: add qnx entry, remove aix entry [Truta]
+- Install zlib.3 into mandir [Wilson]
+- Move contrib/zlib_dll_FAQ.txt to win32/DLL_FAQ.txt; update [Truta]
+- Adapt the zlib interface to the new DLL convention guidelines [Truta]
+- Introduce ZLIB_WINAPI macro to allow the export of functions using
+  the WINAPI calling convention, for Visual Basic [Vollant, Truta]
+- Update msdos and win32 scripts and makefiles [Truta]
+- Export symbols by name, not by ordinal, in win32/zlib.def [Truta]
+- Add contrib/ada [Anisimkov]
+- Move asm files from contrib/vstudio/vc70_32 to contrib/asm386 [Truta]
+- Rename contrib/asm386 to contrib/masmx86 [Truta, Vollant]
+- Add contrib/masm686 [Truta]
+- Fix offsets in contrib/inflate86 and contrib/masmx86/inffas32.asm
+  [Truta, Vollant]
+- Update contrib/delphi; rename to contrib/pascal; add example [Truta]
+- Remove contrib/delphi2; add a new contrib/delphi [Truta]
+- Avoid inclusion of the nonstandard <memory.h> in contrib/iostream,
+  and fix some method prototypes [Truta]
+- Fix the ZCR_SEED2 constant to avoid warnings in contrib/minizip
+  [Truta]
+- Avoid the use of backslash (\) in contrib/minizip [Vollant]
+- Fix file time handling in contrib/untgz; update makefiles [Truta]
+- Update contrib/vstudio/vc70_32 to comply with the new DLL guidelines
+  [Vollant]
+- Remove contrib/vstudio/vc15_16 [Vollant]
+- Rename contrib/vstudio/vc70_32 to contrib/vstudio/vc7 [Truta]
+- Update README.contrib [Truta]
+- Invert the assignment order of match_head and s->prev[...] in
+  INSERT_STRING [Truta]
+- Compare TOO_FAR with 32767 instead of 32768, to avoid 16-bit warnings
+  [Truta]
+- Compare function pointers with 0, not with NULL or Z_NULL [Truta]
+- Fix prototype of syncsearch in inflate.c [Truta]
+- Introduce ASMINF macro to be enabled when using an ASM implementation
+  of inflate_fast [Truta]
+- Change NO_DEFLATE to NO_GZCOMPRESS [Truta]
+- Modify test_gzio in example.c to take a single file name as a
+  parameter [Truta]
+- Exit the example.c program if gzopen fails [Truta]
+- Add type casts around strlen in example.c [Truta]
+- Remove casting to sizeof in minigzip.c; give a proper type
+  to the variable compared with SUFFIX_LEN [Truta]
+- Update definitions of STDC and STDC99 in zconf.h [Truta]
+- Synchronize zconf.h with the new Windows DLL interface [Truta]
+- Use SYS16BIT instead of __32BIT__ to distinguish between
+  16- and 32-bit platforms [Truta]
+- Use far memory allocators in small 16-bit memory models for
+  Turbo C [Truta]
+- Add info about the use of ASMV, ASMINF and ZLIB_WINAPI in
+  zlibCompileFlags [Truta]
+- Cygwin has vsnprintf [Wilson]
+- In Windows16, OS_CODE is 0, as in MSDOS [Truta]
+- In Cygwin, OS_CODE is 3 (Unix), not 11 (Windows32) [Wilson]
+
+Changes in 1.2.0.4 (10 August 2003)
+- Minor FAQ updates
+- Be more strict when checking inflateInit2's windowBits parameter
+- Change NO_GUNZIP compile option to NO_GZIP to cover deflate as well
+- Add gzip wrapper option to deflateInit2 using windowBits
+- Add updated QNX rule in configure and qnx directory [Bonnefoy]
+- Make inflate distance-too-far checks more rigorous
+- Clean up FAR usage in inflate
+- Add casting to sizeof() in gzio.c and minigzip.c
+
+Changes in 1.2.0.3 (19 July 2003)
+- Fix silly error in gzungetc() implementation [Vollant]
+- Update contrib/minizip and contrib/vstudio [Vollant]
+- Fix printf format in example.c
+- Correct cdecl support in zconf.in.h [Anisimkov]
+- Minor FAQ updates
+
+Changes in 1.2.0.2 (13 July 2003)
+- Add ZLIB_VERNUM in zlib.h for numerical preprocessor comparisons
+- Attempt to avoid warnings in crc32.c for pointer-int conversion
+- Add AIX to configure, remove aix directory [Bakker]
+- Add some casts to minigzip.c
+- Improve checking after insecure sprintf() or vsprintf() calls
+- Remove #elif's from crc32.c
+- Change leave label to inf_leave in inflate.c and infback.c to avoid
+  library conflicts
+- Remove inflate gzip decoding by default--only enable gzip decoding by
+  special request for stricter backward compatibility
+- Add zlibCompileFlags() function to return compilation information
+- More typecasting in deflate.c to avoid warnings
+- Remove leading underscore from _Capital #defines [Truta]
+- Fix configure to link shared library when testing
+- Add some Windows CE target adjustments [Mai]
+- Remove #define ZLIB_DLL in zconf.h [Vollant]
+- Add zlib.3 [Rodgers]
+- Update RFC URL in deflate.c and algorithm.txt [Mai]
+- Add zlib_dll_FAQ.txt to contrib [Truta]
+- Add UL to some constants [Truta]
+- Update minizip and vstudio [Vollant]
+- Remove vestigial NEED_DUMMY_RETURN from zconf.in.h
+- Expand use of NO_DUMMY_DECL to avoid all dummy structures
+- Added iostream3 to contrib [Schwardt]
+- Replace rewind() with fseek() for WinCE [Truta]
+- Improve setting of zlib format compression level flags
+    - Report 0 for huffman and rle strategies and for level == 0 or 1
+    - Report 2 only for level == 6
+- Only deal with 64K limit when necessary at compile time [Truta]
+- Allow TOO_FAR check to be turned off at compile time [Truta]
+- Add gzclearerr() function [Souza]
+- Add gzungetc() function
+
+Changes in 1.2.0.1 (17 March 2003)
+- Add Z_RLE strategy for run-length encoding [Truta]
+    - When Z_RLE requested, restrict matches to distance one
+    - Update zlib.h, minigzip.c, gzopen(), gzdopen() for Z_RLE
+- Correct FASTEST compilation to allow level == 0
+- Clean up what gets compiled for FASTEST
+- Incorporate changes to zconf.in.h [Vollant]
+    - Refine detection of Turbo C need for dummy returns
+    - Refine ZLIB_DLL compilation
+    - Include additional header file on VMS for off_t typedef
+- Try to use _vsnprintf where it supplants vsprintf [Vollant]
+- Add some casts in inffast.c
+- Enchance comments in zlib.h on what happens if gzprintf() tries to
+  write more than 4095 bytes before compression
+- Remove unused state from inflateBackEnd()
+- Remove exit(0) from minigzip.c, example.c
+- Get rid of all those darn tabs
+- Add "check" target to Makefile.in that does the same thing as "test"
+- Add &qu