X-Git-Url: http://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/6658905f18a1eebc148836f26c731dea9c1377dc..7fe9b0b742d7dae9c5af1d292d11840b5c3cbfae:/armsrc/iso14443a.c diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index a687d877..02d912e7 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -5,7 +5,12 @@ //----------------------------------------------------------------------------- #include #include "apps.h" -#include "..\common\iso14443_crc.c" +#include "iso14443crc.h" + +static BYTE *trace = (BYTE *) BigBuf; +static int traceLen = 0; +static int rsamples = 0; +static BOOL tracing = TRUE; typedef enum { SEC_D = 1, @@ -16,6 +21,83 @@ typedef enum { SEC_Z = 6 } SecType; +static const BYTE OddByteParity[256] = { + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 +}; + +// BIG CHANGE - UNDERSTAND THIS BEFORE WE COMMIT +#define RECV_CMD_OFFSET 3032 +#define RECV_RES_OFFSET 3096 +#define DMA_BUFFER_OFFSET 3160 +#define DMA_BUFFER_SIZE 4096 +#define TRACE_LENGTH 3000 + +//----------------------------------------------------------------------------- +// Generate the parity value for a byte sequence +// +//----------------------------------------------------------------------------- +DWORD GetParity(const BYTE * pbtCmd, int iLen) +{ + int i; + DWORD dwPar = 0; + + // Generate the encrypted data + for (i = 0; i < iLen; i++) { + // Save the encrypted parity bit + dwPar |= ((OddByteParity[pbtCmd[i]]) << i); + } + return dwPar; +} + +static void AppendCrc14443a(BYTE* data, int len) +{ + ComputeCrc14443(CRC_14443_A,data,len,data+len,data+len+1); +} + +BOOL LogTrace(const BYTE * btBytes, int iLen, int iSamples, DWORD dwParity, BOOL bReader) +{ + // Return when trace is full + if (traceLen >= TRACE_LENGTH) return FALSE; + + // Trace the random, i'm curious + rsamples += iSamples; + trace[traceLen++] = ((rsamples >> 0) & 0xff); + trace[traceLen++] = ((rsamples >> 8) & 0xff); + trace[traceLen++] = ((rsamples >> 16) & 0xff); + trace[traceLen++] = ((rsamples >> 24) & 0xff); + if (!bReader) { + trace[traceLen - 1] |= 0x80; + } + trace[traceLen++] = ((dwParity >> 0) & 0xff); + trace[traceLen++] = ((dwParity >> 8) & 0xff); + trace[traceLen++] = ((dwParity >> 16) & 0xff); + trace[traceLen++] = ((dwParity >> 24) & 0xff); + trace[traceLen++] = iLen; + memcpy(trace + traceLen, btBytes, iLen); + traceLen += iLen; + return TRUE; +} + +BOOL LogTraceInfo(byte_t* data, size_t len) +{ + return LogTrace(data,len,0,GetParity(data,len),TRUE); +} + //----------------------------------------------------------------------------- // The software UART that receives commands from the reader, and its state // variables. @@ -509,15 +591,6 @@ static BOOL ManchesterDecoding(int v) //----------------------------------------------------------------------------- void SnoopIso14443a(void) { - - // BIG CHANGE - UNDERSTAND THIS BEFORE WE COMMIT - - #define RECV_CMD_OFFSET 3032 - #define RECV_RES_OFFSET 3096 - #define DMA_BUFFER_OFFSET 3160 - #define DMA_BUFFER_SIZE 4096 - #define TRACE_LENGTH 3000 - // #define RECV_CMD_OFFSET 2032 // original (working as of 21/2/09) values // #define RECV_RES_OFFSET 2096 // original (working as of 21/2/09) values // #define DMA_BUFFER_OFFSET 2160 // original (working as of 21/2/09) values @@ -538,8 +611,8 @@ void SnoopIso14443a(void) // As we receive stuff, we copy it from receivedCmd or receivedResponse // into trace, along with its length and other annotations. - BYTE *trace = (BYTE *)BigBuf; - int traceLen = 0; + //BYTE *trace = (BYTE *)BigBuf; + //int traceLen = 0; // The DMA buffer, used to stream samples from the FPGA SBYTE *dmaBuf = ((SBYTE *)BigBuf) + DMA_BUFFER_OFFSET; @@ -567,6 +640,8 @@ void SnoopIso14443a(void) Uart.state = STATE_UNSYNCD; // And put the FPGA in the appropriate mode + // Signal field is off with the appropriate LED + LED_D_OFF(); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_SNIFFER); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); @@ -581,7 +656,7 @@ void SnoopIso14443a(void) // And now we loop, receiving samples. for(;;) { WDT_HIT(); - int behindBy = (lastRxCounter - PDC_RX_COUNTER(SSC_BASE)) & + int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) & (DMA_BUFFER_SIZE-1); if(behindBy > maxBehindBy) { maxBehindBy = behindBy; @@ -598,8 +673,8 @@ void SnoopIso14443a(void) if(upTo - dmaBuf > DMA_BUFFER_SIZE) { upTo -= DMA_BUFFER_SIZE; lastRxCounter += DMA_BUFFER_SIZE; - PDC_RX_NEXT_POINTER(SSC_BASE) = (DWORD)upTo; - PDC_RX_NEXT_COUNTER(SSC_BASE) = DMA_BUFFER_SIZE; + AT91C_BASE_PDC_SSC->PDC_RNPR = (DWORD)upTo; + AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE; } samples += 4; @@ -666,13 +741,13 @@ void SnoopIso14443a(void) DbpString("COMMAND FINISHED"); - DbpIntegers(maxBehindBy, Uart.state, Uart.byteCnt); - DbpIntegers(Uart.byteCntMax, traceLen, (int)Uart.output[0]); + Dbprintf("%x %x %x", maxBehindBy, Uart.state, Uart.byteCnt); + Dbprintf("%x %x %x", Uart.byteCntMax, traceLen, (int)Uart.output[0]); done: - PDC_CONTROL(SSC_BASE) = PDC_RX_DISABLE; - DbpIntegers(maxBehindBy, Uart.state, Uart.byteCnt); - DbpIntegers(Uart.byteCntMax, traceLen, (int)Uart.output[0]); + AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; + Dbprintf("%x %x %x", maxBehindBy, Uart.state, Uart.byteCnt); + Dbprintf("%x %x %x", Uart.byteCntMax, traceLen, (int)Uart.output[0]); LED_A_OFF(); LED_B_OFF(); LED_C_OFF(); @@ -841,6 +916,8 @@ static BOOL GetIso14443aCommandFromReader(BYTE *received, int *len, int maxLen) { // Set FPGA mode to "simulated ISO 14443 tag", no modulation (listen // only, since we are receiving, not transmitting). + // Signal field is off with the appropriate LED + LED_D_OFF(); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN); // Now run a `software UART' on the stream of incoming samples. @@ -853,11 +930,11 @@ static BOOL GetIso14443aCommandFromReader(BYTE *received, int *len, int maxLen) if(BUTTON_PRESS()) return FALSE; - if(SSC_STATUS & (SSC_STATUS_TX_READY)) { - SSC_TRANSMIT_HOLDING = 0x00; + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = 0x00; } - if(SSC_STATUS & (SSC_STATUS_RX_READY)) { - BYTE b = (BYTE)SSC_RECEIVE_HOLDING; + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + BYTE b = (BYTE)AT91C_BASE_SSC->SSC_RHR; if(MillerDecoding((b & 0xf0) >> 4)) { *len = Uart.byteCnt; return TRUE; @@ -893,8 +970,8 @@ void SimulateIso14443aTag(int tagType, int TagUid) // my desfire static const BYTE response2[] = { 0x88, 0x04, 0x21, 0x3f, 0x4d }; // known uid - note cascade (0x88), 2nd byte (0x04) = NXP/Phillips - - + + // When reader selects us during cascade1 it will send cmd3 //BYTE response3[] = { 0x04, 0x00, 0x00 }; // SAK Select (cascade1) successful response (ULTRALITE) BYTE response3[] = { 0x24, 0x00, 0x00 }; // SAK Select (cascade1) successful response (DESFire) @@ -909,9 +986,7 @@ static const BYTE response2a[] = { 0x51, 0x48, 0x1d, 0x80, 0x84 }; // uid - cas //BYTE response3a[] = { 0x00, 0x00, 0x00 }; // SAK Select (cascade2) successful response (ULTRALITE) BYTE response3a[] = { 0x20, 0x00, 0x00 }; // SAK Select (cascade2) successful response (DESFire) ComputeCrc14443(CRC_14443_A, response3a, 1, &response3a[1], &response3a[2]); - -// When reader tries to authenticate - // static const BYTE cmd5[] = { 0x60, 0x00, 0xf5, 0x7b }; + static const BYTE response5[] = { 0x00, 0x00, 0x00, 0x00 }; // Very random tag nonce BYTE *resp; @@ -1069,8 +1144,8 @@ ComputeCrc14443(CRC_14443_A, response3a, 1, &response3a[1], &response3a[2]); } else if(receivedCmd[0] == 0x30) { // Received a READ resp = resp4; respLen = resp4Len; order = 4; // Do nothing - DbpString("Read request from reader:"); - DbpIntegers(receivedCmd[0], receivedCmd[1], receivedCmd[2]); + Dbprintf("Read request from reader: %x %x %x", + receivedCmd[0], receivedCmd[1], receivedCmd[2]); } else if(receivedCmd[0] == 0x50) { @@ -1081,21 +1156,20 @@ ComputeCrc14443(CRC_14443_A, response3a, 1, &response3a[1], &response3a[2]); } else if(receivedCmd[0] == 0x60) { // Received an authentication request resp = resp5; respLen = resp5Len; order = 7; - DbpString("Authenticate request from reader:"); - DbpIntegers(receivedCmd[0], receivedCmd[1], receivedCmd[2]); + Dbprintf("Authenticate request from reader: %x %x %x", + receivedCmd[0], receivedCmd[1], receivedCmd[2]); } else if(receivedCmd[0] == 0xE0) { // Received a RATS request resp = resp1; respLen = 0;order = 70; - DbpString("RATS request from reader:"); - DbpIntegers(receivedCmd[0], receivedCmd[1], receivedCmd[2]); + Dbprintf("RATS request from reader: %x %x %x", + receivedCmd[0], receivedCmd[1], receivedCmd[2]); } else { // Never seen this command before - DbpString("Unknown command received from reader:"); - DbpIntegers(receivedCmd[0], receivedCmd[1], receivedCmd[2]); - DbpIntegers(receivedCmd[3], receivedCmd[4], receivedCmd[5]); - DbpIntegers(receivedCmd[6], receivedCmd[7], receivedCmd[8]); - + Dbprintf("Unknown command received from reader: %x %x %x %x %x %x %x %x %x", + receivedCmd[0], receivedCmd[1], receivedCmd[2], + receivedCmd[3], receivedCmd[3], receivedCmd[4], + receivedCmd[5], receivedCmd[6], receivedCmd[7]); // Do not respond resp = resp1; respLen = 0; order = 0; } @@ -1126,7 +1200,7 @@ ComputeCrc14443(CRC_14443_A, response3a, 1, &response3a[1], &response3a[2]); // Modulate Manchester FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_MOD); - SSC_TRANSMIT_HOLDING = 0x00; + AT91C_BASE_SSC->SSC_THR = 0x00; FpgaSetupSsc(); // ### Transmit the response ### @@ -1134,11 +1208,11 @@ ComputeCrc14443(CRC_14443_A, response3a, 1, &response3a[1], &response3a[2]); b = 0x00; fdt_indicator = FALSE; for(;;) { - if(SSC_STATUS & (SSC_STATUS_RX_READY)) { - volatile BYTE b = (BYTE)SSC_RECEIVE_HOLDING; + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + volatile BYTE b = (BYTE)AT91C_BASE_SSC->SSC_RHR; (void)b; } - if(SSC_STATUS & (SSC_STATUS_TX_READY)) { + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { if(i > respLen) { b = 0x00; u++; @@ -1146,7 +1220,7 @@ ComputeCrc14443(CRC_14443_A, response3a, 1, &response3a[1], &response3a[2]); b = resp[i]; i++; } - SSC_TRANSMIT_HOLDING = b; + AT91C_BASE_SSC->SSC_THR = b; if(u > 4) { break; @@ -1159,7 +1233,7 @@ ComputeCrc14443(CRC_14443_A, response3a, 1, &response3a[1], &response3a[2]); } - DbpIntegers(happened, happened2, cmdsRecvd); + Dbprintf("%x %x %x", happened, happened2, cmdsRecvd); LED_A_OFF(); } @@ -1168,40 +1242,42 @@ ComputeCrc14443(CRC_14443_A, response3a, 1, &response3a[1], &response3a[2]); //----------------------------------------------------------------------------- static void TransmitFor14443a(const BYTE *cmd, int len, int *samples, int *wait) { - int c; - - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); - - 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(); + int c; + + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); + + if (wait) + 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++; } - - 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(); + 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; } - *samples = (c + *wait) << 3; + WDT_HIT(); + } + if (samples) *samples = (c + *wait) << 3; } //----------------------------------------------------------------------------- @@ -1288,11 +1364,11 @@ void ArbitraryFromReader(const BYTE *cmd, int parity, int len) // Code a 7-bit command without parity bit // This is especially for 0x26 and 0x52 (REQA and WUPA) //----------------------------------------------------------------------------- -void ShortFrameFromReader(const BYTE *cmd) +void ShortFrameFromReader(const BYTE bt) { int j; int last; - BYTE b; + BYTE b; ToSendReset(); @@ -1300,7 +1376,7 @@ void ShortFrameFromReader(const BYTE *cmd) Sequence(SEC_Z); last = 0; - b = cmd[0]; + b = bt; for(j = 0; j < 7; j++) { if(b & 1) { // Sequence X @@ -1344,86 +1420,81 @@ void ShortFrameFromReader(const BYTE *cmd) //----------------------------------------------------------------------------- // Prepare reader command to send to FPGA -// +// //----------------------------------------------------------------------------- -void CodeIso14443aAsReader(const BYTE *cmd, int len) +void CodeIso14443aAsReaderPar(const BYTE * cmd, int len, DWORD dwParity) { - int i, j; - int last; - int oddparity; - BYTE b; - - ToSendReset(); - - // Start of Communication (Seq. Z) - Sequence(SEC_Z); - last = 0; - - for(i = 0; i < len; i++) { - // Data bits - b = cmd[i]; - oddparity = 0x01; - for(j = 0; j < 8; j++) { - oddparity ^= (b & 1); - if(b & 1) { - // Sequence X - Sequence(SEC_X); - last = 1; - } else { - if(last == 0) { - // Sequence Z - Sequence(SEC_Z); - } - else { - // Sequence Y - Sequence(SEC_Y); - last = 0; - } - } - b >>= 1; + int i, j; + int last; + BYTE b; + + ToSendReset(); + + // Start of Communication (Seq. Z) + Sequence(SEC_Z); + last = 0; + + // Generate send structure for the data bits + for (i = 0; i < len; i++) { + // Get the current byte to send + b = cmd[i]; + + for (j = 0; j < 8; j++) { + if (b & 1) { + // Sequence X + Sequence(SEC_X); + last = 1; + } else { + if (last == 0) { + // Sequence Z + Sequence(SEC_Z); + } else { + // Sequence Y + Sequence(SEC_Y); + last = 0; } - - // Parity bit - if(oddparity) { - // Sequence X - Sequence(SEC_X); - last = 1; - } else { - if(last == 0) { - // Sequence Z - Sequence(SEC_Z); - } - else { - // Sequence Y - Sequence(SEC_Y); - last = 0; - } - } + } + b >>= 1; } - - // End of Communication - if(last == 0) { - // Sequence Z - Sequence(SEC_Z); - } - else { - // Sequence Y - Sequence(SEC_Y); - last = 0; - } - // Sequence Y - Sequence(SEC_Y); - - // Just to be sure! - Sequence(SEC_Y); - Sequence(SEC_Y); - Sequence(SEC_Y); - - // Convert from last character reference to length - ToSendMax++; + + // Get the parity bit + if ((dwParity >> i) & 0x01) { + // Sequence X + Sequence(SEC_X); + last = 1; + } else { + if (last == 0) { + // Sequence Z + Sequence(SEC_Z); + } else { + // Sequence Y + Sequence(SEC_Y); + last = 0; + } + } + } + + // End of Communication + if (last == 0) { + // Sequence Z + Sequence(SEC_Z); + } else { + // Sequence Y + Sequence(SEC_Y); + last = 0; + } + // Sequence Y + Sequence(SEC_Y); + + // Just to be sure! + Sequence(SEC_Y); + Sequence(SEC_Y); + Sequence(SEC_Y); + + // Convert from last character reference to length + ToSendMax++; } - //----------------------------------------------------------------------------- // Wait a certain time for tag response // If a response is captured return TRUE @@ -1434,8 +1505,10 @@ static BOOL GetIso14443aAnswerFromTag(BYTE *receivedResponse, int maxLen, int *s // buffer needs to be 512 bytes int c; - // Set FPGA mode to "simulated ISO 14443 tag", no modulation (listen + // Set FPGA mode to "reader listen mode", no modulation (listen // only, since we are receiving, not transmitting). + // Signal field is on with the appropriate LED + LED_D_ON(); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_LISTEN); // Now get the answer from the card @@ -1444,19 +1517,19 @@ static BOOL GetIso14443aAnswerFromTag(BYTE *receivedResponse, int maxLen, int *s Demod.state = DEMOD_UNSYNCD; BYTE b; - *elapsed = 0; + if (elapsed) *elapsed = 0; c = 0; for(;;) { WDT_HIT(); - if(SSC_STATUS & (SSC_STATUS_TX_READY)) { - SSC_TRANSMIT_HOLDING = 0x00; // To make use of exact timing of next command from reader!! - (*elapsed)++; + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = 0x00; // To make use of exact timing of next command from reader!! + if (elapsed) (*elapsed)++; } - if(SSC_STATUS & (SSC_STATUS_RX_READY)) { + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { if(c < 512) { c++; } else { return FALSE; } - b = (BYTE)SSC_RECEIVE_HOLDING; + b = (BYTE)AT91C_BASE_SSC->SSC_RHR; if(ManchesterDecoding((b & 0xf0) >> 4)) { *samples = ((c - 1) << 3) + 4; return TRUE; @@ -1469,6 +1542,51 @@ static BOOL GetIso14443aAnswerFromTag(BYTE *receivedResponse, int maxLen, int *s } } +void ReaderTransmitShort(const BYTE* bt) +{ + int wait = 0; + int samples = 0; + + ShortFrameFromReader(*bt); + + // Select the card + TransmitFor14443a(ToSend, ToSendMax, &samples, &wait); + + // Store reader command in buffer + if (tracing) LogTrace(bt,1,0,GetParity(bt,1),TRUE); +} + +void ReaderTransmitPar(BYTE* frame, int len, DWORD par) +{ + int wait = 0; + int samples = 0; + + // This is tied to other size changes + // BYTE* frame_addr = ((BYTE*)BigBuf) + 2024; + CodeIso14443aAsReaderPar(frame,len,par); + + // Select the card + TransmitFor14443a(ToSend, ToSendMax, &samples, &wait); + + // Store reader command in buffer + if (tracing) LogTrace(frame,len,0,par,TRUE); +} + + +void ReaderTransmit(BYTE* frame, int len) +{ + // Generate parity and redirect + ReaderTransmitPar(frame,len,GetParity(frame,len)); +} + +BOOL ReaderReceive(BYTE* receivedAnswer) +{ + int samples = 0; + if (!GetIso14443aAnswerFromTag(receivedAnswer,100,&samples,0)) return FALSE; + if (tracing) LogTrace(receivedAnswer,Demod.len,samples,Demod.parityBits,FALSE); + return TRUE; +} + //----------------------------------------------------------------------------- // Read an ISO 14443a tag. Send out commands and store answers. // @@ -1476,340 +1594,259 @@ static BOOL GetIso14443aAnswerFromTag(BYTE *receivedResponse, int maxLen, int *s void ReaderIso14443a(DWORD parameter) { // Anticollision - static const BYTE cmd1[] = { 0x52 }; // or 0x26 - static const BYTE cmd2[] = { 0x93,0x20 }; - // UID = 0x2a,0x69,0x8d,0x43,0x8d, last two bytes are CRC bytes - BYTE cmd3[] = { 0x93,0x70,0x2a,0x69,0x8d,0x43,0x8d,0x52,0x55 }; - - // For Ultralight add an extra anticollission layer -> 95 20 and then 95 70 - - // greg - here we will add our cascade level 2 anticolission and select functions to deal with ultralight // and 7-byte UIDs in generall... - BYTE cmd4[] = {0x95,0x20}; // ask for cascade 2 select - // 95 20 - //BYTE cmd3a[] = { 0x95,0x70,0x2a,0x69,0x8d,0x43,0x8d,0x52,0x55 }; - // 95 70 - - // cascade 2 select - BYTE cmd5[] = { 0x95,0x70,0x2a,0x69,0x8d,0x43,0x8d,0x52,0x55 }; - - - // RATS (request for answer to select) - //BYTE cmd6[] = { 0xe0,0x50,0xbc,0xa5 }; // original RATS - BYTE cmd6[] = { 0xe0,0x21,0xb2,0xc7 }; // Desfire RATS - - int reqaddr = 2024; // was 2024 - tied to other size changes - int reqsize = 60; - - BYTE *req1 = (((BYTE *)BigBuf) + reqaddr); - int req1Len; - - BYTE *req2 = (((BYTE *)BigBuf) + reqaddr + reqsize); - int req2Len; - - BYTE *req3 = (((BYTE *)BigBuf) + reqaddr + (reqsize * 2)); - int req3Len; - -// greg added req 4 & 5 to deal with cascade 2 section - BYTE *req4 = (((BYTE *)BigBuf) + reqaddr + (reqsize * 3)); - int req4Len; - - BYTE *req5 = (((BYTE *)BigBuf) + reqaddr + (reqsize * 4)); - int req5Len; - - BYTE *req6 = (((BYTE *)BigBuf) + reqaddr + (reqsize * 5)); - int req6Len; - - //BYTE *req7 = (((BYTE *)BigBuf) + reqaddr + (reqsize * 6)); - //int req7Len; - - BYTE *receivedAnswer = (((BYTE *)BigBuf) + 3560); // was 3560 - tied to other size changes - - BYTE *trace = (BYTE *)BigBuf; - int traceLen = 0; - int rsamples = 0; - - memset(trace, 0x44, 2000); // was 2000 - tied to oter size chnages - // setting it to 3000 causes no tag responses to be detected (2900 is ok) - // setting it to 1000 causes no tag responses to be detected - - // Prepare some commands! - ShortFrameFromReader(cmd1); - memcpy(req1, ToSend, ToSendMax); req1Len = ToSendMax; - - CodeIso14443aAsReader(cmd2, sizeof(cmd2)); - memcpy(req2, ToSend, ToSendMax); req2Len = ToSendMax; - - CodeIso14443aAsReader(cmd3, sizeof(cmd3)); - memcpy(req3, ToSend, ToSendMax); req3Len = ToSendMax; - - - CodeIso14443aAsReader(cmd4, sizeof(cmd4)); // 4 is cascade 2 request - memcpy(req4, ToSend, ToSendMax); req4Len = ToSendMax; - - - CodeIso14443aAsReader(cmd5, sizeof(cmd5)); // 5 is cascade 2 select - memcpy(req5, ToSend, ToSendMax); req5Len = ToSendMax; - - - CodeIso14443aAsReader(cmd6, sizeof(cmd6)); - memcpy(req6, ToSend, ToSendMax); req6Len = ToSendMax; + BYTE wupa[] = { 0x52 }; + BYTE sel_all[] = { 0x93,0x20 }; + BYTE sel_uid[] = { 0x93,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; + BYTE sel_all_c2[] = { 0x95,0x20 }; + BYTE sel_uid_c2[] = { 0x95,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; + + // Mifare AUTH + BYTE mf_auth[] = { 0x60,0x00,0xf5,0x7b }; +// BYTE mf_nr_ar[] = { 0x00,0x00,0x00,0x00 }; + + BYTE* receivedAnswer = (((BYTE *)BigBuf) + 3560); // was 3560 - tied to other size changes + traceLen = 0; // Setup SSC FpgaSetupSsc(); // Start from off (no field generated) - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(200); + // Signal field is off with the appropriate LED + LED_D_OFF(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(200); - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - FpgaSetupSsc(); + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + FpgaSetupSsc(); // Now give it time to spin up. - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); + // Signal field is on with the appropriate LED + LED_D_ON(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); 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; - for(;;) { - // Send WUPA (or REQA) - TransmitFor14443a(req1, req1Len, &tsamples, &wait); - // Store answer in buffer - trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; - trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; - trace[traceLen++] = 1; - memcpy(trace+traceLen, cmd1, 1); - traceLen += 1; - if(traceLen > TRACE_LENGTH) goto done; - - while(!GetIso14443aAnswerFromTag(receivedAnswer, 100, &samples, &elapsed)) { - if(BUTTON_PRESS()) goto done; - - // No answer, just continue polling - TransmitFor14443a(req1, req1Len, &tsamples, &wait); - // Store answer in buffer - trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; - trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; - trace[traceLen++] = 1; - memcpy(trace+traceLen, cmd1, 1); - traceLen += 1; - if(traceLen > TRACE_LENGTH) goto done; - } - - // Store answer in buffer - rsamples = rsamples + (samples - Demod.samples); - trace[traceLen++] = ((rsamples >> 0) & 0xff); - trace[traceLen++] = ((rsamples >> 8) & 0xff); - trace[traceLen++] = ((rsamples >> 16) & 0xff); - trace[traceLen++] = 0x80 | ((rsamples >> 24) & 0xff); - trace[traceLen++] = ((Demod.parityBits >> 0) & 0xff); - trace[traceLen++] = ((Demod.parityBits >> 8) & 0xff); - trace[traceLen++] = ((Demod.parityBits >> 16) & 0xff); - trace[traceLen++] = ((Demod.parityBits >> 24) & 0xff); - trace[traceLen++] = Demod.len; - memcpy(trace+traceLen, receivedAnswer, Demod.len); - traceLen += Demod.len; - if(traceLen > TRACE_LENGTH) goto done; - - // Ask for card UID - TransmitFor14443a(req2, req2Len, &tsamples, &wait); - // Store answer in buffer - trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; - trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; - trace[traceLen++] = 2; - memcpy(trace+traceLen, cmd2, 2); - traceLen += 2; - if(traceLen > TRACE_LENGTH) goto done; - - if(!GetIso14443aAnswerFromTag(receivedAnswer, 100, &samples, &elapsed)) { - continue; - } + while(traceLen < TRACE_LENGTH) + { + // Broadcast for a card, WUPA (0x52) will force response from all cards in the field + ReaderTransmitShort(wupa); + + // Test if the action was cancelled + if(BUTTON_PRESS()) { + break; + } + + // Receive the ATQA + if (!ReaderReceive(receivedAnswer)) continue; - // Store answer in buffer - rsamples = rsamples + (samples - Demod.samples); - trace[traceLen++] = ((rsamples >> 0) & 0xff); - trace[traceLen++] = ((rsamples >> 8) & 0xff); - trace[traceLen++] = ((rsamples >> 16) & 0xff); - trace[traceLen++] = 0x80 | ((rsamples >> 24) & 0xff); - trace[traceLen++] = ((Demod.parityBits >> 0) & 0xff); - trace[traceLen++] = ((Demod.parityBits >> 8) & 0xff); - trace[traceLen++] = ((Demod.parityBits >> 16) & 0xff); - trace[traceLen++] = ((Demod.parityBits >> 24) & 0xff); - trace[traceLen++] = Demod.len; - memcpy(trace+traceLen, receivedAnswer, Demod.len); - traceLen += Demod.len; - if(traceLen > TRACE_LENGTH) goto done; + // Transmit SELECT_ALL + ReaderTransmit(sel_all,sizeof(sel_all)); + // Receive the UID + if (!ReaderReceive(receivedAnswer)) continue; + // Construct SELECT UID command // First copy the 5 bytes (Mifare Classic) after the 93 70 - memcpy(cmd3+2,receivedAnswer,5); + memcpy(sel_uid+2,receivedAnswer,5); // Secondly compute the two CRC bytes at the end - ComputeCrc14443(CRC_14443_A, cmd3, 7, &cmd3[7], &cmd3[8]); - // Prepare the bit sequence to modulate the subcarrier - // Store answer in buffer - trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; - trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; - trace[traceLen++] = 9; - memcpy(trace+traceLen, cmd3, 9); - traceLen += 9; - if(traceLen > TRACE_LENGTH) goto done; - CodeIso14443aAsReader(cmd3, sizeof(cmd3)); - memcpy(req3, ToSend, ToSendMax); req3Len = ToSendMax; - - // Select the card - TransmitFor14443a(req3, req3Len, &samples, &wait); - if(!GetIso14443aAnswerFromTag(receivedAnswer, 100, &samples, &elapsed)) { - continue; - } + AppendCrc14443a(sel_uid,7); + + // Transmit SELECT_UID + ReaderTransmit(sel_uid,sizeof(sel_uid)); + + // Receive the SAK + if (!ReaderReceive(receivedAnswer)) continue; - // Store answer in buffer - rsamples = rsamples + (samples - Demod.samples); - trace[traceLen++] = ((rsamples >> 0) & 0xff); - trace[traceLen++] = ((rsamples >> 8) & 0xff); - trace[traceLen++] = ((rsamples >> 16) & 0xff); - trace[traceLen++] = 0x80 | ((rsamples >> 24) & 0xff); - trace[traceLen++] = ((Demod.parityBits >> 0) & 0xff); - trace[traceLen++] = ((Demod.parityBits >> 8) & 0xff); - trace[traceLen++] = ((Demod.parityBits >> 16) & 0xff); - trace[traceLen++] = ((Demod.parityBits >> 24) & 0xff); - trace[traceLen++] = Demod.len; - memcpy(trace+traceLen, receivedAnswer, Demod.len); - traceLen += Demod.len; - if(traceLen > TRACE_LENGTH) goto done; - -// OK we have selected at least at cascade 1, lets see if first byte of UID was 0x88 in -// which case we need to make a cascade 2 request and select - this is a long UID - if (receivedAnswer[0] = 0x88) + // OK we have selected at least at cascade 1, lets see if first byte of UID was 0x88 in + // which case we need to make a cascade 2 request and select - this is a long UID + // When the UID is not complete, the 3nd bit (from the right) is set in the SAK. + if (receivedAnswer[0] &= 0x04) { - // Do cascade level 2 stuff - /////////////////////////////////////////////////////////////////// - // First issue a '95 20' identify request - // Ask for card UID (part 2) - TransmitFor14443a(req4, req4Len, &tsamples, &wait); - // Store answer in buffer - trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; - trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; - trace[traceLen++] = 2; - memcpy(trace+traceLen, cmd4, 2); - traceLen += 2; - if(traceLen > TRACE_LENGTH) { - DbpString("Bugging out, just popped tracelength"); - goto done;} - - if(!GetIso14443aAnswerFromTag(receivedAnswer, 100, &samples, &elapsed)) { - continue; + // Transmit SELECT_ALL + ReaderTransmit(sel_all_c2,sizeof(sel_all_c2)); + + // Receive the UID + if (!ReaderReceive(receivedAnswer)) continue; + + // Construct SELECT UID command + memcpy(sel_uid_c2+2,receivedAnswer,5); + // Secondly compute the two CRC bytes at the end + AppendCrc14443a(sel_uid_c2,7); + + // Transmit SELECT_UID + ReaderTransmit(sel_uid_c2,sizeof(sel_uid_c2)); + + // Receive the SAK + if (!ReaderReceive(receivedAnswer)) continue; } - // Store answer in buffer - rsamples = rsamples + (samples - Demod.samples); - trace[traceLen++] = ((rsamples >> 0) & 0xff); - trace[traceLen++] = ((rsamples >> 8) & 0xff); - trace[traceLen++] = ((rsamples >> 16) & 0xff); - trace[traceLen++] = 0x80 | ((rsamples >> 24) & 0xff); - trace[traceLen++] = ((Demod.parityBits >> 0) & 0xff); - trace[traceLen++] = ((Demod.parityBits >> 8) & 0xff); - trace[traceLen++] = ((Demod.parityBits >> 16) & 0xff); - trace[traceLen++] = ((Demod.parityBits >> 24) & 0xff); - trace[traceLen++] = Demod.len; - memcpy(trace+traceLen, receivedAnswer, Demod.len); - traceLen += Demod.len; - if(traceLen > TRACE_LENGTH) goto done; - ////////////////////////////////////////////////////////////////// - // Then Construct SELECT UID (cascasde 2) command - DbpString("Just about to copy the UID out of the cascade 2 id req"); - // First copy the 5 bytes (Mifare Classic) after the 95 70 - memcpy(cmd5+2,receivedAnswer,5); - // Secondly compute the two CRC bytes at the end - ComputeCrc14443(CRC_14443_A, cmd4, 7, &cmd5[7], &cmd5[8]); - // Prepare the bit sequence to modulate the subcarrier - // Store answer in buffer - trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; - trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; - trace[traceLen++] = 9; - memcpy(trace+traceLen, cmd5, 9); - traceLen += 9; - if(traceLen > TRACE_LENGTH) goto done; - CodeIso14443aAsReader(cmd5, sizeof(cmd5)); - memcpy(req5, ToSend, ToSendMax); req5Len = ToSendMax; - - // Select the card - TransmitFor14443a(req4, req4Len, &samples, &wait); - if(!GetIso14443aAnswerFromTag(receivedAnswer, 100, &samples, &elapsed)) { - continue; - } - - // Store answer in buffer - rsamples = rsamples + (samples - Demod.samples); - trace[traceLen++] = ((rsamples >> 0) & 0xff); - trace[traceLen++] = ((rsamples >> 8) & 0xff); - trace[traceLen++] = ((rsamples >> 16) & 0xff); - trace[traceLen++] = 0x80 | ((rsamples >> 24) & 0xff); - trace[traceLen++] = ((Demod.parityBits >> 0) & 0xff); - trace[traceLen++] = ((Demod.parityBits >> 8) & 0xff); - trace[traceLen++] = ((Demod.parityBits >> 16) & 0xff); - trace[traceLen++] = ((Demod.parityBits >> 24) & 0xff); - trace[traceLen++] = Demod.len; - memcpy(trace+traceLen, receivedAnswer, Demod.len); - traceLen += Demod.len; - if(traceLen > TRACE_LENGTH) goto done; + // Transmit MIFARE_CLASSIC_AUTH + ReaderTransmit(mf_auth,sizeof(mf_auth)); - - - - - } - - - - // Secondly compute the two CRC bytes at the end - ComputeCrc14443(CRC_14443_A, cmd5, 2, &cmd5[2], &cmd5[3]); - // Send authentication request (Mifare Classic) - TransmitFor14443a(req5, req5Len, &samples, &wait); - trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; - trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; - trace[traceLen++] = 4; - memcpy(trace+traceLen, cmd5, 4); - traceLen += 4; - if(traceLen > TRACE_LENGTH) goto done; - if(GetIso14443aAnswerFromTag(receivedAnswer, 100, &samples, &elapsed)) { - rsamples++; - // We received probably a random, continue and trace! - } - else { - // Received nothing - continue; - } - - // Trace the random, i'm curious - rsamples = rsamples + (samples - Demod.samples); - trace[traceLen++] = ((rsamples >> 0) & 0xff); - trace[traceLen++] = ((rsamples >> 8) & 0xff); - trace[traceLen++] = ((rsamples >> 16) & 0xff); - trace[traceLen++] = 0x80 | ((rsamples >> 24) & 0xff); - trace[traceLen++] = ((Demod.parityBits >> 0) & 0xff); - trace[traceLen++] = ((Demod.parityBits >> 8) & 0xff); - trace[traceLen++] = ((Demod.parityBits >> 16) & 0xff); - trace[traceLen++] = ((Demod.parityBits >> 24) & 0xff); - trace[traceLen++] = Demod.len; - memcpy(trace+traceLen, receivedAnswer, Demod.len); - traceLen += Demod.len; - if(traceLen > TRACE_LENGTH) goto done; - - // Thats it... + // Receive the (16 bit) "random" nonce + if (!ReaderReceive(receivedAnswer)) continue; } -done: - LED_A_OFF(); + // Thats it... + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + Dbprintf("%x %x %x", rsamples, 0xCC, 0xCC); + DbpString("ready.."); +} + +//----------------------------------------------------------------------------- +// Read an ISO 14443a tag. Send out commands and store answers. +// +//----------------------------------------------------------------------------- +void ReaderMifare(DWORD parameter) +{ + + // Anticollision + BYTE wupa[] = { 0x52 }; + BYTE sel_all[] = { 0x93,0x20 }; + BYTE sel_uid[] = { 0x93,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; + + // Mifare AUTH + BYTE mf_auth[] = { 0x60,0x00,0xf5,0x7b }; + BYTE mf_nr_ar[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; + + BYTE* receivedAnswer = (((BYTE *)BigBuf) + 3560); // was 3560 - tied to other size changes + traceLen = 0; + tracing = false; + + // Setup SSC + FpgaSetupSsc(); + + // Start from off (no field generated) + // Signal field is off with the appropriate LED + LED_D_OFF(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(200); + + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + FpgaSetupSsc(); + + // Now give it time to spin up. + // Signal field is on with the appropriate LED + LED_D_ON(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); + SpinDelay(200); + + LED_A_ON(); LED_B_OFF(); LED_C_OFF(); - LED_D_OFF(); - DbpIntegers(rsamples, 0xCC, 0xCC); - DbpString("ready.."); + + // Broadcast for a card, WUPA (0x52) will force response from all cards in the field + ReaderTransmitShort(wupa); + // Receive the ATQA + ReaderReceive(receivedAnswer); + // Transmit SELECT_ALL + ReaderTransmit(sel_all,sizeof(sel_all)); + // Receive the UID + ReaderReceive(receivedAnswer); + // Construct SELECT UID command + // First copy the 5 bytes (Mifare Classic) after the 93 70 + memcpy(sel_uid+2,receivedAnswer,5); + // Secondly compute the two CRC bytes at the end + AppendCrc14443a(sel_uid,7); + + byte_t nt_diff = 0; + LED_A_OFF(); + byte_t par = 0; + byte_t par_mask = 0xff; + byte_t par_low = 0; + BOOL led_on = TRUE; + + tracing = FALSE; + byte_t nt[4]; + byte_t nt_attacked[4]; + byte_t par_list[8]; + byte_t ks_list[8]; + num_to_bytes(parameter,4,nt_attacked); + + while(TRUE) + { + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(200); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); + + // Broadcast for a card, WUPA (0x52) will force response from all cards in the field + ReaderTransmitShort(wupa); + + // Test if the action was cancelled + if(BUTTON_PRESS()) { + break; + } + + // Receive the ATQA + if (!ReaderReceive(receivedAnswer)) continue; + + // Transmit SELECT_ALL + ReaderTransmit(sel_all,sizeof(sel_all)); + + // Receive the UID + if (!ReaderReceive(receivedAnswer)) continue; + + // Transmit SELECT_UID + ReaderTransmit(sel_uid,sizeof(sel_uid)); + + // Receive the SAK + if (!ReaderReceive(receivedAnswer)) continue; + + // Transmit MIFARE_CLASSIC_AUTH + ReaderTransmit(mf_auth,sizeof(mf_auth)); + + // Receive the (16 bit) "random" nonce + if (!ReaderReceive(receivedAnswer)) continue; + memcpy(nt,receivedAnswer,4); + + // Transmit reader nonce and reader answer + ReaderTransmitPar(mf_nr_ar,sizeof(mf_nr_ar),par); + + // Receive 4 bit answer + if (ReaderReceive(receivedAnswer)) + { + if (nt_diff == 0) + { + LED_A_ON(); + memcpy(nt_attacked,nt,4); + par_mask = 0xf8; + par_low = par & 0x07; + } + + if (memcmp(nt,nt_attacked,4) != 0) continue; + + led_on = !led_on; + if(led_on) LED_B_ON(); else LED_B_OFF(); + par_list[nt_diff] = par; + ks_list[nt_diff] = receivedAnswer[0]^0x05; + + // Test if the information is complete + if (nt_diff == 0x07) break; + + nt_diff = (nt_diff+1) & 0x07; + mf_nr_ar[3] = nt_diff << 5; + par = par_low; + } else { + if (nt_diff == 0) + { + par++; + } else { + par = (((par>>3)+1) << 3) | par_low; + } + } + } + + LogTraceInfo(sel_uid+2,4); + LogTraceInfo(nt,4); + LogTraceInfo(par_list,8); + LogTraceInfo(ks_list,8); + + // Thats it... + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + tracing = TRUE; }