Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FL-2754, FL-3945] EM4305 support #4069

Merged
merged 14 commits into from
Feb 12, 2025
108 changes: 65 additions & 43 deletions lib/lfrfid/lfrfid_worker_modes.c
Original file line number Diff line number Diff line change
Expand Up @@ -499,9 +499,6 @@ static void lfrfid_worker_mode_emulate_process(LFRFIDWorker* worker) {
static void lfrfid_worker_mode_write_process(LFRFIDWorker* worker) {
LFRFIDProtocol protocol = worker->protocol;
LFRFIDWriteRequest* request = malloc(sizeof(LFRFIDWriteRequest));
request->write_type = LFRFIDWriteTypeT5577;

bool can_be_written = protocol_dict_get_write_data(worker->protocols, protocol, request);

uint32_t write_start_time = furi_get_tick();
bool too_long = false;
Expand All @@ -510,63 +507,88 @@ static void lfrfid_worker_mode_write_process(LFRFIDWorker* worker) {
size_t data_size = protocol_dict_get_data_size(worker->protocols, protocol);
uint8_t* verify_data = malloc(data_size);
uint8_t* read_data = malloc(data_size);
protocol_dict_get_data(worker->protocols, protocol, verify_data, data_size);

if(can_be_written) {
while(!lfrfid_worker_check_for_stop(worker)) {
FURI_LOG_D(TAG, "Data write");
t5577_write(&request->t5577);

ProtocolId read_result = PROTOCOL_NO;
LFRFIDWorkerReadState state = lfrfid_worker_read_internal(
worker,
protocol_dict_get_features(worker->protocols, protocol),
LFRFID_WORKER_WRITE_VERIFY_TIME_MS,
&read_result);
protocol_dict_get_data(worker->protocols, protocol, verify_data, data_size);

if(state == LFRFIDWorkerReadOK) {
bool read_success = false;
while(!lfrfid_worker_check_for_stop(worker)) {
FURI_LOG_D(TAG, "Data write");
uint16_t skips = 0;
for(size_t i = 0; i < LFRFIDWriteTypeMax; i++) {
memset(request, 0, sizeof(LFRFIDWriteRequest));
LFRFIDWriteType write_type = i;
request->write_type = write_type;

if(read_result == protocol) {
protocol_dict_get_data(worker->protocols, protocol, read_data, data_size);
protocol_dict_set_data(worker->protocols, protocol, verify_data, data_size);

if(memcmp(read_data, verify_data, data_size) == 0) {
read_success = true;
}
}
bool can_be_written =
protocol_dict_get_write_data(worker->protocols, protocol, request);

if(read_success) {
if(!can_be_written) {
skips++;
if(skips == LFRFIDWriteTypeMax) {
if(worker->write_cb) {
worker->write_cb(LFRFIDWorkerWriteOK, worker->cb_ctx);
worker->write_cb(LFRFIDWorkerWriteProtocolCannotBeWritten, worker->cb_ctx);
}
break;
} else {
unsuccessful_reads++;
}
continue;
}

if(unsuccessful_reads == LFRFID_WORKER_WRITE_MAX_UNSUCCESSFUL_READS) {
if(worker->write_cb) {
worker->write_cb(LFRFIDWorkerWriteFobCannotBeWritten, worker->cb_ctx);
}
}
memset(read_data, 0, data_size);

if(request->write_type == LFRFIDWriteTypeT5577) {
t5577_write(&request->t5577);
} else if(request->write_type == LFRFIDWriteTypeEM4305) {
em4305_write(&request->em4305);
} else {
furi_crash("Unknown write type");
}
}
ProtocolId read_result = PROTOCOL_NO;
LFRFIDWorkerReadState state = lfrfid_worker_read_internal(
worker,
protocol_dict_get_features(worker->protocols, protocol),
LFRFID_WORKER_WRITE_VERIFY_TIME_MS,
&read_result);

if(state == LFRFIDWorkerReadOK) {
bool read_success = false;

if(read_result == protocol) {
protocol_dict_get_data(worker->protocols, protocol, read_data, data_size);

if(memcmp(read_data, verify_data, data_size) == 0) {
read_success = true;
}
} else if(state == LFRFIDWorkerReadExit) {
break;
}

if(!too_long &&
(furi_get_tick() - write_start_time) > LFRFID_WORKER_WRITE_TOO_LONG_TIME_MS) {
too_long = true;
if(read_success) {
if(worker->write_cb) {
worker->write_cb(LFRFIDWorkerWriteTooLongToWrite, worker->cb_ctx);
worker->write_cb(LFRFIDWorkerWriteOK, worker->cb_ctx);
}
}
break;
} else {
unsuccessful_reads++;

lfrfid_worker_delay(worker, LFRFID_WORKER_WRITE_DROP_TIME_MS);
if(unsuccessful_reads == LFRFID_WORKER_WRITE_MAX_UNSUCCESSFUL_READS) {
if(worker->write_cb) {
worker->write_cb(LFRFIDWorkerWriteFobCannotBeWritten, worker->cb_ctx);
}
}
}
} else if(state == LFRFIDWorkerReadExit) {
break;
}
} else {
if(worker->write_cb) {
worker->write_cb(LFRFIDWorkerWriteProtocolCannotBeWritten, worker->cb_ctx);

if(!too_long &&
(furi_get_tick() - write_start_time) > LFRFID_WORKER_WRITE_TOO_LONG_TIME_MS) {
too_long = true;
if(worker->write_cb) {
worker->write_cb(LFRFIDWorkerWriteTooLongToWrite, worker->cb_ctx);
}
}

lfrfid_worker_delay(worker, LFRFID_WORKER_WRITE_DROP_TIME_MS);
}

free(request);
Expand Down
6 changes: 6 additions & 0 deletions lib/lfrfid/protocols/lfrfid_protocols.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once
#include <toolbox/protocols/protocol.h>
#include "../tools/t5577.h"
#include "../tools/em4305.h"

typedef enum {
LFRFIDFeatureASK = 1 << 0, /** ASK Demodulation */
Expand Down Expand Up @@ -31,18 +32,23 @@ typedef enum {
LFRFIDProtocolNexwatch,
LFRFIDProtocolSecurakey,
LFRFIDProtocolGProxII,

LFRFIDProtocolMax,
} LFRFIDProtocol;

extern const ProtocolBase* lfrfid_protocols[];

typedef enum {
LFRFIDWriteTypeT5577,
LFRFIDWriteTypeEM4305,

LFRFIDWriteTypeMax,
} LFRFIDWriteType;

typedef struct {
LFRFIDWriteType write_type;
union {
LFRFIDT5577 t5577;
LFRFIDEM4305 em4305;
};
} LFRFIDWriteRequest;
18 changes: 18 additions & 0 deletions lib/lfrfid/protocols/protocol_electra.c
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,24 @@ bool protocol_electra_write_data(ProtocolElectra* protocol, void* data) {
request->t5577.blocks_to_write = 5;
result = true;
}
if(request->write_type == LFRFIDWriteTypeEM4305) {
request->em4305.word[4] =
(EM4x05_MODULATION_MANCHESTER | EM4x05_SET_BITRATE(64) | (8 << EM4x05_MAXBLOCK_SHIFT));
uint64_t encoded_data_reversed = 0;
uint64_t encoded_epilogue_reversed = 0;
for(uint8_t i = 0; i < 64; i++) {
encoded_data_reversed = (encoded_data_reversed << 1) |
((protocol->encoded_base_data >> i) & 1);
encoded_epilogue_reversed = (encoded_epilogue_reversed << 1) |
((protocol->encoded_epilogue >> i) & 1);
}
request->em4305.word[5] = encoded_data_reversed & 0xFFFFFFFF;
request->em4305.word[6] = encoded_data_reversed >> 32;
request->em4305.word[7] = encoded_epilogue_reversed & 0xFFFFFFFF;
request->em4305.word[8] = encoded_epilogue_reversed >> 32;
request->em4305.mask = 0x01F0;
result = true;
}
return result;
}

Expand Down
26 changes: 26 additions & 0 deletions lib/lfrfid/protocols/protocol_em4100.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,19 @@ uint32_t protocol_em4100_get_t5577_bitrate(ProtocolEM4100* proto) {
}
}

uint32_t protocol_em4100_get_em4305_bitrate(ProtocolEM4100* proto) {
switch(proto->clock_per_bit) {
case 64:
return EM4x05_SET_BITRATE(64);
case 32:
return EM4x05_SET_BITRATE(32);
case 16:
return EM4x05_SET_BITRATE(16);
default:
return EM4x05_SET_BITRATE(64);
}
}

uint16_t protocol_em4100_get_short_time_low(ProtocolEM4100* proto) {
return EM_READ_SHORT_TIME_BASE / protocol_em4100_get_time_divisor(proto) -
EM_READ_JITTER_TIME_BASE / protocol_em4100_get_time_divisor(proto);
Expand Down Expand Up @@ -339,6 +352,19 @@ bool protocol_em4100_write_data(ProtocolEM4100* protocol, void* data) {
request->t5577.block[2] = protocol->encoded_data;
request->t5577.blocks_to_write = 3;
result = true;
} else if(request->write_type == LFRFIDWriteTypeEM4305) {
request->em4305.word[4] =
(EM4x05_MODULATION_MANCHESTER | protocol_em4100_get_em4305_bitrate(protocol) |
(6 << EM4x05_MAXBLOCK_SHIFT));
uint64_t encoded_data_reversed = 0;
for(uint8_t i = 0; i < 64; i++) {
encoded_data_reversed = (encoded_data_reversed << 1) |
((protocol->encoded_data >> i) & 1);
}
request->em4305.word[5] = encoded_data_reversed;
request->em4305.word[6] = encoded_data_reversed >> 32;
request->em4305.mask = 0x70;
result = true;
}
return result;
}
Expand Down
14 changes: 14 additions & 0 deletions lib/lfrfid/protocols/protocol_gallagher.c
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,20 @@ bool protocol_gallagher_write_data(ProtocolGallagher* protocol, void* data) {
request->t5577.block[3] = bit_lib_get_bits_32(protocol->encoded_data, 64, 32);
request->t5577.blocks_to_write = 4;
result = true;
} else if(request->write_type == LFRFIDWriteTypeEM4305) {
request->em4305.word[4] =
(EM4x05_MODULATION_MANCHESTER | EM4x05_SET_BITRATE(32) | (7 << EM4x05_MAXBLOCK_SHIFT));
uint32_t encoded_data_reversed[3] = {0};
for(uint8_t i = 0; i < (32 * 3); i++) {
encoded_data_reversed[i / 32] =
(encoded_data_reversed[i / 32] << 1) |
(bit_lib_get_bit(protocol->encoded_data, ((32 * 3) - i)) & 1);
}
request->em4305.word[5] = encoded_data_reversed[2];
request->em4305.word[6] = encoded_data_reversed[1];
request->em4305.word[7] = encoded_data_reversed[0];
request->em4305.mask = 0xF0;
result = true;
}
return result;
}
Expand Down
13 changes: 13 additions & 0 deletions lib/lfrfid/protocols/protocol_viking.c
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,19 @@ bool protocol_viking_write_data(ProtocolViking* protocol, void* data) {
request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32);
request->t5577.blocks_to_write = 3;
result = true;
} else if(request->write_type == LFRFIDWriteTypeEM4305) {
request->em4305.word[4] =
(EM4x05_MODULATION_MANCHESTER | EM4x05_SET_BITRATE(32) | (6 << EM4x05_MAXBLOCK_SHIFT));
uint32_t encoded_data_reversed[2] = {0};
for(uint8_t i = 0; i < 64; i++) {
encoded_data_reversed[i / 32] =
(encoded_data_reversed[i / 32] << 1) |
(bit_lib_get_bit(protocol->encoded_data, (63 - i)) & 1);
}
request->em4305.word[5] = encoded_data_reversed[1];
request->em4305.word[6] = encoded_data_reversed[0];
request->em4305.mask = 0x70;
result = true;
}
return result;
}
Expand Down
Loading
Loading