X-Git-Url: http://cvs.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/15c4dc5ace24e6081d1597b011148f156cdd599e..9c44a9b6caf8a3f4462b77ed30453c5b71c3e7cd:/armsrc/iso15693.c?ds=sidebyside diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index e36baad2..9a6ef9f0 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -1,71 +1,98 @@ //----------------------------------------------------------------------------- +// 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. -// Jonathan Westhues, split Nov 2006 - -// Modified by Greg Jones, Jan 2009 to perform modulation onboard in arm rather than on PC +// Modified to perform modulation onboard in arm rather than on PC // Also added additional reader commands (SELECT, READ etc.) - //----------------------------------------------------------------------------- -#include +// 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" -// 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. -//----------------------------------------------------------------------------- +/////////////////////////////////////////////////////////////////////// +// 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; - // 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) + +// --------------------------- +// 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; @@ -76,6 +103,7 @@ static void CodeIso15693AsReader(BYTE *cmd, int n) ToSendStuffBit(1); } + // SOF for 1of4 ToSendStuffBit(0); ToSendStuffBit(1); ToSendStuffBit(1); @@ -131,6 +159,7 @@ static void CodeIso15693AsReader(BYTE *cmd, int n) } } } + // EOF ToSendStuffBit(1); ToSendStuffBit(1); ToSendStuffBit(0); @@ -142,405 +171,274 @@ static void CodeIso15693AsReader(BYTE *cmd, int n) } } -//----------------------------------------------------------------------------- -// The CRC used by ISO 15693. -//----------------------------------------------------------------------------- -static WORD Crc(BYTE *v, int n) +// 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) { - DWORD reg; int i, j; - reg = 0xffff; + 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++) { - reg = reg ^ ((DWORD)v[i]); - for (j = 0; j < 8; j++) { - if (reg & 0x0001) { - reg = (reg >> 1) ^ 0x8408; + for (j = 0; j<=255; j++) { + if (cmd[i]==j) { + ToSendStuffBit(1); + ToSendStuffBit(0); } else { - reg = (reg >> 1); - } - } + ToSendStuffBit(1); + ToSendStuffBit(1); + } + } } + // EOF + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(0); + ToSendStuffBit(1); - return ~reg; + // And slack at the end, too. + for(i = 0; i < 24; i++) { + ToSendStuffBit(1); + } } -char *strcat(char *dest, const char *src) + +// Transmit the command (to the tag) that was placed in ToSend[]. +static void TransmitTo15693Tag(const uint8_t *cmd, int len, int *samples, int *wait) { - 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; -} + int c; -////////////////////////////////////////// code to do 'itoa' +// FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX); + if(*wait < 10) { *wait = 10; } -/* reverse: reverse string s in place */ -void reverse(char s[]) -{ - int c, i, j; +// 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)) { +// volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR; +// (void)r; +// } +// WDT_HIT(); +// } - for (i = 0, j = strlen(s)-1; iSSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = cmd[c]; + c++; + if(c >= len) { + break; + } + } + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR; + (void)r; + } + WDT_HIT(); } + *samples = (c + *wait) << 3; } -/* itoa: convert n to characters in s */ -void itoa(int n, char s[]) +//----------------------------------------------------------------------------- +// 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 i, sign; - - if ((sign = n) < 0) /* record sign */ - n = -n; /* make n positive */ - i = 0; - do { /* generate digits in reverse order */ - s[i++] = n % 10 + '0'; /* get next digit */ - } while ((n /= 10) > 0); /* delete it */ - if (sign < 0) - s[i++] = '-'; - s[i] = '\0'; - reverse(s); + int c = 0; + 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]; + c++; + if(c >= len) { + break; + } + } + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR; + (void)r; + } + WDT_HIT(); + } + *samples = (c + *wait) << 3; } -//////////////////////////////////////// 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) +// 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) { - BYTE cmd[5]; + int c = 0; + uint8_t *dest = BigBuf_get_addr(); + int getNext = 0; - 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; + int8_t prev = 0; - CodeIso15693AsReader(cmd, sizeof(cmd)); -} +// 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(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; -static void __attribute__((unused)) BuildSysInfoRequest(BYTE *uid) -{ - BYTE cmd[12]; + // 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) { + int8_t r = ABS(b) + ABS(prev); - 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; + dest[c++] = (uint8_t)r; - CodeIso15693AsReader(cmd, sizeof(cmd)); -} + if(c >= 2000) { + break; + } + } else { + prev = b; + } -static void BuildSelectRequest( BYTE uid[]) -{ + getNext = !getNext; + } + } -// uid[6]=0x31; // this is getting ignored - the uid array is not happening... - BYTE cmd[12]; + ////////////////////////////////////////// + /////////// DEMODULATE /////////////////// + ////////////////////////////////////////// - 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? + int i, j; + int max = 0, maxPos=0; - cmd[9]= 0xe0; // always e0 (not exactly unique) + int skip = 4; -// 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; + // if(GraphTraceLen < 1000) return; // THIS CHECKS FOR A BUFFER TO SMALL - CodeIso15693AsReader(cmd, sizeof(cmd)); -} + // 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)); -static void __attribute__((unused)) BuildReadBlockRequest(BYTE *uid, BYTE blockNumber ) -{ - BYTE cmd[13]; + int k = 0; // this will be our return value - 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; + // 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 + +/// DbpString("CRC=%04x", Iso15693Crc(outBuf, k-2)); - CodeIso15693AsReader(cmd, sizeof(cmd)); } -static void __attribute__((unused)) BuildReadMultiBlockRequest(BYTE *uid) + +// Now the GetISO15693 message from sniffing command +static int GetIso15693AnswerFromSniff(uint8_t *receivedResponse, int maxLen, int *samples, int *elapsed) { - BYTE cmd[14]; + int c = 0; + uint8_t *dest = BigBuf_get_addr(); + int getNext = 0; - 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 __attribute__((unused)) 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 __attribute__((unused)) 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(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)) { -// volatile DWORD 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]; - c++; - if(c >= len) { - break; - } - } - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - volatile DWORD 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 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(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = cmd[c]; - c++; - if(c >= len) { - break; - } - } - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - volatile DWORD r = AT91C_BASE_SSC->SSC_RHR; - (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; + int8_t prev = 0; // NOW READ RESPONSE FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); @@ -552,30 +450,18 @@ static int GetIso15693AnswerFromTag(BYTE *receivedResponse, int maxLen, int *sam AT91C_BASE_SSC->SSC_THR = 0x43; } if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - SBYTE b; - b = (SBYTE)AT91C_BASE_SSC->SSC_RHR; + 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) { - SBYTE r; - - if(b < 0) { - r = -b; - } else { - r = b; - } - if(prev < 0) { - r -= prev; - } else { - r += prev; - } + int8_t r = ABS(b) + ABS(prev); - dest[c++] = (BYTE)r; + dest[c++] = (uint8_t)r; - if(c >= 2000) { + if(c >= 20000) { break; } } else { @@ -586,9 +472,9 @@ static int GetIso15693AnswerFromTag(BYTE *receivedResponse, int maxLen, int *sam } } -////////////////////////////////////////// -/////////// DEMODULATE /////////////////// -////////////////////////////////////////// + ////////////////////////////////////////// + /////////// DEMODULATE /////////////////// + ////////////////////////////////////////// int i, j; int max = 0, maxPos=0; @@ -598,7 +484,7 @@ static int GetIso15693AnswerFromTag(BYTE *receivedResponse, int maxLen, int *sam // if(GraphTraceLen < 1000) return; // THIS CHECKS FOR A BUFFER TO SMALL // First, correlate for SOF - for(i = 0; i < 100; i++) { + for(i = 0; i < 19000; i++) { int corr = 0; for(j = 0; j < arraylen(FrameSOF); j += skip) { corr += FrameSOF[j]*dest[i+(j/skip)]; @@ -613,85 +499,118 @@ static int GetIso15693AnswerFromTag(BYTE *receivedResponse, int maxLen, int *sam 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) + 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; + + 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; + } } - mask <<= 1; - if(mask == 0) { - k++; - mask = 0x01; + if(mask != 0x01) { + DbpString("sniff: error, uneven octet! (discard extra bits!)"); + /// DbpString(" mask=%02x", mask); } - if((i+(int)arraylen(FrameEOF)) >= 2000) { - DbpString("ran off end!"); - break; + // 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]; } - } - 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) + +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) { + uint8_t *dest = BigBuf_get_addr(); + int c = 0; - BYTE *dest = (BYTE *)BigBuf; int getNext = 0; + int8_t prev = 0; - SBYTE prev = 0; + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + BuildIdentifyRequest(); -// NOW READ RESPONSE + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + + // Give the tags time to energize FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); - //spindelay(60); // greg - experiment to get rid of some of the 0 byte/failed reads + 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]; + c++; + if(c == ToSendMax+3) { + break; + } + } + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR; + (void)r; + } + WDT_HIT(); + } + + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + c = 0; getNext = FALSE; for(;;) { @@ -699,30 +618,19 @@ static int GetIso15693AnswerFromSniff(BYTE *receivedResponse, int maxLen, int *s AT91C_BASE_SSC->SSC_THR = 0x43; } if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - SBYTE b; - b = (SBYTE)AT91C_BASE_SSC->SSC_RHR; + 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) { - SBYTE r; - - if(b < 0) { - r = -b; - } else { - r = b; - } - if(prev < 0) { - r -= prev; - } else { - r += prev; - } + int8_t r = ABS(b) + ABS(prev); - dest[c++] = (BYTE)r; + dest[c++] = (uint8_t)r; - if(c >= 20000) { + if(c >= 2000) { break; } } else { @@ -732,220 +640,346 @@ static int GetIso15693AnswerFromSniff(BYTE *receivedResponse, int maxLen, int *s getNext = !getNext; } } +} -////////////////////////////////////////// -/////////// DEMODULATE /////////////////// -////////////////////////////////////////// - int i, j; - int max = 0, maxPos=0; +void RecordRawAdcSamplesIso15693(void) +{ + uint8_t *dest = BigBuf_get_addr(); - int skip = 4; + int c = 0; + int getNext = 0; + int8_t prev = 0; -// if(GraphTraceLen < 1000) return; // THIS CHECKS FOR A BUFFER TO SMALL + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + // Setup SSC + FpgaSetupSsc(); - // 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)); + // Start from off (no field generated) + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(200); - int k = 0; // this will be our return value + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - // greg - If correlation is less than 1 then there's little point in continuing - if ((max/(arraylen(FrameSOF)/skip)) >= 1) // THIS SHOULD BE 1 - { + SpinDelay(100); - i = maxPos + arraylen(FrameSOF)/skip; + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); - BYTE outBuf[20]; - memset(outBuf, 0, sizeof(outBuf)); - BYTE mask = 0x01; + c = 0; + getNext = FALSE; 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(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = 0x43; } - if((i+(int)arraylen(FrameEOF)) >= 2000) { - DbpString("ran off end!"); - break; + 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) { + int8_t r = ABS(b) + ABS(prev); + + dest[c++] = (uint8_t)r; + + if(c >= 7000) { + break; + } + } else { + prev = b; + } + + getNext = !getNext; + WDT_HIT(); } } - if(mask != 0x01) { - DbpString("error, uneven octet! (discard extra bits!)"); -/// DbpString(" mask=%02x", mask); - } -// BYTE str1 [8]; -// itoa(k,str1); -// strcat(str1," octets read"); + 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(); -// DbpString( str1); // DbpString("%d octets", k); + // Start from off (no field generated) + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(10); -// for(i = 0; i < k; i+=3) { -// //DbpString("# %2d: %02x ", i, outBuf[i]); -// DbpIntegers(outBuf[i],outBuf[i+1],outBuf[i+2]); -// } + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + FpgaSetupSsc(); - 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 + // Give the tags time to energize + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + SpinDelay(250); -/// DbpString("CRC=%04x", Iso15693Crc(outBuf, k-2)); + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + LED_D_OFF(); } -//----------------------------------------------------------------------------- -// 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) +/////////////////////////////////////////////////////////////////////// +// 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) { - int c = 0; - BYTE *dest = (BYTE *)BigBuf; - int getNext = 0; + uint8_t cmd[5]; + + 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; - SBYTE prev = 0; + CodeIso15693AsReader(cmd, sizeof(cmd)); +} - BuildIdentifyRequest(); +// uid is in transmission order (which is reverse of display order) +static void BuildReadBlockRequest(uint8_t *uid, uint8_t blockNumber ) +{ + uint8_t cmd[13]; - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + 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]; + + 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; + int tsamples = 0; + int wait = 0; + int elapsed = 0; + + LED_A_ON(); + LED_B_ON(); + LED_C_OFF(); + LED_D_OFF(); + + if (init) Iso15693InitReader(); + + int answerLen=0; + uint8_t *answer = BigBuf_get_addr() + 3660; + 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; + } - // Give the tags time to energize - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); - SpinDelay(100); + LED_A_OFF(); + LED_B_OFF(); + LED_C_OFF(); + LED_D_OFF(); + + return answerLen; +} - // 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]; - c++; - if(c == ToSendMax+3) { - break; +// -------------------------------------------------------------------- +// 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); } - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - volatile DWORD r = AT91C_BASE_SSC->SSC_RHR; - (void)r; - } - WDT_HIT(); + + 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); } +} - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); - - c = 0; - getNext = FALSE; - 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)) { - SBYTE b; - b = (SBYTE)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) { - SBYTE r; - if(b < 0) { - r = -b; - } else { - r = b; - } - if(prev < 0) { - r -= prev; - } else { - r += prev; - } +/////////////////////////////////////////////////////////////////////// +// Functions called via USB/Client +/////////////////////////////////////////////////////////////////////// - dest[c++] = (BYTE)r; +void SetDebugIso15693(uint32_t debug) { + DEBUG=debug; + Dbprintf("Iso15693 Debug is now %s",DEBUG?"on":"off"); + return; +} - 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) +void ReaderIso15693(uint32_t parameter) { LED_A_ON(); LED_B_ON(); LED_C_OFF(); LED_D_OFF(); -//DbpString(parameter); - - //BYTE *answer0 = (((BYTE *)BigBuf) + 3560); // allow 100 bytes per reponse (way too much) - BYTE *answer1 = (((BYTE *)BigBuf) + 3660); // - BYTE *answer2 = (((BYTE *)BigBuf) + 3760); - BYTE *answer3 = (((BYTE *)BigBuf) + 3860); - //BYTE *TagUID= (((BYTE *)BigBuf) + 3960); // where we hold the uid for hi15reader -// int answerLen0 = 0; 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_get_addr() + 3660; + uint8_t *answer2 = BigBuf_get_addr() + 3760; + uint8_t *answer3 = BigBuf_get_addr() + 3860; // Blank arrays - memset(BigBuf + 3660, 0, 300); + memset(answer1, 0x00, 300); + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); // Setup SSC FpgaSetupSsc(); // Start from off (no field generated) - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(200); - - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - FpgaSetupSsc(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(200); // Give the tags time to energize FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); @@ -956,44 +990,19 @@ void ReaderIso15693(DWORD parameter) 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 + + 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]; @@ -1001,47 +1010,45 @@ void ReaderIso15693(DWORD parameter) TagUID[4] = answer1[6]; TagUID[5] = answer1[7]; TagUID[6] = answer1[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 - answerLen2 = GetIso15693AnswerFromTag(answer2, 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 - answerLen3 = GetIso15693AnswerFromTag(answer3, 100, &samples, &elapsed) ; + TagUID[7] = answer1[9]; // always E0 } - Dbprintf("%d octets read from IDENTIFY request: %x %x %x %x %x %x %x %x %x", answerLen1, - answer1[0], answer1[1], answer1[2], - answer1[3], answer1[4], answer1[5], - answer1[6], answer1[7], answer1[8]); - - Dbprintf("%d octets read from SELECT request: %x %x %x %x %x %x %x %x %x", answerLen2, - answer2[0], answer2[1], answer2[2], - answer2[3], answer2[4], answer2[5], - answer2[6], answer2[7], answer2[8]); - - Dbprintf("%d octets read from XXX request: %x %x %x %x %x %x %x %x %x", answerLen3, - answer3[0], answer3[1], answer3[2], - answer3[3], answer3[4], answer3[5], - answer3[6], answer3[7], answer3[8]); - - -// str2[0]=0; -// for(i = 0; i < responseLen3; i++) { -// itoa(str1,receivedAnswer3[i]); -// strcat(str2,str1); -// } -// DbpString(str2); + 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(); @@ -1049,35 +1056,31 @@ void ReaderIso15693(DWORD parameter) 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) +void SimTagIso15693(uint32_t parameter, uint8_t *uid) { LED_A_ON(); LED_B_ON(); LED_C_OFF(); LED_D_OFF(); - BYTE *answer1 = (((BYTE *)BigBuf) + 3660); // int answerLen1 = 0; + int samples = 0; + int tsamples = 0; + int wait = 0; + int elapsed = 0; - // Blank arrays - memset(answer1, 0, 100); - - // Setup SSC - FpgaSetupSsc(); - - // Start from off (no field generated) - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(200); + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + uint8_t *buf = BigBuf_get_addr() + 3660; + memset(buf, 0x00, 100); + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); FpgaSetupSsc(); - // Give the tags time to energize -// FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); // NO GOOD FOR SIM TAG!!!! + // Start from off (no field generated) + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); SpinDelay(200); LED_A_OFF(); @@ -1085,27 +1088,254 @@ void SimTagIso15693(DWORD parameter) LED_C_ON(); LED_D_OFF(); - int samples = 0; - int tsamples = 0; - int wait = 0; - int elapsed = 0; - - answerLen1 = GetIso15693AnswerFromSniff(answer1, 100, &samples, &elapsed) ; + // 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 - BuildInventoryResponse(); + // 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, - answer1[0], answer1[1], answer1[2], - answer1[3], answer1[4], answer1[5], - answer1[6], answer1[7], answer1[8]); + 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; + + 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; + 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(); +// UsbCommand n; + + 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); + } + } + +} + + + + +// -------------------------------------------------------------------- +// -- Misc & deprecated functions +// -------------------------------------------------------------------- + +/* + +// do not use; has a fix UID +static void __attribute__((unused)) BuildSysInfoRequest(uint8_t *uid) +{ + uint8_t cmd[12]; + + 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 << 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)); +} + + +// do not use; has a fix UID +static void __attribute__((unused)) BuildReadMultiBlockRequest(uint8_t *uid) +{ + uint8_t cmd[14]; + + 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 << 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)); +} + +// do not use; has a fix UID +static void __attribute__((unused)) BuildArbitraryRequest(uint8_t *uid,uint8_t CmdCode) +{ + uint8_t cmd[14]; + + 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 << 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)); +} + +// do not use; has a fix UID +static void __attribute__((unused)) BuildArbitraryCustomRequest(uint8_t uid[], uint8_t CmdCode) +{ + uint8_t cmd[14]; + + 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 << 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)); +} + + + + +*/ + +