X-Git-Url: http://cvs.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/7381e8f2f285aad4ce3919fa1964638cc08c3899..6c5ad038603d132d10802eecbef5c2f2547d94ae:/armsrc/lfops.c diff --git a/armsrc/lfops.c b/armsrc/lfops.c index f9aee43e..c2d908df 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) @@ -41,12 +42,12 @@ void DoAcquisition125k(BOOL at134khz) memset(dest,0,n); i = 0; for(;;) { - if(SSC_STATUS & (SSC_STATUS_TX_READY)) { - SSC_TRANSMIT_HOLDING = 0x43; + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = 0x43; LED_D_ON(); } - if(SSC_STATUS & (SSC_STATUS_RX_READY)) { - dest[i] = (BYTE)SSC_RECEIVE_HOLDING; + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + dest[i] = (BYTE)AT91C_BASE_SSC->SSC_RHR; i++; LED_D_OFF(); if(i >= n) { @@ -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); @@ -266,17 +274,17 @@ void WriteTIbyte(BYTE b) { if (b&(1<PIO_PDR = GPIO_SSC_DIN; + AT91C_BASE_PIOA->PIO_ASR = GPIO_SSC_DIN; // steal this pin from the SSP and use it to control the modulation - PIO_ENABLE = (1<PIO_PER = GPIO_SSC_DOUT; + AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; - SSC_CONTROL = SSC_CONTROL_RESET; - SSC_CONTROL = SSC_CONTROL_RX_ENABLE | SSC_CONTROL_TX_ENABLE; + AT91C_BASE_SSC->SSC_CR = AT91C_SSC_SWRST; + AT91C_BASE_SSC->SSC_CR = AT91C_SSC_RXEN | AT91C_SSC_TXEN; - // Sample at 2 Mbit/s, so TI tags are 16.2 vs. 14.9 clocks long - // 48/2 = 24 MHz clock must be divided by 12 - SSC_CLOCK_DIVISOR = 12; + // Sample at 2 Mbit/s, so TI tags are 16.2 vs. 14.9 clocks long + // 48/2 = 24 MHz clock must be divided by 12 + AT91C_BASE_SSC->SSC_CMR = 12; - SSC_RECEIVE_CLOCK_MODE = SSC_CLOCK_MODE_SELECT(0); - SSC_RECEIVE_FRAME_MODE = SSC_FRAME_MODE_BITS_IN_WORD(32) | SSC_FRAME_MODE_MSB_FIRST; - SSC_TRANSMIT_CLOCK_MODE = 0; - SSC_TRANSMIT_FRAME_MODE = 0; + AT91C_BASE_SSC->SSC_RCMR = SSC_CLOCK_MODE_SELECT(0); + AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(32) | AT91C_SSC_MSBF; + AT91C_BASE_SSC->SSC_TCMR = 0; + AT91C_BASE_SSC->SSC_TFMR = 0; LED_D_ON(); // modulate antenna - PIO_OUTPUT_DATA_SET = (1<= TIBUFLEN) break; - } - WDT_HIT(); + if(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { + BigBuf[i] = AT91C_BASE_SSC->SSC_RHR; // store 32 bit values in buffer + i++; if(i >= TIBUFLEN) break; + } + WDT_HIT(); } // return stolen pin to SSP - PIO_DISABLE = (1<PIO_PDR = GPIO_SSC_DOUT; + AT91C_BASE_PIOA->PIO_ASR = GPIO_SSC_DIN | GPIO_SSC_DOUT; char *dest = (char *)BigBuf; n = TIBUFLEN*32; @@ -386,8 +394,8 @@ void WriteTItag(DWORD idhi, DWORD idlo, WORD crc) LED_A_ON(); // steal this pin from the SSP and use it to control the modulation - PIO_ENABLE = (1<PIO_PER = GPIO_SSC_DOUT; + AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; // writing algorithm: // a high bit consists of a field off for 1ms and field on for 1ms @@ -400,7 +408,7 @@ void WriteTItag(DWORD idhi, DWORD idlo, WORD crc) // finish with 15ms programming time // modulate antenna - PIO_OUTPUT_DATA_SET = (1<>8 )&0xff ); // crc hi WriteTIbyte(0x00); // write frame lo WriteTIbyte(0x03); // write frame hi - PIO_OUTPUT_DATA_SET = (1<PIO_PER = GPIO_SSC_DOUT | GPIO_SSC_CLK; - PIO_OUTPUT_ENABLE = (1 << GPIO_SSC_DOUT); - PIO_OUTPUT_DISABLE = (1 << GPIO_SSC_CLK); + AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; + AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_CLK; #define SHORT_COIL() LOW(GPIO_SSC_DOUT) -#define OPEN_COIL() HIGH(GPIO_SSC_DOUT) +#define OPEN_COIL() HIGH(GPIO_SSC_DOUT) i = 0; for(;;) { - while(!(PIO_PIN_DATA_STATUS & (1<PIO_PDSR & GPIO_SSC_CLK)) { if(BUTTON_PRESS()) { DbpString("Stopped"); return; @@ -465,7 +473,7 @@ void SimulateTagLowFrequency(int period, int ledcontrol) if (ledcontrol) LED_D_OFF(); - while(PIO_PIN_DATA_STATUS & (1<PIO_PDSR & GPIO_SSC_CLK) { if(BUTTON_PRESS()) { DbpString("Stopped"); return; @@ -478,6 +486,199 @@ 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) + */ + + AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1); + AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + AT91C_BASE_TC1->TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK1 | + AT91C_TC_ETRGEDG_RISING | + AT91C_TC_ABETRG | + AT91C_TC_LDRA_RISING | + AT91C_TC_LDRB_RISING; + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | + AT91C_TC_SWTRG; + + /* calculate the new value for the carrier period in terms of TC1 values */ + t0 = t0/2; + + int overflow = 0; + while(!BUTTON_PRESS()) { + WDT_HIT(); + if(AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { + int ra = AT91C_BASE_TC1->TC_RA; + if((ra > t0*HITAG_T_EOF) | overflow) ra = t0*HITAG_T_EOF+1; +#if DEBUG_RA_VALUES + if(ra > 255 || overflow) ra = 255; + ((char*)BigBuf)[i] = ra; + i = (i+1) % 8000; +#endif + + if(overflow || (ra > t0*HITAG_T_EOF) || (ra < t0*HITAG_T_0_MIN)) { + /* Ignore */ + } else if(ra >= t0*HITAG_T_1_MIN ) { + /* '1' bit */ + if(frame_pos < 8*sizeof(frame)) { + frame[frame_pos / 8] |= 1<<( 7-(frame_pos%8) ); + frame_pos++; + } + } else if(ra >= t0*HITAG_T_0_MIN) { + /* '0' bit */ + if(frame_pos < 8*sizeof(frame)) { + frame[frame_pos / 8] |= 0<<( 7-(frame_pos%8) ); + frame_pos++; + } + } + + overflow = 0; + LED_D_ON(); + } else { + if(AT91C_BASE_TC1->TC_CV > t0*HITAG_T_EOF) { + /* Minor nuisance: In Capture mode, the timer can not be + * stopped by a Compare C. There's no way to stop the clock + * in software, so we'll just have to note the fact that an + * overflow happened and the next loaded timer value might + * have wrapped. Also, this marks the end of frame, and the + * still running counter can be used to determine the correct + * time for the start of the reply. + */ + overflow = 1; + + if(frame_pos > 0) { + /* Have a frame, do something with it */ +#if DEBUG_FRAME_CONTENTS + ((char*)BigBuf)[i++] = frame_pos; + memcpy( ((char*)BigBuf)+i, frame, 7); + i+=7; + i = i % sizeof(BigBuf); +#endif + hitag_handle_frame(t0, frame_pos, frame); + memset(frame, 0, sizeof(frame)); + } + frame_pos = 0; + + } + LED_D_OFF(); + } + } + DbpString("All done"); +} + +static void hitag_send_bit(int t0, int bit) { + if(bit == 1) { + /* Manchester: Loaded, then unloaded */ + LED_A_ON(); + SHORT_COIL(); + while(AT91C_BASE_TC1->TC_CV < t0*15); + OPEN_COIL(); + while(AT91C_BASE_TC1->TC_CV < t0*31); + LED_A_OFF(); + } else if(bit == 0) { + /* Manchester: Unloaded, then loaded */ + LED_B_ON(); + OPEN_COIL(); + while(AT91C_BASE_TC1->TC_CV < t0*15); + SHORT_COIL(); + while(AT91C_BASE_TC1->TC_CV < t0*31); + LED_B_OFF(); + } + AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; /* Reset clock for the next bit */ + +} +static void hitag_send_frame(int t0, int frame_len, const char const * frame, int fdt) +{ + OPEN_COIL(); + AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; + + /* Wait for HITAG_T_WRESP carrier periods after the last reader bit, + * not that since the clock counts since the rising edge, but T_wresp is + * with respect to the falling edge, we need to wait actually (T_wresp - T_g) + * periods. The gap time T_g varies (4..10). + */ + while(AT91C_BASE_TC1->TC_CV < t0*(fdt-8)); + + int saved_cmr = AT91C_BASE_TC1->TC_CMR; + AT91C_BASE_TC1->TC_CMR &= ~AT91C_TC_ETRGEDG; /* Disable external trigger for the clock */ + AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; /* Reset the clock and use it for response timing */ + + int i; + for(i=0; i<5; i++) + hitag_send_bit(t0, 1); /* Start of frame */ + + for(i=0; iTC_CMR = saved_cmr; +} + +/* Callback structure to cleanly separate tag emulation code from the radio layer. */ +static int hitag_cb(const char* response_data, const int response_length, const int fdt, void *cb_cookie) +{ + hitag_send_frame(*(int*)cb_cookie, response_length, response_data, fdt); + return 0; +} +/* Frame length in bits, frame contents in MSBit first format */ +static void hitag_handle_frame(int t0, int frame_len, char *frame) +{ + hitag2_handle_command(frame, frame_len, hitag_cb, &t0); +} + // compose fc/8 fc/10 waveform static void fc(int c, int *n) { BYTE *dest = (BYTE *)BigBuf; @@ -616,13 +817,13 @@ void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol) m = sizeof(BigBuf); memset(dest,128,m); for(;;) { - if(SSC_STATUS & (SSC_STATUS_TX_READY)) { - SSC_TRANSMIT_HOLDING = 0x43; + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = 0x43; if (ledcontrol) LED_D_ON(); } - if(SSC_STATUS & (SSC_STATUS_RX_READY)) { - dest[i] = (BYTE)SSC_RECEIVE_HOLDING; + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + dest[i] = (BYTE)AT91C_BASE_SSC->SSC_RHR; // we don't care about actual value, only if it's more or less than a // threshold essentially we capture zero crossings for later analysis if(dest[i] < 127) dest[i] = 0; else dest[i] = 1;