X-Git-Url: http://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/72c4af087f2950bb445ae0c9c439724efe9a0d0e..15c4dc5ace24e6081d1597b011148f156cdd599e:/armsrc/lfops.c diff --git a/armsrc/lfops.c b/armsrc/lfops.c index a7e1f1df..14cc33a4 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1,971 +1,971 @@ -//----------------------------------------------------------------------------- -// Miscellaneous routines for low frequency tag operations. -// Tags supported here so far are Texas Instruments (TI), HID -// Also routines for raw mode reading/simulating of LF waveform -// -//----------------------------------------------------------------------------- -#include -#include "apps.h" -#include "hitag2.h" -#include "crc16.h" - -void AcquireRawAdcSamples125k(BOOL at134khz) -{ - if (at134khz) - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz - else - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); - - // Connect the A/D to the peak-detected low-frequency path. - SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - - // Give it a bit of time for the resonant antenna to settle. - SpinDelay(50); - - // Now set up the SSC to get the ADC samples that are now streaming at us. - FpgaSetupSsc(); - - // Now call the acquisition routine - DoAcquisition125k(); -} - -// split into two routines so we can avoid timing issues after sending commands // -void DoAcquisition125k(void) -{ - BYTE *dest = (BYTE *)BigBuf; - int n = sizeof(BigBuf); - int i; - - memset(dest, 0, n); - i = 0; - for(;;) { - if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { - AT91C_BASE_SSC->SSC_THR = 0x43; - LED_D_ON(); - } - if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { - dest[i] = (BYTE)AT91C_BASE_SSC->SSC_RHR; - i++; - LED_D_OFF(); - if (i >= n) break; - } - } - Dbprintf("buffer samples: %02x %02x %02x %02x %02x %02x %02x %02x ...", - dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); -} - -void ModThenAcquireRawAdcSamples125k(int delay_off, int period_0, int period_1, BYTE *command) -{ - 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; - else - at134khz = FALSE; - - if (at134khz) - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz - else - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); - - // 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(); - - // now modulate the reader field - while(*command != '\0' && *command != ' ') { - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_D_OFF(); - SpinDelayUs(delay_off); - if (at134khz) - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz - else - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); - LED_D_ON(); - if(*(command++) == '0') - SpinDelayUs(period_0); - else - SpinDelayUs(period_1); - } - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_D_OFF(); - SpinDelayUs(delay_off); - if (at134khz) - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz - else - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); - - // now do the read - DoAcquisition125k(); -} - -/* blank r/w tag data stream -...0000000000000000 01111111 -1010101010101010101010101010101010101010101010101010101010101010 -0011010010100001 -01111111 -101010101010101[0]000... - -[5555fe852c5555555555555555fe0000] -*/ -void ReadTItag(void) -{ - // 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); - - Dbprintf("Info: Tag data: %x%08x, crc=%x", - (unsigned int)shift1, (unsigned int)shift0, (unsigned int)shift2 & 0xFFFF); - if (crc != (shift2&0xffff)) { - Dbprintf("Error: CRC mismatch, expected %x", (unsigned int)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<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 - AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; - AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; - - 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 - AT91C_BASE_SSC->SSC_CMR = 12; - - 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 - HIGH(GPIO_SSC_DOUT); - - // Charge TI tag for 50ms. - SpinDelay(50); - - // stop modulating antenna and listen - LOW(GPIO_SSC_DOUT); - - LED_D_OFF(); - - i = 0; - for(;;) { - 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 - AT91C_BASE_PIOA->PIO_PDR = GPIO_SSC_DOUT; - AT91C_BASE_PIOA->PIO_ASR = GPIO_SSC_DIN | GPIO_SSC_DOUT; - - char *dest = (char *)BigBuf; - n = TIBUFLEN*32; - // unpack buffer - for (i=TIBUFLEN-1; i>=0; i--) { - for (j=0; j<32; j++) { - if(BigBuf[i] & (1 << j)) { - dest[--n] = 1; - } else { - dest[--n] = -1; - } - } - } -} - -// 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. -void WriteTItag(DWORD idhi, DWORD idlo, WORD crc) -{ - if(crc == 0) { - crc = update_crc16(crc, (idlo)&0xff); - crc = update_crc16(crc, (idlo>>8)&0xff); - crc = update_crc16(crc, (idlo>>16)&0xff); - crc = update_crc16(crc, (idlo>>24)&0xff); - crc = update_crc16(crc, (idhi)&0xff); - crc = update_crc16(crc, (idhi>>8)&0xff); - crc = update_crc16(crc, (idhi>>16)&0xff); - crc = update_crc16(crc, (idhi>>24)&0xff); - } - Dbprintf("Writing to tag: %x%08x, crc=%x", - (unsigned int) idhi, (unsigned int) idlo, crc); - - // 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); - LED_A_ON(); - - // steal this pin from the SSP and use it to control the modulation - AT91C_BASE_PIOA->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 - // a low bit consists of a field off for 0.3ms and field on for 1.7ms - // initiate a charge time of 50ms (field on) then immediately start writing bits - // start by writing 0xBB (keyword) and 0xEB (password) - // then write 80 bits of data (or 64 bit data + 16 bit crc if you prefer) - // finally end with 0x0300 (write frame) - // all data is sent lsb firts - // finish with 15ms programming time - - // modulate antenna - HIGH(GPIO_SSC_DOUT); - SpinDelay(50); // charge time - - WriteTIbyte(0xbb); // keyword - WriteTIbyte(0xeb); // password - WriteTIbyte( (idlo )&0xff ); - WriteTIbyte( (idlo>>8 )&0xff ); - WriteTIbyte( (idlo>>16)&0xff ); - WriteTIbyte( (idlo>>24)&0xff ); - WriteTIbyte( (idhi )&0xff ); - WriteTIbyte( (idhi>>8 )&0xff ); - WriteTIbyte( (idhi>>16)&0xff ); - WriteTIbyte( (idhi>>24)&0xff ); // data hi to lo - WriteTIbyte( (crc )&0xff ); // crc lo - WriteTIbyte( (crc>>8 )&0xff ); // crc hi - WriteTIbyte(0x00); // write frame lo - WriteTIbyte(0x03); // write frame hi - HIGH(GPIO_SSC_DOUT); - SpinDelay(50); // programming time - - LED_A_OFF(); - - // get TI tag data into the buffer - AcquireTiType(); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - DbpString("Now use tiread to check"); -} - -void SimulateTagLowFrequency(int period, int gap, int ledcontrol) -{ - int i; - BYTE *tab = (BYTE *)BigBuf; - - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_SIMULATOR); - - AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT | 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) - - i = 0; - for(;;) { - while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) { - if(BUTTON_PRESS()) { - DbpString("Stopped"); - return; - } - WDT_HIT(); - } - - if (ledcontrol) - LED_D_ON(); - - if(tab[i]) - OPEN_COIL(); - else - SHORT_COIL(); - - if (ledcontrol) - LED_D_OFF(); - - while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { - if(BUTTON_PRESS()) { - DbpString("Stopped"); - return; - } - WDT_HIT(); - } - - i++; - if(i == period) { - i = 0; - if (gap) { - SHORT_COIL(); - SpinDelayUs(gap); - } - } - } -} - -/* 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; - int idx; - - // for when we want an fc8 pattern every 4 logical bits - if(c==0) { - dest[((*n)++)]=1; - dest[((*n)++)]=1; - dest[((*n)++)]=0; - dest[((*n)++)]=0; - dest[((*n)++)]=0; - dest[((*n)++)]=0; - dest[((*n)++)]=0; - dest[((*n)++)]=0; - } - // an fc/8 encoded bit is a bit pattern of 11000000 x6 = 48 samples - if(c==8) { - for (idx=0; idx<6; idx++) { - dest[((*n)++)]=1; - dest[((*n)++)]=1; - dest[((*n)++)]=0; - dest[((*n)++)]=0; - dest[((*n)++)]=0; - dest[((*n)++)]=0; - dest[((*n)++)]=0; - dest[((*n)++)]=0; - } - } - - // an fc/10 encoded bit is a bit pattern of 1110000000 x5 = 50 samples - if(c==10) { - for (idx=0; idx<5; idx++) { - dest[((*n)++)]=1; - dest[((*n)++)]=1; - dest[((*n)++)]=1; - dest[((*n)++)]=0; - dest[((*n)++)]=0; - dest[((*n)++)]=0; - dest[((*n)++)]=0; - dest[((*n)++)]=0; - dest[((*n)++)]=0; - dest[((*n)++)]=0; - } - } -} - -// prepare a waveform pattern in the buffer based on the ID given then -// simulate a HID tag until the button is pressed -void CmdHIDsimTAG(int hi, int lo, int ledcontrol) -{ - int n=0, i=0; - /* - HID tag bitstream format - The tag contains a 44bit unique code. This is sent out MSB first in sets of 4 bits - A 1 bit is represented as 6 fc8 and 5 fc10 patterns - A 0 bit is represented as 5 fc10 and 6 fc8 patterns - A fc8 is inserted before every 4 bits - A special start of frame pattern is used consisting a0b0 where a and b are neither 0 - nor 1 bits, they are special patterns (a = set of 12 fc8 and b = set of 10 fc10) - */ - - if (hi>0xFFF) { - DbpString("Tags can only have 44 bits."); - return; - } - fc(0,&n); - // special start of frame marker containing invalid bit sequences - fc(8, &n); fc(8, &n); // invalid - fc(8, &n); fc(10, &n); // logical 0 - fc(10, &n); fc(10, &n); // invalid - fc(8, &n); fc(10, &n); // logical 0 - - WDT_HIT(); - // manchester encode bits 43 to 32 - for (i=11; i>=0; i--) { - if ((i%4)==3) fc(0,&n); - if ((hi>>i)&1) { - fc(10, &n); fc(8, &n); // low-high transition - } else { - fc(8, &n); fc(10, &n); // high-low transition - } - } - - WDT_HIT(); - // manchester encode bits 31 to 0 - for (i=31; i>=0; i--) { - if ((i%4)==3) fc(0,&n); - if ((lo>>i)&1) { - fc(10, &n); fc(8, &n); // low-high transition - } else { - fc(8, &n); fc(10, &n); // high-low transition - } - } - - if (ledcontrol) - LED_A_ON(); - SimulateTagLowFrequency(n, 0, ledcontrol); - - if (ledcontrol) - LED_A_OFF(); -} - - -// loop to capture raw HID waveform then FSK demodulate the TAG ID from it -void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol) -{ - BYTE *dest = (BYTE *)BigBuf; - int m=0, n=0, i=0, idx=0, found=0, lastval=0; - DWORD hi=0, lo=0; - - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); - - // Connect the A/D to the peak-detected low-frequency path. - SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - - // Give it a bit of time for the resonant antenna to settle. - SpinDelay(50); - - // Now set up the SSC to get the ADC samples that are now streaming at us. - FpgaSetupSsc(); - - for(;;) { - WDT_HIT(); - if (ledcontrol) - LED_A_ON(); - if(BUTTON_PRESS()) { - DbpString("Stopped"); - if (ledcontrol) - LED_A_OFF(); - return; - } - - i = 0; - m = sizeof(BigBuf); - memset(dest,128,m); - for(;;) { - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = 0x43; - if (ledcontrol) - LED_D_ON(); - } - 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; - i++; - if (ledcontrol) - LED_D_OFF(); - if(i >= m) { - break; - } - } - } - - // FSK demodulator - - // sync to first lo-hi transition - for( idx=1; idx>1) & 0xFFFF); - /* if we're only looking for one tag */ - if (findone) - { - *high = hi; - *low = lo; - return; - } - hi=0; - lo=0; - found=0; - } - } - if (found) { - if (dest[idx] && (!dest[idx+1]) ) { - hi=(hi<<1)|(lo>>31); - lo=(lo<<1)|0; - } else if ( (!dest[idx]) && dest[idx+1]) { - hi=(hi<<1)|(lo>>31); - lo=(lo<<1)|1; - } else { - found=0; - hi=0; - lo=0; - } - idx++; - } - if ( dest[idx] && dest[idx+1] && dest[idx+2] && (!dest[idx+3]) && (!dest[idx+4]) && (!dest[idx+5]) ) - { - found=1; - idx+=6; - if (found && (hi|lo)) { - Dbprintf("TAG ID: %x%08x (%d)", - (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); - /* if we're only looking for one tag */ - if (findone) - { - *high = hi; - *low = lo; - return; - } - hi=0; - lo=0; - found=0; - } - } - } - WDT_HIT(); - } -} +//----------------------------------------------------------------------------- +// Miscellaneous routines for low frequency tag operations. +// Tags supported here so far are Texas Instruments (TI), HID +// Also routines for raw mode reading/simulating of LF waveform +// +//----------------------------------------------------------------------------- +#include +#include "apps.h" +#include "hitag2.h" +#include "crc16.h" + +void AcquireRawAdcSamples125k(BOOL at134khz) +{ + if (at134khz) + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz + else + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); + + // Connect the A/D to the peak-detected low-frequency path. + SetAdcMuxFor(GPIO_MUXSEL_LOPKD); + + // Give it a bit of time for the resonant antenna to settle. + SpinDelay(50); + + // Now set up the SSC to get the ADC samples that are now streaming at us. + FpgaSetupSsc(); + + // Now call the acquisition routine + DoAcquisition125k(); +} + +// split into two routines so we can avoid timing issues after sending commands // +void DoAcquisition125k(void) +{ + BYTE *dest = (BYTE *)BigBuf; + int n = sizeof(BigBuf); + int i; + + memset(dest, 0, n); + i = 0; + for(;;) { + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { + AT91C_BASE_SSC->SSC_THR = 0x43; + LED_D_ON(); + } + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { + dest[i] = (BYTE)AT91C_BASE_SSC->SSC_RHR; + i++; + LED_D_OFF(); + if (i >= n) break; + } + } + Dbprintf("buffer samples: %02x %02x %02x %02x %02x %02x %02x %02x ...", + dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); +} + +void ModThenAcquireRawAdcSamples125k(int delay_off, int period_0, int period_1, BYTE *command) +{ + 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; + else + at134khz = FALSE; + + if (at134khz) + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz + else + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); + + // 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(); + + // now modulate the reader field + while(*command != '\0' && *command != ' ') { + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); + SpinDelayUs(delay_off); + if (at134khz) + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz + else + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); + LED_D_ON(); + if(*(command++) == '0') + SpinDelayUs(period_0); + else + SpinDelayUs(period_1); + } + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); + SpinDelayUs(delay_off); + if (at134khz) + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz + else + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); + + // now do the read + DoAcquisition125k(); +} + +/* blank r/w tag data stream +...0000000000000000 01111111 +1010101010101010101010101010101010101010101010101010101010101010 +0011010010100001 +01111111 +101010101010101[0]000... + +[5555fe852c5555555555555555fe0000] +*/ +void ReadTItag(void) +{ + // 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); + + Dbprintf("Info: Tag data: %x%08x, crc=%x", + (unsigned int)shift1, (unsigned int)shift0, (unsigned int)shift2 & 0xFFFF); + if (crc != (shift2&0xffff)) { + Dbprintf("Error: CRC mismatch, expected %x", (unsigned int)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<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 + AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; + AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; + + 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 + AT91C_BASE_SSC->SSC_CMR = 12; + + 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 + HIGH(GPIO_SSC_DOUT); + + // Charge TI tag for 50ms. + SpinDelay(50); + + // stop modulating antenna and listen + LOW(GPIO_SSC_DOUT); + + LED_D_OFF(); + + i = 0; + for(;;) { + 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 + AT91C_BASE_PIOA->PIO_PDR = GPIO_SSC_DOUT; + AT91C_BASE_PIOA->PIO_ASR = GPIO_SSC_DIN | GPIO_SSC_DOUT; + + char *dest = (char *)BigBuf; + n = TIBUFLEN*32; + // unpack buffer + for (i=TIBUFLEN-1; i>=0; i--) { + for (j=0; j<32; j++) { + if(BigBuf[i] & (1 << j)) { + dest[--n] = 1; + } else { + dest[--n] = -1; + } + } + } +} + +// 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. +void WriteTItag(DWORD idhi, DWORD idlo, WORD crc) +{ + if(crc == 0) { + crc = update_crc16(crc, (idlo)&0xff); + crc = update_crc16(crc, (idlo>>8)&0xff); + crc = update_crc16(crc, (idlo>>16)&0xff); + crc = update_crc16(crc, (idlo>>24)&0xff); + crc = update_crc16(crc, (idhi)&0xff); + crc = update_crc16(crc, (idhi>>8)&0xff); + crc = update_crc16(crc, (idhi>>16)&0xff); + crc = update_crc16(crc, (idhi>>24)&0xff); + } + Dbprintf("Writing to tag: %x%08x, crc=%x", + (unsigned int) idhi, (unsigned int) idlo, crc); + + // 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); + LED_A_ON(); + + // steal this pin from the SSP and use it to control the modulation + AT91C_BASE_PIOA->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 + // a low bit consists of a field off for 0.3ms and field on for 1.7ms + // initiate a charge time of 50ms (field on) then immediately start writing bits + // start by writing 0xBB (keyword) and 0xEB (password) + // then write 80 bits of data (or 64 bit data + 16 bit crc if you prefer) + // finally end with 0x0300 (write frame) + // all data is sent lsb firts + // finish with 15ms programming time + + // modulate antenna + HIGH(GPIO_SSC_DOUT); + SpinDelay(50); // charge time + + WriteTIbyte(0xbb); // keyword + WriteTIbyte(0xeb); // password + WriteTIbyte( (idlo )&0xff ); + WriteTIbyte( (idlo>>8 )&0xff ); + WriteTIbyte( (idlo>>16)&0xff ); + WriteTIbyte( (idlo>>24)&0xff ); + WriteTIbyte( (idhi )&0xff ); + WriteTIbyte( (idhi>>8 )&0xff ); + WriteTIbyte( (idhi>>16)&0xff ); + WriteTIbyte( (idhi>>24)&0xff ); // data hi to lo + WriteTIbyte( (crc )&0xff ); // crc lo + WriteTIbyte( (crc>>8 )&0xff ); // crc hi + WriteTIbyte(0x00); // write frame lo + WriteTIbyte(0x03); // write frame hi + HIGH(GPIO_SSC_DOUT); + SpinDelay(50); // programming time + + LED_A_OFF(); + + // get TI tag data into the buffer + AcquireTiType(); + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + DbpString("Now use tiread to check"); +} + +void SimulateTagLowFrequency(int period, int gap, int ledcontrol) +{ + int i; + BYTE *tab = (BYTE *)BigBuf; + + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_SIMULATOR); + + AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT | 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) + + i = 0; + for(;;) { + while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) { + if(BUTTON_PRESS()) { + DbpString("Stopped"); + return; + } + WDT_HIT(); + } + + if (ledcontrol) + LED_D_ON(); + + if(tab[i]) + OPEN_COIL(); + else + SHORT_COIL(); + + if (ledcontrol) + LED_D_OFF(); + + while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { + if(BUTTON_PRESS()) { + DbpString("Stopped"); + return; + } + WDT_HIT(); + } + + i++; + if(i == period) { + i = 0; + if (gap) { + SHORT_COIL(); + SpinDelayUs(gap); + } + } + } +} + +/* 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; + int idx; + + // for when we want an fc8 pattern every 4 logical bits + if(c==0) { + dest[((*n)++)]=1; + dest[((*n)++)]=1; + dest[((*n)++)]=0; + dest[((*n)++)]=0; + dest[((*n)++)]=0; + dest[((*n)++)]=0; + dest[((*n)++)]=0; + dest[((*n)++)]=0; + } + // an fc/8 encoded bit is a bit pattern of 11000000 x6 = 48 samples + if(c==8) { + for (idx=0; idx<6; idx++) { + dest[((*n)++)]=1; + dest[((*n)++)]=1; + dest[((*n)++)]=0; + dest[((*n)++)]=0; + dest[((*n)++)]=0; + dest[((*n)++)]=0; + dest[((*n)++)]=0; + dest[((*n)++)]=0; + } + } + + // an fc/10 encoded bit is a bit pattern of 1110000000 x5 = 50 samples + if(c==10) { + for (idx=0; idx<5; idx++) { + dest[((*n)++)]=1; + dest[((*n)++)]=1; + dest[((*n)++)]=1; + dest[((*n)++)]=0; + dest[((*n)++)]=0; + dest[((*n)++)]=0; + dest[((*n)++)]=0; + dest[((*n)++)]=0; + dest[((*n)++)]=0; + dest[((*n)++)]=0; + } + } +} + +// prepare a waveform pattern in the buffer based on the ID given then +// simulate a HID tag until the button is pressed +void CmdHIDsimTAG(int hi, int lo, int ledcontrol) +{ + int n=0, i=0; + /* + HID tag bitstream format + The tag contains a 44bit unique code. This is sent out MSB first in sets of 4 bits + A 1 bit is represented as 6 fc8 and 5 fc10 patterns + A 0 bit is represented as 5 fc10 and 6 fc8 patterns + A fc8 is inserted before every 4 bits + A special start of frame pattern is used consisting a0b0 where a and b are neither 0 + nor 1 bits, they are special patterns (a = set of 12 fc8 and b = set of 10 fc10) + */ + + if (hi>0xFFF) { + DbpString("Tags can only have 44 bits."); + return; + } + fc(0,&n); + // special start of frame marker containing invalid bit sequences + fc(8, &n); fc(8, &n); // invalid + fc(8, &n); fc(10, &n); // logical 0 + fc(10, &n); fc(10, &n); // invalid + fc(8, &n); fc(10, &n); // logical 0 + + WDT_HIT(); + // manchester encode bits 43 to 32 + for (i=11; i>=0; i--) { + if ((i%4)==3) fc(0,&n); + if ((hi>>i)&1) { + fc(10, &n); fc(8, &n); // low-high transition + } else { + fc(8, &n); fc(10, &n); // high-low transition + } + } + + WDT_HIT(); + // manchester encode bits 31 to 0 + for (i=31; i>=0; i--) { + if ((i%4)==3) fc(0,&n); + if ((lo>>i)&1) { + fc(10, &n); fc(8, &n); // low-high transition + } else { + fc(8, &n); fc(10, &n); // high-low transition + } + } + + if (ledcontrol) + LED_A_ON(); + SimulateTagLowFrequency(n, 0, ledcontrol); + + if (ledcontrol) + LED_A_OFF(); +} + + +// loop to capture raw HID waveform then FSK demodulate the TAG ID from it +void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol) +{ + BYTE *dest = (BYTE *)BigBuf; + int m=0, n=0, i=0, idx=0, found=0, lastval=0; + DWORD hi=0, lo=0; + + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); + + // Connect the A/D to the peak-detected low-frequency path. + SetAdcMuxFor(GPIO_MUXSEL_LOPKD); + + // Give it a bit of time for the resonant antenna to settle. + SpinDelay(50); + + // Now set up the SSC to get the ADC samples that are now streaming at us. + FpgaSetupSsc(); + + for(;;) { + WDT_HIT(); + if (ledcontrol) + LED_A_ON(); + if(BUTTON_PRESS()) { + DbpString("Stopped"); + if (ledcontrol) + LED_A_OFF(); + return; + } + + i = 0; + m = sizeof(BigBuf); + memset(dest,128,m); + for(;;) { + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = 0x43; + if (ledcontrol) + LED_D_ON(); + } + 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; + i++; + if (ledcontrol) + LED_D_OFF(); + if(i >= m) { + break; + } + } + } + + // FSK demodulator + + // sync to first lo-hi transition + for( idx=1; idx>1) & 0xFFFF); + /* if we're only looking for one tag */ + if (findone) + { + *high = hi; + *low = lo; + return; + } + hi=0; + lo=0; + found=0; + } + } + if (found) { + if (dest[idx] && (!dest[idx+1]) ) { + hi=(hi<<1)|(lo>>31); + lo=(lo<<1)|0; + } else if ( (!dest[idx]) && dest[idx+1]) { + hi=(hi<<1)|(lo>>31); + lo=(lo<<1)|1; + } else { + found=0; + hi=0; + lo=0; + } + idx++; + } + if ( dest[idx] && dest[idx+1] && dest[idx+2] && (!dest[idx+3]) && (!dest[idx+4]) && (!dest[idx+5]) ) + { + found=1; + idx+=6; + if (found && (hi|lo)) { + Dbprintf("TAG ID: %x%08x (%d)", + (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); + /* if we're only looking for one tag */ + if (findone) + { + *high = hi; + *low = lo; + return; + } + hi=0; + lo=0; + found=0; + } + } + } + WDT_HIT(); + } +}