diff --git a/armsrc/Makefile b/armsrc/Makefile index 0b540b84..e6dd4009 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -15,7 +15,7 @@ APP_CFLAGS = -DWITH_ISO14443a_StandAlone -DWITH_LF -DWITH_ISO15693 -DWITH_ISO144 #-DWITH_LCD #SRC_LCD = fonts.c LCD.c -SRC_LF = lfops.c hitag2.c hitagS.c lfsampling.c pcf7931.c lfdemod.c protocols.c +SRC_LF = lfops.c hitag2.c hitagS.c em4x50.c lfsampling.c pcf7931.c lfdemod.c protocols.c SRC_ISO15693 = iso15693.c iso15693tools.c SRC_ISO14443a = epa.c iso14443a.c mifareutil.c mifarecmd.c mifaresniff.c SRC_ISO14443b = iso14443b.c diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 475b1c1b..9da10656 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1005,6 +1005,9 @@ void UsbPacketReceived(uint8_t *packet, int len) case CMD_VIKING_CLONE_TAG: CopyVikingtoT55xx(c->arg[0], c->arg[1], c->arg[2]); break; + case CMD_SIMULATE_EM4x50: // Simulate EM4x50 tag, args = memory content + SimulateEM4x50Tag((bool)c->arg[0], (byte_t*)c->d.asBytes); + break; #endif #ifdef WITH_HITAG diff --git a/armsrc/apps.h b/armsrc/apps.h index 4d4c8083..d2f6085c 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -175,6 +175,9 @@ void iClass_Dump(uint8_t blockno, uint8_t numblks); void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data); void iClass_ReadCheck(uint8_t blockNo, uint8_t keyType); +// em4x50 +void SimulateEM4x50Tag(bool tag_mem_supplied, byte_t* data); + // hitag2.h void SnoopHitag(uint32_t type); void SimulateHitagTag(bool tag_mem_supplied, byte_t* data); diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c new file mode 100644 index 00000000..8f5a10b7 --- /dev/null +++ b/armsrc/em4x50.c @@ -0,0 +1,708 @@ +#include "proxmark3.h" +#include "apps.h" +#include "util.h" +#include "string.h" + +#define EM4x50_PASSWORD 0 +#define EM4x50_PROTECTION 1 +#define EM4x50_CONTROL 2 +#define EM4x50_SERIAL 32 +#define EM4x50_DEVICE_ID 33 + +#define EM4x50_FIRST_WORD_READ_BYTE 0 +#define EM4x50_LAST_WORD_READ_BYTE 1 +#define EM4x50_FIRST_WORD_READ_PROTECTED_BYTE 0 +#define EM4x50_LAST_WORD_READ_PROTECTED_BYTE 1 +#define EM4x50_FIRST_WORD_WRITE_INHIBITED_BYTE 2 +#define EM4x50_LAST_WORD_WRITE_INHIBITED_BYTE 3 +#define EM4X50_PASSWORD_CHECK_BIT 16 +#define EM4X50_READ_AFTER_WRITE 17 + +// Sam7s has several timers, we will use the source TIMER_CLOCK1 (aka AT91C_TC_CLKS_TIMER_DIV1_CLOCK) +// TIMER_CLOCK1 = MCK/2, MCK is running at 48 MHz, Timer is running at 48/2 = 24 MHz +// Hitag units (T0) have duration of 8 microseconds (us), which is 1/125000 per second (carrier) +// T0 = TIMER_CLOCK1 / 125000 = 192 +#define T0 192 + +#define EM4x50_T_HALF_PERIOD 32 +#define EM4x50_T_FULL_PERIOD 64 + +#define EM4x50_COMMAND_NONE 0xFF +#define EM4x50_COMMAND_BREAK 0x00 +#define EM4x50_COMMAND_LOGIN 0x01 +#define EM4x50_COMMAND_WRITE_PASSWORD 0x11 +#define EM4x50_COMMAND_WRITE 0x12 +#define EM4x50_COMMAND_SELECTIVE_READ 0x0A +#define EM4x50_COMMAND_RESET 0x80 + +#define EM4X50_T_PROCESSING_PAUSE 64 +#define EM4X50_T_INIT 2112 +#define EM4X50_T_WRITE_ACCESS 64 +#define EM4X50_T_EEPROM_WRITE 3200 + +#define EM4X50_WAITING_FOR_DATA 0 +#define EM4X50_WAITING_FOR_BYTE_PARITY 1 +#define EM4X50_WAITING_FOR_CULOMN_PARITY 2 +#define EM4X50_WAITING_FOR_0 3 + +#define EM4X50_STATE_READ 0 +#define EM4X50_STATE_SELECTIVE_READ 1 + +// 1. Login command arguments are +// a. current password (32 bit password + 4 bit byte parity + 8 bit culommn parity + 0) +// 2. Write password arguments are +// a. new password (32 bit password + 4 bit byte parity + 8 bit culommn parity + 0) +// b. current password (32 bit password + 4 bit byte parity + 8 bit culommn parity + 0) +// 3. Write arguments are +// a. address (2 0s + 6 bit address + 1 bit parity) +// b. data (32 bit data + 4 bit byte parity + 8 bit culommn parity + 0) +// 4. Selective read arguments are +// a. First address (2 0s + 6 bit address + 1 bit parity) +// b. Last address (2 0s + 6 bit address + 1 bit parity) +// 5. Reset command has not arguments + +struct em4x50_tag +{ + int state; + int first_word; + int last_word; + byte_t data[34][4]; +}; + +static struct em4x50_tag tag = { + .state = EM4X50_STATE_READ, + .first_word = 0x20, + .last_word = 0x21, + .data = { + [0] = { 0x00, 0x00, 0x00, 0x00 }, // PASSWORD + [1] = { 0x00, 0x1F, 0x00, 0x00 }, // PROTECTION WORD + [2] = { 0x20, 0x20, 0x00, 0x00 }, // CONTROL WORD + [3] = { 0x01, 0x02, 0x03, 0x04 }, // User + [4] = { 0x05, 0x06, 0x07, 0x08 }, // User + [5] = { 0x09, 0x0A, 0x0B, 0x0C }, // User + [6] = { 0x0D, 0x0E, 0x0F, 0x00 }, // User + [7] = { 0x11, 0x12, 0x13, 0x14 }, // User + [8] = { 0x15, 0x16, 0x17, 0x18 }, // User + [9] = { 0x19, 0x1A, 0x1B, 0x1C }, // User + [10] = { 0x1D, 0x1E, 0x1F, 0x10 }, // User + [11] = { 0x21, 0x22, 0x23, 0x24 }, // User + [12] = { 0x25, 0x26, 0x27, 0x28 }, // User + [13] = { 0x29, 0x2A, 0x2B, 0x2C }, // User + [14] = { 0x2D, 0x2E, 0x2F, 0x20 }, // User + [15] = { 0x31, 0x32, 0x33, 0x34 }, // User + [16] = { 0x35, 0x36, 0x37, 0x38 }, // User + [17] = { 0x39, 0x3A, 0x3B, 0x3C }, // User + [18] = { 0x3D, 0x3E, 0x3F, 0x30 }, // User + [19] = { 0x41, 0x42, 0x43, 0x44 }, // User + [20] = { 0x45, 0x46, 0x47, 0x48 }, // User + [21] = { 0x49, 0x4A, 0x4B, 0x4C }, // User + [22] = { 0x4D, 0x4E, 0x4F, 0x40 }, // User + [23] = { 0x51, 0x52, 0x53, 0x54 }, // User + [24] = { 0x55, 0x56, 0x57, 0x58 }, // User + [25] = { 0x59, 0x5A, 0x5B, 0x5C }, // User + [26] = { 0x5D, 0x5E, 0x5F, 0x50 }, // User + [27] = { 0x61, 0x62, 0x63, 0x64 }, // User + [28] = { 0x65, 0x66, 0x67, 0x68 }, // User + [29] = { 0x69, 0x6A, 0x6B, 0x6C }, // User + [30] = { 0x6D, 0x6E, 0x6F, 0x60 }, // User + [31] = { 0x71, 0x72, 0x73, 0x74 }, // User + [32] = { 0x11, 0x22, 0x33, 0x44 }, // Serial number + [33] = { 0x55, 0x66, 0x77, 0x88 } // Device id + } +}; + +static void em4x50_init() +{ + tag.state = EM4X50_STATE_READ; + tag.first_word = tag.data[EM4x50_CONTROL][EM4x50_FIRST_WORD_READ_BYTE]; + tag.last_word = tag.data[EM4x50_CONTROL][EM4x50_LAST_WORD_READ_BYTE]; +} + +static int em4x50_receive_bit() +{ + return 1; +} + +static void em4x50_send_bit(int bit) +{ + // Reset clock for the next bit + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + + // Fixed modulation + if (bit == 0) + { + // Manchester: Unloaded, then loaded |__--| + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0*EM4x50_T_HALF_PERIOD); + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0*EM4x50_T_FULL_PERIOD); + } + else + { + // Manchester: Loaded, then unloaded |--__| + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0*EM4x50_T_HALF_PERIOD); + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0*EM4x50_T_FULL_PERIOD); + } +} + +static void em4x50_send_byte(byte_t byte) +{ + int mask = 0x80; + + for (int i = 0; i < 8; i++) + { + if ((byte & mask) == 0) + { + em4x50_send_bit(0); + } + else + { + em4x50_send_bit(1); + } + + mask >>= 1; + } +} + +static void em4x50_send_byte_with_parity(byte_t byte) +{ + int parity = 0; + int mask = 0x80; + + for (int i = 0; i < 8; i++) + { + if ((byte & mask) == 0) + { + em4x50_send_bit(0); + parity ^= 0; + } + else + { + em4x50_send_bit(1); + parity ^= 1; + } + + mask >>= 1; + } + + em4x50_send_bit(parity); +} + +static void em4x50_send_word(int index) +{ + int parity = 0; + + for (int i = 0; i < 4; i++) + { + em4x50_send_byte_with_parity(tag.data[index][i]); + + parity ^= tag.data[index][i]; + } + + em4x50_send_byte(parity); + em4x50_send_bit(0); +} + +static int em4x50_listen_one_bit(int *time, int *timestamp) +{ + int bit = 1; + + // 32 RF periods - high + *time += T0*EM4x50_T_HALF_PERIOD; + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < *time); + + // 32 RF periods - low + *time += T0*EM4x50_T_HALF_PERIOD; + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < *time); + + return bit; +} + +static int em4x50_listen() +{ + int period = 0; + int first_bit = 1; + int second_bit = 1; + int data_bit; + int parity_bit; + int command = EM4x50_COMMAND_BREAK; + bool command_is_valid = false; + int parity = 0; + int zero_falling_edge_time[2] = { -1, -1 }; + int data_falling_edge_time[9] = { -1, -1, -1, -1, -1, -1, -1, -1, -1 }; + + // Reset clocks + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + + // The listen window is composed of + // 32 RF periods - high + // 32 RF periods - low + // 128 RF periods - high + // 64 RF periods - low + // 64 RF periods - high + + first_bit = em4x50_listen_one_bit(&period, &zero_falling_edge_time[0]); + if (first_bit == 0) + { + second_bit = em4x50_listen_one_bit(&period, &zero_falling_edge_time[1]); + if (second_bit == 0) + { + for (int i = 0; i < 8; i++) + { + data_bit = em4x50_listen_one_bit(&period, &data_falling_edge_time[i]); + command |= (data_bit << (7 - i)); + parity ^= data_bit; + } + + parity_bit = em4x50_listen_one_bit(&period, &data_falling_edge_time[8]); + if (parity_bit == parity) + { + command_is_valid = true; + } + } + } + else + { + // 128 RF periods - high + period += T0 * 2 * EM4x50_T_FULL_PERIOD; + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < period); + + // 64 RF periods - low + period += T0 * EM4x50_T_FULL_PERIOD; + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < period); + + // 64 RF periods - high + period += T0 * EM4x50_T_FULL_PERIOD; + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < period); + + command = EM4x50_COMMAND_NONE; + } + + if (second_bit == 0) + { + if ((command_is_valid == false) || (command == EM4x50_COMMAND_NONE)) + { + command = EM4x50_COMMAND_BREAK; + } + } + + return command; +} + +static void em4x50_send_ack() +{ + int period; + + // Reset clock + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + + period = T0*EM4x50_T_HALF_PERIOD; + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < period); + + period += T0*EM4x50_T_HALF_PERIOD; + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < period); + + period += T0 * 3 * EM4x50_T_HALF_PERIOD; + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < period); + + period += T0 * EM4x50_T_HALF_PERIOD; + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < period); + + period += T0 * 3 * EM4x50_T_HALF_PERIOD; + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < period); + + period += T0 * EM4x50_T_HALF_PERIOD; + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < period); +} + +static void em4x50_send_nack() +{ + int period; + + // Reset clock + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + + period = T0*EM4x50_T_HALF_PERIOD; + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < period); + + period += T0*EM4x50_T_HALF_PERIOD; + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < period); + + period += T0 * 3 * EM4x50_T_HALF_PERIOD; + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < period); + + period += T0 * EM4x50_T_HALF_PERIOD; + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < period); + + period += T0 * 3 * EM4x50_T_HALF_PERIOD; + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < period); + + period += T0 * EM4x50_T_HALF_PERIOD; + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < period); +} + +static void em4x50_handle_login_command() +{ + bool done = false; + bool success = true; + int state = EM4X50_WAITING_FOR_DATA; + int in_state_bits = 0; + int data_bits = 0; + int password = 0; + int byte_parity = 0; + byte_t password_culomn_parity = 0; + byte_t culomn_parity = 0; + + while ((success == true) && (done == false)) + { + int bit = em4x50_receive_bit(); + + switch (state) + { + case EM4X50_WAITING_FOR_DATA: + { + password <<= 1; + password |= bit; + byte_parity ^= bit; + in_state_bits++; + if (in_state_bits == 8) + { + password_culomn_parity ^= (byte_t)password; + + data_bits += in_state_bits; + in_state_bits = 0; + + state = EM4X50_WAITING_FOR_BYTE_PARITY; + } + } + break; + case EM4X50_WAITING_FOR_BYTE_PARITY: + { + if (byte_parity == bit) + { + byte_parity = 0; + + if (data_bits == 32) + { + state = EM4X50_WAITING_FOR_CULOMN_PARITY; + } + else + { + state = EM4X50_WAITING_FOR_DATA; + } + } + else + { + success = false; + } + } + break; + case EM4X50_WAITING_FOR_CULOMN_PARITY: + { + culomn_parity <<= 1; + culomn_parity |= bit; + in_state_bits++; + if (in_state_bits == 8) + { + if (culomn_parity == password_culomn_parity) + { + state = EM4X50_WAITING_FOR_0; + } + else + { + success = false; + } + } + } + break; + case EM4X50_WAITING_FOR_0: + { + if (bit == 0) + { + done = true; + } + { + success = false; + } + } + break; + }; + } + + if (success == false) + { + em4x50_send_nack(); + } + else + { + em4x50_send_ack(); + } + + // Wait for processing pause time + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + while (AT91C_BASE_TC0->TC_CV < EM4X50_T_PROCESSING_PAUSE); +} + +static void em4x50_handle_write_password_command() +{ +} + +static void em4x50_handle_write_command() +{ +} + +static void em4x50_handle_selective_read_command() +{ + bool done = false; + bool success = true; + int state = EM4X50_WAITING_FOR_DATA; + int in_state_bits = 0; + byte_t first_address = 0; + byte_t last_address = 0; + byte_t *p_address = &first_address; + int byte_parity = 0; + + while ((success == true) && (done == false)) + { + int bit = em4x50_receive_bit(); + + switch (state) + { + case EM4X50_WAITING_FOR_DATA: + { + (*p_address) <<= 1; + (*p_address) |= bit; + byte_parity ^= bit; + in_state_bits++; + if (in_state_bits == 8) + { + in_state_bits = 0; + + state = EM4X50_WAITING_FOR_BYTE_PARITY; + } + } + break; + case EM4X50_WAITING_FOR_BYTE_PARITY: + { + if (byte_parity == bit) + { + if (p_address == &first_address) + { + p_address = &last_address; + byte_parity = 0; + + state = EM4X50_WAITING_FOR_DATA; + } + else + { + done = true; + } + } + else + { + success = false; + } + } + break; + }; + } + + if (success == false) + { + em4x50_send_nack(); + } + else + { + em4x50_send_ack(); + } + + // Wait for processing pause time + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + while (AT91C_BASE_TC0->TC_CV < EM4X50_T_PROCESSING_PAUSE); +} + +static void em4x50_handle_reset_command() +{ + // Wait for processing pause time + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + while (AT91C_BASE_TC0->TC_CV < EM4X50_T_PROCESSING_PAUSE); + + em4x50_init(); + + em4x50_send_ack(); + + // Wait for init time + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + while (AT91C_BASE_TC0->TC_CV < EM4X50_T_INIT); +} + +void SimulateEM4x50Tag(bool tag_mem_supplied, byte_t* data) +{ + int command; + + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + + // Clean up trace and prepare it for storing frames + set_tracing(TRUE); + clear_trace(); + + DbpString("Starting EM4x50 simulation"); + LED_D_ON(); + + if (tag_mem_supplied) + { + DbpString("Loading EM4x50 memory..."); + memcpy((byte_t*)tag.data, data, sizeof(tag.data)); + em4x50_init(); + } + + Dbprintf("Read mode %d -> %d", tag.first_word, tag.last_word); + + // Set up simulator mode, frequency divisor which will drive the FPGA + // and analog mux selection. + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_READER_FIELD); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + SetAdcMuxFor(GPIO_MUXSEL_LOPKD); + RELAY_OFF(); + + // Configure output pin that is connected to the FPGA (for modulating) + AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; + AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; + + // Disable modulation at default, which means release resistance + LOW(GPIO_SSC_DOUT); + + // Enable Peripheral Clock for TIMER_CLOCK0, used to measure exact timing before answering + AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0); + + // Enable Peripheral Clock for TIMER_CLOCK1, used to capture edges of the reader frames + AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1); + AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; + + // Enable timer + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + + // Disable timer during configuration + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + // Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, + // external trigger falling edge, load RA on falling edge of TIOA. + AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_FALLING | AT91C_TC_ABETRG | AT91C_TC_LDRA_FALLING; + + while (!BUTTON_PRESS()) + { + // Watchdog hit + WDT_HIT(); + + // The structure for each frame is + // LISTEN_WINDOW LISTEN_WINDOW FIRST_WORD LISTEN_WINDOW SECOND_WORD ...... LISTEN_WINDOW LAST_WORD + // i.e. it starts with a listen windows and then pairs of (listen window, data word). + // In read mode the range of transmitteed words is defined by the control register. + // During the listen window the transceiver can send commands to the em4x50 . The em4x50 will stop the frame transmission + // and will perform the command. + + // Start a frame with a listen window. + command = em4x50_listen(); + + // If no command was received during the listen window, continue with the frame transmission. + if (command == EM4x50_COMMAND_NONE) + { + // Loop thought the [first_word..last_word] and transmit pairs of (listen window, data word). + for (int i = tag.first_word; i <= tag.last_word; i++) + { + // // Start a pair with a listen window. + command = em4x50_listen(); + + // If no command was received during the listen window, continue with the data word transmission. + if (command == EM4x50_COMMAND_NONE) + { + em4x50_send_word(i); + } + // If a command was received during the listen window, break the frame transmission. + else + { + break; + } + } + } + + // The transceiver can send a selective mode command and provide the first and last word to be transmitted. The em4x50 will send + // those words in the follwoing frame once and will return to read mode. + // If the current frame was transmitted in selective read state then the em4x50 should return to read mode. + if (tag.state == EM4X50_STATE_SELECTIVE_READ) + { + // Set the state to read mode. + tag.state = EM4X50_STATE_READ; + + // Set the transmitted words range according to the control register. + tag.first_word = tag.data[EM4x50_CONTROL][EM4x50_FIRST_WORD_READ_BYTE]; + tag.last_word = tag.data[EM4x50_CONTROL][EM4x50_LAST_WORD_READ_BYTE]; + } + + // If a command was received during the frame + if (command != EM4x50_COMMAND_NONE) + { + switch (command) + { + case EM4x50_COMMAND_BREAK: + { + } + break; + case EM4x50_COMMAND_LOGIN: + { + // Handle login command. + em4x50_handle_login_command(); + } + break; + case EM4x50_COMMAND_WRITE_PASSWORD: + { + // Handle write password command. + em4x50_handle_write_password_command(); + } + break; + case EM4x50_COMMAND_WRITE: + { + // Handle write command. + em4x50_handle_write_command(); + } + break; + case EM4x50_COMMAND_SELECTIVE_READ: + { + // Handle selective command. + em4x50_handle_selective_read_command(); + } + break; + case EM4x50_COMMAND_RESET: + { + // Handle reset command. + em4x50_handle_reset_command(); + } + break; + }; + } + } + + LED_D_OFF(); + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + + DbpString("Sim Stopped"); +} \ No newline at end of file diff --git a/client/cmdlfem4x.c b/client/cmdlfem4x.c index aa0fc856..3ff881a1 100644 --- a/client/cmdlfem4x.c +++ b/client/cmdlfem4x.c @@ -498,6 +498,44 @@ int CmdEM4x50Read(const char *Cmd) return EM4x50Read(Cmd, true); } +int CmdEM4x50Sim(const char *Cmd) +{ + UsbCommand c = { CMD_SIMULATE_EM4x50 }; + char filename[FILE_PATH_SIZE] = { 0x00 }; + FILE* pf; + bool tag_mem_supplied; + int len = strlen(Cmd); + if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; + memcpy(filename, Cmd, len); + + if (strlen(filename) > 0) + { + if ((pf = fopen(filename, "rb+")) == NULL) + { + PrintAndLog("Error: Could not open file [%s]", filename); + return 1; + } + tag_mem_supplied = true; + if (fread(c.d.asBytes, 136, 1, pf) == 0) + { + PrintAndLog("Error: File reading error"); + fclose(pf); + return 1; + } + fclose(pf); + } + else + { + tag_mem_supplied = false; + } + + // Does the tag comes with memory + c.arg[0] = (uint32_t)tag_mem_supplied; + + SendCommand(&c); + return 0; +} + int CmdReadWord(const char *Cmd) { int Word = -1; //default to invalid word @@ -604,6 +642,7 @@ static command_t CommandTable[] = {"em410xspoof", CmdEM410xWatchnSpoof, 0, "['h'] --- Watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)" }, {"em410xwrite", CmdEM410xWrite, 0, " <'0' T5555> <'1' T55x7> [clock rate] -- Write EM410x UID to T5555(Q5) or T55x7 tag, optionally setting clock rate"}, {"em4x50read", CmdEM4x50Read, 1, "Extract data from EM4x50 tag"}, + {"em4x50sim", CmdEM4x50Sim, 0, "Simulates an EM4x50 tag"}, {"readword", CmdReadWord, 1, " -- Read EM4xxx word data"}, {"readwordPWD", CmdReadWordPWD, 1, " -- Read EM4xxx word data in password mode"}, {"writeword", CmdWriteWord, 1, " -- Write EM4xxx word data"}, diff --git a/client/hid-flasher/usb_cmd.h b/client/hid-flasher/usb_cmd.h index bdf18912..9618252d 100644 --- a/client/hid-flasher/usb_cmd.h +++ b/client/hid-flasher/usb_cmd.h @@ -87,6 +87,7 @@ typedef struct { #define CMD_AWID_DEMOD_FSK 0x0221 #define CMD_VIKING_CLONE_TAG 0x0223 #define CMD_T55XX_WAKEUP 0x0224 +#define CMD_SIMULATE_EM4x50 0x0225 /* CMD_SET_ADC_MUX: ext1 is 0 for lopkd, 1 for loraw, 2 for hipkd, 3 for hiraw */ diff --git a/include/usb_cmd.h b/include/usb_cmd.h index 8448b06a..6441e1a7 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -101,7 +101,7 @@ typedef struct{ #define CMD_AWID_DEMOD_FSK 0x0221 #define CMD_VIKING_CLONE_TAG 0x0223 #define CMD_T55XX_WAKEUP 0x0224 - +#define CMD_SIMULATE_EM4x50 0x0225 /* CMD_SET_ADC_MUX: ext1 is 0 for lopkd, 1 for loraw, 2 for hipkd, 3 for hiraw */