This commit is contained in:
iceman1001 2025-03-18 08:11:06 +01:00
commit a776f9a0bd
10 changed files with 231 additions and 187 deletions

View file

@ -108,13 +108,13 @@ static bool command_parity = true;
// //
// Four of the commands send a predetermined bitstream, immediately synchronize // Four of the commands send a predetermined bitstream, immediately synchronize
// on the tag sending the header, and then receive a number of bits from the tag: // on the tag sending the header, and then receive a number of bits from the tag:
// //
// #define EM4X70_COMMAND_ID 0x01 // 0b0001 --> 0b001'1 // #define EM4X70_COMMAND_ID 0x01 // 0b0001 --> 0b001'1
// Tag: [LIW] [Header][ID₃₁..ID₀][LIW] // Tag: [LIW] [Header][ID₃₁..ID₀][LIW]
// Reader: [RM][Command] // Reader: [RM][Command]
// Bits Sent: RM + 4 bits // Bits Sent: RM + 4 bits
// Bits Recv: Header + 32 bits // Bits Recv: Header + 32 bits
// //
// #define EM4X70_COMMAND_UM1 0x02 // 0b0010 --> 0b010'1 // #define EM4X70_COMMAND_UM1 0x02 // 0b0010 --> 0b010'1
// Tag: [LIW] [Header][LB₁, LB₀, UM1₂₉..UM1₀][LIW] // Tag: [LIW] [Header][LB₁, LB₀, UM1₂₉..UM1₀][LIW]
// Reader: [RM][Command] // Reader: [RM][Command]
@ -171,7 +171,7 @@ static bool command_parity = true;
// Auto-detect tag variant and command parity? // Auto-detect tag variant and command parity?
// EM4070/V4070 does not contain UM2 or PIN, and UM1 may be OTP (one-time programmable) // EM4070/V4070 does not contain UM2 or PIN, and UM1 may be OTP (one-time programmable)
// EM4170 added Pin and UM2, and UM1 // EM4170 added Pin and UM2, and UM1
// //
// Thus, to check for overlap, need only check the first three commands with parity: // Thus, to check for overlap, need only check the first three commands with parity:
// | CMD | P? | Bits | Safe? | Overlaps With | Notes // | CMD | P? | Bits | Safe? | Overlaps With | Notes
// |-------|-----|----------|-------|------------------|------------ // |-------|-----|----------|-------|------------------|------------
@ -182,7 +182,7 @@ static bool command_parity = true;
// | PIN | No | `0b0100` | N/A | | DO NOT USE ... just in case // | PIN | No | `0b0100` | N/A | | DO NOT USE ... just in case
// | UM2 | No | `0b0111` | Yes | None! | Safe ... indicates no parity AND EM4170 tag type // | UM2 | No | `0b0111` | Yes | None! | Safe ... indicates no parity AND EM4170 tag type
// | ID | Yes | `0b0011` | Yes | Auth w/o Parity | Safe to try ... indicates parity if successful // | ID | Yes | `0b0011` | Yes | Auth w/o Parity | Safe to try ... indicates parity if successful
// | UM1 | Yes | `0b0101` | Yes | Write w/o Parity | // | UM1 | Yes | `0b0101` | Yes | Write w/o Parity |
// | AUTH | Yes | `0b0110` | Yes | None! | Not testable // | AUTH | Yes | `0b0110` | Yes | None! | Not testable
// | WRITE | Yes | `0b1010` | NO | None! | DO NOT USE ... just in case // | WRITE | Yes | `0b1010` | NO | None! | DO NOT USE ... just in case
// | PIN | Yes | `0b1001` | N/A | None! | DO NOT USE ... just in case // | PIN | Yes | `0b1001` | N/A | None! | DO NOT USE ... just in case
@ -359,15 +359,15 @@ typedef struct _em4x70_transmit_log_t {
em4x70_sublog_t receive; em4x70_sublog_t receive;
} em4x70_transmitted_data_log_t; } em4x70_transmitted_data_log_t;
em4x70_transmitted_data_log_t g_not_used_directly; // change to bigbuff allocation? em4x70_transmitted_data_log_t g_not_used_directly; // change to bigbuff allocation?
em4x70_transmitted_data_log_t* g_Log = &g_not_used_directly; em4x70_transmitted_data_log_t *g_Log = &g_not_used_directly;
static void log_reset(void) { static void log_reset(void) {
if (g_Log != NULL) { if (g_Log != NULL) {
memset(g_Log, 0, sizeof(em4x70_transmitted_data_log_t)); memset(g_Log, 0, sizeof(em4x70_transmitted_data_log_t));
} }
} }
static void log_dump_helper(em4x70_sublog_t * part, bool is_transmit) { static void log_dump_helper(em4x70_sublog_t *part, bool is_transmit) {
if (g_dbglevel >= DBG_INFO || FORCE_ENABLE_LOGGING) { if (g_dbglevel >= DBG_INFO || FORCE_ENABLE_LOGGING) {
char const * const direction = is_transmit ? "sent >>>" : "recv <<<"; char const *const direction = is_transmit ? "sent >>>" : "recv <<<";
if (part->bits_used == 0) { if (part->bits_used == 0) {
DPRINTF_EXTENDED(("%s: no data", direction)); DPRINTF_EXTENDED(("%s: no data", direction));
} else { } else {
@ -377,12 +377,12 @@ static void log_dump_helper(em4x70_sublog_t * part, bool is_transmit) {
bitstring[i] = part->bit[i] ? '1' : '0'; bitstring[i] = part->bit[i] ? '1' : '0';
} }
DPRINTF_EXTENDED(( DPRINTF_EXTENDED((
"%s: [ %8d .. %8d ] ( %6d ) %2d bits: %s", "%s: [ %8d .. %8d ] ( %6d ) %2d bits: %s",
direction, direction,
part->start_tick, part->end_tick, part->start_tick, part->end_tick,
part->end_tick - part->start_tick, part->end_tick - part->start_tick,
part->bits_used, bitstring part->bits_used, bitstring
)); ));
} }
} }
} }
@ -390,7 +390,7 @@ static void log_dump(void) {
if (g_dbglevel >= DBG_INFO || FORCE_ENABLE_LOGGING) { if (g_dbglevel >= DBG_INFO || FORCE_ENABLE_LOGGING) {
bool hasContent = false; bool hasContent = false;
if (g_Log != NULL) { if (g_Log != NULL) {
uint8_t * check_for_data = (uint8_t *)g_Log; uint8_t *check_for_data = (uint8_t *)g_Log;
for (size_t i = 0; i < sizeof(em4x70_transmitted_data_log_t); ++i) { for (size_t i = 0; i < sizeof(em4x70_transmitted_data_log_t); ++i) {
if (check_for_data[i] != 0) { if (check_for_data[i] != 0) {
hasContent = true; hasContent = true;
@ -419,7 +419,7 @@ static void log_sent_bit_end(uint32_t end_tick) {
} }
} }
static void log_received_bit_start(uint32_t start_tick) { static void log_received_bit_start(uint32_t start_tick) {
if (g_Log != NULL && g_Log->receive.start_tick == 0) { if (g_Log != NULL && g_Log->receive.start_tick == 0) {
g_Log->receive.start_tick = start_tick; g_Log->receive.start_tick = start_tick;
} }
} }
@ -475,7 +475,7 @@ static bool check_ack(void) {
// ACK 64 + 64 // ACK 64 + 64
// NAK 64 + 48 // NAK 64 + 48
if (check_pulse_length(get_pulse_length(FALLING_EDGE), 2 * EM4X70_T_TAG_FULL_PERIOD) && if (check_pulse_length(get_pulse_length(FALLING_EDGE), 2 * EM4X70_T_TAG_FULL_PERIOD) &&
check_pulse_length(get_pulse_length(FALLING_EDGE), 2 * EM4X70_T_TAG_FULL_PERIOD)) { check_pulse_length(get_pulse_length(FALLING_EDGE), 2 * EM4X70_T_TAG_FULL_PERIOD)) {
// ACK // ACK
return true; return true;
} }
@ -516,12 +516,12 @@ typedef struct _em4x70_command_bitstream {
uint8_t received_data_converted_to_bytes[(EM4X70_MAX_BITSTREAM_BITS / 8) + (EM4X70_MAX_BITSTREAM_BITS % 8 ? 1 : 0)]; uint8_t received_data_converted_to_bytes[(EM4X70_MAX_BITSTREAM_BITS / 8) + (EM4X70_MAX_BITSTREAM_BITS % 8 ? 1 : 0)];
} em4x70_command_bitstream_t; } em4x70_command_bitstream_t;
typedef bool (*bitstream_command_generator_id_t)(em4x70_command_bitstream_t * out_cmd_bitstream, bool with_command_parity); typedef bool (*bitstream_command_generator_id_t)(em4x70_command_bitstream_t *out_cmd_bitstream, bool with_command_parity);
typedef bool (*bitstream_command_generator_um1_t)(em4x70_command_bitstream_t * out_cmd_bitstream, bool with_command_parity); typedef bool (*bitstream_command_generator_um1_t)(em4x70_command_bitstream_t *out_cmd_bitstream, bool with_command_parity);
typedef bool (*bitstream_command_generator_um2_t)(em4x70_command_bitstream_t * out_cmd_bitstream, bool with_command_parity); typedef bool (*bitstream_command_generator_um2_t)(em4x70_command_bitstream_t *out_cmd_bitstream, bool with_command_parity);
typedef bool (*bitstream_command_generator_auth_t)(em4x70_command_bitstream_t * out_cmd_bitstream, bool with_command_parity, const uint8_t * rnd, const uint8_t * frnd); typedef bool (*bitstream_command_generator_auth_t)(em4x70_command_bitstream_t *out_cmd_bitstream, bool with_command_parity, const uint8_t *rnd, const uint8_t *frnd);
typedef bool (*bitstream_command_generator_pin_t)(em4x70_command_bitstream_t * out_cmd_bitstream, bool with_command_parity, const uint8_t * tag_id, const uint32_t pin_little_endian); typedef bool (*bitstream_command_generator_pin_t)(em4x70_command_bitstream_t *out_cmd_bitstream, bool with_command_parity, const uint8_t *tag_id, const uint32_t pin_little_endian);
typedef bool (*bitstream_command_generator_write_t)(em4x70_command_bitstream_t * out_cmd_bitstream, bool with_command_parity, uint16_t data_little_endian, uint8_t address); typedef bool (*bitstream_command_generator_write_t)(em4x70_command_bitstream_t *out_cmd_bitstream, bool with_command_parity, uint16_t data_little_endian, uint8_t address);
typedef struct _em4x70_command_generators_t { typedef struct _em4x70_command_generators_t {
bitstream_command_generator_id_t id; bitstream_command_generator_id_t id;
@ -534,9 +534,9 @@ typedef struct _em4x70_command_generators_t {
#endif // #pragma endregion // Bitstream structures / enumerations #endif // #pragma endregion // Bitstream structures / enumerations
#if 1 // #pragma region // Functions to dump bitstreams to debug output #if 1 // #pragma region // Functions to dump bitstreams to debug output
static void bitstream_dump_helper(const em4x70_bitstream_t * bitstream, bool is_transmit) { static void bitstream_dump_helper(const em4x70_bitstream_t *bitstream, bool is_transmit) {
// mimic the log's output format to make comparisons easier // mimic the log's output format to make comparisons easier
char const * const direction = is_transmit ? "sent >>>" : "recv <<<"; char const *const direction = is_transmit ? "sent >>>" : "recv <<<";
if (bitstream->bitcount == 0) { if (bitstream->bitcount == 0) {
if (g_dbglevel >= DBG_INFO || true) { if (g_dbglevel >= DBG_INFO || true) {
DPRINTF_EXTENDED(("%s: no data", direction)); DPRINTF_EXTENDED(("%s: no data", direction));
@ -550,17 +550,17 @@ static void bitstream_dump_helper(const em4x70_bitstream_t * bitstream, bool is_
bitstring[i] = bitstream->one_bit_per_byte[i] ? '1' : '0'; bitstring[i] = bitstream->one_bit_per_byte[i] ? '1' : '0';
} }
DPRINTF_EXTENDED(( DPRINTF_EXTENDED((
"%s: [ %8d .. %8d ] ( %6d ) %2d bits: %s%s", "%s: [ %8d .. %8d ] ( %6d ) %2d bits: %s%s",
direction, direction,
0, 0, 0, 0, 0, 0,
bitstream->bitcount + (is_transmit ? 2u : 0u), // add the two RM bits to transmitted data bitstream->bitcount + (is_transmit ? 2u : 0u), // add the two RM bits to transmitted data
is_transmit ? "00" : "", // add the two RM bits to transmitted data is_transmit ? "00" : "", // add the two RM bits to transmitted data
bitstring bitstring
)); ));
} }
} }
static void bitstream_dump(const em4x70_command_bitstream_t * cmd_bitstream) { static void bitstream_dump(const em4x70_command_bitstream_t *cmd_bitstream) {
bitstream_dump_helper(&cmd_bitstream->to_send, true ); bitstream_dump_helper(&cmd_bitstream->to_send, true);
bitstream_dump_helper(&cmd_bitstream->to_receive, false); bitstream_dump_helper(&cmd_bitstream->to_receive, false);
} }
#endif // #pragma region // Functions to dump bitstreams to debug output #endif // #pragma region // Functions to dump bitstreams to debug output
@ -569,14 +569,14 @@ static void bitstream_dump(const em4x70_command_bitstream_t * cmd_bitstream) {
/// @brief Internal function to send a bitstream to the tag. /// @brief Internal function to send a bitstream to the tag.
/// @details This function presumes a validated structure, and sends the bitstream without delays, to support timing-sensitive operations. /// @details This function presumes a validated structure, and sends the bitstream without delays, to support timing-sensitive operations.
/// @param send The details on the bitstream to send to the tag. /// @param send The details on the bitstream to send to the tag.
/// @return /// @return
static bool send_bitstream_internal(const em4x70_bitstream_t * send) { static bool send_bitstream_internal(const em4x70_bitstream_t *send) {
// similar to original send_command_and_read, but using provided bitstream // similar to original send_command_and_read, but using provided bitstream
int retries = EM4X70_COMMAND_RETRIES; int retries = EM4X70_COMMAND_RETRIES;
// TIMING SENSITIVE FUNCTION ... Minimize delays after finding the listen window // TIMING SENSITIVE FUNCTION ... Minimize delays after finding the listen window
while (retries) { while (retries) {
const uint8_t * s = send->one_bit_per_byte; const uint8_t *s = send->one_bit_per_byte;
uint8_t sent = 0; uint8_t sent = 0;
retries--; retries--;
if (find_listen_window(true)) { // `true` will automatically send the two `RM` zero bits if (find_listen_window(true)) { // `true` will automatically send the two `RM` zero bits
@ -597,9 +597,9 @@ static bool send_bitstream_internal(const em4x70_bitstream_t * send) {
/// @param recv Buffer to store received data from the tag. /// @param recv Buffer to store received data from the tag.
/// `recv->expected_bitcount` must be initialized to indicate expected bits to receive from the tag. /// `recv->expected_bitcount` must be initialized to indicate expected bits to receive from the tag.
/// @return true only if the bitstream was sent and the expected count of bits were received from the tag. /// @return true only if the bitstream was sent and the expected count of bits were received from the tag.
static bool send_bitstream_and_read(em4x70_command_bitstream_t * command_bitstream) { static bool send_bitstream_and_read(em4x70_command_bitstream_t *command_bitstream) {
const em4x70_bitstream_t * send = &command_bitstream->to_send; const em4x70_bitstream_t *send = &command_bitstream->to_send;
em4x70_bitstream_t * recv = &command_bitstream->to_receive; em4x70_bitstream_t *recv = &command_bitstream->to_receive;
// Validate the parameters before proceeding // Validate the parameters before proceeding
bool parameters_valid = true; bool parameters_valid = true;
@ -614,7 +614,7 @@ static bool send_bitstream_and_read(em4x70_command_bitstream_t * command_bitstre
(command_bitstream->command == EM4X70_COMMAND_UM1) || (command_bitstream->command == EM4X70_COMMAND_UM1) ||
(command_bitstream->command == EM4X70_COMMAND_UM2) || (command_bitstream->command == EM4X70_COMMAND_UM2) ||
(command_bitstream->command == EM4X70_COMMAND_AUTH) (command_bitstream->command == EM4X70_COMMAND_AUTH)
) { ) {
// These are the four commands that are supported by this function. // These are the four commands that are supported by this function.
// Allow these to proceed. // Allow these to proceed.
} else { } else {
@ -665,7 +665,7 @@ static bool send_bitstream_and_read(em4x70_command_bitstream_t * command_bitstre
// similar to original send_command_and_read, but using provided bitstream // similar to original send_command_and_read, but using provided bitstream
int bits_received = 0; int bits_received = 0;
// NOTE: reset of log does not track the time first bit is sent. That occurs // NOTE: reset of log does not track the time first bit is sent. That occurs
// when the first sent bit is recorded in the log. // when the first sent bit is recorded in the log.
log_reset(); log_reset();
@ -694,9 +694,9 @@ static bool send_bitstream_and_read(em4x70_command_bitstream_t * command_bitstre
// finally return the result of the operation // finally return the result of the operation
return result; return result;
} }
static bool send_bitstream_wait_ack_wait_read(em4x70_command_bitstream_t * command_bitstream) { static bool send_bitstream_wait_ack_wait_read(em4x70_command_bitstream_t *command_bitstream) {
const em4x70_bitstream_t * send = &command_bitstream->to_send; const em4x70_bitstream_t *send = &command_bitstream->to_send;
em4x70_bitstream_t * recv = &command_bitstream->to_receive; em4x70_bitstream_t *recv = &command_bitstream->to_receive;
// Validate the parameters before proceeding // Validate the parameters before proceeding
bool parameters_valid = true; bool parameters_valid = true;
@ -769,10 +769,10 @@ static bool send_bitstream_wait_ack_wait_read(em4x70_command_bitstream_t * comma
return result; return result;
} }
static bool send_bitstream_wait_ack_wait_ack(em4x70_command_bitstream_t * command_bitstream) { static bool send_bitstream_wait_ack_wait_ack(em4x70_command_bitstream_t *command_bitstream) {
const em4x70_bitstream_t * send = &command_bitstream->to_send; const em4x70_bitstream_t *send = &command_bitstream->to_send;
em4x70_bitstream_t * recv = &command_bitstream->to_receive; em4x70_bitstream_t *recv = &command_bitstream->to_receive;
// Validate the parameters before proceeding // Validate the parameters before proceeding
bool parameters_valid = true; bool parameters_valid = true;
@ -835,7 +835,7 @@ static bool send_bitstream_wait_ack_wait_ack(em4x70_command_bitstream_t * comman
#endif // #pragma region // Functions to send bitstreams, with options to receive data #endif // #pragma region // Functions to send bitstreams, with options to receive data
#if 1 // #pragma region // Create bitstreams for each type of EM4x70 command #if 1 // #pragma region // Create bitstreams for each type of EM4x70 command
static bool add_bit_to_bitstream(em4x70_bitstream_t * s, bool b) { static bool add_bit_to_bitstream(em4x70_bitstream_t *s, bool b) {
uint8_t i = s->bitcount; uint8_t i = s->bitcount;
uint8_t bits_to_add = 1u; uint8_t bits_to_add = 1u;
@ -848,10 +848,10 @@ static bool add_bit_to_bitstream(em4x70_bitstream_t * s, bool b) {
s->bitcount++; s->bitcount++;
return true; return true;
} }
static bool add_nibble_to_bitstream(em4x70_bitstream_t * s, uint8_t nibble, bool add_fifth_parity_bit) { static bool add_nibble_to_bitstream(em4x70_bitstream_t *s, uint8_t nibble, bool add_fifth_parity_bit) {
uint8_t i = s->bitcount; uint8_t i = s->bitcount;
uint8_t bits_to_add = add_fifth_parity_bit ? 5u : 4u; uint8_t bits_to_add = add_fifth_parity_bit ? 5u : 4u;
if (i > EM4X70_MAX_BITSTREAM_BITS - bits_to_add) { if (i > EM4X70_MAX_BITSTREAM_BITS - bits_to_add) {
DPRINTF_ERROR(("Too many bits to add to bitstream: %d, %d", i, bits_to_add)); DPRINTF_ERROR(("Too many bits to add to bitstream: %d, %d", i, bits_to_add));
return false; return false;
@ -875,7 +875,7 @@ static bool add_nibble_to_bitstream(em4x70_bitstream_t * s, uint8_t nibble, bool
s->bitcount += bits_to_add; s->bitcount += bits_to_add;
return true; return true;
} }
static bool add_byte_to_bitstream(em4x70_bitstream_t * s, uint8_t b) { static bool add_byte_to_bitstream(em4x70_bitstream_t *s, uint8_t b) {
uint8_t i = s->bitcount; uint8_t i = s->bitcount;
uint8_t bits_to_add = 8u; uint8_t bits_to_add = 8u;
@ -897,7 +897,7 @@ static bool add_byte_to_bitstream(em4x70_bitstream_t * s, uint8_t b) {
} }
static bool create_legacy_em4x70_bitstream_for_cmd_id(em4x70_command_bitstream_t * out_cmd_bitstream, bool with_command_parity) { static bool create_legacy_em4x70_bitstream_for_cmd_id(em4x70_command_bitstream_t *out_cmd_bitstream, bool with_command_parity) {
const uint8_t expected_bits_to_send = 4u; const uint8_t expected_bits_to_send = 4u;
bool result = true; bool result = true;
memset(out_cmd_bitstream, 0, sizeof(em4x70_command_bitstream_t)); memset(out_cmd_bitstream, 0, sizeof(em4x70_command_bitstream_t));
@ -911,7 +911,7 @@ static bool create_legacy_em4x70_bitstream_for_cmd_id(em4x70_command_bitstream_t
} }
return result; return result;
} }
static bool create_legacy_em4x70_bitstream_for_cmd_um1(em4x70_command_bitstream_t * out_cmd_bitstream, bool with_command_parity) { static bool create_legacy_em4x70_bitstream_for_cmd_um1(em4x70_command_bitstream_t *out_cmd_bitstream, bool with_command_parity) {
const uint8_t expected_bits_to_send = 4u; const uint8_t expected_bits_to_send = 4u;
bool result = true; bool result = true;
memset(out_cmd_bitstream, 0, sizeof(em4x70_command_bitstream_t)); memset(out_cmd_bitstream, 0, sizeof(em4x70_command_bitstream_t));
@ -925,7 +925,7 @@ static bool create_legacy_em4x70_bitstream_for_cmd_um1(em4x70_command_bitstream_
} }
return result; return result;
} }
static bool create_legacy_em4x70_bitstream_for_cmd_um2(em4x70_command_bitstream_t * out_cmd_bitstream, bool with_command_parity) { static bool create_legacy_em4x70_bitstream_for_cmd_um2(em4x70_command_bitstream_t *out_cmd_bitstream, bool with_command_parity) {
const uint8_t expected_bits_to_send = 4u; const uint8_t expected_bits_to_send = 4u;
bool result = true; bool result = true;
memset(out_cmd_bitstream, 0, sizeof(em4x70_command_bitstream_t)); memset(out_cmd_bitstream, 0, sizeof(em4x70_command_bitstream_t));
@ -939,14 +939,14 @@ static bool create_legacy_em4x70_bitstream_for_cmd_um2(em4x70_command_bitstream_
} }
return true; return true;
} }
static bool create_legacy_em4x70_bitstream_for_cmd_auth(em4x70_command_bitstream_t * out_cmd_bitstream, bool with_command_parity, const uint8_t *rnd, const uint8_t *frnd) { static bool create_legacy_em4x70_bitstream_for_cmd_auth(em4x70_command_bitstream_t *out_cmd_bitstream, bool with_command_parity, const uint8_t *rnd, const uint8_t *frnd) {
const uint8_t expected_bits_to_send = 96u; const uint8_t expected_bits_to_send = 96u;
bool result = true; bool result = true;
memset(out_cmd_bitstream, 0, sizeof(em4x70_command_bitstream_t)); memset(out_cmd_bitstream, 0, sizeof(em4x70_command_bitstream_t));
out_cmd_bitstream->command = EM4X70_COMMAND_AUTH; out_cmd_bitstream->command = EM4X70_COMMAND_AUTH;
em4x70_bitstream_t * s = &out_cmd_bitstream->to_send; em4x70_bitstream_t *s = &out_cmd_bitstream->to_send;
// ********************************************************************************* // *********************************************************************************
// HACK -- Insert an extra zero bit to match legacy behavior // HACK -- Insert an extra zero bit to match legacy behavior
@ -994,12 +994,12 @@ static bool create_legacy_em4x70_bitstream_for_cmd_auth(em4x70_command_bitstream
return result; return result;
} }
static bool create_legacy_em4x70_bitstream_for_cmd_pin(em4x70_command_bitstream_t * out_cmd_bitstream, bool with_command_parity, const uint8_t *tag_id, const uint32_t pin) { static bool create_legacy_em4x70_bitstream_for_cmd_pin(em4x70_command_bitstream_t *out_cmd_bitstream, bool with_command_parity, const uint8_t *tag_id, const uint32_t pin) {
const uint8_t expected_bits_to_send = 69; // normally 68 bits, but legacy hack inserts an extra RM bit, and always adds a command parity bit const uint8_t expected_bits_to_send = 69; // normally 68 bits, but legacy hack inserts an extra RM bit, and always adds a command parity bit
bool result = true; bool result = true;
memset(out_cmd_bitstream, 0, sizeof(em4x70_command_bitstream_t)); memset(out_cmd_bitstream, 0, sizeof(em4x70_command_bitstream_t));
em4x70_bitstream_t * s = &out_cmd_bitstream->to_send; em4x70_bitstream_t *s = &out_cmd_bitstream->to_send;
out_cmd_bitstream->command = EM4X70_COMMAND_PIN; out_cmd_bitstream->command = EM4X70_COMMAND_PIN;
@ -1015,7 +1015,7 @@ static bool create_legacy_em4x70_bitstream_for_cmd_pin(em4x70_command_bitstream_
// Send tag's ID ... indexes 4 .. 35 // Send tag's ID ... indexes 4 .. 35
// e.g., tag_id points to &tag.data[4] ... &tag.data[7] // e.g., tag_id points to &tag.data[4] ... &tag.data[7]
for (uint_fast8_t i = 0; i < 4; i++) { for (uint_fast8_t i = 0; i < 4; i++) {
uint8_t b = tag_id[3-i]; uint8_t b = tag_id[3 - i];
result = result && add_byte_to_bitstream(s, b); result = result && add_byte_to_bitstream(s, b);
} }
@ -1033,13 +1033,13 @@ static bool create_legacy_em4x70_bitstream_for_cmd_pin(em4x70_command_bitstream_
} }
return result; return result;
} }
static bool create_legacy_em4x70_bitstream_for_cmd_write(em4x70_command_bitstream_t * out_cmd_bitstream, bool with_command_parity, uint16_t new_data, uint8_t address) { static bool create_legacy_em4x70_bitstream_for_cmd_write(em4x70_command_bitstream_t *out_cmd_bitstream, bool with_command_parity, uint16_t new_data, uint8_t address) {
const uint8_t expected_bits_to_send = 35u; // normally 34 bits, but legacy hack inserts an extra RM bit, and always adds a command parity bit const uint8_t expected_bits_to_send = 35u; // normally 34 bits, but legacy hack inserts an extra RM bit, and always adds a command parity bit
bool result = true; bool result = true;
memset(out_cmd_bitstream, 0, sizeof(em4x70_command_bitstream_t)); memset(out_cmd_bitstream, 0, sizeof(em4x70_command_bitstream_t));
out_cmd_bitstream->command = EM4X70_COMMAND_WRITE; out_cmd_bitstream->command = EM4X70_COMMAND_WRITE;
em4x70_bitstream_t * s = &out_cmd_bitstream->to_send; em4x70_bitstream_t *s = &out_cmd_bitstream->to_send;
// ********************************************************************************* // *********************************************************************************
// HACK -- Insert an extra zero bit to match legacy behavior // HACK -- Insert an extra zero bit to match legacy behavior
@ -1105,7 +1105,7 @@ const em4x70_command_generators_t legacy_em4x70_command_generators = {
static int authenticate(const uint8_t *rnd, const uint8_t *frnd, uint8_t *response) { static int authenticate(const uint8_t *rnd, const uint8_t *frnd, uint8_t *response) {
em4x70_command_bitstream_t auth_cmd; em4x70_command_bitstream_t auth_cmd;
const em4x70_command_generators_t * generator = &legacy_em4x70_command_generators; const em4x70_command_generators_t *generator = &legacy_em4x70_command_generators;
generator->auth(&auth_cmd, command_parity, rnd, frnd); generator->auth(&auth_cmd, command_parity, rnd, frnd);
bool result = send_bitstream_and_read(&auth_cmd); bool result = send_bitstream_and_read(&auth_cmd);
@ -1193,7 +1193,7 @@ static int bruteforce(const uint8_t address, const uint8_t *rnd, const uint8_t *
// log entry/exit point // log entry/exit point
static int send_pin(const uint32_t pin) { static int send_pin(const uint32_t pin) {
em4x70_command_bitstream_t send_pin_cmd; em4x70_command_bitstream_t send_pin_cmd;
const em4x70_command_generators_t * generator = &legacy_em4x70_command_generators; const em4x70_command_generators_t *generator = &legacy_em4x70_command_generators;
generator->pin(&send_pin_cmd, command_parity, &tag.data[4], pin); generator->pin(&send_pin_cmd, command_parity, &tag.data[4], pin);
bool result = send_bitstream_wait_ack_wait_read(&send_pin_cmd); bool result = send_bitstream_wait_ack_wait_read(&send_pin_cmd);
@ -1204,7 +1204,7 @@ static int send_pin(const uint32_t pin) {
static int write(const uint16_t word, const uint8_t address) { static int write(const uint16_t word, const uint8_t address) {
em4x70_command_bitstream_t write_cmd; em4x70_command_bitstream_t write_cmd;
const em4x70_command_generators_t * generator = &legacy_em4x70_command_generators; const em4x70_command_generators_t *generator = &legacy_em4x70_command_generators;
generator->write(&write_cmd, command_parity, word, address); generator->write(&write_cmd, command_parity, word, address);
bool result = send_bitstream_wait_ack_wait_ack(&write_cmd); bool result = send_bitstream_wait_ack_wait_ack(&write_cmd);
@ -1226,10 +1226,10 @@ static bool find_listen_window(bool command) {
96 ( 64 + 32 ) 96 ( 64 + 32 )
64 ( 32 + 16 +16 )*/ 64 ( 32 + 16 +16 )*/
if (check_pulse_length(get_pulse_length(RISING_EDGE), (2 * EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_HALF_PERIOD) && if (check_pulse_length(get_pulse_length(RISING_EDGE), (2 * EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_HALF_PERIOD) &&
check_pulse_length(get_pulse_length(RISING_EDGE), (2 * EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_HALF_PERIOD) && check_pulse_length(get_pulse_length(RISING_EDGE), (2 * EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_HALF_PERIOD) &&
check_pulse_length(get_pulse_length(FALLING_EDGE), (2 * EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_FULL_PERIOD) && check_pulse_length(get_pulse_length(FALLING_EDGE), (2 * EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_FULL_PERIOD) &&
check_pulse_length(get_pulse_length(FALLING_EDGE), (1 * EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_FULL_PERIOD)) { check_pulse_length(get_pulse_length(FALLING_EDGE), (1 * EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_FULL_PERIOD)) {
if (command) { if (command) {
/* Here we are after the 64 duration edge. /* Here we are after the 64 duration edge.
@ -1238,7 +1238,7 @@ static bool find_listen_window(bool command) {
* *
* I've found 32-40 field cycles works best * I've found 32-40 field cycles works best
* Allow user adjustment in range: 24-48 field cycles? * Allow user adjustment in range: 24-48 field cycles?
* On PM3Easy I've seen success at 24..40 field * On PM3Easy I've seen success at 24..40 field
*/ */
WaitTicks(40 * TICKS_PER_FC); WaitTicks(40 * TICKS_PER_FC);
// Send RM Command // Send RM Command
@ -1291,7 +1291,7 @@ static uint8_t encoded_bit_array_to_byte(const uint8_t *bits, int count_of_bits)
*/ */
static bool em4x70_read_id(void) { static bool em4x70_read_id(void) {
em4x70_command_bitstream_t read_id_cmd; em4x70_command_bitstream_t read_id_cmd;
const em4x70_command_generators_t * generator = &legacy_em4x70_command_generators; const em4x70_command_generators_t *generator = &legacy_em4x70_command_generators;
generator->id(&read_id_cmd, command_parity); generator->id(&read_id_cmd, command_parity);
bool result = send_bitstream_and_read(&read_id_cmd); bool result = send_bitstream_and_read(&read_id_cmd);
@ -1308,7 +1308,7 @@ static bool em4x70_read_id(void) {
*/ */
static bool em4x70_read_um1(void) { static bool em4x70_read_um1(void) {
em4x70_command_bitstream_t read_um1_cmd; em4x70_command_bitstream_t read_um1_cmd;
const em4x70_command_generators_t * generator = &legacy_em4x70_command_generators; const em4x70_command_generators_t *generator = &legacy_em4x70_command_generators;
generator->um1(&read_um1_cmd, command_parity); generator->um1(&read_um1_cmd, command_parity);
bool result = send_bitstream_and_read(&read_um1_cmd); bool result = send_bitstream_and_read(&read_um1_cmd);
@ -1327,7 +1327,7 @@ static bool em4x70_read_um1(void) {
*/ */
static bool em4x70_read_um2(void) { static bool em4x70_read_um2(void) {
em4x70_command_bitstream_t read_um2_cmd; em4x70_command_bitstream_t read_um2_cmd;
const em4x70_command_generators_t * generator = &legacy_em4x70_command_generators; const em4x70_command_generators_t *generator = &legacy_em4x70_command_generators;
generator->um2(&read_um2_cmd, command_parity); generator->um2(&read_um2_cmd, command_parity);
bool result = send_bitstream_and_read(&read_um2_cmd); bool result = send_bitstream_and_read(&read_um2_cmd);

View file

@ -43,7 +43,7 @@
#define _64T0 (CLOCK) #define _64T0 (CLOCK)
// calculating the two possible pmc lengths, based on the clock. -4 at the end is to make sure not to increment too far // calculating the two possible pmc lengths, based on the clock. -4 at the end is to make sure not to increment too far
#define PMC_16T0_LEN ((128 + 127 + 16 + 32 + 33 + 16) * CLOCK/64); #define PMC_16T0_LEN ((128 + 127 + 16 + 32 + 33 + 16) * CLOCK/64);
#define PMC_32T0_LEN ((128 + 127 + 16 + 32 + 33 ) * CLOCK/64); #define PMC_32T0_LEN ((128 + 127 + 16 + 32 + 33 ) * CLOCK/64);
// theshold for recognition of positive/negative slope // theshold for recognition of positive/negative slope
@ -54,13 +54,13 @@ size_t DemodPCF7931(uint8_t **outBlocks, bool ledcontrol) {
uint8_t blocks[8][16]; uint8_t blocks[8][16];
uint8_t *dest = BigBuf_get_addr(); uint8_t *dest = BigBuf_get_addr();
uint16_t g_GraphTraceLen = BigBuf_max_traceLen(); uint16_t g_GraphTraceLen = BigBuf_max_traceLen();
// limit g_GraphTraceLen to a little more than 2 data frames. // limit g_GraphTraceLen to a little more than 2 data frames.
// To make sure a complete dataframe is in the dataset. // To make sure a complete dataframe is in the dataset.
// 1 Frame is 16 Byte -> 128byte. at a T0 of 64 -> 8129 Samples per frame. // 1 Frame is 16 Byte -> 128byte. at a T0 of 64 -> 8129 Samples per frame.
// + PMC -> 384T0 --> 8576 samples required for one block // + PMC -> 384T0 --> 8576 samples required for one block
// to make sure that one complete block is definitely being sampled, we need 2 times that // to make sure that one complete block is definitely being sampled, we need 2 times that
// which is ~17.xxx samples. round up. and clamp to this value. // which is ~17.xxx samples. round up. and clamp to this value.
// TODO: Doublecheck why this is being limited? - seems not to be needed. // TODO: Doublecheck why this is being limited? - seems not to be needed.
// g_GraphTraceLen = (g_GraphTraceLen > 18000) ? 18000 : g_GraphTraceLen; // g_GraphTraceLen = (g_GraphTraceLen > 18000) ? 18000 : g_GraphTraceLen;
@ -87,15 +87,15 @@ size_t DemodPCF7931(uint8_t **outBlocks, bool ledcontrol) {
samplePosLastEdge = 0; samplePosLastEdge = 0;
block_done = 0; block_done = 0;
bitPos = 0; bitPos = 0;
lastClockDuration=0; lastClockDuration = 0;
for (sample = 1 ; sample < g_GraphTraceLen-4; sample++) {
// condition is searching for the next edge, in the expected diretion.
//todo: without flouz
dest[sample] = (uint8_t)(dest[sample-1] * IIR_CONST1 + dest[sample] * IIR_CONST2); // apply IIR filter
if ( ((dest[sample] + THRESHOLD) < dest[sample-1] && expectedNextEdge == FALLING ) || for (sample = 1 ; sample < g_GraphTraceLen - 4; sample++) {
((dest[sample] - THRESHOLD) > dest[sample-1] && expectedNextEdge == RISING )) { // condition is searching for the next edge, in the expected diretion.
//todo: without flouz
dest[sample] = (uint8_t)(dest[sample - 1] * IIR_CONST1 + dest[sample] * IIR_CONST2); // apply IIR filter
if (((dest[sample] + THRESHOLD) < dest[sample - 1] && expectedNextEdge == FALLING) ||
((dest[sample] - THRESHOLD) > dest[sample - 1] && expectedNextEdge == RISING)) {
//okay, next falling/rising edge found //okay, next falling/rising edge found
expectedNextEdge = (expectedNextEdge == FALLING) ? RISING : FALLING; //toggle the next expected edge expectedNextEdge = (expectedNextEdge == FALLING) ? RISING : FALLING; //toggle the next expected edge
@ -104,14 +104,14 @@ size_t DemodPCF7931(uint8_t **outBlocks, bool ledcontrol) {
lastClockDuration = samplePosCurrentEdge - samplePosLastEdge; lastClockDuration = samplePosCurrentEdge - samplePosLastEdge;
samplePosLastEdge = sample; samplePosLastEdge = sample;
// Dbprintf("%d, %d, edge found, len: %d, nextEdge: %d", sample, dest[sample], lastClockDuration*DECIMATION, expectedNextEdge); // Dbprintf("%d, %d, edge found, len: %d, nextEdge: %d", sample, dest[sample], lastClockDuration*DECIMATION, expectedNextEdge);
// Switch depending on lastClockDuration length: // Switch depending on lastClockDuration length:
// 16T0 // 16T0
if (ABS(lastClockDuration - _16T0) < TOLERANCE) { if (ABS(lastClockDuration - _16T0) < TOLERANCE) {
// if the clock before also was 16T0, it is a PMC! // if the clock before also was 16T0, it is a PMC!
if (ABS(beforeLastClockDuration - _16T0) < TOLERANCE) { if (ABS(beforeLastClockDuration - _16T0) < TOLERANCE) {
// It's a PMC // It's a PMC
Dbprintf(_GREEN_("PMC 16T0 FOUND:") " bitPos: %d, sample: %d", bitPos, sample); Dbprintf(_GREEN_("PMC 16T0 FOUND:") " bitPos: %d, sample: %d", bitPos, sample);
sample += PMC_16T0_LEN; // move to the sample after PMC sample += PMC_16T0_LEN; // move to the sample after PMC
@ -120,44 +120,44 @@ size_t DemodPCF7931(uint8_t **outBlocks, bool ledcontrol) {
samplePosLastEdge = sample; samplePosLastEdge = sample;
block_done = 1; block_done = 1;
} }
// 32TO // 32TO
} else if (ABS(lastClockDuration - _32T0) < TOLERANCE) { } else if (ABS(lastClockDuration - _32T0) < TOLERANCE) {
// if the clock before also was 16T0, it is a PMC! // if the clock before also was 16T0, it is a PMC!
if (ABS(beforeLastClockDuration - _16T0) < TOLERANCE) { if (ABS(beforeLastClockDuration - _16T0) < TOLERANCE) {
// It's a PMC ! // It's a PMC !
Dbprintf(_GREEN_("PMC 32T0 FOUND:") " bitPos: %d, sample: %d", bitPos, sample); Dbprintf(_GREEN_("PMC 32T0 FOUND:") " bitPos: %d, sample: %d", bitPos, sample);
sample += PMC_32T0_LEN; // move to the sample after PMC sample += PMC_32T0_LEN; // move to the sample after PMC
expectedNextEdge = FALLING; expectedNextEdge = FALLING;
samplePosLastEdge = sample; samplePosLastEdge = sample;
block_done = 1; block_done = 1;
// if no pmc, then its a normal bit. // if no pmc, then its a normal bit.
// Check if its the second time, the edge changed if yes, then the bit is 0 // Check if its the second time, the edge changed if yes, then the bit is 0
} else if (half_switch == 1) { } else if (half_switch == 1) {
bits[bitPos] = 0; bits[bitPos] = 0;
// reset the edge counter to 0 // reset the edge counter to 0
half_switch = 0; half_switch = 0;
bitPos++; bitPos++;
// if it is the first time the edge changed. No bit value will be set here, bit if the // if it is the first time the edge changed. No bit value will be set here, bit if the
// edge changes again, it will be. see case above. // edge changes again, it will be. see case above.
} else } else
half_switch++; half_switch++;
// 64T0 // 64T0
} else if (ABS(lastClockDuration - _64T0) < TOLERANCE) { } else if (ABS(lastClockDuration - _64T0) < TOLERANCE) {
// this means, bit here is 1 // this means, bit here is 1
bits[bitPos] = 1; bits[bitPos] = 1;
bitPos++; bitPos++;
// Error // Error
} else { } else {
// some Error. maybe check tolerances. // some Error. maybe check tolerances.
// likeley to happen in the first block. // likeley to happen in the first block.
// In an Ideal world, this can be enabled. However, if only bad antenna field, this print will flood the output // In an Ideal world, this can be enabled. However, if only bad antenna field, this print will flood the output
// and one might miss some "good" frames. // and one might miss some "good" frames.
//Dbprintf(_RED_("ERROR in demodulation") " Length last clock: %d - check threshold/tolerance/signal. Toss block", lastClockDuration*DECIMATION); //Dbprintf(_RED_("ERROR in demodulation") " Length last clock: %d - check threshold/tolerance/signal. Toss block", lastClockDuration*DECIMATION);
@ -168,7 +168,7 @@ size_t DemodPCF7931(uint8_t **outBlocks, bool ledcontrol) {
if (block_done == 1) { if (block_done == 1) {
// Dbprintf(_YELLOW_("Block Done") " bitPos: %d, sample: %d", bitPos, sample); // Dbprintf(_YELLOW_("Block Done") " bitPos: %d, sample: %d", bitPos, sample);
// check if it is a complete block. If bitpos <128, it means that we did not receive // check if it is a complete block. If bitpos <128, it means that we did not receive
// a complete block. E.g. at the first start of a transmission. // a complete block. E.g. at the first start of a transmission.
// only save if a complete block is being received. // only save if a complete block is being received.
@ -187,14 +187,14 @@ size_t DemodPCF7931(uint8_t **outBlocks, bool ledcontrol) {
} }
num_blocks++; num_blocks++;
} }
// now start over for the next block / first complete block. // now start over for the next block / first complete block.
bitPos = 0; bitPos = 0;
block_done = 0; block_done = 0;
half_switch = 0; half_switch = 0;
} }
}else { } else {
// Dbprintf("%d, %d", sample, dest[sample]); // Dbprintf("%d, %d", sample, dest[sample]);
} }
// one block only holds 16byte (=128 bit) and then comes the PMC. so if more bit are found than 129, there must be an issue and PMC has not been identfied... // one block only holds 16byte (=128 bit) and then comes the PMC. so if more bit are found than 129, there must be an issue and PMC has not been identfied...
@ -204,8 +204,8 @@ size_t DemodPCF7931(uint8_t **outBlocks, bool ledcontrol) {
bitPos = 0; bitPos = 0;
} }
} }
memcpy(outBlocks, blocks, 16 * num_blocks); memcpy(outBlocks, blocks, 16 * num_blocks);
return num_blocks; return num_blocks;
} }
@ -251,10 +251,10 @@ bool IsBlock1PCF7931(const uint8_t *block) {
} }
void ReadPCF7931(bool ledcontrol) { void ReadPCF7931(bool ledcontrol) {
uint8_t maxBlocks = 8; // readable blocks uint8_t maxBlocks = 8; // readable blocks
int found_blocks = 0; // successfully read blocks int found_blocks = 0; // successfully read blocks
// TODO: Why 17 byte len? 16 should be good. // TODO: Why 17 byte len? 16 should be good.
uint8_t memory_blocks[maxBlocks][17]; // PCF content uint8_t memory_blocks[maxBlocks][17]; // PCF content
uint8_t single_blocks[maxBlocks][17]; // PFC blocks with unknown position uint8_t single_blocks[maxBlocks][17]; // PFC blocks with unknown position
@ -263,7 +263,7 @@ void ReadPCF7931(bool ledcontrol) {
int single_blocks_cnt = 0; int single_blocks_cnt = 0;
size_t n; // transmitted blocks size_t n; // transmitted blocks
//uint8_t found_0_1 = 0; // flag: blocks 0 and 1 were found //uint8_t found_0_1 = 0; // flag: blocks 0 and 1 were found
int errors = 0; // error counter int errors = 0; // error counter
int tries = 0; // tries counter int tries = 0; // tries counter
@ -300,7 +300,7 @@ void ReadPCF7931(bool ledcontrol) {
goto end; goto end;
} }
// This part was not working properly. // This part was not working properly.
// So currently the blocks are not being sorted, but at least printed. // So currently the blocks are not being sorted, but at least printed.
// // our logic breaks if we don't get at least two blocks // // our logic breaks if we don't get at least two blocks
@ -403,28 +403,28 @@ void ReadPCF7931(bool ledcontrol) {
end: end:
/* /*
Dbprintf("-----------------------------------------"); Dbprintf("-----------------------------------------");
Dbprintf("Memory content:"); Dbprintf("Memory content:");
Dbprintf("-----------------------------------------"); Dbprintf("-----------------------------------------");
for (i = 0; i < maxBlocks; ++i) { for (i = 0; i < maxBlocks; ++i) {
if (memory_blocks[i][ALLOC]) if (memory_blocks[i][ALLOC])
print_result("Block", memory_blocks[i], 16); print_result("Block", memory_blocks[i], 16);
else else
Dbprintf("<missing block %d>", i); Dbprintf("<missing block %d>", i);
} }
Dbprintf("-----------------------------------------"); Dbprintf("-----------------------------------------");
if (found_blocks < maxBlocks) { if (found_blocks < maxBlocks) {
Dbprintf("-----------------------------------------"); Dbprintf("-----------------------------------------");
Dbprintf("Blocks with unknown position:"); Dbprintf("Blocks with unknown position:");
Dbprintf("-----------------------------------------"); Dbprintf("-----------------------------------------");
for (i = 0; i < single_blocks_cnt; ++i) for (i = 0; i < single_blocks_cnt; ++i)
print_result("Block", single_blocks[i], 16); print_result("Block", single_blocks[i], 16);
Dbprintf("-----------------------------------------"); Dbprintf("-----------------------------------------");
} }
*/ */
reply_mix(CMD_ACK, 0, 0, 0, 0, 0); reply_mix(CMD_ACK, 0, 0, 0, 0, 0);
} }
@ -434,7 +434,7 @@ static void RealWritePCF7931(
uint16_t init_delay, uint16_t init_delay,
int8_t offsetPulseWidth, int8_t offsetPulsePosition, int8_t offsetPulseWidth, int8_t offsetPulsePosition,
uint8_t address, uint8_t byte, uint8_t data, uint8_t address, uint8_t byte, uint8_t data,
bool ledcontrol){ bool ledcontrol) {
uint32_t tab[1024] = {0}; // data times frame uint32_t tab[1024] = {0}; // data times frame
uint32_t u = 0; uint32_t u = 0;
@ -512,10 +512,10 @@ static void RealWritePCF7931(
* @param data : data to write * @param data : data to write
*/ */
void WritePCF7931( void WritePCF7931(
uint8_t pass1, uint8_t pass2, uint8_t pass3, uint8_t pass4, uint8_t pass5, uint8_t pass6, uint8_t pass7, uint8_t pass1, uint8_t pass2, uint8_t pass3, uint8_t pass4, uint8_t pass5, uint8_t pass6, uint8_t pass7,
uint16_t init_delay, uint16_t init_delay,
int8_t offsetPulseWidth, int8_t offsetPulsePosition, int8_t offsetPulseWidth, int8_t offsetPulsePosition,
uint8_t address, uint8_t byte, uint8_t data, uint8_t address, uint8_t byte, uint8_t data,
bool ledcontrol) { bool ledcontrol) {
if (g_dbglevel >= DBG_INFO) { if (g_dbglevel >= DBG_INFO) {
@ -550,7 +550,7 @@ void SendCmdPCF7931(uint32_t *tab, bool ledcontrol) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU); FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU);
if (ledcontrol) LED_A_ON(); if (ledcontrol) LED_A_ON();
// rescale the values to match the time of the timer below. // rescale the values to match the time of the timer below.
for (u = 0; u < 500; ++u) { for (u = 0; u < 500; ++u) {
tab[u] = (tab[u] * 3) / 2; tab[u] = (tab[u] * 3) / 2;
@ -651,7 +651,7 @@ bool AddBitPCF7931(bool b, uint32_t *tab, int8_t offsetPulseWidth, int8_t offset
tab[u + 1] = 6 * T0_PCF + tab[u] + offsetPulseWidth; tab[u + 1] = 6 * T0_PCF + tab[u] + offsetPulseWidth;
tab[u + 2] = 88 * T0_PCF + tab[u + 1] - offsetPulseWidth - offsetPulsePosition; tab[u + 2] = 88 * T0_PCF + tab[u + 1] - offsetPulseWidth - offsetPulsePosition;
} else { //add a bit 0 } else { //add a bit 0
if (u == 0) if (u == 0)
tab[u] = 98 * T0_PCF + offsetPulsePosition; tab[u] = 98 * T0_PCF + offsetPulsePosition;
@ -660,7 +660,7 @@ bool AddBitPCF7931(bool b, uint32_t *tab, int8_t offsetPulseWidth, int8_t offset
tab[u + 1] = 6 * T0_PCF + tab[u] + offsetPulseWidth; tab[u + 1] = 6 * T0_PCF + tab[u] + offsetPulseWidth;
tab[u + 2] = 24 * T0_PCF + tab[u + 1] - offsetPulseWidth - offsetPulsePosition; tab[u + 2] = 24 * T0_PCF + tab[u + 1] - offsetPulseWidth - offsetPulsePosition;
} }
return true; return true;
} }

View file

@ -19,9 +19,9 @@
#include "common.h" #include "common.h"
typedef enum{ typedef enum {
FALLING, FALLING,
RISING RISING
} EdgeType; } EdgeType;
size_t DemodPCF7931(uint8_t **outBlocks, bool ledcontrol); size_t DemodPCF7931(uint8_t **outBlocks, bool ledcontrol);

View file

@ -102,7 +102,7 @@ local function reanimate_t5577(password)
p:console('lf t55 write -b 0 -d 000880E0 --pg1 --r0 -p 00000000') p:console('lf t55 write -b 0 -d 000880E0 --pg1 --r0 -p 00000000')
p:console('lf t55 write -b 0 -d 000880E0 --pg1 --r1 -p 00000000') p:console('lf t55 write -b 0 -d 000880E0 --pg1 --r1 -p 00000000')
p:console('lf t55 write -b 0 -d 000880E0 --pg1 --r2 -p 00000000') p:console('lf t55 write -b 0 -d 000880E0 --pg1 --r2 -p 00000000')
p:console('lf t55 write -b 0 -d 000880E0 --pg1 --r3 -p 00000000') p:console('lf t55 write -b 0 -d 000880E0 --pg1 --r3 -p 00000000')
reset_log_file() reset_log_file()
end end
@ -118,7 +118,7 @@ local function main(args)
print(dash) print(dash)
print("::: "..ac.cyan.."Hold on, I'm searching for a password in the dictionary"..ac.reset.." :::") print("::: "..ac.cyan.."Hold on, I'm searching for a password in the dictionary"..ac.reset.." :::")
print(dash) print(dash)
p:console('lf t55 chk') p:console('lf t55 chk')
local log_content = read_log_file(logfile) local log_content = read_log_file(logfile)
local password = log_content and extract_password(log_content) or nil local password = log_content and extract_password(log_content) or nil
reanimate_t5577(password) reanimate_t5577(password)
@ -141,4 +141,4 @@ local function main(args)
print(dash) print(dash)
end end
main(args) main(args)

View file

@ -9,14 +9,14 @@ local command = core.console
command('clear') command('clear')
author = ' Author: jareckib - 12.03.2025' author = ' Author: jareckib - 12.03.2025'
version = ' version v1.03' version = ' version v1.03'
desc = [[ desc = [[
This simple script stores 1, 2 or 3 different EM4102 on a single T5577. This simple script stores 1, 2 or 3 different EM4102 on a single T5577.
There is an option to enter the number engraved on the fob in decimal form. There is an option to enter the number engraved on the fob in decimal form.
The script can therefore be useful if the original EM4102 doesn't work but The script can therefore be useful if the original EM4102 doesn't work but
has an engraved ID number. By entering such an ID as a single EM4102, we has an engraved ID number. By entering such an ID as a single EM4102, we
can create a working copy of our damaged fob. can create a working copy of our damaged fob.
A tag T5577 created in this way works with the following USB readers: A tag T5577 created in this way works with the following USB readers:
- ACM08Y - ACM08Y
- ACM26C - ACM26C
- Sycreader R60D - Sycreader R60D
@ -121,7 +121,7 @@ local function get_uid_from_user()
while true do while true do
print(dash) print(dash)
io.write(ac.cyan .. '(1)' .. ac.reset .. ' Manual entry UID |' .. ac.cyan .. ' (2)' .. ac.reset .. ' Read via Proxmark3 ') io.write(ac.cyan .. '(1)' .. ac.reset .. ' Manual entry UID |' .. ac.cyan .. ' (2)' .. ac.reset .. ' Read via Proxmark3 ')
local choice local choice
repeat repeat
choice = io.read() choice = io.read()
@ -159,7 +159,7 @@ local function get_uid_from_user()
io.read() io.read()
while true do while true do
reset_log_file() reset_log_file()
command('lf em 410x read') command('lf em 410x read')
local log_content = read_log_file(logfile) local log_content = read_log_file(logfile)
local uid = extract_uid(log_content) local uid = extract_uid(log_content)
@ -178,7 +178,7 @@ end
local function main(args) local function main(args)
for o, a in getopt.getopt(args, 'h') do for o, a in getopt.getopt(args, 'h') do
if o == 'h' then return help() end if o == 'h' then return help() end
end end
local blocks = {} local blocks = {}
local uid_count = 0 local uid_count = 0
@ -224,4 +224,4 @@ local function main(args)
print(ac.green .. "Successfully written " .. uid_count .. " EM4102 UID(s) to T5577" .. ac.reset) print(ac.green .. "Successfully written " .. uid_count .. " EM4102 UID(s) to T5577" .. ac.reset)
end end
main(args) main(args)

View file

@ -459,4 +459,4 @@ local function main(args)
end end
end end
main(args) main(args)

View file

@ -77,14 +77,14 @@ def parse_config(config: str):
cfg_auth_type = config[8:10] cfg_auth_type = config[8:10]
cfg_cuid = config[12:14] cfg_cuid = config[12:14]
cfg_memory_config = config[14:16] cfg_memory_config = config[14:16]
log_magic_wup = "Magic wakeup " + ("en" if cfg_magic_wup != "8500" else "dis") + "abled" + (" with config access" if cfg_magic_wup == "7AFF" else "") log_magic_wup = "Magic wakeup " + ("en" if cfg_magic_wup != "8500" else "dis") + "abled" + (" with config access" if cfg_magic_wup == "7AFF" else "")
log_wup_style = "Magic wakeup style " + ("Gen1a 40(7)/43" if cfg_wup_style == "00" else ("GDM 20(7)/23" if cfg_wup_style == "85" else "unknown")) log_wup_style = "Magic wakeup style " + ("Gen1a 40(7)/43" if cfg_wup_style == "00" else ("GDM 20(7)/23" if cfg_wup_style == "85" else "unknown"))
log_regular_available = "Config " + ("" if cfg_regular_available == "A0" else "un") + "available in regular mode" log_regular_available = "Config " + ("" if cfg_regular_available == "A0" else "un") + "available in regular mode"
log_auth_type = "Auth type " + ("1B - PWD" if cfg_auth_type == "00" else "1A - 3DES") log_auth_type = "Auth type " + ("1B - PWD" if cfg_auth_type == "00" else "1A - 3DES")
log_cuid = "CUID " + ("dis" if cfg_cuid == "A0" else "en") + "abled" log_cuid = "CUID " + ("dis" if cfg_cuid == "A0" else "en") + "abled"
log_memory_config = "Maximum memory configuration: " + (MEMORY_CONFIG[cfg_memory_config] if cfg_memory_config in MEMORY_CONFIG.keys() else "unknown") log_memory_config = "Maximum memory configuration: " + (MEMORY_CONFIG[cfg_memory_config] if cfg_memory_config in MEMORY_CONFIG.keys() else "unknown")
print(SUCCESS + "^^^^............................ " + log_magic_wup) print(SUCCESS + "^^^^............................ " + log_magic_wup)
print(SUCCESS + "....^^.......................... " + log_wup_style) print(SUCCESS + "....^^.......................... " + log_wup_style)
print(SUCCESS + "......^^........................ " + log_regular_available) print(SUCCESS + "......^^........................ " + log_regular_available)
@ -93,7 +93,7 @@ def parse_config(config: str):
print(SUCCESS + "............^^.................. " + log_cuid) print(SUCCESS + "............^^.................. " + log_cuid)
print(SUCCESS + "..............^^................ " + log_memory_config) print(SUCCESS + "..............^^................ " + log_memory_config)
print(SUCCESS + "................^^^^^^^^^^^^^^^^ version info") print(SUCCESS + "................^^^^^^^^^^^^^^^^ version info")
def try_auth_magic(enforced = False): def try_auth_magic(enforced = False):
if enforced and not (gen1a | alt): if enforced and not (gen1a | alt):
print(ERROR + "Magic wakeup required. Please select one.") print(ERROR + "Magic wakeup required. Please select one.")
@ -158,7 +158,7 @@ elif write_backdoor != None:
if len(data) % 8 != 0: if len(data) % 8 != 0:
print(ERROR + "Data must be a multiple of 4 bytes.") print(ERROR + "Data must be a multiple of 4 bytes.")
exit() exit()
try_auth_magic(True) try_auth_magic(True)
for i in range(len(data) // 8): for i in range(len(data) // 8):
p.console("hf 14a raw -" + ("k" if i != (len(data) // 8 - 1) else "") + f"c A2{(write_backdoor_num + i):02x}{data[8*i:8*i+8]}", False, False) p.console("hf 14a raw -" + ("k" if i != (len(data) // 8 - 1) else "") + f"c A2{(write_backdoor_num + i):02x}{data[8*i:8*i+8]}", False, False)
@ -171,13 +171,13 @@ elif uid != None:
p.console(f"hf 14a raw -kc" + ("s" if not (gen1a or alt) else "") + " 3002") p.console(f"hf 14a raw -kc" + ("s" if not (gen1a or alt) else "") + " 3002")
block_2 = p.grabbed_output.split("\n")[-2][4:-9].replace(" ", "")[:8] block_2 = p.grabbed_output.split("\n")[-2][4:-9].replace(" ", "")[:8]
uid_bytes = [int(uid[2*x:2*x+2], 16) for x in range(7)] uid_bytes = [int(uid[2*x:2*x+2], 16) for x in range(7)]
bcc_0 = 0x88 ^ uid_bytes[0] ^ uid_bytes[1] ^ uid_bytes[2] bcc_0 = 0x88 ^ uid_bytes[0] ^ uid_bytes[1] ^ uid_bytes[2]
new_block_0 = "" new_block_0 = ""
for i in range(3): for i in range(3):
new_block_0 += f"{uid_bytes[i]:02x}" new_block_0 += f"{uid_bytes[i]:02x}"
new_block_0 += f"{bcc_0:02x}" new_block_0 += f"{bcc_0:02x}"
bcc_1 = uid_bytes[3] ^ uid_bytes[4] ^ uid_bytes[5] ^ uid_bytes[6] bcc_1 = uid_bytes[3] ^ uid_bytes[4] ^ uid_bytes[5] ^ uid_bytes[6]
new_block_1 = uid[6:] new_block_1 = uid[6:]
new_block_2 = f"{bcc_1:02x}" + block_2[2:] new_block_2 = f"{bcc_1:02x}" + block_2[2:]

View file

@ -42,7 +42,7 @@ typedef struct _em4x70_tag_info_t {
/// * UM2 does not exist on the tag /// * UM2 does not exist on the tag
/// * Pin does not exist on the tag /// * Pin does not exist on the tag
/// * UM1 (including the lock bits) might be one-time programmable (OTP) /// * UM1 (including the lock bits) might be one-time programmable (OTP)
/// ///
/// [31] == Block 15 MSB == UM2₆₃..UM2₅₆ /// [31] == Block 15 MSB == UM2₆₃..UM2₅₆
/// [30] == Block 15 LSB == UM2₅₅..UM2₄₈ /// [30] == Block 15 LSB == UM2₅₅..UM2₄₈
/// [29] == Block 14 MSB == UM2₄₇..UM2₄₀ /// [29] == Block 14 MSB == UM2₄₇..UM2₄₀

View file

@ -186,6 +186,7 @@ static void fill_grabber(const char *string) {
g_grabbed_output.ptr = tmp; g_grabbed_output.ptr = tmp;
g_grabbed_output.size += MAX_PRINT_BUFFER; g_grabbed_output.size += MAX_PRINT_BUFFER;
} }
int len = snprintf(g_grabbed_output.ptr + g_grabbed_output.idx, MAX_PRINT_BUFFER, "%s", string); int len = snprintf(g_grabbed_output.ptr + g_grabbed_output.idx, MAX_PRINT_BUFFER, "%s", string);
if (len < 0 || len > MAX_PRINT_BUFFER) { if (len < 0 || len > MAX_PRINT_BUFFER) {
// We leave current g_grabbed_output_len untouched // We leave current g_grabbed_output_len untouched
@ -196,24 +197,34 @@ static void fill_grabber(const char *string) {
} }
void PrintAndLogOptions(const char *str[][2], size_t size, size_t space) { void PrintAndLogOptions(const char *str[][2], size_t size, size_t space) {
char buff[2000] = "Options:\n"; char buff[2000] = "Options:\n";
char format[2000] = ""; char format[2000] = "";
size_t counts[2] = {0, 0}; size_t counts[2] = {0, 0};
for (size_t i = 0; i < size; i++)
for (size_t j = 0 ; j < 2 ; j++) for (size_t i = 0; i < size; i++) {
for (size_t j = 0 ; j < 2 ; j++) {
if (counts[j] < strlen(str[i][j])) { if (counts[j] < strlen(str[i][j])) {
counts[j] = strlen(str[i][j]); counts[j] = strlen(str[i][j]);
} }
}
}
for (size_t i = 0; i < size; i++) { for (size_t i = 0; i < size; i++) {
for (size_t j = 0; j < 2; j++) { for (size_t j = 0; j < 2; j++) {
if (j == 0) if (j == 0) {
snprintf(format, sizeof(format), "%%%zus%%%zus", space, counts[j]); snprintf(format, sizeof(format), "%%%zus%%%zus", space, counts[j]);
else } else {
snprintf(format, sizeof(format), "%%%zus%%-%zus", space, counts[j]); snprintf(format, sizeof(format), "%%%zus%%-%zus", space, counts[j]);
}
snprintf(buff + strlen(buff), sizeof(buff) - strlen(buff), format, " ", str[i][j]); snprintf(buff + strlen(buff), sizeof(buff) - strlen(buff), format, " ", str[i][j]);
} }
if (i < size - 1)
if (i < size - 1) {
strncat(buff, "\n", sizeof(buff) - strlen(buff) - 1); strncat(buff, "\n", sizeof(buff) - strlen(buff) - 1);
}
} }
PrintAndLogEx(NORMAL, "%s", buff); PrintAndLogEx(NORMAL, "%s", buff);
} }
@ -223,12 +234,14 @@ static uint8_t PrintAndLogEx_spinidx = 0;
void PrintAndLogEx(logLevel_t level, const char *fmt, ...) { void PrintAndLogEx(logLevel_t level, const char *fmt, ...) {
// skip debug messages if client debugging is turned off i.e. 'DATA SETDEBUG -0' // skip debug messages if client debugging is turned off i.e. 'DATA SETDEBUG -0'
if (g_debugMode == 0 && level == DEBUG) if (g_debugMode == 0 && level == DEBUG) {
return; return;
}
// skip HINT messages if client has hints turned off i.e. 'HINT 0' // skip HINT messages if client has hints turned off i.e. 'HINT 0'
if (g_session.show_hints == false && level == HINT) if (g_session.show_hints == false && level == HINT) {
return; return;
}
char prefix[40] = {0}; char prefix[40] = {0};
char buffer[MAX_PRINT_BUFFER] = {0}; char buffer[MAX_PRINT_BUFFER] = {0};
@ -242,17 +255,19 @@ void PrintAndLogEx(logLevel_t level, const char *fmt, ...) {
}; };
switch (level) { switch (level) {
case ERR: case ERR:
if (g_session.emoji_mode == EMO_EMOJI) if (g_session.emoji_mode == EMO_EMOJI) {
strncpy(prefix, "[" _RED_("!!") "] :rotating_light: ", sizeof(prefix) - 1); strncpy(prefix, "[" _RED_("!!") "] :rotating_light: ", sizeof(prefix) - 1);
else } else {
strncpy(prefix, "[" _RED_("!!") "] ", sizeof(prefix) - 1); strncpy(prefix, "[" _RED_("!!") "] ", sizeof(prefix) - 1);
}
stream = stderr; stream = stderr;
break; break;
case FAILED: case FAILED:
if (g_session.emoji_mode == EMO_EMOJI) if (g_session.emoji_mode == EMO_EMOJI) {
strncpy(prefix, "[" _RED_("-") "] :no_entry: ", sizeof(prefix) - 1); strncpy(prefix, "[" _RED_("-") "] :no_entry: ", sizeof(prefix) - 1);
else } else {
strncpy(prefix, "[" _RED_("-") "] ", sizeof(prefix) - 1); strncpy(prefix, "[" _RED_("-") "] ", sizeof(prefix) - 1);
}
break; break;
case DEBUG: case DEBUG:
strncpy(prefix, "[" _BLUE_("#") "] ", sizeof(prefix) - 1); strncpy(prefix, "[" _BLUE_("#") "] ", sizeof(prefix) - 1);
@ -264,10 +279,11 @@ void PrintAndLogEx(logLevel_t level, const char *fmt, ...) {
strncpy(prefix, "[" _GREEN_("+") "] ", sizeof(prefix) - 1); strncpy(prefix, "[" _GREEN_("+") "] ", sizeof(prefix) - 1);
break; break;
case WARNING: case WARNING:
if (g_session.emoji_mode == EMO_EMOJI) if (g_session.emoji_mode == EMO_EMOJI) {
strncpy(prefix, "[" _CYAN_("!") "] :warning: ", sizeof(prefix) - 1); strncpy(prefix, "[" _CYAN_("!") "] :warning: ", sizeof(prefix) - 1);
else } else {
strncpy(prefix, "[" _CYAN_("!") "] ", sizeof(prefix) - 1); strncpy(prefix, "[" _CYAN_("!") "] ", sizeof(prefix) - 1);
}
break; break;
case INFO: case INFO:
strncpy(prefix, "[" _YELLOW_("=") "] ", sizeof(prefix) - 1); strncpy(prefix, "[" _YELLOW_("=") "] ", sizeof(prefix) - 1);
@ -276,13 +292,15 @@ void PrintAndLogEx(logLevel_t level, const char *fmt, ...) {
if (g_session.emoji_mode == EMO_EMOJI) { if (g_session.emoji_mode == EMO_EMOJI) {
strncpy(prefix, spinner_emoji[PrintAndLogEx_spinidx], sizeof(prefix) - 1); strncpy(prefix, spinner_emoji[PrintAndLogEx_spinidx], sizeof(prefix) - 1);
PrintAndLogEx_spinidx++; PrintAndLogEx_spinidx++;
if (PrintAndLogEx_spinidx >= ARRAYLEN(spinner_emoji)) if (PrintAndLogEx_spinidx >= ARRAYLEN(spinner_emoji)) {
PrintAndLogEx_spinidx = 0; PrintAndLogEx_spinidx = 0;
}
} else { } else {
strncpy(prefix, spinner[PrintAndLogEx_spinidx], sizeof(prefix) - 1); strncpy(prefix, spinner[PrintAndLogEx_spinidx], sizeof(prefix) - 1);
PrintAndLogEx_spinidx++; PrintAndLogEx_spinidx++;
if (PrintAndLogEx_spinidx >= ARRAYLEN(spinner)) if (PrintAndLogEx_spinidx >= ARRAYLEN(spinner)) {
PrintAndLogEx_spinidx = 0; PrintAndLogEx_spinidx = 0;
}
} }
break; break;
case NORMAL: case NORMAL:
@ -306,8 +324,9 @@ void PrintAndLogEx(logLevel_t level, const char *fmt, ...) {
const char delim[2] = "\n"; const char delim[2] = "\n";
// line starts with newline // line starts with newline
if (buffer[0] == '\n') if (buffer[0] == '\n') {
fPrintAndLog(stream, ""); fPrintAndLog(stream, "");
}
token = strtok_r(buffer, delim, &tmp_ptr); token = strtok_r(buffer, delim, &tmp_ptr);
@ -315,16 +334,21 @@ void PrintAndLogEx(logLevel_t level, const char *fmt, ...) {
size_t size = strlen(buffer2); size_t size = strlen(buffer2);
if (strlen(token)) if (strlen(token)) {
snprintf(buffer2 + size, sizeof(buffer2) - size, "%s%s\n", prefix, token); snprintf(buffer2 + size, sizeof(buffer2) - size, "%s%s\n", prefix, token);
else } else {
snprintf(buffer2 + size, sizeof(buffer2) - size, "\n"); snprintf(buffer2 + size, sizeof(buffer2) - size, "\n");
}
token = strtok_r(NULL, delim, &tmp_ptr); token = strtok_r(NULL, delim, &tmp_ptr);
} }
fPrintAndLog(stream, "%s", buffer2); fPrintAndLog(stream, "%s", buffer2);
} else { } else {
snprintf(buffer2, sizeof(buffer2), "%s%s", prefix, buffer); snprintf(buffer2, sizeof(buffer2), "%s%s", prefix, buffer);
if (level == INPLACE) { if (level == INPLACE) {
// ignore INPLACE if rest of output is grabbed // ignore INPLACE if rest of output is grabbed
if (!(g_printAndLog & PRINTANDLOG_GRAB)) { if (!(g_printAndLog & PRINTANDLOG_GRAB)) {
@ -354,6 +378,7 @@ static void fPrintAndLog(FILE *stream, const char *fmt, ...) {
if (logging && g_session.incognito) { if (logging && g_session.incognito) {
logging = 0; logging = 0;
} }
if ((g_printAndLog & PRINTANDLOG_LOG) && logging && !logfile) { if ((g_printAndLog & PRINTANDLOG_LOG) && logging && !logfile) {
char *my_logfile_path = NULL; char *my_logfile_path = NULL;
char filename[40]; char filename[40];
@ -361,11 +386,15 @@ static void fPrintAndLog(FILE *stream, const char *fmt, ...) {
time_t now = time(NULL); time_t now = time(NULL);
timenow = gmtime(&now); timenow = gmtime(&now);
strftime(filename, sizeof(filename), PROXLOG, timenow); strftime(filename, sizeof(filename), PROXLOG, timenow);
if (searchHomeFilePath(&my_logfile_path, LOGS_SUBDIR, filename, true) != PM3_SUCCESS) { if (searchHomeFilePath(&my_logfile_path, LOGS_SUBDIR, filename, true) != PM3_SUCCESS) {
printf(_YELLOW_("[-]") " Logging disabled!\n"); printf(_YELLOW_("[-]") " Logging disabled!\n");
my_logfile_path = NULL; my_logfile_path = NULL;
logging = 0; logging = 0;
} else { } else {
logfile = fopen(my_logfile_path, "a"); logfile = fopen(my_logfile_path, "a");
if (logfile == NULL) { if (logfile == NULL) {
printf(_YELLOW_("[-]") " Can't open logfile %s, logging disabled!\n", my_logfile_path); printf(_YELLOW_("[-]") " Can't open logfile %s, logging disabled!\n", my_logfile_path);
@ -411,13 +440,16 @@ static void fPrintAndLog(FILE *stream, const char *fmt, ...) {
linefeed = false; linefeed = false;
buffer[strlen(buffer) - 1] = 0; buffer[strlen(buffer) - 1] = 0;
} }
bool filter_ansi = !g_session.supports_colors; bool filter_ansi = !g_session.supports_colors;
memcpy_filter_ansi(buffer2, buffer, sizeof(buffer), filter_ansi); memcpy_filter_ansi(buffer2, buffer, sizeof(buffer), filter_ansi);
if (g_printAndLog & PRINTANDLOG_PRINT) {
if ((g_printAndLog & PRINTANDLOG_PRINT) == PRINTANDLOG_PRINT) {
memcpy_filter_emoji(buffer3, buffer2, sizeof(buffer2), g_session.emoji_mode); memcpy_filter_emoji(buffer3, buffer2, sizeof(buffer2), g_session.emoji_mode);
fprintf(stream, "%s", buffer3); fprintf(stream, "%s", buffer3);
if (linefeed) if (linefeed) {
fprintf(stream, "\n"); fprintf(stream, "\n");
}
} }
#ifdef RL_STATE_READCMD #ifdef RL_STATE_READCMD
@ -433,33 +465,44 @@ static void fPrintAndLog(FILE *stream, const char *fmt, ...) {
if (((g_printAndLog & PRINTANDLOG_LOG) && logging && logfile) || if (((g_printAndLog & PRINTANDLOG_LOG) && logging && logfile) ||
(g_printAndLog & PRINTANDLOG_GRAB)) { (g_printAndLog & PRINTANDLOG_GRAB)) {
memcpy_filter_emoji(buffer3, buffer2, sizeof(buffer2), EMO_ALTTEXT); memcpy_filter_emoji(buffer3, buffer2, sizeof(buffer2), EMO_ALTTEXT);
if (filter_ansi == false) { if (filter_ansi == false) {
memcpy_filter_ansi(buffer, buffer3, sizeof(buffer3), true); memcpy_filter_ansi(buffer, buffer3, sizeof(buffer3), true);
} }
} }
if ((g_printAndLog & PRINTANDLOG_LOG) && logging && logfile) { if ((g_printAndLog & PRINTANDLOG_LOG) && logging && logfile) {
if (filter_ansi) { if (filter_ansi) {
fprintf(logfile, "%s", buffer3); fprintf(logfile, "%s", buffer3);
} else { } else {
fprintf(logfile, "%s", buffer); fprintf(logfile, "%s", buffer);
} }
if (linefeed)
if (linefeed) {
fprintf(logfile, "\n"); fprintf(logfile, "\n");
}
fflush(logfile); fflush(logfile);
} }
if (g_printAndLog & PRINTANDLOG_GRAB) { if (g_printAndLog & PRINTANDLOG_GRAB) {
if (filter_ansi) { if (filter_ansi) {
fill_grabber(buffer3); fill_grabber(buffer3);
} else { } else {
fill_grabber(buffer); fill_grabber(buffer);
} }
if (linefeed)
if (linefeed) {
fill_grabber("\n"); fill_grabber("\n");
}
} }
if (flushAfterWrite) if (flushAfterWrite) {
fflush(stdout); fflush(stdout);
}
//release lock //release lock
pthread_mutex_unlock(&g_print_lock); pthread_mutex_unlock(&g_print_lock);
@ -478,9 +521,10 @@ void memcpy_filter_rlmarkers(void *dest, const void *src, size_t n) {
uint8_t *rsrc = (uint8_t *)src; uint8_t *rsrc = (uint8_t *)src;
uint16_t si = 0; uint16_t si = 0;
for (size_t i = 0; i < n; i++) { for (size_t i = 0; i < n; i++) {
if ((rsrc[i] == '\001') || (rsrc[i] == '\002')) if ((rsrc[i] == '\001') || (rsrc[i] == '\002')) {
// skip readline special markers // skip readline special markers
continue; continue;
}
rdest[si++] = rsrc[i]; rdest[si++] = rsrc[i];
} }
} }

View file

@ -5047,7 +5047,7 @@
"-v, --verbose verbose output", "-v, --verbose verbose output",
"-f, --file <fn> Specify a filename for dump file", "-f, --file <fn> Specify a filename for dump file",
"--emu from emulator memory", "--emu from emulator memory",
"--start <dec> index of block to start writing (default 0)", "--start <dec> index of block to start writing (def 0)",
"--end <dec> index of block to end writing (default last block)" "--end <dec> index of block to end writing (default last block)"
], ],
"usage": "hf mf gload [-hv] [--mini] [--1k] [--1k+] [--2k] [--4k] [-p <hex>] [-f <fn>] [--emu] [--start <dec>] [--end <dec>]" "usage": "hf mf gload [-hv] [--mini] [--1k] [--1k+] [--2k] [--4k] [-p <hex>] [-f <fn>] [--emu] [--start <dec>] [--end <dec>]"
@ -10992,8 +10992,8 @@
"-r, --reset Reset configuration to default values", "-r, --reset Reset configuration to default values",
"-p, --pwd <hex> Password, 7bytes, LSB-order", "-p, --pwd <hex> Password, 7bytes, LSB-order",
"-d, --delay <dec> Tag initialization delay (in us)", "-d, --delay <dec> Tag initialization delay (in us)",
"--lw <dec> offset, low pulses width (in us)", "--lw <dec> offset, low pulses width (in us), optional!",
"--lp <dec> offset, low pulses position (in us)" "--lp <dec> offset, low pulses position (in us), optional!"
], ],
"usage": "lf pcf7931 config [-hr] [-p <hex>] [-d <dec>] [--lw <dec>] [--lp <dec>]" "usage": "lf pcf7931 config [-hr] [-p <hex>] [-d <dec>] [--lw <dec>] [--lp <dec>]"
}, },
@ -13232,6 +13232,6 @@
"metadata": { "metadata": {
"commands_extracted": 760, "commands_extracted": 760,
"extracted_by": "PM3Help2JSON v1.00", "extracted_by": "PM3Help2JSON v1.00",
"extracted_on": "2025-03-12T15:46:33" "extracted_on": "2025-03-18T06:54:58"
} }
} }