mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-02-19 13:48:16 +08:00
I have kept whatever copyright notices exist. Please add your own copyright notice if you have made any nontrivial changes or additions to the code. There are several files without any attribution, currently.
1118 lines
28 KiB
C
1118 lines
28 KiB
C
//-----------------------------------------------------------------------------
|
|
// Jonathan Westhues, split Nov 2006
|
|
// Modified by Greg Jones, Jan 2009
|
|
//
|
|
// 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.)
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "proxmark3.h"
|
|
#include "util.h"
|
|
#include "apps.h"
|
|
#include "string.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.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// 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(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);
|
|
}
|
|
|
|
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 uint16_t Crc(uint8_t *v, int n)
|
|
{
|
|
uint32_t reg;
|
|
int i, j;
|
|
|
|
reg = 0xffff;
|
|
for(i = 0; i < n; i++) {
|
|
reg = reg ^ ((uint32_t)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<j; i++, j--) {
|
|
c = s[i];
|
|
s[i] = s[j];
|
|
s[j] = c;
|
|
}
|
|
}
|
|
|
|
/* itoa: convert n to characters in s */
|
|
void itoa(int n, char s[])
|
|
{
|
|
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);
|
|
}
|
|
|
|
//////////////////////////////////////// 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)
|
|
{
|
|
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;
|
|
|
|
CodeIso15693AsReader(cmd, sizeof(cmd));
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
static void BuildSelectRequest( uint8_t uid[])
|
|
{
|
|
|
|
// uid[6]=0x31; // this is getting ignored - the uid array is not happening...
|
|
uint8_t cmd[12];
|
|
|
|
uint16_t 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 __attribute__((unused)) BuildReadBlockRequest(uint8_t *uid, uint8_t blockNumber )
|
|
{
|
|
uint8_t cmd[13];
|
|
|
|
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
|
|
// 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 __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));
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// Now the VICC>VCD responses when we are simulating a tag
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
static void BuildInventoryResponse(void)
|
|
{
|
|
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
|
|
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 uint8_t *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 uint32_t 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 uint32_t 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;
|
|
|
|
// 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 uint32_t r = AT91C_BASE_SSC->SSC_RHR;
|
|
(void)r;
|
|
}
|
|
WDT_HIT();
|
|
}
|
|
*samples = (c + *wait) << 3;
|
|
}
|
|
|
|
static int GetIso15693AnswerFromTag(uint8_t *receivedResponse, int maxLen, int *samples, int *elapsed)
|
|
{
|
|
int c = 0;
|
|
uint8_t *dest = (uint8_t *)BigBuf;
|
|
int getNext = 0;
|
|
|
|
int8_t 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(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) {
|
|
int8_t r;
|
|
|
|
if(b < 0) {
|
|
r = -b;
|
|
} else {
|
|
r = b;
|
|
}
|
|
if(prev < 0) {
|
|
r -= prev;
|
|
} else {
|
|
r += prev;
|
|
}
|
|
|
|
dest[c++] = (uint8_t)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;
|
|
|
|
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("error, uneven octet! (discard extra bits!)");
|
|
/// DbpString(" mask=%02x", mask);
|
|
}
|
|
// uint8_t 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(uint8_t *receivedResponse, int maxLen, int *samples, int *elapsed)
|
|
{
|
|
int c = 0;
|
|
uint8_t *dest = (uint8_t *)BigBuf;
|
|
int getNext = 0;
|
|
|
|
int8_t 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(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) {
|
|
int8_t r;
|
|
|
|
if(b < 0) {
|
|
r = -b;
|
|
} else {
|
|
r = b;
|
|
}
|
|
if(prev < 0) {
|
|
r -= prev;
|
|
} else {
|
|
r += prev;
|
|
}
|
|
|
|
dest[c++] = (uint8_t)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;
|
|
|
|
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("error, uneven octet! (discard extra bits!)");
|
|
/// DbpString(" mask=%02x", mask);
|
|
}
|
|
// uint8_t 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;
|
|
uint8_t *dest = (uint8_t *)BigBuf;
|
|
int getNext = 0;
|
|
|
|
int8_t 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(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(;;) {
|
|
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) {
|
|
int8_t r;
|
|
|
|
if(b < 0) {
|
|
r = -b;
|
|
} else {
|
|
r = b;
|
|
}
|
|
if(prev < 0) {
|
|
r -= prev;
|
|
} else {
|
|
r += prev;
|
|
}
|
|
|
|
dest[c++] = (uint8_t)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(uint32_t parameter)
|
|
{
|
|
LED_A_ON();
|
|
LED_B_ON();
|
|
LED_C_OFF();
|
|
LED_D_OFF();
|
|
|
|
//DbpString(parameter);
|
|
|
|
//uint8_t *answer0 = (((uint8_t *)BigBuf) + 3560); // allow 100 bytes per reponse (way too much)
|
|
uint8_t *answer1 = (((uint8_t *)BigBuf) + 3660); //
|
|
uint8_t *answer2 = (((uint8_t *)BigBuf) + 3760);
|
|
uint8_t *answer3 = (((uint8_t *)BigBuf) + 3860);
|
|
//uint8_t *TagUID= (((uint8_t *)BigBuf) + 3960); // where we hold the uid for hi15reader
|
|
// int answerLen0 = 0;
|
|
int answerLen1 = 0;
|
|
int answerLen2 = 0;
|
|
int answerLen3 = 0;
|
|
|
|
// Blank arrays
|
|
memset(BigBuf + 3660, 0, 300);
|
|
|
|
// 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
|
|
uint8_t 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
|
|
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
|
|
|
|
// 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) ;
|
|
|
|
}
|
|
|
|
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);
|
|
|
|
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)
|
|
{
|
|
LED_A_ON();
|
|
LED_B_ON();
|
|
LED_C_OFF();
|
|
LED_D_OFF();
|
|
|
|
uint8_t *answer1 = (((uint8_t *)BigBuf) + 3660); //
|
|
int answerLen1 = 0;
|
|
|
|
// Blank arrays
|
|
memset(answer1, 0, 100);
|
|
|
|
// 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;
|
|
|
|
answerLen1 = GetIso15693AnswerFromSniff(answer1, 100, &samples, &elapsed) ;
|
|
|
|
if (answerLen1 >=1) // we should do a better check than this
|
|
{
|
|
// Build a suitable reponse to the reader INVENTORY cocmmand
|
|
BuildInventoryResponse();
|
|
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]);
|
|
|
|
LED_A_OFF();
|
|
LED_B_OFF();
|
|
LED_C_OFF();
|
|
LED_D_OFF();
|
|
}
|