X-Git-Url: https://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/ddcb2bb5ca908a1a262bb86b59325cf5b5fb0312..3458bb279b00048892e56cec6f0a13e8c03f97db:/armsrc/lfops.c?ds=inline diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 7e53d4a5..995a8810 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -4,7 +4,7 @@ // the license. //----------------------------------------------------------------------------- // Miscellaneous routines for low frequency tag operations. -// Tags supported here so far are Texas Instruments (TI), HID +// Tags supported here so far are Texas Instruments (TI), HID, EM4x05, EM410x // Also routines for raw mode reading/simulating of LF waveform //----------------------------------------------------------------------------- @@ -16,8 +16,9 @@ #include "string.h" #include "lfdemod.h" #include "lfsampling.h" +#include "protocols.h" #include "usb_cdc.h" - +#include "fpgaloader.h" /** * Function to do a modulation and then get samples. @@ -26,54 +27,106 @@ * @param period_1 * @param command */ -void ModThenAcquireRawAdcSamples125k(int delay_off, int period_0, int period_1, uint8_t *command) +void ModThenAcquireRawAdcSamples125k(uint32_t delay_off, uint32_t period_0, uint32_t period_1, uint8_t *command) { + // start timer + StartTicks(); - int divisor_used = 95; // 125 KHz - // see if 'h' was specified - - if (command[strlen((char *) command) - 1] == 'h') - divisor_used = 88; // 134.8 KHz + // use lf config settings + sample_config *sc = getSamplingConfig(); - sample_config sc = { 0,0,1, divisor_used, 0}; - setSamplingConfig(&sc); - - /* Make sure the tag is reset */ + // Make sure the tag is reset FpgaDownloadAndGo(FPGA_BITSTREAM_LF); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(2500); + WaitMS(2500); - LFSetupFPGAForADC(sc.divisor, 1); + // clear read buffer (after fpga bitstream loaded...) + BigBuf_Clear_keep_EM(); - // And a little more time for the tag to fully power up - SpinDelay(2000); + // power on + LFSetupFPGAForADC(sc->divisor, 1); + // And a little more time for the tag to fully power up + WaitMS(2000); + // if delay_off = 0 then just bitbang 1 = antenna on 0 = off for respective periods. + bool bitbang = delay_off == 0; // now modulate the reader field - while(*command != '\0' && *command != ' ') { + + if (bitbang) { + // HACK it appears the loop and if statements take up about 7us so adjust waits accordingly... + uint8_t hack_cnt = 7; + if (period_0 < hack_cnt || period_1 < hack_cnt) { + DbpString("Warning periods cannot be less than 7us in bit bang mode"); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); + return; + } + + // hack2 needed--- it appears to take about 8-16us to turn the antenna back on + // leading to ~ 1 to 2 125khz samples extra in every off period + // so we should test for last 0 before next 1 and reduce period_0 by this extra amount... + // but is this time different for every antenna or other hw builds??? more testing needed + + // prime cmd_len to save time comparing strings while modulating + int cmd_len = 0; + while(command[cmd_len] != '\0' && command[cmd_len] != ' ') + cmd_len++; + + int counter = 0; + bool off = false; + for (counter = 0; counter < cmd_len; counter++) { + // if cmd = 0 then turn field off + if (command[counter] == '0') { + // if field already off leave alone (affects timing otherwise) + if (off == false) { + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); + off = true; + } + // note we appear to take about 7us to switch over (or run the if statements/loop...) + WaitUS(period_0-hack_cnt); + // else if cmd = 1 then turn field on + } else { + // if field already on leave alone (affects timing otherwise) + if (off) { + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); + LED_D_ON(); + off = false; + } + // note we appear to take about 7us to switch over (or run the if statements/loop...) + WaitUS(period_1-hack_cnt); + } + } + } else { // old mode of cmd read using delay as off period + while(*command != '\0' && *command != ' ') { + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); + WaitUS(delay_off); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, sc->divisor); + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); + LED_D_ON(); + if(*(command++) == '0') { + WaitUS(period_0); + } else { + WaitUS(period_1); + } + } FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LED_D_OFF(); - SpinDelayUs(delay_off); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, sc.divisor); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); - LED_D_ON(); - if(*(command++) == '0') - SpinDelayUs(period_0); - else - SpinDelayUs(period_1); + WaitUS(delay_off); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, sc->divisor); } - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_D_OFF(); - SpinDelayUs(delay_off); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, sc.divisor); FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); // now do the read - DoAcquisition_config(false); -} - + DoAcquisition_config(false, 0); + // Turn off antenna + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + // tell client we are done + cmd_send(CMD_ACK,0,0,0,0,0); +} /* blank r/w tag data stream ...0000000000000000 01111111 @@ -248,7 +301,7 @@ void AcquireTiType(void) // clear buffer uint32_t *BigBuf = (uint32_t *)BigBuf_get_addr(); - memset(BigBuf,0,BigBuf_max_traceLen()/sizeof(uint32_t)); + BigBuf_Clear_ext(false); // Set up the synchronous serial port AT91C_BASE_PIOA->PIO_PDR = GPIO_SSC_DIN; @@ -379,7 +432,7 @@ void WriteTItag(uint32_t idhi, uint32_t idlo, uint16_t crc) AcquireTiType(); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - DbpString("Now use tiread to check"); + DbpString("Now use `lf ti read` to check"); } void SimulateTagLowFrequency(int period, int gap, int ledcontrol) @@ -387,7 +440,8 @@ void SimulateTagLowFrequency(int period, int gap, int ledcontrol) int i; uint8_t *tab = BigBuf_get_addr(); - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + //note FpgaDownloadAndGo destroys the bigbuf so be sure this is called before now... + //FpgaDownloadAndGo(FPGA_BITSTREAM_LF); FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT | GPIO_SSC_CLK; @@ -395,18 +449,25 @@ void SimulateTagLowFrequency(int period, int gap, int ledcontrol) 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 SHORT_COIL() LOW(GPIO_SSC_DOUT) + #define OPEN_COIL() HIGH(GPIO_SSC_DOUT) i = 0; for(;;) { //wait until SSC_CLK goes HIGH + int ii = 0; while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) { - if(BUTTON_PRESS() || usb_poll()) { - DbpString("Stopped"); - return; + //only check every 1000th time (usb_poll_validate_length on some systems was too slow) + if ( ii == 1000 ) { + if (BUTTON_PRESS() || usb_poll_validate_length() ) { + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + DbpString("Stopped"); + return; + } + ii=0; } WDT_HIT(); + ii++; } if (ledcontrol) LED_D_ON(); @@ -418,13 +479,20 @@ void SimulateTagLowFrequency(int period, int gap, int ledcontrol) if (ledcontrol) LED_D_OFF(); + ii=0; //wait until SSC_CLK goes LOW while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { - if(BUTTON_PRESS()) { - DbpString("Stopped"); - return; + //only check every 1000th time (usb_poll_validate_length on some systems was too slow) + if ( ii == 1000 ) { + if (BUTTON_PRESS() || usb_poll_validate_length() ) { + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + DbpString("Stopped"); + return; + } + ii=0; } WDT_HIT(); + ii++; } i++; @@ -436,6 +504,7 @@ void SimulateTagLowFrequency(int period, int gap, int ledcontrol) SpinDelayUs(gap); } } + } } @@ -500,7 +569,7 @@ static void fcAll(uint8_t fc, int *n, uint8_t clock, uint16_t *modCnt) uint8_t wavesPerClock = clock/fc; uint8_t mod = clock % fc; //modifier uint8_t modAdj = fc/mod; //how often to apply modifier - bool modAdjOk = !(fc % mod); //if (fc % mod==0) modAdjOk=TRUE; + bool modAdjOk = !(fc % mod); //if (fc % mod==0) modAdjOk=true; // loop through clock - step field clock for (uint8_t idx=0; idx < wavesPerClock; idx++){ // put 1/2 FC length 1's and 1/2 0's per field clock wave (to create the wave) @@ -525,7 +594,7 @@ static void fcAll(uint8_t fc, int *n, uint8_t clock, uint16_t *modCnt) // 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) +void CmdHIDsimTAG(int hi2, int hi, int lo, int ledcontrol) { int n=0, i=0; /* @@ -538,10 +607,13 @@ void CmdHIDsimTAG(int hi, int lo, int ledcontrol) 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. - USE lf simfsk for larger tags"); + if (hi2>0x0FFFFFFF) { + DbpString("Tags can only have 44 or 84 bits. - USE lf simfsk for larger tags"); return; } + // set LF so we don't kill the bigbuf we are setting with simulation data. + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + fc(0,&n); // special start of frame marker containing invalid bit sequences fc(8, &n); fc(8, &n); // invalid @@ -550,13 +622,35 @@ void CmdHIDsimTAG(int hi, int lo, int ledcontrol) 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 + if (hi2 > 0 || hi > 0xFFF){ + // manchester encode bits 91 to 64 (91-84 are part of the header) + for (i=27; i>=0; i--) { + if ((i%4)==3) fc(0,&n); + if ((hi2>>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 63 to 32 + for (i=31; 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 + } + } + } else { + // 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 + } } } @@ -592,6 +686,9 @@ void CmdFSKsimTAG(uint16_t arg1, uint16_t arg2, size_t size, uint8_t *BitStream) uint8_t clk = arg2 & 0xFF; uint8_t invert = (arg2 >> 8) & 1; + // set LF so we don't kill the bigbuf we are setting with simulation data. + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + for (i=0; i> 8) & 1; + // set LF so we don't kill the bigbuf we are setting with simulation data. + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + if (encoding==2){ //biphase uint8_t phase=0; for (i=0; i0 && lo>0 && (size==96 || size==192)){ + uint8_t bitlen = 0; + uint32_t fc = 0; + uint32_t cardnum = 0; + bool decoded = false; + // go over previously decoded manchester data and decode into usable tag ID - if (hi2 != 0){ //extra large HID tags 88/192 bits - Dbprintf("TAG ID: %x%08x%08x (%d)", - (unsigned int) hi2, (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); - }else { //standard HID tags 44/96 bits - //Dbprintf("TAG ID: %x%08x (%d)",(unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); //old print cmd - uint8_t bitlen = 0; - uint32_t fc = 0; - uint32_t cardnum = 0; - if (((hi>>5)&1) == 1){//if bit 38 is set then < 37 bit format is used - uint32_t lo2=0; - lo2=(((hi & 31) << 12) | (lo>>20)); //get bits 21-37 to check for format len bit - uint8_t idx3 = 1; - while(lo2 > 1){ //find last bit set to 1 (format len bit) - lo2=lo2 >> 1; - idx3++; - } - bitlen = idx3+19; - fc =0; - cardnum=0; - if(bitlen == 26){ - cardnum = (lo>>1)&0xFFFF; - fc = (lo>>17)&0xFF; - } - if(bitlen == 37){ - cardnum = (lo>>1)&0x7FFFF; - fc = ((hi&0xF)<<12)|(lo>>20); - } - if(bitlen == 34){ - cardnum = (lo>>1)&0xFFFF; - fc= ((hi&1)<<15)|(lo>>17); - } - if(bitlen == 35){ - cardnum = (lo>>1)&0xFFFFF; - fc = ((hi&1)<<11)|(lo>>21); - } + if ((hi2 & 0x000FFFF) != 0){ //extra large HID tags 88/192 bits + uint32_t bp = hi2 & 0x000FFFFF; + bitlen = 63; + while (bp > 0) { + bp = bp >> 1; + bitlen++; } - else { //if bit 38 is not set then 37 bit format is used - bitlen= 37; - fc =0; - cardnum=0; - if(bitlen==37){ - cardnum = (lo>>1)&0x7FFFF; - fc = ((hi&0xF)<<12)|(lo>>20); - } + } else if ((hi >> 6) > 0) { + uint32_t bp = hi; + bitlen = 31; + while (bp > 0) { + bp = bp >> 1; + bitlen++; } - //Dbprintf("TAG ID: %x%08x (%d)", - // (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); - Dbprintf("TAG ID: %x%08x (%d) - Format Len: %dbit - FC: %d - Card: %d", - (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF, - (unsigned int) bitlen, (unsigned int) fc, (unsigned int) cardnum); + } else if (((hi >> 5) & 1) == 0) { + bitlen = 37; + } else if ((hi & 0x0000001F) > 0 ) { + uint32_t bp = (hi & 0x0000001F); + bitlen = 31; + while (bp > 0) { + bp = bp >> 1; + bitlen++; + } + } else { + uint32_t bp = lo; + bitlen = 0; + while (bp > 0) { + bp = bp >> 1; + bitlen++; + } + } + switch (bitlen){ + case 26: + cardnum = (lo>>1)&0xFFFF; + fc = (lo>>17)&0xFF; + decoded = true; + break; + case 35: + cardnum = (lo>>1)&0xFFFFF; + fc = ((hi&1)<<11)|(lo>>21); + decoded = true; + break; } + + if (hi2 != 0) //extra large HID tags 88/192 bits + Dbprintf("TAG ID: %x%08x%08x (%d)", + (unsigned int) hi2, (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); + else + Dbprintf("TAG ID: %x%08x (%d)", + (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); + + if (decoded) + Dbprintf("Format Len: %dbits - FC: %d - Card: %d", + (unsigned int) bitlen, (unsigned int) fc, (unsigned int) cardnum); + if (findone){ if (ledcontrol) LED_A_OFF(); + *high2 = hi2; *high = hi; *low = lo; - return; + break; } // reset } hi2 = hi = lo = idx = 0; WDT_HIT(); } + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + DbpString("Stopped"); + if (ledcontrol) LED_A_OFF(); +} + +// loop to get raw HID waveform then FSK demodulate the TAG ID from it +void CmdAWIDdemodFSK(int findone, int *high, int *low, int ledcontrol) +{ + uint8_t *dest = BigBuf_get_addr(); + size_t size; + int idx=0, dummyIdx=0; + //clear read buffer + BigBuf_Clear_keep_EM(); + // Configure to go in 125Khz listen mode + LFSetupFPGAForADC(95, true); + + while(!BUTTON_PRESS() && !usb_poll_validate_length()) { + + WDT_HIT(); + if (ledcontrol) LED_A_ON(); + + DoAcquisition_default(-1,true); + // FSK demodulator + size = 50*128*2; //big enough to catch 2 sequences of largest format + idx = AWIDdemodFSK(dest, &size, &dummyIdx); + + if (idx<=0 || size!=96) continue; + // Index map + // 0 10 20 30 40 50 60 + // | | | | | | | + // 01234567 890 1 234 5 678 9 012 3 456 7 890 1 234 5 678 9 012 3 456 7 890 1 234 5 678 9 012 3 - to 96 + // ----------------------------------------------------------------------------- + // 00000001 000 1 110 1 101 1 011 1 101 1 010 0 000 1 000 1 010 0 001 0 110 1 100 0 000 1 000 1 + // premable bbb o bbb o bbw o fff o fff o ffc o ccc o ccc o ccc o ccc o ccc o wxx o xxx o xxx o - to 96 + // |---26 bit---| |-----117----||-------------142-------------| + // b = format bit len, o = odd parity of last 3 bits + // f = facility code, c = card number + // w = wiegand parity + // (26 bit format shown) + + //get raw ID before removing parities + uint32_t rawLo = bytebits_to_byte(dest+idx+64,32); + uint32_t rawHi = bytebits_to_byte(dest+idx+32,32); + uint32_t rawHi2 = bytebits_to_byte(dest+idx,32); + + size = removeParity(dest, idx+8, 4, 1, 88); + if (size != 66) continue; + // ok valid card found! + + // Index map + // 0 10 20 30 40 50 60 + // | | | | | | | + // 01234567 8 90123456 7890123456789012 3 456789012345678901234567890123456 + // ----------------------------------------------------------------------------- + // 00011010 1 01110101 0000000010001110 1 000000000000000000000000000000000 + // bbbbbbbb w ffffffff cccccccccccccccc w xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + // |26 bit| |-117--| |-----142------| + // b = format bit len, o = odd parity of last 3 bits + // f = facility code, c = card number + // w = wiegand parity + // (26 bit format shown) + + uint32_t fc = 0; + uint32_t cardnum = 0; + uint32_t code1 = 0; + uint32_t code2 = 0; + uint8_t fmtLen = bytebits_to_byte(dest,8); + if (fmtLen==26){ + fc = bytebits_to_byte(dest+9, 8); + cardnum = bytebits_to_byte(dest+17, 16); + code1 = bytebits_to_byte(dest+8,fmtLen); + Dbprintf("AWID Found - BitLength: %d, FC: %d, Card: %d - Wiegand: %x, Raw: %08x%08x%08x", fmtLen, fc, cardnum, code1, rawHi2, rawHi, rawLo); + } else { + cardnum = bytebits_to_byte(dest+8+(fmtLen-17), 16); + if (fmtLen>32){ + code1 = bytebits_to_byte(dest+8,fmtLen-32); + code2 = bytebits_to_byte(dest+8+(fmtLen-32),32); + Dbprintf("AWID Found - BitLength: %d -unknown BitLength- (%d) - Wiegand: %x%08x, Raw: %08x%08x%08x", fmtLen, cardnum, code1, code2, rawHi2, rawHi, rawLo); + } else{ + code1 = bytebits_to_byte(dest+8,fmtLen); + Dbprintf("AWID Found - BitLength: %d -unknown BitLength- (%d) - Wiegand: %x, Raw: %08x%08x%08x", fmtLen, cardnum, code1, rawHi2, rawHi, rawLo); + } + } + if (findone){ + if (ledcontrol) LED_A_OFF(); + break; + } + // reset + idx = 0; + WDT_HIT(); + } + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); DbpString("Stopped"); if (ledcontrol) LED_A_OFF(); } @@ -849,10 +1065,12 @@ void CmdEM410xdemod(int findone, int *high, int *low, int ledcontrol) int clk=0, invert=0, errCnt=0, maxErr=20; uint32_t hi=0; uint64_t lo=0; + //clear read buffer + BigBuf_Clear_keep_EM(); // Configure to go in 125Khz listen mode LFSetupFPGAForADC(95, true); - while(!BUTTON_PRESS()) { + while(!BUTTON_PRESS() && !usb_poll_validate_length()) { WDT_HIT(); if (ledcontrol) LED_A_ON(); @@ -889,13 +1107,14 @@ void CmdEM410xdemod(int findone, int *high, int *low, int ledcontrol) if (ledcontrol) LED_A_OFF(); *high=lo>>32; *low=lo & 0xFFFFFFFF; - return; + break; } } WDT_HIT(); hi = lo = size = idx = 0; clk = invert = errCnt = 0; } + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); DbpString("Stopped"); if (ledcontrol) LED_A_OFF(); } @@ -908,16 +1127,19 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) uint8_t version=0; uint8_t facilitycode=0; uint16_t number=0; + int dummyIdx=0; + //clear read buffer + BigBuf_Clear_keep_EM(); // Configure to go in 125Khz listen mode LFSetupFPGAForADC(95, true); - while(!BUTTON_PRESS()) { + while(!BUTTON_PRESS() && !usb_poll_validate_length()) { WDT_HIT(); if (ledcontrol) LED_A_ON(); DoAcquisition_default(-1,true); //fskdemod and get start index WDT_HIT(); - idx = IOdemodFSK(dest, BigBuf_max_traceLen()); + idx = IOdemodFSK(dest, BigBuf_max_traceLen(), &dummyIdx); if (idx<0) continue; //valid tag found @@ -952,7 +1174,7 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) //LED_A_OFF(); *high=code; *low=code2; - return; + break; } code=code2=0; version=facilitycode=0; @@ -961,242 +1183,426 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) WDT_HIT(); } + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); DbpString("Stopped"); if (ledcontrol) LED_A_OFF(); } /*------------------------------ - * T5555/T5557/T5567 routines + * T5555/T5557/T5567/T5577 routines *------------------------------ - */ - -/* T55x7 configuration register definitions */ -#define T55x7_POR_DELAY 0x00000001 -#define T55x7_ST_TERMINATOR 0x00000008 -#define T55x7_PWD 0x00000010 -#define T55x7_MAXBLOCK_SHIFT 5 -#define T55x7_AOR 0x00000200 -#define T55x7_PSKCF_RF_2 0 -#define T55x7_PSKCF_RF_4 0x00000400 -#define T55x7_PSKCF_RF_8 0x00000800 -#define T55x7_MODULATION_DIRECT 0 -#define T55x7_MODULATION_PSK1 0x00001000 -#define T55x7_MODULATION_PSK2 0x00002000 -#define T55x7_MODULATION_PSK3 0x00003000 -#define T55x7_MODULATION_FSK1 0x00004000 -#define T55x7_MODULATION_FSK2 0x00005000 -#define T55x7_MODULATION_FSK1a 0x00006000 -#define T55x7_MODULATION_FSK2a 0x00007000 -#define T55x7_MODULATION_MANCHESTER 0x00008000 -#define T55x7_MODULATION_BIPHASE 0x00010000 -#define T55x7_BITRATE_RF_8 0 -#define T55x7_BITRATE_RF_16 0x00040000 -#define T55x7_BITRATE_RF_32 0x00080000 -#define T55x7_BITRATE_RF_40 0x000C0000 -#define T55x7_BITRATE_RF_50 0x00100000 -#define T55x7_BITRATE_RF_64 0x00140000 -#define T55x7_BITRATE_RF_100 0x00180000 -#define T55x7_BITRATE_RF_128 0x001C0000 - -/* T5555 (Q5) configuration register definitions */ -#define T5555_ST_TERMINATOR 0x00000001 -#define T5555_MAXBLOCK_SHIFT 0x00000001 -#define T5555_MODULATION_MANCHESTER 0 -#define T5555_MODULATION_PSK1 0x00000010 -#define T5555_MODULATION_PSK2 0x00000020 -#define T5555_MODULATION_PSK3 0x00000030 -#define T5555_MODULATION_FSK1 0x00000040 -#define T5555_MODULATION_FSK2 0x00000050 -#define T5555_MODULATION_BIPHASE 0x00000060 -#define T5555_MODULATION_DIRECT 0x00000070 -#define T5555_INVERT_OUTPUT 0x00000080 -#define T5555_PSK_RF_2 0 -#define T5555_PSK_RF_4 0x00000100 -#define T5555_PSK_RF_8 0x00000200 -#define T5555_USE_PWD 0x00000400 -#define T5555_USE_AOR 0x00000800 -#define T5555_BITRATE_SHIFT 12 -#define T5555_FAST_WRITE 0x00004000 -#define T5555_PAGE_SELECT 0x00008000 - -/* - * Relevant times in microsecond + * NOTE: T55x7/T5555 configuration register definitions moved to protocols.h + * + * Relevant communication times in microsecond * To compensate antenna falling times shorten the write times * and enlarge the gap ones. + * Q5 tags seems to have issues when these values changes. */ + + /* + // Original Timings for reference +//note startgap must be sent after tag has been powered up for more than 3ms (per T5557 ds) + #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 READ_GAP 15*8 -#define T55xx_SAMPLES_SIZE 12000 // 32 x 32 x 10 (32 bit times numofblock (7), times clock skip..) +*/ +/* Q5 timing datasheet: + * Type | MIN | Typical | Max | + * Start_Gap | 10*8 | ? | 50*8 | + * Write_Gap Normal mode | 8*8 | 14*8 | 20*8 | + * Write_Gap Fast Mode | 8*8 | ? | 20*8 | + * Write_0 Normal mode | 16*8 | 24*8 | 32*8 | + * Write_1 Normal mode | 48*8 | 56*8 | 64*8 | + * Write_0 Fast Mode | 8*8 | 12*8 | 16*8 | + * Write_1 Fast Mode | 24*8 | 28*8 | 32*8 | +*/ -// Write one bit to card -void T55xxWriteBit(int bit) -{ - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz +/* T5557 timing datasheet: + * Type | MIN | Typical | Max | + * Start_Gap | 10*8 | ? | 50*8 | + * Write_Gap Normal mode | 8*8 |50-150us | 30*8 | + * Write_Gap Fast Mode | 8*8 | ? | 20*8 | + * Write_0 Normal mode | 16*8 | 24*8 | 31*8 | + * Write_1 Normal mode | 48*8 | 54*8 | 63*8 | + * Write_0 Fast Mode | 8*8 | 12*8 | 15*8 | + * Write_1 Fast Mode | 24*8 | 28*8 | 31*8 | +*/ + +/* T5577C timing datasheet for Fixed-Bit-Length protocol (defualt): + * Type | MIN | Typical | Max | + * Start_Gap | 8*8 | 15*8 | 50*8 | + * Write_Gap Normal mode | 8*8 | 10*8 | 20*8 | + * Write_Gap Fast Mode | 8*8 | 10*8 | 20*8 | + * Write_0 Normal mode | 16*8 | 24*8 | 32*8 | + * Write_1 Normal mode | 48*8 | 56*8 | 64*8 | + * Write_0 Fast Mode | 8*8 | 12*8 | 16*8 | + * Write_1 Fast Mode | 24*8 | 28*8 | 32*8 | +*/ + +// Structure to hold Timing values. In future will be simplier to add user changable timings. +typedef struct { + uint16_t START_GAP; + uint16_t WRITE_GAP; + uint16_t WRITE_0; + uint16_t WRITE_1; + uint16_t WRITE_2; + uint16_t WRITE_3; + uint16_t READ_GAP; +} T55xx_Timing; + +// Set Initial/Default Values. Note: *8 can occure when used. This should keep things simplier here. +T55xx_Timing T55xx_Timing_FixedBit = { 31 * 8 , 20 * 8 , 18 * 8 , 50 * 8 , 0 , 0 , 15 * 8 }; +T55xx_Timing T55xx_Timing_LLR = { 31 * 8 , 20 * 8 , 18 * 8 , 50 * 8 , 0 , 0 , 15 * 8 }; +T55xx_Timing T55xx_Timing_Leading0 = { 31 * 8 , 20 * 8 , 18 * 8 , 40 * 8 , 0 , 0 , 15 * 8 }; +T55xx_Timing T55xx_Timing_1of4 = { 31 * 8 , 20 * 8 , 18 * 8 , 34 * 8 , 50 * 8 , 66 * 8 , 15 * 8 }; + +// Some defines for readability +#define T55xx_DLMode_Fixed 0 // Default Mode +#define T55xx_DLMode_LLR 1 // Long Leading Reference +#define T55xx_DLMode_Leading0 2 // Leading Zero +#define T55xx_DLMode_1of4 3 // 1 of 4 +#define T55xx_LongLeadingReference 4 // Value to tell Write Bit to send long reference +// Macro for code readability +#define BitStream_Byte(X) ((X) >> 3) +#define BitStream_Bit(X) ((X) & 7) + + +void TurnReadLFOn(int delay) { FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); - if (bit == 0) - SpinDelayUs(WRITE_0); - else - SpinDelayUs(WRITE_1); + // Give it a bit of time for the resonant antenna to settle. + WaitUS(delay); //155*8 //50*8 +} + +// Write one bit to card +void T55xxWriteBit(int bit, T55xx_Timing *Timings) { + + // If bit = 4 Send Long Leading Reference which is 138 + WRITE_0 + // Dbprintf ("Bits : %d",bit); + switch (bit){ + case 0 : TurnReadLFOn(Timings->WRITE_0); break; // Send bit 0/00 + case 1 : TurnReadLFOn(Timings->WRITE_1); break; // Send bit 1/01 + case 2 : TurnReadLFOn(Timings->WRITE_2); break; // Send bits 10 + case 3 : TurnReadLFOn(Timings->WRITE_3); break; // Send bits 11 + case 4 : TurnReadLFOn(Timings->WRITE_0 + (136 * 8)); break; // Send Long Leading Reference + } FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelayUs(WRITE_GAP); + WaitUS(Timings->WRITE_GAP); } -// Write one card block in page 0, no lock -void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t PwdMode) +// Function to abstract an Arbitrary length byte array to store bit pattern. +// bit_array - Array to hold data/bit pattern +// start_offset - bit location to start storing new bits. +// data - upto 32 bits of data to store +// num_bits - how many bits (low x bits of data) Max 32 bits at a time +// max_len - how many bytes can the bit_array hold (ensure no buffer overflow) +// returns "Next" bit offset / bits stored (for next store) +//int T55xx_SetBits (uint8_t *bit_array, int start_offset, uint32_t data , int num_bits, int max_len) +int T55xx_SetBits (uint8_t *BitStream, uint8_t start_offset, uint32_t data , uint8_t num_bits, uint8_t max_len) { - uint32_t i = 0; + int8_t offset; + int8_t NextOffset = start_offset; - // Set up FPGA, 125kHz - // Wait for config.. (192+8190xPOW)x8 == 67ms - LFSetupFPGAForADC(0, true); + // Check if data will fit. + if ((start_offset + num_bits) <= (max_len*8)) { + // Loop through the data and store + for (offset = (num_bits-1); offset >= 0; offset--) { - // Now start writting - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelayUs(START_GAP); - - // Opcode - T55xxWriteBit(1); - T55xxWriteBit(0); //Page 0 - if (PwdMode == 1){ - // Pwd - for (i = 0x80000000; i != 0; i >>= 1) - T55xxWriteBit(Pwd & i); + if ((data >> offset) & 1) BitStream[BitStream_Byte(NextOffset)] |= (1 << BitStream_Bit(NextOffset)); // Set the bit to 1 + else BitStream[BitStream_Byte(NextOffset)] &= (0xff ^ (1 << BitStream_Bit(NextOffset))); // Set the bit to 0 + + NextOffset++; + } } - // Lock bit - T55xxWriteBit(0); + else { + // Note: This should never happen unless some code changes cause it. + // So short message for coders when testing. + Dbprintf ("T55 too many bits"); + } + return NextOffset; +} - // Data - for (i = 0x80000000; i != 0; i >>= 1) - T55xxWriteBit(Data & i); +// Send one downlink command to the card +void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { - // Block - for (i = 0x04; i != 0; i >>= 1) - T55xxWriteBit(Block & i); + /* + arg bits + xxxxxxx1 0x01 PwdMode + xxxxxx1x 0x02 Page + xxxxx1xx 0x04 testMode + xxx11xxx 0x18 downlink mode + xx1xxxxx 0x20 !reg_readmode + x1xxxxxx 0x40 called for a read, so no data packet + 1xxxxxxx 0x80 reset - // Now perform write (nominal is 5.6 ms for T55x7 and 18ms for E5550, - // so wait a little more) - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); - SpinDelay(20); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); -} + */ + bool PwdMode = ((arg & 0x01) == 0x01); + bool Page = (arg & 0x02); + bool testMode = ((arg & 0x04) == 0x04); + uint8_t downlink_mode = (arg >> 3) & 0x03; + bool reg_readmode = ((arg & 0x20) == 0x20); + bool read_cmd = ((arg & 0x40) == 0x40); + bool reset = (arg & 0x80); + + uint8_t i = 0; + uint8_t BitStream[10]; // Max Downlink Command size ~74 bits, so 10 bytes (80 bits) + uint8_t BitStreamLen; + T55xx_Timing *Timing; + uint8_t SendBits; + + // Assigning Downlink Timeing for write + switch (downlink_mode) + { + case T55xx_DLMode_Fixed : Timing = &T55xx_Timing_FixedBit; break; + case T55xx_DLMode_LLR : Timing = &T55xx_Timing_LLR; break; + case T55xx_DLMode_Leading0 : Timing = &T55xx_Timing_Leading0; break; + case T55xx_DLMode_1of4 : Timing = &T55xx_Timing_1of4; break; + default: + Timing = &T55xx_Timing_FixedBit; + } -void TurnReadLFOn(){ - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); - // Give it a bit of time for the resonant antenna to settle. - SpinDelayUs(8*150); -} + // Build Bit Stream to send. + memset (BitStream,0x00,sizeof(BitStream)); + + BitStreamLen = 0; // Ensure 0 bit index to start. + + // Add Leading 0 and 1 of 4 reference bit + if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4)) + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); + + // Add extra reference 0 for 1 of 4 + if (downlink_mode == T55xx_DLMode_1of4) + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); + + // Add Opcode + if (reset) { + // Reset : r*) 00 + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 2,sizeof(BitStream)); + } + else + { + if (testMode) Dbprintf("TestMODE"); + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,testMode ? 0 : 1 , 1,sizeof(BitStream)); + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,testMode ? 1 : Page , 1,sizeof(BitStream)); + + if (PwdMode) { + // Leading 0 and 1 of 4 00 fixed bits if passsword used + if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4)) { + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 2,sizeof(BitStream)); + } + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Pwd, 32,sizeof(BitStream)); + } + // Add Lock bit 0 + if (!reg_readmode) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); -// Read one card block in page 0 -void T55xxReadBlock(uint32_t Block, uint32_t Pwd, uint8_t PwdMode) -{ - uint32_t i = 0; - uint8_t *dest = BigBuf_get_addr(); - uint16_t bufferlength = BigBuf_max_traceLen(); - if ( bufferlength > T55xx_SAMPLES_SIZE ) - bufferlength = T55xx_SAMPLES_SIZE; + // Add Data if a write command + if (!read_cmd) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Data, 32,sizeof(BitStream)); - // Clear destination buffer before sending the command - memset(dest, 0x80, bufferlength); + // Add Address + if (!reg_readmode) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Block, 3,sizeof(BitStream)); + } + // Send Bits to T55xx // Set up FPGA, 125kHz - // Wait for config.. (192+8190xPOW)x8 == 67ms - LFSetupFPGAForADC(0, true); + LFSetupFPGAForADC(95, true); + StartTicks(); + // make sure tag is fully powered up... + WaitMS(5); + // Trigger T55x7 in mode. FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelayUs(START_GAP); - - // Opcode - T55xxWriteBit(1); - T55xxWriteBit(0); //Page 0 - if (PwdMode == 1){ - // Pwd - for (i = 0x80000000; i != 0; i >>= 1) - T55xxWriteBit(Pwd & i); - } - // Lock bit - T55xxWriteBit(0); - // Block - for (i = 0x04; i != 0; i >>= 1) - T55xxWriteBit(Block & i); + WaitUS(Timing->START_GAP); - // Turn field on to read the response - TurnReadLFOn(); - // Now do the acquisition - i = 0; - for(;;) { - if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { - AT91C_BASE_SSC->SSC_THR = 0x43; - LED_D_ON(); + // If long leading 0 send long reference pulse + if (downlink_mode == T55xx_DLMode_LLR) + T55xxWriteBit (T55xx_LongLeadingReference,Timing); // Send Long Leading Start Reference + + if ((downlink_mode == T55xx_DLMode_1of4) && (BitStreamLen > 0)) { // 1 of 4 need to send 2 bits at a time + for ( i = 0; i < BitStreamLen-1; i+=2 ) { + SendBits = (BitStream[BitStream_Byte(i )] >> (BitStream_Bit(i )) & 1) << 1; // Bit i + SendBits += (BitStream[BitStream_Byte(i+1)] >> (BitStream_Bit(i+1)) & 1); // Bit i+1; + T55xxWriteBit (SendBits & 3,Timing); } - if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { - dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - i++; - LED_D_OFF(); - if (i >= bufferlength) break; + } + else { + for (i = 0; i < BitStreamLen; i++) { + SendBits = (BitStream[BitStream_Byte(i)] >> BitStream_Bit(i)); + T55xxWriteBit (SendBits & 1,Timing); } } +} - cmd_send(CMD_ACK,0,0,0,0,0); +// Send T5577 reset command then read stream (see if we can identify the start of the stream) +void T55xxResetRead(void) { + LED_A_ON(); + + // send r* 00 + uint8_t arg = 0x80; // SendCMD will add correct reference mode based on flags (when added). + + // Add in downlink_mode when ready + // arg |= 0x00; // dlmode << 3 (00 default - 08 leading 0 - 10 Fixed - 18 1 of 4 ) + + //clear buffer now so it does not interfere with timing later + BigBuf_Clear_keep_EM(); + + T55xx_SendCMD (0, 0, 0, arg); //, true); + + TurnReadLFOn(T55xx_Timing_FixedBit.READ_GAP); + + // Acquisition + DoPartialAcquisition(0, true, BigBuf_max_traceLen(), 0); + + // Turn the field off FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off - LED_D_OFF(); + cmd_send(CMD_ACK,0,0,0,0,0); + LED_A_OFF(); } -// Read card traceability data (page 1) -void T55xxReadTrace(void){ +// Write one card block in page 0, no lock +void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { + /* + arg bits + xxxxxxx1 0x01 PwdMode + xxxxxx1x 0x02 Page + xxxxx1xx 0x04 testMode + xxx11xxx 0x18 downlink mode + xx1xxxxx 0x20 !reg_readmode + x1xxxxxx 0x40 called for a read, so no data packet + 1xxxxxxx 0x80 reset + */ - uint32_t i = 0; - uint8_t *dest = BigBuf_get_addr(); - uint16_t bufferlength = BigBuf_max_traceLen(); - if ( bufferlength > T55xx_SAMPLES_SIZE ) - bufferlength= T55xx_SAMPLES_SIZE; + bool testMode = ((arg & 0x04) == 0x04); + arg &= (0xff ^ 0x40); // Called for a write, so ensure it is clear/0 + + LED_A_ON (); + T55xx_SendCMD (Data, Block, Pwd, arg) ;//, false); - // Clear destination buffer before sending the command - memset(dest, 0x80, bufferlength); + // Perform write (nominal is 5.6 ms for T55x7 and 18ms for E5550, + // so wait a little more) + + // "there is a clock delay before programming" + // - programming takes ~5.6ms for t5577 ~18ms for E5550 or t5567 + // so we should wait 1 clock + 5.6ms then read response? + // but we need to know we are dealing with t5577 vs t5567 vs e5550 (or q5) marshmellow... + if (testMode) { + //TESTMODE TIMING TESTS: + // <566us does nothing + // 566-568 switches between wiping to 0s and doing nothing + // 5184 wipes and allows 1 block to be programmed. + // indefinite power on wipes and then programs all blocks with bitshifted data sent. + TurnReadLFOn(5184); - LFSetupFPGAForADC(0, true); + } else { + TurnReadLFOn(20 * 1000); + //could attempt to do a read to confirm write took + // as the tag should repeat back the new block + // until it is reset, but to confirm it we would + // need to know the current block 0 config mode for + // modulation clock an other details to demod the response... + // response should be (for t55x7) a 0 bit then (ST if on) + // block data written in on repeat until reset. + + //DoPartialAcquisition(20, true, 12000); + } + // turn field off FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelayUs(START_GAP); - // Opcode - T55xxWriteBit(1); - T55xxWriteBit(1); //Page 1 + cmd_send(CMD_ACK,0,0,0,0,0); + + LED_A_OFF (); +} + +// Read one card block in page [page] +void T55xxReadBlock (uint16_t arg0, uint8_t Block, uint32_t Pwd) {//, struct T55xx_Timing *Timing) { + + LED_A_ON(); + + /* + arg bits + xxxxxxx1 0x01 PwdMode + xxxxxx1x 0x02 Page + xxxxx1xx 0x04 testMode + xxx11xxx 0x18 downlink mode + xx1xxxxx 0x20 !reg_readmode + x1xxxxxx 0x40 called for a read, so no data packet + 1xxxxxxx 0x80 reset + */ + + // Set Read Flag to ensure SendCMD does not add "data" to the packet + arg0 |= 0x40; + + // RegRead Mode true of block 0xff + if (Block == 0xff) arg0 |= 0x20; + + //make sure block is at max 7 + Block &= 0x7; + + //clear buffer now so it does not interfere with timing later + BigBuf_Clear_ext(false); + + T55xx_SendCMD (0, Block, Pwd, arg0); //, true); // Turn field on to read the response - TurnReadLFOn(); + // 137*8 seems to get to the start of data pretty well... + // but we want to go past the start and let the repeating data settle in... + TurnReadLFOn(210*8); + // Acquisition // Now do the acquisition - 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] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - i++; - LED_D_OFF(); - - if (i >= bufferlength) break; - } - } + DoPartialAcquisition(0, true, 12000, 0); - cmd_send(CMD_ACK,0,0,0,0,0); + // Turn the field off FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off - LED_D_OFF(); + cmd_send(CMD_ACK,0,0,0,0,0); + + LED_A_OFF(); +} + +void T55xxWakeUp(uint32_t Pwd){ + LED_B_ON(); + /* + arg bits + xxxxxxx1 0x01 PwdMode + xxxxxx1x 0x02 Page + xxxxx1xx 0x04 testMode + xxx11xxx 0x18 downlink mode + xx1xxxxx 0x20 !reg_readmode + x1xxxxxx 0x40 called for a read, so no data packet + 1xxxxxxx 0x80 reset + */ + + // r* 10 (00) r* for llr , L0 and 1/4 - (00) for L0 and 1/4 - All handled in SendCMD + // So, default Opcode 10 and pwd. + uint8_t arg = 0x01 | 0x40 | 0x20; //Password Read Call no data | reg_read no block + + // Add in downlink_mode when ready + // arg |= 0x00; // dlmode << 3 (00 default - 08 leading 0 - 10 Fixed - 18 1 of 4 ) + + T55xx_SendCMD (0, 0, Pwd, arg); //, true); + + // Turn and leave field on to let the begin repeating transmission + TurnReadLFOn(20*1000); } /*-------------- Cloning routines -----------*/ -// Copy HID id to card and setup block 0 config -void CopyHIDtoT55x7(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT) -{ - int data1=0, data2=0, data3=0, data4=0, data5=0, data6=0; //up to six blocks for long format - int last_block = 0; - if (longFMT){ +void WriteT55xx(uint32_t *blockdata, uint8_t startblock, uint8_t numblocks) { + // write last block first and config block last (if included) + for (uint8_t i = numblocks+startblock; i > startblock; i--) { + T55xxWriteBlock(blockdata[i-1],i-1,0,0);//,false); //,&T55xx_Timing_FixedBit); + //T55xx_SendCMD (blockdata[i-1],i-1,0,0);//,false); //,&T55xx_Timing_FixedBit); + } +} + +// Copy a HID-like card (e.g. HID Proximity, Paradox) to a T55x7 compatible card +void CopyHIDtoT55x7(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT, uint8_t preamble) { + uint32_t data[] = {0,0,0,0,0,0,0}; + uint8_t last_block = 0; + + if (longFMT) { // Ensure no more than 84 bits supplied if (hi2>0xFFFFF) { DbpString("Tags can only have 84 bits."); @@ -1204,140 +1610,100 @@ void CopyHIDtoT55x7(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT) } // Build the 6 data blocks for supplied 84bit ID last_block = 6; - data1 = 0x1D96A900; // load preamble (1D) & long format identifier (9E manchester encoded) - for (int i=0;i<4;i++) { - if (hi2 & (1<<(19-i))) - data1 |= (1<<(((3-i)*2)+1)); // 1 -> 10 - else - data1 |= (1<<((3-i)*2)); // 0 -> 01 - } - - data2 = 0; - for (int i=0;i<16;i++) { - if (hi2 & (1<<(15-i))) - data2 |= (1<<(((15-i)*2)+1)); // 1 -> 10 - else - data2 |= (1<<((15-i)*2)); // 0 -> 01 - } - - data3 = 0; - for (int i=0;i<16;i++) { - if (hi & (1<<(31-i))) - data3 |= (1<<(((15-i)*2)+1)); // 1 -> 10 - else - data3 |= (1<<((15-i)*2)); // 0 -> 01 - } - - data4 = 0; - for (int i=0;i<16;i++) { - if (hi & (1<<(15-i))) - data4 |= (1<<(((15-i)*2)+1)); // 1 -> 10 - else - data4 |= (1<<((15-i)*2)); // 0 -> 01 - } - - data5 = 0; - for (int i=0;i<16;i++) { - if (lo & (1<<(31-i))) - data5 |= (1<<(((15-i)*2)+1)); // 1 -> 10 - else - data5 |= (1<<((15-i)*2)); // 0 -> 01 - } - - data6 = 0; - for (int i=0;i<16;i++) { - if (lo & (1<<(15-i))) - data6 |= (1<<(((15-i)*2)+1)); // 1 -> 10 - else - data6 |= (1<<((15-i)*2)); // 0 -> 01 - } - } - else { + // load preamble & long format identifier (9E manchester encoded) + data[1] = (preamble << 24) | 0x96A900 | (manchesterEncode2Bytes((hi2 >> 16) & 0xF) & 0xFF); + // load raw id from hi2, hi, lo to data blocks (manchester encoded) + data[2] = manchesterEncode2Bytes(hi2 & 0xFFFF); + data[3] = manchesterEncode2Bytes(hi >> 16); + data[4] = manchesterEncode2Bytes(hi & 0xFFFF); + data[5] = manchesterEncode2Bytes(lo >> 16); + data[6] = manchesterEncode2Bytes(lo & 0xFFFF); + } else { // Ensure no more than 44 bits supplied if (hi>0xFFF) { DbpString("Tags can only have 44 bits."); return; } - // Build the 3 data blocks for supplied 44bit ID last_block = 3; - - data1 = 0x1D000000; // load preamble - - for (int i=0;i<12;i++) { - if (hi & (1<<(11-i))) - data1 |= (1<<(((11-i)*2)+1)); // 1 -> 10 - else - data1 |= (1<<((11-i)*2)); // 0 -> 01 - } - - data2 = 0; - for (int i=0;i<16;i++) { - if (lo & (1<<(31-i))) - data2 |= (1<<(((15-i)*2)+1)); // 1 -> 10 - else - data2 |= (1<<((15-i)*2)); // 0 -> 01 - } - - data3 = 0; - for (int i=0;i<16;i++) { - if (lo & (1<<(15-i))) - data3 |= (1<<(((15-i)*2)+1)); // 1 -> 10 - else - data3 |= (1<<((15-i)*2)); // 0 -> 01 - } + // load preamble + data[1] = (preamble << 24) | (manchesterEncode2Bytes(hi) & 0xFFFFFF); + data[2] = manchesterEncode2Bytes(lo >> 16); + data[3] = manchesterEncode2Bytes(lo & 0xFFFF); } + // load chip config block + data[0] = T55x7_BITRATE_RF_50 | T55x7_MODULATION_FSK2a | last_block << T55x7_MAXBLOCK_SHIFT; + + //TODO add selection of chip for Q5 or T55x7 + // data[0] = (((50-2)/2)<>1)<> 32), 1, 0, 0); - T55xxWriteBlock((uint32_t)id, 2, 0, 0); - - // Config for EM410x (RF/64, Manchester, Maxblock=2) - if (card) { - // Clock rate is stored in bits 8-15 of the card value - clock = (card & 0xFF00) >> 8; - Dbprintf("Clock rate: %d", clock); - switch (clock) - { - case 32: - clock = T55x7_BITRATE_RF_32; - break; - case 16: - clock = T55x7_BITRATE_RF_16; - break; - case 0: - // A value of 0 is assumed to be 64 for backwards-compatibility - // Fall through... - case 64: - clock = T55x7_BITRATE_RF_64; - break; - default: + uint32_t data[] = {0, (uint32_t)(id>>32), (uint32_t)(id & 0xFFFFFFFF)}; + + clock = (card & 0xFF00) >> 8; + clock = (clock == 0) ? 64 : clock; + Dbprintf("Clock rate: %d", clock); + if (card & 0xFF) { //t55x7 + clock = GetT55xxClockBit(clock); + if (clock == 0) { Dbprintf("Invalid clock rate: %d", clock); return; } - - // Writing configuration for T55x7 tag - T55xxWriteBlock(clock | - T55x7_MODULATION_MANCHESTER | - 2 << T55x7_MAXBLOCK_SHIFT, - 0, 0, 0); + data[0] = clock | T55x7_MODULATION_MANCHESTER | (2 << T55x7_MAXBLOCK_SHIFT); + } else { //t5555 (Q5) + data[0] = T5555_SET_BITRATE(clock) | T5555_MODULATION_MANCHESTER | (2 << T5555_MAXBLOCK_SHIFT); } - else - // Writing configuration for T5555(Q5) tag - T55xxWriteBlock(0x1F << T5555_BITRATE_SHIFT | - T5555_MODULATION_MANCHESTER | - 2 << T5555_MAXBLOCK_SHIFT, - 0, 0, 0); + + WriteT55xx(data, 0, 3); LED_D_OFF(); Dbprintf("Tag %s written with 0x%08x%08x\n", card ? "T55x7":"T5555", (uint32_t)(id >> 32), (uint32_t)id); } -// Clone Indala 64-bit tag by UID to T55x7 -void CopyIndala64toT55x7(int hi, int lo) -{ - - //Program the 2 data blocks for supplied 64bit UID - // and the block 0 for Indala64 format - T55xxWriteBlock(hi,1,0,0); - T55xxWriteBlock(lo,2,0,0); - //Config for Indala (RF/32;PSK1 with RF/2;Maxblock=2) - T55xxWriteBlock(T55x7_BITRATE_RF_32 | - T55x7_MODULATION_PSK1 | - 2 << T55x7_MAXBLOCK_SHIFT, - 0, 0, 0); - //Alternative config for Indala (Extended mode;RF/32;PSK1 with RF/2;Maxblock=2;Inverse data) - // T5567WriteBlock(0x603E1042,0); - - DbpString("DONE!"); - -} - -void CopyIndala224toT55x7(int uid1, int uid2, int uid3, int uid4, int uid5, int uid6, int uid7) -{ - - //Program the 7 data blocks for supplied 224bit UID - // and the block 0 for Indala224 format - T55xxWriteBlock(uid1,1,0,0); - T55xxWriteBlock(uid2,2,0,0); - T55xxWriteBlock(uid3,3,0,0); - T55xxWriteBlock(uid4,4,0,0); - T55xxWriteBlock(uid5,5,0,0); - T55xxWriteBlock(uid6,6,0,0); - T55xxWriteBlock(uid7,7,0,0); - //Config for Indala (RF/32;PSK1 with RF/2;Maxblock=7) - T55xxWriteBlock(T55x7_BITRATE_RF_32 | - T55x7_MODULATION_PSK1 | - 7 << T55x7_MAXBLOCK_SHIFT, - 0,0,0); - //Alternative config for Indala (Extended mode;RF/32;PSK1 with RF/2;Maxblock=7;Inverse data) - // T5567WriteBlock(0x603E10E2,0); - - DbpString("DONE!"); - -} - - -#define abs(x) ( ((x)<0) ? -(x) : (x) ) -#define max(x,y) ( x GraphBuffer[0]) { - while(i < GraphTraceLen) { - if( !(GraphBuffer[i] > GraphBuffer[i-1]) && GraphBuffer[i] > lmax) - break; - i++; - } - dir = 0; - } - else { - while(i < GraphTraceLen) { - if( !(GraphBuffer[i] < GraphBuffer[i-1]) && GraphBuffer[i] < lmin) - break; - i++; - } - dir = 1; - } - - lastval = i++; - half_switch = 0; - pmc = 0; - block_done = 0; - - for (bitidx = 0; i < GraphTraceLen; i++) - { - if ( (GraphBuffer[i-1] > GraphBuffer[i] && dir == 1 && GraphBuffer[i] > lmax) || (GraphBuffer[i-1] < GraphBuffer[i] && dir == 0 && GraphBuffer[i] < lmin)) - { - lc = i - lastval; - lastval = i; - - // Switch depending on lc length: - // Tolerance is 1/8 of clock rate (arbitrary) - if (abs(lc-clock/4) < tolerance) { - // 16T0 - if((i - pmc) == lc) { /* 16T0 was previous one */ - /* It's a PMC ! */ - i += (128+127+16+32+33+16)-1; - lastval = i; - pmc = 0; - block_done = 1; - } - else { - pmc = i; - } - } else if (abs(lc-clock/2) < tolerance) { - // 32TO - if((i - pmc) == lc) { /* 16T0 was previous one */ - /* It's a PMC ! */ - i += (128+127+16+32+33)-1; - lastval = i; - pmc = 0; - block_done = 1; - } - else if(half_switch == 1) { - BitStream[bitidx++] = 0; - half_switch = 0; - } - else - half_switch++; - } else if (abs(lc-clock) < tolerance) { - // 64TO - BitStream[bitidx++] = 1; - } else { - // Error - warnings++; - if (warnings > 10) - { - Dbprintf("Error: too many detection errors, aborting."); - return 0; - } - } - - if(block_done == 1) { - if(bitidx == 128) { - for(j=0; j<16; j++) { - Blocks[num_blocks][j] = 128*BitStream[j*8+7]+ - 64*BitStream[j*8+6]+ - 32*BitStream[j*8+5]+ - 16*BitStream[j*8+4]+ - 8*BitStream[j*8+3]+ - 4*BitStream[j*8+2]+ - 2*BitStream[j*8+1]+ - BitStream[j*8]; - } - num_blocks++; - } - bitidx = 0; - block_done = 0; - half_switch = 0; - } - if(i < GraphTraceLen) - { - if (GraphBuffer[i-1] > GraphBuffer[i]) dir=0; - else dir = 1; - } - } - if(bitidx==255) - bitidx=0; - warnings = 0; - if(num_blocks == 4) break; - } - memcpy(outBlocks, Blocks, 16*num_blocks); - return num_blocks; -} - -int IsBlock0PCF7931(uint8_t *Block) { - // Assume RFU means 0 :) - if((memcmp(Block, "\x00\x00\x00\x00\x00\x00\x00\x01", 8) == 0) && memcmp(Block+9, "\x00\x00\x00\x00\x00\x00\x00", 7) == 0) // PAC enabled - return 1; - if((memcmp(Block+9, "\x00\x00\x00\x00\x00\x00\x00", 7) == 0) && Block[7] == 0) // PAC disabled, can it *really* happen ? - return 1; - return 0; -} - -int IsBlock1PCF7931(uint8_t *Block) { - // Assume RFU means 0 :) - if(Block[10] == 0 && Block[11] == 0 && Block[12] == 0 && Block[13] == 0) - if((Block[14] & 0x7f) <= 9 && Block[15] <= 9) - return 1; - - return 0; -} - -#define ALLOC 16 - -void ReadPCF7931() { - uint8_t Blocks[8][17]; - uint8_t tmpBlocks[4][16]; - int i, j, ind, ind2, n; - int num_blocks = 0; - int max_blocks = 8; - int ident = 0; - int error = 0; - int tries = 0; - - memset(Blocks, 0, 8*17*sizeof(uint8_t)); - - do { - memset(tmpBlocks, 0, 4*16*sizeof(uint8_t)); - n = DemodPCF7931((uint8_t**)tmpBlocks); - if(!n) - error++; - if(error==10 && num_blocks == 0) { - Dbprintf("Error, no tag or bad tag"); - return; - } - else if (tries==20 || error==10) { - Dbprintf("Error reading the tag"); - Dbprintf("Here is the partial content"); - goto end; - } - - for(i=0; i= 0; ind--,ind2--) { - if(ind2 < 0) - ind2 = max_blocks; - if(!Blocks[ind2][ALLOC]) { // Block ind2 not already found - // Dbprintf("Tmp %d -> Block %d", ind, ind2); - memcpy(Blocks[ind2], tmpBlocks[ind], 16); - Blocks[ind2][ALLOC] = 1; - num_blocks++; - if(num_blocks == max_blocks) goto end; - } - } - for(ind=i+1,ind2=j+1; ind < n; ind++,ind2++) { - if(ind2 > max_blocks) - ind2 = 0; - if(!Blocks[ind2][ALLOC]) { // Block ind2 not already found - // Dbprintf("Tmp %d -> Block %d", ind, ind2); - memcpy(Blocks[ind2], tmpBlocks[ind], 16); - Blocks[ind2][ALLOC] = 1; - num_blocks++; - if(num_blocks == max_blocks) goto end; - } - } - } - } - } - } - } - tries++; - if (BUTTON_PRESS()) return; - } while (num_blocks != max_blocks); - end: - Dbprintf("-----------------------------------------"); - Dbprintf("Memory content:"); - Dbprintf("-----------------------------------------"); - for(i=0; i", i); - } - Dbprintf("-----------------------------------------"); - - return ; -} - - //----------------------------------- // EM4469 / EM4305 routines //----------------------------------- @@ -1758,7 +1793,7 @@ void ReadPCF7931() { #define FWD_CMD_WRITE 0xA #define FWD_CMD_READ 0x9 #define FWD_CMD_DISABLE 0x5 - +#define FWD_CMD_PROTECT 0x3 uint8_t forwardLink_data[64]; //array of forwarded bits uint8_t * forward_ptr; //ptr for forward message preparation @@ -1770,8 +1805,15 @@ uint8_t * fwd_write_ptr; //forwardlink bit pointer // see EM4469 spec //==================================================================== //-------------------------------------------------------------------- +// VALUES TAKEN FROM EM4x function: SendForward +// START_GAP = 440; (55*8) cycles at 125Khz (8us = 1cycle) +// WRITE_GAP = 128; (16*8) +// WRITE_1 = 256 32*8; (32*8) + +// These timings work for 4469/4269/4305 (with the 55*8 above) +// WRITE_0 = 23*8 , 9*8 SpinDelayUs(23*8); + uint8_t Prepare_Cmd( uint8_t cmd ) { - //-------------------------------------------------------------------- *forward_ptr++ = 0; //start bit *forward_ptr++ = 0; //second pause for 4050 code @@ -1791,10 +1833,7 @@ uint8_t Prepare_Cmd( uint8_t cmd ) { // prepares address bits // see EM4469 spec //==================================================================== - -//-------------------------------------------------------------------- uint8_t Prepare_Addr( uint8_t addr ) { - //-------------------------------------------------------------------- register uint8_t line_parity; @@ -1815,10 +1854,7 @@ uint8_t Prepare_Addr( uint8_t addr ) { // prepares data bits intreleaved with parity bits // see EM4469 spec //==================================================================== - -//-------------------------------------------------------------------- uint8_t Prepare_Data( uint16_t data_low, uint16_t data_hi) { - //-------------------------------------------------------------------- register uint8_t line_parity; register uint8_t column_parity; @@ -1860,37 +1896,27 @@ void SendForward(uint8_t fwd_bit_count) { fwd_write_ptr = forwardLink_data; fwd_bit_sz = fwd_bit_count; - LED_D_ON(); - - //Field on - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); - - // Give it a bit of time for the resonant antenna to settle. - // And for the tag to fully power up - SpinDelay(150); + // Set up FPGA, 125kHz or 95 divisor + LFSetupFPGAForADC(95, true); // force 1st mod pulse (start gap must be longer for 4305) fwd_bit_sz--; //prepare next bit modulation fwd_write_ptr++; FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off - SpinDelayUs(55*8); //55 cycles off (8us each)for 4305 - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + WaitUS(55*8); //55 cycles off (8us each)for 4305 //another reader has 37 here... FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);//field on - SpinDelayUs(16*8); //16 cycles on (8us each) + WaitUS(18*8); //18 cycles on (8us each) - // now start writting + // now start writting - each bit should be 32*8 total length while(fwd_bit_sz-- > 0) { //prepare next bit modulation if(((*fwd_write_ptr++) & 1) == 1) - SpinDelayUs(32*8); //32 cycles at 125Khz (8us each) + WaitUS(32*8); //32 cycles at 125Khz (8us each) else { //These timings work for 4469/4269/4305 (with the 55*8 above) FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off - SpinDelayUs(23*8); //16-4 cycles off (8us each) - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + WaitUS(23*8); //23 cycles off (8us each) FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);//field on - SpinDelayUs(9*8); //16 cycles on (8us each) + WaitUS((32-23)*8); //remaining cycles on (8us each) } } } @@ -1907,15 +1933,17 @@ void EM4xLogin(uint32_t Password) { //Wait for command to complete SpinDelay(20); - } void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode) { uint8_t fwd_bit_count; - uint8_t *dest = BigBuf_get_addr(); - int m=0, i=0; + // Clear destination buffer before sending the command + BigBuf_Clear_ext(false); + + LED_A_ON(); + StartTicks(); //If password mode do login if (PwdMode == 1) EM4xLogin(Pwd); @@ -1923,38 +1951,29 @@ void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode) { fwd_bit_count = Prepare_Cmd( FWD_CMD_READ ); fwd_bit_count += Prepare_Addr( Address ); - m = BigBuf_max_traceLen(); - // Clear destination buffer before sending the command - memset(dest, 128, m); - // Connect the A/D to the peak-detected low-frequency path. - SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - // Now set up the SSC to get the ADC samples that are now streaming at us. - FpgaSetupSsc(); - SendForward(fwd_bit_count); - + WaitUS(400); // Now do the acquisition - i = 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) { - dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - i++; - if (i >= m) break; - } - } + DoPartialAcquisition(20, true, 6000, 1000); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off - LED_D_OFF(); + LED_A_OFF(); + cmd_send(CMD_ACK,0,0,0,0,0); } -void EM4xWriteWord(uint32_t Data, uint8_t Address, uint32_t Pwd, uint8_t PwdMode) { - +void EM4xWriteWord(uint32_t flag, uint32_t Data, uint32_t Pwd) { + + bool PwdMode = (flag & 0x1); + uint8_t Address = (flag >> 8) & 0xFF; uint8_t fwd_bit_count; + //clear buffer now so it does not interfere with timing later + BigBuf_Clear_ext(false); + + LED_A_ON(); + StartTicks(); //If password mode do login - if (PwdMode == 1) EM4xLogin(Pwd); + if (PwdMode) EM4xLogin(Pwd); forward_ptr = forwardLink_data; fwd_bit_count = Prepare_Cmd( FWD_CMD_WRITE ); @@ -1964,7 +1983,105 @@ void EM4xWriteWord(uint32_t Data, uint8_t Address, uint32_t Pwd, uint8_t PwdMode SendForward(fwd_bit_count); //Wait for write to complete - SpinDelay(20); + //SpinDelay(10); + + WaitUS(6500); + //Capture response if one exists + DoPartialAcquisition(20, true, 6000, 1000); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off - LED_D_OFF(); + LED_A_OFF(); + cmd_send(CMD_ACK,0,0,0,0,0); +} + +void EM4xProtect(uint32_t flag, uint32_t Data, uint32_t Pwd) { + + bool PwdMode = (flag & 0x1); + uint8_t fwd_bit_count; + + //clear buffer now so it does not interfere with timing later + BigBuf_Clear_ext(false); + + LED_A_ON(); + StartTicks(); + //If password mode do login + if (PwdMode) EM4xLogin(Pwd); + + forward_ptr = forwardLink_data; + fwd_bit_count = Prepare_Cmd( FWD_CMD_PROTECT ); + + //unsure if this needs the full packet config... + fwd_bit_count += Prepare_Data( Data&0xFFFF, Data>>16 ); + + SendForward(fwd_bit_count); + + //Wait for write to complete + //SpinDelay(10); + + WaitUS(6500); + //Capture response if one exists + DoPartialAcquisition(20, true, 6000, 1000); + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off + LED_A_OFF(); + cmd_send(CMD_ACK,0,0,0,0,0); +} +/* +Reading a COTAG. + +COTAG needs the reader to send a startsequence and the card has an extreme slow datarate. +because of this, we can "sample" the data signal but we interpreate it to Manchester direct. + +READER START SEQUENCE: +burst 800 us, gap 2.2 msecs +burst 3.6 msecs gap 2.2 msecs +burst 800 us gap 2.2 msecs +pulse 3.6 msecs + +This triggers a COTAG tag to response +*/ +void Cotag(uint32_t arg0) { + +#define OFF { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); WaitUS(2035); } +#define ON(x) { FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); WaitUS((x)); } + + uint8_t rawsignal = arg0 & 0xF; + + LED_A_ON(); + + // Switching to LF image on FPGA. This might empty BigBuff + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + + //clear buffer now so it does not interfere with timing later + BigBuf_Clear_ext(false); + + // Set up FPGA, 132kHz to power up the tag + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 89); + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); + + // Connect the A/D to the peak-detected low-frequency path. + SetAdcMuxFor(GPIO_MUXSEL_LOPKD); + + // Now set up the SSC to get the ADC samples that are now streaming at us. + FpgaSetupSsc(FPGA_MAJOR_MODE_LF_ADC); + + // start clock - 1.5ticks is 1us + StartTicks(); + + //send COTAG start pulse + ON(740) OFF + ON(3330) OFF + ON(740) OFF + ON(1000) + + switch(rawsignal) { + case 0: doCotagAcquisition(50000); break; + case 1: doCotagAcquisitionManchester(); break; + case 2: DoAcquisition_config(true, 0); break; + } + + // Turn the field off + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off + cmd_send(CMD_ACK,0,0,0,0,0); + LED_A_OFF(); }