next version of half duplex simulation

This commit is contained in:
tharexde 2021-01-05 01:12:21 +01:00
commit 560be30053

View file

@ -57,12 +57,17 @@
int gHigh = 190; int gHigh = 190;
int gLow = 60; int gLow = 60;
// a global parameter is needed to indicate whether a previous login was
// successful, so operations that require authentication may be performed
bool gLogin = 0;
int gcount = 0; int gcount = 0;
int gcycles = 0; int gcycles = 0;
int rm = 0; int rm = 0;
static bool em4x50_sim_send_listen_window(void); static bool em4x50_sim_send_listen_window(uint32_t *tag);
static void em4x50_sim_handle_command(uint8_t command); static void em4x50_sim_handle_command(uint8_t command, uint32_t *tag);
void catch_samples(void); void catch_samples(void);
@ -170,22 +175,19 @@ static void em4x50_setup_read(void) {
// Enable Peripheral Clock for // Enable Peripheral Clock for
// TIMER_CLOCK0, used to measure exact timing before answering // TIMER_CLOCK0, used to measure exact timing before answering
AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1); AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0);// | (1 << AT91C_ID_TC1);
AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME;
// Disable timer during configuration // Disable timer during configuration
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
// TC0: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers // TC0: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers
AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK;
AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK;
// TC1: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers // TC1: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers
// Enable and reset counters // Enable and reset counters
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
// synchronized startup procedure // synchronized startup procedure
while (AT91C_BASE_TC0->TC_CV > 0) {}; // wait until TC1 returned to zero while (AT91C_BASE_TC0->TC_CV > 0) {}; // wait until TC1 returned to zero
@ -289,13 +291,11 @@ static bool invalid_bit(void) {
// get sample at 3/4 of bit period // get sample at 3/4 of bit period
wait_timer(T0 * EM4X50_T_TAG_THREE_QUARTER_PERIOD); wait_timer(T0 * EM4X50_T_TAG_THREE_QUARTER_PERIOD);
//wait_timer(T0 * EM4X50_T_TAG_HALF_PERIOD);
uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
// wait until end of bit period // wait until end of bit period
wait_timer(T0 * EM4X50_T_TAG_QUARTER_PERIOD); wait_timer(T0 * EM4X50_T_TAG_QUARTER_PERIOD);
//wait_timer(T0 * EM4X50_T_TAG_HALF_PERIOD);
// bit in "undefined" state? // bit in "undefined" state?
if (sample <= gHigh && sample >= gLow) if (sample <= gHigh && sample >= gLow)
@ -522,18 +522,14 @@ static int request_receive_mode(void) {
// If <bliw> is true then within the single listen window right after the // If <bliw> is true then within the single listen window right after the
// ack signal a RM request has to be sent. // ack signal a RM request has to be sent.
static bool check_ack(bool bliw) { static bool check_ack(bool bliw) {
int cnt_pulses = 0; int count_cycles = 0;
while (count_cycles < EM4X50_T_WAITING_FOR_ACK) {
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
//while (cnt_pulses < EM4X50_T_WAITING_FOR_ACK) {
while (AT91C_BASE_TC0->TC_CV < T0 * 4 * EM4X50_T_TAG_FULL_PERIOD) {
if (BUTTON_PRESS()) if (BUTTON_PRESS())
return false; return false;
if (check_pulse_length(get_pulse_length(), 2 * EM4X50_T_TAG_FULL_PERIOD)) { if (check_pulse_length(get_pulse_length(), 2 * EM4X50_T_TAG_FULL_PERIOD)) {
catch_samples(); //catch_samples();
// The received signal is either ACK or NAK. // The received signal is either ACK or NAK.
@ -570,7 +566,7 @@ static bool check_ack(bool bliw) {
break; break;
} }
} }
cnt_pulses++; count_cycles++;
} }
return false; return false;
@ -919,6 +915,8 @@ static void em4x50_sim_send_nak(void) {
SHORT_COIL(); SHORT_COIL();
wait_cycles(EM4X50_T_TAG_HALF_PERIOD); wait_cycles(EM4X50_T_TAG_HALF_PERIOD);
OPEN_COIL();
} }
/* /*
@ -969,68 +967,57 @@ static bool em4x50_sim_send_listen_window(void) {
} }
*/ */
static void em4x50_sim_handle_login_command(void) { static void em4x50_sim_handle_login_command(uint32_t *tag) {
//uint8_t *em4x50_mem = BigBuf_get_EM_addr();
uint32_t password = 0; uint32_t password = 0;
//uint32_t tag[EM4X50_NO_WORDS] = {0x0};
// read password // read password
password = em4x50_sim_read_word(); password = em4x50_sim_read_word();
//for (int i = 0; i < EM4X50_NO_WORDS; i++)
// tag[i] = reflect32(bytes_to_num(em4x50_mem + (i * 4), 4));
// processing pause time (corresponds to a "1" bit) // processing pause time (corresponds to a "1" bit)
em4x50_sim_send_bit(1); em4x50_sim_send_bit(1);
em4x50_sim_send_ack(); // empirically determined delay (to be examined seperately)
wait_cycles(1);
/*
if (password == tag[0]) { if (password == tag[0]) {
em4x50_sim_send_ack(); em4x50_sim_send_ack();
gLogin = true;
} else { } else {
em4x50_sim_send_ack(); em4x50_sim_send_nak();
gLogin = false;
} }
*/
// continue with standard read mode // continue with standard read mode
em4x50_sim_handle_command(0); em4x50_sim_handle_command(0, tag);
Dbprintf("password = %08x", password);
BigBuf_free();
} }
static void em4x50_sim_handle_reset_command(void) { static void em4x50_sim_handle_reset_command(uint32_t *tag) {
// processing pause time (corresponds to a "1" bit) // processing pause time (corresponds to a "1" bit)
em4x50_sim_send_bit(1); em4x50_sim_send_bit(1);
// send ACK // send ACK
em4x50_sim_send_ack(); em4x50_sim_send_ack();
gLogin = false;
// wait for tinit // wait for tinit
wait_timer(T0 * EM4X50_T_TAG_TINIT); wait_cycles(EM4X50_T_TAG_TINIT);
// continue with standard read mode // continue with standard read mode
em4x50_sim_handle_command(0); em4x50_sim_handle_command(0, tag);
} }
static void em4x50_sim_handle_write_command(void) { static void em4x50_sim_handle_write_command(uint32_t *tag) {
uint8_t *em4x50_mem = BigBuf_get_EM_addr();
uint8_t address = 0; uint8_t address = 0;
uint32_t data = 0; uint32_t data = 0;
uint32_t tag[EM4X50_NO_WORDS] = {0x0};
// read address // read address
address = em4x50_sim_read_byte_with_parity_check(); address = em4x50_sim_read_byte_with_parity_check();
// read data // read data
data = em4x50_sim_read_word(); data = em4x50_sim_read_word();
for (int i = 0; i < EM4X50_NO_WORDS; i++) {
tag[i] = reflect32(bytes_to_num(em4x50_mem + (i * 4), 4));
}
// extract necessary control data // extract necessary control data
bool raw = (tag[EM4X50_CONTROL] >> CONFIG_BLOCK) & READ_AFTER_WRITE; bool raw = (tag[EM4X50_CONTROL] >> CONFIG_BLOCK) & READ_AFTER_WRITE;
// extract protection data // extract protection data
@ -1041,7 +1028,7 @@ static void em4x50_sim_handle_write_command(void) {
tag[address] = data; tag[address] = data;
// write access time // write access time
wait_timer(T0 * EM4X50_T_TAG_TWA); wait_cycles(EM4X50_T_TAG_TWA);
if ((address >= fwrp) && (address <= lwrp)) { if ((address >= fwrp) && (address <= lwrp)) {
em4x50_sim_send_nak(); em4x50_sim_send_nak();
@ -1055,28 +1042,24 @@ static void em4x50_sim_handle_write_command(void) {
} }
// EEPROM write time // EEPROM write time
//wait_timer(T0 * EM4X50_T_TAG_TWEE); wait_cycles(EM4X50_T_TAG_TWEE);
em4x50_sim_send_ack(); em4x50_sim_send_ack();
// if "read after write" (raw) bit is set, repeat written data once // if "read after write" (raw) bit is set, repeat written data once
if (raw) { if (raw) {
em4x50_sim_send_listen_window(); em4x50_sim_send_listen_window(tag);
em4x50_sim_send_listen_window(); em4x50_sim_send_listen_window(tag);
em4x50_sim_send_word(tag[address]); em4x50_sim_send_word(tag[address]);
} }
BigBuf_free();
// continue with standard read mode // continue with standard read mode
em4x50_sim_handle_command(0); em4x50_sim_handle_command(0, tag);
} }
static void em4x50_sim_handle_selective_read_command(void) { static void em4x50_sim_handle_selective_read_command(uint32_t *tag) {
uint8_t *em4x50_mem = BigBuf_get_EM_addr();
uint32_t address = 0; uint32_t address = 0;
uint32_t tag[EM4X50_NO_WORDS] = {0x0};
// read password // read password
address = em4x50_sim_read_word(); address = em4x50_sim_read_word();
@ -1085,10 +1068,6 @@ static void em4x50_sim_handle_selective_read_command(void) {
int fwr = address & 0xFF; // first word read int fwr = address & 0xFF; // first word read
int lwr = (address >> 8) & 0xFF; // last word read int lwr = (address >> 8) & 0xFF; // last word read
for (int i = 0; i < EM4X50_NO_WORDS; i++) {
tag[i] = reflect32(bytes_to_num(em4x50_mem + (i * 4), 4));
}
// extract protection data // extract protection data
int fwrp = tag[EM4X50_PROTECTION] & 0xFF; // first word read protected int fwrp = tag[EM4X50_PROTECTION] & 0xFF; // first word read protected
int lwrp = (tag[EM4X50_PROTECTION] >> 8) & 0xFF; // last word read protected int lwrp = (tag[EM4X50_PROTECTION] >> 8) & 0xFF; // last word read protected
@ -1098,34 +1077,27 @@ static void em4x50_sim_handle_selective_read_command(void) {
em4x50_sim_send_ack(); em4x50_sim_send_ack();
// iceman, will need a usb cmd check to break as well
while (BUTTON_PRESS() == false) { while (BUTTON_PRESS() == false) {
WDT_HIT(); WDT_HIT();
em4x50_sim_send_listen_window(); em4x50_sim_send_listen_window(tag);
for (int i = fwr; i <= lwr; i++) { for (int i = fwr; i <= lwr; i++) {
em4x50_sim_send_listen_window(); em4x50_sim_send_listen_window(tag);
if ((i >= fwrp) && (i <= lwrp)) { // if not authenticated do not send read protected words
if ((gLogin == false) && (i >= fwrp) && (i <= lwrp)) {
em4x50_sim_send_word(0x00); em4x50_sim_send_word(0x00);
} else { } else {
em4x50_sim_send_word(tag[i]); em4x50_sim_send_word(tag[i]);
} }
} }
} }
BigBuf_free();
} }
static void em4x50_sim_handle_standard_read_command(void) { static void em4x50_sim_handle_standard_read_command(uint32_t *tag) {
uint8_t *em4x50_mem = BigBuf_get_EM_addr();
uint32_t tag[EM4X50_NO_WORDS] = {0x0};
for (int i = 0; i < EM4X50_NO_WORDS; i++) {
tag[i] = reflect32(bytes_to_num(em4x50_mem + (i * 4), 4));
}
// extract control data // extract control data
int fwr = tag[CONFIG_BLOCK] & 0xFF; // first word read int fwr = tag[CONFIG_BLOCK] & 0xFF; // first word read
int lwr = (tag[CONFIG_BLOCK] >> 8) & 0xFF; // last word read int lwr = (tag[CONFIG_BLOCK] >> 8) & 0xFF; // last word read
@ -1133,13 +1105,14 @@ static void em4x50_sim_handle_standard_read_command(void) {
int fwrp = tag[EM4X50_PROTECTION] & 0xFF; // first word read protected int fwrp = tag[EM4X50_PROTECTION] & 0xFF; // first word read protected
int lwrp = (tag[EM4X50_PROTECTION] >> 8) & 0xFF; // last word read protected int lwrp = (tag[EM4X50_PROTECTION] >> 8) & 0xFF; // last word read protected
// iceman, will need a usb cmd check to break as well
while (BUTTON_PRESS() == false) { while (BUTTON_PRESS() == false) {
WDT_HIT(); WDT_HIT();
em4x50_sim_send_listen_window(); em4x50_sim_send_listen_window(tag);
for (int i = fwr; i <= lwr; i++) { for (int i = fwr; i <= lwr; i++) {
em4x50_sim_send_listen_window(); em4x50_sim_send_listen_window(tag);
if ((i >= fwrp) && (i <= lwrp)) { if ((i >= fwrp) && (i <= lwrp)) {
em4x50_sim_send_word(0x00); em4x50_sim_send_word(0x00);
@ -1148,23 +1121,22 @@ static void em4x50_sim_handle_standard_read_command(void) {
} }
} }
} }
BigBuf_free();
} }
static void em4x50_sim_handle_command(uint8_t command) { static void em4x50_sim_handle_command(uint8_t command, uint32_t *tag) {
switch (command) { switch (command) {
case EM4X50_COMMAND_LOGIN: case EM4X50_COMMAND_LOGIN:
em4x50_sim_handle_login_command(); em4x50_sim_handle_login_command(tag);
break; break;
case EM4X50_COMMAND_RESET: case EM4X50_COMMAND_RESET:
em4x50_sim_handle_reset_command(); em4x50_sim_handle_reset_command(tag);
break; break;
case EM4X50_COMMAND_WRITE: case EM4X50_COMMAND_WRITE:
em4x50_sim_handle_write_command(); em4x50_sim_handle_write_command(tag);
break; break;
case EM4X50_COMMAND_WRITE_PASSWORD: case EM4X50_COMMAND_WRITE_PASSWORD:
@ -1172,17 +1144,17 @@ static void em4x50_sim_handle_command(uint8_t command) {
break; break;
case EM4X50_COMMAND_SELECTIVE_READ: case EM4X50_COMMAND_SELECTIVE_READ:
em4x50_sim_handle_selective_read_command(); em4x50_sim_handle_selective_read_command(tag);
break; break;
default: default:
em4x50_sim_handle_standard_read_command(); em4x50_sim_handle_standard_read_command(tag);
break; break;
} }
} }
// reader requests receive mode (rm) by sending two zeros // reader requests receive mode (rm) by sending two zeros
static void check_rm_request(void) { static void check_rm_request(uint32_t *tag) {
int cond = EM4X50_T_TAG_FULL_PERIOD - EM4X50_TAG_TOLERANCE; int cond = EM4X50_T_TAG_FULL_PERIOD - EM4X50_TAG_TOLERANCE;
@ -1194,12 +1166,12 @@ static void check_rm_request(void) {
// read mode request detected, get command from reader // read mode request detected, get command from reader
uint8_t command = em4x50_sim_read_byte_with_parity_check(); uint8_t command = em4x50_sim_read_byte_with_parity_check();
em4x50_sim_handle_command(command); em4x50_sim_handle_command(command, tag);
} }
} }
} }
static bool em4x50_sim_send_listen_window(void) { static bool em4x50_sim_send_listen_window(uint32_t *tag) {
SHORT_COIL(); SHORT_COIL();
wait_cycles(EM4X50_T_TAG_HALF_PERIOD); wait_cycles(EM4X50_T_TAG_HALF_PERIOD);
@ -1211,7 +1183,7 @@ static bool em4x50_sim_send_listen_window(void) {
wait_cycles(2 * EM4X50_T_TAG_FULL_PERIOD); wait_cycles(2 * EM4X50_T_TAG_FULL_PERIOD);
OPEN_COIL(); OPEN_COIL();
check_rm_request(); check_rm_request(tag);
SHORT_COIL(); SHORT_COIL();
wait_cycles(EM4X50_T_TAG_FULL_PERIOD); wait_cycles(EM4X50_T_TAG_FULL_PERIOD);
@ -1230,7 +1202,7 @@ static bool login(uint32_t password) {
// send password // send password
em4x50_reader_send_word(password); em4x50_reader_send_word(password);
wait_timer(T0 * EM4X50_T_TAG_TPP); wait_timer(T0 * (EM4X50_T_TAG_TPP));
// check if ACK is returned // check if ACK is returned
if (check_ack(false)) { if (check_ack(false)) {
@ -1377,7 +1349,7 @@ static int reset(void) {
// send reset command // send reset command
em4x50_reader_send_byte_with_parity(EM4X50_COMMAND_RESET); em4x50_reader_send_byte_with_parity(EM4X50_COMMAND_RESET);
if (check_ack(false)) if (check_ack(false))
return PM3_SUCCESS; return PM3_SUCCESS;
@ -1674,60 +1646,36 @@ void em4x50_writepwd(em4x50_data_t *etd) {
} }
// simulate uploaded data in emulator memory // simulate uploaded data in emulator memory
// (currently simulation allows only a one-way communication)
void em4x50_sim() { void em4x50_sim() {
int status = PM3_SUCCESS; int status = PM3_SUCCESS;
uint8_t *em4x50_mem = BigBuf_get_EM_addr(); uint8_t *em4x50_mem = BigBuf_get_EM_addr();
uint32_t words[EM4X50_NO_WORDS] = {0x0}; uint32_t tag[EM4X50_NO_WORDS] = {0x0};
for (int i = 0; i < EM4X50_NO_WORDS; i++) for (int i = 0; i < EM4X50_NO_WORDS; i++)
words[i] = reflect32(bytes_to_num(em4x50_mem + (i * 4), 4)); tag[i] = reflect32(bytes_to_num(em4x50_mem + (i * 4), 4));
// only if valid em4x50 data (e.g. uid == serial) // only if valid em4x50 data (e.g. uid == serial)
if (words[EM4X50_DEVICE_SERIAL] != words[EM4X50_DEVICE_ID]) { if (tag[EM4X50_DEVICE_SERIAL] != tag[EM4X50_DEVICE_ID]) {
// init
em4x50_setup_sim(); em4x50_setup_sim();
gLogin = false;
em4x50_sim_handle_command(0); // start with inital command = standard read mode (= 0)
em4x50_sim_handle_command(0, tag);
/*
// extract control data
int fwr = words[CONFIG_BLOCK] & 0xFF; // first word read
int lwr = (words[CONFIG_BLOCK] >> 8) & 0xFF; // last word read
// extract protection data
int fwrp = words[EM4X50_PROTECTION] & 0xFF; // first word read protected
int lwrp = (words[EM4X50_PROTECTION] >> 8) & 0xFF; // last word read protected
// iceman, will need a usb cmd check to break as well
while (BUTTON_PRESS() == false) {
rm = 0;
WDT_HIT();
em4x50_sim_send_listen_window();
for (int i = fwr; i <= lwr; i++) {
em4x50_sim_send_listen_window();
if ((i >= fwrp) && (i <= lwrp))
em4x50_sim_send_word(0x00);
else
em4x50_sim_send_word(words[i]);
}
}
*/
} else { } else {
status = PM3_ENODATA; status = PM3_ENODATA;
} }
BigBuf_free(); BigBuf_free();
lf_finalize(); lf_finalize();
reply_ng(CMD_LF_EM4X50_SIM, status, NULL, 0); reply_ng(CMD_LF_EM4X50_SIM, status, NULL, 0);
} }
void em4x50_test(em4x50_test_t *ett) { void em4x50_test(em4x50_test_t *ett) {
int status = PM3_EFAILED; int status = 0;
// set field on or off // set field on or off
if (ett->field != -1) { if (ett->field != -1) {
@ -1791,25 +1739,21 @@ void em4x50_test(em4x50_test_t *ett) {
} }
} }
em4x50_setup_sim(); // perform reset
for (;;) { if (ett->reset) {
em4x50_sim_send_listen_window(); em4x50_setup_read();
em4x50_sim_send_listen_window();
em4x50_sim_send_bit(0); status = PM3_EFAILED;
em4x50_sim_send_bit(0); if (get_signalproperties() && find_em4x50_tag()) {
em4x50_sim_send_bit(0);
em4x50_sim_send_ack(); if (reset() == PM3_SUCCESS) {
em4x50_sim_send_ack(); status = 1;
em4x50_sim_send_bit(0); }
em4x50_sim_send_bit(0); }
em4x50_sim_send_bit(0);
em4x50_sim_send_nak(); lf_finalize();
em4x50_sim_send_nak();
em4x50_sim_send_bit(0);
em4x50_sim_send_bit(0);
em4x50_sim_send_bit(0);
} }
reply_ng(CMD_LF_EM4X50_TEST, status, NULL, 0); reply_ng(CMD_LF_EM4X50_TEST, status, NULL, 0);
} }