X-Git-Url: https://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/f7c64b570c154063916d42bc6abe3a36df8f59f6..cd79d9722300fa22ee1571eab241512ee21ed14e:/armsrc/iso15693.c diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index 62e480c2..1e9a3b5b 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -1,1190 +1,1126 @@ -//----------------------------------------------------------------------------- -// Routines to support ISO 15693. This includes both the reader software and -// the `fake tag' modes, but at the moment I've implemented only the reader -// stuff, and that barely. -// Jonathan Westhues, split Nov 2006 - -// Modified by Greg Jones, Jan 2009 to perform modulation onboard in arm rather than on PC -// Also added additional reader commands (SELECT, READ etc.) - -//----------------------------------------------------------------------------- -#include -#include "apps.h" -#include -#include - -// FROM winsrc\prox.h ////////////////////////////////// -#define arraylen(x) (sizeof(x)/sizeof((x)[0])) - -//----------------------------------------------------------------------------- -// Map a sequence of octets (~layer 2 command) into the set of bits to feed -// to the FPGA, to transmit that command to the tag. -//----------------------------------------------------------------------------- - - // The sampling rate is 106.353 ksps/s, for T = 18.8 us - - // SOF defined as - // 1) Unmodulated time of 56.64us - // 2) 24 pulses of 423.75khz - // 3) logic '1' (unmodulated for 18.88us followed by 8 pulses of 423.75khz) - - static const int FrameSOF[] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - -1, -1, -1, -1, - -1, -1, -1, -1, - 1, 1, 1, 1, - 1, 1, 1, 1 - }; - static const int Logic0[] = { - 1, 1, 1, 1, - 1, 1, 1, 1, - -1, -1, -1, -1, - -1, -1, -1, -1 - }; - static const int Logic1[] = { - -1, -1, -1, -1, - -1, -1, -1, -1, - 1, 1, 1, 1, - 1, 1, 1, 1 - }; - - // EOF defined as - // 1) logic '0' (8 pulses of 423.75khz followed by unmodulated for 18.88us) - // 2) 24 pulses of 423.75khz - // 3) Unmodulated time of 56.64us - - static const int FrameEOF[] = { - 1, 1, 1, 1, - 1, 1, 1, 1, - -1, -1, -1, -1, - -1, -1, -1, -1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 - }; - -static void CodeIso15693AsReader(BYTE *cmd, int n) -{ - int i, j; - - ToSendReset(); - - // Give it a bit of slack at the beginning - for(i = 0; i < 24; i++) { - ToSendStuffBit(1); - } - - ToSendStuffBit(0); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(0); - ToSendStuffBit(1); - ToSendStuffBit(1); - for(i = 0; i < n; i++) { - for(j = 0; j < 8; j += 2) { - int these = (cmd[i] >> j) & 3; - switch(these) { - case 0: - ToSendStuffBit(1); - ToSendStuffBit(0); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - break; - case 1: - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(0); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - break; - case 2: - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(0); - ToSendStuffBit(1); - ToSendStuffBit(1); - break; - case 3: - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(0); - break; - } - } - } - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(0); - ToSendStuffBit(1); - - // And slack at the end, too. - for(i = 0; i < 24; i++) { - ToSendStuffBit(1); - } -} - -//----------------------------------------------------------------------------- -// The CRC used by ISO 15693. -//----------------------------------------------------------------------------- -static WORD Crc(BYTE *v, int n) -{ - DWORD reg; - int i, j; - - reg = 0xffff; - for(i = 0; i < n; i++) { - reg = reg ^ ((DWORD)v[i]); - for (j = 0; j < 8; j++) { - if (reg & 0x0001) { - reg = (reg >> 1) ^ 0x8408; - } else { - reg = (reg >> 1); - } - } - } - - return ~reg; -} - -char *strcat(char *dest, const char *src) -{ - size_t dest_len = strlen(dest); - size_t i; - - for (i = 0 ; src[i] != '\0' ; i++) - dest[dest_len + i] = src[i]; - dest[dest_len + i] = '\0'; - - return dest; -} - -////////////////////////////////////////// code to do 'itoa' - -/* reverse: reverse string s in place */ -void reverse(char s[]) -{ - int c, i, j; - - for (i = 0, j = strlen(s)-1; i 0); /* delete it */ - if (sign < 0) - s[i++] = '-'; - s[i] = '\0'; - reverse(s); -} - -//////////////////////////////////////// END 'itoa' CODE - -//----------------------------------------------------------------------------- -// Encode (into the ToSend buffers) an identify request, which is the first -// thing that you must send to a tag to get a response. -//----------------------------------------------------------------------------- -static void BuildIdentifyRequest(void) -{ - BYTE cmd[5]; - - WORD crc; - // one sub-carrier, inventory, 1 slot, fast rate - // AFI is at bit 5 (1<<4) when doing an INVENTORY - cmd[0] = (1 << 2) | (1 << 5) | (1 << 1); - // inventory command code - cmd[1] = 0x01; - // no mask - cmd[2] = 0x00; - //Now the CRC - crc = Crc(cmd, 3); - cmd[3] = crc & 0xff; - cmd[4] = crc >> 8; - - CodeIso15693AsReader(cmd, sizeof(cmd)); -} - -static void BuildSysInfoRequest(BYTE *uid) -{ - BYTE cmd[12]; - - WORD crc; - // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block - // followed by teh block data - // one sub-carrier, inventory, 1 slot, fast rate - cmd[0] = (1 << 5) | (1 << 1); // no SELECT bit - // System Information command code - cmd[1] = 0x2B; - // UID may be optionally specified here - // 64-bit UID - cmd[2] = 0x32; - cmd[3]= 0x4b; - cmd[4] = 0x03; - cmd[5] = 0x01; - cmd[6] = 0x00; - cmd[7] = 0x10; - cmd[8] = 0x05; - cmd[9]= 0xe0; // always e0 (not exactly unique) - //Now the CRC - crc = Crc(cmd, 10); // the crc needs to be calculated over 2 bytes - cmd[10] = crc & 0xff; - cmd[11] = crc >> 8; - - CodeIso15693AsReader(cmd, sizeof(cmd)); -} - -static void BuildSelectRequest( BYTE uid[]) -{ - -// uid[6]=0x31; // this is getting ignored - the uid array is not happening... - BYTE cmd[12]; - - WORD crc; - // one sub-carrier, inventory, 1 slot, fast rate - //cmd[0] = (1 << 2) | (1 << 5) | (1 << 1); // INVENTROY FLAGS - cmd[0] = (1 << 4) | (1 << 5) | (1 << 1); // Select and addressed FLAGS - // SELECT command code - cmd[1] = 0x25; - // 64-bit UID -// cmd[2] = uid[0];//0x32; -// cmd[3]= uid[1];//0x4b; -// cmd[4] = uid[2];//0x03; -// cmd[5] = uid[3];//0x01; -// cmd[6] = uid[4];//0x00; -// cmd[7] = uid[5];//0x10; -// cmd[8] = uid[6];//0x05; - cmd[2] = 0x32;// - cmd[3] = 0x4b; - cmd[4] = 0x03; - cmd[5] = 0x01; - cmd[6] = 0x00; - cmd[7] = 0x10; - cmd[8] = 0x05; // infineon? - - cmd[9]= 0xe0; // always e0 (not exactly unique) - -// DbpIntegers(cmd[8],cmd[7],cmd[6]); - // Now the CRC - crc = Crc(cmd, 10); // the crc needs to be calculated over 10 bytes - cmd[10] = crc & 0xff; - cmd[11] = crc >> 8; - - CodeIso15693AsReader(cmd, sizeof(cmd)); -} - -static void BuildReadBlockRequest(BYTE *uid, BYTE blockNumber ) -{ - BYTE cmd[13]; - - WORD crc; - // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block - // followed by teh block data - // one sub-carrier, inventory, 1 slot, fast rate - cmd[0] = (1 << 6)| (1 << 5) | (1 << 1); // no SELECT bit - // READ BLOCK command code - cmd[1] = 0x20; - // UID may be optionally specified here - // 64-bit UID - cmd[2] = 0x32; - cmd[3]= 0x4b; - cmd[4] = 0x03; - cmd[5] = 0x01; - cmd[6] = 0x00; - cmd[7] = 0x10; - cmd[8] = 0x05; - cmd[9]= 0xe0; // always e0 (not exactly unique) - // Block number to read - cmd[10] = blockNumber;//0x00; - //Now the CRC - crc = Crc(cmd, 11); // the crc needs to be calculated over 2 bytes - cmd[11] = crc & 0xff; - cmd[12] = crc >> 8; - - CodeIso15693AsReader(cmd, sizeof(cmd)); -} - -static void BuildReadMultiBlockRequest(BYTE *uid) -{ - BYTE cmd[14]; - - WORD crc; - // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block - // followed by teh block data - // one sub-carrier, inventory, 1 slot, fast rate - cmd[0] = (1 << 5) | (1 << 1); // no SELECT bit - // READ Multi BLOCK command code - cmd[1] = 0x23; - // UID may be optionally specified here - // 64-bit UID - cmd[2] = 0x32; - cmd[3]= 0x4b; - cmd[4] = 0x03; - cmd[5] = 0x01; - cmd[6] = 0x00; - cmd[7] = 0x10; - cmd[8] = 0x05; - cmd[9]= 0xe0; // always e0 (not exactly unique) - // First Block number to read - cmd[10] = 0x00; - // Number of Blocks to read - cmd[11] = 0x2f; // read quite a few - //Now the CRC - crc = Crc(cmd, 12); // the crc needs to be calculated over 2 bytes - cmd[12] = crc & 0xff; - cmd[13] = crc >> 8; - - CodeIso15693AsReader(cmd, sizeof(cmd)); -} - -static void BuildArbitraryRequest(BYTE *uid,BYTE CmdCode) -{ - BYTE cmd[14]; - - WORD crc; - // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block - // followed by teh block data - // one sub-carrier, inventory, 1 slot, fast rate - cmd[0] = (1 << 5) | (1 << 1); // no SELECT bit - // READ BLOCK command code - cmd[1] = CmdCode; - // UID may be optionally specified here - // 64-bit UID - cmd[2] = 0x32; - cmd[3]= 0x4b; - cmd[4] = 0x03; - cmd[5] = 0x01; - cmd[6] = 0x00; - cmd[7] = 0x10; - cmd[8] = 0x05; - cmd[9]= 0xe0; // always e0 (not exactly unique) - // Parameter - cmd[10] = 0x00; - cmd[11] = 0x0a; - -// cmd[12] = 0x00; -// cmd[13] = 0x00; //Now the CRC - crc = Crc(cmd, 12); // the crc needs to be calculated over 2 bytes - cmd[12] = crc & 0xff; - cmd[13] = crc >> 8; - - CodeIso15693AsReader(cmd, sizeof(cmd)); -} - -static void BuildArbitraryCustomRequest(BYTE uid[], BYTE CmdCode) -{ - BYTE cmd[14]; - - WORD crc; - // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block - // followed by teh block data - // one sub-carrier, inventory, 1 slot, fast rate - cmd[0] = (1 << 5) | (1 << 1); // no SELECT bit - // READ BLOCK command code - cmd[1] = CmdCode; - // UID may be optionally specified here - // 64-bit UID - cmd[2] = 0x32; - cmd[3]= 0x4b; - cmd[4] = 0x03; - cmd[5] = 0x01; - cmd[6] = 0x00; - cmd[7] = 0x10; - cmd[8] = 0x05; - cmd[9]= 0xe0; // always e0 (not exactly unique) - // Parameter - cmd[10] = 0x05; // for custom codes this must be manufcturer code - cmd[11] = 0x00; - -// cmd[12] = 0x00; -// cmd[13] = 0x00; //Now the CRC - crc = Crc(cmd, 12); // the crc needs to be calculated over 2 bytes - cmd[12] = crc & 0xff; - cmd[13] = crc >> 8; - - CodeIso15693AsReader(cmd, sizeof(cmd)); -} - -///////////////////////////////////////////////////////////////////////// -// Now the VICC>VCD responses when we are simulating a tag -//////////////////////////////////////////////////////////////////// - - static void BuildInventoryResponse(void) -{ - BYTE cmd[12]; - - WORD crc; - // one sub-carrier, inventory, 1 slot, fast rate - // AFI is at bit 5 (1<<4) when doing an INVENTORY - cmd[0] = 0; //(1 << 2) | (1 << 5) | (1 << 1); - cmd[1] = 0; - // 64-bit UID - cmd[2] = 0x32; - cmd[3]= 0x4b; - cmd[4] = 0x03; - cmd[5] = 0x01; - cmd[6] = 0x00; - cmd[7] = 0x10; - cmd[8] = 0x05; - cmd[9]= 0xe0; - //Now the CRC - crc = Crc(cmd, 10); - cmd[10] = crc & 0xff; - cmd[11] = crc >> 8; - - CodeIso15693AsReader(cmd, sizeof(cmd)); -} - -//----------------------------------------------------------------------------- -// Transmit the command (to the tag) that was placed in ToSend[]. -//----------------------------------------------------------------------------- -static void TransmitTo15693Tag(const BYTE *cmd, int len, int *samples, int *wait) -{ - int c; - -// FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX); - if(*wait < 10) { *wait = 10; } - -// for(c = 0; c < *wait;) { -// if(SSC_STATUS & (SSC_STATUS_TX_READY)) { -// SSC_TRANSMIT_HOLDING = 0x00; // For exact timing! -// c++; -// } -// if(SSC_STATUS & (SSC_STATUS_RX_READY)) { -// volatile DWORD r = SSC_RECEIVE_HOLDING; -// (void)r; -// } -// WDT_HIT(); -// } - - c = 0; - for(;;) { - if(SSC_STATUS & (SSC_STATUS_TX_READY)) { - SSC_TRANSMIT_HOLDING = cmd[c]; - c++; - if(c >= len) { - break; - } - } - if(SSC_STATUS & (SSC_STATUS_RX_READY)) { - volatile DWORD r = SSC_RECEIVE_HOLDING; - (void)r; - } - WDT_HIT(); - } - *samples = (c + *wait) << 3; -} - -//----------------------------------------------------------------------------- -// Transmit the command (to the reader) that was placed in ToSend[]. -//----------------------------------------------------------------------------- -static void TransmitTo15693Reader(const BYTE *cmd, int len, int *samples, int *wait) -{ - int c; - -// FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR); // No requirement to energise my coils - if(*wait < 10) { *wait = 10; } - - c = 0; - for(;;) { - if(SSC_STATUS & (SSC_STATUS_TX_READY)) { - SSC_TRANSMIT_HOLDING = cmd[c]; - c++; - if(c >= len) { - break; - } - } - if(SSC_STATUS & (SSC_STATUS_RX_READY)) { - volatile DWORD r = SSC_RECEIVE_HOLDING; - (void)r; - } - WDT_HIT(); - } - *samples = (c + *wait) << 3; -} - -static int GetIso15693AnswerFromTag(BYTE *receivedResponse, int maxLen, int *samples, int *elapsed) -{ - int c = 0; - BYTE *dest = (BYTE *)BigBuf; - int getNext = 0; - - SBYTE prev = 0; - -// NOW READ RESPONSE - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); - //spindelay(60); // greg - experiment to get rid of some of the 0 byte/failed reads - c = 0; - getNext = FALSE; - for(;;) { - if(SSC_STATUS & (SSC_STATUS_TX_READY)) { - SSC_TRANSMIT_HOLDING = 0x43; - } - if(SSC_STATUS & (SSC_STATUS_RX_READY)) { - SBYTE b; - b = (SBYTE)SSC_RECEIVE_HOLDING; - - // The samples are correlations against I and Q versions of the - // tone that the tag AM-modulates, so every other sample is I, - // every other is Q. We just want power, so abs(I) + abs(Q) is - // close to what we want. - if(getNext) { - SBYTE r; - - if(b < 0) { - r = -b; - } else { - r = b; - } - if(prev < 0) { - r -= prev; - } else { - r += prev; - } - - dest[c++] = (BYTE)r; - - if(c >= 2000) { - break; - } - } else { - prev = b; - } - - getNext = !getNext; - } - } - -////////////////////////////////////////// -/////////// DEMODULATE /////////////////// -////////////////////////////////////////// - - int i, j; - int max = 0, maxPos=0; - - int skip = 4; - -// if(GraphTraceLen < 1000) return; // THIS CHECKS FOR A BUFFER TO SMALL - - // First, correlate for SOF - for(i = 0; i < 100; i++) { - int corr = 0; - for(j = 0; j < arraylen(FrameSOF); j += skip) { - corr += FrameSOF[j]*dest[i+(j/skip)]; - } - if(corr > max) { - max = corr; - maxPos = i; - } - } -// DbpString("SOF at %d, correlation %d", maxPos,max/(arraylen(FrameSOF)/skip)); - - int k = 0; // this will be our return value - - // greg - If correlation is less than 1 then there's little point in continuing - if ((max/(arraylen(FrameSOF)/skip)) >= 1) - { - - i = maxPos + arraylen(FrameSOF)/skip; - - BYTE outBuf[20]; - memset(outBuf, 0, sizeof(outBuf)); - BYTE mask = 0x01; - for(;;) { - int corr0 = 0, corr1 = 0, corrEOF = 0; - for(j = 0; j < arraylen(Logic0); j += skip) { - corr0 += Logic0[j]*dest[i+(j/skip)]; - } - for(j = 0; j < arraylen(Logic1); j += skip) { - corr1 += Logic1[j]*dest[i+(j/skip)]; - } - for(j = 0; j < arraylen(FrameEOF); j += skip) { - corrEOF += FrameEOF[j]*dest[i+(j/skip)]; - } - // Even things out by the length of the target waveform. - corr0 *= 4; - corr1 *= 4; - - if(corrEOF > corr1 && corrEOF > corr0) { -// DbpString("EOF at %d", i); - break; - } else if(corr1 > corr0) { - i += arraylen(Logic1)/skip; - outBuf[k] |= mask; - } else { - i += arraylen(Logic0)/skip; - } - mask <<= 1; - if(mask == 0) { - k++; - mask = 0x01; - } - if((i+(int)arraylen(FrameEOF)) >= 2000) { - DbpString("ran off end!"); - break; - } - } - if(mask != 0x01) { - DbpString("error, uneven octet! (discard extra bits!)"); -/// DbpString(" mask=%02x", mask); - } -// BYTE str1 [8]; -// itoa(k,str1); -// strcat(str1," octets read"); - -// DbpString( str1); // DbpString("%d octets", k); - -// for(i = 0; i < k; i+=3) { -// //DbpString("# %2d: %02x ", i, outBuf[i]); -// DbpIntegers(outBuf[i],outBuf[i+1],outBuf[i+2]); -// } - - for(i = 0; i < k; i++) { - receivedResponse[i] = outBuf[i]; - } - } // "end if correlation > 0" (max/(arraylen(FrameSOF)/skip)) - return k; // return the number of bytes demodulated - -/// DbpString("CRC=%04x", Iso15693Crc(outBuf, k-2)); - -} - -// Now the GetISO15693 message from sniffing command -static int GetIso15693AnswerFromSniff(BYTE *receivedResponse, int maxLen, int *samples, int *elapsed) -{ - int c = 0; - BYTE *dest = (BYTE *)BigBuf; - int getNext = 0; - - SBYTE prev = 0; - -// NOW READ RESPONSE - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); - //spindelay(60); // greg - experiment to get rid of some of the 0 byte/failed reads - c = 0; - getNext = FALSE; - for(;;) { - if(SSC_STATUS & (SSC_STATUS_TX_READY)) { - SSC_TRANSMIT_HOLDING = 0x43; - } - if(SSC_STATUS & (SSC_STATUS_RX_READY)) { - SBYTE b; - b = (SBYTE)SSC_RECEIVE_HOLDING; - - // The samples are correlations against I and Q versions of the - // tone that the tag AM-modulates, so every other sample is I, - // every other is Q. We just want power, so abs(I) + abs(Q) is - // close to what we want. - if(getNext) { - SBYTE r; - - if(b < 0) { - r = -b; - } else { - r = b; - } - if(prev < 0) { - r -= prev; - } else { - r += prev; - } - - dest[c++] = (BYTE)r; - - if(c >= 20000) { - break; - } - } else { - prev = b; - } - - getNext = !getNext; - } - } - -////////////////////////////////////////// -/////////// DEMODULATE /////////////////// -////////////////////////////////////////// - - int i, j; - int max = 0, maxPos=0; - - int skip = 4; - -// if(GraphTraceLen < 1000) return; // THIS CHECKS FOR A BUFFER TO SMALL - - // First, correlate for SOF - for(i = 0; i < 19000; i++) { - int corr = 0; - for(j = 0; j < arraylen(FrameSOF); j += skip) { - corr += FrameSOF[j]*dest[i+(j/skip)]; - } - if(corr > max) { - max = corr; - maxPos = i; - } - } -// DbpString("SOF at %d, correlation %d", maxPos,max/(arraylen(FrameSOF)/skip)); - - int k = 0; // this will be our return value - - // greg - If correlation is less than 1 then there's little point in continuing - if ((max/(arraylen(FrameSOF)/skip)) >= 1) // THIS SHOULD BE 1 - { - - i = maxPos + arraylen(FrameSOF)/skip; - - BYTE outBuf[20]; - memset(outBuf, 0, sizeof(outBuf)); - BYTE mask = 0x01; - for(;;) { - int corr0 = 0, corr1 = 0, corrEOF = 0; - for(j = 0; j < arraylen(Logic0); j += skip) { - corr0 += Logic0[j]*dest[i+(j/skip)]; - } - for(j = 0; j < arraylen(Logic1); j += skip) { - corr1 += Logic1[j]*dest[i+(j/skip)]; - } - for(j = 0; j < arraylen(FrameEOF); j += skip) { - corrEOF += FrameEOF[j]*dest[i+(j/skip)]; - } - // Even things out by the length of the target waveform. - corr0 *= 4; - corr1 *= 4; - - if(corrEOF > corr1 && corrEOF > corr0) { -// DbpString("EOF at %d", i); - break; - } else if(corr1 > corr0) { - i += arraylen(Logic1)/skip; - outBuf[k] |= mask; - } else { - i += arraylen(Logic0)/skip; - } - mask <<= 1; - if(mask == 0) { - k++; - mask = 0x01; - } - if((i+(int)arraylen(FrameEOF)) >= 2000) { - DbpString("ran off end!"); - break; - } - } - if(mask != 0x01) { - DbpString("error, uneven octet! (discard extra bits!)"); -/// DbpString(" mask=%02x", mask); - } -// BYTE str1 [8]; -// itoa(k,str1); -// strcat(str1," octets read"); - -// DbpString( str1); // DbpString("%d octets", k); - -// for(i = 0; i < k; i+=3) { -// //DbpString("# %2d: %02x ", i, outBuf[i]); -// DbpIntegers(outBuf[i],outBuf[i+1],outBuf[i+2]); -// } - - for(i = 0; i < k; i++) { - receivedResponse[i] = outBuf[i]; - } - } // "end if correlation > 0" (max/(arraylen(FrameSOF)/skip)) - return k; // return the number of bytes demodulated - -/// DbpString("CRC=%04x", Iso15693Crc(outBuf, k-2)); -} - -//----------------------------------------------------------------------------- -// Start to read an ISO 15693 tag. We send an identify request, then wait -// for the response. The response is not demodulated, just left in the buffer -// so that it can be downloaded to a PC and processed there. -//----------------------------------------------------------------------------- -void AcquireRawAdcSamplesIso15693(void) -{ - int c = 0; - BYTE *dest = (BYTE *)BigBuf; - int getNext = 0; - - SBYTE prev = 0; - - BuildIdentifyRequest(); - - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - - // Give the tags time to energize - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); - SpinDelay(100); - - // Now send the command - FpgaSetupSsc(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX); - - c = 0; - for(;;) { - if(SSC_STATUS & (SSC_STATUS_TX_READY)) { - SSC_TRANSMIT_HOLDING = ToSend[c]; - c++; - if(c == ToSendMax+3) { - break; - } - } - if(SSC_STATUS & (SSC_STATUS_RX_READY)) { - volatile DWORD r = SSC_RECEIVE_HOLDING; - (void)r; - } - WDT_HIT(); - } - - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); - - c = 0; - getNext = FALSE; - for(;;) { - if(SSC_STATUS & (SSC_STATUS_TX_READY)) { - SSC_TRANSMIT_HOLDING = 0x43; - } - if(SSC_STATUS & (SSC_STATUS_RX_READY)) { - SBYTE b; - b = (SBYTE)SSC_RECEIVE_HOLDING; - - // The samples are correlations against I and Q versions of the - // tone that the tag AM-modulates, so every other sample is I, - // every other is Q. We just want power, so abs(I) + abs(Q) is - // close to what we want. - if(getNext) { - SBYTE r; - - if(b < 0) { - r = -b; - } else { - r = b; - } - if(prev < 0) { - r -= prev; - } else { - r += prev; - } - - dest[c++] = (BYTE)r; - - if(c >= 2000) { - break; - } - } else { - prev = b; - } - - getNext = !getNext; - } - } -} - -//----------------------------------------------------------------------------- -// Simulate an ISO15693 reader, perform anti-collision and then attempt to read a sector -// all demodulation performed in arm rather than host. - greg -//----------------------------------------------------------------------------- -void ReaderIso15693(DWORD parameter) -{ - LED_A_ON(); - LED_B_ON(); - LED_C_OFF(); - LED_D_OFF(); - -//DbpString(parameter); - - BYTE *receivedAnswer0 = (((BYTE *)BigBuf) + 3560); // allow 100 bytes per reponse (way too much) - BYTE *receivedAnswer1 = (((BYTE *)BigBuf) + 3660); // - BYTE *receivedAnswer2 = (((BYTE *)BigBuf) + 3760); - BYTE *receivedAnswer3 = (((BYTE *)BigBuf) + 3860); - //BYTE *TagUID= (((BYTE *)BigBuf) + 3960); // where we hold the uid for hi15reader -// int responseLen0 = 0; - int responseLen1 = 0; - int responseLen2 = 0; - int responseLen3 = 0; - - // Blank arrays - int j; - for(j = 0; j < 100; j++) { - receivedAnswer3[j] = 0; - receivedAnswer2[j] =0; - receivedAnswer1[j] = 0; - receivedAnswer0[j] = 0; - } - - // Setup SSC - FpgaSetupSsc(); - - // Start from off (no field generated) - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(200); - - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - FpgaSetupSsc(); - - // Give the tags time to energize - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); - SpinDelay(200); - - LED_A_ON(); - LED_B_OFF(); - LED_C_OFF(); - LED_D_OFF(); - - int samples = 0; - int tsamples = 0; - int wait = 0; - int elapsed = 0; - - // FIRST WE RUN AN INVENTORY TO GET THE TAG UID - // THIS MEANS WE CAN PRE-BUILD REQUESTS TO SAVE CPU TIME - BYTE TagUID[7]; // where we hold the uid for hi15reader - -// BuildIdentifyRequest(); -// //TransmitTo15693Tag(ToSend,ToSendMax+3,&tsamples, &wait); -// TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); // No longer ToSendMax+3 -// // Now wait for a response -// responseLen0 = GetIso15693AnswerFromTag(receivedAnswer0, 100, &samples, &elapsed) ; -// if (responseLen0 >=12) // we should do a better check than this -// { -// // really we should check it is a valid mesg -// // but for now just grab what we think is the uid -// TagUID[0] = receivedAnswer0[2]; -// TagUID[1] = receivedAnswer0[3]; -// TagUID[2] = receivedAnswer0[4]; -// TagUID[3] = receivedAnswer0[5]; -// TagUID[4] = receivedAnswer0[6]; -// TagUID[5] = receivedAnswer0[7]; -// TagUID[6] = receivedAnswer0[8]; // IC Manufacturer code -// DbpIntegers(TagUID[6],TagUID[5],TagUID[4]); -//} - - // Now send the IDENTIFY command - BuildIdentifyRequest(); - //TransmitTo15693Tag(ToSend,ToSendMax+3,&tsamples, &wait); - TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); // No longer ToSendMax+3 - // Now wait for a response - responseLen1 = GetIso15693AnswerFromTag(receivedAnswer1, 100, &samples, &elapsed) ; - - if (responseLen1 >=12) // we should do a better check than this - { - - TagUID[0] = receivedAnswer1[2]; - TagUID[1] = receivedAnswer1[3]; - TagUID[2] = receivedAnswer1[4]; - TagUID[3] = receivedAnswer1[5]; - TagUID[4] = receivedAnswer1[6]; - TagUID[5] = receivedAnswer1[7]; - TagUID[6] = receivedAnswer1[8]; // IC Manufacturer code - - // Now send the SELECT command - BuildSelectRequest(TagUID); - TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); // No longer ToSendMax+3 - // Now wait for a response - responseLen2 = GetIso15693AnswerFromTag(receivedAnswer2, 100, &samples, &elapsed); - - // Now send the MULTI READ command -// BuildArbitraryRequest(*TagUID,parameter); - BuildArbitraryCustomRequest(TagUID,parameter); -// BuildReadBlockRequest(*TagUID,parameter); -// BuildSysInfoRequest(*TagUID); - //TransmitTo15693Tag(ToSend,ToSendMax+3,&tsamples, &wait); - TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); // No longer ToSendMax+3 - // Now wait for a response - responseLen3 = GetIso15693AnswerFromTag(receivedAnswer3, 100, &samples, &elapsed) ; - - } - - char str1 [4]; - //char str2 [200]; - int i; - - itoa(responseLen1,str1); - strcat(str1," octets read from IDENTIFY request"); - DbpString(str1); - for(i = 0; i < responseLen1; i+=3) { - DbpIntegers(receivedAnswer1[i],receivedAnswer1[i+1],receivedAnswer1[i+2]); - } - - itoa(responseLen2,str1); - strcat(str1," octets read from SELECT request"); - DbpString(str1); - for(i = 0; i < responseLen2; i+=3) { - DbpIntegers(receivedAnswer2[i],receivedAnswer2[i+1],receivedAnswer2[i+2]); - } - - itoa(responseLen3,str1); - strcat(str1," octets read from XXX request"); - DbpString(str1); - for(i = 0; i < responseLen3; i+=3) { - DbpIntegers(receivedAnswer3[i],receivedAnswer3[i+1],receivedAnswer3[i+2]); - } - -// str2[0]=0; -// for(i = 0; i < responseLen3; i++) { -// itoa(str1,receivedAnswer3[i]); -// strcat(str2,str1); -// } -// DbpString(str2); - - LED_A_OFF(); - LED_B_OFF(); - LED_C_OFF(); - LED_D_OFF(); -} - -//----------------------------------------------------------------------------- -// Simulate an ISO15693 TAG, perform anti-collision and then print any reader commands -// all demodulation performed in arm rather than host. - greg -//----------------------------------------------------------------------------- -void SimTagIso15693(DWORD parameter) -{ - LED_A_ON(); - LED_B_ON(); - LED_C_OFF(); - LED_D_OFF(); - -//DbpString(parameter); - - BYTE *receivedAnswer0 = (((BYTE *)BigBuf) + 3560); // allow 100 bytes per reponse (way too much) - BYTE *receivedAnswer1 = (((BYTE *)BigBuf) + 3660); // - BYTE *receivedAnswer2 = (((BYTE *)BigBuf) + 3760); - BYTE *receivedAnswer3 = (((BYTE *)BigBuf) + 3860); - //BYTE *TagUID= (((BYTE *)BigBuf) + 3960); // where we hold the uid for hi15reader -// int responseLen0 = 0; - int responseLen1 = 0; -// int responseLen2 = 0; -// int responseLen3 = 0; - - // Blank arrays - int j; - for(j = 0; j < 100; j++) { - receivedAnswer3[j] = 0; - receivedAnswer2[j] =0; - receivedAnswer1[j] = 0; - receivedAnswer0[j] = 0; - } - - // Setup SSC - FpgaSetupSsc(); - - // Start from off (no field generated) - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(200); - - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - FpgaSetupSsc(); - - // Give the tags time to energize -// FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); // NO GOOD FOR SIM TAG!!!! - SpinDelay(200); - - LED_A_OFF(); - LED_B_OFF(); - LED_C_ON(); - LED_D_OFF(); - - int samples = 0; - int tsamples = 0; - int wait = 0; - int elapsed = 0; - - // FIRST WE RUN AN INVENTORY TO GET THE TAG UID - // THIS MEANS WE CAN PRE-BUILD REQUESTS TO SAVE CPU TIME - // BYTE TagUID[7]; // where we hold the uid for hi15reader - - // Now send the IDENTIFY command - // BuildIdentifyRequest(); - // TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); // No longer ToSendMax+3 - - // Now wait for a command from the reader - responseLen1=0; - // while(responseLen1=0) { - // if(BUTTON_PRESS()) break; - responseLen1 = GetIso15693AnswerFromSniff(receivedAnswer1, 100, &samples, &elapsed) ; - // } - - if (responseLen1 >=1) // we should do a better check than this - { - // Build a suitable reponse to the reader INVENTORY cocmmand - BuildInventoryResponse(); - TransmitTo15693Reader(ToSend,ToSendMax,&tsamples, &wait); - - // Now wait for a command from the reader -// responseLen2 = GetIso15693AnswerFromTag(receivedAnswer2, 100, &samples, &elapsed); - - // Now wait for a command from the reader -// responseLen3 = GetIso15693AnswerFromTag(receivedAnswer3, 100, &samples, &elapsed) ; - - } - - char str1 [4]; - //char str2 [200]; - int i; - - itoa(responseLen1,str1); - strcat(str1," octets read from reader command"); - DbpString(str1); - for(i = 0; i < responseLen1; i+=3) { - DbpIntegers(receivedAnswer1[i],receivedAnswer1[i+1],receivedAnswer1[i+2]); - } - -// itoa(responseLen2,str1); -// strcat(str1," octets read from SELECT request"); -// DbpString(str1); -// for(i = 0; i < responseLen2; i+=3) { -// DbpIntegers(receivedAnswer2[i],receivedAnswer2[i+1],receivedAnswer2[i+2]); -// } -// -// itoa(responseLen3,str1); -// strcat(str1," octets read from XXX request"); -// DbpString(str1); -// for(i = 0; i < responseLen3; i+=3) { -// DbpIntegers(receivedAnswer3[i],receivedAnswer3[i+1],receivedAnswer3[i+2]); -// } - -// str2[0]=0; -// for(i = 0; i < responseLen3; i++) { -// itoa(str1,receivedAnswer3[i]); -// strcat(str2,str1); -// } -// DbpString(str2); - - LED_A_OFF(); - LED_B_OFF(); - LED_C_OFF(); - LED_D_OFF(); -} +//----------------------------------------------------------------------------- +// Jonathan Westhues, split Nov 2006 +// Modified by Greg Jones, Jan 2009 +// Modified by Adrian Dabrowski "atrox", Mar-Sept 2010,Oct 2011 +// +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- +// Routines to support ISO 15693. This includes both the reader software and +// the `fake tag' modes, but at the moment I've implemented only the reader +// stuff, and that barely. +// Modified to perform modulation onboard in arm rather than on PC +// Also added additional reader commands (SELECT, READ etc.) +//----------------------------------------------------------------------------- +// The ISO 15693 describes two transmission modes from reader to tag, and 4 +// transmission modes from tag to reader. As of Mar 2010 this code only +// supports one of each: "1of4" mode from reader to tag, and the highspeed +// variant with one subcarrier from card to reader. +// As long, as the card fully support ISO 15693 this is no problem, since the +// reader chooses both data rates, but some non-standard tags do not. Further for +// the simulation to work, we will need to support all data rates. +// +// VCD (reader) -> VICC (tag) +// 1 out of 256: +// data rate: 1,66 kbit/s (fc/8192) +// used for long range +// 1 out of 4: +// data rate: 26,48 kbit/s (fc/512) +// used for short range, high speed +// +// VICC (tag) -> VCD (reader) +// Modulation: +// ASK / one subcarrier (423,75 khz) +// FSK / two subcarriers (423,75 khz && 484,28 khz) +// Data Rates / Modes: +// low ASK: 6,62 kbit/s +// low FSK: 6.67 kbit/s +// high ASK: 26,48 kbit/s +// high FSK: 26,69 kbit/s +//----------------------------------------------------------------------------- +// added "1 out of 256" mode (for VCD->PICC) - atrox 20100911 + + +// Random Remarks: +// *) UID is always used "transmission order" (LSB), which is reverse to display order + +// TODO / BUGS / ISSUES: +// *) writing to tags takes longer: we miss the answer from the tag in most cases +// -> tweak the read-timeout times +// *) signal decoding from the card is still a bit shaky. +// *) signal decoding is unable to detect collissions. +// *) add anti-collission support for inventory-commands +// *) read security status of a block +// *) sniffing and simulation do only support one transmission mode. need to support +// all 8 transmission combinations +// *) remove or refactor code under "depricated" +// *) document all the functions + + +#include "proxmark3.h" +#include "util.h" +#include "apps.h" +#include "string.h" +#include "iso15693tools.h" +#include "cmd.h" + +/////////////////////////////////////////////////////////////////////// +// ISO 15693 Part 2 - Air Interface +// This section basicly contains transmission and receiving of bits +/////////////////////////////////////////////////////////////////////// + +#define FrameSOF Iso15693FrameSOF +#define Logic0 Iso15693Logic0 +#define Logic1 Iso15693Logic1 +#define FrameEOF Iso15693FrameEOF + +#define Crc(data,datalen) Iso15693Crc(data,datalen) +#define AddCrc(data,datalen) Iso15693AddCrc(data,datalen) +#define sprintUID(target,uid) Iso15693sprintUID(target,uid) + +int DEBUG = 0; + + +// --------------------------- +// Signal Processing +// --------------------------- + +// prepare data using "1 out of 4" code for later transmission +// resulting data rate is 26,48 kbit/s (fc/512) +// cmd ... data +// n ... length of data +static void CodeIso15693AsReader(uint8_t *cmd, int n) +{ + int i, j; + + ToSendReset(); + + // Give it a bit of slack at the beginning + for(i = 0; i < 24; i++) + ToSendStuffBit(1); + + // SOF for 1of4 + ToSendStuffBit(0); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(0); + ToSendStuffBit(1); + ToSendStuffBit(1); + for(i = 0; i < n; i++) { + for(j = 0; j < 8; j += 2) { + int these = (cmd[i] >> j) & 3; + switch(these) { + case 0: + ToSendStuffBit(1); + ToSendStuffBit(0); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + break; + case 1: + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(0); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + break; + case 2: + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(0); + ToSendStuffBit(1); + ToSendStuffBit(1); + break; + case 3: + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(0); + break; + } + } + } + // EOF + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(0); + ToSendStuffBit(1); + + // And slack at the end, too. + for(i = 0; i < 24; i++) + ToSendStuffBit(1); +} + +// encode data using "1 out of 256" sheme +// data rate is 1,66 kbit/s (fc/8192) +// is designed for more robust communication over longer distances +static void CodeIso15693AsReader256(uint8_t *cmd, int n) +{ + int i, j; + + ToSendReset(); + + // Give it a bit of slack at the beginning + for(i = 0; i < 24; i++) + ToSendStuffBit(1); + + // SOF for 1of256 + ToSendStuffBit(0); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(0); + + for(i = 0; i < n; i++) { + for (j = 0; j <= 255; j++) { + if (cmd[i] == j) { + ToSendStuffBit(1); + ToSendStuffBit(0); + } else { + ToSendStuffBit(1); + ToSendStuffBit(1); + } + } + } + // EOF + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(0); + ToSendStuffBit(1); + + // And slack at the end, too. + for(i = 0; i < 24; i++) + ToSendStuffBit(1); +} + + +// Transmit the command (to the tag) that was placed in ToSend[]. +static void TransmitTo15693Tag(const uint8_t *cmd, int len, int *samples, int *wait) +{ + int c; + volatile uint32_t r; + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX); + if(*wait < 10) { *wait = 10; } + +// for(c = 0; c < *wait;) { +// if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { +// AT91C_BASE_SSC->SSC_THR = 0x00; // For exact timing! +// ++c; +// } +// if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { +// r = AT91C_BASE_SSC->SSC_RHR; +// (void)r; +// } +// WDT_HIT(); +// } + + c = 0; + for(;;) { + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = cmd[c]; + if( ++c >= len) break; + } + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + r = AT91C_BASE_SSC->SSC_RHR; + (void)r; + } + WDT_HIT(); + } + *samples = (c + *wait) << 3; +} + +//----------------------------------------------------------------------------- +// Transmit the command (to the reader) that was placed in ToSend[]. +//----------------------------------------------------------------------------- +static void TransmitTo15693Reader(const uint8_t *cmd, int len, int *samples, int *wait) +{ + int c = 0; + volatile uint32_t r; + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR|FPGA_HF_SIMULATOR_MODULATE_424K); + if(*wait < 10) { *wait = 10; } + + for(;;) { + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = cmd[c]; + if( ++c >= len) break; + } + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + r = AT91C_BASE_SSC->SSC_RHR; + (void)r; + } + WDT_HIT(); + } + *samples = (c + *wait) << 3; +} + + +// Read from Tag +// Parameters: +// receivedResponse +// maxLen +// samples +// elapsed +// returns: +// number of decoded bytes +static int GetIso15693AnswerFromTag(uint8_t *receivedResponse, int maxLen, int *samples, int *elapsed) +{ + uint8_t *dest = BigBuf_get_addr(); + + int c = 0, getNext = FALSE; + int8_t prev = 0; + + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + SpinDelay(100); // greg - experiment to get rid of some of the 0 byte/failed reads + + 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)) { + int8_t b; + b = (int8_t)AT91C_BASE_SSC->SSC_RHR; + + // The samples are correlations against I and Q versions of the + // tone that the tag AM-modulates, so every other sample is I, + // every other is Q. We just want power, so abs(I) + abs(Q) is + // close to what we want. + // iceman 2016, amplitude sqrt(abs(i) + abs(q)) + if(getNext) { + dest[c++] = (uint8_t)ABS(b) + ABS(prev); + + if(c >= 2000) + break; + } else { + prev = b; + } + + getNext = !getNext; + } + } + + ////////////////////////////////////////// + /////////// DEMODULATE /////////////////// + ////////////////////////////////////////// + + int i, j; + int max = 0, maxPos=0, skip = 4; + int k = 0; // this will be our return value + + // if(GraphTraceLen < 1000) return; // THIS CHECKS FOR A BUFFER TO SMALL + + // First, correlate for SOF + for(i = 0; i < 100; i++) { + int corr = 0; + for(j = 0; j < ARRAYLEN(FrameSOF); j += skip) { + corr += FrameSOF[j] * dest[i+(j/skip)]; + } + if(corr > max) { + max = corr; + maxPos = i; + } + } + // DbpString("SOF at %d, correlation %d", maxPos,max/(ARRAYLEN(FrameSOF)/skip)); + + // greg - If correlation is less than 1 then there's little point in continuing + if ((max/(ARRAYLEN(FrameSOF)/skip)) >= 1) + { + i = maxPos + ARRAYLEN(FrameSOF) / skip; + + uint8_t outBuf[20]; + memset(outBuf, 0, sizeof(outBuf)); + uint8_t mask = 0x01; + for(;;) { + int corr0 = 0, corr1 = 0, corrEOF = 0; + for(j = 0; j < ARRAYLEN(Logic0); j += skip) { + corr0 += Logic0[j] * dest[i+(j/skip)]; + } + for(j = 0; j < ARRAYLEN(Logic1); j += skip) { + corr1 += Logic1[j] * dest[i+(j/skip)]; + } + for(j = 0; j < ARRAYLEN(FrameEOF); j += skip) { + corrEOF += FrameEOF[j] * dest[i+(j/skip)]; + } + // Even things out by the length of the target waveform. + corr0 *= 4; + corr1 *= 4; + + if(corrEOF > corr1 && corrEOF > corr0) { + // DbpString("EOF at %d", i); + break; + } else if(corr1 > corr0) { + i += ARRAYLEN(Logic1)/skip; + outBuf[k] |= mask; + } else { + i += ARRAYLEN(Logic0)/skip; + } + mask <<= 1; + if(mask == 0) { + k++; + mask = 0x01; + } + if( ( i + (int)ARRAYLEN(FrameEOF)) >= 2000) { + DbpString("ran off end!"); + break; + } + } + if(mask != 0x01) { // this happens, when we miss the EOF + // TODO: for some reason this happens quite often + if (DEBUG) Dbprintf("error, uneven octet! (extra bits!) mask=%02x", mask); + if (mask < 0x08) k--; // discard the last uneven octet; + // 0x08 is an assumption - but works quite often + } + // uint8_t str1 [8]; + // itoa(k,str1); + // strncat(str1," octets read",8); + + // DbpString( str1); // DbpString("%d octets", k); + + // for(i = 0; i < k; i+=3) { + // //DbpString("# %2d: %02x ", i, outBuf[i]); + // DbpIntegers(outBuf[i],outBuf[i+1],outBuf[i+2]); + // } + + for(i = 0; i < k; i++) { + receivedResponse[i] = outBuf[i]; + } + } // "end if correlation > 0" (max/(ARRAYLEN(FrameSOF)/skip)) + return k; // return the number of bytes demodulated +} + + +// Now the GetISO15693 message from sniffing command +static int GetIso15693AnswerFromSniff(uint8_t *receivedResponse, int maxLen, int *samples, int *elapsed) +{ + uint8_t *dest = BigBuf_get_addr(); + + int c = 0, getNext = FALSE; + int8_t prev = 0; + + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + SpinDelay(100); // greg - experiment to get rid of some of the 0 byte/failed reads + + 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)) { + int8_t b = (int8_t)AT91C_BASE_SSC->SSC_RHR; + + // The samples are correlations against I and Q versions of the + // tone that the tag AM-modulates, so every other sample is I, + // every other is Q. We just want power, so abs(I) + abs(Q) is + // close to what we want. + if(getNext) { + dest[c++] = (uint8_t)ABS(b) + ABS(prev); + + if(c >= 20000) + break; + } else { + prev = b; + } + getNext = !getNext; + } + } + + ////////////////////////////////////////// + /////////// DEMODULATE /////////////////// + ////////////////////////////////////////// + + int i, j, max = 0, maxPos=0, skip = 4; + + // First, correlate for SOF + for(i = 0; i < 19000; i++) { + int corr = 0; + for(j = 0; j < ARRAYLEN(FrameSOF); j += skip) { + corr += FrameSOF[j]*dest[i+(j/skip)]; + } + if(corr > max) { + max = corr; + maxPos = i; + } + } +// DbpString("SOF at %d, correlation %d", maxPos,max/(ARRAYLEN(FrameSOF)/skip)); + + int k = 0; // this will be our return value + + // greg - If correlation is less than 1 then there's little point in continuing + if ((max/(ARRAYLEN(FrameSOF)/skip)) >= 1) // THIS SHOULD BE 1 + { + + i = maxPos + ARRAYLEN(FrameSOF)/skip; + + uint8_t outBuf[20]; + memset(outBuf, 0, sizeof(outBuf)); + uint8_t mask = 0x01; + for(;;) { + int corr0 = 0, corr1 = 0, corrEOF = 0; + for(j = 0; j < ARRAYLEN(Logic0); j += skip) { + corr0 += Logic0[j]*dest[i+(j/skip)]; + } + for(j = 0; j < ARRAYLEN(Logic1); j += skip) { + corr1 += Logic1[j]*dest[i+(j/skip)]; + } + for(j = 0; j < ARRAYLEN(FrameEOF); j += skip) { + corrEOF += FrameEOF[j]*dest[i+(j/skip)]; + } + // Even things out by the length of the target waveform. + corr0 *= 4; + corr1 *= 4; + + if(corrEOF > corr1 && corrEOF > corr0) { + // DbpString("EOF at %d", i); + break; + } else if(corr1 > corr0) { + i += ARRAYLEN(Logic1)/skip; + outBuf[k] |= mask; + } else { + i += ARRAYLEN(Logic0)/skip; + } + mask <<= 1; + if(mask == 0) { + k++; + mask = 0x01; + } + if((i+(int)ARRAYLEN(FrameEOF)) >= 2000) { + DbpString("ran off end!"); + break; + } + } + if(mask != 0x01) { + DbpString("sniff: error, uneven octet! (discard extra bits!)"); + // DbpString(" mask=%02x", mask); + } + // uint8_t str1 [8]; + // itoa(k,str1); + // strncat(str1," octets read",8); + + // DbpString( str1); // DbpString("%d octets", k); + + // for(i = 0; i < k; i+=3) { + // //DbpString("# %2d: %02x ", i, outBuf[i]); + // DbpIntegers(outBuf[i],outBuf[i+1],outBuf[i+2]); + // } + + for(i = 0; i < k; i++) { + receivedResponse[i] = outBuf[i]; + } + } // "end if correlation > 0" (max/(ARRAYLEN(FrameSOF)/skip)) + return k; // return the number of bytes demodulated +} + + +static void BuildIdentifyRequest(void); +//----------------------------------------------------------------------------- +// Start to read an ISO 15693 tag. We send an identify request, then wait +// for the response. The response is not demodulated, just left in the buffer +// so that it can be downloaded to a PC and processed there. +//----------------------------------------------------------------------------- +void AcquireRawAdcSamplesIso15693(void) +{ + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + + int c = 0, getNext = FALSE; + int8_t prev = 0; + volatile uint32_t r; + + uint8_t *dest = BigBuf_get_addr(); + BuildIdentifyRequest(); + + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + + // Give the tags time to energize + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + SpinDelay(100); + + // Now send the command + FpgaSetupSsc(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX); + + c = 0; + for(;;) { + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = ToSend[c]; + if( ++c == ToSendMax+3) break; + } + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + r = AT91C_BASE_SSC->SSC_RHR; + (void)r; + } + WDT_HIT(); + } + + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + + c = 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)) { + + int8_t b = (int8_t)AT91C_BASE_SSC->SSC_RHR; + + // The samples are correlations against I and Q versions of the + // tone that the tag AM-modulates, so every other sample is I, + // every other is Q. We just want power, so abs(I) + abs(Q) is + // close to what we want. + if(getNext) { + + dest[c++] = (uint8_t)(ABS(b) + ABS(prev)); + + if(c >= 2000) break; + + } else { + prev = b; + } + getNext = !getNext; + } + } +} + + +void RecordRawAdcSamplesIso15693(void) +{ + uint8_t *dest = BigBuf_get_addr(); + + int c = 0, getNext = FALSE; + int8_t prev = 0; + + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + // Setup SSC + FpgaSetupSsc(); + + // Start from off (no field generated) + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(200); + + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + SpinDelay(100); + + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + + 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)) { + int8_t b; + b = (int8_t)AT91C_BASE_SSC->SSC_RHR; + + // The samples are correlations against I and Q versions of the + // tone that the tag AM-modulates, so every other sample is I, + // every other is Q. We just want power, so abs(I) + abs(Q) is + // close to what we want. + if(getNext) { + dest[c++] = (uint8_t) ABS(b) + ABS(prev); + + if(c >= 7000) + break; + } else { + prev = b; + } + + getNext = !getNext; + WDT_HIT(); + } + } + Dbprintf("fin record"); +} + + +// Initialize the proxmark as iso15k reader +// (this might produces glitches that confuse some tags +void Iso15693InitReader() { + LED_A_ON(); + LED_B_ON(); + LED_C_OFF(); + LED_D_OFF(); + + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + // Setup SSC + // FpgaSetupSsc(); + + // Start from off (no field generated) + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(10); + + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + FpgaSetupSsc(); + + // Give the tags time to energize + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + SpinDelay(250); + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + LED_D_OFF(); +} + +/////////////////////////////////////////////////////////////////////// +// ISO 15693 Part 3 - Air Interface +// This section basicly contains transmission and receiving of bits +/////////////////////////////////////////////////////////////////////// + +// Encode (into the ToSend buffers) an identify request, which is the first +// thing that you must send to a tag to get a response. +static void BuildIdentifyRequest(void) +{ + uint8_t cmd[5] = {0,1,0,0,0}; + uint16_t crc; + // one sub-carrier, inventory, 1 slot, fast rate + // AFI is at bit 5 (1<<4) when doing an INVENTORY + cmd[0] = (1 << 2) | (1 << 5) | (1 << 1); + // inventory command code + cmd[1] = 0x01; + // no mask + cmd[2] = 0x00; + //Now the CRC + crc = Crc(cmd, 3); + cmd[3] = crc & 0xff; + cmd[4] = crc >> 8; + + CodeIso15693AsReader(cmd, sizeof(cmd)); +} + +// uid is in transmission order (which is reverse of display order) +static void BuildReadBlockRequest(uint8_t *uid, uint8_t blockNumber ) +{ + uint8_t cmd[13] = {0,0,0,0,0,0,0,0,0,0,0,0,0}; + uint16_t crc; + // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block + // followed by teh block data + // one sub-carrier, inventory, 1 slot, fast rate + cmd[0] = (1 << 6)| (1 << 5) | (1 << 1); // no SELECT bit, ADDR bit, OPTION bit + // READ BLOCK command code + cmd[1] = 0x20; + // UID may be optionally specified here + // 64-bit UID + cmd[2] = uid[0]; + cmd[3] = uid[1]; + cmd[4] = uid[2]; + cmd[5] = uid[3]; + cmd[6] = uid[4]; + cmd[7] = uid[5]; + cmd[8] = uid[6]; + cmd[9] = uid[7]; // 0xe0; // always e0 (not exactly unique) + // Block number to read + cmd[10] = blockNumber;//0x00; + //Now the CRC + crc = Crc(cmd, 11); // the crc needs to be calculated over 12 bytes + cmd[11] = crc & 0xff; + cmd[12] = crc >> 8; + + CodeIso15693AsReader(cmd, sizeof(cmd)); +} + +// Now the VICC>VCD responses when we are simulating a tag + static void BuildInventoryResponse( uint8_t *uid) +{ + uint8_t cmd[12] = {0,0,0,0,0,0,0,0,0,0,0,0}; + uint16_t crc; + // one sub-carrier, inventory, 1 slot, fast rate + // AFI is at bit 5 (1<<4) when doing an INVENTORY + //(1 << 2) | (1 << 5) | (1 << 1); + cmd[0] = 0; // + cmd[1] = 0; // DSFID (data storage format identifier). 0x00 = not supported + // 64-bit UID + cmd[2] = uid[7]; //0x32; + cmd[3] = uid[6]; //0x4b; + cmd[4] = uid[5]; //0x03; + cmd[5] = uid[4]; //0x01; + cmd[6] = uid[3]; //0x00; + cmd[7] = uid[2]; //0x10; + cmd[8] = uid[1]; //0x05; + cmd[9] = uid[0]; //0xe0; + //Now the CRC + crc = Crc(cmd, 10); + cmd[10] = crc & 0xff; + cmd[11] = crc >> 8; + + CodeIso15693AsReader(cmd, sizeof(cmd)); +} + +// Universal Method for sending to and recv bytes from a tag +// init ... should we initialize the reader? +// speed ... 0 low speed, 1 hi speed +// **recv will return you a pointer to the received data +// If you do not need the answer use NULL for *recv[] +// return: lenght of received data +int SendDataTag(uint8_t *send, int sendlen, int init, int speed, uint8_t **recv) { + + int samples = 0, tsamples = 0; + int wait = 0, elapsed = 0; + int answerLen = 0; + + LED_A_ON(); LED_B_ON(); + + LED_C_OFF(); LED_D_OFF(); + + if (init) Iso15693InitReader(); + + // answer is 100bytes long? + uint8_t *answer = BigBuf_malloc(100); + if (recv != NULL) memset(answer, 0, 100); + + if (!speed) { + // low speed (1 out of 256) + CodeIso15693AsReader256(send, sendlen); + } else { + // high speed (1 out of 4) + CodeIso15693AsReader(send, sendlen); + } + + LED_A_ON(); + LED_B_OFF(); + + TransmitTo15693Tag(ToSend, ToSendMax, &tsamples, &wait); + // Now wait for a response + if (recv!=NULL) { + LED_A_OFF(); + LED_B_ON(); + answerLen = GetIso15693AnswerFromTag(answer, 100, &samples, &elapsed) ; + *recv = answer; + } + + LEDsoff(); + return answerLen; +} + + +// -------------------------------------------------------------------- +// Debug Functions +// -------------------------------------------------------------------- + +// Decodes a message from a tag and displays its metadata and content +#define DBD15STATLEN 48 +void DbdecodeIso15693Answer(int len, uint8_t *d) { + char status[DBD15STATLEN+1] = {0}; + uint16_t crc; + + if (len > 3) { + if (d[0] & ( 1 << 3 )) + strncat(status, "ProtExt ", DBD15STATLEN); + if (d[0] & 1) { + // error + strncat(status, "Error ", DBD15STATLEN); + switch (d[1]) { + case 0x01: + strncat(status, "01:notSupp", DBD15STATLEN); + break; + case 0x02: + strncat(status, "02:notRecog", DBD15STATLEN); + break; + case 0x03: + strncat(status, "03:optNotSupp", DBD15STATLEN); + break; + case 0x0f: + strncat(status, "0f:noInfo", DBD15STATLEN); + break; + case 0x10: + strncat(status, "10:dontExist", DBD15STATLEN); + break; + case 0x11: + strncat(status, "11:lockAgain", DBD15STATLEN); + break; + case 0x12: + strncat(status, "12:locked", DBD15STATLEN); + break; + case 0x13: + strncat(status, "13:progErr", DBD15STATLEN); + break; + case 0x14: + strncat(status, "14:lockErr", DBD15STATLEN); + break; + default: + strncat(status, "unknownErr", DBD15STATLEN); + } + strncat(status ," " ,DBD15STATLEN); + } else { + strncat(status ,"NoErr ", DBD15STATLEN); + } + + crc = Crc(d,len-2); + if ( (( crc & 0xff ) == d[len-2]) && (( crc >> 8 ) == d[len-1]) ) + strncat(status, "CrcOK", DBD15STATLEN); + else + strncat(status, "CrcFail!", DBD15STATLEN); + + Dbprintf("%s", status); + } +} + +/////////////////////////////////////////////////////////////////////// +// Functions called via USB/Client +/////////////////////////////////////////////////////////////////////// + +void SetDebugIso15693(uint32_t debug) { + DEBUG = debug; + Dbprintf("Iso15693 Debug is now %s", DEBUG ? "on" : "off"); + return; +} + +//----------------------------------------------------------------------------- +// Simulate an ISO15693 reader, perform anti-collision and then attempt to read a sector +// all demodulation performed in arm rather than host. - greg +//----------------------------------------------------------------------------- +void ReaderIso15693(uint32_t parameter) +{ + LED_A_ON(); + LED_B_ON(); + LED_C_OFF(); + LED_D_OFF(); + + int answerLen1 = 0; + int answerLen2 = 0; + int answerLen3 = 0; + int i = 0; + int samples = 0; + int tsamples = 0; + int wait = 0; + int elapsed = 0; + uint8_t TagUID[8] = {0x00}; + + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + + uint8_t *answer1 = BigBuf_malloc(100); + uint8_t *answer2 = BigBuf_malloc(100); + uint8_t *answer3 = BigBuf_malloc(100); + // Blank arrays + memset(answer1, 0x00, 100); + memset(answer2, 0x00, 100); + memset(answer3, 0x00, 100); + + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + // Setup SSC + FpgaSetupSsc(); + + // Start from off (no field generated) + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(200); + + // Give the tags time to energize + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + SpinDelay(200); + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + LED_D_OFF(); + + // FIRST WE RUN AN INVENTORY TO GET THE TAG UID + // THIS MEANS WE CAN PRE-BUILD REQUESTS TO SAVE CPU TIME + + // Now send the IDENTIFY command + BuildIdentifyRequest(); + + TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); + + // Now wait for a response + answerLen1 = GetIso15693AnswerFromTag(answer1, 100, &samples, &elapsed) ; + + if (answerLen1 >= 12) // we should do a better check than this + { + TagUID[0] = answer1[2]; + TagUID[1] = answer1[3]; + TagUID[2] = answer1[4]; + TagUID[3] = answer1[5]; + TagUID[4] = answer1[6]; + TagUID[5] = answer1[7]; + TagUID[6] = answer1[8]; // IC Manufacturer code + TagUID[7] = answer1[9]; // always E0 + + } + + Dbprintf("%d octets read from IDENTIFY request:", answerLen1); + DbdecodeIso15693Answer(answerLen1, answer1); + Dbhexdump(answerLen1, answer1, true); + + // UID is reverse + if (answerLen1>=12) + Dbprintf("UID = %02hX%02hX%02hX%02hX%02hX%02hX%02hX%02hX", + TagUID[7],TagUID[6],TagUID[5],TagUID[4], + TagUID[3],TagUID[2],TagUID[1],TagUID[0]); + + + Dbprintf("%d octets read from SELECT request:", answerLen2); + DbdecodeIso15693Answer(answerLen2, answer2); + Dbhexdump(answerLen2, answer2, true); + + Dbprintf("%d octets read from XXX request:", answerLen3); + DbdecodeIso15693Answer(answerLen3,answer3); + Dbhexdump(answerLen3, answer3, true); + + // read all pages + if (answerLen1 >= 12 && DEBUG) { + i = 0; + while ( i < 32 ) { // sanity check, assume max 32 pages + BuildReadBlockRequest(TagUID,i); + TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); + answerLen2 = GetIso15693AnswerFromTag(answer2, 100, &samples, &elapsed); + if (answerLen2>0) { + Dbprintf("READ SINGLE BLOCK %d returned %d octets:", i, answerLen2); + DbdecodeIso15693Answer(answerLen2, answer2); + Dbhexdump(answerLen2, answer2, true); + if ( *((uint32_t*) answer2) == 0x07160101 ) break; // exit on NoPageErr + } + ++i; + } + } + + LED_A_OFF(); + LED_B_OFF(); + LED_C_OFF(); + LED_D_OFF(); +} + +// Simulate an ISO15693 TAG, perform anti-collision and then print any reader commands +// all demodulation performed in arm rather than host. - greg +void SimTagIso15693(uint32_t parameter, uint8_t *uid) +{ + LED_A_ON(); + LED_B_ON(); + LED_C_OFF(); + LED_D_OFF(); + + int answerLen1 = 0; + int samples = 0; + int tsamples = 0; + int wait = 0; + int elapsed = 0; + + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + + uint8_t *buf = BigBuf_malloc(100); + memset(buf, 0x00, 100); + + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + FpgaSetupSsc(); + + // Start from off (no field generated) + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(200); + + LED_A_OFF(); + LED_B_OFF(); + LED_C_ON(); + LED_D_OFF(); + + // Listen to reader + answerLen1 = GetIso15693AnswerFromSniff(buf, 100, &samples, &elapsed) ; + + if (answerLen1 >=1) // we should do a better check than this + { + // Build a suitable reponse to the reader INVENTORY cocmmand + // not so obsvious, but in the call to BuildInventoryResponse, the command is copied to the global ToSend buffer used below. + + BuildInventoryResponse(uid); + + TransmitTo15693Reader(ToSend,ToSendMax, &tsamples, &wait); + } + + Dbprintf("%d octets read from reader command: %x %x %x %x %x %x %x %x %x", answerLen1, + buf[0], buf[1], buf[2], buf[3], + buf[4], buf[5], buf[6], buf[7], buf[8]); + + Dbprintf("Simulationg uid: %x %x %x %x %x %x %x %x", + uid[0], uid[1], uid[2], uid[3], + uid[4], uid[5], uid[6], uid[7]); + + LED_A_OFF(); + LED_B_OFF(); + LED_C_OFF(); + LED_D_OFF(); +} + + +// Since there is no standardized way of reading the AFI out of a tag, we will brute force it +// (some manufactures offer a way to read the AFI, though) +void BruteforceIso15693Afi(uint32_t speed) +{ + uint8_t data[20]; + uint8_t *recv = data; + int datalen = 0, recvlen = 0; + + memset(data, 0, sizeof(data)); + + Iso15693InitReader(); + + // first without AFI + // Tags should respond wihtout AFI and with AFI=0 even when AFI is active + + data[0] = ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | + ISO15_REQ_INVENTORY | ISO15_REQINV_SLOT1; + data[1] = ISO15_CMD_INVENTORY; + data[2] = 0; // mask length + datalen = AddCrc(data, 3); + recvlen = SendDataTag(data, datalen, 0, speed, &recv); + WDT_HIT(); + if (recvlen >= 12) { + Dbprintf("NoAFI UID=%s", sprintUID(NULL, &recv[2])); + } + + // now with AFI + + data[0] = ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | + ISO15_REQ_INVENTORY | ISO15_REQINV_AFI | ISO15_REQINV_SLOT1; + data[1] = ISO15_CMD_INVENTORY; + data[2] = 0; // AFI + data[3] = 0; // mask length + + for (int i = 0; i < 256; i++) { + data[2] = i & 0xFF; // iceman 2016, is & 0xFF needed? + datalen = AddCrc(data, 4); + recvlen = SendDataTag(data, datalen, 0, speed, &recv); + WDT_HIT(); + if (recvlen >= 12) { + Dbprintf("AFI=%i UID=%s", i, sprintUID(NULL, &recv[2])); + } + } + Dbprintf("AFI Bruteforcing done."); +} + +// Allows to directly send commands to the tag via the client +void DirectTag15693Command(uint32_t datalen,uint32_t speed, uint32_t recv, uint8_t data[]) { + + int recvlen = 0; + uint8_t *recvbuf = BigBuf_get_addr(); + + if (DEBUG) { + Dbprintf("SEND"); + Dbhexdump(datalen,data,true); + } + + recvlen = SendDataTag(data, datalen, 1, speed, (recv ? &recvbuf : NULL)); + + if (recv) { + LED_B_ON(); + cmd_send(CMD_ACK,recvlen>48?48:recvlen,0,0,recvbuf,48); + LED_B_OFF(); + + if (DEBUG) { + Dbprintf("RECV"); + DbdecodeIso15693Answer(recvlen,recvbuf); + Dbhexdump(recvlen,recvbuf,true); + } + } +} \ No newline at end of file