From 438cada2cf7729d5bed42f59a6a70d9b8d1d3efa Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 27 Dec 2020 22:22:44 +0100 Subject: [PATCH 01/22] commits after xcode crash --- armsrc/appmain.c | 4 +++ armsrc/em4x50.c | 67 +++++++++++++++++++++++++++++++++++++++- armsrc/em4x50.h | 1 + client/src/cmdlfem4x50.c | 39 +++++++++++++++++++++++ client/src/cmdlfem4x50.h | 1 + include/em4x50.h | 4 +++ include/pm3_cmd.h | 1 + 7 files changed, 116 insertions(+), 1 deletion(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index fe8566363..87b17afd9 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1163,6 +1163,10 @@ static void PacketReceived(PacketCommandNG *packet) { em4x50_chk((uint8_t *)packet->data.asBytes); break; } + case CMD_LF_EM4X50_TEST: { + em4x50_test((em4x50_test_t *)packet->data.asBytes); + break; + } #endif #ifdef WITH_EM4x70 diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 437afd956..a84a911c5 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -431,7 +431,6 @@ static int find_double_listen_window(bool bcommand) { // send RM for request mode em4x50_reader_send_bit(0); em4x50_reader_send_bit(0); - LED_B_OFF(); return PM3_SUCCESS; @@ -724,13 +723,27 @@ static bool em4x50_sim_send_word(uint32_t word) { static bool em4x50_sim_send_listen_window(void) { + bool cond = false; uint16_t check = 0; + uint32_t tval1[5 * EM4X50_T_TAG_FULL_PERIOD] = {0}; + uint32_t tval2[5 * EM4X50_T_TAG_FULL_PERIOD] = {0}; + + StartTicks(); for (int t = 0; t < 5 * EM4X50_T_TAG_FULL_PERIOD; t++) { + cond = ((t >= 3 * EM4X50_T_TAG_FULL_PERIOD) && (t < 4 * EM4X50_T_TAG_FULL_PERIOD)); + // wait until SSC_CLK goes HIGH + if (cond) { + AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + while (AT91C_BASE_TC0->TC_CV > 0); + } + while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) { WDT_HIT(); + if (check == 1000) { if (BUTTON_PRESS()) return false; @@ -738,6 +751,8 @@ static bool em4x50_sim_send_listen_window(void) { } ++check; } + if (cond) + tval1[t] = GetTicks(); if (t >= 4 * EM4X50_T_TAG_FULL_PERIOD) SHORT_COIL(); @@ -753,6 +768,12 @@ static bool em4x50_sim_send_listen_window(void) { check = 0; // wait until SSC_CLK goes LOW + if (cond) { + AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + while (AT91C_BASE_TC0->TC_CV > 0); + } + while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { WDT_HIT(); if (check == 1000) { @@ -762,8 +783,16 @@ static bool em4x50_sim_send_listen_window(void) { } ++check; } + if (cond) + tval2[t] = GetTicks(); } + for (int t = 0; t < 5 * EM4X50_T_TAG_FULL_PERIOD; t++) { + //if (tval[t] > 4) + Dbprintf("%3i probably RM intialization found: delta = %i %i", t, tval1[t], tval2[t]); + } + Dbprintf(""); + return true; } @@ -1281,3 +1310,39 @@ void em4x50_sim(uint8_t *filename) { lf_finalize(); reply_ng(CMD_LF_EM4X50_SIM, status, NULL, 0); } + +void em4x50_test(em4x50_test_t *ett) { + + int status = PM3_EFAILED; + + em4x50_setup_read(); + + if (ett->field) { + LOW(GPIO_SSC_DOUT); + LED_A_ON(); + + if (DBGLEVEL >= DBG_DEBUG) + Dbprintf("switched field on"); + + status = 1; + } else { + HIGH(GPIO_SSC_DOUT); + LED_A_OFF(); + + if (DBGLEVEL >= DBG_DEBUG) + Dbprintf("switched field off"); + + status = 0; + } + + while (BUTTON_PRESS() == false) { + + if (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { + Dbprintf("field on"); + } else if (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)){ + Dbprintf("field on"); + } + } + + reply_ng(CMD_LF_EM4X50_TEST, status, NULL, 0); +} diff --git a/armsrc/em4x50.h b/armsrc/em4x50.h index 9f9b38351..87451e198 100644 --- a/armsrc/em4x50.h +++ b/armsrc/em4x50.h @@ -22,5 +22,6 @@ void em4x50_login(uint32_t *password); void em4x50_sim(uint8_t *filename); void em4x50_reader(void); void em4x50_chk(uint8_t *filename); +void em4x50_test(em4x50_test_t *ett); #endif /* EM4X50_H */ diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 79b019a03..8182a822f 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -1158,6 +1158,43 @@ int CmdEM4x50Sim(const char *Cmd) { return resp.status; } +int CmdEM4x50Test(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x50 test", + "perform EM4x50 tests.", + "lf em 4x50 test --field 1 -> reader field on \n" + ); + + void *argtable[] = { + arg_param_begin, + arg_lit0("", "field", "field off/on"), + arg_param_end + }; + + CLIExecWithReturn(ctx, Cmd, argtable, true); + + em4x50_test_t ett; + ett.field = arg_get_lit(ctx, 1); + CLIParserFree(ctx); + + // start + clearCommandBuffer(); + PacketResponseNG resp; + SendCommandNG(CMD_LF_EM4X50_TEST, (uint8_t *)&ett, sizeof(ett)); + WaitForResponse(CMD_LF_EM4X50_TEST, &resp); + + // print response + if (resp.status == 1) { + PrintAndLogEx(SUCCESS, "Field switched " _GREEN_("on")); + } else if (resp.status == 0) { + PrintAndLogEx(SUCCESS, "Field switched " _GREEN_("off")); + } else { + PrintAndLogEx(FAILED, "Test call " _RED_("failed")); + } + + return resp.status; +} + static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"brute", CmdEM4x50Brute, IfPm3EM4x50, "guess password of EM4x50"}, @@ -1175,6 +1212,7 @@ static command_t CommandTable[] = { {"eload", CmdEM4x50ELoad, IfPm3EM4x50, "upload dump of EM4x50 to emulator memory"}, {"esave", CmdEM4x50ESave, IfPm3EM4x50, "save emulator memory to file"}, {"eview", CmdEM4x50EView, IfPm3EM4x50, "view EM4x50 content in emulator memory"}, + {"test", CmdEM4x50Test, IfPm3EM4x50, "perform EM4x50 tests"}, {NULL, NULL, NULL, NULL} }; @@ -1188,3 +1226,4 @@ int CmdLFEM4X50(const char *Cmd) { clearCommandBuffer(); return CmdsParse(CommandTable, Cmd); } + diff --git a/client/src/cmdlfem4x50.h b/client/src/cmdlfem4x50.h index 0d5c04bc6..df9c587de 100644 --- a/client/src/cmdlfem4x50.h +++ b/client/src/cmdlfem4x50.h @@ -34,5 +34,6 @@ int CmdEM4x50ELoad(const char *Cmd); int CmdEM4x50ESave(const char *Cmd); int CmdEM4x50Chk(const char *Cmd); int CmdEM4x50EView(const char *Cmd); +int CmdEM4x50Test(const char *Cmd); #endif diff --git a/include/em4x50.h b/include/em4x50.h index 573c58375..27d71e661 100644 --- a/include/em4x50.h +++ b/include/em4x50.h @@ -46,6 +46,10 @@ typedef struct { uint32_t addresses; } PACKED em4x50_data_t; +typedef struct { + bool field; +} PACKED em4x50_test_t; + typedef struct { uint8_t byte[4]; } PACKED em4x50_word_t; diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index e3dc29aee..022b602e3 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -516,6 +516,7 @@ typedef struct { #define CMD_LF_EM4X50_READER 0x0251 #define CMD_LF_EM4X50_ESET 0x0252 #define CMD_LF_EM4X50_CHK 0x0253 +#define CMD_LF_EM4X50_TEST 0x0254 #define CMD_LF_EM4X70_INFO 0x0260 #define CMD_LF_EM4X70_WRITE 0x0261 #define CMD_LF_EM4X70_UNLOCK 0x0262 From 9b3bc551368bf126e03f504d695518afbf188bca Mon Sep 17 00:00:00 2001 From: tharexde Date: Tue, 29 Dec 2020 17:40:18 +0100 Subject: [PATCH 02/22] aa --- armsrc/em4x50.c | 132 ++++++++++++++++++++++++--------------- client/src/cmdlfem4x50.c | 96 ++++++++++++++++++++++++++-- include/em4x50.h | 5 +- 3 files changed, 178 insertions(+), 55 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index a84a911c5..b03872bea 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -62,6 +62,26 @@ static void wait_timer(uint32_t period) { while (AT91C_BASE_TC0->TC_CV < period); } +static void catch_samples(void) { + + uint8_t sample = 0; + + if (EM4X50_MAX_NO_SAMPLES > CARD_MEMORY_SIZE) { + Dbprintf("exeeded emulator memory size"); + return; + } + + uint8_t *em4x50_sample_buffer = BigBuf_get_addr(); + + memcpy(em4x50_sample_buffer, &gHigh, 1); + memcpy(em4x50_sample_buffer + 1, &gLow, 1); + + for (int i = 2; i < EM4X50_MAX_NO_SAMPLES + 2; i++) { + sample = AT91C_BASE_SSC->SSC_RHR; + memcpy(em4x50_sample_buffer + i, &sample, 1); + wait_timer(T0); // 8µs delay + } +} // extract and check parities // return result of parity check and extracted plain data @@ -242,11 +262,13 @@ static bool invalid_bit(void) { // get sample at 3/4 of bit 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; // wait until end of bit period wait_timer(T0 * EM4X50_T_TAG_QUARTER_PERIOD); + //wait_timer(T0 * EM4X50_T_TAG_HALF_PERIOD); // bit in "undefined" state? if (sample <= gHigh && sample >= gLow) @@ -422,6 +444,8 @@ static int find_double_listen_window(bool bcommand) { // skip the next bit... wait_timer(T0 * EM4X50_T_TAG_FULL_PERIOD); + catch_samples(); + break; // ...and check if the following bit does make sense // (if not it is the correct position within the second @@ -723,24 +747,11 @@ static bool em4x50_sim_send_word(uint32_t word) { static bool em4x50_sim_send_listen_window(void) { - bool cond = false; uint16_t check = 0; - uint32_t tval1[5 * EM4X50_T_TAG_FULL_PERIOD] = {0}; - uint32_t tval2[5 * EM4X50_T_TAG_FULL_PERIOD] = {0}; - - StartTicks(); for (int t = 0; t < 5 * EM4X50_T_TAG_FULL_PERIOD; t++) { - cond = ((t >= 3 * EM4X50_T_TAG_FULL_PERIOD) && (t < 4 * EM4X50_T_TAG_FULL_PERIOD)); - // wait until SSC_CLK goes HIGH - if (cond) { - AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - while (AT91C_BASE_TC0->TC_CV > 0); - } - while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) { WDT_HIT(); @@ -751,8 +762,6 @@ static bool em4x50_sim_send_listen_window(void) { } ++check; } - if (cond) - tval1[t] = GetTicks(); if (t >= 4 * EM4X50_T_TAG_FULL_PERIOD) SHORT_COIL(); @@ -768,12 +777,6 @@ static bool em4x50_sim_send_listen_window(void) { check = 0; // wait until SSC_CLK goes LOW - if (cond) { - AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - while (AT91C_BASE_TC0->TC_CV > 0); - } - while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { WDT_HIT(); if (check == 1000) { @@ -783,15 +786,7 @@ static bool em4x50_sim_send_listen_window(void) { } ++check; } - if (cond) - tval2[t] = GetTicks(); } - - for (int t = 0; t < 5 * EM4X50_T_TAG_FULL_PERIOD; t++) { - //if (tval[t] > 4) - Dbprintf("%3i probably RM intialization found: delta = %i %i", t, tval1[t], tval2[t]); - } - Dbprintf(""); return true; } @@ -1315,33 +1310,72 @@ void em4x50_test(em4x50_test_t *ett) { int status = PM3_EFAILED; - em4x50_setup_read(); + // set field on or off + if (ett->field != -1) { + em4x50_setup_read(); + if (ett->field == 1) { + LED_A_ON(); + } else { + HIGH(GPIO_SSC_DOUT); + LED_A_OFF(); + } + status = ett->field; + } - if (ett->field) { - LOW(GPIO_SSC_DOUT); - LED_A_ON(); + // check field status + if (ett->check_field) { + em4x50_setup_sim(); + bool field_on = false; + while (BUTTON_PRESS() == false) { - if (DBGLEVEL >= DBG_DEBUG) - Dbprintf("switched field on"); - + if (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) { + if (field_on == false) { + Dbprintf("field on"); + field_on = true; + } + } else if (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK){ + if (field_on == true) { + Dbprintf("field off"); + field_on = false; + } + } + } status = 1; - } else { - HIGH(GPIO_SSC_DOUT); - LED_A_OFF(); - - if (DBGLEVEL >= DBG_DEBUG) - Dbprintf("switched field off"); - - status = 0; } - while (BUTTON_PRESS() == false) { + // timing values + if (ett->cycles != 0) { + uint32_t tval = 0; + uint32_t tvalhigh[ett->cycles]; + uint32_t tvallow[ett->cycles]; - if (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { - Dbprintf("field on"); - } else if (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)){ - Dbprintf("field on"); + em4x50_setup_sim(); + AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0); + AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; + AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + while (AT91C_BASE_TC0->TC_CV > 0); + + for (int t = 0; t < ett->cycles; t++) { + + // field on -> high value + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + tval = AT91C_BASE_TC0->TC_CV; + while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); + tvalhigh[t] = AT91C_BASE_TC0->TC_CV - tval; + + // filed off -> zero value + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + tval = AT91C_BASE_TC0->TC_CV; + while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); + tvallow[t] = AT91C_BASE_TC0->TC_CV - tval; } + + for (int t = 0; t < ett->cycles; t++) { + Dbprintf("%03i %li %li", t, tvallow[t], tvalhigh[t]); + } + } reply_ng(CMD_LF_EM4X50_TEST, status, NULL, 0); diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 8182a822f..a3da00bcc 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -23,6 +23,61 @@ static int CmdHelp(const char *Cmd); +static void write_gnuplot_config_file(int gHigh, int gLow) { + + const char *fn = "../data/data.gnu"; + FILE *fp = NULL; + + if ((fp = fopen(fn, "w+")) == false) { + PrintAndLogEx(WARNING, "Fail, open file %s", fn); + } + + fprintf(fp, "set term qt size 1400, 350 enhanced\n"); + fprintf(fp, "set border 31 front linecolor rgb 'dark-grey' linewidth 1.000 dashtype solid\n"); + fprintf(fp, "set xtics 0, 1 textcolor rgb 'dark-grey'\n"); + fprintf(fp, "set ytics 0, 64 textcolor rgb 'dark-grey'\n"); + fprintf(fp, "set title 'EM4x50 signal (amplitude vs time)'\n"); + fprintf(fp, "set title font ',14' textcolor rgb 'white'\n"); + fprintf(fp, "set xlabel 'time / ms'\n"); + fprintf(fp, "set xlabel font ',12' textcolor rgb 'dark-grey'\n"); + fprintf(fp, "set ylabel 'amplitude'\n"); + fprintf(fp, "set ylabel font ',12' textcolor rgb 'dark-grey'\n"); + fprintf(fp, "set key textcolor 'green'\n"); + fprintf(fp, "set grid\n"); + fprintf(fp, "#set time textcolor 'dark-grey'\n"); + fprintf(fp, "plot [0:][-50:300] '../data/data.dat' u ($1/1000):2 w l linecolor 'green' title '500/4', '../data/data.dat' u ($1/1000):3 w l linecolor 'yellow' title 'gHigh = %i', '../data/data.dat' u ($1/1000):4 w l linecolor 'yellow' title 'gLow = %i'\n", gHigh, gLow); + fprintf(fp, "pause -1\n"); + + fclose(fp); +} + +static void get_samples(void) { + + int gHigh = 0, gLow = 0; + const char *fn = "../data/data.dat"; + FILE *fp = NULL; + + // download from BigBuf memory + uint8_t data[EM4X50_MAX_NO_SAMPLES + 2] = {0x0}; + if (GetFromDevice(BIG_BUF, data, EM4X50_MAX_NO_SAMPLES + 2, 0, NULL, 0, NULL, 2500, false) == false) { + PrintAndLogEx(WARNING, "Fail, transfer from device time-out"); + } + + if ((fp = fopen(fn, "w+")) == false) { + PrintAndLogEx(WARNING, "Fail, open file %s", fn); + } + + gHigh = data[0]; + gLow = data[1]; + for (int i = 2; i < EM4X50_MAX_NO_SAMPLES + 2; i++) { + fprintf(fp, "%i %i %i %i\n", (i - 2) * 8, data[i], gHigh, gLow); + } + + fclose(fp); + + write_gnuplot_config_file(gHigh, gLow); +} + static void prepare_result(const uint8_t *data, int fwr, int lwr, em4x50_word_t *words) { // restructure received result in "em4x50_word_t" structure @@ -612,6 +667,8 @@ int CmdEM4x50Read(const char *Cmd) { } } + get_samples(); + return em4x50_read(&etd, NULL); } @@ -1162,19 +1219,43 @@ int CmdEM4x50Test(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50 test", "perform EM4x50 tests.", - "lf em 4x50 test --field 1 -> reader field on \n" + "lf em 4x50 test --field on -> reader field on\n" + "lf em 4x50 test --field off -> reader field off\n" + "lf em 4x50 test --check -> check on/off status of reader field\n" + "lf em 4x50 test --cycles 100 -> measure time of 100 field cycles\n" ); void *argtable[] = { arg_param_begin, - arg_lit0("", "field", "field off/on"), + arg_str0(NULL, "field", "on/off", "field on/off"), + arg_lit0(NULL, "check", "check if field is on or off"), + arg_int0(NULL, "cycles", "", "number of field cycles"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - em4x50_test_t ett; - ett.field = arg_get_lit(ctx, 1); + // option: field + int slen = 0; + char format[3] = {0}; + CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)format, sizeof(format), &slen); + em4x50_test_t ett = {.field = -1}; + if (slen != 0) { + if (strcmp(format, "on") == 0) { + ett.field = 1; + } else if (strcmp(format, "off") == 0) { + ett.field = 0; + } else { + PrintAndLogEx(INFO, "Unknown option for --field: %s", format); + return PM3_ESOFT; + } + } + + // option: check_field + ett.check_field = arg_get_lit(ctx, 2); + // option: cycles + ett.cycles = arg_get_int_def(ctx, 3, 0); + CLIParserFree(ctx); // start @@ -1185,9 +1266,14 @@ int CmdEM4x50Test(const char *Cmd) { // print response if (resp.status == 1) { - PrintAndLogEx(SUCCESS, "Field switched " _GREEN_("on")); + if (ett.field == 1) + PrintAndLogEx(SUCCESS, "Field switched " _GREEN_("on")); + if (ett.check_field == 1) + PrintAndLogEx(SUCCESS, "Field status evaluated"); } else if (resp.status == 0) { PrintAndLogEx(SUCCESS, "Field switched " _GREEN_("off")); + } else if (resp.status == -1) { + PrintAndLogEx(INFO, "Nothing done"); } else { PrintAndLogEx(FAILED, "Test call " _RED_("failed")); } diff --git a/include/em4x50.h b/include/em4x50.h index 27d71e661..3308a371f 100644 --- a/include/em4x50.h +++ b/include/em4x50.h @@ -36,6 +36,7 @@ // misc #define TIMEOUT 2000 #define DUMP_FILESIZE 136 +#define EM4X50_MAX_NO_SAMPLES 1000 typedef struct { bool addr_given; @@ -47,7 +48,9 @@ typedef struct { } PACKED em4x50_data_t; typedef struct { - bool field; + bool check_field; + int field; + int cycles; } PACKED em4x50_test_t; typedef struct { From eea63a6cb772be7a783f50c11e34d59f57c5481f Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 3 Jan 2021 22:50:27 +0100 Subject: [PATCH 03/22] first draft half duplex simulation --- armsrc/appmain.c | 2 +- armsrc/em4x50.c | 523 +++++++++++++++++++++++++++++++++++---- armsrc/em4x50.h | 2 +- client/src/cmdlfem4x50.c | 29 ++- client/src/cmdlfem4x70.h | 2 +- include/em4x50.h | 3 + 6 files changed, 511 insertions(+), 50 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 87b17afd9..6fba90e0e 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1136,7 +1136,7 @@ static void PacketReceived(PacketCommandNG *packet) { // destroy the Emulator Memory. //----------------------------------------------------------------------------- FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - em4x50_sim((uint8_t *)packet->data.asBytes); + em4x50_sim(); break; } case CMD_LF_EM4X50_READER: { diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index b03872bea..6c6091a8b 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -11,6 +11,7 @@ #include "fpgaloader.h" #include "ticks.h" #include "dbprint.h" +#include "lfsampling.h" #include "lfadc.h" #include "lfdemod.h" #include "commonutil.h" @@ -34,14 +35,15 @@ #define EM4X50_T_TAG_FULL_PERIOD 64 #define EM4X50_T_TAG_TPP 64 #define EM4X50_T_TAG_TWA 64 +#define EM4X50_T_TAG_TINIT 2112 +#define EM4X50_T_TAG_TWEE 3200 #define EM4X50_T_TAG_WAITING_FOR_SIGNAL 75 #define EM4X50_T_WAITING_FOR_DBLLIW 1550 -#define EM4X50_T_WAITING_FOR_SNGLLIW 140 // this value seems to be -// critical; -// if it's too low -// (e.g. < 120) some cards -// are no longer readable -// although they're ok +#define EM4X50_T_WAITING_FOR_ACK 4 + +// the following value seems to be critical; if it's too low (e.g. < 120) +// some cards are no longer readable although they're ok +#define EM4X50_T_WAITING_FOR_SNGLLIW 140 #define EM4X50_TAG_TOLERANCE 8 #define EM4X50_TAG_WORD 45 @@ -55,6 +57,14 @@ int gHigh = 190; int gLow = 60; +int gcount = 0; +int gcycles = 0; +int rm = 0; + +static bool em4x50_sim_send_listen_window(void); +static void em4x50_sim_handle_command(uint8_t command); + +void catch_samples(void); // do nothing for using timer0 static void wait_timer(uint32_t period) { @@ -62,7 +72,7 @@ static void wait_timer(uint32_t period) { while (AT91C_BASE_TC0->TC_CV < period); } -static void catch_samples(void) { +void catch_samples(void) { uint8_t sample = 0; @@ -160,19 +170,22 @@ static void em4x50_setup_read(void) { // Enable Peripheral Clock for // 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; // Disable timer during configuration 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 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 // Enable and reset counters 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 while (AT91C_BASE_TC0->TC_CV > 0) {}; // wait until TC1 returned to zero @@ -182,13 +195,27 @@ static void em4x50_setup_read(void) { } static void em4x50_setup_sim(void) { + StopTicks(); + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + + sample_config *sc = getSamplingConfig(); + sc->decimation = 1; + sc->averaging = 0; + sc->divisor = LF_DIVISOR_125; + + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, sc->divisor); FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125); AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT | GPIO_SSC_CLK; AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_CLK; + + AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0); + AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; + AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; } // calculate signal properties (mean amplitudes) from measured data: @@ -323,12 +350,12 @@ static void em4x50_reader_send_bit(int bit) { if (bit == 0) { - // disable modulation (drops the field) for 7 cycles of carrier + // disable modulation (activate the field) for 7 cycles of carrier // period (Opt64) LOW(GPIO_SSC_DOUT); while (AT91C_BASE_TC0->TC_CV < T0 * 7); - // enable modulation (activates the field) for remaining first + // enable modulation (drop the field) for remaining first // half of bit period HIGH(GPIO_SSC_DOUT); while (AT91C_BASE_TC0->TC_CV < T0 * EM4X50_T_TAG_HALF_PERIOD); @@ -432,9 +459,7 @@ static int find_double_listen_window(bool bcommand) { // first listen window found if (bcommand) { - -// SpinDelay(10); - + // data transmission from card has to be stopped, because // a commamd shall be issued @@ -444,8 +469,6 @@ static int find_double_listen_window(bool bcommand) { // skip the next bit... wait_timer(T0 * EM4X50_T_TAG_FULL_PERIOD); - catch_samples(); - break; // ...and check if the following bit does make sense // (if not it is the correct position within the second @@ -499,14 +522,19 @@ static int request_receive_mode(void) { // If is true then within the single listen window right after the // ack signal a RM request has to be sent. static bool check_ack(bool bliw) { + int cnt_pulses = 0; + 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()) return false; - + if (check_pulse_length(get_pulse_length(), 2 * EM4X50_T_TAG_FULL_PERIOD)) { + catch_samples(); + // The received signal is either ACK or NAK. if (check_pulse_length(get_pulse_length(), 2 * EM4X50_T_TAG_FULL_PERIOD)) { @@ -542,6 +570,7 @@ static bool check_ack(bool bliw) { break; } } + cnt_pulses++; } return false; @@ -745,6 +774,154 @@ static bool em4x50_sim_send_word(uint32_t word) { return true; } +static int wait_cycles(int maxperiods) { + + int period = 0; + + while (period < maxperiods) { + + while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); + while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); + + period++; + } + + return PM3_SUCCESS; +} + +static int get_cycles(void) { + + int cycles = 0; + + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + while (AT91C_BASE_TC0->TC_CV < T0 * EM4X50_T_TAG_FULL_PERIOD) { + + while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); + + // check again to minimize desynchronization + if (AT91C_BASE_TC0->TC_CV >= T0 * EM4X50_T_TAG_FULL_PERIOD) + break; + + while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); + + cycles++; + } + + return cycles; +} + +static uint8_t em4x50_sim_read_bit(void) { + + int cond = EM4X50_T_TAG_FULL_PERIOD - EM4X50_TAG_TOLERANCE; + + return (get_cycles() < cond) ? 0 : 1; +} + +static uint8_t em4x50_sim_read_byte(void) { + + uint8_t byte = 0; + + for (int i = 0; i < 8; i++) { + byte <<= 1; + byte |= em4x50_sim_read_bit(); + } + + return byte; +} + +static uint8_t em4x50_sim_read_byte_with_parity_check(void) { + + uint8_t byte = 0, parity = 0, pval = 0; + + for (int i = 0; i < 8; i++) { + byte <<= 1; + byte |= em4x50_sim_read_bit(); + parity ^= (byte & 1); + } + + pval = em4x50_sim_read_bit(); + + return (parity == pval) ? byte : 0; +} + +static uint32_t em4x50_sim_read_word(void) { + + uint8_t parities = 0, parities_calculated = 0, stop_bit = 0; + uint8_t bytes[4] = {0}; + + // read plain data + for (int i = 0; i < 4; i++) { + bytes[i] = em4x50_sim_read_byte_with_parity_check(); + } + + // read column parities and stop bit + parities = em4x50_sim_read_byte(); + stop_bit = em4x50_sim_read_bit(); + + // calculate column parities from data + for (int i = 0; i < 8; i++) { + parities_calculated <<= 1; + for (int j = 0; j < 4; j++) { + parities_calculated ^= (bytes[j] >> (7 - i)) & 1; + } + } + + // check parities + if ((parities == parities_calculated) && (stop_bit == 0)) { + return BYTES2UINT32(bytes); + } + + return 0; +} + +static void em4x50_sim_send_ack(void) { + + SHORT_COIL(); + wait_cycles(EM4X50_T_TAG_HALF_PERIOD); + + OPEN_COIL(); + wait_cycles(EM4X50_T_TAG_HALF_PERIOD); + + SHORT_COIL(); + wait_cycles(3 * EM4X50_T_TAG_HALF_PERIOD); + + OPEN_COIL(); + wait_cycles(EM4X50_T_TAG_HALF_PERIOD); + + SHORT_COIL(); + wait_cycles(3 * EM4X50_T_TAG_HALF_PERIOD); + + OPEN_COIL(); + wait_cycles(EM4X50_T_TAG_HALF_PERIOD); + + SHORT_COIL(); +} + +static void em4x50_sim_send_nak(void) { + + SHORT_COIL(); + wait_cycles(EM4X50_T_TAG_HALF_PERIOD); + + OPEN_COIL(); + wait_cycles(EM4X50_T_TAG_HALF_PERIOD); + + SHORT_COIL(); + wait_cycles(3 * EM4X50_T_TAG_HALF_PERIOD); + + OPEN_COIL(); + wait_cycles(EM4X50_T_TAG_HALF_PERIOD); + + SHORT_COIL(); + wait_cycles(EM4X50_T_TAG_FULL_PERIOD); + + OPEN_COIL(); + wait_cycles(EM4X50_T_TAG_HALF_PERIOD); + + SHORT_COIL(); + wait_cycles(EM4X50_T_TAG_HALF_PERIOD); +} + +/* static bool em4x50_sim_send_listen_window(void) { uint16_t check = 0; @@ -790,6 +967,257 @@ static bool em4x50_sim_send_listen_window(void) { return true; } +*/ + +static void em4x50_sim_handle_login_command(void) { + + //uint8_t *em4x50_mem = BigBuf_get_EM_addr(); + uint32_t password = 0; + //uint32_t tag[EM4X50_NO_WORDS] = {0x0}; + + // read password + 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) + em4x50_sim_send_bit(1); + + em4x50_sim_send_ack(); + + /* + if (password == tag[0]) { + em4x50_sim_send_ack(); + } else { + em4x50_sim_send_ack(); + } + */ + + // continue with standard read mode + em4x50_sim_handle_command(0); + Dbprintf("password = %08x", password); + BigBuf_free(); +} + +static void em4x50_sim_handle_reset_command(void) { + + // processing pause time (corresponds to a "1" bit) + em4x50_sim_send_bit(1); + + // send ACK + em4x50_sim_send_ack(); + + // wait for tinit + wait_timer(T0 * EM4X50_T_TAG_TINIT); + + // continue with standard read mode + em4x50_sim_handle_command(0); +} + +static void em4x50_sim_handle_write_command(void) { + + uint8_t *em4x50_mem = BigBuf_get_EM_addr(); + uint8_t address = 0; + uint32_t data = 0; + uint32_t tag[EM4X50_NO_WORDS] = {0x0}; + + // read address + address = em4x50_sim_read_byte_with_parity_check(); + // read data + 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 + bool raw = (tag[EM4X50_CONTROL] >> CONFIG_BLOCK) & READ_AFTER_WRITE; + // extract protection data + int fwrp = tag[EM4X50_PROTECTION] & 0xFF; // first word read protected + int lwrp = (tag[EM4X50_PROTECTION] >> 8) & 0xFF; // last word read protected + + // save data to tag + tag[address] = data; + + // write access time + wait_timer(T0 * EM4X50_T_TAG_TWA); + + if ((address >= fwrp) && (address <= lwrp)) { + em4x50_sim_send_nak(); + } else if ((address == EM4X50_DEVICE_SERIAL) + && (address == EM4X50_DEVICE_ID) + && (address == 0) + ) { + em4x50_sim_send_nak(); + } else { + em4x50_sim_send_ack(); + } + + // EEPROM write time + //wait_timer(T0 * EM4X50_T_TAG_TWEE); + + em4x50_sim_send_ack(); + + // if "read after write" (raw) bit is set, repeat written data once + if (raw) { + em4x50_sim_send_listen_window(); + em4x50_sim_send_listen_window(); + em4x50_sim_send_word(tag[address]); + } + + BigBuf_free(); + + // continue with standard read mode + em4x50_sim_handle_command(0); +} + +static void em4x50_sim_handle_selective_read_command(void) { + + uint8_t *em4x50_mem = BigBuf_get_EM_addr(); + uint32_t address = 0; + uint32_t tag[EM4X50_NO_WORDS] = {0x0}; + + // read password + address = em4x50_sim_read_word(); + + // extract control data + int fwr = address & 0xFF; // first 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 + int fwrp = tag[EM4X50_PROTECTION] & 0xFF; // first word read protected + int lwrp = (tag[EM4X50_PROTECTION] >> 8) & 0xFF; // last word read protected + + // processing pause time (corresponds to a "1" bit) + em4x50_sim_send_bit(1); + + em4x50_sim_send_ack(); + + while (BUTTON_PRESS() == false) { + + 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(tag[i]); + } + } + } + + BigBuf_free(); +} + +static void em4x50_sim_handle_standard_read_command(void) { + + 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 + int fwr = tag[CONFIG_BLOCK] & 0xFF; // first word read + int lwr = (tag[CONFIG_BLOCK] >> 8) & 0xFF; // last word read + // extract protection data + int fwrp = tag[EM4X50_PROTECTION] & 0xFF; // first word read protected + int lwrp = (tag[EM4X50_PROTECTION] >> 8) & 0xFF; // last word read protected + + while (BUTTON_PRESS() == false) { + + 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(tag[i]); + } + } + } + BigBuf_free(); +} + +static void em4x50_sim_handle_command(uint8_t command) { + + switch (command) { + + case EM4X50_COMMAND_LOGIN: + em4x50_sim_handle_login_command(); + break; + + case EM4X50_COMMAND_RESET: + em4x50_sim_handle_reset_command(); + break; + + case EM4X50_COMMAND_WRITE: + em4x50_sim_handle_write_command(); + break; + + case EM4X50_COMMAND_WRITE_PASSWORD: + Dbprintf("Command = write_password"); + break; + + case EM4X50_COMMAND_SELECTIVE_READ: + em4x50_sim_handle_selective_read_command(); + break; + + default: + em4x50_sim_handle_standard_read_command(); + break; + } +} + +// reader requests receive mode (rm) by sending two zeros +static void check_rm_request(void) { + + int cond = EM4X50_T_TAG_FULL_PERIOD - EM4X50_TAG_TOLERANCE; + + // look for first zero + if (get_cycles() < cond) { + + // look for second zero + if (get_cycles() < cond) { + + // read mode request detected, get command from reader + uint8_t command = em4x50_sim_read_byte_with_parity_check(); + em4x50_sim_handle_command(command); + } + } +} + +static bool em4x50_sim_send_listen_window(void) { + + SHORT_COIL(); + wait_cycles(EM4X50_T_TAG_HALF_PERIOD); + + OPEN_COIL(); + wait_cycles(EM4X50_T_TAG_HALF_PERIOD); + + SHORT_COIL(); + wait_cycles(2 * EM4X50_T_TAG_FULL_PERIOD); + + OPEN_COIL(); + check_rm_request(); + + SHORT_COIL(); + wait_cycles(EM4X50_T_TAG_FULL_PERIOD); + + return true; +} // simple login to EM4x50, // used in operations that require authentication @@ -805,8 +1233,9 @@ static bool login(uint32_t password) { wait_timer(T0 * EM4X50_T_TAG_TPP); // check if ACK is returned - if (check_ack(false)) + if (check_ack(false)) { return PM3_SUCCESS; + } } else { if (DBGLEVEL >= DBG_DEBUG) @@ -1051,6 +1480,7 @@ void em4x50_info(em4x50_data_t *etd) { uint32_t addresses = 0x00002100; // read from fwr = 0 to lwr = 33 (0x21) uint32_t words[EM4X50_NO_WORDS] = {0x0}; + gcount = 0; em4x50_setup_read(); if (get_signalproperties() && find_em4x50_tag()) { @@ -1064,7 +1494,7 @@ void em4x50_info(em4x50_data_t *etd) { } lf_finalize(); - + reply_ng(CMD_LF_EM4X50_INFO, status, (uint8_t *)words, EM4X50_TAG_MAX_NO_BYTES); } @@ -1081,6 +1511,7 @@ void em4x50_reader(void) { LOW(GPIO_SSC_DOUT); lf_finalize(); + reply_ng(CMD_LF_EM4X50_READER, now, (uint8_t *)words, 4 * now); } @@ -1244,35 +1675,22 @@ void em4x50_writepwd(em4x50_data_t *etd) { // simulate uploaded data in emulator memory // (currently simulation allows only a one-way communication) -void em4x50_sim(uint8_t *filename) { +void em4x50_sim() { int status = PM3_SUCCESS; uint8_t *em4x50_mem = BigBuf_get_EM_addr(); uint32_t words[EM4X50_NO_WORDS] = {0x0}; -#ifdef WITH_FLASH - - if (strlen((char *)filename) != 0) { - - BigBuf_free(); - - int changed = rdv40_spiffs_lazy_mount(); - uint32_t size = size_in_spiffs((char *)filename); - em4x50_mem = BigBuf_malloc(size); - - rdv40_spiffs_read_as_filetype((char *)filename, em4x50_mem, size, RDV40_SPIFFS_SAFETY_SAFE); - - if (changed) - rdv40_spiffs_lazy_unmount(); - } - -#endif - for (int i = 0; i < EM4X50_NO_WORDS; i++) words[i] = reflect32(bytes_to_num(em4x50_mem + (i * 4), 4)); // only if valid em4x50 data (e.g. uid == serial) if (words[EM4X50_DEVICE_SERIAL] != words[EM4X50_DEVICE_ID]) { + em4x50_setup_sim(); + + em4x50_sim_handle_command(0); + + /* // extract control data int fwr = words[CONFIG_BLOCK] & 0xFF; // first word read int lwr = (words[CONFIG_BLOCK] >> 8) & 0xFF; // last word read @@ -1280,11 +1698,10 @@ void em4x50_sim(uint8_t *filename) { int fwrp = words[EM4X50_PROTECTION] & 0xFF; // first word read protected int lwrp = (words[EM4X50_PROTECTION] >> 8) & 0xFF; // last word read protected - em4x50_setup_sim(); - // 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++) { @@ -1297,12 +1714,14 @@ void em4x50_sim(uint8_t *filename) { em4x50_sim_send_word(words[i]); } } + */ } else { status = PM3_ENODATA; } BigBuf_free(); lf_finalize(); + reply_ng(CMD_LF_EM4X50_SIM, status, NULL, 0); } @@ -1350,11 +1769,6 @@ void em4x50_test(em4x50_test_t *ett) { uint32_t tvallow[ett->cycles]; em4x50_setup_sim(); - AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0); - AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; - AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; while (AT91C_BASE_TC0->TC_CV > 0); for (int t = 0; t < ett->cycles; t++) { @@ -1378,5 +1792,24 @@ void em4x50_test(em4x50_test_t *ett) { } + em4x50_setup_sim(); + for (;;) { + em4x50_sim_send_listen_window(); + em4x50_sim_send_listen_window(); + em4x50_sim_send_bit(0); + em4x50_sim_send_bit(0); + em4x50_sim_send_bit(0); + em4x50_sim_send_ack(); + em4x50_sim_send_ack(); + em4x50_sim_send_bit(0); + em4x50_sim_send_bit(0); + em4x50_sim_send_bit(0); + em4x50_sim_send_nak(); + 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); } diff --git a/armsrc/em4x50.h b/armsrc/em4x50.h index 87451e198..a753b0808 100644 --- a/armsrc/em4x50.h +++ b/armsrc/em4x50.h @@ -19,7 +19,7 @@ void em4x50_writepwd(em4x50_data_t *etd); void em4x50_read(em4x50_data_t *etd); void em4x50_brute(em4x50_data_t *etd); void em4x50_login(uint32_t *password); -void em4x50_sim(uint8_t *filename); +void em4x50_sim(void); void em4x50_reader(void); void em4x50_chk(uint8_t *filename); void em4x50_test(em4x50_test_t *ett); diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index a3da00bcc..402c826e4 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -78,6 +78,31 @@ static void get_samples(void) { write_gnuplot_config_file(gHigh, gLow); } +/* +static void get_time_samples(void) { + + const char *fn = "../data/data.dat"; + FILE *fp = NULL; + + // download from BigBuf memory + uint32_t data[EM4X50_MAX_TIME_SAMPLES] = {0x0}; + if (GetFromDevice(BIG_BUF, (uint8_t *)data, EM4X50_MAX_TIME_SAMPLES, 0, NULL, 0, NULL, 2500, false) == false) { + PrintAndLogEx(WARNING, "Fail, transfer from device time-out"); + } + + if ((fp = fopen(fn, "w+")) == false) { + PrintAndLogEx(WARNING, "Fail, open file %s", fn); + } + + for (int i = 0; i < EM4X50_MAX_TIME_SAMPLES; i++) { + PrintAndLogEx(INFO, "%i %"PRIu32"", i, data[i]); + fprintf(fp, "%i %"PRIu32"\n", i, data[i]); + } + + fclose(fp); +} +*/ + static void prepare_result(const uint8_t *data, int fwr, int lwr, em4x50_word_t *words) { // restructure received result in "em4x50_word_t" structure @@ -398,6 +423,8 @@ int CmdEM4x50Login(const char *Cmd) { else PrintAndLogEx(FAILED, "Login " _RED_("failed")); + get_samples(); + return resp.status; } @@ -667,8 +694,6 @@ int CmdEM4x50Read(const char *Cmd) { } } - get_samples(); - return em4x50_read(&etd, NULL); } diff --git a/client/src/cmdlfem4x70.h b/client/src/cmdlfem4x70.h index f0f221b06..c72450e88 100644 --- a/client/src/cmdlfem4x70.h +++ b/client/src/cmdlfem4x70.h @@ -12,7 +12,7 @@ #define CMDLFEM4X70_H__ #include "common.h" -#include "em4x50.h" +#include "em4x70.h" #define TIMEOUT 2000 diff --git a/include/em4x50.h b/include/em4x50.h index 3308a371f..06ca3f10a 100644 --- a/include/em4x50.h +++ b/include/em4x50.h @@ -37,6 +37,9 @@ #define TIMEOUT 2000 #define DUMP_FILESIZE 136 #define EM4X50_MAX_NO_SAMPLES 1000 +#define EM4X50_MAX_TIME_SAMPLES 1000 + +#define BYTES2UINT32(x) ((x[0] << 24) | (x[1] << 16) | (x[2] << 8) | (x[3])) typedef struct { bool addr_given; From f6868aadf97b0dd42c2ba465677f769927f87e75 Mon Sep 17 00:00:00 2001 From: tharexde Date: Tue, 5 Jan 2021 01:11:46 +0100 Subject: [PATCH 04/22] next version of half duplex simulation --- client/src/cmdlfem4x50.c | 15 ++++++++++++--- include/em4x50.h | 1 + 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 402c826e4..d4a458438 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -1247,7 +1247,8 @@ int CmdEM4x50Test(const char *Cmd) { "lf em 4x50 test --field on -> reader field on\n" "lf em 4x50 test --field off -> reader field off\n" "lf em 4x50 test --check -> check on/off status of reader field\n" - "lf em 4x50 test --cycles 100 -> measure time of 100 field cycles\n" + "lf em 4x50 test --cycles 100 -> measure time of 100 field cycles\n" + "lf em 4x50 test --reset -> intitiate reset command\n" ); void *argtable[] = { @@ -1255,6 +1256,7 @@ int CmdEM4x50Test(const char *Cmd) { arg_str0(NULL, "field", "on/off", "field on/off"), arg_lit0(NULL, "check", "check if field is on or off"), arg_int0(NULL, "cycles", "", "number of field cycles"), + arg_lit0(NULL, "reset", "initiates a manual reset command"), arg_param_end }; @@ -1280,7 +1282,9 @@ int CmdEM4x50Test(const char *Cmd) { ett.check_field = arg_get_lit(ctx, 2); // option: cycles ett.cycles = arg_get_int_def(ctx, 3, 0); - + // option: reset + ett.reset = arg_get_lit(ctx, 4); + CLIParserFree(ctx); // start @@ -1295,8 +1299,13 @@ int CmdEM4x50Test(const char *Cmd) { PrintAndLogEx(SUCCESS, "Field switched " _GREEN_("on")); if (ett.check_field == 1) PrintAndLogEx(SUCCESS, "Field status evaluated"); + if (ett.reset == 1) + PrintAndLogEx(SUCCESS, "reset command " _GREEN_("ok")); } else if (resp.status == 0) { - PrintAndLogEx(SUCCESS, "Field switched " _GREEN_("off")); + if (ett.field == 1) + PrintAndLogEx(SUCCESS, "Field switched " _GREEN_("off")); + if (ett.reset == 1) + PrintAndLogEx(SUCCESS, "reset command " _GREEN_("failed")); } else if (resp.status == -1) { PrintAndLogEx(INFO, "Nothing done"); } else { diff --git a/include/em4x50.h b/include/em4x50.h index 06ca3f10a..a2d1dfe23 100644 --- a/include/em4x50.h +++ b/include/em4x50.h @@ -52,6 +52,7 @@ typedef struct { typedef struct { bool check_field; + bool reset; int field; int cycles; } PACKED em4x50_test_t; From 560be3005301b94e5918d7766ea7a6c2a283335b Mon Sep 17 00:00:00 2001 From: tharexde Date: Tue, 5 Jan 2021 01:12:21 +0100 Subject: [PATCH 05/22] next version of half duplex simulation --- armsrc/em4x50.c | 212 ++++++++++++++++++------------------------------ 1 file changed, 78 insertions(+), 134 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 6c6091a8b..e0b93ce0f 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -57,12 +57,17 @@ int gHigh = 190; 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 gcycles = 0; int rm = 0; -static bool em4x50_sim_send_listen_window(void); -static void em4x50_sim_handle_command(uint8_t command); +static bool em4x50_sim_send_listen_window(uint32_t *tag); +static void em4x50_sim_handle_command(uint8_t command, uint32_t *tag); void catch_samples(void); @@ -170,22 +175,19 @@ static void em4x50_setup_read(void) { // Enable Peripheral Clock for // 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; // Disable timer during configuration 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 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 // Enable and reset counters 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 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 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; // wait until end of bit period wait_timer(T0 * EM4X50_T_TAG_QUARTER_PERIOD); - //wait_timer(T0 * EM4X50_T_TAG_HALF_PERIOD); // bit in "undefined" state? if (sample <= gHigh && sample >= gLow) @@ -522,18 +522,14 @@ static int request_receive_mode(void) { // If is true then within the single listen window right after the // ack signal a RM request has to be sent. static bool check_ack(bool bliw) { - int cnt_pulses = 0; - - 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) { - + int count_cycles = 0; + while (count_cycles < EM4X50_T_WAITING_FOR_ACK) { if (BUTTON_PRESS()) return false; 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. @@ -570,7 +566,7 @@ static bool check_ack(bool bliw) { break; } } - cnt_pulses++; + count_cycles++; } return false; @@ -919,6 +915,8 @@ static void em4x50_sim_send_nak(void) { SHORT_COIL(); 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 tag[EM4X50_NO_WORDS] = {0x0}; // read password 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) em4x50_sim_send_bit(1); - em4x50_sim_send_ack(); - - /* + // empirically determined delay (to be examined seperately) + wait_cycles(1); + if (password == tag[0]) { em4x50_sim_send_ack(); + gLogin = true; } else { - em4x50_sim_send_ack(); + em4x50_sim_send_nak(); + gLogin = false; } - */ // continue with standard read mode - em4x50_sim_handle_command(0); - Dbprintf("password = %08x", password); - BigBuf_free(); + em4x50_sim_handle_command(0, tag); } -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) em4x50_sim_send_bit(1); // send ACK em4x50_sim_send_ack(); + gLogin = false; // wait for tinit - wait_timer(T0 * EM4X50_T_TAG_TINIT); - + wait_cycles(EM4X50_T_TAG_TINIT); + // 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; uint32_t data = 0; - uint32_t tag[EM4X50_NO_WORDS] = {0x0}; // read address address = em4x50_sim_read_byte_with_parity_check(); // read data 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 bool raw = (tag[EM4X50_CONTROL] >> CONFIG_BLOCK) & READ_AFTER_WRITE; // extract protection data @@ -1041,7 +1028,7 @@ static void em4x50_sim_handle_write_command(void) { tag[address] = data; // write access time - wait_timer(T0 * EM4X50_T_TAG_TWA); + wait_cycles(EM4X50_T_TAG_TWA); if ((address >= fwrp) && (address <= lwrp)) { em4x50_sim_send_nak(); @@ -1055,28 +1042,24 @@ static void em4x50_sim_handle_write_command(void) { } // EEPROM write time - //wait_timer(T0 * EM4X50_T_TAG_TWEE); + wait_cycles(EM4X50_T_TAG_TWEE); em4x50_sim_send_ack(); // if "read after write" (raw) bit is set, repeat written data once if (raw) { - em4x50_sim_send_listen_window(); - em4x50_sim_send_listen_window(); + em4x50_sim_send_listen_window(tag); + em4x50_sim_send_listen_window(tag); em4x50_sim_send_word(tag[address]); } - BigBuf_free(); - // 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 tag[EM4X50_NO_WORDS] = {0x0}; // read password 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 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 int fwrp = tag[EM4X50_PROTECTION] & 0xFF; // first 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(); + // iceman, will need a usb cmd check to break as well while (BUTTON_PRESS() == false) { WDT_HIT(); - em4x50_sim_send_listen_window(); + em4x50_sim_send_listen_window(tag); 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); } else { 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 int fwr = tag[CONFIG_BLOCK] & 0xFF; // first 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 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) { WDT_HIT(); - em4x50_sim_send_listen_window(); + em4x50_sim_send_listen_window(tag); for (int i = fwr; i <= lwr; i++) { - em4x50_sim_send_listen_window(); + em4x50_sim_send_listen_window(tag); if ((i >= fwrp) && (i <= lwrp)) { 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) { case EM4X50_COMMAND_LOGIN: - em4x50_sim_handle_login_command(); + em4x50_sim_handle_login_command(tag); break; case EM4X50_COMMAND_RESET: - em4x50_sim_handle_reset_command(); + em4x50_sim_handle_reset_command(tag); break; case EM4X50_COMMAND_WRITE: - em4x50_sim_handle_write_command(); + em4x50_sim_handle_write_command(tag); break; case EM4X50_COMMAND_WRITE_PASSWORD: @@ -1172,17 +1144,17 @@ static void em4x50_sim_handle_command(uint8_t command) { break; case EM4X50_COMMAND_SELECTIVE_READ: - em4x50_sim_handle_selective_read_command(); + em4x50_sim_handle_selective_read_command(tag); break; default: - em4x50_sim_handle_standard_read_command(); + em4x50_sim_handle_standard_read_command(tag); break; } } // 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; @@ -1194,12 +1166,12 @@ static void check_rm_request(void) { // read mode request detected, get command from reader 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(); 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); OPEN_COIL(); - check_rm_request(); + check_rm_request(tag); SHORT_COIL(); wait_cycles(EM4X50_T_TAG_FULL_PERIOD); @@ -1230,7 +1202,7 @@ static bool login(uint32_t password) { // send 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 if (check_ack(false)) { @@ -1377,7 +1349,7 @@ static int reset(void) { // send reset command em4x50_reader_send_byte_with_parity(EM4X50_COMMAND_RESET); - + if (check_ack(false)) return PM3_SUCCESS; @@ -1674,60 +1646,36 @@ void em4x50_writepwd(em4x50_data_t *etd) { } // simulate uploaded data in emulator memory -// (currently simulation allows only a one-way communication) void em4x50_sim() { int status = PM3_SUCCESS; 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++) - 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) - if (words[EM4X50_DEVICE_SERIAL] != words[EM4X50_DEVICE_ID]) { + if (tag[EM4X50_DEVICE_SERIAL] != tag[EM4X50_DEVICE_ID]) { + // init 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 { status = PM3_ENODATA; } BigBuf_free(); lf_finalize(); - reply_ng(CMD_LF_EM4X50_SIM, status, NULL, 0); } void em4x50_test(em4x50_test_t *ett) { - int status = PM3_EFAILED; + int status = 0; // set field on or off if (ett->field != -1) { @@ -1791,25 +1739,21 @@ void em4x50_test(em4x50_test_t *ett) { } } - - em4x50_setup_sim(); - for (;;) { - em4x50_sim_send_listen_window(); - em4x50_sim_send_listen_window(); - em4x50_sim_send_bit(0); - em4x50_sim_send_bit(0); - em4x50_sim_send_bit(0); - em4x50_sim_send_ack(); - em4x50_sim_send_ack(); - em4x50_sim_send_bit(0); - em4x50_sim_send_bit(0); - em4x50_sim_send_bit(0); - em4x50_sim_send_nak(); - em4x50_sim_send_nak(); - em4x50_sim_send_bit(0); - em4x50_sim_send_bit(0); - em4x50_sim_send_bit(0); + + // perform reset + if (ett->reset) { + em4x50_setup_read(); + + status = PM3_EFAILED; + if (get_signalproperties() && find_em4x50_tag()) { + + if (reset() == PM3_SUCCESS) { + status = 1; + } + } + + lf_finalize(); } - + reply_ng(CMD_LF_EM4X50_TEST, status, NULL, 0); } From 12071080a6abf6d84c65f6469ea7744fbcbb390e Mon Sep 17 00:00:00 2001 From: tharexde Date: Thu, 7 Jan 2021 01:22:46 +0100 Subject: [PATCH 06/22] next step (half duplex simulation): all commands seem to work --- armsrc/appmain.c | 2 +- armsrc/em4x50.c | 247 ++++++++++++++++++++++++++++++--------- armsrc/em4x50.h | 2 +- client/src/cmdlfem4x50.c | 20 +++- 4 files changed, 212 insertions(+), 59 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 6fba90e0e..b3f752fb8 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1136,7 +1136,7 @@ static void PacketReceived(PacketCommandNG *packet) { // destroy the Emulator Memory. //----------------------------------------------------------------------------- FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - em4x50_sim(); + em4x50_sim((uint32_t *)packet->data.asBytes); break; } case CMD_LF_EM4X50_READER: { diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index e0b93ce0f..9ff516797 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -61,6 +61,8 @@ 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; +// additionally a global variable to identify the WritePassword process +bool gWritePasswordProcess = 0; int gcount = 0; int gcycles = 0; @@ -218,6 +220,9 @@ static void em4x50_setup_sim(void) { AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + + // Watchdog hit + WDT_HIT(); } // calculate signal properties (mean amplitudes) from measured data: @@ -840,7 +845,7 @@ static uint8_t em4x50_sim_read_byte_with_parity_check(void) { return (parity == pval) ? byte : 0; } -static uint32_t em4x50_sim_read_word(void) { +static bool em4x50_sim_read_word(uint32_t *word) { uint8_t parities = 0, parities_calculated = 0, stop_bit = 0; uint8_t bytes[4] = {0}; @@ -864,10 +869,11 @@ static uint32_t em4x50_sim_read_word(void) { // check parities if ((parities == parities_calculated) && (stop_bit == 0)) { - return BYTES2UINT32(bytes); + *word = BYTES2UINT32(bytes); + return true; } - return 0; + return false; } static void em4x50_sim_send_ack(void) { @@ -969,10 +975,9 @@ static bool em4x50_sim_send_listen_window(void) { static void em4x50_sim_handle_login_command(uint32_t *tag) { - uint32_t password = 0; - // read password - password = em4x50_sim_read_word(); + uint32_t password = 0; + bool pwd_ok = em4x50_sim_read_word(&password); // processing pause time (corresponds to a "1" bit) em4x50_sim_send_bit(1); @@ -980,7 +985,7 @@ static void em4x50_sim_handle_login_command(uint32_t *tag) { // empirically determined delay (to be examined seperately) wait_cycles(1); - if (password == tag[0]) { + if (pwd_ok && (password == reflect32(tag[EM4X50_DEVICE_PASSWORD]))) { em4x50_sim_send_ack(); gLogin = true; } else { @@ -1010,43 +1015,87 @@ static void em4x50_sim_handle_reset_command(uint32_t *tag) { static void em4x50_sim_handle_write_command(uint32_t *tag) { - uint8_t address = 0; - uint32_t data = 0; - // read address + uint8_t address = 0; address = em4x50_sim_read_byte_with_parity_check(); // read data - data = em4x50_sim_read_word(); - - // extract necessary control data - bool raw = (tag[EM4X50_CONTROL] >> CONFIG_BLOCK) & READ_AFTER_WRITE; - // extract protection data - int fwrp = tag[EM4X50_PROTECTION] & 0xFF; // first word read protected - int lwrp = (tag[EM4X50_PROTECTION] >> 8) & 0xFF; // last word read protected - - // save data to tag - tag[address] = data; + uint32_t data = 0; + bool word_ok = em4x50_sim_read_word(&data); // write access time wait_cycles(EM4X50_T_TAG_TWA); - if ((address >= fwrp) && (address <= lwrp)) { + if (word_ok == false) { em4x50_sim_send_nak(); - } else if ((address == EM4X50_DEVICE_SERIAL) - && (address == EM4X50_DEVICE_ID) - && (address == 0) - ) { - em4x50_sim_send_nak(); - } else { - em4x50_sim_send_ack(); + em4x50_sim_handle_command(0, tag); + } + + // extract necessary control data + bool raw = (tag[EM4X50_CONTROL] >> CONFIG_BLOCK) & READ_AFTER_WRITE; + // extract protection data: + // first word write protected + int fwwp = reflect8((tag[EM4X50_PROTECTION] >> 24) & 0xFF); + // last word write protected + int lwwp = reflect8((tag[EM4X50_PROTECTION] >> 16) & 0xFF); + + switch (address) { + + case EM4X50_DEVICE_PASSWORD: + em4x50_sim_send_nak(); + em4x50_sim_handle_command(0, tag); + break; + + case EM4X50_PROTECTION: + if (gLogin) { + tag[address] = reflect32(data); + em4x50_sim_send_ack(); + } else { + em4x50_sim_send_nak(); + em4x50_sim_handle_command(0, tag); + } + break; + + case EM4X50_CONTROL: + if (gLogin) { + tag[address] = reflect32(data); + em4x50_sim_send_ack(); + } else { + em4x50_sim_send_nak(); + em4x50_sim_handle_command(0, tag); + } + break; + + case EM4X50_DEVICE_SERIAL: + em4x50_sim_send_nak(); + em4x50_sim_handle_command(0, tag); + break; + + case EM4X50_DEVICE_ID: + em4x50_sim_send_nak(); + em4x50_sim_handle_command(0, tag); + break; + + default: + if ((address >= fwwp) && (address <= lwwp) && (gLogin == false)) { + em4x50_sim_send_nak(); + em4x50_sim_handle_command(0, tag); + } else { + tag[address] = reflect32(data); + em4x50_sim_send_ack(); + } + break; } // EEPROM write time wait_cycles(EM4X50_T_TAG_TWEE); + // strange: need some sort of 'waveform correction', otherwise ack signal + // will not be detected; sending a single "1" seems to solve the problem + em4x50_sim_send_bit(1); + em4x50_sim_send_ack(); - // if "read after write" (raw) bit is set, repeat written data once + // if "read after write" (raw) bit is set, send written data once if (raw) { em4x50_sim_send_listen_window(tag); em4x50_sim_send_listen_window(tag); @@ -1057,25 +1106,90 @@ static void em4x50_sim_handle_write_command(uint32_t *tag) { em4x50_sim_handle_command(0, tag); } +static void em4x50_sim_handle_writepwd_command(uint32_t *tag) { + + bool pwd_ok = false; + + if (gWritePasswordProcess == false) { + + gWritePasswordProcess = true; + + // read password + uint32_t act_password = 0; + pwd_ok = em4x50_sim_read_word(&act_password); + + // processing pause time (corresponds to a "1" bit) + em4x50_sim_send_bit(1); + + if (pwd_ok && (act_password == reflect32(tag[EM4X50_DEVICE_PASSWORD]))) { + em4x50_sim_send_ack(); + gLogin = true; + } else { + em4x50_sim_send_nak(); + gLogin = false; + em4x50_sim_handle_command(0, tag); + } + + em4x50_sim_send_listen_window(tag); + + } else { + + gWritePasswordProcess = false; + + // read new password + uint32_t new_password = 0; + pwd_ok = em4x50_sim_read_word(&new_password); + + // write access time + wait_cycles(EM4X50_T_TAG_TWA); + + if (pwd_ok) { + em4x50_sim_send_ack(); + tag[EM4X50_DEVICE_PASSWORD] = reflect32(new_password); + } else { + em4x50_sim_send_ack(); + em4x50_sim_handle_command(0, tag); + } + + // EEPROM write time + wait_cycles(EM4X50_T_TAG_TWEE); + + // strange: need some sort of 'waveform correction', otherwise ack signal + // will not be detected; sending a single "1" seems to solve the problem + em4x50_sim_send_bit(1); + + em4x50_sim_send_ack(); + + // continue with standard read mode + em4x50_sim_handle_command(0, tag); + } +} + static void em4x50_sim_handle_selective_read_command(uint32_t *tag) { - uint32_t address = 0; - // read password - address = em4x50_sim_read_word(); + uint32_t address = 0; + bool addr_ok = em4x50_sim_read_word(&address); + + // processing pause time (corresponds to a "1" bit) + em4x50_sim_send_bit(1); + + if (addr_ok) { + em4x50_sim_send_ack(); + } else { + em4x50_sim_send_nak(); + em4x50_sim_handle_command(0, tag); + } // extract control data int fwr = address & 0xFF; // first word read int lwr = (address >> 8) & 0xFF; // last word read - // extract protection data - int fwrp = tag[EM4X50_PROTECTION] & 0xFF; // first word read protected - int lwrp = (tag[EM4X50_PROTECTION] >> 8) & 0xFF; // last word read protected - - // processing pause time (corresponds to a "1" bit) - em4x50_sim_send_bit(1); - - em4x50_sim_send_ack(); + // extract protection data: + // first word read protected + int fwrp = reflect32(tag[EM4X50_PROTECTION]) & 0xFF; + // last word read protected + int lwrp = (reflect32(tag[EM4X50_PROTECTION]) >> 8) & 0xFF; // iceman, will need a usb cmd check to break as well while (BUTTON_PRESS() == false) { @@ -1090,7 +1204,7 @@ static void em4x50_sim_handle_selective_read_command(uint32_t *tag) { if ((gLogin == false) && (i >= fwrp) && (i <= lwrp)) { em4x50_sim_send_word(0x00); } else { - em4x50_sim_send_word(tag[i]); + em4x50_sim_send_word(reflect32(tag[i])); } } } @@ -1099,11 +1213,13 @@ static void em4x50_sim_handle_selective_read_command(uint32_t *tag) { static void em4x50_sim_handle_standard_read_command(uint32_t *tag) { // extract control data - int fwr = tag[CONFIG_BLOCK] & 0xFF; // first word read - int lwr = (tag[CONFIG_BLOCK] >> 8) & 0xFF; // last word read - // extract protection data - int fwrp = tag[EM4X50_PROTECTION] & 0xFF; // first word read protected - int lwrp = (tag[EM4X50_PROTECTION] >> 8) & 0xFF; // last word read protected + int fwr = reflect32(tag[EM4X50_CONTROL]) & 0xFF; // first word read + int lwr = (reflect32(tag[EM4X50_CONTROL]) >> 8) & 0xFF; // last word read + // extract protection data: + // first word read protected + int fwrp = reflect32(tag[EM4X50_PROTECTION]) & 0xFF; + // last word read protected + int lwrp = (reflect32(tag[EM4X50_PROTECTION]) >> 8) & 0xFF; // iceman, will need a usb cmd check to break as well while (BUTTON_PRESS() == false) { @@ -1117,7 +1233,7 @@ static void em4x50_sim_handle_standard_read_command(uint32_t *tag) { if ((i >= fwrp) && (i <= lwrp)) { em4x50_sim_send_word(0x00); } else { - em4x50_sim_send_word(tag[i]); + em4x50_sim_send_word(reflect32(tag[i])); } } } @@ -1140,7 +1256,7 @@ static void em4x50_sim_handle_command(uint8_t command, uint32_t *tag) { break; case EM4X50_COMMAND_WRITE_PASSWORD: - Dbprintf("Command = write_password"); + em4x50_sim_handle_writepwd_command(tag); break; case EM4X50_COMMAND_SELECTIVE_READ: @@ -1164,9 +1280,15 @@ static void check_rm_request(uint32_t *tag) { // look for second zero if (get_cycles() < cond) { - // read mode request detected, get command from reader - uint8_t command = em4x50_sim_read_byte_with_parity_check(); - em4x50_sim_handle_command(command, tag); + // if command before was EM4X50_COMMAND_WRITE_PASSWORD + // switch to separate process + if (gWritePasswordProcess) { + em4x50_sim_handle_command(EM4X50_COMMAND_WRITE_PASSWORD, tag); + } else { + // read mode request detected, get command from reader + uint8_t command = em4x50_sim_read_byte_with_parity_check(); + em4x50_sim_handle_command(command, tag); + } } } } @@ -1514,8 +1636,13 @@ static int write(uint32_t word, uint32_t addresses) { // now EM4x50 needs T0 * EM4X50_T_TAG_TWEE (EEPROM write time) // for saving data and should return with ACK - if (check_ack(false)) + for (int i = 0; i < 50; i++) { + wait_timer(T0 * EM4X50_T_TAG_FULL_PERIOD); + } + + if (check_ack(false)) { return PM3_SUCCESS; + } } } } else { @@ -1554,9 +1681,12 @@ static int write_password(uint32_t password, uint32_t new_password) { // wait for T0 * EM4X50_T_TAG_TWA (write access time) wait_timer(T0 * EM4X50_T_TAG_TWA); - if (check_ack(false)) - if (check_ack(false)) + if (check_ack(false)) { + //Dbprintf("zweites ack"); + if (check_ack(false)) { return PM3_SUCCESS; + } + } } } } else { @@ -1646,13 +1776,18 @@ void em4x50_writepwd(em4x50_data_t *etd) { } // simulate uploaded data in emulator memory -void em4x50_sim() { +void em4x50_sim(uint32_t *password) { int status = PM3_SUCCESS; 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)); + tag[i] = bytes_to_num(em4x50_mem + (i * 4), 4); + + // via eload uploaded dump usually does not contain a password + if (tag[EM4X50_DEVICE_PASSWORD] == 0) { + tag[EM4X50_DEVICE_PASSWORD] = reflect32(*password); + } // only if valid em4x50 data (e.g. uid == serial) if (tag[EM4X50_DEVICE_SERIAL] != tag[EM4X50_DEVICE_ID]) { diff --git a/armsrc/em4x50.h b/armsrc/em4x50.h index a753b0808..5d4812f42 100644 --- a/armsrc/em4x50.h +++ b/armsrc/em4x50.h @@ -19,7 +19,7 @@ void em4x50_writepwd(em4x50_data_t *etd); void em4x50_read(em4x50_data_t *etd); void em4x50_brute(em4x50_data_t *etd); void em4x50_login(uint32_t *password); -void em4x50_sim(void); +void em4x50_sim(uint32_t *password); void em4x50_reader(void); void em4x50_chk(uint8_t *filename); void em4x50_test(em4x50_test_t *ett); diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index d4a458438..3aea9e981 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -1211,25 +1211,43 @@ int CmdEM4x50Restore(const char *Cmd) { } int CmdEM4x50Sim(const char *Cmd) { + + uint32_t password = 0; + CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50 sim", "Simulates a EM4x50 tag.\n" "Upload using `lf em 4x50 eload`", "lf em 4x50 sim" + "lf em 4x50 sim -p 27182818 -> uses password for eload data" ); void *argtable[] = { arg_param_begin, + arg_str0("p", "passsword", "", "password, 4 bytes, lsb"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); + int pwd_len = 0; + uint8_t pwd[4] = {0}; + CLIGetHexWithReturn(ctx, 1, pwd, &pwd_len); + CLIParserFree(ctx); + + if (pwd_len) { + if (pwd_len != 4) { + PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwd_len); + return PM3_EINVARG; + } else { + password = BYTES2UINT32(pwd); + } + } CLIParserFree(ctx); PrintAndLogEx(INFO, "Simulating data from emulator memory"); clearCommandBuffer(); - SendCommandNG(CMD_LF_EM4X50_SIM, NULL, 0); + SendCommandNG(CMD_LF_EM4X50_SIM, (uint8_t *)&password, sizeof(password)); PacketResponseNG resp; WaitForResponse(CMD_LF_EM4X50_SIM, &resp); if (resp.status == PM3_SUCCESS) From 56efcc9d7f948d06f3ac21184b13556f75e1f6af Mon Sep 17 00:00:00 2001 From: tharexde Date: Thu, 7 Jan 2021 23:49:59 +0100 Subject: [PATCH 07/22] half duplex sim status: stop mechanism still missing --- armsrc/em4x50.c | 64 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 48 insertions(+), 16 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 9ff516797..262b4c6a6 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -60,9 +60,9 @@ 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; +bool gLogin = false; // additionally a global variable to identify the WritePassword process -bool gWritePasswordProcess = 0; +bool gWritePasswordProcess = false; int gcount = 0; int gcycles = 0; @@ -777,12 +777,35 @@ static bool em4x50_sim_send_word(uint32_t word) { static int wait_cycles(int maxperiods) { - int period = 0; + int period = 0, check = 0; while (period < maxperiods) { - while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); - while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); + while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) { + WDT_HIT(); + + if (check == 1000) { + if (BUTTON_PRESS()) { + malsehn(PM3_SUCCESS); + } + check = 0; + } + ++check; + } + + check = 0; + + while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { + WDT_HIT(); + + if (check == 1000) { + if (BUTTON_PRESS()) { + malsehn(PM3_SUCCESS); + } + check = 0; + } + ++check; + } period++; } @@ -830,19 +853,19 @@ static uint8_t em4x50_sim_read_byte(void) { return byte; } -static uint8_t em4x50_sim_read_byte_with_parity_check(void) { +static bool em4x50_sim_read_byte_with_parity_check(uint8_t *byte) { - uint8_t byte = 0, parity = 0, pval = 0; + uint8_t parity = 0, pval = 0; for (int i = 0; i < 8; i++) { - byte <<= 1; - byte |= em4x50_sim_read_bit(); - parity ^= (byte & 1); + *byte <<= 1; + *byte |= em4x50_sim_read_bit(); + parity ^= ((*byte) & 1); } pval = em4x50_sim_read_bit(); - return (parity == pval) ? byte : 0; + return (parity == pval); } static bool em4x50_sim_read_word(uint32_t *word) { @@ -852,7 +875,7 @@ static bool em4x50_sim_read_word(uint32_t *word) { // read plain data for (int i = 0; i < 4; i++) { - bytes[i] = em4x50_sim_read_byte_with_parity_check(); + em4x50_sim_read_byte_with_parity_check(&bytes[i]); } // read column parities and stop bit @@ -1017,7 +1040,7 @@ static void em4x50_sim_handle_write_command(uint32_t *tag) { // read address uint8_t address = 0; - address = em4x50_sim_read_byte_with_parity_check(); + bool addr_ok = em4x50_sim_read_byte_with_parity_check(&address); // read data uint32_t data = 0; bool word_ok = em4x50_sim_read_word(&data); @@ -1025,7 +1048,7 @@ static void em4x50_sim_handle_write_command(uint32_t *tag) { // write access time wait_cycles(EM4X50_T_TAG_TWA); - if (word_ok == false) { + if ((addr_ok == false) || (word_ok == false)) { em4x50_sim_send_nak(); em4x50_sim_handle_command(0, tag); } @@ -1286,7 +1309,8 @@ static void check_rm_request(uint32_t *tag) { em4x50_sim_handle_command(EM4X50_COMMAND_WRITE_PASSWORD, tag); } else { // read mode request detected, get command from reader - uint8_t command = em4x50_sim_read_byte_with_parity_check(); + uint8_t command = 0; + em4x50_sim_read_byte_with_parity_check(&command); em4x50_sim_handle_command(command, tag); } } @@ -1682,7 +1706,13 @@ static int write_password(uint32_t password, uint32_t new_password) { wait_timer(T0 * EM4X50_T_TAG_TWA); if (check_ack(false)) { - //Dbprintf("zweites ack"); + + // now EM4x50 needs T0 * EM4X50_T_TAG_TWEE (EEPROM write time) + // for saving data and should return with ACK + for (int i = 0; i < 50; i++) { + wait_timer(T0 * EM4X50_T_TAG_FULL_PERIOD); + } + if (check_ack(false)) { return PM3_SUCCESS; } @@ -1777,7 +1807,9 @@ void em4x50_writepwd(em4x50_data_t *etd) { // simulate uploaded data in emulator memory void em4x50_sim(uint32_t *password) { + int status = PM3_SUCCESS; + uint8_t *em4x50_mem = BigBuf_get_EM_addr(); uint32_t tag[EM4X50_NO_WORDS] = {0x0}; From af5237e6fdf5311f9e8c6732d5bae7cc452aa497 Mon Sep 17 00:00:00 2001 From: tharexde Date: Mon, 11 Jan 2021 21:23:38 +0100 Subject: [PATCH 08/22] changes due to desynchronization effects --- armsrc/em4x50.c | 259 ++++++++++++++++++++++++------------------------ 1 file changed, 132 insertions(+), 127 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 262b4c6a6..cb9b26485 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -54,6 +54,7 @@ #define EM4X50_COMMAND_WRITE 0x12 #define EM4X50_COMMAND_WRITE_PASSWORD 0x11 #define EM4X50_COMMAND_SELECTIVE_READ 0x0A +#define EM4X50_COMMAND_STANDARD_READ 0x02 // virtual command int gHigh = 190; int gLow = 60; @@ -68,8 +69,7 @@ int gcount = 0; int gcycles = 0; int rm = 0; -static bool em4x50_sim_send_listen_window(uint32_t *tag); -static void em4x50_sim_handle_command(uint8_t command, uint32_t *tag); +static int em4x50_sim_send_listen_window(uint32_t *tag); void catch_samples(void); @@ -786,7 +786,7 @@ static int wait_cycles(int maxperiods) { if (check == 1000) { if (BUTTON_PRESS()) { - malsehn(PM3_SUCCESS); + return PM3_EOPABORTED; } check = 0; } @@ -800,7 +800,7 @@ static int wait_cycles(int maxperiods) { if (check == 1000) { if (BUTTON_PRESS()) { - malsehn(PM3_SUCCESS); + return PM3_EOPABORTED; } check = 0; } @@ -818,16 +818,16 @@ static int get_cycles(void) { int cycles = 0; AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - while (AT91C_BASE_TC0->TC_CV < T0 * EM4X50_T_TAG_FULL_PERIOD) { + while (AT91C_BASE_TC0->TC_CV < T0 * (EM4X50_T_TAG_FULL_PERIOD - 2)) { while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); - + // check again to minimize desynchronization if (AT91C_BASE_TC0->TC_CV >= T0 * EM4X50_T_TAG_FULL_PERIOD) break; - - while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); + while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); + cycles++; } @@ -890,9 +890,10 @@ static bool em4x50_sim_read_word(uint32_t *word) { } } + *word = BYTES2UINT32(bytes); + // check parities if ((parities == parities_calculated) && (stop_bit == 0)) { - *word = BYTES2UINT32(bytes); return true; } @@ -948,59 +949,13 @@ static void em4x50_sim_send_nak(void) { OPEN_COIL(); } -/* -static bool em4x50_sim_send_listen_window(void) { - - uint16_t check = 0; - - for (int t = 0; t < 5 * EM4X50_T_TAG_FULL_PERIOD; t++) { - - // wait until SSC_CLK goes HIGH - while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) { - WDT_HIT(); - - if (check == 1000) { - if (BUTTON_PRESS()) - return false; - check = 0; - } - ++check; - } - - if (t >= 4 * EM4X50_T_TAG_FULL_PERIOD) - SHORT_COIL(); - else if (t >= 3 * EM4X50_T_TAG_FULL_PERIOD) - OPEN_COIL(); - else if (t >= EM4X50_T_TAG_FULL_PERIOD) - SHORT_COIL(); - else if (t >= EM4X50_T_TAG_HALF_PERIOD) - OPEN_COIL(); - else - SHORT_COIL(); - - check = 0; - - // wait until SSC_CLK goes LOW - while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { - WDT_HIT(); - if (check == 1000) { - if (BUTTON_PRESS()) - return false; - check = 0; - } - ++check; - } - } - - return true; -} -*/ - -static void em4x50_sim_handle_login_command(uint32_t *tag) { +static int em4x50_sim_handle_login_command(uint32_t *tag) { // read password uint32_t password = 0; bool pwd_ok = em4x50_sim_read_word(&password); + //Dbprintf("address = %08x", address); + wait_cycles(15); // processing pause time (corresponds to a "1" bit) em4x50_sim_send_bit(1); @@ -1017,10 +972,10 @@ static void em4x50_sim_handle_login_command(uint32_t *tag) { } // continue with standard read mode - em4x50_sim_handle_command(0, tag); + return EM4X50_COMMAND_STANDARD_READ; } -static void em4x50_sim_handle_reset_command(uint32_t *tag) { +static int em4x50_sim_handle_reset_command(uint32_t *tag) { // processing pause time (corresponds to a "1" bit) em4x50_sim_send_bit(1); @@ -1033,10 +988,10 @@ static void em4x50_sim_handle_reset_command(uint32_t *tag) { wait_cycles(EM4X50_T_TAG_TINIT); // continue with standard read mode - em4x50_sim_handle_command(0, tag); + return EM4X50_COMMAND_STANDARD_READ; } -static void em4x50_sim_handle_write_command(uint32_t *tag) { +static int em4x50_sim_handle_write_command(uint32_t *tag) { // read address uint8_t address = 0; @@ -1044,15 +999,15 @@ static void em4x50_sim_handle_write_command(uint32_t *tag) { // read data uint32_t data = 0; bool word_ok = em4x50_sim_read_word(&data); - + // write access time wait_cycles(EM4X50_T_TAG_TWA); if ((addr_ok == false) || (word_ok == false)) { em4x50_sim_send_nak(); - em4x50_sim_handle_command(0, tag); + return EM4X50_COMMAND_STANDARD_READ; } - + // extract necessary control data bool raw = (tag[EM4X50_CONTROL] >> CONFIG_BLOCK) & READ_AFTER_WRITE; // extract protection data: @@ -1065,7 +1020,7 @@ static void em4x50_sim_handle_write_command(uint32_t *tag) { case EM4X50_DEVICE_PASSWORD: em4x50_sim_send_nak(); - em4x50_sim_handle_command(0, tag); + return EM4X50_COMMAND_STANDARD_READ; break; case EM4X50_PROTECTION: @@ -1074,7 +1029,7 @@ static void em4x50_sim_handle_write_command(uint32_t *tag) { em4x50_sim_send_ack(); } else { em4x50_sim_send_nak(); - em4x50_sim_handle_command(0, tag); + return EM4X50_COMMAND_STANDARD_READ; } break; @@ -1084,24 +1039,24 @@ static void em4x50_sim_handle_write_command(uint32_t *tag) { em4x50_sim_send_ack(); } else { em4x50_sim_send_nak(); - em4x50_sim_handle_command(0, tag); + return EM4X50_COMMAND_STANDARD_READ; } break; case EM4X50_DEVICE_SERIAL: em4x50_sim_send_nak(); - em4x50_sim_handle_command(0, tag); + return EM4X50_COMMAND_STANDARD_READ; break; case EM4X50_DEVICE_ID: em4x50_sim_send_nak(); - em4x50_sim_handle_command(0, tag); + return EM4X50_COMMAND_STANDARD_READ; break; default: if ((address >= fwwp) && (address <= lwwp) && (gLogin == false)) { em4x50_sim_send_nak(); - em4x50_sim_handle_command(0, tag); + return EM4X50_COMMAND_STANDARD_READ; } else { tag[address] = reflect32(data); em4x50_sim_send_ack(); @@ -1120,16 +1075,24 @@ static void em4x50_sim_handle_write_command(uint32_t *tag) { // if "read after write" (raw) bit is set, send written data once if (raw) { - em4x50_sim_send_listen_window(tag); - em4x50_sim_send_listen_window(tag); + int command = em4x50_sim_send_listen_window(tag); + if (command != PM3_SUCCESS) { + return command; + } + + command = em4x50_sim_send_listen_window(tag); + if (command != PM3_SUCCESS) { + return command; + } + em4x50_sim_send_word(tag[address]); } // continue with standard read mode - em4x50_sim_handle_command(0, tag); + return EM4X50_COMMAND_STANDARD_READ; } -static void em4x50_sim_handle_writepwd_command(uint32_t *tag) { +static int em4x50_sim_handle_writepwd_command(uint32_t *tag) { bool pwd_ok = false; @@ -1140,6 +1103,8 @@ static void em4x50_sim_handle_writepwd_command(uint32_t *tag) { // read password uint32_t act_password = 0; pwd_ok = em4x50_sim_read_word(&act_password); + + wait_cycles(15); // processing pause time (corresponds to a "1" bit) em4x50_sim_send_bit(1); @@ -1150,10 +1115,13 @@ static void em4x50_sim_handle_writepwd_command(uint32_t *tag) { } else { em4x50_sim_send_nak(); gLogin = false; - em4x50_sim_handle_command(0, tag); + return EM4X50_COMMAND_STANDARD_READ; + } + + int command = em4x50_sim_send_listen_window(tag); + if (command != PM3_SUCCESS) { + return command; } - - em4x50_sim_send_listen_window(tag); } else { @@ -1162,7 +1130,7 @@ static void em4x50_sim_handle_writepwd_command(uint32_t *tag) { // read new password uint32_t new_password = 0; pwd_ok = em4x50_sim_read_word(&new_password); - + // write access time wait_cycles(EM4X50_T_TAG_TWA); @@ -1171,8 +1139,9 @@ static void em4x50_sim_handle_writepwd_command(uint32_t *tag) { tag[EM4X50_DEVICE_PASSWORD] = reflect32(new_password); } else { em4x50_sim_send_ack(); - em4x50_sim_handle_command(0, tag); + return EM4X50_COMMAND_STANDARD_READ; } + //OPEN_COIL(); // EEPROM write time wait_cycles(EM4X50_T_TAG_TWEE); @@ -1184,15 +1153,21 @@ static void em4x50_sim_handle_writepwd_command(uint32_t *tag) { em4x50_sim_send_ack(); // continue with standard read mode - em4x50_sim_handle_command(0, tag); + return EM4X50_COMMAND_STANDARD_READ; } + + // call writepwd function again for else branch + return EM4X50_COMMAND_WRITE_PASSWORD; } -static void em4x50_sim_handle_selective_read_command(uint32_t *tag) { +static int em4x50_sim_handle_selective_read_command(uint32_t *tag) { + int command = PM3_EOPABORTED; + // read password uint32_t address = 0; bool addr_ok = em4x50_sim_read_word(&address); + wait_cycles(15); // processing pause time (corresponds to a "1" bit) em4x50_sim_send_bit(1); @@ -1201,7 +1176,7 @@ static void em4x50_sim_handle_selective_read_command(uint32_t *tag) { em4x50_sim_send_ack(); } else { em4x50_sim_send_nak(); - em4x50_sim_handle_command(0, tag); + return EM4X50_COMMAND_STANDARD_READ; } // extract control data @@ -1218,10 +1193,18 @@ static void em4x50_sim_handle_selective_read_command(uint32_t *tag) { while (BUTTON_PRESS() == false) { WDT_HIT(); - em4x50_sim_send_listen_window(tag); + + command = em4x50_sim_send_listen_window(tag); + if (command != PM3_SUCCESS) { + return command; + } + for (int i = fwr; i <= lwr; i++) { - em4x50_sim_send_listen_window(tag); + command = em4x50_sim_send_listen_window(tag); + if (command != PM3_SUCCESS) { + return command; + } // if not authenticated do not send read protected words if ((gLogin == false) && (i >= fwrp) && (i <= lwrp)) { @@ -1231,9 +1214,13 @@ static void em4x50_sim_handle_selective_read_command(uint32_t *tag) { } } } + + return command; } -static void em4x50_sim_handle_standard_read_command(uint32_t *tag) { +static int em4x50_sim_handle_standard_read_command(uint32_t *tag) { + + int command = PM3_EOPABORTED; // extract control data int fwr = reflect32(tag[EM4X50_CONTROL]) & 0xFF; // first word read @@ -1248,10 +1235,18 @@ static void em4x50_sim_handle_standard_read_command(uint32_t *tag) { while (BUTTON_PRESS() == false) { WDT_HIT(); - em4x50_sim_send_listen_window(tag); + + command = em4x50_sim_send_listen_window(tag); + if (command != PM3_SUCCESS) { + return command; + } + for (int i = fwr; i <= lwr; i++) { - em4x50_sim_send_listen_window(tag); + command = em4x50_sim_send_listen_window(tag); + if (command != PM3_SUCCESS) { + return command; + } if ((i >= fwrp) && (i <= lwrp)) { em4x50_sim_send_word(0x00); @@ -1260,40 +1255,11 @@ static void em4x50_sim_handle_standard_read_command(uint32_t *tag) { } } } -} - -static void em4x50_sim_handle_command(uint8_t command, uint32_t *tag) { - - switch (command) { - - case EM4X50_COMMAND_LOGIN: - em4x50_sim_handle_login_command(tag); - break; - - case EM4X50_COMMAND_RESET: - em4x50_sim_handle_reset_command(tag); - break; - - case EM4X50_COMMAND_WRITE: - em4x50_sim_handle_write_command(tag); - break; - - case EM4X50_COMMAND_WRITE_PASSWORD: - em4x50_sim_handle_writepwd_command(tag); - break; - - case EM4X50_COMMAND_SELECTIVE_READ: - em4x50_sim_handle_selective_read_command(tag); - break; - - default: - em4x50_sim_handle_standard_read_command(tag); - break; - } + return command; } // reader requests receive mode (rm) by sending two zeros -static void check_rm_request(uint32_t *tag) { +static int check_rm_request(uint32_t *tag) { int cond = EM4X50_T_TAG_FULL_PERIOD - EM4X50_TAG_TOLERANCE; @@ -1306,19 +1272,21 @@ static void check_rm_request(uint32_t *tag) { // if command before was EM4X50_COMMAND_WRITE_PASSWORD // switch to separate process if (gWritePasswordProcess) { - em4x50_sim_handle_command(EM4X50_COMMAND_WRITE_PASSWORD, tag); + return EM4X50_COMMAND_WRITE_PASSWORD; } else { // read mode request detected, get command from reader uint8_t command = 0; em4x50_sim_read_byte_with_parity_check(&command); - em4x50_sim_handle_command(command, tag); + return command; } } } + + return PM3_SUCCESS; } -static bool em4x50_sim_send_listen_window(uint32_t *tag) { - +static int em4x50_sim_send_listen_window(uint32_t *tag) { + SHORT_COIL(); wait_cycles(EM4X50_T_TAG_HALF_PERIOD); @@ -1329,12 +1297,15 @@ static bool em4x50_sim_send_listen_window(uint32_t *tag) { wait_cycles(2 * EM4X50_T_TAG_FULL_PERIOD); OPEN_COIL(); - check_rm_request(tag); + int command = check_rm_request(tag); + if (command != PM3_SUCCESS) { + return command; + } SHORT_COIL(); wait_cycles(EM4X50_T_TAG_FULL_PERIOD); - return true; + return PM3_SUCCESS; } // simple login to EM4x50, @@ -1828,8 +1799,42 @@ void em4x50_sim(uint32_t *password) { em4x50_setup_sim(); gLogin = false; - // start with inital command = standard read mode (= 0) - em4x50_sim_handle_command(0, tag); + // start with inital command = standard read mode + int command = EM4X50_COMMAND_STANDARD_READ; + + for (;;) { + + switch (command) { + + case EM4X50_COMMAND_LOGIN: + command = em4x50_sim_handle_login_command(tag); + break; + + case EM4X50_COMMAND_RESET: + command = em4x50_sim_handle_reset_command(tag); + break; + + case EM4X50_COMMAND_WRITE: + command = em4x50_sim_handle_write_command(tag); + break; + + case EM4X50_COMMAND_WRITE_PASSWORD: + command = em4x50_sim_handle_writepwd_command(tag); + break; + + case EM4X50_COMMAND_SELECTIVE_READ: + command = em4x50_sim_handle_selective_read_command(tag); + break; + + default: + command = em4x50_sim_handle_standard_read_command(tag); + break; + } + + if (command == PM3_EOPABORTED) { + break; + } + } } else { status = PM3_ENODATA; From 1f085126702b634a1455030180e552eb8a460d96 Mon Sep 17 00:00:00 2001 From: tharexde Date: Tue, 12 Jan 2021 00:22:53 +0100 Subject: [PATCH 09/22] reduced use of timers and synchronized read actions --- armsrc/em4x50.c | 68 +++++++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 31 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index cb9b26485..a90d977ea 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -46,6 +46,7 @@ #define EM4X50_T_WAITING_FOR_SNGLLIW 140 #define EM4X50_TAG_TOLERANCE 8 +#define EM4X50_ZERO_DETECTION 3 #define EM4X50_TAG_WORD 45 #define EM4X50_TAG_MAX_NO_BYTES 136 @@ -60,15 +61,11 @@ int gHigh = 190; int gLow = 60; // a global parameter is needed to indicate whether a previous login was -// successful, so operations that require authentication may be performed +// successful, so operations that require authentication can be handled bool gLogin = false; // additionally a global variable to identify the WritePassword process bool gWritePasswordProcess = false; -int gcount = 0; -int gcycles = 0; -int rm = 0; - static int em4x50_sim_send_listen_window(uint32_t *tag); void catch_samples(void); @@ -812,35 +809,48 @@ static int wait_cycles(int maxperiods) { return PM3_SUCCESS; } - -static int get_cycles(void) { + +static uint8_t em4x50_sim_read_bit(void) { int cycles = 0; - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - while (AT91C_BASE_TC0->TC_CV < T0 * (EM4X50_T_TAG_FULL_PERIOD - 2)) { + while (cycles < EM4X50_T_TAG_FULL_PERIOD) { + // wait until reader field disappears while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); - // check again to minimize desynchronization - if (AT91C_BASE_TC0->TC_CV >= T0 * EM4X50_T_TAG_FULL_PERIOD) - break; + // reader field is off, reset timer TC0 + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); - + // now check until reader switches on carrier field + while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { + + // check if cycle (i.e. off -> on -> off) takes longer than T0 + if (AT91C_BASE_TC0->TC_CV > T0 * EM4X50_ZERO_DETECTION) { + + // gap detected; wait until reader field is switched on again + while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); + + // now we have a reference "position", from here it will take + // slightly less 32 cycles until the end of the bit period + wait_cycles(EM4X50_T_TAG_FULL_PERIOD - EM4X50_ZERO_DETECTION); + + // end of bit period is reached; return with bit value "0" + // (cf. datasheet) + return 0; + } + + } + + // no gap detected, i.e. reader field is still up; + // continue with counting cycles cycles++; } - return cycles; + // reached 64 cycles (= EM4X50_T_TAG_FULL_PERIOD) -> return bit value "1" + return 1; } - -static uint8_t em4x50_sim_read_bit(void) { - - int cond = EM4X50_T_TAG_FULL_PERIOD - EM4X50_TAG_TOLERANCE; - - return (get_cycles() < cond) ? 0 : 1; -} - + static uint8_t em4x50_sim_read_byte(void) { uint8_t byte = 0; @@ -954,8 +964,7 @@ static int em4x50_sim_handle_login_command(uint32_t *tag) { // read password uint32_t password = 0; bool pwd_ok = em4x50_sim_read_word(&password); - //Dbprintf("address = %08x", address); - wait_cycles(15); + //wait_cycles(15); // processing pause time (corresponds to a "1" bit) em4x50_sim_send_bit(1); @@ -1261,13 +1270,11 @@ static int em4x50_sim_handle_standard_read_command(uint32_t *tag) { // reader requests receive mode (rm) by sending two zeros static int check_rm_request(uint32_t *tag) { - int cond = EM4X50_T_TAG_FULL_PERIOD - EM4X50_TAG_TOLERANCE; - // look for first zero - if (get_cycles() < cond) { - + if (em4x50_sim_read_bit() == 0) { + // look for second zero - if (get_cycles() < cond) { + if (em4x50_sim_read_bit() == 0) { // if command before was EM4X50_COMMAND_WRITE_PASSWORD // switch to separate process @@ -1569,7 +1576,6 @@ void em4x50_info(em4x50_data_t *etd) { uint32_t addresses = 0x00002100; // read from fwr = 0 to lwr = 33 (0x21) uint32_t words[EM4X50_NO_WORDS] = {0x0}; - gcount = 0; em4x50_setup_read(); if (get_signalproperties() && find_em4x50_tag()) { From c15266dfc2fa8ca8f260cfb15dee60c15ee4db4c Mon Sep 17 00:00:00 2001 From: tharexde Date: Sat, 16 Jan 2021 01:59:02 +0100 Subject: [PATCH 10/22] added timeouts --- armsrc/em4x50.c | 255 ++++++++++++++++++++++----------------- client/src/cmdlfem4x50.c | 22 +++- 2 files changed, 159 insertions(+), 118 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index a90d977ea..80e675165 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -40,6 +40,7 @@ #define EM4X50_T_TAG_WAITING_FOR_SIGNAL 75 #define EM4X50_T_WAITING_FOR_DBLLIW 1550 #define EM4X50_T_WAITING_FOR_ACK 4 +//#define EM4X50_T_SIMULATION_TIMEOUT 100 // the following value seems to be critical; if it's too low (e.g. < 120) // some cards are no longer readable although they're ok @@ -669,62 +670,53 @@ static int get_word_from_bitstream(uint32_t *data) { return PM3_EOPABORTED; } -static bool em4x50_sim_send_bit(uint8_t bit) { +static int em4x50_sim_send_bit(uint8_t bit) { - uint16_t check = 0; + uint16_t timeout = EM4X50_T_TAG_FULL_PERIOD; for (int t = 0; t < EM4X50_T_TAG_FULL_PERIOD; t++) { // wait until SSC_CLK goes HIGH // used as a simple detection of a reader field? - while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) { - WDT_HIT(); - if (check == 1000) { - if (BUTTON_PRESS()) - return false; - check = 0; - } - ++check; + while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) && (timeout--)); + + if (timeout == 0) { + return PM3_ETIMEOUT; } + timeout = EM4X50_T_TAG_FULL_PERIOD; if (bit) OPEN_COIL(); else SHORT_COIL(); - check = 0; - //wait until SSC_CLK goes LOW - while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { - WDT_HIT(); - if (check == 1000) { - if (BUTTON_PRESS()) - return false; - check = 0; - } - ++check; + while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK && (timeout--)); + if (timeout == 0) { + return PM3_ETIMEOUT; } + timeout = EM4X50_T_TAG_FULL_PERIOD; if (t == EM4X50_T_TAG_HALF_PERIOD) bit ^= 1; } - return true; + return PM3_SUCCESS; } -static bool em4x50_sim_send_byte(uint8_t byte) { +static int em4x50_sim_send_byte(uint8_t byte) { // send byte for (int i = 0; i < 8; i++) - if (!em4x50_sim_send_bit((byte >> (7 - i)) & 1)) - return false; + if (em4x50_sim_send_bit((byte >> (7 - i)) & 1) == PM3_ETIMEOUT) + return PM3_ETIMEOUT; - return true; + return PM3_SUCCESS; } -static bool em4x50_sim_send_byte_with_parity(uint8_t byte) { +static int em4x50_sim_send_byte_with_parity(uint8_t byte) { uint8_t parity = 0x0; @@ -732,16 +724,18 @@ static bool em4x50_sim_send_byte_with_parity(uint8_t byte) { for (int i = 0; i < 8; i++) parity ^= (byte >> i) & 1; - if (em4x50_sim_send_byte(byte) == false) - return false;; + if (em4x50_sim_send_byte(byte) == PM3_ETIMEOUT) { + return PM3_ETIMEOUT; + } - if (em4x50_sim_send_bit(parity) == false) - return false; + if (em4x50_sim_send_bit(parity) == PM3_ETIMEOUT) { + return PM3_ETIMEOUT; + } - return true; + return PM3_SUCCESS; } -static bool em4x50_sim_send_word(uint32_t word) { +static int em4x50_sim_send_word(uint32_t word) { uint8_t cparity = 0x00; @@ -750,8 +744,8 @@ static bool em4x50_sim_send_word(uint32_t word) { // 4 bytes each with even row parity bit for (int i = 0; i < 4; i++) { - if (em4x50_sim_send_byte_with_parity((word >> ((3 - i) * 8)) & 0xFF) == false) { - return false; + if (em4x50_sim_send_byte_with_parity((word >> ((3 - i) * 8)) & 0xFF) == PM3_ETIMEOUT) { + return PM3_ETIMEOUT; } } @@ -762,47 +756,36 @@ static bool em4x50_sim_send_word(uint32_t word) { cparity ^= (((word >> ((3 - j) * 8)) & 0xFF) >> (7 - i)) & 1; } } - if (em4x50_sim_send_byte(cparity) == false) - return false; + if (em4x50_sim_send_byte(cparity) == PM3_ETIMEOUT) { + return PM3_ETIMEOUT; + } // stop bit - if (em4x50_sim_send_bit(0) == false) - return false; + if (em4x50_sim_send_bit(0) == PM3_ETIMEOUT) { + return PM3_ETIMEOUT; + } - return true; + return PM3_SUCCESS; } static int wait_cycles(int maxperiods) { - int period = 0, check = 0; + int EM4X50_T_SIMULATION_TIMEOUT = 500; + int period = 0, timeout = EM4X50_T_SIMULATION_TIMEOUT; while (period < maxperiods) { - while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) { - WDT_HIT(); - - if (check == 1000) { - if (BUTTON_PRESS()) { - return PM3_EOPABORTED; - } - check = 0; - } - ++check; + while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) && (timeout--)); + if (timeout <= 0) { + return PM3_ETIMEOUT; } - - check = 0; + timeout = EM4X50_T_SIMULATION_TIMEOUT; - while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { - WDT_HIT(); - - if (check == 1000) { - if (BUTTON_PRESS()) { - return PM3_EOPABORTED; - } - check = 0; - } - ++check; + while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK && (timeout--)); + if (timeout <= 0) { + return PM3_ETIMEOUT; } + timeout = EM4X50_T_SIMULATION_TIMEOUT; period++; } @@ -810,14 +793,21 @@ static int wait_cycles(int maxperiods) { return PM3_SUCCESS; } -static uint8_t em4x50_sim_read_bit(void) { +static int em4x50_sim_read_bit(void) { + int EM4X50_T_SIMULATION_TIMEOUT = 500; int cycles = 0; + int timeout1 = EM4X50_T_SIMULATION_TIMEOUT; + int timeout2 = EM4X50_T_SIMULATION_TIMEOUT; while (cycles < EM4X50_T_TAG_FULL_PERIOD) { // wait until reader field disappears - while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); + while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) && (timeout1--)); + if (timeout1 <= 0) { + return PM3_ETIMEOUT; + } + timeout1 = EM4X50_T_SIMULATION_TIMEOUT; // reader field is off, reset timer TC0 AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; @@ -829,12 +819,17 @@ static uint8_t em4x50_sim_read_bit(void) { if (AT91C_BASE_TC0->TC_CV > T0 * EM4X50_ZERO_DETECTION) { // gap detected; wait until reader field is switched on again - while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); + while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK && (timeout2--)); + if (timeout2 <= 0) { + return PM3_ETIMEOUT; + } + timeout2 = EM4X50_T_SIMULATION_TIMEOUT; + // now we have a reference "position", from here it will take // slightly less 32 cycles until the end of the bit period - wait_cycles(EM4X50_T_TAG_FULL_PERIOD - EM4X50_ZERO_DETECTION); - + wait_cycles(28); + // end of bit period is reached; return with bit value "0" // (cf. datasheet) return 0; @@ -851,46 +846,68 @@ static uint8_t em4x50_sim_read_bit(void) { return 1; } -static uint8_t em4x50_sim_read_byte(void) { +static int em4x50_sim_read_byte(void) { - uint8_t byte = 0; + int bit = 0, byte = 0; for (int i = 0; i < 8; i++) { byte <<= 1; - byte |= em4x50_sim_read_bit(); + bit = em4x50_sim_read_bit(); + if (bit == PM3_ETIMEOUT) { + return PM3_ETIMEOUT; + } + byte |= bit; } return byte; } -static bool em4x50_sim_read_byte_with_parity_check(uint8_t *byte) { +static int em4x50_sim_read_byte_with_parity_check(uint8_t *byte) { - uint8_t parity = 0, pval = 0; + int bit = 0, pval = 0; + uint8_t parity = 0; for (int i = 0; i < 8; i++) { *byte <<= 1; - *byte |= em4x50_sim_read_bit(); + bit = em4x50_sim_read_bit(); + if (bit == PM3_ETIMEOUT) { + return PM3_ETIMEOUT; + } + *byte |= bit; + parity ^= ((*byte) & 1); } pval = em4x50_sim_read_bit(); + if (pval == PM3_ETIMEOUT) { + return PM3_ETIMEOUT; + } - return (parity == pval); + return (parity == pval) ? PM3_SUCCESS : PM3_EFAILED; } -static bool em4x50_sim_read_word(uint32_t *word) { +static int em4x50_sim_read_word(uint32_t *word) { - uint8_t parities = 0, parities_calculated = 0, stop_bit = 0; + int stop_bit = 0; + int parities = 0, parities_calculated = 0; uint8_t bytes[4] = {0}; // read plain data for (int i = 0; i < 4; i++) { - em4x50_sim_read_byte_with_parity_check(&bytes[i]); + if (em4x50_sim_read_byte_with_parity_check(&bytes[i]) != PM3_SUCCESS) { + return PM3_ETIMEOUT; + } } // read column parities and stop bit parities = em4x50_sim_read_byte(); + if (parities == PM3_ETIMEOUT) { + return PM3_ETIMEOUT; + } stop_bit = em4x50_sim_read_bit(); + if (stop_bit == PM3_ETIMEOUT) { + return PM3_ETIMEOUT; + } // calculate column parities from data for (int i = 0; i < 8; i++) { @@ -904,10 +921,10 @@ static bool em4x50_sim_read_word(uint32_t *word) { // check parities if ((parities == parities_calculated) && (stop_bit == 0)) { - return true; + return PM3_SUCCESS; } - return false; + return PM3_EFAILED; } static void em4x50_sim_send_ack(void) { @@ -963,7 +980,9 @@ static int em4x50_sim_handle_login_command(uint32_t *tag) { // read password uint32_t password = 0; - bool pwd_ok = em4x50_sim_read_word(&password); + int pwd = em4x50_sim_read_word(&password); + + em4x50_sim_read_word(&password); //wait_cycles(15); // processing pause time (corresponds to a "1" bit) @@ -972,14 +991,13 @@ static int em4x50_sim_handle_login_command(uint32_t *tag) { // empirically determined delay (to be examined seperately) wait_cycles(1); - if (pwd_ok && (password == reflect32(tag[EM4X50_DEVICE_PASSWORD]))) { + if ((pwd == PM3_SUCCESS) && (password == reflect32(tag[EM4X50_DEVICE_PASSWORD]))) { em4x50_sim_send_ack(); gLogin = true; } else { em4x50_sim_send_nak(); gLogin = false; } - // continue with standard read mode return EM4X50_COMMAND_STANDARD_READ; } @@ -1004,15 +1022,15 @@ static int em4x50_sim_handle_write_command(uint32_t *tag) { // read address uint8_t address = 0; - bool addr_ok = em4x50_sim_read_byte_with_parity_check(&address); + int addr = em4x50_sim_read_byte_with_parity_check(&address); // read data uint32_t data = 0; - bool word_ok = em4x50_sim_read_word(&data); + int word = em4x50_sim_read_word(&data); // write access time wait_cycles(EM4X50_T_TAG_TWA); - if ((addr_ok == false) || (word_ok == false)) { + if ((addr != PM3_SUCCESS) || (word != PM3_SUCCESS)) { em4x50_sim_send_nak(); return EM4X50_COMMAND_STANDARD_READ; } @@ -1103,7 +1121,7 @@ static int em4x50_sim_handle_write_command(uint32_t *tag) { static int em4x50_sim_handle_writepwd_command(uint32_t *tag) { - bool pwd_ok = false; + int pwd = 0; if (gWritePasswordProcess == false) { @@ -1111,14 +1129,14 @@ static int em4x50_sim_handle_writepwd_command(uint32_t *tag) { // read password uint32_t act_password = 0; - pwd_ok = em4x50_sim_read_word(&act_password); + pwd = em4x50_sim_read_word(&act_password); - wait_cycles(15); + //wait_cycles(15); // processing pause time (corresponds to a "1" bit) em4x50_sim_send_bit(1); - if (pwd_ok && (act_password == reflect32(tag[EM4X50_DEVICE_PASSWORD]))) { + if ((pwd == PM3_SUCCESS) && (act_password == reflect32(tag[EM4X50_DEVICE_PASSWORD]))) { em4x50_sim_send_ack(); gLogin = true; } else { @@ -1138,19 +1156,20 @@ static int em4x50_sim_handle_writepwd_command(uint32_t *tag) { // read new password uint32_t new_password = 0; - pwd_ok = em4x50_sim_read_word(&new_password); - + pwd = em4x50_sim_read_word(&new_password); + // write access time wait_cycles(EM4X50_T_TAG_TWA); - if (pwd_ok) { + if (pwd == PM3_SUCCESS) { em4x50_sim_send_ack(); tag[EM4X50_DEVICE_PASSWORD] = reflect32(new_password); } else { em4x50_sim_send_ack(); return EM4X50_COMMAND_STANDARD_READ; } - //OPEN_COIL(); + + //wait_cycles(15); // EEPROM write time wait_cycles(EM4X50_T_TAG_TWEE); @@ -1158,7 +1177,7 @@ static int em4x50_sim_handle_writepwd_command(uint32_t *tag) { // strange: need some sort of 'waveform correction', otherwise ack signal // will not be detected; sending a single "1" seems to solve the problem em4x50_sim_send_bit(1); - + em4x50_sim_send_ack(); // continue with standard read mode @@ -1171,17 +1190,17 @@ static int em4x50_sim_handle_writepwd_command(uint32_t *tag) { static int em4x50_sim_handle_selective_read_command(uint32_t *tag) { - int command = PM3_EOPABORTED; + int command = 0; // read password uint32_t address = 0; - bool addr_ok = em4x50_sim_read_word(&address); - wait_cycles(15); + int addr = em4x50_sim_read_word(&address); + //wait_cycles(15); // processing pause time (corresponds to a "1" bit) em4x50_sim_send_bit(1); - if (addr_ok) { + if (addr == PM3_SUCCESS) { em4x50_sim_send_ack(); } else { em4x50_sim_send_nak(); @@ -1224,12 +1243,12 @@ static int em4x50_sim_handle_selective_read_command(uint32_t *tag) { } } - return command; + return PM3_EOPABORTED; } static int em4x50_sim_handle_standard_read_command(uint32_t *tag) { - int command = PM3_EOPABORTED; + int command = 0; // extract control data int fwr = reflect32(tag[EM4X50_CONTROL]) & 0xFF; // first word read @@ -1264,17 +1283,20 @@ static int em4x50_sim_handle_standard_read_command(uint32_t *tag) { } } } - return command; + + return PM3_EOPABORTED; } // reader requests receive mode (rm) by sending two zeros static int check_rm_request(uint32_t *tag) { // look for first zero - if (em4x50_sim_read_bit() == 0) { + int bit = em4x50_sim_read_bit(); + if (bit == 0) { // look for second zero - if (em4x50_sim_read_bit() == 0) { + bit = em4x50_sim_read_bit(); + if (bit == 0) { // if command before was EM4X50_COMMAND_WRITE_PASSWORD // switch to separate process @@ -1289,7 +1311,7 @@ static int check_rm_request(uint32_t *tag) { } } - return PM3_SUCCESS; + return (bit != PM3_ETIMEOUT) ? PM3_SUCCESS : PM3_ETIMEOUT; } static int em4x50_sim_send_listen_window(uint32_t *tag) { @@ -1785,7 +1807,7 @@ void em4x50_writepwd(em4x50_data_t *etd) { // simulate uploaded data in emulator memory void em4x50_sim(uint32_t *password) { - int status = PM3_SUCCESS; + int command = PM3_ENODATA; uint8_t *em4x50_mem = BigBuf_get_EM_addr(); uint32_t tag[EM4X50_NO_WORDS] = {0x0}; @@ -1806,10 +1828,14 @@ void em4x50_sim(uint32_t *password) { gLogin = false; // start with inital command = standard read mode - int command = EM4X50_COMMAND_STANDARD_READ; + command = EM4X50_COMMAND_STANDARD_READ; for (;;) { + if (data_available()) { + command = PM3_EOPABORTED; + } + switch (command) { case EM4X50_COMMAND_LOGIN: @@ -1831,24 +1857,25 @@ void em4x50_sim(uint32_t *password) { case EM4X50_COMMAND_SELECTIVE_READ: command = em4x50_sim_handle_selective_read_command(tag); break; - - default: + + case EM4X50_COMMAND_STANDARD_READ: command = em4x50_sim_handle_standard_read_command(tag); break; } - + if (command == PM3_EOPABORTED) { break; } + + if (command == PM3_ETIMEOUT) { + command = EM4X50_COMMAND_STANDARD_READ; + } } - - } else { - status = PM3_ENODATA; } - + BigBuf_free(); lf_finalize(); - reply_ng(CMD_LF_EM4X50_SIM, status, NULL, 0); + reply_ng(CMD_LF_EM4X50_SIM, command, NULL, 0); } void em4x50_test(em4x50_test_t *ett) { diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 3aea9e981..f71696268 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -1249,11 +1249,25 @@ int CmdEM4x50Sim(const char *Cmd) { clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_SIM, (uint8_t *)&password, sizeof(password)); PacketResponseNG resp; - WaitForResponse(CMD_LF_EM4X50_SIM, &resp); - if (resp.status == PM3_SUCCESS) - PrintAndLogEx(INFO, "Done"); + + PrintAndLogEx(INFO, "Press pm3-button to abort simulation"); + bool keypress = kbd_enter_pressed(); + while (keypress == false) { + keypress = kbd_enter_pressed(); + + if (WaitForResponseTimeout(CMD_LF_EM4X50_SIM, &resp, 1500)) { + break; + } + + } + if (keypress) { + SendCommandNG(CMD_BREAK_LOOP, NULL, 0); + } + + if ((resp.status == PM3_SUCCESS) || (resp.status == PM3_EOPABORTED)) + PrintAndLogEx(SUCCESS, "Done"); else - PrintAndLogEx(FAILED, "No valid em4x50 data in memory."); + PrintAndLogEx(FAILED, "No valid em4x50 data in memory"); return resp.status; } From cff48f84c6f9fa1ae65ed872b0d916ad8bf052fd Mon Sep 17 00:00:00 2001 From: tharexde Date: Sat, 16 Jan 2021 19:40:42 +0100 Subject: [PATCH 11/22] refactoring --- armsrc/em4x50.c | 70 +++++++++++----------------------------- client/src/cmdlfem4x50.c | 7 ++-- 2 files changed, 23 insertions(+), 54 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 80e675165..b0bbe827e 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -708,9 +708,9 @@ static int em4x50_sim_send_bit(uint8_t bit) { static int em4x50_sim_send_byte(uint8_t byte) { // send byte - for (int i = 0; i < 8; i++) - if (em4x50_sim_send_bit((byte >> (7 - i)) & 1) == PM3_ETIMEOUT) - return PM3_ETIMEOUT; + for (int i = 0; i < 8; i++) { + em4x50_sim_send_bit((byte >> (7 - i)) & 1); + } return PM3_SUCCESS; @@ -724,13 +724,8 @@ static int em4x50_sim_send_byte_with_parity(uint8_t byte) { for (int i = 0; i < 8; i++) parity ^= (byte >> i) & 1; - if (em4x50_sim_send_byte(byte) == PM3_ETIMEOUT) { - return PM3_ETIMEOUT; - } - - if (em4x50_sim_send_bit(parity) == PM3_ETIMEOUT) { - return PM3_ETIMEOUT; - } + em4x50_sim_send_byte(byte); + em4x50_sim_send_bit(parity); return PM3_SUCCESS; } @@ -744,9 +739,7 @@ static int em4x50_sim_send_word(uint32_t word) { // 4 bytes each with even row parity bit for (int i = 0; i < 4; i++) { - if (em4x50_sim_send_byte_with_parity((word >> ((3 - i) * 8)) & 0xFF) == PM3_ETIMEOUT) { - return PM3_ETIMEOUT; - } + em4x50_sim_send_byte_with_parity((word >> ((3 - i) * 8)) & 0xFF); } // column parity @@ -756,14 +749,10 @@ static int em4x50_sim_send_word(uint32_t word) { cparity ^= (((word >> ((3 - j) * 8)) & 0xFF) >> (7 - i)) & 1; } } - if (em4x50_sim_send_byte(cparity) == PM3_ETIMEOUT) { - return PM3_ETIMEOUT; - } + em4x50_sim_send_byte(cparity); // stop bit - if (em4x50_sim_send_bit(0) == PM3_ETIMEOUT) { - return PM3_ETIMEOUT; - } + em4x50_sim_send_bit(0); return PM3_SUCCESS; } @@ -848,15 +837,11 @@ static int em4x50_sim_read_bit(void) { static int em4x50_sim_read_byte(void) { - int bit = 0, byte = 0; + int byte = 0; for (int i = 0; i < 8; i++) { byte <<= 1; - bit = em4x50_sim_read_bit(); - if (bit == PM3_ETIMEOUT) { - return PM3_ETIMEOUT; - } - byte |= bit; + byte |= em4x50_sim_read_bit(); } return byte; @@ -864,24 +849,16 @@ static int em4x50_sim_read_byte(void) { static int em4x50_sim_read_byte_with_parity_check(uint8_t *byte) { - int bit = 0, pval = 0; + int pval = 0; uint8_t parity = 0; for (int i = 0; i < 8; i++) { *byte <<= 1; - bit = em4x50_sim_read_bit(); - if (bit == PM3_ETIMEOUT) { - return PM3_ETIMEOUT; - } - *byte |= bit; - + *byte |= em4x50_sim_read_bit(); parity ^= ((*byte) & 1); } pval = em4x50_sim_read_bit(); - if (pval == PM3_ETIMEOUT) { - return PM3_ETIMEOUT; - } return (parity == pval) ? PM3_SUCCESS : PM3_EFAILED; } @@ -894,20 +871,12 @@ static int em4x50_sim_read_word(uint32_t *word) { // read plain data for (int i = 0; i < 4; i++) { - if (em4x50_sim_read_byte_with_parity_check(&bytes[i]) != PM3_SUCCESS) { - return PM3_ETIMEOUT; - } + em4x50_sim_read_byte_with_parity_check(&bytes[i]); } - + // read column parities and stop bit parities = em4x50_sim_read_byte(); - if (parities == PM3_ETIMEOUT) { - return PM3_ETIMEOUT; - } stop_bit = em4x50_sim_read_bit(); - if (stop_bit == PM3_ETIMEOUT) { - return PM3_ETIMEOUT; - } // calculate column parities from data for (int i = 0; i < 8; i++) { @@ -1217,8 +1186,7 @@ static int em4x50_sim_handle_selective_read_command(uint32_t *tag) { // last word read protected int lwrp = (reflect32(tag[EM4X50_PROTECTION]) >> 8) & 0xFF; - // iceman, will need a usb cmd check to break as well - while (BUTTON_PRESS() == false) { + while ((BUTTON_PRESS() == false) && (data_available() == false)) { WDT_HIT(); @@ -1260,7 +1228,7 @@ static int em4x50_sim_handle_standard_read_command(uint32_t *tag) { int lwrp = (reflect32(tag[EM4X50_PROTECTION]) >> 8) & 0xFF; // iceman, will need a usb cmd check to break as well - while (BUTTON_PRESS() == false) { + while ((BUTTON_PRESS() == false) && (data_available() == false)) { WDT_HIT(); @@ -1832,10 +1800,6 @@ void em4x50_sim(uint32_t *password) { for (;;) { - if (data_available()) { - command = PM3_EOPABORTED; - } - switch (command) { case EM4X50_COMMAND_LOGIN: @@ -1863,10 +1827,12 @@ void em4x50_sim(uint32_t *password) { break; } + // stop if key (pm3 button or enter key) has been pressed if (command == PM3_EOPABORTED) { break; } + // if timeout (e.g. no reader field) go on with standard read mode if (command == PM3_ETIMEOUT) { command = EM4X50_COMMAND_STANDARD_READ; } diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index f71696268..908ab3bfa 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -1212,6 +1212,7 @@ int CmdEM4x50Restore(const char *Cmd) { int CmdEM4x50Sim(const char *Cmd) { + int status = PM3_EFAILED; uint32_t password = 0; CLIParserContext *ctx; @@ -1256,16 +1257,18 @@ int CmdEM4x50Sim(const char *Cmd) { keypress = kbd_enter_pressed(); if (WaitForResponseTimeout(CMD_LF_EM4X50_SIM, &resp, 1500)) { + status = resp.status; break; } } if (keypress) { SendCommandNG(CMD_BREAK_LOOP, NULL, 0); + status = PM3_EOPABORTED; } - if ((resp.status == PM3_SUCCESS) || (resp.status == PM3_EOPABORTED)) - PrintAndLogEx(SUCCESS, "Done"); + if ((status == PM3_SUCCESS) || (status == PM3_EOPABORTED)) + PrintAndLogEx(INFO, "Done"); else PrintAndLogEx(FAILED, "No valid em4x50 data in memory"); From 03d56596cb8811abe0d4eaa0cc085191cbcebcca Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 17 Jan 2021 00:27:08 +0100 Subject: [PATCH 12/22] clean up --- armsrc/em4x50.c | 189 +++++++++++++++++++++++++----------------------- 1 file changed, 97 insertions(+), 92 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index b0bbe827e..eed22bb96 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -40,7 +40,8 @@ #define EM4X50_T_TAG_WAITING_FOR_SIGNAL 75 #define EM4X50_T_WAITING_FOR_DBLLIW 1550 #define EM4X50_T_WAITING_FOR_ACK 4 -//#define EM4X50_T_SIMULATION_TIMEOUT 100 +#define EM4X50_T_SIMULATION_TIMEOUT_READ 400 +#define EM4X50_T_SIMULATION_TIMEOUT_WAIT 50 // the following value seems to be critical; if it's too low (e.g. < 120) // some cards are no longer readable although they're ok @@ -221,6 +222,8 @@ static void em4x50_setup_sim(void) { // Watchdog hit WDT_HIT(); + + LEDsoff(); } // calculate signal properties (mean amplitudes) from measured data: @@ -670,7 +673,7 @@ static int get_word_from_bitstream(uint32_t *data) { return PM3_EOPABORTED; } -static int em4x50_sim_send_bit(uint8_t bit) { +static void em4x50_sim_send_bit(uint8_t bit) { uint16_t timeout = EM4X50_T_TAG_FULL_PERIOD; @@ -681,7 +684,7 @@ static int em4x50_sim_send_bit(uint8_t bit) { while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) && (timeout--)); if (timeout == 0) { - return PM3_ETIMEOUT; + return; } timeout = EM4X50_T_TAG_FULL_PERIOD; @@ -693,7 +696,7 @@ static int em4x50_sim_send_bit(uint8_t bit) { //wait until SSC_CLK goes LOW while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK && (timeout--)); if (timeout == 0) { - return PM3_ETIMEOUT; + return; } timeout = EM4X50_T_TAG_FULL_PERIOD; @@ -701,36 +704,28 @@ static int em4x50_sim_send_bit(uint8_t bit) { bit ^= 1; } - - return PM3_SUCCESS; } -static int em4x50_sim_send_byte(uint8_t byte) { +static void em4x50_sim_send_byte(uint8_t byte, bool paritycheck) { // send byte for (int i = 0; i < 8; i++) { em4x50_sim_send_bit((byte >> (7 - i)) & 1); } - return PM3_SUCCESS; + if (paritycheck) { + uint8_t parity = 0x0; + + for (int i = 0; i < 8; i++) { + parity ^= (byte >> i) & 1; + } + + em4x50_sim_send_bit(parity); + } } -static int em4x50_sim_send_byte_with_parity(uint8_t byte) { - - uint8_t parity = 0x0; - - // send byte with parity (even) - for (int i = 0; i < 8; i++) - parity ^= (byte >> i) & 1; - - em4x50_sim_send_byte(byte); - em4x50_sim_send_bit(parity); - - return PM3_SUCCESS; -} - -static int em4x50_sim_send_word(uint32_t word) { +static void em4x50_sim_send_word(uint32_t word) { uint8_t cparity = 0x00; @@ -739,7 +734,7 @@ static int em4x50_sim_send_word(uint32_t word) { // 4 bytes each with even row parity bit for (int i = 0; i < 4; i++) { - em4x50_sim_send_byte_with_parity((word >> ((3 - i) * 8)) & 0xFF); + em4x50_sim_send_byte((word >> ((3 - i) * 8)) & 0xFF, true); } // column parity @@ -749,56 +744,44 @@ static int em4x50_sim_send_word(uint32_t word) { cparity ^= (((word >> ((3 - j) * 8)) & 0xFF) >> (7 - i)) & 1; } } - em4x50_sim_send_byte(cparity); + em4x50_sim_send_byte(cparity, false); // stop bit em4x50_sim_send_bit(0); - - return PM3_SUCCESS; } -static int wait_cycles(int maxperiods) { +static void wait_cycles(int maxperiods) { - int EM4X50_T_SIMULATION_TIMEOUT = 500; - int period = 0, timeout = EM4X50_T_SIMULATION_TIMEOUT; + int period = 0, timeout = EM4X50_T_SIMULATION_TIMEOUT_WAIT; while (period < maxperiods) { while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) && (timeout--)); if (timeout <= 0) { - return PM3_ETIMEOUT; + return; } - timeout = EM4X50_T_SIMULATION_TIMEOUT; + timeout = EM4X50_T_SIMULATION_TIMEOUT_WAIT; while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK && (timeout--)); if (timeout <= 0) { - return PM3_ETIMEOUT; + return; } - timeout = EM4X50_T_SIMULATION_TIMEOUT; + timeout = EM4X50_T_SIMULATION_TIMEOUT_WAIT; period++; } - - return PM3_SUCCESS; } static int em4x50_sim_read_bit(void) { - int EM4X50_T_SIMULATION_TIMEOUT = 500; int cycles = 0; - int timeout1 = EM4X50_T_SIMULATION_TIMEOUT; - int timeout2 = EM4X50_T_SIMULATION_TIMEOUT; + int timeout = EM4X50_T_SIMULATION_TIMEOUT_READ; while (cycles < EM4X50_T_TAG_FULL_PERIOD) { // wait until reader field disappears - while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) && (timeout1--)); - if (timeout1 <= 0) { - return PM3_ETIMEOUT; - } - timeout1 = EM4X50_T_SIMULATION_TIMEOUT; + while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); - // reader field is off, reset timer TC0 AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; // now check until reader switches on carrier field @@ -808,15 +791,15 @@ static int em4x50_sim_read_bit(void) { if (AT91C_BASE_TC0->TC_CV > T0 * EM4X50_ZERO_DETECTION) { // gap detected; wait until reader field is switched on again - while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK && (timeout2--)); + while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK && (timeout--)); - if (timeout2 <= 0) { + if (timeout <= 0) { return PM3_ETIMEOUT; } - timeout2 = EM4X50_T_SIMULATION_TIMEOUT; + timeout = EM4X50_T_SIMULATION_TIMEOUT_READ; // now we have a reference "position", from here it will take - // slightly less 32 cycles until the end of the bit period + // slightly less than 32 cycles until the end of the bit period wait_cycles(28); // end of bit period is reached; return with bit value "0" @@ -834,48 +817,45 @@ static int em4x50_sim_read_bit(void) { // reached 64 cycles (= EM4X50_T_TAG_FULL_PERIOD) -> return bit value "1" return 1; } - -static int em4x50_sim_read_byte(void) { - - int byte = 0; - - for (int i = 0; i < 8; i++) { - byte <<= 1; - byte |= em4x50_sim_read_bit(); - } - - return byte; -} -static int em4x50_sim_read_byte_with_parity_check(uint8_t *byte) { - - int pval = 0; - uint8_t parity = 0; +static bool em4x50_sim_read_byte(uint8_t *byte, bool paritycheck) { for (int i = 0; i < 8; i++) { *byte <<= 1; *byte |= em4x50_sim_read_bit(); - parity ^= ((*byte) & 1); } - pval = em4x50_sim_read_bit(); + if (paritycheck) { - return (parity == pval) ? PM3_SUCCESS : PM3_EFAILED; + int pval = em4x50_sim_read_bit(); + uint8_t parity = 0; + + for (int i = 0; i < 8; i++) { + parity ^= ((*byte) >> i) & 1; + } + + if (parity != pval) { + return false; + } + } + + return true; + } -static int em4x50_sim_read_word(uint32_t *word) { +static bool em4x50_sim_read_word(uint32_t *word) { - int stop_bit = 0; - int parities = 0, parities_calculated = 0; + uint8_t stop_bit = 0; + uint8_t parities = 0, parities_calculated = 0; uint8_t bytes[4] = {0}; // read plain data for (int i = 0; i < 4; i++) { - em4x50_sim_read_byte_with_parity_check(&bytes[i]); + em4x50_sim_read_byte(&bytes[i], true); } // read column parities and stop bit - parities = em4x50_sim_read_byte(); + em4x50_sim_read_byte(&parities, false); stop_bit = em4x50_sim_read_bit(); // calculate column parities from data @@ -890,10 +870,10 @@ static int em4x50_sim_read_word(uint32_t *word) { // check parities if ((parities == parities_calculated) && (stop_bit == 0)) { - return PM3_SUCCESS; + return true; } - return PM3_EFAILED; + return false; } static void em4x50_sim_send_ack(void) { @@ -949,9 +929,11 @@ static int em4x50_sim_handle_login_command(uint32_t *tag) { // read password uint32_t password = 0; - int pwd = em4x50_sim_read_word(&password); + bool pwd = em4x50_sim_read_word(&password); + + // signal that reader sent the password + LED_D_ON(); - em4x50_sim_read_word(&password); //wait_cycles(15); // processing pause time (corresponds to a "1" bit) @@ -960,12 +942,14 @@ static int em4x50_sim_handle_login_command(uint32_t *tag) { // empirically determined delay (to be examined seperately) wait_cycles(1); - if ((pwd == PM3_SUCCESS) && (password == reflect32(tag[EM4X50_DEVICE_PASSWORD]))) { + if (pwd && (password == reflect32(tag[EM4X50_DEVICE_PASSWORD]))) { em4x50_sim_send_ack(); gLogin = true; + LED_A_ON(); } else { em4x50_sim_send_nak(); gLogin = false; + LED_A_OFF(); } // continue with standard read mode return EM4X50_COMMAND_STANDARD_READ; @@ -991,15 +975,15 @@ static int em4x50_sim_handle_write_command(uint32_t *tag) { // read address uint8_t address = 0; - int addr = em4x50_sim_read_byte_with_parity_check(&address); + bool addr = em4x50_sim_read_byte(&address, true); // read data uint32_t data = 0; - int word = em4x50_sim_read_word(&data); + bool word = em4x50_sim_read_word(&data); // write access time wait_cycles(EM4X50_T_TAG_TWA); - if ((addr != PM3_SUCCESS) || (word != PM3_SUCCESS)) { + if ((addr == false) || (word == false)) { em4x50_sim_send_nak(); return EM4X50_COMMAND_STANDARD_READ; } @@ -1051,8 +1035,13 @@ static int em4x50_sim_handle_write_command(uint32_t *tag) { default: if ((address >= fwwp) && (address <= lwwp) && (gLogin == false)) { - em4x50_sim_send_nak(); - return EM4X50_COMMAND_STANDARD_READ; + if (gLogin) { + tag[address] = reflect32(data); + em4x50_sim_send_ack(); + } else { + em4x50_sim_send_nak(); + return EM4X50_COMMAND_STANDARD_READ; + } } else { tag[address] = reflect32(data); em4x50_sim_send_ack(); @@ -1090,7 +1079,7 @@ static int em4x50_sim_handle_write_command(uint32_t *tag) { static int em4x50_sim_handle_writepwd_command(uint32_t *tag) { - int pwd = 0; + bool pwd = false; if (gWritePasswordProcess == false) { @@ -1105,7 +1094,7 @@ static int em4x50_sim_handle_writepwd_command(uint32_t *tag) { // processing pause time (corresponds to a "1" bit) em4x50_sim_send_bit(1); - if ((pwd == PM3_SUCCESS) && (act_password == reflect32(tag[EM4X50_DEVICE_PASSWORD]))) { + if (pwd && (act_password == reflect32(tag[EM4X50_DEVICE_PASSWORD]))) { em4x50_sim_send_ack(); gLogin = true; } else { @@ -1130,7 +1119,7 @@ static int em4x50_sim_handle_writepwd_command(uint32_t *tag) { // write access time wait_cycles(EM4X50_T_TAG_TWA); - if (pwd == PM3_SUCCESS) { + if (pwd) { em4x50_sim_send_ack(); tag[EM4X50_DEVICE_PASSWORD] = reflect32(new_password); } else { @@ -1163,13 +1152,13 @@ static int em4x50_sim_handle_selective_read_command(uint32_t *tag) { // read password uint32_t address = 0; - int addr = em4x50_sim_read_word(&address); + bool addr = em4x50_sim_read_word(&address); //wait_cycles(15); // processing pause time (corresponds to a "1" bit) em4x50_sim_send_bit(1); - if (addr == PM3_SUCCESS) { + if (addr) { em4x50_sim_send_ack(); } else { em4x50_sim_send_nak(); @@ -1217,7 +1206,7 @@ static int em4x50_sim_handle_selective_read_command(uint32_t *tag) { static int em4x50_sim_handle_standard_read_command(uint32_t *tag) { int command = 0; - + // extract control data int fwr = reflect32(tag[EM4X50_CONTROL]) & 0xFF; // first word read int lwr = (reflect32(tag[EM4X50_CONTROL]) >> 8) & 0xFF; // last word read @@ -1244,7 +1233,7 @@ static int em4x50_sim_handle_standard_read_command(uint32_t *tag) { return command; } - if ((i >= fwrp) && (i <= lwrp)) { + if ((gLogin == false) && (i >= fwrp) && (i <= lwrp)) { em4x50_sim_send_word(0x00); } else { em4x50_sim_send_word(reflect32(tag[i])); @@ -1273,7 +1262,7 @@ static int check_rm_request(uint32_t *tag) { } else { // read mode request detected, get command from reader uint8_t command = 0; - em4x50_sim_read_byte_with_parity_check(&command); + em4x50_sim_read_byte(&command, true); return command; } } @@ -1773,6 +1762,10 @@ void em4x50_writepwd(em4x50_data_t *etd) { } // simulate uploaded data in emulator memory +// LED A -> operations that require authentication are possible +// LED B -> standard read mode is active +// LED C -> command has been transmitted by reader +// LED D -> password has been caught from reader void em4x50_sim(uint32_t *password) { int command = PM3_ENODATA; @@ -1803,26 +1796,38 @@ void em4x50_sim(uint32_t *password) { switch (command) { case EM4X50_COMMAND_LOGIN: + LED_B_OFF(); + LED_C_OFF(); command = em4x50_sim_handle_login_command(tag); break; case EM4X50_COMMAND_RESET: + LED_B_OFF(); + LED_C_OFF(); command = em4x50_sim_handle_reset_command(tag); break; case EM4X50_COMMAND_WRITE: + LED_B_OFF(); + LED_C_OFF(); command = em4x50_sim_handle_write_command(tag); break; case EM4X50_COMMAND_WRITE_PASSWORD: + LED_B_OFF(); + LED_C_OFF(); command = em4x50_sim_handle_writepwd_command(tag); break; case EM4X50_COMMAND_SELECTIVE_READ: + LED_B_OFF(); + LED_C_ON(); command = em4x50_sim_handle_selective_read_command(tag); break; case EM4X50_COMMAND_STANDARD_READ: + LED_B_ON(); + LED_C_OFF(); command = em4x50_sim_handle_standard_read_command(tag); break; } @@ -1832,7 +1837,7 @@ void em4x50_sim(uint32_t *password) { break; } - // if timeout (e.g. no reader field) go on with standard read mode + // if timeout (e.g. no reader field) continue with standard read mode if (command == PM3_ETIMEOUT) { command = EM4X50_COMMAND_STANDARD_READ; } From 473d89342b7ab2bfad28787d65b51d9e993469e7 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 17 Jan 2021 23:35:21 +0100 Subject: [PATCH 13/22] rearrangements --- armsrc/em4x50.c | 1264 ++++++++++++++++++++++++----------------------- 1 file changed, 637 insertions(+), 627 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index eed22bb96..9d9da9a8d 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -40,8 +40,8 @@ #define EM4X50_T_TAG_WAITING_FOR_SIGNAL 75 #define EM4X50_T_WAITING_FOR_DBLLIW 1550 #define EM4X50_T_WAITING_FOR_ACK 4 -#define EM4X50_T_SIMULATION_TIMEOUT_READ 400 -#define EM4X50_T_SIMULATION_TIMEOUT_WAIT 50 +#define EM4X50_T_SIMULATION_TIMEOUT_READ 5000 // 400 +#define EM4X50_T_SIMULATION_TIMEOUT_WAIT 5000 // 50 // the following value seems to be critical; if it's too low (e.g. < 120) // some cards are no longer readable although they're ok @@ -62,10 +62,12 @@ int gHigh = 190; int gLow = 60; -// a global parameter is needed to indicate whether a previous login was -// successful, so operations that require authentication can be handled +// indication whether a previous login has been successful, so operations +// that require authentication can be handled bool gLogin = false; -// additionally a global variable to identify the WritePassword process +// WritePassword process in simulation mode is handled in a different way +// compared to operations like read, write, login, so it is necessary to +// to be able to identfiy it bool gWritePasswordProcess = false; static int em4x50_sim_send_listen_window(uint32_t *tag); @@ -673,627 +675,6 @@ static int get_word_from_bitstream(uint32_t *data) { return PM3_EOPABORTED; } -static void em4x50_sim_send_bit(uint8_t bit) { - - uint16_t timeout = EM4X50_T_TAG_FULL_PERIOD; - - for (int t = 0; t < EM4X50_T_TAG_FULL_PERIOD; t++) { - - // wait until SSC_CLK goes HIGH - // used as a simple detection of a reader field? - while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) && (timeout--)); - - if (timeout == 0) { - return; - } - timeout = EM4X50_T_TAG_FULL_PERIOD; - - if (bit) - OPEN_COIL(); - else - SHORT_COIL(); - - //wait until SSC_CLK goes LOW - while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK && (timeout--)); - if (timeout == 0) { - return; - } - timeout = EM4X50_T_TAG_FULL_PERIOD; - - if (t == EM4X50_T_TAG_HALF_PERIOD) - bit ^= 1; - - } -} - -static void em4x50_sim_send_byte(uint8_t byte, bool paritycheck) { - - // send byte - for (int i = 0; i < 8; i++) { - em4x50_sim_send_bit((byte >> (7 - i)) & 1); - } - - if (paritycheck) { - - uint8_t parity = 0x0; - - for (int i = 0; i < 8; i++) { - parity ^= (byte >> i) & 1; - } - - em4x50_sim_send_bit(parity); - } -} - -static void em4x50_sim_send_word(uint32_t word) { - - uint8_t cparity = 0x00; - - // word has tobe sent in msb, not lsb - word = reflect32(word); - - // 4 bytes each with even row parity bit - for (int i = 0; i < 4; i++) { - em4x50_sim_send_byte((word >> ((3 - i) * 8)) & 0xFF, true); - } - - // column parity - for (int i = 0; i < 8; i++) { - cparity <<= 1; - for (int j = 0; j < 4; j++) { - cparity ^= (((word >> ((3 - j) * 8)) & 0xFF) >> (7 - i)) & 1; - } - } - em4x50_sim_send_byte(cparity, false); - - // stop bit - em4x50_sim_send_bit(0); -} - -static void wait_cycles(int maxperiods) { - - int period = 0, timeout = EM4X50_T_SIMULATION_TIMEOUT_WAIT; - - while (period < maxperiods) { - - while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) && (timeout--)); - if (timeout <= 0) { - return; - } - timeout = EM4X50_T_SIMULATION_TIMEOUT_WAIT; - - while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK && (timeout--)); - if (timeout <= 0) { - return; - } - timeout = EM4X50_T_SIMULATION_TIMEOUT_WAIT; - - period++; - } -} - -static int em4x50_sim_read_bit(void) { - - int cycles = 0; - int timeout = EM4X50_T_SIMULATION_TIMEOUT_READ; - - while (cycles < EM4X50_T_TAG_FULL_PERIOD) { - - // wait until reader field disappears - while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); - - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - - // now check until reader switches on carrier field - while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { - - // check if cycle (i.e. off -> on -> off) takes longer than T0 - if (AT91C_BASE_TC0->TC_CV > T0 * EM4X50_ZERO_DETECTION) { - - // gap detected; wait until reader field is switched on again - while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK && (timeout--)); - - if (timeout <= 0) { - return PM3_ETIMEOUT; - } - timeout = EM4X50_T_SIMULATION_TIMEOUT_READ; - - // now we have a reference "position", from here it will take - // slightly less than 32 cycles until the end of the bit period - wait_cycles(28); - - // end of bit period is reached; return with bit value "0" - // (cf. datasheet) - return 0; - } - - } - - // no gap detected, i.e. reader field is still up; - // continue with counting cycles - cycles++; - } - - // reached 64 cycles (= EM4X50_T_TAG_FULL_PERIOD) -> return bit value "1" - return 1; -} - -static bool em4x50_sim_read_byte(uint8_t *byte, bool paritycheck) { - - for (int i = 0; i < 8; i++) { - *byte <<= 1; - *byte |= em4x50_sim_read_bit(); - } - - if (paritycheck) { - - int pval = em4x50_sim_read_bit(); - uint8_t parity = 0; - - for (int i = 0; i < 8; i++) { - parity ^= ((*byte) >> i) & 1; - } - - if (parity != pval) { - return false; - } - } - - return true; - -} - -static bool em4x50_sim_read_word(uint32_t *word) { - - uint8_t stop_bit = 0; - uint8_t parities = 0, parities_calculated = 0; - uint8_t bytes[4] = {0}; - - // read plain data - for (int i = 0; i < 4; i++) { - em4x50_sim_read_byte(&bytes[i], true); - } - - // read column parities and stop bit - em4x50_sim_read_byte(&parities, false); - stop_bit = em4x50_sim_read_bit(); - - // calculate column parities from data - for (int i = 0; i < 8; i++) { - parities_calculated <<= 1; - for (int j = 0; j < 4; j++) { - parities_calculated ^= (bytes[j] >> (7 - i)) & 1; - } - } - - *word = BYTES2UINT32(bytes); - - // check parities - if ((parities == parities_calculated) && (stop_bit == 0)) { - return true; - } - - return false; -} - -static void em4x50_sim_send_ack(void) { - - SHORT_COIL(); - wait_cycles(EM4X50_T_TAG_HALF_PERIOD); - - OPEN_COIL(); - wait_cycles(EM4X50_T_TAG_HALF_PERIOD); - - SHORT_COIL(); - wait_cycles(3 * EM4X50_T_TAG_HALF_PERIOD); - - OPEN_COIL(); - wait_cycles(EM4X50_T_TAG_HALF_PERIOD); - - SHORT_COIL(); - wait_cycles(3 * EM4X50_T_TAG_HALF_PERIOD); - - OPEN_COIL(); - wait_cycles(EM4X50_T_TAG_HALF_PERIOD); - - SHORT_COIL(); -} - -static void em4x50_sim_send_nak(void) { - - SHORT_COIL(); - wait_cycles(EM4X50_T_TAG_HALF_PERIOD); - - OPEN_COIL(); - wait_cycles(EM4X50_T_TAG_HALF_PERIOD); - - SHORT_COIL(); - wait_cycles(3 * EM4X50_T_TAG_HALF_PERIOD); - - OPEN_COIL(); - wait_cycles(EM4X50_T_TAG_HALF_PERIOD); - - SHORT_COIL(); - wait_cycles(EM4X50_T_TAG_FULL_PERIOD); - - OPEN_COIL(); - wait_cycles(EM4X50_T_TAG_HALF_PERIOD); - - SHORT_COIL(); - wait_cycles(EM4X50_T_TAG_HALF_PERIOD); - - OPEN_COIL(); -} - -static int em4x50_sim_handle_login_command(uint32_t *tag) { - - // read password - uint32_t password = 0; - bool pwd = em4x50_sim_read_word(&password); - - // signal that reader sent the password - LED_D_ON(); - - //wait_cycles(15); - - // processing pause time (corresponds to a "1" bit) - em4x50_sim_send_bit(1); - - // empirically determined delay (to be examined seperately) - wait_cycles(1); - - if (pwd && (password == reflect32(tag[EM4X50_DEVICE_PASSWORD]))) { - em4x50_sim_send_ack(); - gLogin = true; - LED_A_ON(); - } else { - em4x50_sim_send_nak(); - gLogin = false; - LED_A_OFF(); - } - // continue with standard read mode - return EM4X50_COMMAND_STANDARD_READ; -} - -static int em4x50_sim_handle_reset_command(uint32_t *tag) { - - // processing pause time (corresponds to a "1" bit) - em4x50_sim_send_bit(1); - - // send ACK - em4x50_sim_send_ack(); - gLogin = false; - - // wait for tinit - wait_cycles(EM4X50_T_TAG_TINIT); - - // continue with standard read mode - return EM4X50_COMMAND_STANDARD_READ; -} - -static int em4x50_sim_handle_write_command(uint32_t *tag) { - - // read address - uint8_t address = 0; - bool addr = em4x50_sim_read_byte(&address, true); - // read data - uint32_t data = 0; - bool word = em4x50_sim_read_word(&data); - - // write access time - wait_cycles(EM4X50_T_TAG_TWA); - - if ((addr == false) || (word == false)) { - em4x50_sim_send_nak(); - return EM4X50_COMMAND_STANDARD_READ; - } - - // extract necessary control data - bool raw = (tag[EM4X50_CONTROL] >> CONFIG_BLOCK) & READ_AFTER_WRITE; - // extract protection data: - // first word write protected - int fwwp = reflect8((tag[EM4X50_PROTECTION] >> 24) & 0xFF); - // last word write protected - int lwwp = reflect8((tag[EM4X50_PROTECTION] >> 16) & 0xFF); - - switch (address) { - - case EM4X50_DEVICE_PASSWORD: - em4x50_sim_send_nak(); - return EM4X50_COMMAND_STANDARD_READ; - break; - - case EM4X50_PROTECTION: - if (gLogin) { - tag[address] = reflect32(data); - em4x50_sim_send_ack(); - } else { - em4x50_sim_send_nak(); - return EM4X50_COMMAND_STANDARD_READ; - } - break; - - case EM4X50_CONTROL: - if (gLogin) { - tag[address] = reflect32(data); - em4x50_sim_send_ack(); - } else { - em4x50_sim_send_nak(); - return EM4X50_COMMAND_STANDARD_READ; - } - break; - - case EM4X50_DEVICE_SERIAL: - em4x50_sim_send_nak(); - return EM4X50_COMMAND_STANDARD_READ; - break; - - case EM4X50_DEVICE_ID: - em4x50_sim_send_nak(); - return EM4X50_COMMAND_STANDARD_READ; - break; - - default: - if ((address >= fwwp) && (address <= lwwp) && (gLogin == false)) { - if (gLogin) { - tag[address] = reflect32(data); - em4x50_sim_send_ack(); - } else { - em4x50_sim_send_nak(); - return EM4X50_COMMAND_STANDARD_READ; - } - } else { - tag[address] = reflect32(data); - em4x50_sim_send_ack(); - } - break; - } - - // EEPROM write time - wait_cycles(EM4X50_T_TAG_TWEE); - - // strange: need some sort of 'waveform correction', otherwise ack signal - // will not be detected; sending a single "1" seems to solve the problem - em4x50_sim_send_bit(1); - - em4x50_sim_send_ack(); - - // if "read after write" (raw) bit is set, send written data once - if (raw) { - int command = em4x50_sim_send_listen_window(tag); - if (command != PM3_SUCCESS) { - return command; - } - - command = em4x50_sim_send_listen_window(tag); - if (command != PM3_SUCCESS) { - return command; - } - - em4x50_sim_send_word(tag[address]); - } - - // continue with standard read mode - return EM4X50_COMMAND_STANDARD_READ; -} - -static int em4x50_sim_handle_writepwd_command(uint32_t *tag) { - - bool pwd = false; - - if (gWritePasswordProcess == false) { - - gWritePasswordProcess = true; - - // read password - uint32_t act_password = 0; - pwd = em4x50_sim_read_word(&act_password); - - //wait_cycles(15); - - // processing pause time (corresponds to a "1" bit) - em4x50_sim_send_bit(1); - - if (pwd && (act_password == reflect32(tag[EM4X50_DEVICE_PASSWORD]))) { - em4x50_sim_send_ack(); - gLogin = true; - } else { - em4x50_sim_send_nak(); - gLogin = false; - return EM4X50_COMMAND_STANDARD_READ; - } - - int command = em4x50_sim_send_listen_window(tag); - if (command != PM3_SUCCESS) { - return command; - } - - } else { - - gWritePasswordProcess = false; - - // read new password - uint32_t new_password = 0; - pwd = em4x50_sim_read_word(&new_password); - - // write access time - wait_cycles(EM4X50_T_TAG_TWA); - - if (pwd) { - em4x50_sim_send_ack(); - tag[EM4X50_DEVICE_PASSWORD] = reflect32(new_password); - } else { - em4x50_sim_send_ack(); - return EM4X50_COMMAND_STANDARD_READ; - } - - //wait_cycles(15); - - // EEPROM write time - wait_cycles(EM4X50_T_TAG_TWEE); - - // strange: need some sort of 'waveform correction', otherwise ack signal - // will not be detected; sending a single "1" seems to solve the problem - em4x50_sim_send_bit(1); - - em4x50_sim_send_ack(); - - // continue with standard read mode - return EM4X50_COMMAND_STANDARD_READ; - } - - // call writepwd function again for else branch - return EM4X50_COMMAND_WRITE_PASSWORD; -} - -static int em4x50_sim_handle_selective_read_command(uint32_t *tag) { - - int command = 0; - - // read password - uint32_t address = 0; - bool addr = em4x50_sim_read_word(&address); - //wait_cycles(15); - - // processing pause time (corresponds to a "1" bit) - em4x50_sim_send_bit(1); - - if (addr) { - em4x50_sim_send_ack(); - } else { - em4x50_sim_send_nak(); - return EM4X50_COMMAND_STANDARD_READ; - } - - // extract control data - int fwr = address & 0xFF; // first word read - int lwr = (address >> 8) & 0xFF; // last word read - - // extract protection data: - // first word read protected - int fwrp = reflect32(tag[EM4X50_PROTECTION]) & 0xFF; - // last word read protected - int lwrp = (reflect32(tag[EM4X50_PROTECTION]) >> 8) & 0xFF; - - while ((BUTTON_PRESS() == false) && (data_available() == false)) { - - WDT_HIT(); - - command = em4x50_sim_send_listen_window(tag); - if (command != PM3_SUCCESS) { - return command; - } - - for (int i = fwr; i <= lwr; i++) { - - command = em4x50_sim_send_listen_window(tag); - if (command != PM3_SUCCESS) { - return command; - } - - // if not authenticated do not send read protected words - if ((gLogin == false) && (i >= fwrp) && (i <= lwrp)) { - em4x50_sim_send_word(0x00); - } else { - em4x50_sim_send_word(reflect32(tag[i])); - } - } - } - - return PM3_EOPABORTED; -} - -static int em4x50_sim_handle_standard_read_command(uint32_t *tag) { - - int command = 0; - - // extract control data - int fwr = reflect32(tag[EM4X50_CONTROL]) & 0xFF; // first word read - int lwr = (reflect32(tag[EM4X50_CONTROL]) >> 8) & 0xFF; // last word read - // extract protection data: - // first word read protected - int fwrp = reflect32(tag[EM4X50_PROTECTION]) & 0xFF; - // last word read protected - int lwrp = (reflect32(tag[EM4X50_PROTECTION]) >> 8) & 0xFF; - - // iceman, will need a usb cmd check to break as well - while ((BUTTON_PRESS() == false) && (data_available() == false)) { - - WDT_HIT(); - - command = em4x50_sim_send_listen_window(tag); - if (command != PM3_SUCCESS) { - return command; - } - - for (int i = fwr; i <= lwr; i++) { - - command = em4x50_sim_send_listen_window(tag); - if (command != PM3_SUCCESS) { - return command; - } - - if ((gLogin == false) && (i >= fwrp) && (i <= lwrp)) { - em4x50_sim_send_word(0x00); - } else { - em4x50_sim_send_word(reflect32(tag[i])); - } - } - } - - return PM3_EOPABORTED; -} - -// reader requests receive mode (rm) by sending two zeros -static int check_rm_request(uint32_t *tag) { - - // look for first zero - int bit = em4x50_sim_read_bit(); - if (bit == 0) { - - // look for second zero - bit = em4x50_sim_read_bit(); - if (bit == 0) { - - // if command before was EM4X50_COMMAND_WRITE_PASSWORD - // switch to separate process - if (gWritePasswordProcess) { - return EM4X50_COMMAND_WRITE_PASSWORD; - } else { - // read mode request detected, get command from reader - uint8_t command = 0; - em4x50_sim_read_byte(&command, true); - return command; - } - } - } - - return (bit != PM3_ETIMEOUT) ? PM3_SUCCESS : PM3_ETIMEOUT; -} - -static int em4x50_sim_send_listen_window(uint32_t *tag) { - - SHORT_COIL(); - wait_cycles(EM4X50_T_TAG_HALF_PERIOD); - - OPEN_COIL(); - wait_cycles(EM4X50_T_TAG_HALF_PERIOD); - - SHORT_COIL(); - wait_cycles(2 * EM4X50_T_TAG_FULL_PERIOD); - - OPEN_COIL(); - int command = check_rm_request(tag); - if (command != PM3_SUCCESS) { - return command; - } - - SHORT_COIL(); - wait_cycles(EM4X50_T_TAG_FULL_PERIOD); - - return PM3_SUCCESS; -} - // simple login to EM4x50, // used in operations that require authentication static bool login(uint32_t password) { @@ -1619,7 +1000,7 @@ static int write(uint32_t word, uint32_t addresses) { for (int i = 0; i < 50; i++) { wait_timer(T0 * EM4X50_T_TAG_FULL_PERIOD); } - + if (check_ack(false)) { return PM3_SUCCESS; } @@ -1761,6 +1142,635 @@ void em4x50_writepwd(em4x50_data_t *etd) { reply_ng(CMD_LF_EM4X50_WRITEPWD, status, NULL, 0); } +// send bit in receive mode by counting carrier cycles +static void em4x50_sim_send_bit(uint8_t bit) { + + uint16_t timeout = EM4X50_T_TAG_FULL_PERIOD; + + for (int t = 0; t < EM4X50_T_TAG_FULL_PERIOD; t++) { + + // wait until SSC_CLK goes HIGH + // used as a simple detection of a reader field? + while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) && (timeout--)); + + if (timeout == 0) { + return; + } + timeout = EM4X50_T_TAG_FULL_PERIOD; + + if (bit) + OPEN_COIL(); + else + SHORT_COIL(); + + //wait until SSC_CLK goes LOW + while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK && (timeout--)); + if (timeout == 0) { + return; + } + timeout = EM4X50_T_TAG_FULL_PERIOD; + + if (t == EM4X50_T_TAG_HALF_PERIOD) + bit ^= 1; + + } +} + +// send byte in receive mode either with or without parity check (even) +static void em4x50_sim_send_byte(uint8_t byte, bool paritycheck) { + + // send byte + for (int i = 0; i < 8; i++) { + em4x50_sim_send_bit((byte >> (7 - i)) & 1); + } + + if (paritycheck) { + + uint8_t parity = 0x0; + + for (int i = 0; i < 8; i++) { + parity ^= (byte >> i) & 1; + } + + em4x50_sim_send_bit(parity); + } +} + +// send complete word in receive mode (including all parity checks) +static void em4x50_sim_send_word(uint32_t word) { + + uint8_t cparity = 0x00; + + // word has tobe sent in msb, not lsb + word = reflect32(word); + + // 4 bytes each with even row parity bit + for (int i = 0; i < 4; i++) { + em4x50_sim_send_byte((word >> ((3 - i) * 8)) & 0xFF, true); + } + + // column parity + for (int i = 0; i < 8; i++) { + cparity <<= 1; + for (int j = 0; j < 4; j++) { + cparity ^= (((word >> ((3 - j) * 8)) & 0xFF) >> (7 - i)) & 1; + } + } + em4x50_sim_send_byte(cparity, false); + + // stop bit + em4x50_sim_send_bit(0); +} + +// wait for pulses of carrier frequency +static void wait_cycles(int maxperiods) { + + int period = 0, timeout = EM4X50_T_SIMULATION_TIMEOUT_WAIT; + + while (period < maxperiods) { + + while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) && (timeout--)); + if (timeout <= 0) { + return; + } + timeout = EM4X50_T_SIMULATION_TIMEOUT_WAIT; + + while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK && (timeout--)); + if (timeout <= 0) { + return; + } + timeout = EM4X50_T_SIMULATION_TIMEOUT_WAIT; + + period++; + } +} + +// read single bit while simulating +static int em4x50_sim_read_bit(void) { + + int cycles = 0; + int timeout = EM4X50_T_SIMULATION_TIMEOUT_READ; + + while (cycles < EM4X50_T_TAG_FULL_PERIOD) { + + // wait until reader field disappears + while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); + + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + + // now check until reader switches on carrier field + while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { + + // check if cycle (i.e. off -> on -> off) takes longer than T0 + if (AT91C_BASE_TC0->TC_CV > T0 * EM4X50_ZERO_DETECTION) { + + // gap detected; wait until reader field is switched on again + while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK && (timeout--)); + + if (timeout <= 0) { + return PM3_ETIMEOUT; + } + timeout = EM4X50_T_SIMULATION_TIMEOUT_READ; + + // now we have a reference "position", from here it will take + // slightly less than 32 cycles until the end of the bit period + wait_cycles(28); + + // end of bit period is reached; return with bit value "0" + // (cf. datasheet) + return 0; + } + + } + + // no gap detected, i.e. reader field is still up; + // continue with counting cycles + cycles++; + } + + // reached 64 cycles (= EM4X50_T_TAG_FULL_PERIOD) -> return bit value "1" + return 1; +} + +// read byte in while simulation either with or without parity check (even) +static bool em4x50_sim_read_byte(uint8_t *byte, bool paritycheck) { + + for (int i = 0; i < 8; i++) { + *byte <<= 1; + *byte |= em4x50_sim_read_bit(); + } + + if (paritycheck) { + + int pval = em4x50_sim_read_bit(); + uint8_t parity = 0; + + for (int i = 0; i < 8; i++) { + parity ^= ((*byte) >> i) & 1; + } + + if (parity != pval) { + return false; + } + } + + return true; + +} + +// read complete word while simulating +static bool em4x50_sim_read_word(uint32_t *word) { + + uint8_t stop_bit = 0; + uint8_t parities = 0, parities_calculated = 0; + uint8_t bytes[4] = {0}; + + // read plain data + for (int i = 0; i < 4; i++) { + em4x50_sim_read_byte(&bytes[i], true); + } + + // read column parities and stop bit + em4x50_sim_read_byte(&parities, false); + stop_bit = em4x50_sim_read_bit(); + + // calculate column parities from data + for (int i = 0; i < 8; i++) { + parities_calculated <<= 1; + for (int j = 0; j < 4; j++) { + parities_calculated ^= (bytes[j] >> (7 - i)) & 1; + } + } + + *word = BYTES2UINT32(bytes); + + // check parities + if ((parities == parities_calculated) && (stop_bit == 0)) { + return true; + } + + return false; +} + +// check if reader requests receive mode (rm) by sending two zeros +static int check_rm_request(uint32_t *tag) { + + // look for first zero + int bit = em4x50_sim_read_bit(); + if (bit == 0) { + + // look for second zero + bit = em4x50_sim_read_bit(); + if (bit == 0) { + + // if command before was EM4X50_COMMAND_WRITE_PASSWORD + // switch to separate process + if (gWritePasswordProcess) { + return EM4X50_COMMAND_WRITE_PASSWORD; + } else { + // read mode request detected, get command from reader + uint8_t command = 0; + em4x50_sim_read_byte(&command, true); + return command; + } + } + } + + return (bit != PM3_ETIMEOUT) ? PM3_SUCCESS : PM3_ETIMEOUT; +} + +// send single listen window while simulating +static int em4x50_sim_send_listen_window(uint32_t *tag) { + + SHORT_COIL(); + wait_cycles(EM4X50_T_TAG_HALF_PERIOD); + + OPEN_COIL(); + wait_cycles(EM4X50_T_TAG_HALF_PERIOD); + + SHORT_COIL(); + wait_cycles(2 * EM4X50_T_TAG_FULL_PERIOD); + + OPEN_COIL(); + int command = check_rm_request(tag); + if (command != PM3_SUCCESS) { + return command; + } + + SHORT_COIL(); + wait_cycles(EM4X50_T_TAG_FULL_PERIOD); + + return PM3_SUCCESS; +} + +// send ack +static void em4x50_sim_send_ack(void) { + + SHORT_COIL(); + wait_cycles(EM4X50_T_TAG_HALF_PERIOD); + + OPEN_COIL(); + wait_cycles(EM4X50_T_TAG_HALF_PERIOD); + + SHORT_COIL(); + wait_cycles(3 * EM4X50_T_TAG_HALF_PERIOD); + + OPEN_COIL(); + wait_cycles(EM4X50_T_TAG_HALF_PERIOD); + + SHORT_COIL(); + wait_cycles(3 * EM4X50_T_TAG_HALF_PERIOD); + + OPEN_COIL(); + wait_cycles(EM4X50_T_TAG_HALF_PERIOD); + + SHORT_COIL(); +} + +// send nak +static void em4x50_sim_send_nak(void) { + + SHORT_COIL(); + wait_cycles(EM4X50_T_TAG_HALF_PERIOD); + + OPEN_COIL(); + wait_cycles(EM4X50_T_TAG_HALF_PERIOD); + + SHORT_COIL(); + wait_cycles(3 * EM4X50_T_TAG_HALF_PERIOD); + + OPEN_COIL(); + wait_cycles(EM4X50_T_TAG_HALF_PERIOD); + + SHORT_COIL(); + wait_cycles(EM4X50_T_TAG_FULL_PERIOD); + + OPEN_COIL(); + wait_cycles(EM4X50_T_TAG_HALF_PERIOD); + + SHORT_COIL(); + wait_cycles(EM4X50_T_TAG_HALF_PERIOD); + + OPEN_COIL(); +} + +// standard read mode process (simulation mode) +static int em4x50_sim_handle_standard_read_command(uint32_t *tag) { + + int command = 0; + + // extract control data + int fwr = reflect32(tag[EM4X50_CONTROL]) & 0xFF; // first word read + int lwr = (reflect32(tag[EM4X50_CONTROL]) >> 8) & 0xFF; // last word read + // extract protection data: + // first word read protected + int fwrp = reflect32(tag[EM4X50_PROTECTION]) & 0xFF; + // last word read protected + int lwrp = (reflect32(tag[EM4X50_PROTECTION]) >> 8) & 0xFF; + + // iceman, will need a usb cmd check to break as well + while ((BUTTON_PRESS() == false) && (data_available() == false)) { + + WDT_HIT(); + + command = em4x50_sim_send_listen_window(tag); + if (command != PM3_SUCCESS) { + return command; + } + + for (int i = fwr; i <= lwr; i++) { + + command = em4x50_sim_send_listen_window(tag); + if (command != PM3_SUCCESS) { + return command; + } + + if ((gLogin == false) && (i >= fwrp) && (i <= lwrp)) { + em4x50_sim_send_word(0x00); + } else { + em4x50_sim_send_word(reflect32(tag[i])); + } + } + } + + return PM3_EOPABORTED; +} + +// selective read mode process (simulation mode) +static int em4x50_sim_handle_selective_read_command(uint32_t *tag) { + + int command = 0; + + // read password + uint32_t address = 0; + bool addr = em4x50_sim_read_word(&address); + + // processing pause time (corresponds to a "1" bit) + em4x50_sim_send_bit(1); + + if (addr) { + em4x50_sim_send_ack(); + } else { + em4x50_sim_send_nak(); + return EM4X50_COMMAND_STANDARD_READ; + } + + // extract control data + int fwr = address & 0xFF; // first word read + int lwr = (address >> 8) & 0xFF; // last word read + + // extract protection data: + // first word read protected + int fwrp = reflect32(tag[EM4X50_PROTECTION]) & 0xFF; + // last word read protected + int lwrp = (reflect32(tag[EM4X50_PROTECTION]) >> 8) & 0xFF; + + while ((BUTTON_PRESS() == false) && (data_available() == false)) { + + WDT_HIT(); + + command = em4x50_sim_send_listen_window(tag); + if (command != PM3_SUCCESS) { + return command; + } + + for (int i = fwr; i <= lwr; i++) { + + command = em4x50_sim_send_listen_window(tag); + if (command != PM3_SUCCESS) { + return command; + } + + // if not authenticated do not send read protected words + if ((gLogin == false) && (i >= fwrp) && (i <= lwrp)) { + em4x50_sim_send_word(0x00); + } else { + em4x50_sim_send_word(reflect32(tag[i])); + } + } + } + + return PM3_EOPABORTED; +} + +// login process (simulation mode) +static int em4x50_sim_handle_login_command(uint32_t *tag) { + + // read password + uint32_t password = 0; + bool pwd = em4x50_sim_read_word(&password); + + // signal that reader sent the password + LED_D_ON(); + + // processing pause time (corresponds to a "1" bit) + em4x50_sim_send_bit(1); + + // empirically determined delay (to be examined seperately) + wait_cycles(1); + + if (pwd && (password == reflect32(tag[EM4X50_DEVICE_PASSWORD]))) { + em4x50_sim_send_ack(); + gLogin = true; + LED_A_ON(); + } else { + em4x50_sim_send_nak(); + gLogin = false; + LED_A_OFF(); + } + // continue with standard read mode + return EM4X50_COMMAND_STANDARD_READ; +} + +// reset process (simulation mode) +static int em4x50_sim_handle_reset_command(uint32_t *tag) { + + // processing pause time (corresponds to a "1" bit) + em4x50_sim_send_bit(1); + + // send ACK + em4x50_sim_send_ack(); + gLogin = false; + LED_A_OFF(); + + // wait for tinit + wait_cycles(EM4X50_T_TAG_TINIT); + + // continue with standard read mode + return EM4X50_COMMAND_STANDARD_READ; +} + +// write process (simulation mode) +static int em4x50_sim_handle_write_command(uint32_t *tag) { + + // read address + uint8_t address = 0; + bool addr = em4x50_sim_read_byte(&address, true); + // read data + uint32_t data = 0; + bool word = em4x50_sim_read_word(&data); + + // write access time + wait_cycles(EM4X50_T_TAG_TWA); + + if ((addr == false) || (word == false)) { + em4x50_sim_send_nak(); + return EM4X50_COMMAND_STANDARD_READ; + } + + // extract necessary control data + bool raw = (tag[EM4X50_CONTROL] >> CONFIG_BLOCK) & READ_AFTER_WRITE; + // extract protection data: + // first word write protected + int fwwp = reflect8((tag[EM4X50_PROTECTION] >> 24) & 0xFF); + // last word write protected + int lwwp = reflect8((tag[EM4X50_PROTECTION] >> 16) & 0xFF); + + switch (address) { + + case EM4X50_DEVICE_PASSWORD: + em4x50_sim_send_nak(); + return EM4X50_COMMAND_STANDARD_READ; + break; + + case EM4X50_PROTECTION: + if (gLogin) { + tag[address] = reflect32(data); + em4x50_sim_send_ack(); + } else { + em4x50_sim_send_nak(); + return EM4X50_COMMAND_STANDARD_READ; + } + break; + + case EM4X50_CONTROL: + if (gLogin) { + tag[address] = reflect32(data); + em4x50_sim_send_ack(); + } else { + em4x50_sim_send_nak(); + return EM4X50_COMMAND_STANDARD_READ; + } + break; + + case EM4X50_DEVICE_SERIAL: + em4x50_sim_send_nak(); + return EM4X50_COMMAND_STANDARD_READ; + break; + + case EM4X50_DEVICE_ID: + em4x50_sim_send_nak(); + return EM4X50_COMMAND_STANDARD_READ; + break; + + default: + if ((address >= fwwp) && (address <= lwwp)) { + if (gLogin) { + tag[address] = reflect32(data); + em4x50_sim_send_ack(); + } else { + em4x50_sim_send_nak(); + return EM4X50_COMMAND_STANDARD_READ; + } + } else { + tag[address] = reflect32(data); + em4x50_sim_send_ack(); + } + break; + } + + // EEPROM write time + // strange: need some sort of 'waveform correction', otherwise ack signal + // will not be detected; sending a single "1" as last "bit"" of Twee + // seems to solve the problem + wait_cycles(EM4X50_T_TAG_TWEE - EM4X50_T_TAG_FULL_PERIOD); + em4x50_sim_send_bit(1); + em4x50_sim_send_ack(); + + // if "read after write" (raw) bit is set, send written data once + if (raw) { + int command = em4x50_sim_send_listen_window(tag); + if (command != PM3_SUCCESS) { + return command; + } + + command = em4x50_sim_send_listen_window(tag); + if (command != PM3_SUCCESS) { + return command; + } + + em4x50_sim_send_word(tag[address]); + } + + // continue with standard read mode + return EM4X50_COMMAND_STANDARD_READ; +} + +// write password process (simulation mode) +static int em4x50_sim_handle_writepwd_command(uint32_t *tag) { + + bool pwd = false; + + if (gWritePasswordProcess == false) { + + gWritePasswordProcess = true; + + // read password + uint32_t act_password = 0; + pwd = em4x50_sim_read_word(&act_password); + + // processing pause time (corresponds to a "1" bit) + em4x50_sim_send_bit(1); + + if (pwd && (act_password == reflect32(tag[EM4X50_DEVICE_PASSWORD]))) { + em4x50_sim_send_ack(); + gLogin = true; + } else { + em4x50_sim_send_nak(); + gLogin = false; + return EM4X50_COMMAND_STANDARD_READ; + } + + int command = em4x50_sim_send_listen_window(tag); + if (command != PM3_SUCCESS) { + return command; + } + + } else { + + gWritePasswordProcess = false; + + // read new password + uint32_t new_password = 0; + pwd = em4x50_sim_read_word(&new_password); + + // write access time + wait_cycles(EM4X50_T_TAG_TWA); + + if (pwd) { + em4x50_sim_send_ack(); + tag[EM4X50_DEVICE_PASSWORD] = reflect32(new_password); + } else { + em4x50_sim_send_ack(); + return EM4X50_COMMAND_STANDARD_READ; + } + + // EEPROM write time + // strange: need some sort of 'waveform correction', otherwise ack signal + // will not be detected; sending a single "1" as last part of Twee + // seems to solve the problem + wait_cycles(EM4X50_T_TAG_TWEE - EM4X50_T_TAG_FULL_PERIOD); + em4x50_sim_send_bit(1); + em4x50_sim_send_ack(); + + // continue with standard read mode + return EM4X50_COMMAND_STANDARD_READ; + } + + // call writepwd function again for else branch + return EM4X50_COMMAND_WRITE_PASSWORD; +} + // simulate uploaded data in emulator memory // LED A -> operations that require authentication are possible // LED B -> standard read mode is active From 78d1e09595cabe07dbd96f81108f06dbdded0d82 Mon Sep 17 00:00:00 2001 From: tharexde Date: Mon, 18 Jan 2021 00:01:22 +0100 Subject: [PATCH 14/22] deleted test functions, clean up --- armsrc/appmain.c | 4 - armsrc/em4x50.c | 134 +++------------------------------ armsrc/em4x50.h | 1 - client/src/cmdlfem4x50.c | 158 --------------------------------------- client/src/cmdlfem4x50.h | 1 - include/em4x50.h | 9 --- include/pm3_cmd.h | 1 - 7 files changed, 9 insertions(+), 299 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 5f70fa957..dca2def3b 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1172,10 +1172,6 @@ static void PacketReceived(PacketCommandNG *packet) { em4x50_chk((uint8_t *)packet->data.asBytes); break; } - case CMD_LF_EM4X50_TEST: { - em4x50_test((em4x50_test_t *)packet->data.asBytes); - break; - } #endif #ifdef WITH_EM4x70 diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 9d9da9a8d..c87f7a01e 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -70,37 +70,12 @@ bool gLogin = false; // to be able to identfiy it bool gWritePasswordProcess = false; -static int em4x50_sim_send_listen_window(uint32_t *tag); - -void catch_samples(void); - // do nothing for using timer0 static void wait_timer(uint32_t period) { AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; while (AT91C_BASE_TC0->TC_CV < period); } -void catch_samples(void) { - - uint8_t sample = 0; - - if (EM4X50_MAX_NO_SAMPLES > CARD_MEMORY_SIZE) { - Dbprintf("exeeded emulator memory size"); - return; - } - - uint8_t *em4x50_sample_buffer = BigBuf_get_addr(); - - memcpy(em4x50_sample_buffer, &gHigh, 1); - memcpy(em4x50_sample_buffer + 1, &gLow, 1); - - for (int i = 2; i < EM4X50_MAX_NO_SAMPLES + 2; i++) { - sample = AT91C_BASE_SSC->SSC_RHR; - memcpy(em4x50_sample_buffer + i, &sample, 1); - wait_timer(T0); // 8µs delay - } -} - // extract and check parities // return result of parity check and extracted plain data static bool extract_parities(uint64_t word, uint32_t *data) { @@ -387,7 +362,7 @@ static void em4x50_reader_send_byte(uint8_t byte) { } } -// send byte followed by its (equal) parity bit +// send byte followed by its (even) parity bit static void em4x50_reader_send_byte_with_parity(uint8_t byte) { int parity = 0, bit = 0; @@ -537,8 +512,6 @@ static bool check_ack(bool bliw) { if (check_pulse_length(get_pulse_length(), 2 * EM4X50_T_TAG_FULL_PERIOD)) { - //catch_samples(); - // The received signal is either ACK or NAK. if (check_pulse_length(get_pulse_length(), 2 * EM4X50_T_TAG_FULL_PERIOD)) { @@ -1245,7 +1218,7 @@ static void wait_cycles(int maxperiods) { } } -// read single bit while simulating +// read single bit in simulation mode static int em4x50_sim_read_bit(void) { int cycles = 0; @@ -1292,7 +1265,7 @@ static int em4x50_sim_read_bit(void) { return 1; } -// read byte in while simulation either with or without parity check (even) +// read byte in simulation mode either with or without parity check (even) static bool em4x50_sim_read_byte(uint8_t *byte, bool paritycheck) { for (int i = 0; i < 8; i++) { @@ -1318,7 +1291,7 @@ static bool em4x50_sim_read_byte(uint8_t *byte, bool paritycheck) { } -// read complete word while simulating +// read complete word in simulation mode static bool em4x50_sim_read_word(uint32_t *word) { uint8_t stop_bit = 0; @@ -1379,7 +1352,7 @@ static int check_rm_request(uint32_t *tag) { return (bit != PM3_ETIMEOUT) ? PM3_SUCCESS : PM3_ETIMEOUT; } -// send single listen window while simulating +// send single listen window in simulation mode static int em4x50_sim_send_listen_window(uint32_t *tag) { SHORT_COIL(); @@ -1454,7 +1427,7 @@ static void em4x50_sim_send_nak(void) { OPEN_COIL(); } -// standard read mode process (simulation mode) +// standard read mode process (simulation mode) static int em4x50_sim_handle_standard_read_command(uint32_t *tag) { int command = 0; @@ -1560,13 +1533,10 @@ static int em4x50_sim_handle_login_command(uint32_t *tag) { uint32_t password = 0; bool pwd = em4x50_sim_read_word(&password); - // signal that reader sent the password - LED_D_ON(); - // processing pause time (corresponds to a "1" bit) em4x50_sim_send_bit(1); - // empirically determined delay (to be examined seperately) + // empirically determined delay (to be checked in detail) wait_cycles(1); if (pwd && (password == reflect32(tag[EM4X50_DEVICE_PASSWORD]))) { @@ -1593,7 +1563,7 @@ static int em4x50_sim_handle_reset_command(uint32_t *tag) { gLogin = false; LED_A_OFF(); - // wait for tinit + // wait for initialization (tinit) wait_cycles(EM4X50_T_TAG_TINIT); // continue with standard read mode @@ -1681,7 +1651,7 @@ static int em4x50_sim_handle_write_command(uint32_t *tag) { // EEPROM write time // strange: need some sort of 'waveform correction', otherwise ack signal - // will not be detected; sending a single "1" as last "bit"" of Twee + // will not be detected; sending a single "1" as last "bit" of Twee // seems to solve the problem wait_cycles(EM4X50_T_TAG_TWEE - EM4X50_T_TAG_FULL_PERIOD); em4x50_sim_send_bit(1); @@ -1775,7 +1745,6 @@ static int em4x50_sim_handle_writepwd_command(uint32_t *tag) { // LED A -> operations that require authentication are possible // LED B -> standard read mode is active // LED C -> command has been transmitted by reader -// LED D -> password has been caught from reader void em4x50_sim(uint32_t *password) { int command = PM3_ENODATA; @@ -1858,88 +1827,3 @@ void em4x50_sim(uint32_t *password) { lf_finalize(); reply_ng(CMD_LF_EM4X50_SIM, command, NULL, 0); } - -void em4x50_test(em4x50_test_t *ett) { - - int status = 0; - - // set field on or off - if (ett->field != -1) { - em4x50_setup_read(); - if (ett->field == 1) { - LED_A_ON(); - } else { - HIGH(GPIO_SSC_DOUT); - LED_A_OFF(); - } - status = ett->field; - } - - // check field status - if (ett->check_field) { - em4x50_setup_sim(); - bool field_on = false; - while (BUTTON_PRESS() == false) { - - if (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) { - if (field_on == false) { - Dbprintf("field on"); - field_on = true; - } - } else if (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK){ - if (field_on == true) { - Dbprintf("field off"); - field_on = false; - } - } - } - status = 1; - } - - // timing values - if (ett->cycles != 0) { - uint32_t tval = 0; - uint32_t tvalhigh[ett->cycles]; - uint32_t tvallow[ett->cycles]; - - em4x50_setup_sim(); - while (AT91C_BASE_TC0->TC_CV > 0); - - for (int t = 0; t < ett->cycles; t++) { - - // field on -> high value - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - tval = AT91C_BASE_TC0->TC_CV; - while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); - tvalhigh[t] = AT91C_BASE_TC0->TC_CV - tval; - - // filed off -> zero value - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - tval = AT91C_BASE_TC0->TC_CV; - while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); - tvallow[t] = AT91C_BASE_TC0->TC_CV - tval; - } - - for (int t = 0; t < ett->cycles; t++) { - Dbprintf("%03i %li %li", t, tvallow[t], tvalhigh[t]); - } - - } - - // perform reset - if (ett->reset) { - em4x50_setup_read(); - - status = PM3_EFAILED; - if (get_signalproperties() && find_em4x50_tag()) { - - if (reset() == PM3_SUCCESS) { - status = 1; - } - } - - lf_finalize(); - } - - reply_ng(CMD_LF_EM4X50_TEST, status, NULL, 0); -} diff --git a/armsrc/em4x50.h b/armsrc/em4x50.h index 5d4812f42..72304192b 100644 --- a/armsrc/em4x50.h +++ b/armsrc/em4x50.h @@ -22,6 +22,5 @@ void em4x50_login(uint32_t *password); void em4x50_sim(uint32_t *password); void em4x50_reader(void); void em4x50_chk(uint8_t *filename); -void em4x50_test(em4x50_test_t *ett); #endif /* EM4X50_H */ diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 908ab3bfa..84c331337 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -23,86 +23,6 @@ static int CmdHelp(const char *Cmd); -static void write_gnuplot_config_file(int gHigh, int gLow) { - - const char *fn = "../data/data.gnu"; - FILE *fp = NULL; - - if ((fp = fopen(fn, "w+")) == false) { - PrintAndLogEx(WARNING, "Fail, open file %s", fn); - } - - fprintf(fp, "set term qt size 1400, 350 enhanced\n"); - fprintf(fp, "set border 31 front linecolor rgb 'dark-grey' linewidth 1.000 dashtype solid\n"); - fprintf(fp, "set xtics 0, 1 textcolor rgb 'dark-grey'\n"); - fprintf(fp, "set ytics 0, 64 textcolor rgb 'dark-grey'\n"); - fprintf(fp, "set title 'EM4x50 signal (amplitude vs time)'\n"); - fprintf(fp, "set title font ',14' textcolor rgb 'white'\n"); - fprintf(fp, "set xlabel 'time / ms'\n"); - fprintf(fp, "set xlabel font ',12' textcolor rgb 'dark-grey'\n"); - fprintf(fp, "set ylabel 'amplitude'\n"); - fprintf(fp, "set ylabel font ',12' textcolor rgb 'dark-grey'\n"); - fprintf(fp, "set key textcolor 'green'\n"); - fprintf(fp, "set grid\n"); - fprintf(fp, "#set time textcolor 'dark-grey'\n"); - fprintf(fp, "plot [0:][-50:300] '../data/data.dat' u ($1/1000):2 w l linecolor 'green' title '500/4', '../data/data.dat' u ($1/1000):3 w l linecolor 'yellow' title 'gHigh = %i', '../data/data.dat' u ($1/1000):4 w l linecolor 'yellow' title 'gLow = %i'\n", gHigh, gLow); - fprintf(fp, "pause -1\n"); - - fclose(fp); -} - -static void get_samples(void) { - - int gHigh = 0, gLow = 0; - const char *fn = "../data/data.dat"; - FILE *fp = NULL; - - // download from BigBuf memory - uint8_t data[EM4X50_MAX_NO_SAMPLES + 2] = {0x0}; - if (GetFromDevice(BIG_BUF, data, EM4X50_MAX_NO_SAMPLES + 2, 0, NULL, 0, NULL, 2500, false) == false) { - PrintAndLogEx(WARNING, "Fail, transfer from device time-out"); - } - - if ((fp = fopen(fn, "w+")) == false) { - PrintAndLogEx(WARNING, "Fail, open file %s", fn); - } - - gHigh = data[0]; - gLow = data[1]; - for (int i = 2; i < EM4X50_MAX_NO_SAMPLES + 2; i++) { - fprintf(fp, "%i %i %i %i\n", (i - 2) * 8, data[i], gHigh, gLow); - } - - fclose(fp); - - write_gnuplot_config_file(gHigh, gLow); -} - -/* -static void get_time_samples(void) { - - const char *fn = "../data/data.dat"; - FILE *fp = NULL; - - // download from BigBuf memory - uint32_t data[EM4X50_MAX_TIME_SAMPLES] = {0x0}; - if (GetFromDevice(BIG_BUF, (uint8_t *)data, EM4X50_MAX_TIME_SAMPLES, 0, NULL, 0, NULL, 2500, false) == false) { - PrintAndLogEx(WARNING, "Fail, transfer from device time-out"); - } - - if ((fp = fopen(fn, "w+")) == false) { - PrintAndLogEx(WARNING, "Fail, open file %s", fn); - } - - for (int i = 0; i < EM4X50_MAX_TIME_SAMPLES; i++) { - PrintAndLogEx(INFO, "%i %"PRIu32"", i, data[i]); - fprintf(fp, "%i %"PRIu32"\n", i, data[i]); - } - - fclose(fp); -} -*/ - static void prepare_result(const uint8_t *data, int fwr, int lwr, em4x50_word_t *words) { // restructure received result in "em4x50_word_t" structure @@ -423,8 +343,6 @@ int CmdEM4x50Login(const char *Cmd) { else PrintAndLogEx(FAILED, "Login " _RED_("failed")); - get_samples(); - return resp.status; } @@ -1275,81 +1193,6 @@ int CmdEM4x50Sim(const char *Cmd) { return resp.status; } -int CmdEM4x50Test(const char *Cmd) { - CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x50 test", - "perform EM4x50 tests.", - "lf em 4x50 test --field on -> reader field on\n" - "lf em 4x50 test --field off -> reader field off\n" - "lf em 4x50 test --check -> check on/off status of reader field\n" - "lf em 4x50 test --cycles 100 -> measure time of 100 field cycles\n" - "lf em 4x50 test --reset -> intitiate reset command\n" - ); - - void *argtable[] = { - arg_param_begin, - arg_str0(NULL, "field", "on/off", "field on/off"), - arg_lit0(NULL, "check", "check if field is on or off"), - arg_int0(NULL, "cycles", "", "number of field cycles"), - arg_lit0(NULL, "reset", "initiates a manual reset command"), - arg_param_end - }; - - CLIExecWithReturn(ctx, Cmd, argtable, true); - - // option: field - int slen = 0; - char format[3] = {0}; - CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)format, sizeof(format), &slen); - em4x50_test_t ett = {.field = -1}; - if (slen != 0) { - if (strcmp(format, "on") == 0) { - ett.field = 1; - } else if (strcmp(format, "off") == 0) { - ett.field = 0; - } else { - PrintAndLogEx(INFO, "Unknown option for --field: %s", format); - return PM3_ESOFT; - } - } - - // option: check_field - ett.check_field = arg_get_lit(ctx, 2); - // option: cycles - ett.cycles = arg_get_int_def(ctx, 3, 0); - // option: reset - ett.reset = arg_get_lit(ctx, 4); - - CLIParserFree(ctx); - - // start - clearCommandBuffer(); - PacketResponseNG resp; - SendCommandNG(CMD_LF_EM4X50_TEST, (uint8_t *)&ett, sizeof(ett)); - WaitForResponse(CMD_LF_EM4X50_TEST, &resp); - - // print response - if (resp.status == 1) { - if (ett.field == 1) - PrintAndLogEx(SUCCESS, "Field switched " _GREEN_("on")); - if (ett.check_field == 1) - PrintAndLogEx(SUCCESS, "Field status evaluated"); - if (ett.reset == 1) - PrintAndLogEx(SUCCESS, "reset command " _GREEN_("ok")); - } else if (resp.status == 0) { - if (ett.field == 1) - PrintAndLogEx(SUCCESS, "Field switched " _GREEN_("off")); - if (ett.reset == 1) - PrintAndLogEx(SUCCESS, "reset command " _GREEN_("failed")); - } else if (resp.status == -1) { - PrintAndLogEx(INFO, "Nothing done"); - } else { - PrintAndLogEx(FAILED, "Test call " _RED_("failed")); - } - - return resp.status; -} - static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"brute", CmdEM4x50Brute, IfPm3EM4x50, "guess password of EM4x50"}, @@ -1367,7 +1210,6 @@ static command_t CommandTable[] = { {"eload", CmdEM4x50ELoad, IfPm3EM4x50, "upload dump of EM4x50 to emulator memory"}, {"esave", CmdEM4x50ESave, IfPm3EM4x50, "save emulator memory to file"}, {"eview", CmdEM4x50EView, IfPm3EM4x50, "view EM4x50 content in emulator memory"}, - {"test", CmdEM4x50Test, IfPm3EM4x50, "perform EM4x50 tests"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdlfem4x50.h b/client/src/cmdlfem4x50.h index df9c587de..0d5c04bc6 100644 --- a/client/src/cmdlfem4x50.h +++ b/client/src/cmdlfem4x50.h @@ -34,6 +34,5 @@ int CmdEM4x50ELoad(const char *Cmd); int CmdEM4x50ESave(const char *Cmd); int CmdEM4x50Chk(const char *Cmd); int CmdEM4x50EView(const char *Cmd); -int CmdEM4x50Test(const char *Cmd); #endif diff --git a/include/em4x50.h b/include/em4x50.h index a2d1dfe23..ff0090547 100644 --- a/include/em4x50.h +++ b/include/em4x50.h @@ -36,8 +36,6 @@ // misc #define TIMEOUT 2000 #define DUMP_FILESIZE 136 -#define EM4X50_MAX_NO_SAMPLES 1000 -#define EM4X50_MAX_TIME_SAMPLES 1000 #define BYTES2UINT32(x) ((x[0] << 24) | (x[1] << 16) | (x[2] << 8) | (x[3])) @@ -50,13 +48,6 @@ typedef struct { uint32_t addresses; } PACKED em4x50_data_t; -typedef struct { - bool check_field; - bool reset; - int field; - int cycles; -} PACKED em4x50_test_t; - typedef struct { uint8_t byte[4]; } PACKED em4x50_word_t; diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index 022b602e3..e3dc29aee 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -516,7 +516,6 @@ typedef struct { #define CMD_LF_EM4X50_READER 0x0251 #define CMD_LF_EM4X50_ESET 0x0252 #define CMD_LF_EM4X50_CHK 0x0253 -#define CMD_LF_EM4X50_TEST 0x0254 #define CMD_LF_EM4X70_INFO 0x0260 #define CMD_LF_EM4X70_WRITE 0x0261 #define CMD_LF_EM4X70_UNLOCK 0x0262 From a931cea2f64ca0e69726719c300888144db448ff Mon Sep 17 00:00:00 2001 From: tharexde Date: Tue, 19 Jan 2021 00:20:03 +0100 Subject: [PATCH 15/22] First fully functional version of 4x50 sim --- armsrc/em4x50.c | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index c87f7a01e..c5f4ec319 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -40,8 +40,10 @@ #define EM4X50_T_TAG_WAITING_FOR_SIGNAL 75 #define EM4X50_T_WAITING_FOR_DBLLIW 1550 #define EM4X50_T_WAITING_FOR_ACK 4 -#define EM4X50_T_SIMULATION_TIMEOUT_READ 5000 // 400 -#define EM4X50_T_SIMULATION_TIMEOUT_WAIT 5000 // 50 + +// timeout values for simulation mode (may vary with regard to reader) +#define EM4X50_T_SIMULATION_TIMEOUT_READ 600 +#define EM4X50_T_SIMULATION_TIMEOUT_WAIT 50 // the following value seems to be critical; if it's too low (e.g. < 120) // some cards are no longer readable although they're ok @@ -1118,18 +1120,19 @@ void em4x50_writepwd(em4x50_data_t *etd) { // send bit in receive mode by counting carrier cycles static void em4x50_sim_send_bit(uint8_t bit) { - uint16_t timeout = EM4X50_T_TAG_FULL_PERIOD; + //uint16_t timeout = EM4X50_T_TAG_FULL_PERIOD; + uint16_t timeout = 500; for (int t = 0; t < EM4X50_T_TAG_FULL_PERIOD; t++) { // wait until SSC_CLK goes HIGH // used as a simple detection of a reader field? - while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) && (timeout--)); + while ((timeout--) && !(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); - if (timeout == 0) { + if (timeout <= 0) { return; } - timeout = EM4X50_T_TAG_FULL_PERIOD; + timeout = 500; if (bit) OPEN_COIL(); @@ -1137,11 +1140,11 @@ static void em4x50_sim_send_bit(uint8_t bit) { SHORT_COIL(); //wait until SSC_CLK goes LOW - while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK && (timeout--)); - if (timeout == 0) { + while ((timeout--) && (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); + if (timeout <= 0) { return; } - timeout = EM4X50_T_TAG_FULL_PERIOD; + timeout = 500; if (t == EM4X50_T_TAG_HALF_PERIOD) bit ^= 1; @@ -1202,13 +1205,13 @@ static void wait_cycles(int maxperiods) { while (period < maxperiods) { - while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) && (timeout--)); + while ((timeout--) && !(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); if (timeout <= 0) { return; } timeout = EM4X50_T_SIMULATION_TIMEOUT_WAIT; - while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK && (timeout--)); + while ((timeout--) && (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); if (timeout <= 0) { return; } @@ -1238,7 +1241,7 @@ static int em4x50_sim_read_bit(void) { if (AT91C_BASE_TC0->TC_CV > T0 * EM4X50_ZERO_DETECTION) { // gap detected; wait until reader field is switched on again - while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK && (timeout--)); + while ((timeout--) && (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); if (timeout <= 0) { return PM3_ETIMEOUT; @@ -1253,7 +1256,6 @@ static int em4x50_sim_read_bit(void) { // (cf. datasheet) return 0; } - } // no gap detected, i.e. reader field is still up; @@ -1433,7 +1435,7 @@ static int em4x50_sim_handle_standard_read_command(uint32_t *tag) { int command = 0; // extract control data - int fwr = reflect32(tag[EM4X50_CONTROL]) & 0xFF; // first word read + int fwr = reflect32(tag[EM4X50_CONTROL]) & 0xFF; // first word read int lwr = (reflect32(tag[EM4X50_CONTROL]) >> 8) & 0xFF; // last word read // extract protection data: // first word read protected @@ -1441,7 +1443,6 @@ static int em4x50_sim_handle_standard_read_command(uint32_t *tag) { // last word read protected int lwrp = (reflect32(tag[EM4X50_PROTECTION]) >> 8) & 0xFF; - // iceman, will need a usb cmd check to break as well while ((BUTTON_PRESS() == false) && (data_available() == false)) { WDT_HIT(); @@ -1536,9 +1537,6 @@ static int em4x50_sim_handle_login_command(uint32_t *tag) { // processing pause time (corresponds to a "1" bit) em4x50_sim_send_bit(1); - // empirically determined delay (to be checked in detail) - wait_cycles(1); - if (pwd && (password == reflect32(tag[EM4X50_DEVICE_PASSWORD]))) { em4x50_sim_send_ack(); gLogin = true; @@ -1766,6 +1764,7 @@ void em4x50_sim(uint32_t *password) { // init em4x50_setup_sim(); gLogin = false; + gWritePasswordProcess = false; // start with inital command = standard read mode command = EM4X50_COMMAND_STANDARD_READ; @@ -1809,6 +1808,12 @@ void em4x50_sim(uint32_t *password) { LED_C_OFF(); command = em4x50_sim_handle_standard_read_command(tag); break; + + // bit errors during reading may lead to unknown commands + // -> continue with standard read mode + default: + command = EM4X50_COMMAND_STANDARD_READ; + break; } // stop if key (pm3 button or enter key) has been pressed @@ -1822,7 +1827,7 @@ void em4x50_sim(uint32_t *password) { } } } - + BigBuf_free(); lf_finalize(); reply_ng(CMD_LF_EM4X50_SIM, command, NULL, 0); From 6b6f104d9aa6c140c3177b10fb168e871437ec20 Mon Sep 17 00:00:00 2001 From: tharexde Date: Wed, 20 Jan 2021 00:58:48 +0100 Subject: [PATCH 16/22] if no carrier clear former authentication --- armsrc/em4x50.c | 43 +++++++++++++++++-------------------------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index c5f4ec319..05bcfce0e 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -78,6 +78,7 @@ static void wait_timer(uint32_t period) { while (AT91C_BASE_TC0->TC_CV < period); } + // extract and check parities // return result of parity check and extracted plain data static bool extract_parities(uint64_t word, uint32_t *data) { @@ -177,17 +178,9 @@ static void em4x50_setup_read(void) { } static void em4x50_setup_sim(void) { - StopTicks(); - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - - sample_config *sc = getSamplingConfig(); - sc->decimation = 1; - sc->averaging = 0; - sc->divisor = LF_DIVISOR_125; - - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, sc->divisor); FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125); AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT | GPIO_SSC_CLK; AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; @@ -444,7 +437,7 @@ static int find_double_listen_window(bool bcommand) { // first listen window found if (bcommand) { - + // data transmission from card has to be stopped, because // a commamd shall be issued @@ -463,6 +456,7 @@ static int find_double_listen_window(bool bcommand) { // send RM for request mode em4x50_reader_send_bit(0); em4x50_reader_send_bit(0); + LED_B_OFF(); return PM3_SUCCESS; @@ -511,7 +505,7 @@ static bool check_ack(bool bliw) { while (count_cycles < EM4X50_T_WAITING_FOR_ACK) { if (BUTTON_PRESS()) return false; - + if (check_pulse_length(get_pulse_length(), 2 * EM4X50_T_TAG_FULL_PERIOD)) { // The received signal is either ACK or NAK. @@ -661,12 +655,11 @@ static bool login(uint32_t password) { // send 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 - if (check_ack(false)) { + if (check_ack(false)) return PM3_SUCCESS; - } } else { if (DBGLEVEL >= DBG_DEBUG) @@ -808,7 +801,7 @@ static int reset(void) { // send reset command em4x50_reader_send_byte_with_parity(EM4X50_COMMAND_RESET); - + if (check_ack(false)) return PM3_SUCCESS; @@ -924,7 +917,7 @@ void em4x50_info(em4x50_data_t *etd) { } lf_finalize(); - + reply_ng(CMD_LF_EM4X50_INFO, status, (uint8_t *)words, EM4X50_TAG_MAX_NO_BYTES); } @@ -941,7 +934,6 @@ void em4x50_reader(void) { LOW(GPIO_SSC_DOUT); lf_finalize(); - reply_ng(CMD_LF_EM4X50_READER, now, (uint8_t *)words, 4 * now); } @@ -970,15 +962,14 @@ static int write(uint32_t word, uint32_t addresses) { // look for ACK sequence if (check_ack(false)) { - // now EM4x50 needs T0 * EM4X50_T_TAG_TWEE (EEPROM write time) + // now EM4x50 needs T0 * EM4X50_T_TAG_TWEE (EEPROM write time = 3.2ms = 50 * 64 periods) // for saving data and should return with ACK for (int i = 0; i < 50; i++) { wait_timer(T0 * EM4X50_T_TAG_FULL_PERIOD); } - if (check_ack(false)) { + if (check_ack(false)) return PM3_SUCCESS; - } } } } else { @@ -1019,15 +1010,14 @@ static int write_password(uint32_t password, uint32_t new_password) { if (check_ack(false)) { - // now EM4x50 needs T0 * EM4X50_T_TAG_TWEE (EEPROM write time) + // now EM4x50 needs T0 * EM4X50_T_TAG_TWEE (EEPROM write time = 3.2ms = 50 * 64 periods) // for saving data and should return with ACK for (int i = 0; i < 50; i++) { wait_timer(T0 * EM4X50_T_TAG_FULL_PERIOD); } - if (check_ack(false)) { + if (check_ack(false)) return PM3_SUCCESS; - } } } } @@ -1425,8 +1415,6 @@ static void em4x50_sim_send_nak(void) { SHORT_COIL(); wait_cycles(EM4X50_T_TAG_HALF_PERIOD); - - OPEN_COIL(); } // standard read mode process (simulation mode) @@ -1821,9 +1809,12 @@ void em4x50_sim(uint32_t *password) { break; } - // if timeout (e.g. no reader field) continue with standard read mode + // if timeout (e.g. no reader field) continue with standard read + // mode and reset former authentication if (command == PM3_ETIMEOUT) { command = EM4X50_COMMAND_STANDARD_READ; + gLogin = false; + LED_A_OFF(); } } } From ecb5879da8749f8a420ae110ec4c09926c4e21a6 Mon Sep 17 00:00:00 2001 From: tharexde Date: Wed, 20 Jan 2021 01:06:09 +0100 Subject: [PATCH 17/22] entry for extended sim function for EM4x50 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a2c3e0ad..dbe79d9bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file. This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... ## [unreleased][unreleased] + - Added half duplex support for `lf em 4x50 sim` (sim function is now complete) (@tharexde) - Added `tools/hitag2crack/crack5opencl`, an optimized version of `crack5gpu` (@matrix) - Fixed Makefile to account for changes when running on Apple Silicon (@tcprst) - Added support for debugging ARM with JTAG & VSCode (@Gator96100) From 08c2d447fd49e26e37d38a59d10f707576a54d33 Mon Sep 17 00:00:00 2001 From: tharexde Date: Wed, 20 Jan 2021 01:08:20 +0100 Subject: [PATCH 18/22] textual --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dbe79d9bf..323774a34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ All notable changes to this project will be documented in this file. This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... ## [unreleased][unreleased] - - Added half duplex support for `lf em 4x50 sim` (sim function is now complete) (@tharexde) + - Added support for bidirectional communication for `lf em 4x50 sim` (@tharexde) - Added `tools/hitag2crack/crack5opencl`, an optimized version of `crack5gpu` (@matrix) - Fixed Makefile to account for changes when running on Apple Silicon (@tcprst) - Added support for debugging ARM with JTAG & VSCode (@Gator96100) From e09d8b27a2957d692bb0eaffe5af96301dba31d9 Mon Sep 17 00:00:00 2001 From: tharexde Date: Wed, 20 Jan 2021 19:29:57 +0100 Subject: [PATCH 19/22] timeout define instead of hardcoded value --- armsrc/em4x50.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 05bcfce0e..f27a21367 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -1111,7 +1111,7 @@ void em4x50_writepwd(em4x50_data_t *etd) { static void em4x50_sim_send_bit(uint8_t bit) { //uint16_t timeout = EM4X50_T_TAG_FULL_PERIOD; - uint16_t timeout = 500; + uint16_t timeout = EM4X50_T_SIMULATION_TIMEOUT_READ; for (int t = 0; t < EM4X50_T_TAG_FULL_PERIOD; t++) { @@ -1122,7 +1122,7 @@ static void em4x50_sim_send_bit(uint8_t bit) { if (timeout <= 0) { return; } - timeout = 500; + timeout = EM4X50_T_SIMULATION_TIMEOUT_READ; if (bit) OPEN_COIL(); @@ -1134,7 +1134,7 @@ static void em4x50_sim_send_bit(uint8_t bit) { if (timeout <= 0) { return; } - timeout = 500; + timeout = EM4X50_T_SIMULATION_TIMEOUT_READ; if (t == EM4X50_T_TAG_HALF_PERIOD) bit ^= 1; From e061645c6beb333caa801921b124c2def5ed855d Mon Sep 17 00:00:00 2001 From: tharexde Date: Wed, 20 Jan 2021 19:37:38 +0100 Subject: [PATCH 20/22] deleted unneeded include statement --- client/src/cmdlfem4x70.h | 1 - 1 file changed, 1 deletion(-) diff --git a/client/src/cmdlfem4x70.h b/client/src/cmdlfem4x70.h index c72450e88..75e3e27fc 100644 --- a/client/src/cmdlfem4x70.h +++ b/client/src/cmdlfem4x70.h @@ -12,7 +12,6 @@ #define CMDLFEM4X70_H__ #include "common.h" -#include "em4x70.h" #define TIMEOUT 2000 From d41a884c2f0b90665286266571b05c7321ac92a0 Mon Sep 17 00:00:00 2001 From: tharexde Date: Wed, 20 Jan 2021 19:47:14 +0100 Subject: [PATCH 21/22] restoring filename from commit. --- client/src/cmdlfem4x70.h | 1 + 1 file changed, 1 insertion(+) diff --git a/client/src/cmdlfem4x70.h b/client/src/cmdlfem4x70.h index 75e3e27fc..f0f221b06 100644 --- a/client/src/cmdlfem4x70.h +++ b/client/src/cmdlfem4x70.h @@ -12,6 +12,7 @@ #define CMDLFEM4X70_H__ #include "common.h" +#include "em4x50.h" #define TIMEOUT 2000 From 843dd9bef49b3b5931574e9534c744205a0d2a42 Mon Sep 17 00:00:00 2001 From: tharexde Date: Wed, 20 Jan 2021 19:47:55 +0100 Subject: [PATCH 22/22] deleted unneeded include statement --- client/src/cmdlfem4x70.h | 1 - 1 file changed, 1 deletion(-) diff --git a/client/src/cmdlfem4x70.h b/client/src/cmdlfem4x70.h index f0f221b06..75e3e27fc 100644 --- a/client/src/cmdlfem4x70.h +++ b/client/src/cmdlfem4x70.h @@ -12,7 +12,6 @@ #define CMDLFEM4X70_H__ #include "common.h" -#include "em4x50.h" #define TIMEOUT 2000