X-Git-Url: http://cvs.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/9bea179a71188589f8e642f615177a108cea8d55..98af9ddf8ca969ce45b3e6078cb8f39573a99ee9:/armsrc/lfops.c?ds=sidebyside diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 9fe60de8..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); @@ -115,12 +123,179 @@ void ModThenAcquireRawAdcSamples125k(int delay_off,int period_0,int period_1,BYT DoAcquisition125k(at134khz); } +/* blank r/w tag data stream +...0000000000000000 01111111 +1010101010101010101010101010101010101010101010101010101010101010 +0011010010100001 +01111111 +101010101010101[0]000... + +[5555fe852c5555555555555555fe0000] +*/ +void ReadTItag() +{ + // some hardcoded initial params + // when we read a TI tag we sample the zerocross line at 2Mhz + // TI tags modulate a 1 as 16 cycles of 123.2Khz + // TI tags modulate a 0 as 16 cycles of 134.2Khz + #define FSAMPLE 2000000 + #define FREQLO 123200 + #define FREQHI 134200 + + signed char *dest = (signed char *)BigBuf; + int n = sizeof(BigBuf); +// int *dest = GraphBuffer; +// int n = GraphTraceLen; + + // 128 bit shift register [shift3:shift2:shift1:shift0] + DWORD shift3 = 0, shift2 = 0, shift1 = 0, shift0 = 0; + + int i, cycles=0, samples=0; + // how many sample points fit in 16 cycles of each frequency + DWORD sampleslo = (FSAMPLE<<4)/FREQLO, sampleshi = (FSAMPLE<<4)/FREQHI; + // when to tell if we're close enough to one freq or another + DWORD threshold = (sampleslo - sampleshi + 1)>>1; + + // TI tags charge at 134.2Khz + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz + + // Place FPGA in passthrough mode, in this mode the CROSS_LO line + // connects to SSP_DIN and the SSP_DOUT logic level controls + // whether we're modulating the antenna (high) + // or listening to the antenna (low) + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU); + + // get TI tag data into the buffer + AcquireTiType(); + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + + for (i=0; i0) ) { + cycles++; + // after 16 cycles, measure the frequency + if (cycles>15) { + cycles=0; + samples=i-samples; // number of samples in these 16 cycles + + // TI bits are coming to us lsb first so shift them + // right through our 128 bit right shift register + shift0 = (shift0>>1) | (shift1 << 31); + shift1 = (shift1>>1) | (shift2 << 31); + shift2 = (shift2>>1) | (shift3 << 31); + shift3 >>= 1; + + // check if the cycles fall close to the number + // expected for either the low or high frequency + if ( (samples>(sampleslo-threshold)) && (samples<(sampleslo+threshold)) ) { + // low frequency represents a 1 + shift3 |= (1<<31); + } else if ( (samples>(sampleshi-threshold)) && (samples<(sampleshi+threshold)) ) { + // high frequency represents a 0 + } else { + // probably detected a gay waveform or noise + // use this as gaydar or discard shift register and start again + shift3 = shift2 = shift1 = shift0 = 0; + } + samples = i; + + // for each bit we receive, test if we've detected a valid tag + + // if we see 17 zeroes followed by 6 ones, we might have a tag + // remember the bits are backwards + if ( ((shift0 & 0x7fffff) == 0x7e0000) ) { + // if start and end bytes match, we have a tag so break out of the loop + if ( ((shift0>>16)&0xff) == ((shift3>>8)&0xff) ) { + cycles = 0xF0B; //use this as a flag (ugly but whatever) + break; + } + } + } + } + } + + // if flag is set we have a tag + if (cycles!=0xF0B) { + DbpString("Info: No valid tag detected."); + } else { + // put 64 bit data into shift1 and shift0 + shift0 = (shift0>>24) | (shift1 << 8); + shift1 = (shift1>>24) | (shift2 << 8); + + // align 16 bit crc into lower half of shift2 + shift2 = ((shift2>>24) | (shift3 << 8)) & 0x0ffff; + + // if r/w tag, check ident match + if ( shift3&(1<<15) ) { + DbpString("Info: TI tag is rewriteable"); + // only 15 bits compare, last bit of ident is not valid + if ( ((shift3>>16)^shift0)&0x7fff ) { + DbpString("Error: Ident mismatch!"); + } else { + DbpString("Info: TI tag ident is valid"); + } + } else { + DbpString("Info: TI tag is readonly"); + } + + // WARNING the order of the bytes in which we calc crc below needs checking + // i'm 99% sure the crc algorithm is correct, but it may need to eat the + // bytes in reverse or something + // calculate CRC + DWORD crc=0; + + crc = update_crc16(crc, (shift0)&0xff); + crc = update_crc16(crc, (shift0>>8)&0xff); + crc = update_crc16(crc, (shift0>>16)&0xff); + crc = update_crc16(crc, (shift0>>24)&0xff); + crc = update_crc16(crc, (shift1)&0xff); + crc = update_crc16(crc, (shift1>>8)&0xff); + crc = update_crc16(crc, (shift1>>16)&0xff); + crc = update_crc16(crc, (shift1>>24)&0xff); + + DbpString("Info: Tag data_hi, data_lo, crc = "); + DbpIntegers(shift1, shift0, shift2&0xffff); + if (crc != (shift2&0xffff)) { + DbpString("Error: CRC mismatch, expected"); + DbpIntegers(0, 0, crc); + } else { + DbpString("Info: CRC is good"); + } + } +} + +void WriteTIbyte(BYTE b) +{ + int i = 0; + + // modulate 8 bits out to the antenna + for (i=0; i<8; i++) + { + if (b&(1<= n) return; + i++; if(i >= TIBUFLEN) break; } WDT_HIT(); } @@ -170,65 +345,22 @@ void AcquireTiType(void) // return stolen pin to SSP PIO_DISABLE = (1<=0; i--) { +// DbpIntegers(0, 0, BigBuf[i]); + for (j=0; j<32; j++) { + if(BigBuf[i] & (1 << j)) { + dest[--n] = 1; + } else { + dest[--n] = -1; + } } } } -void AcquireRawBitsTI(void) -{ - // TI tags charge at 134.2Khz - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz - - // Place FPGA in passthrough mode, in this mode the CROSS_LO line - // connects to SSP_DIN and the SSP_DOUT logic level controls - // whether we're modulating the antenna (high) - // or listening to the antenna (low) - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU); - - // get TI tag data into the buffer - AcquireTiType(); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); -} - -// this is a dummy function to get around -// a possible flash bug in the bootloader -// delete once you've added more code. -void DummyDummyDummy(void) -{ - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU); - AcquireTiType(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); -} - // arguments: 64bit data split into 32bit idhi:idlo and optional 16bit crc // if crc provided, it will be written with the data verbatim (even if bogus) // if not provided a valid crc will be computed from the data and written. @@ -302,7 +434,7 @@ void WriteTItag(DWORD idhi, DWORD idlo, WORD crc) AcquireTiType(); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - DbpString("Now use tibits and tidemod"); + DbpString("Now use tiread to check"); } void SimulateTagLowFrequency(int period, int ledcontrol) @@ -354,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