From 0fa9ca5b53e412decad0df1f6b5baca73ae76a9c Mon Sep 17 00:00:00 2001 From: "henryk@ploetzli.ch" Date: Fri, 28 Aug 2009 21:56:43 +0000 Subject: [PATCH] Add command and code for bidirectional LF emulation of Hitag2. Should be extended for other types of tags --- armsrc/Makefile | 1 + armsrc/appmain.c | 3 + armsrc/apps.h | 1 + armsrc/lfops.c | 201 ++++++++++++++++++++++++++++++++++++++++++++- include/usb_cmd.h | 1 + winsrc/command.cpp | 10 +++ 6 files changed, 215 insertions(+), 2 deletions(-) diff --git a/armsrc/Makefile b/armsrc/Makefile index 13e43ba9..00e99b1f 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -14,6 +14,7 @@ THUMBSRC = start.c \ iso15693.c \ util.c \ version.c \ + hitag2.c \ usb.c # These are to be compiled in ARM mode diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 9696b008..59cc6dea 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -645,6 +645,9 @@ void UsbPacketReceived(BYTE *packet, int len) case CMD_VERSION: SendVersion(); break; + case CMD_LF_SIMULATE_BIDIR: + SimulateTagLowFrequencyBidir(c->ext1, c->ext2); + break; #ifdef WITH_LCD case CMD_LCD_RESET: LCDReset(); diff --git a/armsrc/apps.h b/armsrc/apps.h index 6f146f78..f07504d2 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -74,6 +74,7 @@ void AcquireRawBitsTI(void); void SimulateTagLowFrequency(int period, int ledcontrol); void CmdHIDsimTAG(int hi, int lo, int ledcontrol); void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol); +void SimulateTagLowFrequencyBidir(int divisor, int max_bitlen); /// iso14443.h void SimulateIso14443Tag(void); diff --git a/armsrc/lfops.c b/armsrc/lfops.c index f9aee43e..8ad25ce0 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -6,6 +6,7 @@ //----------------------------------------------------------------------------- #include #include "apps.h" +#include "hitag2.h" #include "../common/crc16.c" void AcquireRawAdcSamples125k(BOOL at134khz) @@ -61,6 +62,10 @@ void ModThenAcquireRawAdcSamples125k(int delay_off,int period_0,int period_1,BYT { BOOL at134khz; + /* Make sure the tag is reset */ + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(2500); + // see if 'h' was specified if(command[strlen((char *) command) - 1] == 'h') at134khz= TRUE; @@ -77,6 +82,8 @@ void ModThenAcquireRawAdcSamples125k(int delay_off,int period_0,int period_1,BYT // Give it a bit of time for the resonant antenna to settle. SpinDelay(50); + // And a little more time for the tag to fully power up + SpinDelay(2000); // Now set up the SSC to get the ADC samples that are now streaming at us. FpgaSetupSsc(); @@ -95,11 +102,12 @@ void ModThenAcquireRawAdcSamples125k(int delay_off,int period_0,int period_1,BYT FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); } LED_D_ON(); - if(*(command++) == '0') + if(*(command++) == '0') { SpinDelayUs(period_0); - else + } else { SpinDelayUs(period_1); } + } FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LED_D_OFF(); SpinDelayUs(delay_off); @@ -478,6 +486,195 @@ void SimulateTagLowFrequency(int period, int ledcontrol) } } +/* Provides a framework for bidirectional LF tag communication + * Encoding is currently Hitag2, but the general idea can probably + * be transferred to other encodings. + * + * The new FPGA code will, for the LF simulator mode, give on SSC_FRAME + * (PA15) a thresholded version of the signal from the ADC. Setting the + * ADC path to the low frequency peak detection signal, will enable a + * somewhat reasonable receiver for modulation on the carrier signal + * that is generated by the reader. The signal is low when the reader + * field is switched off, and high when the reader field is active. Due + * to the way that the signal looks like, mostly only the rising edge is + * useful, your mileage may vary. + * + * Neat perk: PA15 can not only be used as a bit-banging GPIO, but is also + * TIOA1, which can be used as the capture input for timer 1. This should + * make it possible to measure the exact edge-to-edge time, without processor + * intervention. + * + * Arguments: divisor is the divisor to be sent to the FPGA (e.g. 95 for 125kHz) + * t0 is the carrier frequency cycle duration in terms of MCK (384 for 125kHz) + * + * The following defines are in carrier periods: + */ +#define HITAG_T_0_MIN 15 /* T[0] should be 18..22 */ +#define HITAG_T_1_MIN 24 /* T[1] should be 26..30 */ +#define HITAG_T_EOF 40 /* T_EOF should be > 36 */ +#define HITAG_T_WRESP 208 /* T_wresp should be 204..212 */ + +static void hitag_handle_frame(int t0, int frame_len, char *frame); +//#define DEBUG_RA_VALUES 1 +#define DEBUG_FRAME_CONTENTS 1 +void SimulateTagLowFrequencyBidir(int divisor, int t0) +{ +#if DEBUG_RA_VALUES || DEBUG_FRAME_CONTENTS + int i = 0; +#endif + char frame[10]; + int frame_pos=0; + + DbpString("Starting Hitag2 emulator, press button to end"); + hitag2_init(); + + /* Set up simulator mode, frequency divisor which will drive the FPGA + * and analog mux selection. + */ + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_SIMULATOR); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor); + SetAdcMuxFor(GPIO_MUXSEL_LOPKD); + RELAY_OFF(); + + /* Set up Timer 1: + * Capture mode, timer source MCK/2 (TIMER_CLOCK1), TIOA is external trigger, + * external trigger rising edge, load RA on rising edge of TIOA, load RB on rising + * edge of TIOA. Assign PA15 to TIOA1 (peripheral B) + */ + + PMC_PERIPHERAL_CLK_ENABLE = (1 << PERIPH_TC1); + PIO_PERIPHERAL_B_SEL = (1 << GPIO_SSC_FRAME); + TC1_CCR = TC_CCR_CLKDIS; + TC1_CMR = TC_CMR_TCCLKS_TIMER_CLOCK1 | TC_CMR_ETRGEDG_RISING | TC_CMR_ABETRG | + TC_CMR_LDRA_RISING | TC_CMR_LDRB_RISING; + TC1_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG; + + /* calculate the new value for the carrier period in terms of TC1 values */ + t0 = t0/2; + + int overflow = 0; + while(!BUTTON_PRESS()) { + WDT_HIT(); + if(TC1_SR & TC_SR_LDRAS) { + int ra = TC1_RA; + if((ra > t0*HITAG_T_EOF) | overflow) ra = t0*HITAG_T_EOF+1; +#if DEBUG_RA_VALUES + if(ra > 255 || overflow) ra = 255; + ((char*)BigBuf)[i] = ra; + i = (i+1) % 8000; +#endif + + if(overflow || (ra > t0*HITAG_T_EOF) || (ra < t0*HITAG_T_0_MIN)) { + /* Ignore */ + } else if(ra >= t0*HITAG_T_1_MIN ) { + /* '1' bit */ + if(frame_pos < 8*sizeof(frame)) { + frame[frame_pos / 8] |= 1<<( 7-(frame_pos%8) ); + frame_pos++; + } + } else if(ra >= t0*HITAG_T_0_MIN) { + /* '0' bit */ + if(frame_pos < 8*sizeof(frame)) { + frame[frame_pos / 8] |= 0<<( 7-(frame_pos%8) ); + frame_pos++; + } + } + + overflow = 0; + LED_D_ON(); + } else { + if(TC1_CV > t0*HITAG_T_EOF) { + /* Minor nuisance: In Capture mode, the timer can not be + * stopped by a Compare C. There's no way to stop the clock + * in software, so we'll just have to note the fact that an + * overflow happened and the next loaded timer value might + * have wrapped. Also, this marks the end of frame, and the + * still running counter can be used to determine the correct + * time for the start of the reply. + */ + overflow = 1; + + if(frame_pos > 0) { + /* Have a frame, do something with it */ +#if DEBUG_FRAME_CONTENTS + ((char*)BigBuf)[i++] = frame_pos; + memcpy( ((char*)BigBuf)+i, frame, 7); + i+=7; + i = i % sizeof(BigBuf); +#endif + hitag_handle_frame(t0, frame_pos, frame); + memset(frame, 0, sizeof(frame)); + } + frame_pos = 0; + + } + LED_D_OFF(); + } + } + DbpString("All done"); +} + +static void hitag_send_bit(int t0, int bit) { + if(bit == 1) { + /* Manchester: Loaded, then unloaded */ + LED_A_ON(); + SHORT_COIL(); + while(TC1_CV < t0*15); + OPEN_COIL(); + while(TC1_CV < t0*31); + LED_A_OFF(); + } else if(bit == 0) { + /* Manchester: Unloaded, then loaded */ + LED_B_ON(); + OPEN_COIL(); + while(TC1_CV < t0*15); + SHORT_COIL(); + while(TC1_CV < t0*31); + LED_B_OFF(); + } + TC1_CCR = TC_CCR_SWTRG; /* Reset clock for the next bit */ + +} +static void hitag_send_frame(int t0, int frame_len, const char const * frame, int fdt) +{ + OPEN_COIL(); + PIO_OUTPUT_ENABLE = (1 << GPIO_SSC_DOUT); + + /* Wait for HITAG_T_WRESP carrier periods after the last reader bit, + * not that since the clock counts since the rising edge, but T_wresp is + * with respect to the falling edge, we need to wait actually (T_wresp - T_g) + * periods. The gap time T_g varies (4..10). + */ + while(TC1_CV < t0*(fdt-8)); + + int saved_cmr = TC1_CMR; + TC1_CMR &= ~TC_CMR_ETRGEDG; /* Disable external trigger for the clock */ + TC1_CCR = TC_CCR_SWTRG; /* Reset the clock and use it for response timing */ + + int i; + for(i=0; i<5; i++) + hitag_send_bit(t0, 1); /* Start of frame */ + + for(i=0; i -- Trim samples from left of trace"}, {"mandemod", Cmdmanchesterdemod, 1, "[i] [clock rate] -- Manchester demodulate binary stream (option 'i' to invert output)"}, {"manmod", Cmdmanchestermod, 1, "[clock rate] -- Manchester modulate a binary stream"}, -- 2.39.2