mirror of
https://github.com/flipperdevices/flipperzero-firmware.git
synced 2025-12-12 12:51:22 +04:00
[FL-2754, FL-3945] EM4305 support (#4069)
* Initial EM4305 write support * Support for writing EM4100 data to EM4305 blank tags * F18 API version bump * Satisfy pvs * Lib: cleanup em4305 code * Mask size fix * Electra * Fix leftovers from a previous implementation * Viking * Gallagher * LFRFID: cleanup em4305 Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
@@ -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;
|
||||
@@ -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);
|
||||
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;
|
||||
|
||||
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_set_data(worker->protocols, protocol, verify_data, data_size);
|
||||
|
||||
if(state == LFRFIDWorkerReadOK) {
|
||||
bool read_success = false;
|
||||
bool can_be_written =
|
||||
protocol_dict_get_write_data(worker->protocols, protocol, request);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if(read_success) {
|
||||
if(worker->write_cb) {
|
||||
worker->write_cb(LFRFIDWorkerWriteOK, worker->cb_ctx);
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
unsuccessful_reads++;
|
||||
|
||||
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(state == LFRFIDWorkerReadExit) {
|
||||
break;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
if(worker->write_cb) {
|
||||
worker->write_cb(LFRFIDWorkerWriteProtocolCannotBeWritten, worker->cb_ctx);
|
||||
}
|
||||
lfrfid_worker_delay(worker, LFRFID_WORKER_WRITE_DROP_TIME_MS);
|
||||
}
|
||||
|
||||
free(request);
|
||||
|
||||
@@ -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 */
|
||||
@@ -31,6 +32,7 @@ typedef enum {
|
||||
LFRFIDProtocolNexwatch,
|
||||
LFRFIDProtocolSecurakey,
|
||||
LFRFIDProtocolGProxII,
|
||||
|
||||
LFRFIDProtocolMax,
|
||||
} LFRFIDProtocol;
|
||||
|
||||
@@ -38,11 +40,15 @@ extern const ProtocolBase* lfrfid_protocols[];
|
||||
|
||||
typedef enum {
|
||||
LFRFIDWriteTypeT5577,
|
||||
LFRFIDWriteTypeEM4305,
|
||||
|
||||
LFRFIDWriteTypeMax,
|
||||
} LFRFIDWriteType;
|
||||
|
||||
typedef struct {
|
||||
LFRFIDWriteType write_type;
|
||||
union {
|
||||
LFRFIDT5577 t5577;
|
||||
LFRFIDEM4305 em4305;
|
||||
};
|
||||
} LFRFIDWriteRequest;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
152
lib/lfrfid/tools/em4305.c
Normal file
152
lib/lfrfid/tools/em4305.c
Normal file
@@ -0,0 +1,152 @@
|
||||
#include "em4305.h"
|
||||
#include <furi.h>
|
||||
#include <furi_hal_rfid.h>
|
||||
|
||||
#define TAG "EM4305"
|
||||
|
||||
#define EM4305_TIMING_1 (32)
|
||||
#define EM4305_TIMING_0_OFF (23)
|
||||
#define EM4305_TIMING_0_ON (18)
|
||||
|
||||
#define EM4305_FIELD_STOP_OFF_CYCLES (55)
|
||||
#define EM4305_FIELD_STOP_ON_CYCLES (18)
|
||||
|
||||
#define EM4305_TIMING_POWER_CHECK (1480)
|
||||
#define EM4305_TIMING_EEPROM_WRITE (9340)
|
||||
|
||||
static bool em4305_line_parity(uint8_t data) {
|
||||
uint8_t parity = 0;
|
||||
for(uint8_t i = 0; i < 8; i++) {
|
||||
parity ^= (data >> i) & 1;
|
||||
}
|
||||
return parity;
|
||||
}
|
||||
|
||||
static uint64_t em4305_prepare_data(uint32_t data) {
|
||||
uint8_t i, j;
|
||||
uint64_t data_with_parity = 0;
|
||||
|
||||
// 4 lines of 8 bits of data
|
||||
// line even parity at bits 8 17 26 35
|
||||
// column even parity at bits 36-43
|
||||
// bit 44 is always 0
|
||||
// final table is 5 lines of 9 bits
|
||||
|
||||
// line parity
|
||||
for(i = 0; i < 4; i++) {
|
||||
for(j = 0; j < 8; j++) {
|
||||
data_with_parity = (data_with_parity << 1) | ((data >> (i * 8 + j)) & 1);
|
||||
}
|
||||
data_with_parity = (data_with_parity << 1) | (uint64_t)em4305_line_parity(data >> (i * 8));
|
||||
}
|
||||
|
||||
// column parity
|
||||
for(i = 0; i < 8; i++) {
|
||||
uint8_t column_parity = 0;
|
||||
for(j = 0; j < 4; j++) {
|
||||
column_parity ^= (data >> (j * 8 + i)) & 1;
|
||||
}
|
||||
data_with_parity = (data_with_parity << 1) | column_parity;
|
||||
}
|
||||
|
||||
// bit 44
|
||||
data_with_parity = (data_with_parity << 1) | 0;
|
||||
|
||||
return data_with_parity;
|
||||
}
|
||||
|
||||
static void em4305_start(void) {
|
||||
furi_hal_rfid_tim_read_start(125000, 0.5);
|
||||
|
||||
// do not ground the antenna
|
||||
furi_hal_rfid_pin_pull_release();
|
||||
}
|
||||
|
||||
static void em4305_stop(void) {
|
||||
furi_hal_rfid_tim_read_stop();
|
||||
furi_hal_rfid_pins_reset();
|
||||
}
|
||||
|
||||
static void em4305_write_bit(bool value) {
|
||||
if(value) {
|
||||
furi_delay_us(EM4305_TIMING_1 * 8);
|
||||
} else {
|
||||
furi_hal_rfid_tim_read_pause();
|
||||
furi_delay_us(EM4305_TIMING_0_OFF * 8);
|
||||
furi_hal_rfid_tim_read_continue();
|
||||
furi_delay_us(EM4305_TIMING_0_ON * 8);
|
||||
}
|
||||
}
|
||||
|
||||
static void em4305_write_opcode(uint8_t value) {
|
||||
// 3 bit opcode
|
||||
for(uint8_t i = 0; i < 3; i++) {
|
||||
em4305_write_bit((value >> i) & 1);
|
||||
}
|
||||
|
||||
// parity
|
||||
bool parity = 0;
|
||||
for(uint8_t i = 0; i < 3; i++) {
|
||||
parity ^= (value >> i) & 1;
|
||||
}
|
||||
em4305_write_bit(parity);
|
||||
}
|
||||
|
||||
static void em4305_field_stop() {
|
||||
furi_hal_rfid_tim_read_pause();
|
||||
furi_delay_us(EM4305_FIELD_STOP_OFF_CYCLES * 8);
|
||||
furi_hal_rfid_tim_read_continue();
|
||||
furi_delay_us(EM4305_FIELD_STOP_ON_CYCLES * 8);
|
||||
}
|
||||
|
||||
static void em4305_write_word(uint8_t address, uint32_t data) {
|
||||
// parity
|
||||
uint64_t data_with_parity = em4305_prepare_data(data);
|
||||
|
||||
// power up the tag
|
||||
furi_delay_us(8000);
|
||||
|
||||
// field stop
|
||||
em4305_field_stop();
|
||||
|
||||
// start bit
|
||||
em4305_write_bit(0);
|
||||
|
||||
// opcode
|
||||
em4305_write_opcode(EM4x05_OPCODE_WRITE);
|
||||
|
||||
// address
|
||||
bool address_parity = 0;
|
||||
for(uint8_t i = 0; i < 4; i++) {
|
||||
em4305_write_bit((address >> (i)) & 1);
|
||||
address_parity ^= (address >> (i)) & 1;
|
||||
}
|
||||
em4305_write_bit(0);
|
||||
em4305_write_bit(0);
|
||||
em4305_write_bit(address_parity);
|
||||
|
||||
// data
|
||||
for(uint8_t i = 0; i < 45; i++) {
|
||||
em4305_write_bit((data_with_parity >> (44 - i)) & 1);
|
||||
}
|
||||
|
||||
// wait for power check and eeprom write
|
||||
furi_delay_us(EM4305_TIMING_POWER_CHECK);
|
||||
furi_delay_us(EM4305_TIMING_EEPROM_WRITE);
|
||||
}
|
||||
|
||||
void em4305_write(LFRFIDEM4305* data) {
|
||||
furi_check(data);
|
||||
|
||||
em4305_start();
|
||||
FURI_CRITICAL_ENTER();
|
||||
|
||||
for(uint8_t i = 0; i < EM4x05_WORD_COUNT; i++) {
|
||||
if(data->mask & (1 << i)) {
|
||||
em4305_write_word(i, data->word[i]);
|
||||
}
|
||||
}
|
||||
|
||||
FURI_CRITICAL_EXIT();
|
||||
em4305_stop();
|
||||
}
|
||||
61
lib/lfrfid/tools/em4305.h
Normal file
61
lib/lfrfid/tools/em4305.h
Normal file
@@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// EM4305/4205 chip config definitions, thanks proxmark3!
|
||||
#define EM4x05_GET_BITRATE(x) ((((x) & 0x3F) * 2) + 2)
|
||||
// Note: only data rates 8, 16, 32, 40(*) and 64 are supported. (*) only with EM4305 330pF
|
||||
#define EM4x05_SET_BITRATE(x) (((x) - 2) / 2)
|
||||
#define EM4x05_MODULATION_NRZ (0x00000000)
|
||||
#define EM4x05_MODULATION_MANCHESTER (0x00000040)
|
||||
#define EM4x05_MODULATION_BIPHASE (0x00000080)
|
||||
#define EM4x05_MODULATION_MILLER (0x000000C0) // not supported by all 4x05/4x69 chips
|
||||
#define EM4x05_MODULATION_PSK1 (0x00000100) // not supported by all 4x05/4x69 chips
|
||||
#define EM4x05_MODULATION_PSK2 (0x00000140) // not supported by all 4x05/4x69 chips
|
||||
#define EM4x05_MODULATION_PSK3 (0x00000180) // not supported by all 4x05/4x69 chips
|
||||
#define EM4x05_MODULATION_FSK1 (0x00000200) // not supported by all 4x05/4x69 chips
|
||||
#define EM4x05_MODULATION_FSK2 (0x00000240) // not supported by all 4x05/4x69 chips
|
||||
#define EM4x05_PSK_RF_2 (0)
|
||||
#define EM4x05_PSK_RF_4 (0x00000400)
|
||||
#define EM4x05_PSK_RF_8 (0x00000800)
|
||||
#define EM4x05_MAXBLOCK_SHIFT (14)
|
||||
#define EM4x05_FIRST_USER_BLOCK (5)
|
||||
#define EM4x05_SET_NUM_BLOCKS(x) \
|
||||
(((x) + 4) << 14) // number of blocks sent during default read mode
|
||||
#define EM4x05_GET_NUM_BLOCKS(x) ((((x) >> 14) & 0xF) - 4)
|
||||
#define EM4x05_READ_LOGIN_REQ (1 << 18)
|
||||
#define EM4x05_READ_HK_LOGIN_REQ (1 << 19)
|
||||
#define EM4x05_WRITE_LOGIN_REQ (1 << 20)
|
||||
#define EM4x05_WRITE_HK_LOGIN_REQ (1 << 21)
|
||||
#define EM4x05_READ_AFTER_WRITE (1 << 22)
|
||||
#define EM4x05_DISABLE_ALLOWED (1 << 23)
|
||||
#define EM4x05_READER_TALK_FIRST (1 << 24)
|
||||
#define EM4x05_INVERT (1 << 25)
|
||||
#define EM4x05_PIGEON (1 << 26)
|
||||
|
||||
#define EM4x05_WORD_COUNT (16)
|
||||
|
||||
#define EM4x05_OPCODE_LOGIN (0b001)
|
||||
#define EM4x05_OPCODE_WRITE (0b010)
|
||||
#define EM4x05_OPCODE_READ (0b100)
|
||||
#define EM4x05_OPCODE_PROTECT (0b110)
|
||||
#define EM4x05_OPCODE_DISABLE (0b101)
|
||||
|
||||
typedef struct {
|
||||
uint32_t word[EM4x05_WORD_COUNT]; /**< Word data to write */
|
||||
uint16_t mask; /**< Word mask */
|
||||
} LFRFIDEM4305;
|
||||
|
||||
/** Write EM4305 tag data to tag
|
||||
*
|
||||
* @param data The data to write (mask is taken from that data)
|
||||
*/
|
||||
void em4305_write(LFRFIDEM4305* data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,5 +1,5 @@
|
||||
entry,status,name,type,params
|
||||
Version,+,79.2,,
|
||||
Version,+,79.3,,
|
||||
Header,+,applications/services/bt/bt_service/bt.h,,
|
||||
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
|
||||
Header,+,applications/services/cli/cli.h,,
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
entry,status,name,type,params
|
||||
Version,+,79.2,,
|
||||
Version,+,79.3,,
|
||||
Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
|
||||
Header,+,applications/services/bt/bt_service/bt.h,,
|
||||
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
|
||||
@@ -1000,6 +1000,7 @@ Function,+,elements_string_fit_width,void,"Canvas*, FuriString*, size_t"
|
||||
Function,+,elements_text_box,void,"Canvas*, int32_t, int32_t, size_t, size_t, Align, Align, const char*, _Bool"
|
||||
Function,+,elf_resolve_from_hashtable,_Bool,"const ElfApiInterface*, uint32_t, Elf32_Addr*"
|
||||
Function,+,elf_symbolname_hash,uint32_t,const char*
|
||||
Function,+,em4305_write,void,LFRFIDEM4305*
|
||||
Function,+,empty_screen_alloc,EmptyScreen*,
|
||||
Function,+,empty_screen_free,void,EmptyScreen*
|
||||
Function,+,empty_screen_get_view,View*,EmptyScreen*
|
||||
|
||||
|
Reference in New Issue
Block a user