From a66f26da182040ac798a7c629d255cb86803e9c2 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Tue, 10 Sep 2019 18:18:54 +0200 Subject: [PATCH] fix 'hf iclass sim': * add simulation of block 3 and 4 reads * add simulation of READ4 (4 blocks read) * fixing TransmitTo15693Reader() (again) * FPGA change (hi_simulate.v): avoid spp_clk phase changes * some whitespace fixes --- armsrc/iclass.c | 85 +++++++++++----- armsrc/iso15693.c | 242 ++++++++++++++++++++++----------------------- armsrc/iso15693.h | 2 +- fpga/fpga_hf.bit | Bin 42175 -> 42175 bytes fpga/hi_simulate.v | 54 +++++----- 5 files changed, 211 insertions(+), 172 deletions(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index daa44256..66238a10 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -860,6 +860,12 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { uint8_t *resp_cc = BigBuf_malloc(18); int resp_cc_len; + // Kd, Kc (blocks 3 and 4). Cannot be read. Always respond with 0xff bytes only + uint8_t *resp_ff = BigBuf_malloc(22); + int resp_ff_len; + uint8_t ff_data[10] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00}; + AppendCrc(ff_data, 8); + // Application Issuer Area (block 5) uint8_t *resp_aia = BigBuf_malloc(22); int resp_aia_len; @@ -897,14 +903,19 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { memcpy(resp_cc, ToSend, ToSendMax); resp_cc_len = ToSendMax; + // Kd, Kc (blocks 3 and 4) + CodeIso15693AsTag(ff_data, sizeof(ff_data)); + memcpy(resp_ff, ToSend, ToSendMax); + resp_ff_len = ToSendMax; + // Application Issuer Area (block 5) CodeIso15693AsTag(aia_data, sizeof(aia_data)); memcpy(resp_aia, ToSend, ToSendMax); resp_aia_len = ToSendMax; //This is used for responding to READ-block commands or other data which is dynamically generated - uint8_t *data_generic_trace = BigBuf_malloc(8 + 2); // 8 bytes data + 2byte CRC is max tag answer - uint8_t *data_response = BigBuf_malloc( (8 + 2) * 2 + 2); + uint8_t *data_generic_trace = BigBuf_malloc(32 + 2); // 32 bytes data + 2byte CRC is max tag answer + uint8_t *data_response = BigBuf_malloc( (32 + 2) * 2 + 2); LED_A_ON(); bool buttonPressed = false; @@ -921,7 +932,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { buttonPressed = true; break; } - + //Signal tracer LED_C_ON(); @@ -931,6 +942,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { modulated_response_size = 0; trace_data = NULL; trace_data_size = 0; + if (receivedCmd[0] == ICLASS_CMD_ACTALL) { // Reader in anticollission phase modulated_response = resp_sof; @@ -944,12 +956,11 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { modulated_response_size = resp_anticoll_len; trace_data = anticoll_data; trace_data_size = sizeof(anticoll_data); - //DbpString("Reader requests anticollission CSN:"); - + } else if (receivedCmd[0] == ICLASS_CMD_READ_OR_IDENTIFY && len == 4) { // read block uint16_t blockNo = receivedCmd[1]; - if (simulationMode != ICLASS_SIM_MODE_FULL) { - // provide defaults for blocks 0, 1, 2, 5 + if (simulationMode == ICLASS_SIM_MODE_EXIT_AFTER_MAC) { + // provide defaults for blocks 0 ... 5 switch (blockNo) { case 0: // csn (block 00) modulated_response = resp_csn; @@ -973,6 +984,13 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { memcpy(reader_mac_buf, card_challenge_data, 8); } break; + case 3: + case 4: // Kd, Kd, always respond with 0xff bytes + modulated_response = resp_ff; + modulated_response_size = resp_ff_len; + trace_data = ff_data; + trace_data_size = sizeof(ff_data); + break; case 5: // Application Issuer Area (block 05) modulated_response = resp_aia; modulated_response_size = resp_aia_len; @@ -981,15 +999,22 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { break; // default: don't respond } - } else { // use data from emulator memory - memcpy(data_generic_trace, emulator + (receivedCmd[1] << 3), 8); - AppendCrc(data_generic_trace, 8); - trace_data = data_generic_trace; - trace_data_size = 10; - CodeIso15693AsTag(trace_data, trace_data_size); - memcpy(data_response, ToSend, ToSendMax); - modulated_response = data_response; - modulated_response_size = ToSendMax; + } else if (simulationMode == ICLASS_SIM_MODE_FULL) { + if (blockNo == 3 || blockNo == 4) { // Kd, Kc, always respond with 0xff bytes + modulated_response = resp_ff; + modulated_response_size = resp_ff_len; + trace_data = ff_data; + trace_data_size = sizeof(ff_data); + } else { // use data from emulator memory + memcpy(data_generic_trace, emulator + (receivedCmd[1] << 3), 8); + AppendCrc(data_generic_trace, 8); + trace_data = data_generic_trace; + trace_data_size = 10; + CodeIso15693AsTag(trace_data, trace_data_size); + memcpy(data_response, ToSend, ToSendMax); + modulated_response = data_response; + modulated_response_size = ToSendMax; + } } } else if (receivedCmd[0] == ICLASS_CMD_SELECT) { @@ -1039,6 +1064,18 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { trace_data = NULL; trace_data_size = 0; + } else if (simulationMode == ICLASS_SIM_MODE_FULL && receivedCmd[0] == ICLASS_CMD_READ4 && len == 4) { // 0x06 + //Read block + //Take the data... + memcpy(data_generic_trace, emulator + (receivedCmd[1] << 3), 8 * 4); + AppendCrc(data_generic_trace, 8 * 4); + trace_data = data_generic_trace; + trace_data_size = 8 * 4 + 2; + CodeIso15693AsTag(trace_data, trace_data_size); + memcpy(data_response, ToSend, ToSendMax); + modulated_response = data_response; + modulated_response_size = ToSendMax; + } else if (receivedCmd[0] == ICLASS_CMD_UPDATE && simulationMode == ICLASS_SIM_MODE_FULL) { // Probably the reader wants to update the nonce. Let's just ignore that for now. // OBS! If this is implemented, don't forget to regenerate the cipher_state @@ -1072,7 +1109,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { } /** - A legit tag has about 330us delay between reader EOT and tag SOF. + A legit tag has about 311,5us delay between reader EOT and tag SOF. **/ if (modulated_response_size > 0) { uint32_t response_time = reader_eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM - DELAY_ARM_TO_READER_SIM; @@ -1112,7 +1149,7 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain // setup hardware for simulation: FpgaDownloadAndGo(FPGA_BITSTREAM_HF); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR); StartCountSspClk(); @@ -1150,8 +1187,8 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain datain[i*8+0], datain[i*8+1], datain[i*8+2], datain[i*8+3], datain[i*8+4], datain[i*8+5], datain[i*8+6], datain[i*8+7]); Dbprintf("NR,MAC: %02x %02x %02x %02x %02x %02x %02x %02x", - datain[i*8+ 8], datain[i*8+ 9], datain[i*8+10], datain[i*8+11], - datain[i*8+12], datain[i*8+13], datain[i*8+14], datain[i*8+15]); + datain[i*8+ 8], datain[i*8+ 9], datain[i*8+10], datain[i*8+11], + datain[i*8+12], datain[i*8+13], datain[i*8+14], datain[i*8+15]); } cmd_send(CMD_ACK, CMD_SIMULATE_TAG_ICLASS, i, 0, mac_responses, i*16); } else if (simType == ICLASS_SIM_MODE_FULL) { @@ -1319,10 +1356,10 @@ static int GetIClassAnswer(uint8_t *receivedResponse, int maxLen, int *samples, if (elapsed) (*elapsed)++; } if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - if (c < timeout) { - c++; - } else { - return false; + if (c < timeout) { + c++; + } else { + return false; } b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; skip = !skip; diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index 7fdf2a35..4b4577e7 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -2,7 +2,7 @@ // Jonathan Westhues, split Nov 2006 // Modified by Greg Jones, Jan 2009 // Modified by Adrian Dabrowski "atrox", Mar-Sept 2010,Oct 2011 -// Modified by piwi, Oct 2018 +// Modified by piwi, Oct 2018 // // 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 @@ -16,26 +16,26 @@ // transmission modes from tag to reader. As of Oct 2018 this code supports // both reader modes and the high speed 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. +// reader chooses both data rates, but some non-standard tags do not. // For card simulation, the code supports both high and low speed modes with one subcarrier. // // VCD (reader) -> VICC (tag) // 1 out of 256: -// data rate: 1,66 kbit/s (fc/8192) -// used for long range +// 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 +// 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) +// 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 +// low ASK: 6,62 kbit/s +// low FSK: 6.67 kbit/s +// high ASK: 26,48 kbit/s +// high FSK: 26,69 kbit/s //----------------------------------------------------------------------------- @@ -161,7 +161,7 @@ static void CodeIso15693AsReader(uint8_t *cmd, int n) for(i = 0; i < 4; i++) { ToSendStuffBit(1); } - + ToSendMax++; } @@ -338,20 +338,20 @@ void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t start_time, LED_C_ON(); uint8_t bits_to_shift = 0x00; uint8_t bits_to_send = 0x00; - for(size_t c = 0; c < len; c++) { + for(size_t c = 0; c < len; c++) { for (int i = 7; i >= 0; i--) { uint8_t cmd_bits = ((cmd[c] >> i) & 0x01) ? 0xff : 0x00; for (int j = 0; j < (slow?4:1); ) { - bits_to_send = bits_to_shift << (8 - shift_delay) | cmd_bits >> shift_delay; - bits_to_shift = cmd_bits; if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { + bits_to_send = bits_to_shift << (8 - shift_delay) | cmd_bits >> shift_delay; AT91C_BASE_SSC->SSC_THR = bits_to_send; + bits_to_shift = cmd_bits; j++; } } - } + } WDT_HIT(); - } + } // send the remaining bits, padded with 0: bits_to_send = bits_to_shift << (8 - shift_delay); for ( ; ; ) { @@ -408,7 +408,7 @@ typedef struct DecodeTag { static int inline __attribute__((always_inline)) Handle15693SamplesFromTag(uint16_t amplitude, DecodeTag_t *DecodeTag) { switch(DecodeTag->state) { - case STATE_TAG_SOF_LOW: + case STATE_TAG_SOF_LOW: // waiting for 12 times low (11 times low is accepted as well) if (amplitude < NOISE_THRESHOLD) { DecodeTag->posCount++; @@ -422,7 +422,7 @@ static int inline __attribute__((always_inline)) Handle15693SamplesFromTag(uint1 } } break; - + case STATE_TAG_SOF_HIGH: // waiting for 10 times high. Take average over the last 8 if (amplitude > NOISE_THRESHOLD) { @@ -592,7 +592,7 @@ static int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, int tim bool gotFrame = false; uint16_t *dmaBuf = (uint16_t*)BigBuf_malloc(ISO15693_DMA_BUFFER_SIZE*sizeof(uint16_t)); - + // the Decoder data structure DecodeTag_t DecodeTag = { 0 }; DecodeTagInit(&DecodeTag, response, max_len); @@ -643,9 +643,9 @@ static int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, int tim FpgaDisableSscDma(); BigBuf_free(); - + if (DEBUG) Dbprintf("samples = %d, gotFrame = %d, Decoder: state = %d, len = %d, bitCount = %d, posCount = %d", - samples, gotFrame, DecodeTag.state, DecodeTag.len, DecodeTag.bitCount, DecodeTag.posCount); + samples, gotFrame, DecodeTag.state, DecodeTag.len, DecodeTag.bitCount, DecodeTag.posCount); if (DecodeTag.len > 0) { LogTrace(DecodeTag.output, DecodeTag.len, 0, 0, NULL, false); @@ -687,7 +687,7 @@ typedef struct DecodeReader { int byteCount; int byteCountMax; int posCount; - int sum1, sum2; + int sum1, sum2; uint8_t *output; } DecodeReader_t; @@ -985,12 +985,12 @@ int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eo } FpgaDisableSscDma(); - + if (DEBUG) Dbprintf("samples = %d, gotFrame = %d, Decoder: state = %d, len = %d, bitCount = %d, posCount = %d", - samples, gotFrame, DecodeReader.state, DecodeReader.byteCount, DecodeReader.bitCount, DecodeReader.posCount); + samples, gotFrame, DecodeReader.state, DecodeReader.byteCount, DecodeReader.bitCount, DecodeReader.posCount); if (DecodeReader.byteCount > 0) { - uint32_t sof_time = *eof_time + uint32_t sof_time = *eof_time - DecodeReader.byteCount * (DecodeReader.Coding==CODING_1_OUT_OF_4?128:2048) // time for byte transfers - 32 // time for SOF transfer - 16; // time for EOF transfer @@ -1101,7 +1101,7 @@ void SnoopIso15693(void) Dbprintf(" DMA: %i bytes", ISO15693_DMA_BUFFER_SIZE * sizeof(uint16_t)); } Dbprintf("Snoop started. Press PM3 Button to stop."); - + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SNOOP_AMPLITUDE); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); @@ -1139,7 +1139,7 @@ void SnoopIso15693(void) } } samples++; - + if (!TagIsActive) { // no need to try decoding reader data if the tag is sending if (Handle15693SampleFromReader(snoopdata & 0x02, &DecodeReader)) { FpgaDisableSscDma(); @@ -1168,7 +1168,7 @@ void SnoopIso15693(void) ReaderIsActive = (DecodeReader.state >= STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF); } - if (!ReaderIsActive && ExpectTagAnswer) { // no need to try decoding tag data if the reader is currently sending or no answer expected yet + if (!ReaderIsActive && ExpectTagAnswer) { // no need to try decoding tag data if the reader is currently sending or no answer expected yet if (Handle15693SamplesFromTag(snoopdata >> 2, &DecodeTag)) { FpgaDisableSscDma(); //Use samples as a time measurement @@ -1187,7 +1187,7 @@ void SnoopIso15693(void) FpgaDisableSscDma(); BigBuf_free(); - + LEDsoff(); DbpString("Snoop statistics:"); @@ -1234,7 +1234,7 @@ static void BuildReadBlockRequest(uint8_t *uid, uint8_t blockNumber ) uint16_t crc; // If we set the Option_Flag in this request, the VICC will respond with the security status of the block // followed by the block data - cmd[0] = ISO15693_REQ_OPTION | ISO15693_REQ_ADDRESS | ISO15693_REQ_DATARATE_HIGH; + cmd[0] = ISO15693_REQ_OPTION | ISO15693_REQ_ADDRESS | ISO15693_REQ_DATARATE_HIGH; // READ BLOCK command code cmd[1] = ISO15693_READBLOCK; // UID may be optionally specified here @@ -1285,10 +1285,10 @@ static void BuildInventoryResponse(uint8_t *uid) } // 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 contain the tag's answer -// return: lenght of received data +// init ... should we initialize the reader? +// speed ... 0 low speed, 1 hi speed +// *recv will contain the tag's answer +// return: lenght of received data int SendDataTag(uint8_t *send, int sendlen, bool init, int speed, uint8_t *recv, uint16_t max_recv_len, uint32_t start_time) { LED_A_ON(); @@ -1405,7 +1405,7 @@ void ReaderIso15693(uint32_t parameter) LED_A_ON(); set_tracing(true); - + int answerLen = 0; uint8_t TagUID[8] = {0x00}; @@ -1418,8 +1418,8 @@ void ReaderIso15693(uint32_t parameter) FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); // Start from off (no field generated) - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(200); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(200); // Give the tags time to energize LED_D_ON(); @@ -1434,7 +1434,7 @@ void ReaderIso15693(uint32_t parameter) // Now send the IDENTIFY command BuildIdentifyRequest(); TransmitTo15693Tag(ToSend, ToSendMax, 0); - + // Now wait for a response answerLen = GetIso15693AnswerFromTag(answer, sizeof(answer), DELAY_ISO15693_VCD_TO_VICC_READER * 2) ; uint32_t start_time = GetCountSspClk() + DELAY_ISO15693_VICC_TO_VCD_READER; @@ -1489,7 +1489,7 @@ void ReaderIso15693(uint32_t parameter) // for the time being, switch field off to protect rdv4.0 // note: this prevents using hf 15 cmd with s option - which isn't implemented yet anyway - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LED_D_OFF(); LED_A_OFF(); @@ -1506,7 +1506,7 @@ void SimTagIso15693(uint32_t parameter, uint8_t *uid) FpgaDownloadAndGo(FPGA_BITSTREAM_HF); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR); StartCountSspClk(); @@ -1531,7 +1531,7 @@ void SimTagIso15693(uint32_t parameter, uint8_t *uid) Dbhexdump(cmd_len, cmd, false); } - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); } @@ -1545,12 +1545,12 @@ void BruteforceIso15693Afi(uint32_t speed) uint8_t data[6]; uint8_t recv[ISO15693_MAX_RESPONSE_LENGTH]; - + int datalen=0, recvlen=0; Iso15693InitReader(); StartCountSspClk(); - + // first without AFI // Tags should respond without AFI and with AFI=0 even when AFI is active @@ -1584,7 +1584,7 @@ void BruteforceIso15693Afi(uint32_t speed) } Dbprintf("AFI Bruteforcing done."); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); } @@ -1616,7 +1616,7 @@ void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint // for the time being, switch field off to protect rdv4.0 // note: this prevents using hf 15 cmd with s option - which isn't implemented yet anyway - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LED_D_OFF(); LED_A_OFF(); @@ -1630,76 +1630,76 @@ void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint // Set the UID to the tag (based on Iceman work). void SetTag15693Uid(uint8_t *uid) { - uint8_t cmd[4][9] = {0x00}; - - uint16_t crc; - - int recvlen = 0; - uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; - - LED_A_ON(); - - // Command 1 : 02213E00000000 - cmd[0][0] = 0x02; - cmd[0][1] = 0x21; - cmd[0][2] = 0x3e; - cmd[0][3] = 0x00; - cmd[0][4] = 0x00; - cmd[0][5] = 0x00; - cmd[0][6] = 0x00; - - // Command 2 : 02213F69960000 - cmd[1][0] = 0x02; - cmd[1][1] = 0x21; - cmd[1][2] = 0x3f; - cmd[1][3] = 0x69; - cmd[1][4] = 0x96; - cmd[1][5] = 0x00; - cmd[1][6] = 0x00; - - // Command 3 : 022138u8u7u6u5 (where uX = uid byte X) - cmd[2][0] = 0x02; - cmd[2][1] = 0x21; - cmd[2][2] = 0x38; - cmd[2][3] = uid[7]; - cmd[2][4] = uid[6]; - cmd[2][5] = uid[5]; - cmd[2][6] = uid[4]; - - // Command 4 : 022139u4u3u2u1 (where uX = uid byte X) - cmd[3][0] = 0x02; - cmd[3][1] = 0x21; - cmd[3][2] = 0x39; - cmd[3][3] = uid[3]; - cmd[3][4] = uid[2]; - cmd[3][5] = uid[1]; - cmd[3][6] = uid[0]; - - for (int i=0; i<4; i++) { - // Add the CRC - crc = Iso15693Crc(cmd[i], 7); - cmd[i][7] = crc & 0xff; - cmd[i][8] = crc >> 8; - - if (DEBUG) { - Dbprintf("SEND:"); - Dbhexdump(sizeof(cmd[i]), cmd[i], false); - } - - recvlen = SendDataTag(cmd[i], sizeof(cmd[i]), true, 1, recvbuf, sizeof(recvbuf), 0); - - if (DEBUG) { - Dbprintf("RECV:"); - Dbhexdump(recvlen, recvbuf, false); - DbdecodeIso15693Answer(recvlen, recvbuf); - } - - cmd_send(CMD_ACK, recvlen>ISO15693_MAX_RESPONSE_LENGTH?ISO15693_MAX_RESPONSE_LENGTH:recvlen, 0, 0, recvbuf, ISO15693_MAX_RESPONSE_LENGTH); - } - - LED_D_OFF(); - - LED_A_OFF(); + uint8_t cmd[4][9] = {0x00}; + + uint16_t crc; + + int recvlen = 0; + uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; + + LED_A_ON(); + + // Command 1 : 02213E00000000 + cmd[0][0] = 0x02; + cmd[0][1] = 0x21; + cmd[0][2] = 0x3e; + cmd[0][3] = 0x00; + cmd[0][4] = 0x00; + cmd[0][5] = 0x00; + cmd[0][6] = 0x00; + + // Command 2 : 02213F69960000 + cmd[1][0] = 0x02; + cmd[1][1] = 0x21; + cmd[1][2] = 0x3f; + cmd[1][3] = 0x69; + cmd[1][4] = 0x96; + cmd[1][5] = 0x00; + cmd[1][6] = 0x00; + + // Command 3 : 022138u8u7u6u5 (where uX = uid byte X) + cmd[2][0] = 0x02; + cmd[2][1] = 0x21; + cmd[2][2] = 0x38; + cmd[2][3] = uid[7]; + cmd[2][4] = uid[6]; + cmd[2][5] = uid[5]; + cmd[2][6] = uid[4]; + + // Command 4 : 022139u4u3u2u1 (where uX = uid byte X) + cmd[3][0] = 0x02; + cmd[3][1] = 0x21; + cmd[3][2] = 0x39; + cmd[3][3] = uid[3]; + cmd[3][4] = uid[2]; + cmd[3][5] = uid[1]; + cmd[3][6] = uid[0]; + + for (int i=0; i<4; i++) { + // Add the CRC + crc = Iso15693Crc(cmd[i], 7); + cmd[i][7] = crc & 0xff; + cmd[i][8] = crc >> 8; + + if (DEBUG) { + Dbprintf("SEND:"); + Dbhexdump(sizeof(cmd[i]), cmd[i], false); + } + + recvlen = SendDataTag(cmd[i], sizeof(cmd[i]), true, 1, recvbuf, sizeof(recvbuf), 0); + + if (DEBUG) { + Dbprintf("RECV:"); + Dbhexdump(recvlen, recvbuf, false); + DbdecodeIso15693Answer(recvlen, recvbuf); + } + + cmd_send(CMD_ACK, recvlen>ISO15693_MAX_RESPONSE_LENGTH?ISO15693_MAX_RESPONSE_LENGTH:recvlen, 0, 0, recvbuf, ISO15693_MAX_RESPONSE_LENGTH); + } + + LED_D_OFF(); + + LED_A_OFF(); } @@ -1801,8 +1801,8 @@ static void __attribute__((unused)) BuildArbitraryRequest(uint8_t *uid,uint8_t C cmd[10] = 0x00; cmd[11] = 0x0a; -// cmd[12] = 0x00; -// cmd[13] = 0x00; //Now the CRC +// cmd[12] = 0x00; +// cmd[13] = 0x00; //Now the CRC crc = Iso15693Crc(cmd, 12); // the crc needs to be calculated over 2 bytes cmd[12] = crc & 0xff; cmd[13] = crc >> 8; @@ -1836,8 +1836,8 @@ static void __attribute__((unused)) BuildArbitraryCustomRequest(uint8_t uid[], u cmd[10] = 0x05; // for custom codes this must be manufacturer code cmd[11] = 0x00; -// cmd[12] = 0x00; -// cmd[13] = 0x00; //Now the CRC +// cmd[12] = 0x00; +// cmd[13] = 0x00; //Now the CRC crc = Iso15693Crc(cmd, 12); // the crc needs to be calculated over 2 bytes cmd[12] = crc & 0xff; cmd[13] = crc >> 8; diff --git a/armsrc/iso15693.h b/armsrc/iso15693.h index f6cf29f1..7964d79e 100644 --- a/armsrc/iso15693.h +++ b/armsrc/iso15693.h @@ -18,7 +18,7 @@ // Delays in SSP_CLK ticks. // SSP_CLK runs at 13,56MHz / 32 = 423.75kHz when simulating a tag #define DELAY_READER_TO_ARM_SIM 8 -#define DELAY_ARM_TO_READER_SIM 1 +#define DELAY_ARM_TO_READER_SIM 0 #define DELAY_ISO15693_VCD_TO_VICC_SIM 132 // 132/423.75kHz = 311.5us from end of command EOF to start of tag response //SSP_CLK runs at 13.56MHz / 4 = 3,39MHz when acting as reader #define DELAY_ISO15693_VCD_TO_VICC_READER 1056 // 1056/3,39MHz = 311.5us from end of command EOF to start of tag response diff --git a/fpga/fpga_hf.bit b/fpga/fpga_hf.bit index 665f7bcbe9df8553e37ddf040bf7406f7b59798e..70c7909aeb328809bb41a63c389b1db42501aceb 100644 GIT binary patch literal 42175 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 OIriLoM!!1$Z~qrf_Yi^r literal 42175 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 diff --git a/fpga/hi_simulate.v b/fpga/hi_simulate.v index de58a74e..92ebcb51 100644 --- a/fpga/hi_simulate.v +++ b/fpga/hi_simulate.v @@ -47,46 +47,48 @@ end // Divide 13.56 MHz to produce various frequencies for SSP_CLK // and modulation. -reg [7:0] ssp_clk_divider; +reg [8:0] ssp_clk_divider; -always @(posedge adc_clk) +always @(negedge adc_clk) ssp_clk_divider <= (ssp_clk_divider + 1); reg ssp_clk; always @(negedge adc_clk) begin - if(mod_type == `FPGA_HF_SIMULATOR_MODULATE_424K_8BIT) + if (mod_type == `FPGA_HF_SIMULATOR_MODULATE_424K_8BIT) // Get bit every at 53KHz (every 8th carrier bit of 424kHz) - ssp_clk <= ssp_clk_divider[7]; - else if(mod_type == `FPGA_HF_SIMULATOR_MODULATE_212K) + ssp_clk <= ~ssp_clk_divider[7]; + else if (mod_type == `FPGA_HF_SIMULATOR_MODULATE_212K) // Get next bit at 212kHz - ssp_clk <= ssp_clk_divider[5]; + ssp_clk <= ~ssp_clk_divider[5]; else // Get next bit at 424Khz - ssp_clk <= ssp_clk_divider[4]; + ssp_clk <= ~ssp_clk_divider[4]; end -// Divide SSP_CLK by 8 to produce the byte framing signal; the phase of -// this is arbitrary, because it's just a bitstream. -// One nasty issue, though: I can't make it work with both rx and tx at -// once. The phase wrt ssp_clk must be changed. TODO to find out why -// that is and make a better fix. -reg [2:0] ssp_frame_divider_to_arm; -always @(posedge ssp_clk) - ssp_frame_divider_to_arm <= (ssp_frame_divider_to_arm + 1); -reg [2:0] ssp_frame_divider_from_arm; -always @(negedge ssp_clk) - ssp_frame_divider_from_arm <= (ssp_frame_divider_from_arm + 1); - - +// Produce the byte framing signal; the phase of this signal +// is arbitrary, because it's just a bit stream in this module. reg ssp_frame; -always @(ssp_frame_divider_to_arm or ssp_frame_divider_from_arm or mod_type) - if(mod_type == `FPGA_HF_SIMULATOR_NO_MODULATION) // not modulating, so listening, to ARM - ssp_frame = (ssp_frame_divider_to_arm == 3'b000); - else - ssp_frame = (ssp_frame_divider_from_arm == 3'b000); +always @(negedge adc_clk) +begin + if (mod_type == `FPGA_HF_SIMULATOR_MODULATE_212K) + begin + if (ssp_clk_divider[8:5] == 4'd1) + ssp_frame <= 1'b1; + if (ssp_clk_divider[8:5] == 4'd5) + ssp_frame <= 1'b0; + end + else + begin + if (ssp_clk_divider[7:4] == 4'd1) + ssp_frame <= 1'b1; + if (ssp_clk_divider[7:4] == 4'd5) + ssp_frame <= 1'b0; + end +end + // Synchronize up the after-hysteresis signal, to produce DIN. reg ssp_din; @@ -120,6 +122,6 @@ assign pwr_lo = 1'b0; assign pwr_oe2 = 1'b0; -assign dbg = ssp_din; +assign dbg = ssp_frame; endmodule -- 2.39.2