[FL-2529][FL-1628] New LF-RFID subsystem (#1601)

* Makefile: unit tests pack
* RFID: pulse joiner and its unit test
* Move pulse protocol helpers to appropriate place
* Drop pulse_joiner tests
* Generic protocol, protocols dictionary, unit test
* Protocol dict unit test
* iButton: protocols dictionary
* Lib: varint
* Lib: profiler
* Unit test: varint
* rfid: worker mockup
* LFRFID: em4100 unit test
* Storage: file_exist function
* rfid: fsk osc
* rfid: generic fsk demodulator
* rfid: protocol em4100
* rfid: protocol h10301
* rfid: protocol io prox xsf
* Unit test: rfid protocols
* rfid: new hal
* rfid: raw worker
* Unit test: fix error output
* rfid: worker
* rfid: plain c cli
* fw: migrate to scons
* lfrfid: full io prox support
* unit test: io prox protocol
* SubGHZ: move bit defines to source
* FSK oscillator: level duration compability
* libs: bit manipulation library
* lfrfid: ioprox protocol, use bit library and new level duration method of FSK ocillator
* bit lib: unit tests
* Bit lib: parity tests, remove every nth bit, copy bits
* Lfrfid: awid protocol
* bit lib: uint16 and uint32 getters, unit tests
* lfrfid: FDX-B read, draft version
* Minunit: better memeq assert
* bit lib: reverse, print, print regions
* Protocol dict: get protocol features, get protocol validate count
* lfrfid worker: improved read
* lfrfid raw worker: psk support
* Cli: rfid plain C cli
* protocol AWID: render
* protocol em4100: render
* protocol h10301: render
* protocol indala26: support every indala 26 scramble
* Protocol IO Prox: render
* Protocol FDX-B: advanced read
* lfrfid: remove unused test function
* lfrfid: fix os primitives
* bit lib: crc16 and unit tests
* FDX-B: save data
* lfrfid worker: increase stream size. Alloc raw worker only when needed.
* lfrfid: indala26 emulation
* lfrfid: prepare to write
* lfrfid: fdx-b emulation
* lfrfid: awid, ioprox write
* lfrfid: write t55xx w\o validation
* lfrfid: better t55xx block0 handling
* lfrfid: use new t5577 functions in worker
* lfrfid: improve protocol description
* lfrfid: write and verify
* lfrfid: delete cpp cli
* lfrfid: improve worker usage
* lfrfid-app: step to new worker
* lfrfid: old indala (I40134) load fallback
* lfrfid: indala26, recover wrong synced data
* lfrfid: remove old worker
* lfrfid app: dummy read screen
* lfrfid app: less dummy read screen
* lfrfid: generic 96-bit HID protocol (covers up to HID 37-bit)
* rename
* lfrfid: improve indala26 read
* lfrfid: generic 192-bit HID protocol (covers all HID extended)
* lfrfid: TODO about HID render
* lfrfid: new protocol FDX-A
* lfrfid-app: correct worker stop on exit
* misc fixes
* lfrfid: FDX-A and HID distinguishability has been fixed.
* lfrfid: decode HID size header and render it (#1612)
* lfrfid: rename HID96 and HID192 to HIDProx and HIDExt
* lfrfid: extra actions scene
* lfrfid: decode generic HID Proximity size lazily (#1618)
* lib: stream of data buffers concept
* lfrfid: raw file helper
* lfrfid: changed raw worker api
* lfrfid: packed varint pair
* lfrfid: read stream speedup
* lfrfid app: show read mode
* Documentation
* lfrfid app: raw read gui
* lfrfid app: storage check for raw read
* memleak fix
* review fixes
* lfrfid app: read blink color
* lfrfid app: reset key name after read
* review fixes
* lfrfid app: fix copypasted text
* review fixes
* lfrfid: disable debug gpio
* lfrfid: card detection events
* lfrfid: change validation color from magenta to green
* Update core_defines.
* lfrfid: prefix fdx-b id by zeroes
* lfrfid: parse up to 43-bit HID Proximity keys (#1640)
* Fbt: downgrade toolchain and fix PS1
* lfrfid: fix unit tests
* lfrfid app: remove printf
* lfrfid: indala26, use bit 55 as data
* lfrfid: indala26, better brief format
* lfrfid: indala26, loading fallback
* lfrfid: read timing tuning

Co-authored-by: James Ide <ide@users.noreply.github.com>
Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
SG
2022-08-24 01:57:39 +10:00
committed by GitHub
parent f92127c0a7
commit 9bfb641d3e
179 changed files with 10234 additions and 4804 deletions

19
lib/lfrfid/SConscript Normal file
View File

@@ -0,0 +1,19 @@
Import("env")
env.Append(
LINT_SOURCES=[
"#/lib/lfrfid",
],
CPPPATH=[
"#/lib/lfrfid",
],
)
libenv = env.Clone(FW_LIB_NAME="lfrfid")
libenv.ApplyLibFlags()
sources = libenv.GlobRecursive("*.c*")
lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources)
libenv.Install("${LIB_DIST_DIR}", lib)
Return("lib")

View File

@@ -0,0 +1,182 @@
#include "lfrfid_dict_file.h"
#include <storage/storage.h>
#include <flipper_format/flipper_format.h>
#include <lfrfid/tools/bit_lib.h>
#define LFRFID_DICT_FILETYPE "Flipper RFID key"
bool lfrfid_dict_file_save(ProtocolDict* dict, ProtocolId protocol, const char* filename) {
furi_check(protocol != PROTOCOL_NO);
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* file = flipper_format_file_alloc(storage);
size_t data_size = protocol_dict_get_data_size(dict, protocol);
uint8_t* data = malloc(data_size);
bool result = false;
do {
if(!flipper_format_file_open_always(file, filename)) break;
if(!flipper_format_write_header_cstr(file, LFRFID_DICT_FILETYPE, 1)) break;
// TODO: write comment about protocol types into file
if(!flipper_format_write_string_cstr(
file, "Key type", protocol_dict_get_name(dict, protocol)))
break;
// TODO: write comment about protocol sizes into file
protocol_dict_get_data(dict, protocol, data, data_size);
if(!flipper_format_write_hex(file, "Data", data, data_size)) break;
result = true;
} while(false);
flipper_format_free(file);
furi_record_close(RECORD_STORAGE);
free(data);
return result;
}
static void lfrfid_dict_protocol_indala_data(
uint8_t* data,
size_t data_size,
uint8_t* protocol_data,
size_t protocol_data_size) {
UNUSED(data_size);
memset(protocol_data, 0, protocol_data_size);
// fc
bit_lib_set_bit(protocol_data, 24, bit_lib_get_bit(data, 0));
bit_lib_set_bit(protocol_data, 16, bit_lib_get_bit(data, 1));
bit_lib_set_bit(protocol_data, 11, bit_lib_get_bit(data, 2));
bit_lib_set_bit(protocol_data, 14, bit_lib_get_bit(data, 3));
bit_lib_set_bit(protocol_data, 15, bit_lib_get_bit(data, 4));
bit_lib_set_bit(protocol_data, 20, bit_lib_get_bit(data, 5));
bit_lib_set_bit(protocol_data, 6, bit_lib_get_bit(data, 6));
bit_lib_set_bit(protocol_data, 25, bit_lib_get_bit(data, 7));
// cn
bit_lib_set_bit(protocol_data, 9, bit_lib_get_bit(data, 8 + 0));
bit_lib_set_bit(protocol_data, 12, bit_lib_get_bit(data, 8 + 1));
bit_lib_set_bit(protocol_data, 10, bit_lib_get_bit(data, 8 + 2));
bit_lib_set_bit(protocol_data, 7, bit_lib_get_bit(data, 8 + 3));
bit_lib_set_bit(protocol_data, 19, bit_lib_get_bit(data, 8 + 4));
bit_lib_set_bit(protocol_data, 3, bit_lib_get_bit(data, 8 + 5));
bit_lib_set_bit(protocol_data, 2, bit_lib_get_bit(data, 8 + 6));
bit_lib_set_bit(protocol_data, 18, bit_lib_get_bit(data, 8 + 7));
bit_lib_set_bit(protocol_data, 13, bit_lib_get_bit(data, 8 + 8));
bit_lib_set_bit(protocol_data, 0, bit_lib_get_bit(data, 8 + 9));
bit_lib_set_bit(protocol_data, 4, bit_lib_get_bit(data, 8 + 10));
bit_lib_set_bit(protocol_data, 21, bit_lib_get_bit(data, 8 + 11));
bit_lib_set_bit(protocol_data, 23, bit_lib_get_bit(data, 8 + 12));
bit_lib_set_bit(protocol_data, 26, bit_lib_get_bit(data, 8 + 13));
bit_lib_set_bit(protocol_data, 17, bit_lib_get_bit(data, 8 + 14));
bit_lib_set_bit(protocol_data, 8, bit_lib_get_bit(data, 8 + 15));
const uint32_t fc_and_card = data[0] << 16 | data[1] << 8 | data[2];
// indala checksum
uint8_t checksum_sum = 0;
checksum_sum += ((fc_and_card >> 14) & 1);
checksum_sum += ((fc_and_card >> 12) & 1);
checksum_sum += ((fc_and_card >> 9) & 1);
checksum_sum += ((fc_and_card >> 8) & 1);
checksum_sum += ((fc_and_card >> 6) & 1);
checksum_sum += ((fc_and_card >> 5) & 1);
checksum_sum += ((fc_and_card >> 2) & 1);
checksum_sum += ((fc_and_card >> 0) & 1);
checksum_sum = checksum_sum & 0b1;
if(checksum_sum) {
bit_lib_set_bit(protocol_data, 27, 0);
bit_lib_set_bit(protocol_data, 28, 1);
} else {
bit_lib_set_bit(protocol_data, 27, 1);
bit_lib_set_bit(protocol_data, 28, 0);
}
// wiegand parity
uint8_t even_parity_sum = 0;
for(int8_t i = 12; i < 24; i++) {
if(((fc_and_card >> i) & 1) == 1) {
even_parity_sum++;
}
}
bit_lib_set_bit(protocol_data, 1, even_parity_sum % 2);
uint8_t odd_parity_sum = 1;
for(int8_t i = 0; i < 12; i++) {
if(((fc_and_card >> i) & 1) == 1) {
odd_parity_sum++;
}
}
bit_lib_set_bit(protocol_data, 5, odd_parity_sum % 2);
}
static ProtocolId lfrfid_dict_protocol_fallback(
ProtocolDict* dict,
const char* protocol_name,
FlipperFormat* file) {
ProtocolId result = PROTOCOL_NO;
if(strcmp(protocol_name, "I40134") == 0) {
ProtocolId protocol = LFRFIDProtocolIndala26;
size_t data_size = 3;
size_t protocol_data_size = protocol_dict_get_data_size(dict, protocol);
uint8_t* data = malloc(data_size);
uint8_t* protocol_data = malloc(protocol_data_size);
if(flipper_format_read_hex(file, "Data", data, data_size)) {
lfrfid_dict_protocol_indala_data(data, data_size, protocol_data, protocol_data_size);
protocol_dict_set_data(dict, protocol, protocol_data, protocol_data_size);
result = protocol;
}
free(protocol_data);
free(data);
}
return result;
}
ProtocolId lfrfid_dict_file_load(ProtocolDict* dict, const char* filename) {
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* file = flipper_format_file_alloc(storage);
ProtocolId result = PROTOCOL_NO;
uint8_t* data = malloc(protocol_dict_get_max_data_size(dict));
string_t str_result;
string_init(str_result);
do {
if(!flipper_format_file_open_existing(file, filename)) break;
// header
uint32_t version;
if(!flipper_format_read_header(file, str_result, &version)) break;
if(string_cmp_str(str_result, LFRFID_DICT_FILETYPE) != 0) break;
if(version != 1) break;
// type
if(!flipper_format_read_string(file, "Key type", str_result)) break;
ProtocolId protocol;
protocol = protocol_dict_get_protocol_by_name(dict, string_get_cstr(str_result));
if(protocol == PROTOCOL_NO) {
protocol = lfrfid_dict_protocol_fallback(dict, string_get_cstr(str_result), file);
if(protocol == PROTOCOL_NO) break;
} else {
// data
size_t data_size = protocol_dict_get_data_size(dict, protocol);
if(!flipper_format_read_hex(file, "Data", data, data_size)) break;
protocol_dict_set_data(dict, protocol, data, data_size);
}
result = protocol;
} while(false);
free(data);
string_clear(str_result);
flipper_format_free(file);
furi_record_close(RECORD_STORAGE);
return result;
}

View File

@@ -0,0 +1,31 @@
#pragma once
#include <toolbox/protocols/protocol_dict.h>
#include "protocols/lfrfid_protocols.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Save protocol from dictionary to file
*
* @param dict
* @param protocol
* @param filename
* @return true
* @return false
*/
bool lfrfid_dict_file_save(ProtocolDict* dict, ProtocolId protocol, const char* filename);
/**
* @brief Load protocol from file to dictionary
*
* @param dict
* @param filename
* @return ProtocolId
*/
ProtocolId lfrfid_dict_file_load(ProtocolDict* dict, const char* filename);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,145 @@
#include "lfrfid_raw_file.h"
#include "tools/varint_pair.h"
#include <toolbox/stream/file_stream.h>
#include <toolbox/varint.h>
#define LFRFID_RAW_FILE_MAGIC 0x4C464952
#define LFRFID_RAW_FILE_VERSION 1
#define TAG "RFID RAW File"
typedef struct {
uint32_t magic;
uint32_t version;
float frequency;
float duty_cycle;
uint32_t max_buffer_size;
} LFRFIDRawFileHeader;
struct LFRFIDRawFile {
Stream* stream;
uint32_t max_buffer_size;
uint8_t* buffer;
uint32_t buffer_size;
size_t buffer_counter;
};
LFRFIDRawFile* lfrfid_raw_file_alloc(Storage* storage) {
LFRFIDRawFile* file = malloc(sizeof(LFRFIDRawFile));
file->stream = file_stream_alloc(storage);
file->buffer = NULL;
return file;
}
void lfrfid_raw_file_free(LFRFIDRawFile* file) {
if(file->buffer) free(file->buffer);
stream_free(file->stream);
free(file);
}
bool lfrfid_raw_file_open_write(LFRFIDRawFile* file, const char* file_path) {
return file_stream_open(file->stream, file_path, FSAM_READ_WRITE, FSOM_CREATE_ALWAYS);
}
bool lfrfid_raw_file_open_read(LFRFIDRawFile* file, const char* file_path) {
return file_stream_open(file->stream, file_path, FSAM_READ, FSOM_OPEN_EXISTING);
}
bool lfrfid_raw_file_write_header(
LFRFIDRawFile* file,
float frequency,
float duty_cycle,
uint32_t max_buffer_size) {
LFRFIDRawFileHeader header = {
.magic = LFRFID_RAW_FILE_MAGIC,
.version = LFRFID_RAW_FILE_VERSION,
.frequency = frequency,
.duty_cycle = duty_cycle,
.max_buffer_size = max_buffer_size};
size_t size = stream_write(file->stream, (uint8_t*)&header, sizeof(LFRFIDRawFileHeader));
return (size == sizeof(LFRFIDRawFileHeader));
}
bool lfrfid_raw_file_write_buffer(LFRFIDRawFile* file, uint8_t* buffer_data, size_t buffer_size) {
size_t size;
size = stream_write(file->stream, (uint8_t*)&buffer_size, sizeof(size_t));
if(size != sizeof(size_t)) return false;
size = stream_write(file->stream, buffer_data, buffer_size);
if(size != buffer_size) return false;
return true;
}
bool lfrfid_raw_file_read_header(LFRFIDRawFile* file, float* frequency, float* duty_cycle) {
LFRFIDRawFileHeader header;
size_t size = stream_read(file->stream, (uint8_t*)&header, sizeof(LFRFIDRawFileHeader));
if(size == sizeof(LFRFIDRawFileHeader)) {
if(header.magic == LFRFID_RAW_FILE_MAGIC && header.version == LFRFID_RAW_FILE_VERSION) {
*frequency = header.frequency;
*duty_cycle = header.duty_cycle;
file->max_buffer_size = header.max_buffer_size;
file->buffer = malloc(file->max_buffer_size);
file->buffer_size = 0;
file->buffer_counter = 0;
return true;
} else {
return false;
}
} else {
return false;
}
}
bool lfrfid_raw_file_read_pair(
LFRFIDRawFile* file,
uint32_t* duration,
uint32_t* pulse,
bool* pass_end) {
size_t length = 0;
if(file->buffer_counter >= file->buffer_size) {
if(stream_eof(file->stream)) {
// rewind stream and pass header
stream_seek(file->stream, sizeof(LFRFIDRawFileHeader), StreamOffsetFromStart);
if(pass_end) *pass_end = true;
}
length = stream_read(file->stream, (uint8_t*)&file->buffer_size, sizeof(size_t));
if(length != sizeof(size_t)) {
FURI_LOG_E(TAG, "read pair: failed to read size");
return false;
}
if(file->buffer_size > file->max_buffer_size) {
FURI_LOG_E(TAG, "read pair: buffer size is too big");
return false;
}
length = stream_read(file->stream, file->buffer, file->buffer_size);
if(length != file->buffer_size) {
FURI_LOG_E(TAG, "read pair: failed to read data");
return false;
}
file->buffer_counter = 0;
}
size_t size = 0;
bool result = varint_pair_unpack(
&file->buffer[file->buffer_counter],
(size_t)(file->buffer_size - file->buffer_counter),
pulse,
duration,
&size);
if(result) {
file->buffer_counter += size;
} else {
FURI_LOG_E(TAG, "read pair: buffer is too small");
return false;
}
return true;
}

View File

@@ -0,0 +1,95 @@
#pragma once
#include <furi.h>
#include <storage/storage.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct LFRFIDRawFile LFRFIDRawFile;
/**
* @brief Allocate a new LFRFIDRawFile instance
*
* @param storage
* @return LFRFIDRawFile*
*/
LFRFIDRawFile* lfrfid_raw_file_alloc(Storage* storage);
/**
* @brief Free a LFRFIDRawFile instance
*
* @param file
*/
void lfrfid_raw_file_free(LFRFIDRawFile* file);
/**
* @brief Open RAW file for writing
*
* @param file
* @param file_path
* @return bool
*/
bool lfrfid_raw_file_open_write(LFRFIDRawFile* file, const char* file_path);
/**
* @brief Open RAW file for reading
* @param file
* @param file_path
* @return bool
*/
bool lfrfid_raw_file_open_read(LFRFIDRawFile* file, const char* file_path);
/**
* @brief Write RAW file header
*
* @param file
* @param frequency
* @param duty_cycle
* @param max_buffer_size
* @return bool
*/
bool lfrfid_raw_file_write_header(
LFRFIDRawFile* file,
float frequency,
float duty_cycle,
uint32_t max_buffer_size);
/**
* @brief Write data to RAW file
*
* @param file
* @param buffer_data
* @param buffer_size
* @return bool
*/
bool lfrfid_raw_file_write_buffer(LFRFIDRawFile* file, uint8_t* buffer_data, size_t buffer_size);
/**
* @brief Read RAW file header
*
* @param file
* @param frequency
* @param duty_cycle
* @return bool
*/
bool lfrfid_raw_file_read_header(LFRFIDRawFile* file, float* frequency, float* duty_cycle);
/**
* @brief Read varint-encoded pair from RAW file
*
* @param file
* @param duration
* @param pulse
* @param pass_end file was wrapped around, can be NULL
* @return bool
*/
bool lfrfid_raw_file_read_pair(
LFRFIDRawFile* file,
uint32_t* duration,
uint32_t* pulse,
bool* pass_end);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,357 @@
#include <furi_hal_rfid.h>
#include <toolbox/stream/file_stream.h>
#include <toolbox/buffer_stream.h>
#include <toolbox/varint.h>
#include <stream_buffer.h>
#include "lfrfid_raw_worker.h"
#include "lfrfid_raw_file.h"
#include "tools/varint_pair.h"
#define EMULATE_BUFFER_SIZE 1024
#define RFID_DATA_BUFFER_SIZE 2048
#define READ_DATA_BUFFER_COUNT 4
#define TAG_EMULATE "RAW EMULATE"
// emulate mode
typedef struct {
size_t overrun_count;
StreamBufferHandle_t stream;
} RfidEmulateCtx;
typedef struct {
uint32_t emulate_buffer_arr[EMULATE_BUFFER_SIZE];
uint32_t emulate_buffer_ccr[EMULATE_BUFFER_SIZE];
RfidEmulateCtx ctx;
} LFRFIDRawWorkerEmulateData;
typedef enum {
HalfTransfer,
TransferComplete,
} LFRFIDRawEmulateDMAEvent;
// read mode
#define READ_TEMP_DATA_SIZE 10
typedef struct {
BufferStream* stream;
VarintPair* pair;
} LFRFIDRawWorkerReadData;
// main worker
struct LFRFIDRawWorker {
string_t file_path;
FuriThread* thread;
FuriEventFlag* events;
LFRFIDWorkerEmulateRawCallback emulate_callback;
LFRFIDWorkerReadRawCallback read_callback;
void* context;
float frequency;
float duty_cycle;
};
typedef enum {
LFRFIDRawWorkerEventStop,
} LFRFIDRawWorkerEvent;
static int32_t lfrfid_raw_read_worker_thread(void* thread_context);
static int32_t lfrfid_raw_emulate_worker_thread(void* thread_context);
LFRFIDRawWorker* lfrfid_raw_worker_alloc() {
LFRFIDRawWorker* worker = malloc(sizeof(LFRFIDRawWorker));
worker->thread = furi_thread_alloc();
furi_thread_set_name(worker->thread, "lfrfid_raw_worker");
furi_thread_set_context(worker->thread, worker);
furi_thread_set_stack_size(worker->thread, 2048);
worker->events = furi_event_flag_alloc(NULL);
string_init(worker->file_path);
return worker;
}
void lfrfid_raw_worker_free(LFRFIDRawWorker* worker) {
furi_thread_free(worker->thread);
furi_event_flag_free(worker->events);
string_clear(worker->file_path);
free(worker);
}
void lfrfid_raw_worker_start_read(
LFRFIDRawWorker* worker,
const char* file_path,
float freq,
float duty_cycle,
LFRFIDWorkerReadRawCallback callback,
void* context) {
furi_check(furi_thread_get_state(worker->thread) == FuriThreadStateStopped);
string_set(worker->file_path, file_path);
worker->frequency = freq;
worker->duty_cycle = duty_cycle;
worker->read_callback = callback;
worker->context = context;
furi_thread_set_callback(worker->thread, lfrfid_raw_read_worker_thread);
furi_thread_start(worker->thread);
}
void lfrfid_raw_worker_start_emulate(
LFRFIDRawWorker* worker,
const char* file_path,
LFRFIDWorkerEmulateRawCallback callback,
void* context) {
furi_check(furi_thread_get_state(worker->thread) == FuriThreadStateStopped);
string_set(worker->file_path, file_path);
worker->emulate_callback = callback;
worker->context = context;
furi_thread_set_callback(worker->thread, lfrfid_raw_emulate_worker_thread);
furi_thread_start(worker->thread);
}
void lfrfid_raw_worker_stop(LFRFIDRawWorker* worker) {
worker->emulate_callback = NULL;
worker->context = NULL;
worker->read_callback = NULL;
worker->context = NULL;
furi_event_flag_set(worker->events, 1 << LFRFIDRawWorkerEventStop);
furi_thread_join(worker->thread);
}
static void lfrfid_raw_worker_capture(bool level, uint32_t duration, void* context) {
LFRFIDRawWorkerReadData* ctx = context;
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
bool need_to_send = varint_pair_pack(ctx->pair, level, duration);
if(need_to_send) {
buffer_stream_send_from_isr(
ctx->stream,
varint_pair_get_data(ctx->pair),
varint_pair_get_size(ctx->pair),
&xHigherPriorityTaskWoken);
varint_pair_reset(ctx->pair);
}
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
static int32_t lfrfid_raw_read_worker_thread(void* thread_context) {
LFRFIDRawWorker* worker = (LFRFIDRawWorker*)thread_context;
Storage* storage = furi_record_open(RECORD_STORAGE);
LFRFIDRawFile* file = lfrfid_raw_file_alloc(storage);
const char* filename = string_get_cstr(worker->file_path);
bool file_valid = lfrfid_raw_file_open_write(file, filename);
LFRFIDRawWorkerReadData* data = malloc(sizeof(LFRFIDRawWorkerReadData));
data->stream = buffer_stream_alloc(RFID_DATA_BUFFER_SIZE, READ_DATA_BUFFER_COUNT);
data->pair = varint_pair_alloc();
if(file_valid) {
// write header
file_valid = lfrfid_raw_file_write_header(
file, worker->frequency, worker->duty_cycle, RFID_DATA_BUFFER_SIZE);
}
if(file_valid) {
// setup carrier
furi_hal_rfid_pins_read();
furi_hal_rfid_tim_read(worker->frequency, worker->duty_cycle);
furi_hal_rfid_tim_read_start();
// stabilize detector
furi_delay_ms(1500);
// start capture
furi_hal_rfid_tim_read_capture_start(lfrfid_raw_worker_capture, data);
while(1) {
Buffer* buffer = buffer_stream_receive(data->stream, 100);
if(buffer != NULL) {
file_valid = lfrfid_raw_file_write_buffer(
file, buffer_get_data(buffer), buffer_get_size(buffer));
buffer_reset(buffer);
}
if(!file_valid) {
if(worker->read_callback != NULL) {
// message file_error to worker
worker->read_callback(LFRFIDWorkerReadRawFileError, worker->context);
}
break;
}
if(buffer_stream_get_overrun_count(data->stream) > 0 &&
worker->read_callback != NULL) {
// message overrun to worker
worker->read_callback(LFRFIDWorkerReadRawOverrun, worker->context);
}
uint32_t flags = furi_event_flag_get(worker->events);
if(FURI_BIT(flags, LFRFIDRawWorkerEventStop)) {
break;
}
}
furi_hal_rfid_tim_read_capture_stop();
furi_hal_rfid_tim_read_stop();
} else {
if(worker->read_callback != NULL) {
// message file_error to worker
worker->read_callback(LFRFIDWorkerReadRawFileError, worker->context);
}
}
if(!file_valid) {
const uint32_t available_flags = (1 << LFRFIDRawWorkerEventStop);
while(true) {
uint32_t flags = furi_event_flag_wait(
worker->events, available_flags, FuriFlagWaitAny, FuriWaitForever);
if(FURI_BIT(flags, LFRFIDRawWorkerEventStop)) {
break;
}
}
}
varint_pair_free(data->pair);
buffer_stream_free(data->stream);
lfrfid_raw_file_free(file);
furi_record_close(RECORD_STORAGE);
free(data);
return 0;
}
static void rfid_emulate_dma_isr(bool half, void* context) {
RfidEmulateCtx* ctx = context;
uint32_t flag = half ? HalfTransfer : TransferComplete;
size_t len = xStreamBufferSendFromISR(ctx->stream, &flag, sizeof(uint32_t), pdFALSE);
if(len != sizeof(uint32_t)) {
ctx->overrun_count++;
}
}
static int32_t lfrfid_raw_emulate_worker_thread(void* thread_context) {
LFRFIDRawWorker* worker = thread_context;
bool file_valid = true;
LFRFIDRawWorkerEmulateData* data = malloc(sizeof(LFRFIDRawWorkerEmulateData));
Storage* storage = furi_record_open(RECORD_STORAGE);
data->ctx.overrun_count = 0;
data->ctx.stream = xStreamBufferCreate(sizeof(uint32_t), sizeof(uint32_t));
LFRFIDRawFile* file = lfrfid_raw_file_alloc(storage);
do {
file_valid = lfrfid_raw_file_open_read(file, string_get_cstr(worker->file_path));
if(!file_valid) break;
file_valid = lfrfid_raw_file_read_header(file, &worker->frequency, &worker->duty_cycle);
if(!file_valid) break;
for(size_t i = 0; i < EMULATE_BUFFER_SIZE; i++) {
file_valid = lfrfid_raw_file_read_pair(
file, &data->emulate_buffer_arr[i], &data->emulate_buffer_ccr[i], NULL);
if(!file_valid) break;
data->emulate_buffer_arr[i] /= 8;
data->emulate_buffer_arr[i] -= 1;
data->emulate_buffer_ccr[i] /= 8;
}
} while(false);
furi_hal_rfid_tim_emulate_dma_start(
data->emulate_buffer_arr,
data->emulate_buffer_ccr,
EMULATE_BUFFER_SIZE,
rfid_emulate_dma_isr,
&data->ctx);
if(!file_valid && worker->emulate_callback != NULL) {
// message file_error to worker
worker->emulate_callback(LFRFIDWorkerEmulateRawFileError, worker->context);
}
if(file_valid) {
uint32_t flag = 0;
while(true) {
size_t size = xStreamBufferReceive(data->ctx.stream, &flag, sizeof(uint32_t), 100);
if(size == sizeof(uint32_t)) {
size_t start = 0;
if(flag == TransferComplete) {
start = (EMULATE_BUFFER_SIZE / 2);
}
for(size_t i = 0; i < (EMULATE_BUFFER_SIZE / 2); i++) {
file_valid = lfrfid_raw_file_read_pair(
file,
&data->emulate_buffer_arr[start + i],
&data->emulate_buffer_ccr[start + i],
NULL);
if(!file_valid) break;
data->emulate_buffer_arr[i] /= 8;
data->emulate_buffer_arr[i] -= 1;
data->emulate_buffer_ccr[i] /= 8;
}
} else if(size != 0) {
data->ctx.overrun_count++;
}
if(!file_valid) {
if(worker->emulate_callback != NULL) {
// message file_error to worker
worker->emulate_callback(LFRFIDWorkerEmulateRawFileError, worker->context);
}
break;
}
if(data->ctx.overrun_count > 0 && worker->emulate_callback != NULL) {
// message overrun to worker
worker->emulate_callback(LFRFIDWorkerEmulateRawOverrun, worker->context);
}
uint32_t flags = furi_event_flag_get(worker->events);
if(FURI_BIT(flags, LFRFIDRawWorkerEventStop)) {
break;
};
}
}
furi_hal_rfid_tim_emulate_dma_stop();
if(!file_valid) {
const uint32_t available_flags = (1 << LFRFIDRawWorkerEventStop);
while(true) {
uint32_t flags = furi_event_flag_wait(
worker->events, available_flags, FuriFlagWaitAny, FuriWaitForever);
if(FURI_BIT(flags, LFRFIDRawWorkerEventStop)) {
break;
};
}
}
if(data->ctx.overrun_count) {
FURI_LOG_E(TAG_EMULATE, "overruns: %lu", data->ctx.overrun_count);
}
vStreamBufferDelete(data->ctx.stream);
lfrfid_raw_file_free(file);
furi_record_close(RECORD_STORAGE);
free(data);
return 0;
}

View File

@@ -0,0 +1,68 @@
#pragma once
#include <furi.h>
#include "lfrfid_worker.h"
#include <toolbox/protocols/protocol_dict.h>
#include "protocols/lfrfid_protocols.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct LFRFIDRawWorker LFRFIDRawWorker;
/**
* @brief Allocate a new LFRFIDRawWorker instance
*
* @return LFRFIDRawWorker*
*/
LFRFIDRawWorker* lfrfid_raw_worker_alloc();
/**
* @brief Free a LFRFIDRawWorker instance
*
* @param worker LFRFIDRawWorker instance
*/
void lfrfid_raw_worker_free(LFRFIDRawWorker* worker);
/**
* @brief Start reading
*
* @param worker LFRFIDRawWorker instance
* @param file_path path where file will be saved
* @param frequency HW frequency
* @param duty_cycle HW duty cycle
* @param callback callback for read event
* @param context context for callback
*/
void lfrfid_raw_worker_start_read(
LFRFIDRawWorker* worker,
const char* file_path,
float frequency,
float duty_cycle,
LFRFIDWorkerReadRawCallback callback,
void* context);
/**
* @brief Start emulate
*
* @param worker LFRFIDRawWorker instance
* @param file_path path to file that will be emulated
* @param callback callback for emulate event
* @param context context for callback
*/
void lfrfid_raw_worker_start_emulate(
LFRFIDRawWorker* worker,
const char* file_path,
LFRFIDWorkerEmulateRawCallback callback,
void* context);
/**
* @brief Stop worker
*
* @param worker
*/
void lfrfid_raw_worker_stop(LFRFIDRawWorker* worker);
#ifdef __cplusplus
}
#endif

169
lib/lfrfid/lfrfid_worker.c Normal file
View File

@@ -0,0 +1,169 @@
#include <furi.h>
#include <furi_hal.h>
#include <atomic.h>
#include "lfrfid_worker_i.h"
typedef enum {
LFRFIDEventStopThread = (1 << 0),
LFRFIDEventStopMode = (1 << 1),
LFRFIDEventRead = (1 << 2),
LFRFIDEventWrite = (1 << 3),
LFRFIDEventEmulate = (1 << 4),
LFRFIDEventReadRaw = (1 << 5),
LFRFIDEventEmulateRaw = (1 << 6),
LFRFIDEventAll =
(LFRFIDEventStopThread | LFRFIDEventStopMode | LFRFIDEventRead | LFRFIDEventWrite |
LFRFIDEventEmulate | LFRFIDEventReadRaw | LFRFIDEventEmulateRaw),
} LFRFIDEventType;
static int32_t lfrfid_worker_thread(void* thread_context);
LFRFIDWorker* lfrfid_worker_alloc(ProtocolDict* dict) {
furi_assert(dict);
LFRFIDWorker* worker = malloc(sizeof(LFRFIDWorker));
worker->mode_index = LFRFIDWorkerIdle;
worker->read_cb = NULL;
worker->write_cb = NULL;
worker->cb_ctx = NULL;
worker->raw_filename = NULL;
worker->mode_storage = NULL;
worker->thread = furi_thread_alloc();
furi_thread_set_name(worker->thread, "lfrfid_worker");
furi_thread_set_callback(worker->thread, lfrfid_worker_thread);
furi_thread_set_context(worker->thread, worker);
furi_thread_set_stack_size(worker->thread, 2048);
worker->protocols = dict;
return worker;
}
void lfrfid_worker_free(LFRFIDWorker* worker) {
if(worker->raw_filename) {
free(worker->raw_filename);
}
furi_thread_free(worker->thread);
free(worker);
}
void lfrfid_worker_read_start(
LFRFIDWorker* worker,
LFRFIDWorkerReadType type,
LFRFIDWorkerReadCallback callback,
void* context) {
furi_assert(worker->mode_index == LFRFIDWorkerIdle);
worker->read_type = type;
worker->read_cb = callback;
worker->cb_ctx = context;
furi_thread_flags_set(furi_thread_get_id(worker->thread), LFRFIDEventRead);
}
void lfrfid_worker_write_start(
LFRFIDWorker* worker,
LFRFIDProtocol protocol,
LFRFIDWorkerWriteCallback callback,
void* context) {
furi_assert(worker->mode_index == LFRFIDWorkerIdle);
worker->protocol = protocol;
worker->write_cb = callback;
worker->cb_ctx = context;
furi_thread_flags_set(furi_thread_get_id(worker->thread), LFRFIDEventWrite);
}
void lfrfid_worker_emulate_start(LFRFIDWorker* worker, LFRFIDProtocol protocol) {
furi_assert(worker->mode_index == LFRFIDWorkerIdle);
worker->protocol = protocol;
furi_thread_flags_set(furi_thread_get_id(worker->thread), LFRFIDEventEmulate);
}
void lfrfid_worker_set_filename(LFRFIDWorker* worker, const char* filename) {
if(worker->raw_filename) {
free(worker->raw_filename);
}
worker->raw_filename = strdup(filename);
}
void lfrfid_worker_read_raw_start(
LFRFIDWorker* worker,
const char* filename,
LFRFIDWorkerReadType type,
LFRFIDWorkerReadRawCallback callback,
void* context) {
furi_assert(worker->mode_index == LFRFIDWorkerIdle);
worker->read_type = type;
worker->read_raw_cb = callback;
worker->cb_ctx = context;
lfrfid_worker_set_filename(worker, filename);
furi_thread_flags_set(furi_thread_get_id(worker->thread), LFRFIDEventReadRaw);
}
void lfrfid_worker_emulate_raw_start(
LFRFIDWorker* worker,
const char* filename,
LFRFIDWorkerEmulateRawCallback callback,
void* context) {
furi_assert(worker->mode_index == LFRFIDWorkerIdle);
lfrfid_worker_set_filename(worker, filename);
worker->emulate_raw_cb = callback;
worker->cb_ctx = context;
furi_thread_flags_set(furi_thread_get_id(worker->thread), LFRFIDEventEmulateRaw);
}
void lfrfid_worker_stop(LFRFIDWorker* worker) {
furi_thread_flags_set(furi_thread_get_id(worker->thread), LFRFIDEventStopMode);
}
void lfrfid_worker_start_thread(LFRFIDWorker* worker) {
furi_thread_start(worker->thread);
}
void lfrfid_worker_stop_thread(LFRFIDWorker* worker) {
furi_assert(worker->mode_index == LFRFIDWorkerIdle);
furi_thread_flags_set(furi_thread_get_id(worker->thread), LFRFIDEventStopThread);
furi_thread_join(worker->thread);
}
bool lfrfid_worker_check_for_stop(LFRFIDWorker* worker) {
UNUSED(worker);
uint32_t flags = furi_thread_flags_get();
return (flags & LFRFIDEventStopMode);
}
size_t lfrfid_worker_dict_get_data_size(LFRFIDWorker* worker, LFRFIDProtocol protocol) {
furi_assert(worker->mode_index == LFRFIDWorkerIdle);
return protocol_dict_get_data_size(worker->protocols, protocol);
}
static int32_t lfrfid_worker_thread(void* thread_context) {
LFRFIDWorker* worker = thread_context;
bool running = true;
while(running) {
uint32_t flags = furi_thread_flags_wait(LFRFIDEventAll, FuriFlagWaitAny, FuriWaitForever);
if(flags != FuriFlagErrorTimeout) {
// stop thread
if(flags & LFRFIDEventStopThread) break;
// switch mode
if(flags & LFRFIDEventRead) worker->mode_index = LFRFIDWorkerRead;
if(flags & LFRFIDEventWrite) worker->mode_index = LFRFIDWorkerWrite;
if(flags & LFRFIDEventEmulate) worker->mode_index = LFRFIDWorkerEmulate;
if(flags & LFRFIDEventReadRaw) worker->mode_index = LFRFIDWorkerReadRaw;
if(flags & LFRFIDEventEmulateRaw) worker->mode_index = LFRFIDWorkerEmulateRaw;
// do mode, if it exists
if(lfrfid_worker_modes[worker->mode_index].process) {
lfrfid_worker_modes[worker->mode_index].process(worker);
}
// reset mode
worker->mode_index = LFRFIDWorkerIdle;
}
}
return 0;
}

152
lib/lfrfid/lfrfid_worker.h Normal file
View File

@@ -0,0 +1,152 @@
/**
* @file lfrfid_worker.h
*
* LFRFID worker
*/
#pragma once
#include <toolbox/protocols/protocol_dict.h>
#include "protocols/lfrfid_protocols.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
LFRFIDWorkerWriteOK,
LFRFIDWorkerWriteProtocolCannotBeWritten,
LFRFIDWorkerWriteFobCannotBeWritten,
LFRFIDWorkerWriteTooLongToWrite,
} LFRFIDWorkerWriteResult;
typedef enum {
LFRFIDWorkerReadTypeAuto,
LFRFIDWorkerReadTypeASKOnly,
LFRFIDWorkerReadTypePSKOnly,
} LFRFIDWorkerReadType;
typedef enum {
LFRFIDWorkerReadSenseStart, // TODO: not implemented
LFRFIDWorkerReadSenseEnd, // TODO: not implemented
LFRFIDWorkerReadSenseCardStart,
LFRFIDWorkerReadSenseCardEnd,
LFRFIDWorkerReadStartASK,
LFRFIDWorkerReadStartPSK,
LFRFIDWorkerReadDone,
} LFRFIDWorkerReadResult;
typedef enum {
LFRFIDWorkerReadRawFileError,
LFRFIDWorkerReadRawOverrun,
} LFRFIDWorkerReadRawResult;
typedef enum {
LFRFIDWorkerEmulateRawFileError,
LFRFIDWorkerEmulateRawOverrun,
} LFRFIDWorkerEmulateRawResult;
typedef void (
*LFRFIDWorkerReadCallback)(LFRFIDWorkerReadResult result, ProtocolId protocol, void* context);
typedef void (*LFRFIDWorkerWriteCallback)(LFRFIDWorkerWriteResult result, void* context);
typedef void (*LFRFIDWorkerReadRawCallback)(LFRFIDWorkerReadRawResult result, void* context);
typedef void (*LFRFIDWorkerEmulateRawCallback)(LFRFIDWorkerEmulateRawResult result, void* context);
typedef struct LFRFIDWorker LFRFIDWorker;
/**
* Allocate LF-RFID worker
* @return LFRFIDWorker*
*/
LFRFIDWorker* lfrfid_worker_alloc(ProtocolDict* dict);
/**
* Free LF-RFID worker
* @param worker
*/
void lfrfid_worker_free(LFRFIDWorker* worker);
/**
* Start LF-RFID worker thread
* @param worker
*/
void lfrfid_worker_start_thread(LFRFIDWorker* worker);
/**
* Stop LF-RFID worker thread
* @param worker
*/
void lfrfid_worker_stop_thread(LFRFIDWorker* worker);
/**
* @brief Start read mode
*
* @param worker
* @param type
* @param callback
* @param context
*/
void lfrfid_worker_read_start(
LFRFIDWorker* worker,
LFRFIDWorkerReadType type,
LFRFIDWorkerReadCallback callback,
void* context);
/**
* @brief Start write mode
*
* @param worker
* @param protocol
* @param callback
* @param context
*/
void lfrfid_worker_write_start(
LFRFIDWorker* worker,
LFRFIDProtocol protocol,
LFRFIDWorkerWriteCallback callback,
void* context);
/**
* Start emulate mode
* @param worker
*/
void lfrfid_worker_emulate_start(LFRFIDWorker* worker, LFRFIDProtocol protocol);
/**
* @brief Start raw read mode
*
* @param worker
* @param filename
* @param type
* @param callback
* @param context
*/
void lfrfid_worker_read_raw_start(
LFRFIDWorker* worker,
const char* filename,
LFRFIDWorkerReadType type,
LFRFIDWorkerReadRawCallback callback,
void* context);
/**
* Emulate raw read mode
* @param worker
* @param filename
* @param callback
* @param context
*/
void lfrfid_worker_emulate_raw_start(
LFRFIDWorker* worker,
const char* filename,
LFRFIDWorkerEmulateRawCallback callback,
void* context);
/**
* Stop all modes
* @param worker
*/
void lfrfid_worker_stop(LFRFIDWorker* worker);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,64 @@
/**
* @file lfrfid_worker_i.h
*
* lfrfid worker, internal definitions
*/
#pragma once
#include <furi.h>
#include "lfrfid_worker.h"
#include "lfrfid_raw_worker.h"
#include "protocols/lfrfid_protocols.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
void (*const process)(LFRFIDWorker* worker);
} LFRFIDWorkerModeType;
typedef enum {
LFRFIDWorkerIdle,
LFRFIDWorkerRead,
LFRFIDWorkerWrite,
LFRFIDWorkerEmulate,
LFRFIDWorkerReadRaw,
LFRFIDWorkerEmulateRaw,
} LFRFIDWorkerMode;
struct LFRFIDWorker {
char* raw_filename;
LFRFIDWorkerMode mode_index;
void* mode_storage;
FuriEventFlag* events;
FuriThread* thread;
LFRFIDWorkerReadType read_type;
LFRFIDWorkerReadCallback read_cb;
LFRFIDWorkerWriteCallback write_cb;
LFRFIDWorkerReadRawCallback read_raw_cb;
LFRFIDWorkerEmulateRawCallback emulate_raw_cb;
void* cb_ctx;
ProtocolDict* protocols;
LFRFIDProtocol protocol;
};
extern const LFRFIDWorkerModeType lfrfid_worker_modes[];
/**
* @brief Check for stop flag
*
* @param worker
* @return bool
*/
bool lfrfid_worker_check_for_stop(LFRFIDWorker* worker);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,624 @@
#include <furi.h>
#include <furi_hal.h>
#include "lfrfid_worker_i.h"
#include "tools/t5577.h"
#include <stream_buffer.h>
#include <toolbox/pulse_protocols/pulse_glue.h>
#include <toolbox/buffer_stream.h>
#include "tools/varint_pair.h"
#include "tools/bit_lib.h"
#define TAG "LFRFIDWorker"
/**
* if READ_DEBUG_GPIO is defined:
* gpio_ext_pa7 will repeat signal coming from the comparator
* gpio_ext_pa6 will show load on the decoder
*/
// #define LFRFID_WORKER_READ_DEBUG_GPIO 1
#ifdef LFRFID_WORKER_READ_DEBUG_GPIO
#define LFRFID_WORKER_READ_DEBUG_GPIO_VALUE &gpio_ext_pa7
#define LFRFID_WORKER_READ_DEBUG_GPIO_LOAD &gpio_ext_pa6
#endif
#define LFRFID_WORKER_READ_AVERAGE_COUNT 64
#define LFRFID_WORKER_READ_MIN_TIME_US 16
#define LFRFID_WORKER_READ_DROP_TIME_MS 50
#define LFRFID_WORKER_READ_STABILIZE_TIME_MS 450
#define LFRFID_WORKER_READ_SWITCH_TIME_MS 1500
#define LFRFID_WORKER_WRITE_VERIFY_TIME_MS 1500
#define LFRFID_WORKER_WRITE_DROP_TIME_MS 50
#define LFRFID_WORKER_WRITE_TOO_LONG_TIME_MS 10000
#define LFRFID_WORKER_WRITE_MAX_UNSUCCESSFUL_READS 5
#define LFRFID_WORKER_READ_BUFFER_SIZE 512
#define LFRFID_WORKER_READ_BUFFER_COUNT 8
#define LFRFID_WORKER_EMULATE_BUFFER_SIZE 1024
#define LFRFID_WORKER_DELAY_QUANT 50
void lfrfid_worker_delay(LFRFIDWorker* worker, uint32_t milliseconds) {
for(uint32_t i = 0; i < (milliseconds / LFRFID_WORKER_DELAY_QUANT); i++) {
if(lfrfid_worker_check_for_stop(worker)) break;
furi_delay_ms(LFRFID_WORKER_DELAY_QUANT);
}
}
/**************************************************************************************************/
/********************************************** READ **********************************************/
/**************************************************************************************************/
typedef struct {
BufferStream* stream;
VarintPair* pair;
bool ignore_next_pulse;
} LFRFIDWorkerReadContext;
static void lfrfid_worker_read_capture(bool level, uint32_t duration, void* context) {
LFRFIDWorkerReadContext* ctx = context;
// ignore pulse if last pulse was noise
if(ctx->ignore_next_pulse) {
ctx->ignore_next_pulse = false;
return;
}
// ignore noise spikes
if(duration <= LFRFID_WORKER_READ_MIN_TIME_US) {
if(level) {
ctx->ignore_next_pulse = true;
}
varint_pair_reset(ctx->pair);
return;
}
#ifdef LFRFID_WORKER_READ_DEBUG_GPIO
furi_hal_gpio_write(LFRFID_WORKER_READ_DEBUG_GPIO_VALUE, level);
#endif
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
bool need_to_send = varint_pair_pack(ctx->pair, level, duration);
if(need_to_send) {
buffer_stream_send_from_isr(
ctx->stream,
varint_pair_get_data(ctx->pair),
varint_pair_get_size(ctx->pair),
&xHigherPriorityTaskWoken);
varint_pair_reset(ctx->pair);
}
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
typedef enum {
LFRFIDWorkerReadOK,
LFRFIDWorkerReadExit,
LFRFIDWorkerReadTimeout,
} LFRFIDWorkerReadState;
static LFRFIDWorkerReadState lfrfid_worker_read_internal(
LFRFIDWorker* worker,
LFRFIDFeature feature,
uint32_t timeout,
ProtocolId* result_protocol) {
LFRFIDWorkerReadState state = LFRFIDWorkerReadTimeout;
furi_hal_rfid_pins_read();
if(feature & LFRFIDFeatureASK) {
furi_hal_rfid_tim_read(125000, 0.5);
FURI_LOG_D(TAG, "Start ASK");
if(worker->read_cb) {
worker->read_cb(LFRFIDWorkerReadStartASK, PROTOCOL_NO, worker->cb_ctx);
}
} else {
furi_hal_rfid_tim_read(62500, 0.25);
FURI_LOG_D(TAG, "Start PSK");
if(worker->read_cb) {
worker->read_cb(LFRFIDWorkerReadStartPSK, PROTOCOL_NO, worker->cb_ctx);
}
}
furi_hal_rfid_tim_read_start();
// stabilize detector
lfrfid_worker_delay(worker, LFRFID_WORKER_READ_STABILIZE_TIME_MS);
protocol_dict_decoders_start(worker->protocols);
#ifdef LFRFID_WORKER_READ_DEBUG_GPIO
furi_hal_gpio_init_simple(LFRFID_WORKER_READ_DEBUG_GPIO_VALUE, GpioModeOutputPushPull);
furi_hal_gpio_init_simple(LFRFID_WORKER_READ_DEBUG_GPIO_LOAD, GpioModeOutputPushPull);
#endif
LFRFIDWorkerReadContext ctx;
ctx.pair = varint_pair_alloc();
ctx.stream =
buffer_stream_alloc(LFRFID_WORKER_READ_BUFFER_SIZE, LFRFID_WORKER_READ_BUFFER_COUNT);
furi_hal_rfid_tim_read_capture_start(lfrfid_worker_read_capture, &ctx);
*result_protocol = PROTOCOL_NO;
ProtocolId last_protocol = PROTOCOL_NO;
size_t last_size = protocol_dict_get_max_data_size(worker->protocols);
uint8_t* last_data = malloc(last_size);
uint8_t* protocol_data = malloc(last_size);
size_t last_read_count = 0;
uint32_t switch_os_tick_last = furi_get_tick();
uint32_t average_duration = 0;
uint32_t average_pulse = 0;
size_t average_index = 0;
bool card_detected = false;
FURI_LOG_D(TAG, "Read started");
while(true) {
if(lfrfid_worker_check_for_stop(worker)) {
state = LFRFIDWorkerReadExit;
break;
}
Buffer* buffer = buffer_stream_receive(ctx.stream, 100);
#ifdef LFRFID_WORKER_READ_DEBUG_GPIO
furi_hal_gpio_write(LFRFID_WORKER_READ_DEBUG_GPIO_LOAD, true);
#endif
if(buffer_stream_get_overrun_count(ctx.stream) > 0) {
FURI_LOG_E(TAG, "Read overrun, recovering");
buffer_stream_reset(ctx.stream);
continue;
}
if(buffer == NULL) {
continue;
}
size_t size = buffer_get_size(buffer);
uint8_t* data = buffer_get_data(buffer);
size_t index = 0;
while(index < size) {
uint32_t duration;
uint32_t pulse;
size_t tmp_size;
if(!varint_pair_unpack(&data[index], size - index, &pulse, &duration, &tmp_size)) {
FURI_LOG_E(TAG, "can't unpack varint pair");
break;
} else {
index += tmp_size;
average_duration += duration;
average_pulse += pulse;
average_index++;
if(average_index >= LFRFID_WORKER_READ_AVERAGE_COUNT) {
float average = (float)average_pulse / (float)average_duration;
average_pulse = 0;
average_duration = 0;
average_index = 0;
if(worker->read_cb) {
if(average > 0.2 && average < 0.8) {
if(!card_detected) {
card_detected = true;
worker->read_cb(
LFRFIDWorkerReadSenseStart, PROTOCOL_NO, worker->cb_ctx);
}
} else {
if(card_detected) {
card_detected = false;
worker->read_cb(
LFRFIDWorkerReadSenseEnd, PROTOCOL_NO, worker->cb_ctx);
}
}
}
}
ProtocolId protocol = PROTOCOL_NO;
protocol = protocol_dict_decoders_feed_by_feature(
worker->protocols, feature, true, pulse);
if(protocol == PROTOCOL_NO) {
protocol = protocol_dict_decoders_feed_by_feature(
worker->protocols, feature, false, duration - pulse);
}
if(protocol != PROTOCOL_NO) {
// reset switch timer
switch_os_tick_last = furi_get_tick();
size_t protocol_data_size =
protocol_dict_get_data_size(worker->protocols, protocol);
protocol_dict_get_data(
worker->protocols, protocol, protocol_data, protocol_data_size);
// validate protocol
if(protocol == last_protocol &&
memcmp(last_data, protocol_data, protocol_data_size) == 0) {
last_read_count = last_read_count + 1;
size_t validation_count =
protocol_dict_get_validate_count(worker->protocols, protocol);
if(last_read_count >= validation_count) {
state = LFRFIDWorkerReadOK;
*result_protocol = protocol;
break;
}
} else {
if(last_protocol == PROTOCOL_NO && worker->read_cb) {
worker->read_cb(
LFRFIDWorkerReadSenseCardStart, protocol, worker->cb_ctx);
}
last_protocol = protocol;
memcpy(last_data, protocol_data, protocol_data_size);
last_read_count = 0;
}
string_t string_info;
string_init(string_info);
for(uint8_t i = 0; i < protocol_data_size; i++) {
if(i != 0) {
string_cat_printf(string_info, " ");
}
string_cat_printf(string_info, "%02X", protocol_data[i]);
}
FURI_LOG_D(
TAG,
"%s, %d, [%s]",
protocol_dict_get_name(worker->protocols, protocol),
last_read_count,
string_get_cstr(string_info));
string_clear(string_info);
protocol_dict_decoders_start(worker->protocols);
}
}
}
buffer_reset(buffer);
#ifdef LFRFID_WORKER_READ_DEBUG_GPIO
furi_hal_gpio_write(LFRFID_WORKER_READ_DEBUG_GPIO_LOAD, false);
#endif
if(*result_protocol != PROTOCOL_NO) {
break;
}
if((furi_get_tick() - switch_os_tick_last) > timeout) {
state = LFRFIDWorkerReadTimeout;
break;
}
}
FURI_LOG_D(TAG, "Read stopped");
if(last_protocol != PROTOCOL_NO && worker->read_cb) {
worker->read_cb(LFRFIDWorkerReadSenseCardEnd, last_protocol, worker->cb_ctx);
}
if(card_detected && worker->read_cb) {
worker->read_cb(LFRFIDWorkerReadSenseEnd, last_protocol, worker->cb_ctx);
}
furi_hal_rfid_tim_read_capture_stop();
furi_hal_rfid_tim_read_stop();
furi_hal_rfid_pins_reset();
varint_pair_free(ctx.pair);
buffer_stream_free(ctx.stream);
free(protocol_data);
free(last_data);
#ifdef LFRFID_WORKER_READ_DEBUG_GPIO
furi_hal_gpio_init_simple(LFRFID_WORKER_READ_DEBUG_GPIO_VALUE, GpioModeAnalog);
furi_hal_gpio_init_simple(LFRFID_WORKER_READ_DEBUG_GPIO_LOAD, GpioModeAnalog);
#endif
return state;
}
static void lfrfid_worker_mode_read_process(LFRFIDWorker* worker) {
LFRFIDFeature feature = LFRFIDFeatureASK;
ProtocolId read_result = PROTOCOL_NO;
LFRFIDWorkerReadState state;
if(worker->read_type == LFRFIDWorkerReadTypePSKOnly) {
feature = LFRFIDFeaturePSK;
} else {
feature = LFRFIDFeatureASK;
}
if(worker->read_type == LFRFIDWorkerReadTypeAuto) {
while(1) {
// read for a while
state = lfrfid_worker_read_internal(
worker, feature, LFRFID_WORKER_READ_SWITCH_TIME_MS, &read_result);
if(state == LFRFIDWorkerReadOK || state == LFRFIDWorkerReadExit) {
break;
}
// switch to next feature
if(feature == LFRFIDFeatureASK) {
feature = LFRFIDFeaturePSK;
} else {
feature = LFRFIDFeatureASK;
}
lfrfid_worker_delay(worker, LFRFID_WORKER_READ_DROP_TIME_MS);
}
} else {
while(1) {
if(worker->read_type == LFRFIDWorkerReadTypeASKOnly) {
state = lfrfid_worker_read_internal(worker, feature, UINT32_MAX, &read_result);
} else {
state = lfrfid_worker_read_internal(
worker, feature, LFRFID_WORKER_READ_SWITCH_TIME_MS, &read_result);
}
if(state == LFRFIDWorkerReadOK || state == LFRFIDWorkerReadExit) {
break;
}
lfrfid_worker_delay(worker, LFRFID_WORKER_READ_DROP_TIME_MS);
}
}
if(state == LFRFIDWorkerReadOK && worker->read_cb) {
worker->read_cb(LFRFIDWorkerReadDone, read_result, worker->cb_ctx);
}
}
/**************************************************************************************************/
/******************************************** EMULATE *********************************************/
/**************************************************************************************************/
typedef struct {
uint32_t duration[LFRFID_WORKER_EMULATE_BUFFER_SIZE];
uint32_t pulse[LFRFID_WORKER_EMULATE_BUFFER_SIZE];
} LFRFIDWorkerEmulateBuffer;
typedef enum {
HalfTransfer,
TransferComplete,
} LFRFIDWorkerEmulateDMAEvent;
static void lfrfid_worker_emulate_dma_isr(bool half, void* context) {
StreamBufferHandle_t stream = context;
uint32_t flag = half ? HalfTransfer : TransferComplete;
xStreamBufferSendFromISR(stream, &flag, sizeof(uint32_t), pdFALSE);
}
static void lfrfid_worker_mode_emulate_process(LFRFIDWorker* worker) {
LFRFIDWorkerEmulateBuffer* buffer = malloc(sizeof(LFRFIDWorkerEmulateBuffer));
StreamBufferHandle_t stream = xStreamBufferCreate(sizeof(uint32_t), sizeof(uint32_t));
LFRFIDProtocol protocol = worker->protocol;
PulseGlue* pulse_glue = pulse_glue_alloc();
protocol_dict_encoder_start(worker->protocols, protocol);
for(size_t i = 0; i < LFRFID_WORKER_EMULATE_BUFFER_SIZE; i++) {
bool pulse_pop = false;
while(!pulse_pop) {
LevelDuration level_duration =
protocol_dict_encoder_yield(worker->protocols, protocol);
pulse_pop = pulse_glue_push(
pulse_glue,
level_duration_get_level(level_duration),
level_duration_get_duration(level_duration));
}
uint32_t duration, pulse;
pulse_glue_pop(pulse_glue, &duration, &pulse);
buffer->duration[i] = duration - 1;
buffer->pulse[i] = pulse;
}
#ifdef LFRFID_WORKER_READ_DEBUG_GPIO
furi_hal_gpio_init_simple(LFRFID_WORKER_READ_DEBUG_GPIO_LOAD, GpioModeOutputPushPull);
#endif
furi_hal_rfid_tim_emulate_dma_start(
buffer->duration,
buffer->pulse,
LFRFID_WORKER_EMULATE_BUFFER_SIZE,
lfrfid_worker_emulate_dma_isr,
stream);
while(true) {
uint32_t flag = 0;
size_t size = xStreamBufferReceive(stream, &flag, sizeof(uint32_t), 100);
#ifdef LFRFID_WORKER_READ_DEBUG_GPIO
furi_hal_gpio_write(LFRFID_WORKER_READ_DEBUG_GPIO_LOAD, true);
#endif
if(size == sizeof(uint32_t)) {
size_t start = 0;
if(flag == HalfTransfer) {
start = 0;
} else if(flag == TransferComplete) {
start = (LFRFID_WORKER_EMULATE_BUFFER_SIZE / 2);
}
for(size_t i = 0; i < (LFRFID_WORKER_EMULATE_BUFFER_SIZE / 2); i++) {
bool pulse_pop = false;
while(!pulse_pop) {
LevelDuration level_duration =
protocol_dict_encoder_yield(worker->protocols, protocol);
pulse_pop = pulse_glue_push(
pulse_glue,
level_duration_get_level(level_duration),
level_duration_get_duration(level_duration));
}
uint32_t duration, pulse;
pulse_glue_pop(pulse_glue, &duration, &pulse);
buffer->duration[start + i] = duration - 1;
buffer->pulse[start + i] = pulse;
}
}
if(lfrfid_worker_check_for_stop(worker)) {
break;
}
#ifdef LFRFID_WORKER_READ_DEBUG_GPIO
furi_hal_gpio_write(LFRFID_WORKER_READ_DEBUG_GPIO_LOAD, false);
#endif
}
furi_hal_rfid_tim_emulate_dma_stop();
#ifdef LFRFID_WORKER_READ_DEBUG_GPIO
furi_hal_gpio_init_simple(LFRFID_WORKER_READ_DEBUG_GPIO_LOAD, GpioModeAnalog);
#endif
free(buffer);
vStreamBufferDelete(stream);
pulse_glue_free(pulse_glue);
}
/**************************************************************************************************/
/********************************************* WRITE **********************************************/
/**************************************************************************************************/
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;
size_t unsuccessful_reads = 0;
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);
if(state == LFRFIDWorkerReadOK) {
protocol_dict_get_data(worker->protocols, protocol, read_data, data_size);
if(memcmp(read_data, verify_data, data_size) == 0) {
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;
}
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);
}
}
free(request);
free(verify_data);
free(read_data);
}
/**************************************************************************************************/
/******************************************* READ RAW *********************************************/
/**************************************************************************************************/
static void lfrfid_worker_mode_read_raw_process(LFRFIDWorker* worker) {
LFRFIDRawWorker* raw_worker = lfrfid_raw_worker_alloc();
switch(worker->read_type) {
case LFRFIDWorkerReadTypePSKOnly:
lfrfid_raw_worker_start_read(
raw_worker, worker->raw_filename, 62500, 0.25, worker->read_raw_cb, worker->cb_ctx);
break;
case LFRFIDWorkerReadTypeASKOnly:
lfrfid_raw_worker_start_read(
raw_worker, worker->raw_filename, 125000, 0.5, worker->read_raw_cb, worker->cb_ctx);
break;
default:
furi_crash("RAW can be only PSK or ASK");
break;
}
while(!lfrfid_worker_check_for_stop(worker)) {
furi_delay_ms(100);
}
lfrfid_raw_worker_stop(raw_worker);
lfrfid_raw_worker_free(raw_worker);
}
/**************************************************************************************************/
/***************************************** EMULATE RAW ********************************************/
/**************************************************************************************************/
static void lfrfid_worker_mode_emulate_raw_process(LFRFIDWorker* worker) {
LFRFIDRawWorker* raw_worker = lfrfid_raw_worker_alloc();
lfrfid_raw_worker_start_emulate(
raw_worker, worker->raw_filename, worker->emulate_raw_cb, worker->cb_ctx);
while(!lfrfid_worker_check_for_stop(worker)) {
furi_delay_ms(100);
}
lfrfid_raw_worker_stop(raw_worker);
lfrfid_raw_worker_free(raw_worker);
}
/**************************************************************************************************/
/******************************************** MODES ***********************************************/
/**************************************************************************************************/
const LFRFIDWorkerModeType lfrfid_worker_modes[] = {
[LFRFIDWorkerIdle] = {.process = NULL},
[LFRFIDWorkerRead] = {.process = lfrfid_worker_mode_read_process},
[LFRFIDWorkerWrite] = {.process = lfrfid_worker_mode_write_process},
[LFRFIDWorkerEmulate] = {.process = lfrfid_worker_mode_emulate_process},
[LFRFIDWorkerReadRaw] = {.process = lfrfid_worker_mode_read_raw_process},
[LFRFIDWorkerEmulateRaw] = {.process = lfrfid_worker_mode_emulate_raw_process},
};

View File

@@ -0,0 +1,22 @@
#include "lfrfid_protocols.h"
#include "protocol_em4100.h"
#include "protocol_h10301.h"
#include "protocol_indala26.h"
#include "protocol_io_prox_xsf.h"
#include "protocol_awid.h"
#include "protocol_fdx_a.h"
#include "protocol_fdx_b.h"
#include "protocol_hid_generic.h"
#include "protocol_hid_ex_generic.h"
const ProtocolBase* lfrfid_protocols[] = {
[LFRFIDProtocolEM4100] = &protocol_em4100,
[LFRFIDProtocolH10301] = &protocol_h10301,
[LFRFIDProtocolIndala26] = &protocol_indala26,
[LFRFIDProtocolIOProxXSF] = &protocol_io_prox_xsf,
[LFRFIDProtocolAwid] = &protocol_awid,
[LFRFIDProtocolFDXA] = &protocol_fdx_a,
[LFRFIDProtocolFDXB] = &protocol_fdx_b,
[LFRFIDProtocolHidGeneric] = &protocol_hid_generic,
[LFRFIDProtocolHidExGeneric] = &protocol_hid_ex_generic,
};

View File

@@ -0,0 +1,35 @@
#pragma once
#include <toolbox/protocols/protocol.h>
#include "../tools/t5577.h"
typedef enum {
LFRFIDFeatureASK = 1 << 0, /** ASK Demodulation */
LFRFIDFeaturePSK = 1 << 1, /** PSK Demodulation */
} LFRFIDFeature;
typedef enum {
LFRFIDProtocolEM4100,
LFRFIDProtocolH10301,
LFRFIDProtocolIndala26,
LFRFIDProtocolIOProxXSF,
LFRFIDProtocolAwid,
LFRFIDProtocolFDXA,
LFRFIDProtocolFDXB,
LFRFIDProtocolHidGeneric,
LFRFIDProtocolHidExGeneric,
LFRFIDProtocolMax,
} LFRFIDProtocol;
extern const ProtocolBase* lfrfid_protocols[];
typedef enum {
LFRFIDWriteTypeT5577,
} LFRFIDWriteType;
typedef struct {
LFRFIDWriteType write_type;
union {
LFRFIDT5577 t5577;
};
} LFRFIDWriteRequest;

View File

@@ -0,0 +1,239 @@
#include <furi.h>
#include <toolbox/protocols/protocol.h>
#include <lfrfid/tools/fsk_demod.h>
#include <lfrfid/tools/fsk_osc.h>
#include <lfrfid/tools/bit_lib.h>
#include "lfrfid_protocols.h"
#define JITTER_TIME (20)
#define MIN_TIME (64 - JITTER_TIME)
#define MAX_TIME (80 + JITTER_TIME)
#define AWID_DECODED_DATA_SIZE (9)
#define AWID_ENCODED_BIT_SIZE (96)
#define AWID_ENCODED_DATA_SIZE (((AWID_ENCODED_BIT_SIZE) / 8) + 1)
#define AWID_ENCODED_DATA_LAST (AWID_ENCODED_DATA_SIZE - 1)
typedef struct {
FSKDemod* fsk_demod;
} ProtocolAwidDecoder;
typedef struct {
FSKOsc* fsk_osc;
uint8_t encoded_index;
} ProtocolAwidEncoder;
typedef struct {
ProtocolAwidDecoder decoder;
ProtocolAwidEncoder encoder;
uint8_t encoded_data[AWID_ENCODED_DATA_SIZE];
uint8_t data[AWID_DECODED_DATA_SIZE];
} ProtocolAwid;
ProtocolAwid* protocol_awid_alloc(void) {
ProtocolAwid* protocol = malloc(sizeof(ProtocolAwid));
protocol->decoder.fsk_demod = fsk_demod_alloc(MIN_TIME, 6, MAX_TIME, 5);
protocol->encoder.fsk_osc = fsk_osc_alloc(8, 10, 50);
return protocol;
};
void protocol_awid_free(ProtocolAwid* protocol) {
fsk_demod_free(protocol->decoder.fsk_demod);
fsk_osc_free(protocol->encoder.fsk_osc);
free(protocol);
};
uint8_t* protocol_awid_get_data(ProtocolAwid* protocol) {
return protocol->data;
};
void protocol_awid_decoder_start(ProtocolAwid* protocol) {
memset(protocol->encoded_data, 0, AWID_ENCODED_DATA_SIZE);
};
static bool protocol_awid_can_be_decoded(const uint8_t* data) {
bool result = false;
// Index map
// 0 10 20 30 40 50 60
// | | | | | | |
// 01234567 890 1 234 5 678 9 012 3 456 7 890 1 234 5 678 9 012 3 456 7 890 1 234 5 678 9 012 3 - to 96
// -----------------------------------------------------------------------------
// 00000001 000 1 110 1 101 1 011 1 101 1 010 0 000 1 000 1 010 0 001 0 110 1 100 0 000 1 000 1
// preamble bbb o bbb o bbw o fff o fff o ffc o ccc o ccc o ccc o ccc o ccc o wxx o xxx o xxx o - to 96
// |---26 bit---| |-----117----||-------------142-------------|
// b = format bit len, o = odd parity of last 3 bits
// f = facility code, c = card number
// w = wiegand parity
// (26 bit format shown)
do {
// check preamble and spacing
if(data[0] != 0b00000001 || data[AWID_ENCODED_DATA_LAST] != 0b00000001) break;
// check odd parity for every 4 bits starting from the second byte
bool parity_error = bit_lib_test_parity(data, 8, 88, BitLibParityOdd, 4);
if(parity_error) break;
result = true;
} while(false);
return result;
}
static void protocol_awid_decode(uint8_t* encoded_data, uint8_t* decoded_data) {
bit_lib_remove_bit_every_nth(encoded_data, 8, 88, 4);
bit_lib_copy_bits(decoded_data, 0, 66, encoded_data, 8);
}
bool protocol_awid_decoder_feed(ProtocolAwid* protocol, bool level, uint32_t duration) {
bool value;
uint32_t count;
bool result = false;
fsk_demod_feed(protocol->decoder.fsk_demod, level, duration, &value, &count);
if(count > 0) {
for(size_t i = 0; i < count; i++) {
bit_lib_push_bit(protocol->encoded_data, AWID_ENCODED_DATA_SIZE, value);
if(protocol_awid_can_be_decoded(protocol->encoded_data)) {
protocol_awid_decode(protocol->encoded_data, protocol->data);
result = true;
break;
}
}
}
return result;
};
static void protocol_awid_encode(const uint8_t* decoded_data, uint8_t* encoded_data) {
memset(encoded_data, 0, AWID_ENCODED_DATA_SIZE);
// preamble
bit_lib_set_bits(encoded_data, 0, 0b00000001, 8);
for(size_t i = 0; i < 88 / 4; i++) {
uint8_t value = bit_lib_get_bits(decoded_data, i * 3, 3) << 1;
value |= bit_lib_test_parity_32(value, BitLibParityOdd);
bit_lib_set_bits(encoded_data, 8 + i * 4, value, 4);
}
};
bool protocol_awid_encoder_start(ProtocolAwid* protocol) {
protocol_awid_encode(protocol->data, (uint8_t*)protocol->encoded_data);
protocol->encoder.encoded_index = 0;
fsk_osc_reset(protocol->encoder.fsk_osc);
return true;
};
LevelDuration protocol_awid_encoder_yield(ProtocolAwid* protocol) {
bool level;
uint32_t duration;
bool bit = bit_lib_get_bit(protocol->encoded_data, protocol->encoder.encoded_index);
bool advance = fsk_osc_next_half(protocol->encoder.fsk_osc, bit, &level, &duration);
if(advance) {
bit_lib_increment_index(protocol->encoder.encoded_index, AWID_ENCODED_BIT_SIZE);
}
return level_duration_make(level, duration);
};
void protocol_awid_render_data(ProtocolAwid* protocol, string_t result) {
// Index map
// 0 10 20 30 40 50 60
// | | | | | | |
// 01234567 8 90123456 7890123456789012 3 456789012345678901234567890123456
// ------------------------------------------------------------------------
// 00011010 1 01110101 0000000010001110 1 000000000000000000000000000000000
// bbbbbbbb w ffffffff cccccccccccccccc w xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// |26 bit| |-117--| |-----142------|
// b = format bit len, o = odd parity of last 3 bits
// f = facility code, c = card number
// w = wiegand parity
// (26 bit format shown)
uint8_t* decoded_data = protocol->data;
uint8_t format_length = decoded_data[0];
string_cat_printf(result, "Format: %d\r\n", format_length);
if(format_length == 26) {
uint8_t facility;
bit_lib_copy_bits(&facility, 0, 8, decoded_data, 9);
uint16_t card_id;
bit_lib_copy_bits((uint8_t*)&card_id, 8, 8, decoded_data, 17);
bit_lib_copy_bits((uint8_t*)&card_id, 0, 8, decoded_data, 25);
string_cat_printf(result, "Facility: %d\r\n", facility);
string_cat_printf(result, "Card: %d", card_id);
} else {
// print 66 bits as hex
string_cat_printf(result, "Data: ");
for(size_t i = 0; i < AWID_DECODED_DATA_SIZE; i++) {
string_cat_printf(result, "%02X", decoded_data[i]);
}
}
};
void protocol_awid_render_brief_data(ProtocolAwid* protocol, string_t result) {
uint8_t* decoded_data = protocol->data;
uint8_t format_length = decoded_data[0];
string_cat_printf(result, "Format: %d\r\n", format_length);
if(format_length == 26) {
uint8_t facility;
bit_lib_copy_bits(&facility, 0, 8, decoded_data, 9);
uint16_t card_id;
bit_lib_copy_bits((uint8_t*)&card_id, 8, 8, decoded_data, 17);
bit_lib_copy_bits((uint8_t*)&card_id, 0, 8, decoded_data, 25);
string_cat_printf(result, "ID: %03u,%05u", facility, card_id);
} else {
string_cat_printf(result, "Data: unknown");
}
};
bool protocol_awid_write_data(ProtocolAwid* protocol, void* data) {
LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data;
bool result = false;
protocol_awid_encode(protocol->data, (uint8_t*)protocol->encoded_data);
if(request->write_type == LFRFIDWriteTypeT5577) {
request->t5577.block[0] = LFRFID_T5577_MODULATION_FSK2a | LFRFID_T5577_BITRATE_RF_50 |
(3 << LFRFID_T5577_MAXBLOCK_SHIFT);
request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32);
request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32);
request->t5577.block[3] = bit_lib_get_bits_32(protocol->encoded_data, 64, 32);
request->t5577.blocks_to_write = 4;
result = true;
}
return result;
};
const ProtocolBase protocol_awid = {
.name = "AWID",
.manufacturer = "AWIG",
.data_size = AWID_DECODED_DATA_SIZE,
.features = LFRFIDFeatureASK,
.validate_count = 3,
.alloc = (ProtocolAlloc)protocol_awid_alloc,
.free = (ProtocolFree)protocol_awid_free,
.get_data = (ProtocolGetData)protocol_awid_get_data,
.decoder =
{
.start = (ProtocolDecoderStart)protocol_awid_decoder_start,
.feed = (ProtocolDecoderFeed)protocol_awid_decoder_feed,
},
.encoder =
{
.start = (ProtocolEncoderStart)protocol_awid_encoder_start,
.yield = (ProtocolEncoderYield)protocol_awid_encoder_yield,
},
.render_data = (ProtocolRenderData)protocol_awid_render_data,
.render_brief_data = (ProtocolRenderData)protocol_awid_render_brief_data,
.write_data = (ProtocolWriteData)protocol_awid_write_data,
};

View File

@@ -0,0 +1,4 @@
#pragma once
#include <toolbox/protocols/protocol.h>
extern const ProtocolBase protocol_awid;

View File

@@ -0,0 +1,292 @@
#include <furi.h>
#include <toolbox/protocols/protocol.h>
#include <toolbox/manchester_decoder.h>
#include "lfrfid_protocols.h"
typedef uint64_t EM4100DecodedData;
#define EM_HEADER_POS (55)
#define EM_HEADER_MASK (0x1FFLLU << EM_HEADER_POS)
#define EM_FIRST_ROW_POS (50)
#define EM_ROW_COUNT (10)
#define EM_COLUMN_COUNT (4)
#define EM_BITS_PER_ROW_COUNT (EM_COLUMN_COUNT + 1)
#define EM_COLUMN_POS (4)
#define EM_STOP_POS (0)
#define EM_STOP_MASK (0x1LLU << EM_STOP_POS)
#define EM_HEADER_AND_STOP_MASK (EM_HEADER_MASK | EM_STOP_MASK)
#define EM_HEADER_AND_STOP_DATA (EM_HEADER_MASK)
#define EM4100_DECODED_DATA_SIZE (5)
#define EM4100_ENCODED_DATA_SIZE (sizeof(EM4100DecodedData))
#define EM4100_CLOCK_PER_BIT (64)
#define EM_READ_SHORT_TIME (256)
#define EM_READ_LONG_TIME (512)
#define EM_READ_JITTER_TIME (100)
#define EM_READ_SHORT_TIME_LOW (EM_READ_SHORT_TIME - EM_READ_JITTER_TIME)
#define EM_READ_SHORT_TIME_HIGH (EM_READ_SHORT_TIME + EM_READ_JITTER_TIME)
#define EM_READ_LONG_TIME_LOW (EM_READ_LONG_TIME - EM_READ_JITTER_TIME)
#define EM_READ_LONG_TIME_HIGH (EM_READ_LONG_TIME + EM_READ_JITTER_TIME)
typedef struct {
uint8_t data[EM4100_DECODED_DATA_SIZE];
EM4100DecodedData encoded_data;
uint8_t encoded_data_index;
bool encoded_polarity;
ManchesterState decoder_manchester_state;
} ProtocolEM4100;
ProtocolEM4100* protocol_em4100_alloc(void) {
ProtocolEM4100* proto = malloc(sizeof(ProtocolEM4100));
return (void*)proto;
};
void protocol_em4100_free(ProtocolEM4100* proto) {
free(proto);
};
uint8_t* protocol_em4100_get_data(ProtocolEM4100* proto) {
return proto->data;
};
static void em4100_decode(
const uint8_t* encoded_data,
const uint8_t encoded_data_size,
uint8_t* decoded_data,
const uint8_t decoded_data_size) {
furi_check(decoded_data_size >= EM4100_DECODED_DATA_SIZE);
furi_check(encoded_data_size >= EM4100_ENCODED_DATA_SIZE);
uint8_t decoded_data_index = 0;
EM4100DecodedData card_data = *((EM4100DecodedData*)(encoded_data));
// clean result
memset(decoded_data, 0, decoded_data_size);
// header
for(uint8_t i = 0; i < 9; i++) {
card_data = card_data << 1;
}
// nibbles
uint8_t value = 0;
for(uint8_t r = 0; r < EM_ROW_COUNT; r++) {
uint8_t nibble = 0;
for(uint8_t i = 0; i < 5; i++) {
if(i < 4) nibble = (nibble << 1) | (card_data & (1LLU << 63) ? 1 : 0);
card_data = card_data << 1;
}
value = (value << 4) | nibble;
if(r % 2) {
decoded_data[decoded_data_index] |= value;
decoded_data_index++;
value = 0;
}
}
}
static bool em4100_can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) {
furi_check(encoded_data_size >= EM4100_ENCODED_DATA_SIZE);
const EM4100DecodedData* card_data = (EM4100DecodedData*)encoded_data;
// check header and stop bit
if((*card_data & EM_HEADER_AND_STOP_MASK) != EM_HEADER_AND_STOP_DATA) return false;
// check row parity
for(uint8_t i = 0; i < EM_ROW_COUNT; i++) {
uint8_t parity_sum = 0;
for(uint8_t j = 0; j < EM_BITS_PER_ROW_COUNT; j++) {
parity_sum += (*card_data >> (EM_FIRST_ROW_POS - i * EM_BITS_PER_ROW_COUNT + j)) & 1;
}
if((parity_sum % 2)) {
return false;
}
}
// check columns parity
for(uint8_t i = 0; i < EM_COLUMN_COUNT; i++) {
uint8_t parity_sum = 0;
for(uint8_t j = 0; j < EM_ROW_COUNT + 1; j++) {
parity_sum += (*card_data >> (EM_COLUMN_POS - i + j * EM_BITS_PER_ROW_COUNT)) & 1;
}
if((parity_sum % 2)) {
return false;
}
}
return true;
}
void protocol_em4100_decoder_start(ProtocolEM4100* proto) {
memset(proto->data, 0, EM4100_DECODED_DATA_SIZE);
proto->encoded_data = 0;
manchester_advance(
proto->decoder_manchester_state,
ManchesterEventReset,
&proto->decoder_manchester_state,
NULL);
};
bool protocol_em4100_decoder_feed(ProtocolEM4100* proto, bool level, uint32_t duration) {
bool result = false;
ManchesterEvent event = ManchesterEventReset;
if(duration > EM_READ_SHORT_TIME_LOW && duration < EM_READ_SHORT_TIME_HIGH) {
if(!level) {
event = ManchesterEventShortHigh;
} else {
event = ManchesterEventShortLow;
}
} else if(duration > EM_READ_LONG_TIME_LOW && duration < EM_READ_LONG_TIME_HIGH) {
if(!level) {
event = ManchesterEventLongHigh;
} else {
event = ManchesterEventLongLow;
}
}
if(event != ManchesterEventReset) {
bool data;
bool data_ok = manchester_advance(
proto->decoder_manchester_state, event, &proto->decoder_manchester_state, &data);
if(data_ok) {
proto->encoded_data = (proto->encoded_data << 1) | data;
if(em4100_can_be_decoded((uint8_t*)&proto->encoded_data, sizeof(EM4100DecodedData))) {
em4100_decode(
(uint8_t*)&proto->encoded_data,
sizeof(EM4100DecodedData),
proto->data,
EM4100_DECODED_DATA_SIZE);
result = true;
}
}
}
return result;
};
static void em4100_write_nibble(bool low_nibble, uint8_t data, EM4100DecodedData* encoded_data) {
uint8_t parity_sum = 0;
uint8_t start = 0;
if(!low_nibble) start = 4;
for(int8_t i = (start + 3); i >= start; i--) {
parity_sum += (data >> i) & 1;
*encoded_data = (*encoded_data << 1) | ((data >> i) & 1);
}
*encoded_data = (*encoded_data << 1) | ((parity_sum % 2) & 1);
}
bool protocol_em4100_encoder_start(ProtocolEM4100* proto) {
// header
proto->encoded_data = 0b111111111;
// data
for(uint8_t i = 0; i < EM4100_DECODED_DATA_SIZE; i++) {
em4100_write_nibble(false, proto->data[i], &proto->encoded_data);
em4100_write_nibble(true, proto->data[i], &proto->encoded_data);
}
// column parity and stop bit
uint8_t parity_sum;
for(uint8_t c = 0; c < EM_COLUMN_COUNT; c++) {
parity_sum = 0;
for(uint8_t i = 1; i <= EM_ROW_COUNT; i++) {
uint8_t parity_bit = (proto->encoded_data >> (i * EM_BITS_PER_ROW_COUNT - 1)) & 1;
parity_sum += parity_bit;
}
proto->encoded_data = (proto->encoded_data << 1) | ((parity_sum % 2) & 1);
}
// stop bit
proto->encoded_data = (proto->encoded_data << 1) | 0;
proto->encoded_data_index = 0;
proto->encoded_polarity = true;
return true;
};
LevelDuration protocol_em4100_encoder_yield(ProtocolEM4100* proto) {
bool level = (proto->encoded_data >> (63 - proto->encoded_data_index)) & 1;
uint32_t duration = EM4100_CLOCK_PER_BIT / 2;
if(proto->encoded_polarity) {
proto->encoded_polarity = false;
} else {
level = !level;
proto->encoded_polarity = true;
proto->encoded_data_index++;
if(proto->encoded_data_index >= 64) {
proto->encoded_data_index = 0;
}
}
return level_duration_make(level, duration);
};
bool protocol_em4100_write_data(ProtocolEM4100* protocol, void* data) {
LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data;
bool result = false;
protocol_em4100_encoder_start(protocol);
if(request->write_type == LFRFIDWriteTypeT5577) {
request->t5577.block[0] =
(LFRFID_T5577_MODULATION_MANCHESTER | LFRFID_T5577_BITRATE_RF_64 |
(2 << LFRFID_T5577_MAXBLOCK_SHIFT));
request->t5577.block[1] = protocol->encoded_data;
request->t5577.block[2] = protocol->encoded_data >> 32;
request->t5577.blocks_to_write = 3;
result = true;
}
return result;
};
void protocol_em4100_render_data(ProtocolEM4100* protocol, string_t result) {
uint8_t* data = protocol->data;
string_printf(result, "ID: %03u,%05u", data[2], (uint16_t)((data[3] << 8) | (data[4])));
};
const ProtocolBase protocol_em4100 = {
.name = "EM4100",
.manufacturer = "EM-Micro",
.data_size = EM4100_DECODED_DATA_SIZE,
.features = LFRFIDFeatureASK | LFRFIDFeaturePSK,
.validate_count = 3,
.alloc = (ProtocolAlloc)protocol_em4100_alloc,
.free = (ProtocolFree)protocol_em4100_free,
.get_data = (ProtocolGetData)protocol_em4100_get_data,
.decoder =
{
.start = (ProtocolDecoderStart)protocol_em4100_decoder_start,
.feed = (ProtocolDecoderFeed)protocol_em4100_decoder_feed,
},
.encoder =
{
.start = (ProtocolEncoderStart)protocol_em4100_encoder_start,
.yield = (ProtocolEncoderYield)protocol_em4100_encoder_yield,
},
.render_data = (ProtocolRenderData)protocol_em4100_render_data,
.render_brief_data = (ProtocolRenderData)protocol_em4100_render_data,
.write_data = (ProtocolWriteData)protocol_em4100_write_data,
};

View File

@@ -0,0 +1,4 @@
#pragma once
#include <toolbox/protocols/protocol.h>
extern const ProtocolBase protocol_em4100;

View File

@@ -0,0 +1,239 @@
#include <furi.h>
#include <toolbox/protocols/protocol.h>
#include <lfrfid/tools/fsk_demod.h>
#include <lfrfid/tools/fsk_osc.h>
#include "lfrfid_protocols.h"
#include <lfrfid/tools/bit_lib.h>
#define JITTER_TIME (20)
#define MIN_TIME (64 - JITTER_TIME)
#define MAX_TIME (80 + JITTER_TIME)
#define FDXA_DATA_SIZE 10
#define FDXA_PREAMBLE_SIZE 2
#define FDXA_ENCODED_DATA_SIZE (FDXA_PREAMBLE_SIZE + FDXA_DATA_SIZE + FDXA_PREAMBLE_SIZE)
#define FDXA_ENCODED_BIT_SIZE ((FDXA_PREAMBLE_SIZE + FDXA_DATA_SIZE) * 8)
#define FDXA_DECODED_DATA_SIZE (5)
#define FDXA_DECODED_BIT_SIZE ((FDXA_ENCODED_BIT_SIZE - FDXA_PREAMBLE_SIZE * 8) / 2)
#define FDXA_PREAMBLE_0 0x55
#define FDXA_PREAMBLE_1 0x1D
typedef struct {
FSKDemod* fsk_demod;
} ProtocolFDXADecoder;
typedef struct {
FSKOsc* fsk_osc;
uint8_t encoded_index;
uint32_t pulse;
} ProtocolFDXAEncoder;
typedef struct {
ProtocolFDXADecoder decoder;
ProtocolFDXAEncoder encoder;
uint8_t encoded_data[FDXA_ENCODED_DATA_SIZE];
uint8_t data[FDXA_DECODED_DATA_SIZE];
size_t protocol_size;
} ProtocolFDXA;
ProtocolFDXA* protocol_fdx_a_alloc(void) {
ProtocolFDXA* protocol = malloc(sizeof(ProtocolFDXA));
protocol->decoder.fsk_demod = fsk_demod_alloc(MIN_TIME, 6, MAX_TIME, 5);
protocol->encoder.fsk_osc = fsk_osc_alloc(8, 10, 50);
return protocol;
};
void protocol_fdx_a_free(ProtocolFDXA* protocol) {
fsk_demod_free(protocol->decoder.fsk_demod);
fsk_osc_free(protocol->encoder.fsk_osc);
free(protocol);
};
uint8_t* protocol_fdx_a_get_data(ProtocolFDXA* protocol) {
return protocol->data;
};
void protocol_fdx_a_decoder_start(ProtocolFDXA* protocol) {
memset(protocol->encoded_data, 0, FDXA_ENCODED_DATA_SIZE);
};
static bool protocol_fdx_a_decode(const uint8_t* from, uint8_t* to) {
size_t bit_index = 0;
for(size_t i = FDXA_PREAMBLE_SIZE; i < (FDXA_PREAMBLE_SIZE + FDXA_DATA_SIZE); i++) {
for(size_t n = 0; n < 4; n++) {
uint8_t bit_pair = (from[i] >> (6 - (n * 2))) & 0b11;
if(bit_pair == 0b01) {
bit_lib_set_bit(to, bit_index, 0);
} else if(bit_pair == 0b10) {
bit_lib_set_bit(to, bit_index, 1);
} else {
return false;
}
bit_index++;
}
}
return true;
}
static bool protocol_fdx_a_can_be_decoded(const uint8_t* data) {
// check preamble
if(data[0] != FDXA_PREAMBLE_0 || data[1] != FDXA_PREAMBLE_1 || data[12] != FDXA_PREAMBLE_0 ||
data[13] != FDXA_PREAMBLE_1) {
return false;
}
// check for manchester encoding
uint8_t decoded_data[FDXA_DECODED_DATA_SIZE];
if(!protocol_fdx_a_decode(data, decoded_data)) return false;
uint8_t parity_sum = 0;
for(size_t i = 0; i < FDXA_DECODED_DATA_SIZE; i++) {
parity_sum += bit_lib_test_parity_32(decoded_data[i], BitLibParityOdd);
decoded_data[i] &= 0x7F;
}
return (parity_sum == 0);
}
bool protocol_fdx_a_decoder_feed(ProtocolFDXA* protocol, bool level, uint32_t duration) {
bool value;
uint32_t count;
bool result = false;
fsk_demod_feed(protocol->decoder.fsk_demod, level, duration, &value, &count);
if(count > 0) {
for(size_t i = 0; i < count; i++) {
bit_lib_push_bit(protocol->encoded_data, FDXA_ENCODED_DATA_SIZE, value);
if(protocol_fdx_a_can_be_decoded(protocol->encoded_data)) {
protocol_fdx_a_decode(protocol->encoded_data, protocol->data);
result = true;
}
}
}
return result;
};
static void protocol_fdx_a_encode(ProtocolFDXA* protocol) {
protocol->encoded_data[0] = FDXA_PREAMBLE_0;
protocol->encoded_data[1] = FDXA_PREAMBLE_1;
size_t bit_index = 0;
for(size_t i = 0; i < FDXA_DECODED_BIT_SIZE; i++) {
bool bit = bit_lib_get_bit(protocol->data, i);
if(bit) {
bit_lib_set_bit(protocol->encoded_data, 16 + bit_index, 1);
bit_lib_set_bit(protocol->encoded_data, 16 + bit_index + 1, 0);
} else {
bit_lib_set_bit(protocol->encoded_data, 16 + bit_index, 0);
bit_lib_set_bit(protocol->encoded_data, 16 + bit_index + 1, 1);
}
bit_index += 2;
}
}
bool protocol_fdx_a_encoder_start(ProtocolFDXA* protocol) {
protocol->encoder.encoded_index = 0;
protocol->encoder.pulse = 0;
protocol_fdx_a_encode(protocol);
return true;
};
LevelDuration protocol_fdx_a_encoder_yield(ProtocolFDXA* protocol) {
bool level = 0;
uint32_t duration = 0;
// if pulse is zero, we need to output high, otherwise we need to output low
if(protocol->encoder.pulse == 0) {
// get bit
uint8_t bit = bit_lib_get_bit(protocol->encoded_data, protocol->encoder.encoded_index);
// get pulse from oscillator
bool advance = fsk_osc_next(protocol->encoder.fsk_osc, bit, &duration);
if(advance) {
bit_lib_increment_index(protocol->encoder.encoded_index, FDXA_ENCODED_BIT_SIZE);
}
// duration diveded by 2 because we need to output high and low
duration = duration / 2;
protocol->encoder.pulse = duration;
level = true;
} else {
// output low half and reset pulse
duration = protocol->encoder.pulse;
protocol->encoder.pulse = 0;
level = false;
}
return level_duration_make(level, duration);
};
bool protocol_fdx_a_write_data(ProtocolFDXA* protocol, void* data) {
LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data;
bool result = false;
protocol_fdx_a_encoder_start(protocol);
if(request->write_type == LFRFIDWriteTypeT5577) {
request->t5577.block[0] = LFRFID_T5577_MODULATION_FSK2a | LFRFID_T5577_BITRATE_RF_50 |
(3 << LFRFID_T5577_MAXBLOCK_SHIFT);
request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32);
request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32);
request->t5577.block[3] = bit_lib_get_bits_32(protocol->encoded_data, 64, 32);
request->t5577.blocks_to_write = 4;
result = true;
}
return result;
};
void protocol_fdx_a_render_data(ProtocolFDXA* protocol, string_t result) {
uint8_t data[FDXA_DECODED_DATA_SIZE];
memcpy(data, protocol->data, FDXA_DECODED_DATA_SIZE);
uint8_t parity_sum = 0;
for(size_t i = 0; i < FDXA_DECODED_DATA_SIZE; i++) {
parity_sum += bit_lib_test_parity_32(data[i], BitLibParityOdd);
data[i] &= 0x7F;
}
string_printf(
result,
"ID: %02X%02X%02X%02X%02X\r\n"
"Parity: %s",
data[0],
data[1],
data[2],
data[3],
data[4],
parity_sum == 0 ? "+" : "-");
};
const ProtocolBase protocol_fdx_a = {
.name = "FDX-A",
.manufacturer = "FECAVA",
.data_size = FDXA_DECODED_DATA_SIZE,
.features = LFRFIDFeatureASK,
.validate_count = 3,
.alloc = (ProtocolAlloc)protocol_fdx_a_alloc,
.free = (ProtocolFree)protocol_fdx_a_free,
.get_data = (ProtocolGetData)protocol_fdx_a_get_data,
.decoder =
{
.start = (ProtocolDecoderStart)protocol_fdx_a_decoder_start,
.feed = (ProtocolDecoderFeed)protocol_fdx_a_decoder_feed,
},
.encoder =
{
.start = (ProtocolEncoderStart)protocol_fdx_a_encoder_start,
.yield = (ProtocolEncoderYield)protocol_fdx_a_encoder_yield,
},
.render_data = (ProtocolRenderData)protocol_fdx_a_render_data,
.render_brief_data = (ProtocolRenderData)protocol_fdx_a_render_data,
.write_data = (ProtocolWriteData)protocol_fdx_a_write_data,
};

View File

@@ -0,0 +1,4 @@
#pragma once
#include <toolbox/protocols/protocol.h>
extern const ProtocolBase protocol_fdx_a;

View File

@@ -0,0 +1,374 @@
#include <furi.h>
#include "toolbox/level_duration.h"
#include "protocol_fdx_b.h"
#include <toolbox/manchester_decoder.h>
#include <lfrfid/tools/bit_lib.h>
#include "lfrfid_protocols.h"
#define FDX_B_ENCODED_BIT_SIZE (128)
#define FDX_B_ENCODED_BYTE_SIZE (((FDX_B_ENCODED_BIT_SIZE) / 8))
#define FDX_B_PREAMBLE_BIT_SIZE (11)
#define FDX_B_PREAMBLE_BYTE_SIZE (2)
#define FDX_B_ENCODED_BYTE_FULL_SIZE (FDX_B_ENCODED_BYTE_SIZE + FDX_B_PREAMBLE_BYTE_SIZE)
#define FDXB_DECODED_DATA_SIZE (11)
#define FDX_B_SHORT_TIME (128)
#define FDX_B_LONG_TIME (256)
#define FDX_B_JITTER_TIME (60)
#define FDX_B_SHORT_TIME_LOW (FDX_B_SHORT_TIME - FDX_B_JITTER_TIME)
#define FDX_B_SHORT_TIME_HIGH (FDX_B_SHORT_TIME + FDX_B_JITTER_TIME)
#define FDX_B_LONG_TIME_LOW (FDX_B_LONG_TIME - FDX_B_JITTER_TIME)
#define FDX_B_LONG_TIME_HIGH (FDX_B_LONG_TIME + FDX_B_JITTER_TIME)
typedef struct {
bool last_short;
bool last_level;
size_t encoded_index;
uint8_t encoded_data[FDX_B_ENCODED_BYTE_FULL_SIZE];
uint8_t data[FDXB_DECODED_DATA_SIZE];
} ProtocolFDXB;
ProtocolFDXB* protocol_fdx_b_alloc(void) {
ProtocolFDXB* protocol = malloc(sizeof(ProtocolFDXB));
return protocol;
};
void protocol_fdx_b_free(ProtocolFDXB* protocol) {
free(protocol);
};
uint8_t* protocol_fdx_b_get_data(ProtocolFDXB* proto) {
return proto->data;
};
void protocol_fdx_b_decoder_start(ProtocolFDXB* protocol) {
memset(protocol->encoded_data, 0, FDX_B_ENCODED_BYTE_FULL_SIZE);
protocol->last_short = false;
};
static bool protocol_fdx_b_can_be_decoded(ProtocolFDXB* protocol) {
bool result = false;
/*
msb lsb
0 10000000000 Header pattern. 11 bits.
11 1nnnnnnnn
20 1nnnnnnnn 38 bit (12 digit) National code.
29 1nnnnnnnn eg. 000000001008 (decimal).
38 1nnnnnnnn
47 1nnnnnncc 10 bit (3 digit) Country code.
56 1cccccccc eg. 999 (decimal).
65 1s------- 1 bit data block status flag.
74 1-------a 1 bit animal application indicator.
83 1xxxxxxxx 16 bit checksum.
92 1xxxxxxxx
101 1eeeeeeee 24 bits of extra data if present.
110 1eeeeeeee eg. $123456.
119 1eeeeeeee
*/
do {
// check 11 bits preamble
if(bit_lib_get_bits_16(protocol->encoded_data, 0, 11) != 0b10000000000) break;
// check next 11 bits preamble
if(bit_lib_get_bits_16(protocol->encoded_data, 128, 11) != 0b10000000000) break;
// check control bits
if(!bit_lib_test_parity(protocol->encoded_data, 3, 13 * 9, BitLibParityAlways1, 9)) break;
// compute checksum
uint8_t crc_data[8];
for(size_t i = 0; i < 8; i++) {
bit_lib_copy_bits(crc_data, i * 8, 8, protocol->encoded_data, 12 + 9 * i);
}
uint16_t crc_res = bit_lib_crc16(crc_data, 8, 0x1021, 0x0000, false, false, 0x0000);
// read checksum
uint16_t crc_ex = 0;
bit_lib_copy_bits((uint8_t*)&crc_ex, 8, 8, protocol->encoded_data, 84);
bit_lib_copy_bits((uint8_t*)&crc_ex, 0, 8, protocol->encoded_data, 93);
// compare checksum
if(crc_res != crc_ex) break;
result = true;
} while(false);
return result;
}
void protocol_fdx_b_decode(ProtocolFDXB* protocol) {
// remove parity
bit_lib_remove_bit_every_nth(protocol->encoded_data, 3, 13 * 9, 9);
// remove header pattern
for(size_t i = 0; i < 11; i++)
bit_lib_push_bit(protocol->encoded_data, FDX_B_ENCODED_BYTE_FULL_SIZE, 0);
// 0 nnnnnnnn
// 8 nnnnnnnn 38 bit (12 digit) National code.
// 16 nnnnnnnn eg. 000000001008 (decimal).
// 24 nnnnnnnn
// 32 nnnnnncc 10 bit (3 digit) Country code.
// 40 cccccccc eg. 999 (decimal).
// 48 s------- 1 bit data block status flag.
// 56 -------a 1 bit animal application indicator.
// 64 xxxxxxxx 16 bit checksum.
// 72 xxxxxxxx
// 80 eeeeeeee 24 bits of extra data if present.
// 88 eeeeeeee eg. $123456.
// 92 eeeeeeee
// copy data without checksum
bit_lib_copy_bits(protocol->data, 0, 64, protocol->encoded_data, 0);
bit_lib_copy_bits(protocol->data, 64, 24, protocol->encoded_data, 80);
// const BitLibRegion regions_encoded[] = {
// {'n', 0, 38},
// {'c', 38, 10},
// {'b', 48, 16},
// {'x', 64, 16},
// {'e', 80, 24},
// };
// bit_lib_print_regions(regions_encoded, 5, protocol->encoded_data, FDX_B_ENCODED_BIT_SIZE);
// const BitLibRegion regions_decoded[] = {
// {'n', 0, 38},
// {'c', 38, 10},
// {'b', 48, 16},
// {'e', 64, 24},
// };
// bit_lib_print_regions(regions_decoded, 4, protocol->data, FDXB_DECODED_DATA_SIZE * 8);
}
bool protocol_fdx_b_decoder_feed(ProtocolFDXB* protocol, bool level, uint32_t duration) {
bool result = false;
UNUSED(level);
bool pushed = false;
// Bi-Phase Manchester decoding
if(duration >= FDX_B_SHORT_TIME_LOW && duration <= FDX_B_SHORT_TIME_HIGH) {
if(protocol->last_short == false) {
protocol->last_short = true;
} else {
pushed = true;
bit_lib_push_bit(protocol->encoded_data, FDX_B_ENCODED_BYTE_FULL_SIZE, false);
protocol->last_short = false;
}
} else if(duration >= FDX_B_LONG_TIME_LOW && duration <= FDX_B_LONG_TIME_HIGH) {
if(protocol->last_short == false) {
pushed = true;
bit_lib_push_bit(protocol->encoded_data, FDX_B_ENCODED_BYTE_FULL_SIZE, true);
} else {
// reset
protocol->last_short = false;
}
} else {
// reset
protocol->last_short = false;
}
if(pushed && protocol_fdx_b_can_be_decoded(protocol)) {
protocol_fdx_b_decode(protocol);
result = true;
}
return result;
};
bool protocol_fdx_b_encoder_start(ProtocolFDXB* protocol) {
memset(protocol->encoded_data, 0, FDX_B_ENCODED_BYTE_FULL_SIZE);
bit_lib_set_bit(protocol->encoded_data, 0, 1);
for(size_t i = 0; i < 13; i++) {
bit_lib_set_bit(protocol->encoded_data, 11 + 9 * i, 1);
if(i == 8 || i == 9) continue;
if(i < 8) {
bit_lib_copy_bits(protocol->encoded_data, 12 + 9 * i, 8, protocol->data, i * 8);
} else {
bit_lib_copy_bits(protocol->encoded_data, 12 + 9 * i, 8, protocol->data, (i - 2) * 8);
}
}
uint16_t crc_res = bit_lib_crc16(protocol->data, 8, 0x1021, 0x0000, false, false, 0x0000);
bit_lib_copy_bits(protocol->encoded_data, 84, 8, (uint8_t*)&crc_res, 8);
bit_lib_copy_bits(protocol->encoded_data, 93, 8, (uint8_t*)&crc_res, 0);
protocol->encoded_index = 0;
protocol->last_short = false;
protocol->last_level = false;
return true;
};
LevelDuration protocol_fdx_b_encoder_yield(ProtocolFDXB* protocol) {
uint32_t duration;
protocol->last_level = !protocol->last_level;
bool bit = bit_lib_get_bit(protocol->encoded_data, protocol->encoded_index);
// Bi-Phase Manchester encoder
if(bit) {
// one long pulse for 1
duration = FDX_B_LONG_TIME / 8;
bit_lib_increment_index(protocol->encoded_index, FDX_B_ENCODED_BIT_SIZE);
} else {
// two short pulses for 0
duration = FDX_B_SHORT_TIME / 8;
if(protocol->last_short) {
bit_lib_increment_index(protocol->encoded_index, FDX_B_ENCODED_BIT_SIZE);
protocol->last_short = false;
} else {
protocol->last_short = true;
}
}
return level_duration_make(protocol->last_level, duration);
};
// 0 nnnnnnnn
// 8 nnnnnnnn 38 bit (12 digit) National code.
// 16 nnnnnnnn eg. 000000001008 (decimal).
// 24 nnnnnnnn
// 32 nnnnnnnn 10 bit (3 digit) Country code.
// 40 cccccccc eg. 999 (decimal).
// 48 s------- 1 bit data block status flag.
// 56 -------a 1 bit animal application indicator.
// 64 eeeeeeee 24 bits of extra data if present.
// 72 eeeeeeee eg. $123456.
// 80 eeeeeeee
static uint64_t protocol_fdx_b_get_national_code(const uint8_t* data) {
uint64_t national_code = bit_lib_get_bits_32(data, 0, 32);
national_code = national_code << 32;
national_code |= bit_lib_get_bits_32(data, 32, 6) << (32 - 6);
bit_lib_reverse_bits((uint8_t*)&national_code, 0, 64);
return national_code;
}
static uint16_t protocol_fdx_b_get_country_code(const uint8_t* data) {
uint16_t country_code = bit_lib_get_bits_16(data, 38, 10) << 6;
bit_lib_reverse_bits((uint8_t*)&country_code, 0, 16);
return country_code;
}
static bool protocol_fdx_b_get_temp(const uint8_t* data, float* temp) {
uint32_t extended = bit_lib_get_bits_32(data, 64, 24) << 8;
bit_lib_reverse_bits((uint8_t*)&extended, 0, 32);
uint8_t ex_parity = (extended & 0x100) >> 8;
uint8_t ex_temperature = extended & 0xff;
uint8_t ex_calc_parity = bit_lib_test_parity_32(ex_temperature, BitLibParityOdd);
bool ex_temperature_present = (ex_calc_parity == ex_parity) && !(extended & 0xe00);
if(ex_temperature_present) {
float temperature_f = 74 + ex_temperature * 0.2;
*temp = temperature_f;
return true;
} else {
return false;
}
}
void protocol_fdx_b_render_data(ProtocolFDXB* protocol, string_t result) {
// 38 bits of national code
uint64_t national_code = protocol_fdx_b_get_national_code(protocol->data);
// 10 bit of country code
uint16_t country_code = protocol_fdx_b_get_country_code(protocol->data);
bool block_status = bit_lib_get_bit(protocol->data, 48);
bool rudi_bit = bit_lib_get_bit(protocol->data, 49);
uint8_t reserved = bit_lib_get_bits(protocol->data, 50, 5);
uint8_t user_info = bit_lib_get_bits(protocol->data, 55, 5);
uint8_t replacement_number = bit_lib_get_bits(protocol->data, 60, 3);
bool animal_flag = bit_lib_get_bit(protocol->data, 63);
string_printf(result, "ID: %03u-%012llu\r\n", country_code, national_code);
string_cat_printf(result, "Animal: %s, ", animal_flag ? "Yes" : "No");
float temperature;
if(protocol_fdx_b_get_temp(protocol->data, &temperature)) {
float temperature_c = (temperature - 32) / 1.8;
string_cat_printf(
result, "T: %.2fF, %.2fC\r\n", (double)temperature, (double)temperature_c);
} else {
string_cat_printf(result, "T: ---\r\n");
}
string_cat_printf(
result,
"Bits: %X-%X-%X-%X-%X",
block_status,
rudi_bit,
reserved,
user_info,
replacement_number);
};
void protocol_fdx_b_render_brief_data(ProtocolFDXB* protocol, string_t result) {
// 38 bits of national code
uint64_t national_code = protocol_fdx_b_get_national_code(protocol->data);
// 10 bit of country code
uint16_t country_code = protocol_fdx_b_get_country_code(protocol->data);
bool animal_flag = bit_lib_get_bit(protocol->data, 63);
string_printf(result, "ID: %03u-%012llu\r\n", country_code, national_code);
string_cat_printf(result, "Animal: %s, ", animal_flag ? "Yes" : "No");
float temperature;
if(protocol_fdx_b_get_temp(protocol->data, &temperature)) {
float temperature_c = (temperature - 32) / 1.8;
string_cat_printf(result, "T: %.2fC", (double)temperature_c);
} else {
string_cat_printf(result, "T: ---");
}
};
bool protocol_fdx_b_write_data(ProtocolFDXB* protocol, void* data) {
LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data;
bool result = false;
protocol_fdx_b_encoder_start(protocol);
if(request->write_type == LFRFIDWriteTypeT5577) {
request->t5577.block[0] = LFRFID_T5577_MODULATION_DIPHASE | LFRFID_T5577_BITRATE_RF_32 |
(4 << LFRFID_T5577_MAXBLOCK_SHIFT);
request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32);
request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32);
request->t5577.block[3] = bit_lib_get_bits_32(protocol->encoded_data, 64, 32);
request->t5577.block[4] = bit_lib_get_bits_32(protocol->encoded_data, 96, 32);
request->t5577.blocks_to_write = 5;
result = true;
}
return result;
};
const ProtocolBase protocol_fdx_b = {
.name = "FDX-B",
.manufacturer = "ISO",
.data_size = FDXB_DECODED_DATA_SIZE,
.features = LFRFIDFeatureASK,
.validate_count = 3,
.alloc = (ProtocolAlloc)protocol_fdx_b_alloc,
.free = (ProtocolFree)protocol_fdx_b_free,
.get_data = (ProtocolGetData)protocol_fdx_b_get_data,
.decoder =
{
.start = (ProtocolDecoderStart)protocol_fdx_b_decoder_start,
.feed = (ProtocolDecoderFeed)protocol_fdx_b_decoder_feed,
},
.encoder =
{
.start = (ProtocolEncoderStart)protocol_fdx_b_encoder_start,
.yield = (ProtocolEncoderYield)protocol_fdx_b_encoder_yield,
},
.render_data = (ProtocolRenderData)protocol_fdx_b_render_data,
.render_brief_data = (ProtocolRenderData)protocol_fdx_b_render_brief_data,
.write_data = (ProtocolWriteData)protocol_fdx_b_write_data,
};

View File

@@ -0,0 +1,4 @@
#pragma once
#include <toolbox/protocols/protocol.h>
extern const ProtocolBase protocol_fdx_b;

View File

@@ -0,0 +1,386 @@
#include <furi.h>
#include <toolbox/protocols/protocol.h>
#include <lfrfid/tools/fsk_demod.h>
#include <lfrfid/tools/fsk_osc.h>
#include "lfrfid_protocols.h"
#define JITTER_TIME (20)
#define MIN_TIME (64 - JITTER_TIME)
#define MAX_TIME (80 + JITTER_TIME)
#define H10301_DECODED_DATA_SIZE (3)
#define H10301_ENCODED_DATA_SIZE_U32 (3)
#define H10301_ENCODED_DATA_SIZE (sizeof(uint32_t) * H10301_ENCODED_DATA_SIZE_U32)
#define H10301_BIT_SIZE (sizeof(uint32_t) * 8)
#define H10301_BIT_MAX_SIZE (H10301_BIT_SIZE * H10301_DECODED_DATA_SIZE)
typedef struct {
FSKDemod* fsk_demod;
} ProtocolH10301Decoder;
typedef struct {
FSKOsc* fsk_osc;
uint8_t encoded_index;
uint32_t pulse;
} ProtocolH10301Encoder;
typedef struct {
ProtocolH10301Decoder decoder;
ProtocolH10301Encoder encoder;
uint32_t encoded_data[H10301_ENCODED_DATA_SIZE_U32];
uint8_t data[H10301_DECODED_DATA_SIZE];
} ProtocolH10301;
ProtocolH10301* protocol_h10301_alloc(void) {
ProtocolH10301* protocol = malloc(sizeof(ProtocolH10301));
protocol->decoder.fsk_demod = fsk_demod_alloc(MIN_TIME, 6, MAX_TIME, 5);
protocol->encoder.fsk_osc = fsk_osc_alloc(8, 10, 50);
return protocol;
};
void protocol_h10301_free(ProtocolH10301* protocol) {
fsk_demod_free(protocol->decoder.fsk_demod);
fsk_osc_free(protocol->encoder.fsk_osc);
free(protocol);
};
uint8_t* protocol_h10301_get_data(ProtocolH10301* protocol) {
return protocol->data;
};
void protocol_h10301_decoder_start(ProtocolH10301* protocol) {
memset(protocol->encoded_data, 0, sizeof(uint32_t) * 3);
};
static void protocol_h10301_decoder_store_data(ProtocolH10301* protocol, bool data) {
protocol->encoded_data[0] = (protocol->encoded_data[0] << 1) |
((protocol->encoded_data[1] >> 31) & 1);
protocol->encoded_data[1] = (protocol->encoded_data[1] << 1) |
((protocol->encoded_data[2] >> 31) & 1);
protocol->encoded_data[2] = (protocol->encoded_data[2] << 1) | data;
}
static bool protocol_h10301_can_be_decoded(const uint32_t* card_data) {
const uint8_t* encoded_data = (const uint8_t*)card_data;
// packet preamble
// raw data
if(*(encoded_data + 3) != 0x1D) {
return false;
}
// encoded company/oem
// coded with 01 = 0, 10 = 1 transitions
// stored in word 0
if((*card_data >> 10 & 0x3FFF) != 0x1556) {
return false;
}
// encoded format/length
// coded with 01 = 0, 10 = 1 transitions
// stored in word 0 and word 1
if((((*card_data & 0x3FF) << 12) | ((*(card_data + 1) >> 20) & 0xFFF)) != 0x155556) {
return false;
}
// data decoding
uint32_t result = 0;
// decode from word 1
// coded with 01 = 0, 10 = 1 transitions
for(int8_t i = 9; i >= 0; i--) {
switch((*(card_data + 1) >> (2 * i)) & 0b11) {
case 0b01:
result = (result << 1) | 0;
break;
case 0b10:
result = (result << 1) | 1;
break;
default:
return false;
break;
}
}
// decode from word 2
// coded with 01 = 0, 10 = 1 transitions
for(int8_t i = 15; i >= 0; i--) {
switch((*(card_data + 2) >> (2 * i)) & 0b11) {
case 0b01:
result = (result << 1) | 0;
break;
case 0b10:
result = (result << 1) | 1;
break;
default:
return false;
break;
}
}
// trailing parity (odd) test
uint8_t parity_sum = 0;
for(int8_t i = 0; i < 13; i++) {
if(((result >> i) & 1) == 1) {
parity_sum++;
}
}
if((parity_sum % 2) != 1) {
return false;
}
// leading parity (even) test
parity_sum = 0;
for(int8_t i = 13; i < 26; i++) {
if(((result >> i) & 1) == 1) {
parity_sum++;
}
}
if((parity_sum % 2) == 1) {
return false;
}
return true;
}
static void protocol_h10301_decode(const uint32_t* card_data, uint8_t* decoded_data) {
// data decoding
uint32_t result = 0;
// decode from word 1
// coded with 01 = 0, 10 = 1 transitions
for(int8_t i = 9; i >= 0; i--) {
switch((*(card_data + 1) >> (2 * i)) & 0b11) {
case 0b01:
result = (result << 1) | 0;
break;
case 0b10:
result = (result << 1) | 1;
break;
default:
break;
}
}
// decode from word 2
// coded with 01 = 0, 10 = 1 transitions
for(int8_t i = 15; i >= 0; i--) {
switch((*(card_data + 2) >> (2 * i)) & 0b11) {
case 0b01:
result = (result << 1) | 0;
break;
case 0b10:
result = (result << 1) | 1;
break;
default:
break;
}
}
uint8_t data[H10301_DECODED_DATA_SIZE] = {
(uint8_t)(result >> 17), (uint8_t)(result >> 9), (uint8_t)(result >> 1)};
memcpy(decoded_data, &data, H10301_DECODED_DATA_SIZE);
}
bool protocol_h10301_decoder_feed(ProtocolH10301* protocol, bool level, uint32_t duration) {
bool value;
uint32_t count;
bool result = false;
fsk_demod_feed(protocol->decoder.fsk_demod, level, duration, &value, &count);
if(count > 0) {
for(size_t i = 0; i < count; i++) {
protocol_h10301_decoder_store_data(protocol, value);
if(protocol_h10301_can_be_decoded(protocol->encoded_data)) {
protocol_h10301_decode(protocol->encoded_data, protocol->data);
result = true;
break;
}
}
}
return result;
};
static void protocol_h10301_write_raw_bit(bool bit, uint8_t position, uint32_t* card_data) {
if(bit) {
card_data[position / H10301_BIT_SIZE] |=
1UL << (H10301_BIT_SIZE - (position % H10301_BIT_SIZE) - 1);
} else {
card_data[position / H10301_BIT_SIZE] &=
~(1UL << (H10301_BIT_SIZE - (position % H10301_BIT_SIZE) - 1));
}
}
static void protocol_h10301_write_bit(bool bit, uint8_t position, uint32_t* card_data) {
protocol_h10301_write_raw_bit(bit, position + 0, card_data);
protocol_h10301_write_raw_bit(!bit, position + 1, card_data);
}
void protocol_h10301_encode(const uint8_t* decoded_data, uint8_t* encoded_data) {
uint32_t card_data[H10301_DECODED_DATA_SIZE] = {0, 0, 0};
uint32_t fc_cn = (decoded_data[0] << 16) | (decoded_data[1] << 8) | decoded_data[2];
// even parity sum calculation (high 12 bits of data)
uint8_t even_parity_sum = 0;
for(int8_t i = 12; i < 24; i++) {
if(((fc_cn >> i) & 1) == 1) {
even_parity_sum++;
}
}
// odd parity sum calculation (low 12 bits of data)
uint8_t odd_parity_sum = 1;
for(int8_t i = 0; i < 12; i++) {
if(((fc_cn >> i) & 1) == 1) {
odd_parity_sum++;
}
}
// 0x1D preamble
protocol_h10301_write_raw_bit(0, 0, card_data);
protocol_h10301_write_raw_bit(0, 1, card_data);
protocol_h10301_write_raw_bit(0, 2, card_data);
protocol_h10301_write_raw_bit(1, 3, card_data);
protocol_h10301_write_raw_bit(1, 4, card_data);
protocol_h10301_write_raw_bit(1, 5, card_data);
protocol_h10301_write_raw_bit(0, 6, card_data);
protocol_h10301_write_raw_bit(1, 7, card_data);
// company / OEM code 1
protocol_h10301_write_bit(0, 8, card_data);
protocol_h10301_write_bit(0, 10, card_data);
protocol_h10301_write_bit(0, 12, card_data);
protocol_h10301_write_bit(0, 14, card_data);
protocol_h10301_write_bit(0, 16, card_data);
protocol_h10301_write_bit(0, 18, card_data);
protocol_h10301_write_bit(1, 20, card_data);
// card format / length 1
protocol_h10301_write_bit(0, 22, card_data);
protocol_h10301_write_bit(0, 24, card_data);
protocol_h10301_write_bit(0, 26, card_data);
protocol_h10301_write_bit(0, 28, card_data);
protocol_h10301_write_bit(0, 30, card_data);
protocol_h10301_write_bit(0, 32, card_data);
protocol_h10301_write_bit(0, 34, card_data);
protocol_h10301_write_bit(0, 36, card_data);
protocol_h10301_write_bit(0, 38, card_data);
protocol_h10301_write_bit(0, 40, card_data);
protocol_h10301_write_bit(1, 42, card_data);
// even parity bit
protocol_h10301_write_bit((even_parity_sum % 2), 44, card_data);
// data
for(uint8_t i = 0; i < 24; i++) {
protocol_h10301_write_bit((fc_cn >> (23 - i)) & 1, 46 + (i * 2), card_data);
}
// odd parity bit
protocol_h10301_write_bit((odd_parity_sum % 2), 94, card_data);
memcpy(encoded_data, &card_data, H10301_ENCODED_DATA_SIZE);
}
bool protocol_h10301_encoder_start(ProtocolH10301* protocol) {
protocol_h10301_encode(protocol->data, (uint8_t*)protocol->encoded_data);
protocol->encoder.encoded_index = 0;
protocol->encoder.pulse = 0;
return true;
};
LevelDuration protocol_h10301_encoder_yield(ProtocolH10301* protocol) {
bool level = 0;
uint32_t duration = 0;
// if pulse is zero, we need to output high, otherwise we need to output low
if(protocol->encoder.pulse == 0) {
// get bit
uint8_t bit =
(protocol->encoded_data[protocol->encoder.encoded_index / H10301_BIT_SIZE] >>
((H10301_BIT_SIZE - 1) - (protocol->encoder.encoded_index % H10301_BIT_SIZE))) &
1;
// get pulse from oscillator
bool advance = fsk_osc_next(protocol->encoder.fsk_osc, bit, &duration);
if(advance) {
protocol->encoder.encoded_index++;
if(protocol->encoder.encoded_index >= (H10301_BIT_MAX_SIZE)) {
protocol->encoder.encoded_index = 0;
}
}
// duration diveded by 2 because we need to output high and low
duration = duration / 2;
protocol->encoder.pulse = duration;
level = true;
} else {
// output low half and reset pulse
duration = protocol->encoder.pulse;
protocol->encoder.pulse = 0;
level = false;
}
return level_duration_make(level, duration);
};
bool protocol_h10301_write_data(ProtocolH10301* protocol, void* data) {
LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data;
bool result = false;
protocol_h10301_encoder_start(protocol);
if(request->write_type == LFRFIDWriteTypeT5577) {
request->t5577.block[0] = LFRFID_T5577_MODULATION_FSK2a | LFRFID_T5577_BITRATE_RF_50 |
(3 << LFRFID_T5577_MAXBLOCK_SHIFT);
request->t5577.block[1] = protocol->encoded_data[0];
request->t5577.block[2] = protocol->encoded_data[1];
request->t5577.block[3] = protocol->encoded_data[2];
request->t5577.blocks_to_write = 4;
result = true;
}
return result;
};
void protocol_h10301_render_data(ProtocolH10301* protocol, string_t result) {
uint8_t* data = protocol->data;
string_printf(
result,
"FC: %u\r\n"
"Card: %u",
data[0],
(uint16_t)((data[1] << 8) | (data[2])));
};
const ProtocolBase protocol_h10301 = {
.name = "H10301",
.manufacturer = "HID",
.data_size = H10301_DECODED_DATA_SIZE,
.features = LFRFIDFeatureASK,
.validate_count = 3,
.alloc = (ProtocolAlloc)protocol_h10301_alloc,
.free = (ProtocolFree)protocol_h10301_free,
.get_data = (ProtocolGetData)protocol_h10301_get_data,
.decoder =
{
.start = (ProtocolDecoderStart)protocol_h10301_decoder_start,
.feed = (ProtocolDecoderFeed)protocol_h10301_decoder_feed,
},
.encoder =
{
.start = (ProtocolEncoderStart)protocol_h10301_encoder_start,
.yield = (ProtocolEncoderYield)protocol_h10301_encoder_yield,
},
.render_data = (ProtocolRenderData)protocol_h10301_render_data,
.render_brief_data = (ProtocolRenderData)protocol_h10301_render_data,
.write_data = (ProtocolWriteData)protocol_h10301_write_data,
};

View File

@@ -0,0 +1,4 @@
#pragma once
#include <toolbox/protocols/protocol.h>
extern const ProtocolBase protocol_h10301;

View File

@@ -0,0 +1,219 @@
#include <furi.h>
#include <toolbox/protocols/protocol.h>
#include <lfrfid/tools/fsk_demod.h>
#include <lfrfid/tools/fsk_osc.h>
#include "lfrfid_protocols.h"
#include <lfrfid/tools/bit_lib.h>
#define JITTER_TIME (20)
#define MIN_TIME (64 - JITTER_TIME)
#define MAX_TIME (80 + JITTER_TIME)
#define HID_DATA_SIZE 23
#define HID_PREAMBLE_SIZE 1
#define HID_ENCODED_DATA_SIZE (HID_PREAMBLE_SIZE + HID_DATA_SIZE + HID_PREAMBLE_SIZE)
#define HID_ENCODED_BIT_SIZE ((HID_PREAMBLE_SIZE + HID_DATA_SIZE) * 8)
#define HID_DECODED_DATA_SIZE (12)
#define HID_DECODED_BIT_SIZE ((HID_ENCODED_BIT_SIZE - HID_PREAMBLE_SIZE * 8) / 2)
#define HID_PREAMBLE 0x1D
typedef struct {
FSKDemod* fsk_demod;
} ProtocolHIDExDecoder;
typedef struct {
FSKOsc* fsk_osc;
uint8_t encoded_index;
uint32_t pulse;
} ProtocolHIDExEncoder;
typedef struct {
ProtocolHIDExDecoder decoder;
ProtocolHIDExEncoder encoder;
uint8_t encoded_data[HID_ENCODED_DATA_SIZE];
uint8_t data[HID_DECODED_DATA_SIZE];
size_t protocol_size;
} ProtocolHIDEx;
ProtocolHIDEx* protocol_hid_ex_generic_alloc(void) {
ProtocolHIDEx* protocol = malloc(sizeof(ProtocolHIDEx));
protocol->decoder.fsk_demod = fsk_demod_alloc(MIN_TIME, 6, MAX_TIME, 5);
protocol->encoder.fsk_osc = fsk_osc_alloc(8, 10, 50);
return protocol;
};
void protocol_hid_ex_generic_free(ProtocolHIDEx* protocol) {
fsk_demod_free(protocol->decoder.fsk_demod);
fsk_osc_free(protocol->encoder.fsk_osc);
free(protocol);
};
uint8_t* protocol_hid_ex_generic_get_data(ProtocolHIDEx* protocol) {
return protocol->data;
};
void protocol_hid_ex_generic_decoder_start(ProtocolHIDEx* protocol) {
memset(protocol->encoded_data, 0, HID_ENCODED_DATA_SIZE);
};
static bool protocol_hid_ex_generic_can_be_decoded(const uint8_t* data) {
// check preamble
if(data[0] != HID_PREAMBLE || data[HID_PREAMBLE_SIZE + HID_DATA_SIZE] != HID_PREAMBLE) {
return false;
}
// check for manchester encoding
for(size_t i = HID_PREAMBLE_SIZE; i < (HID_PREAMBLE_SIZE + HID_DATA_SIZE); i++) {
for(size_t n = 0; n < 4; n++) {
uint8_t bit_pair = (data[i] >> (n * 2)) & 0b11;
if(bit_pair == 0b11 || bit_pair == 0b00) {
return false;
}
}
}
return true;
}
static void protocol_hid_ex_generic_decode(const uint8_t* from, uint8_t* to) {
size_t bit_index = 0;
for(size_t i = HID_PREAMBLE_SIZE; i < (HID_PREAMBLE_SIZE + HID_DATA_SIZE); i++) {
for(size_t n = 0; n < 4; n++) {
uint8_t bit_pair = (from[i] >> (6 - (n * 2))) & 0b11;
if(bit_pair == 0b01) {
bit_lib_set_bit(to, bit_index, 0);
} else if(bit_pair == 0b10) {
bit_lib_set_bit(to, bit_index, 1);
}
bit_index++;
}
}
}
bool protocol_hid_ex_generic_decoder_feed(ProtocolHIDEx* protocol, bool level, uint32_t duration) {
bool value;
uint32_t count;
bool result = false;
fsk_demod_feed(protocol->decoder.fsk_demod, level, duration, &value, &count);
if(count > 0) {
for(size_t i = 0; i < count; i++) {
bit_lib_push_bit(protocol->encoded_data, HID_ENCODED_DATA_SIZE, value);
if(protocol_hid_ex_generic_can_be_decoded(protocol->encoded_data)) {
protocol_hid_ex_generic_decode(protocol->encoded_data, protocol->data);
result = true;
}
}
}
return result;
};
static void protocol_hid_ex_generic_encode(ProtocolHIDEx* protocol) {
protocol->encoded_data[0] = HID_PREAMBLE;
size_t bit_index = 0;
for(size_t i = 0; i < HID_DECODED_BIT_SIZE; i++) {
bool bit = bit_lib_get_bit(protocol->data, i);
if(bit) {
bit_lib_set_bit(protocol->encoded_data, 8 + bit_index, 1);
bit_lib_set_bit(protocol->encoded_data, 8 + bit_index + 1, 0);
} else {
bit_lib_set_bit(protocol->encoded_data, 8 + bit_index, 0);
bit_lib_set_bit(protocol->encoded_data, 8 + bit_index + 1, 1);
}
bit_index += 2;
}
}
bool protocol_hid_ex_generic_encoder_start(ProtocolHIDEx* protocol) {
protocol->encoder.encoded_index = 0;
protocol->encoder.pulse = 0;
protocol_hid_ex_generic_encode(protocol);
return true;
};
LevelDuration protocol_hid_ex_generic_encoder_yield(ProtocolHIDEx* protocol) {
bool level = 0;
uint32_t duration = 0;
// if pulse is zero, we need to output high, otherwise we need to output low
if(protocol->encoder.pulse == 0) {
// get bit
uint8_t bit = bit_lib_get_bit(protocol->encoded_data, protocol->encoder.encoded_index);
// get pulse from oscillator
bool advance = fsk_osc_next(protocol->encoder.fsk_osc, bit, &duration);
if(advance) {
bit_lib_increment_index(protocol->encoder.encoded_index, HID_ENCODED_BIT_SIZE);
}
// duration diveded by 2 because we need to output high and low
duration = duration / 2;
protocol->encoder.pulse = duration;
level = true;
} else {
// output low half and reset pulse
duration = protocol->encoder.pulse;
protocol->encoder.pulse = 0;
level = false;
}
return level_duration_make(level, duration);
};
bool protocol_hid_ex_generic_write_data(ProtocolHIDEx* protocol, void* data) {
LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data;
bool result = false;
protocol_hid_ex_generic_encoder_start(protocol);
if(request->write_type == LFRFIDWriteTypeT5577) {
request->t5577.block[0] = LFRFID_T5577_MODULATION_FSK2a | LFRFID_T5577_BITRATE_RF_50 |
(6 << LFRFID_T5577_MAXBLOCK_SHIFT);
request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32);
request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32);
request->t5577.block[3] = bit_lib_get_bits_32(protocol->encoded_data, 64, 32);
request->t5577.block[4] = bit_lib_get_bits_32(protocol->encoded_data, 96, 32);
request->t5577.block[5] = bit_lib_get_bits_32(protocol->encoded_data, 128, 32);
request->t5577.block[6] = bit_lib_get_bits_32(protocol->encoded_data, 160, 32);
request->t5577.blocks_to_write = 7;
result = true;
}
return result;
};
void protocol_hid_ex_generic_render_data(ProtocolHIDEx* protocol, string_t result) {
// TODO: parser and render functions
UNUSED(protocol);
string_printf(result, "Generic HID Extended\r\nData: Unknown");
};
const ProtocolBase protocol_hid_ex_generic = {
.name = "HIDExt",
.manufacturer = "Generic",
.data_size = HID_DECODED_DATA_SIZE,
.features = LFRFIDFeatureASK,
.validate_count = 3,
.alloc = (ProtocolAlloc)protocol_hid_ex_generic_alloc,
.free = (ProtocolFree)protocol_hid_ex_generic_free,
.get_data = (ProtocolGetData)protocol_hid_ex_generic_get_data,
.decoder =
{
.start = (ProtocolDecoderStart)protocol_hid_ex_generic_decoder_start,
.feed = (ProtocolDecoderFeed)protocol_hid_ex_generic_decoder_feed,
},
.encoder =
{
.start = (ProtocolEncoderStart)protocol_hid_ex_generic_encoder_start,
.yield = (ProtocolEncoderYield)protocol_hid_ex_generic_encoder_yield,
},
.render_data = (ProtocolRenderData)protocol_hid_ex_generic_render_data,
.render_brief_data = (ProtocolRenderData)protocol_hid_ex_generic_render_data,
.write_data = (ProtocolWriteData)protocol_hid_ex_generic_write_data,
};

View File

@@ -0,0 +1,4 @@
#pragma once
#include <toolbox/protocols/protocol.h>
extern const ProtocolBase protocol_hid_ex_generic;

View File

@@ -0,0 +1,280 @@
#include <furi.h>
#include <toolbox/protocols/protocol.h>
#include <lfrfid/tools/fsk_demod.h>
#include <lfrfid/tools/fsk_osc.h>
#include "lfrfid_protocols.h"
#include <lfrfid/tools/bit_lib.h>
#define JITTER_TIME (20)
#define MIN_TIME (64 - JITTER_TIME)
#define MAX_TIME (80 + JITTER_TIME)
#define HID_DATA_SIZE 11
#define HID_PREAMBLE_SIZE 1
#define HID_PROTOCOL_SIZE_UNKNOWN 0
#define HID_ENCODED_DATA_SIZE (HID_PREAMBLE_SIZE + HID_DATA_SIZE + HID_PREAMBLE_SIZE)
#define HID_ENCODED_BIT_SIZE ((HID_PREAMBLE_SIZE + HID_DATA_SIZE) * 8)
#define HID_DECODED_DATA_SIZE (6)
#define HID_DECODED_BIT_SIZE ((HID_ENCODED_BIT_SIZE - HID_PREAMBLE_SIZE * 8) / 2)
#define HID_PREAMBLE 0x1D
typedef struct {
FSKDemod* fsk_demod;
} ProtocolHIDDecoder;
typedef struct {
FSKOsc* fsk_osc;
uint8_t encoded_index;
uint32_t pulse;
} ProtocolHIDEncoder;
typedef struct {
ProtocolHIDDecoder decoder;
ProtocolHIDEncoder encoder;
uint8_t encoded_data[HID_ENCODED_DATA_SIZE];
uint8_t data[HID_DECODED_DATA_SIZE];
} ProtocolHID;
ProtocolHID* protocol_hid_generic_alloc(void) {
ProtocolHID* protocol = malloc(sizeof(ProtocolHID));
protocol->decoder.fsk_demod = fsk_demod_alloc(MIN_TIME, 6, MAX_TIME, 5);
protocol->encoder.fsk_osc = fsk_osc_alloc(8, 10, 50);
return protocol;
};
void protocol_hid_generic_free(ProtocolHID* protocol) {
fsk_demod_free(protocol->decoder.fsk_demod);
fsk_osc_free(protocol->encoder.fsk_osc);
free(protocol);
};
uint8_t* protocol_hid_generic_get_data(ProtocolHID* protocol) {
return protocol->data;
};
void protocol_hid_generic_decoder_start(ProtocolHID* protocol) {
memset(protocol->encoded_data, 0, HID_ENCODED_DATA_SIZE);
};
static bool protocol_hid_generic_can_be_decoded(const uint8_t* data) {
// check preamble
if(data[0] != HID_PREAMBLE || data[HID_PREAMBLE_SIZE + HID_DATA_SIZE] != HID_PREAMBLE) {
return false;
}
// check for manchester encoding
for(size_t i = HID_PREAMBLE_SIZE; i < (HID_PREAMBLE_SIZE + HID_DATA_SIZE); i++) {
for(size_t n = 0; n < 4; n++) {
uint8_t bit_pair = (data[i] >> (n * 2)) & 0b11;
if(bit_pair == 0b11 || bit_pair == 0b00) {
return false;
}
}
}
return true;
}
static void protocol_hid_generic_decode(const uint8_t* from, uint8_t* to) {
size_t bit_index = 0;
for(size_t i = HID_PREAMBLE_SIZE; i < (HID_PREAMBLE_SIZE + HID_DATA_SIZE); i++) {
for(size_t n = 0; n < 4; n++) {
uint8_t bit_pair = (from[i] >> (6 - (n * 2))) & 0b11;
if(bit_pair == 0b01) {
bit_lib_set_bit(to, bit_index, 0);
} else if(bit_pair == 0b10) {
bit_lib_set_bit(to, bit_index, 1);
}
bit_index++;
}
}
}
/**
* Decodes size from the HID Proximity header:
* - If any of the first six bits is 1, the key is composed of the bits
* following the first 1
* - Otherwise, if the first six bits are 0:
* - If the seventh bit is 0, the key is composed of the remaining 37 bits.
* - If the seventh bit is 1, the size header continues until the next 1 bit,
* and the key is composed of however many bits remain.
*
* HID Proximity keys are 26 bits at minimum. If the header implies a key size
* under 26 bits, this function returns HID_PROTOCOL_SIZE_UNKNOWN.
*/
static uint8_t protocol_hid_generic_decode_protocol_size(ProtocolHID* protocol) {
for(size_t bit_index = 0; bit_index < 6; bit_index++) {
if(bit_lib_get_bit(protocol->data, bit_index)) {
return HID_DECODED_BIT_SIZE - bit_index - 1;
}
}
if(!bit_lib_get_bit(protocol->data, 6)) {
return 37;
}
size_t bit_index = 7;
uint8_t size = 36;
while(!bit_lib_get_bit(protocol->data, bit_index) && size >= 26) {
size--;
bit_index++;
}
return size < 26 ? HID_PROTOCOL_SIZE_UNKNOWN : size;
}
bool protocol_hid_generic_decoder_feed(ProtocolHID* protocol, bool level, uint32_t duration) {
bool value;
uint32_t count;
bool result = false;
fsk_demod_feed(protocol->decoder.fsk_demod, level, duration, &value, &count);
if(count > 0) {
for(size_t i = 0; i < count; i++) {
bit_lib_push_bit(protocol->encoded_data, HID_ENCODED_DATA_SIZE, value);
if(protocol_hid_generic_can_be_decoded(protocol->encoded_data)) {
protocol_hid_generic_decode(protocol->encoded_data, protocol->data);
result = true;
}
}
}
return result;
};
static void protocol_hid_generic_encode(ProtocolHID* protocol) {
protocol->encoded_data[0] = HID_PREAMBLE;
size_t bit_index = 0;
for(size_t i = 0; i < HID_DECODED_BIT_SIZE; i++) {
bool bit = bit_lib_get_bit(protocol->data, i);
if(bit) {
bit_lib_set_bit(protocol->encoded_data, 8 + bit_index, 1);
bit_lib_set_bit(protocol->encoded_data, 8 + bit_index + 1, 0);
} else {
bit_lib_set_bit(protocol->encoded_data, 8 + bit_index, 0);
bit_lib_set_bit(protocol->encoded_data, 8 + bit_index + 1, 1);
}
bit_index += 2;
}
}
bool protocol_hid_generic_encoder_start(ProtocolHID* protocol) {
protocol->encoder.encoded_index = 0;
protocol->encoder.pulse = 0;
protocol_hid_generic_encode(protocol);
return true;
};
LevelDuration protocol_hid_generic_encoder_yield(ProtocolHID* protocol) {
bool level = 0;
uint32_t duration = 0;
// if pulse is zero, we need to output high, otherwise we need to output low
if(protocol->encoder.pulse == 0) {
// get bit
uint8_t bit = bit_lib_get_bit(protocol->encoded_data, protocol->encoder.encoded_index);
// get pulse from oscillator
bool advance = fsk_osc_next(protocol->encoder.fsk_osc, bit, &duration);
if(advance) {
bit_lib_increment_index(protocol->encoder.encoded_index, HID_ENCODED_BIT_SIZE);
}
// duration diveded by 2 because we need to output high and low
duration = duration / 2;
protocol->encoder.pulse = duration;
level = true;
} else {
// output low half and reset pulse
duration = protocol->encoder.pulse;
protocol->encoder.pulse = 0;
level = false;
}
return level_duration_make(level, duration);
};
bool protocol_hid_generic_write_data(ProtocolHID* protocol, void* data) {
LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data;
bool result = false;
protocol_hid_generic_encoder_start(protocol);
if(request->write_type == LFRFIDWriteTypeT5577) {
request->t5577.block[0] = LFRFID_T5577_MODULATION_FSK2a | LFRFID_T5577_BITRATE_RF_50 |
(3 << LFRFID_T5577_MAXBLOCK_SHIFT);
request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32);
request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32);
request->t5577.block[3] = bit_lib_get_bits_32(protocol->encoded_data, 64, 32);
request->t5577.blocks_to_write = 4;
result = true;
}
return result;
};
static void protocol_hid_generic_string_cat_protocol_bits(ProtocolHID* protocol, uint8_t protocol_size, string_t result) {
// round up to the nearest nibble
const uint8_t hex_character_count = (protocol_size + 3) / 4;
const uint8_t protocol_bit_index = HID_DECODED_BIT_SIZE - protocol_size;
for(size_t i = 0; i < hex_character_count; i++) {
uint8_t nibble =
i == 0 ? bit_lib_get_bits(
protocol->data, protocol_bit_index, protocol_size % 4 == 0 ? 4 : protocol_size % 4) :
bit_lib_get_bits(protocol->data, protocol_bit_index + i * 4, 4);
string_cat_printf(result, "%X", nibble & 0xF);
}
}
void protocol_hid_generic_render_data(ProtocolHID* protocol, string_t result) {
const uint8_t protocol_size = protocol_hid_generic_decode_protocol_size(protocol);
if(protocol_size == HID_PROTOCOL_SIZE_UNKNOWN) {
string_printf(
result,
"Generic HID Proximity\r\n"
"Data: %02X%02X%02X%02X%02X%X",
protocol->data[0],
protocol->data[1],
protocol->data[2],
protocol->data[3],
protocol->data[4],
protocol->data[5] >> 4);
} else {
string_printf(
result,
"%hhu-bit HID Proximity\r\n"
"Data: ",
protocol_size);
protocol_hid_generic_string_cat_protocol_bits(protocol, protocol_size, result);
}
};
const ProtocolBase protocol_hid_generic = {
.name = "HIDProx",
.manufacturer = "Generic",
.data_size = HID_DECODED_DATA_SIZE,
.features = LFRFIDFeatureASK,
.validate_count = 6,
.alloc = (ProtocolAlloc)protocol_hid_generic_alloc,
.free = (ProtocolFree)protocol_hid_generic_free,
.get_data = (ProtocolGetData)protocol_hid_generic_get_data,
.decoder =
{
.start = (ProtocolDecoderStart)protocol_hid_generic_decoder_start,
.feed = (ProtocolDecoderFeed)protocol_hid_generic_decoder_feed,
},
.encoder =
{
.start = (ProtocolEncoderStart)protocol_hid_generic_encoder_start,
.yield = (ProtocolEncoderYield)protocol_hid_generic_encoder_yield,
},
.render_data = (ProtocolRenderData)protocol_hid_generic_render_data,
.render_brief_data = (ProtocolRenderData)protocol_hid_generic_render_data,
.write_data = (ProtocolWriteData)protocol_hid_generic_write_data,
};

View File

@@ -0,0 +1,4 @@
#pragma once
#include <toolbox/protocols/protocol.h>
extern const ProtocolBase protocol_hid_generic;

View File

@@ -0,0 +1,353 @@
#include <furi.h>
#include <toolbox/protocols/protocol.h>
#include <lfrfid/tools/bit_lib.h>
#include "lfrfid_protocols.h"
#define INDALA26_PREAMBLE_BIT_SIZE (33)
#define INDALA26_PREAMBLE_DATA_SIZE (5)
#define INDALA26_ENCODED_BIT_SIZE (64)
#define INDALA26_ENCODED_DATA_SIZE \
(((INDALA26_ENCODED_BIT_SIZE) / 8) + INDALA26_PREAMBLE_DATA_SIZE)
#define INDALA26_ENCODED_DATA_LAST ((INDALA26_ENCODED_BIT_SIZE) / 8)
#define INDALA26_DECODED_BIT_SIZE (28)
#define INDALA26_DECODED_DATA_SIZE (4)
#define INDALA26_US_PER_BIT (255)
#define INDALA26_ENCODER_PULSES_PER_BIT (16)
typedef struct {
uint8_t data_index;
uint8_t bit_clock_index;
bool last_bit;
bool current_polarity;
bool pulse_phase;
} ProtocolIndalaEncoder;
typedef struct {
uint8_t encoded_data[INDALA26_ENCODED_DATA_SIZE];
uint8_t negative_encoded_data[INDALA26_ENCODED_DATA_SIZE];
uint8_t corrupted_encoded_data[INDALA26_ENCODED_DATA_SIZE];
uint8_t corrupted_negative_encoded_data[INDALA26_ENCODED_DATA_SIZE];
uint8_t data[INDALA26_DECODED_DATA_SIZE];
ProtocolIndalaEncoder encoder;
} ProtocolIndala;
ProtocolIndala* protocol_indala26_alloc(void) {
ProtocolIndala* protocol = malloc(sizeof(ProtocolIndala));
return protocol;
};
void protocol_indala26_free(ProtocolIndala* protocol) {
free(protocol);
};
uint8_t* protocol_indala26_get_data(ProtocolIndala* protocol) {
return protocol->data;
};
void protocol_indala26_decoder_start(ProtocolIndala* protocol) {
memset(protocol->encoded_data, 0, INDALA26_ENCODED_DATA_SIZE);
memset(protocol->negative_encoded_data, 0, INDALA26_ENCODED_DATA_SIZE);
memset(protocol->corrupted_encoded_data, 0, INDALA26_ENCODED_DATA_SIZE);
memset(protocol->corrupted_negative_encoded_data, 0, INDALA26_ENCODED_DATA_SIZE);
};
static bool protocol_indala26_check_preamble(uint8_t* data, size_t bit_index) {
// Preamble 10100000 00000000 00000000 00000000 1
if(*(uint32_t*)&data[bit_index / 8] != 0b00000000000000000000000010100000) return false;
if(bit_lib_get_bit(data, bit_index + 32) != 1) return false;
return true;
}
static bool protocol_indala26_can_be_decoded(uint8_t* data) {
if(!protocol_indala26_check_preamble(data, 0)) return false;
if(!protocol_indala26_check_preamble(data, 64)) return false;
if(bit_lib_get_bit(data, 61) != 0) return false;
if(bit_lib_get_bit(data, 60) != 0) return false;
return true;
}
static bool protocol_indala26_decoder_feed_internal(bool polarity, uint32_t time, uint8_t* data) {
time += (INDALA26_US_PER_BIT / 2);
size_t bit_count = (time / INDALA26_US_PER_BIT);
bool result = false;
if(bit_count < INDALA26_ENCODED_BIT_SIZE) {
for(size_t i = 0; i < bit_count; i++) {
bit_lib_push_bit(data, INDALA26_ENCODED_DATA_SIZE, polarity);
if(protocol_indala26_can_be_decoded(data)) {
result = true;
break;
}
}
}
return result;
}
static void protocol_indala26_decoder_save(uint8_t* data_to, const uint8_t* data_from) {
bit_lib_copy_bits(data_to, 0, 22, data_from, 33);
bit_lib_copy_bits(data_to, 22, 5, data_from, 55);
bit_lib_copy_bits(data_to, 27, 2, data_from, 62);
}
bool protocol_indala26_decoder_feed(ProtocolIndala* protocol, bool level, uint32_t duration) {
bool result = false;
if(duration > (INDALA26_US_PER_BIT / 2)) {
if(protocol_indala26_decoder_feed_internal(level, duration, protocol->encoded_data)) {
protocol_indala26_decoder_save(protocol->data, protocol->encoded_data);
FURI_LOG_D("Indala26", "Positive");
result = true;
return result;
}
if(protocol_indala26_decoder_feed_internal(
!level, duration, protocol->negative_encoded_data)) {
protocol_indala26_decoder_save(protocol->data, protocol->negative_encoded_data);
FURI_LOG_D("Indala26", "Negative");
result = true;
return result;
}
}
if(duration > (INDALA26_US_PER_BIT / 4)) {
// Try to decode wrong phase synced data
if(level) {
duration += 120;
} else {
if(duration > 120) {
duration -= 120;
}
}
if(protocol_indala26_decoder_feed_internal(
level, duration, protocol->corrupted_encoded_data)) {
protocol_indala26_decoder_save(protocol->data, protocol->corrupted_encoded_data);
FURI_LOG_D("Indala26", "Positive Corrupted");
result = true;
return result;
}
if(protocol_indala26_decoder_feed_internal(
!level, duration, protocol->corrupted_negative_encoded_data)) {
protocol_indala26_decoder_save(
protocol->data, protocol->corrupted_negative_encoded_data);
FURI_LOG_D("Indala26", "Negative Corrupted");
result = true;
return result;
}
}
return result;
};
bool protocol_indala26_encoder_start(ProtocolIndala* protocol) {
memset(protocol->encoded_data, 0, INDALA26_ENCODED_DATA_SIZE);
*(uint32_t*)&protocol->encoded_data[0] = 0b00000000000000000000000010100000;
bit_lib_set_bit(protocol->encoded_data, 32, 1);
bit_lib_copy_bits(protocol->encoded_data, 33, 22, protocol->data, 0);
bit_lib_copy_bits(protocol->encoded_data, 55, 5, protocol->data, 22);
bit_lib_copy_bits(protocol->encoded_data, 62, 2, protocol->data, 27);
protocol->encoder.last_bit =
bit_lib_get_bit(protocol->encoded_data, INDALA26_ENCODED_BIT_SIZE - 1);
protocol->encoder.data_index = 0;
protocol->encoder.current_polarity = true;
protocol->encoder.pulse_phase = true;
protocol->encoder.bit_clock_index = 0;
return true;
};
LevelDuration protocol_indala26_encoder_yield(ProtocolIndala* protocol) {
LevelDuration level_duration;
ProtocolIndalaEncoder* encoder = &protocol->encoder;
if(encoder->pulse_phase) {
level_duration = level_duration_make(encoder->current_polarity, 1);
encoder->pulse_phase = false;
} else {
level_duration = level_duration_make(!encoder->current_polarity, 1);
encoder->pulse_phase = true;
encoder->bit_clock_index++;
if(encoder->bit_clock_index >= INDALA26_ENCODER_PULSES_PER_BIT) {
encoder->bit_clock_index = 0;
bool current_bit = bit_lib_get_bit(protocol->encoded_data, encoder->data_index);
if(current_bit != encoder->last_bit) {
encoder->current_polarity = !encoder->current_polarity;
}
encoder->last_bit = current_bit;
bit_lib_increment_index(encoder->data_index, INDALA26_ENCODED_BIT_SIZE);
}
}
return level_duration;
};
// factory code
static uint8_t get_fc(const uint8_t* data) {
uint8_t fc = 0;
fc = fc << 1 | bit_lib_get_bit(data, 24);
fc = fc << 1 | bit_lib_get_bit(data, 16);
fc = fc << 1 | bit_lib_get_bit(data, 11);
fc = fc << 1 | bit_lib_get_bit(data, 14);
fc = fc << 1 | bit_lib_get_bit(data, 15);
fc = fc << 1 | bit_lib_get_bit(data, 20);
fc = fc << 1 | bit_lib_get_bit(data, 6);
fc = fc << 1 | bit_lib_get_bit(data, 25);
return fc;
}
// card number
static uint16_t get_cn(const uint8_t* data) {
uint16_t cn = 0;
cn = cn << 1 | bit_lib_get_bit(data, 9);
cn = cn << 1 | bit_lib_get_bit(data, 12);
cn = cn << 1 | bit_lib_get_bit(data, 10);
cn = cn << 1 | bit_lib_get_bit(data, 7);
cn = cn << 1 | bit_lib_get_bit(data, 19);
cn = cn << 1 | bit_lib_get_bit(data, 3);
cn = cn << 1 | bit_lib_get_bit(data, 2);
cn = cn << 1 | bit_lib_get_bit(data, 18);
cn = cn << 1 | bit_lib_get_bit(data, 13);
cn = cn << 1 | bit_lib_get_bit(data, 0);
cn = cn << 1 | bit_lib_get_bit(data, 4);
cn = cn << 1 | bit_lib_get_bit(data, 21);
cn = cn << 1 | bit_lib_get_bit(data, 23);
cn = cn << 1 | bit_lib_get_bit(data, 26);
cn = cn << 1 | bit_lib_get_bit(data, 17);
cn = cn << 1 | bit_lib_get_bit(data, 8);
return cn;
}
void protocol_indala26_render_data_internal(ProtocolIndala* protocol, string_t result, bool brief) {
bool wiegand_correct = true;
bool checksum_correct = true;
const uint8_t fc = get_fc(protocol->data);
const uint16_t card = get_cn(protocol->data);
const uint32_t fc_and_card = fc << 16 | card;
const uint8_t checksum = bit_lib_get_bit(protocol->data, 27) << 1 |
bit_lib_get_bit(protocol->data, 28);
const bool even_parity = bit_lib_get_bit(protocol->data, 1);
const bool odd_parity = bit_lib_get_bit(protocol->data, 5);
// indala checksum
uint8_t checksum_sum = 0;
checksum_sum += ((fc_and_card >> 14) & 1);
checksum_sum += ((fc_and_card >> 12) & 1);
checksum_sum += ((fc_and_card >> 9) & 1);
checksum_sum += ((fc_and_card >> 8) & 1);
checksum_sum += ((fc_and_card >> 6) & 1);
checksum_sum += ((fc_and_card >> 5) & 1);
checksum_sum += ((fc_and_card >> 2) & 1);
checksum_sum += ((fc_and_card >> 0) & 1);
checksum_sum = checksum_sum & 0b1;
if(checksum_sum == 1 && checksum == 0b01) {
} else if(checksum_sum == 0 && checksum == 0b10) {
} else {
checksum_correct = false;
}
// wiegand parity
uint8_t even_parity_sum = 0;
for(int8_t i = 12; i < 24; i++) {
if(((fc_and_card >> i) & 1) == 1) {
even_parity_sum++;
}
}
if(even_parity_sum % 2 != even_parity) wiegand_correct = false;
uint8_t odd_parity_sum = 1;
for(int8_t i = 0; i < 12; i++) {
if(((fc_and_card >> i) & 1) == 1) {
odd_parity_sum++;
}
}
if(odd_parity_sum % 2 != odd_parity) wiegand_correct = false;
if(brief) {
string_printf(
result,
"FC: %u\r\nCard: %u, Parity:%s%s",
fc,
card,
(checksum_correct ? "+" : "-"),
(wiegand_correct ? "+" : "-"));
} else {
string_printf(
result,
"FC: %u\r\n"
"Card: %u\r\n"
"Checksum: %s\r\n"
"W26 Parity: %s",
fc,
card,
(checksum_correct ? "+" : "-"),
(wiegand_correct ? "+" : "-"));
}
}
void protocol_indala26_render_data(ProtocolIndala* protocol, string_t result) {
protocol_indala26_render_data_internal(protocol, result, false);
}
void protocol_indala26_render_brief_data(ProtocolIndala* protocol, string_t result) {
protocol_indala26_render_data_internal(protocol, result, true);
}
bool protocol_indala26_write_data(ProtocolIndala* protocol, void* data) {
LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data;
bool result = false;
protocol_indala26_encoder_start(protocol);
if(request->write_type == LFRFIDWriteTypeT5577) {
request->t5577.block[0] = LFRFID_T5577_BITRATE_RF_32 | LFRFID_T5577_MODULATION_PSK1 |
(2 << LFRFID_T5577_MAXBLOCK_SHIFT);
request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32);
request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32);
request->t5577.blocks_to_write = 3;
result = true;
}
return result;
};
const ProtocolBase protocol_indala26 = {
.name = "Indala26",
.manufacturer = "Motorola",
.data_size = INDALA26_DECODED_DATA_SIZE,
.features = LFRFIDFeaturePSK,
.validate_count = 6,
.alloc = (ProtocolAlloc)protocol_indala26_alloc,
.free = (ProtocolFree)protocol_indala26_free,
.get_data = (ProtocolGetData)protocol_indala26_get_data,
.decoder =
{
.start = (ProtocolDecoderStart)protocol_indala26_decoder_start,
.feed = (ProtocolDecoderFeed)protocol_indala26_decoder_feed,
},
.encoder =
{
.start = (ProtocolEncoderStart)protocol_indala26_encoder_start,
.yield = (ProtocolEncoderYield)protocol_indala26_encoder_yield,
},
.render_data = (ProtocolRenderData)protocol_indala26_render_data,
.render_brief_data = (ProtocolRenderData)protocol_indala26_render_brief_data,
.write_data = (ProtocolWriteData)protocol_indala26_write_data,
};

View File

@@ -0,0 +1,4 @@
#pragma once
#include <toolbox/protocols/protocol.h>
extern const ProtocolBase protocol_indala26;

View File

@@ -0,0 +1,297 @@
#include <furi.h>
#include <toolbox/protocols/protocol.h>
#include <lfrfid/tools/fsk_demod.h>
#include <lfrfid/tools/fsk_osc.h>
#include <lfrfid/tools/bit_lib.h>
#include "lfrfid_protocols.h"
#define JITTER_TIME (20)
#define MIN_TIME (64 - JITTER_TIME)
#define MAX_TIME (80 + JITTER_TIME)
#define IOPROXXSF_DECODED_DATA_SIZE (4)
#define IOPROXXSF_ENCODED_DATA_SIZE (8)
#define IOPROXXSF_BIT_SIZE (8)
#define IOPROXXSF_BIT_MAX_SIZE (IOPROXXSF_BIT_SIZE * IOPROXXSF_ENCODED_DATA_SIZE)
typedef struct {
FSKDemod* fsk_demod;
} ProtocolIOProxXSFDecoder;
typedef struct {
FSKOsc* fsk_osc;
uint8_t encoded_index;
} ProtocolIOProxXSFEncoder;
typedef struct {
ProtocolIOProxXSFEncoder encoder;
ProtocolIOProxXSFDecoder decoder;
uint8_t encoded_data[IOPROXXSF_ENCODED_DATA_SIZE];
uint8_t data[IOPROXXSF_DECODED_DATA_SIZE];
} ProtocolIOProxXSF;
ProtocolIOProxXSF* protocol_io_prox_xsf_alloc(void) {
ProtocolIOProxXSF* protocol = malloc(sizeof(ProtocolIOProxXSF));
protocol->decoder.fsk_demod = fsk_demod_alloc(MIN_TIME, 8, MAX_TIME, 6);
protocol->encoder.fsk_osc = fsk_osc_alloc(8, 10, 64);
return protocol;
};
void protocol_io_prox_xsf_free(ProtocolIOProxXSF* protocol) {
fsk_demod_free(protocol->decoder.fsk_demod);
fsk_osc_free(protocol->encoder.fsk_osc);
free(protocol);
};
uint8_t* protocol_io_prox_xsf_get_data(ProtocolIOProxXSF* protocol) {
return protocol->data;
};
void protocol_io_prox_xsf_decoder_start(ProtocolIOProxXSF* protocol) {
memset(protocol->encoded_data, 0, IOPROXXSF_ENCODED_DATA_SIZE);
};
static uint8_t protocol_io_prox_xsf_compute_checksum(const uint8_t* data) {
// Packet structure:
//
//0 1 2 3 4 5 6 7
//v v v v v v v v
//01234567 8 9ABCDEF0 1 23456789 A BCDEF012 3 456789AB C DEF01234 5 6789ABCD EF
//00000000 0 VVVVVVVV 1 WWWWWWWW 1 XXXXXXXX 1 YYYYYYYY 1 ZZZZZZZZ 1 CHECKSUM 11
//
// algorithm as observed by the proxmark3 folks
// CHECKSUM == 0xFF - (V + W + X + Y + Z)
uint8_t checksum = 0;
for(size_t i = 1; i <= 5; i++) {
checksum += bit_lib_get_bits(data, 9 * i, 8);
}
return 0xFF - checksum;
}
static bool protocol_io_prox_xsf_can_be_decoded(const uint8_t* encoded_data) {
// Packet framing
//
//0 1 2 3 4 5 6 7
//v v v v v v v v
//01234567 89ABCDEF 01234567 89ABCDEF 01234567 89ABCDEF 01234567 89ABCDEF
//-----------------------------------------------------------------------
//00000000 01______ _1______ __1_____ ___1____ ____1___ _____1XX XXXXXX11
//
// _ = variable data
// 0 = preamble 0
// 1 = framing 1
// X = checksum
// Validate the packet preamble is there...
if(encoded_data[0] != 0b00000000) {
return false;
}
if((encoded_data[1] >> 6) != 0b01) {
return false;
}
// ... check for known ones...
if(bit_lib_bit_is_not_set(encoded_data[2], 6)) {
return false;
}
if(bit_lib_bit_is_not_set(encoded_data[3], 5)) {
return false;
}
if(bit_lib_bit_is_not_set(encoded_data[4], 4)) {
return false;
}
if(bit_lib_bit_is_not_set(encoded_data[5], 3)) {
return false;
}
if(bit_lib_bit_is_not_set(encoded_data[6], 2)) {
return false;
}
if(bit_lib_bit_is_not_set(encoded_data[7], 1)) {
return false;
}
if(bit_lib_bit_is_not_set(encoded_data[7], 0)) {
return false;
}
// ... and validate our checksums.
uint8_t checksum = protocol_io_prox_xsf_compute_checksum(encoded_data);
uint8_t checkval = bit_lib_get_bits(encoded_data, 54, 8);
if(checksum != checkval) {
return false;
}
return true;
}
void protocol_io_prox_xsf_decode(const uint8_t* encoded_data, uint8_t* decoded_data) {
// Packet structure:
// (Note: the second word seems fixed; but this may not be a guarantee;
// it currently has no meaning.)
//
//0 1 2 3 4 5 6 7
//v v v v v v v v
//01234567 89ABCDEF 01234567 89ABCDEF 01234567 89ABCDEF 01234567 89ABCDEF
//-----------------------------------------------------------------------
//00000000 01111000 01FFFFFF FF1VVVVV VVV1CCCC CCCC1CCC CCCCC1XX XXXXXX11
//
// F = facility code
// V = version
// C = code
// X = checksum
// Facility code
decoded_data[0] = bit_lib_get_bits(encoded_data, 18, 8);
// Version code.
decoded_data[1] = bit_lib_get_bits(encoded_data, 27, 8);
// Code bytes.
decoded_data[2] = bit_lib_get_bits(encoded_data, 36, 8);
decoded_data[3] = bit_lib_get_bits(encoded_data, 45, 8);
}
bool protocol_io_prox_xsf_decoder_feed(ProtocolIOProxXSF* protocol, bool level, uint32_t duration) {
bool result = false;
uint32_t count;
bool value;
fsk_demod_feed(protocol->decoder.fsk_demod, level, duration, &value, &count);
for(size_t i = 0; i < count; i++) {
bit_lib_push_bit(protocol->encoded_data, IOPROXXSF_ENCODED_DATA_SIZE, value);
if(protocol_io_prox_xsf_can_be_decoded(protocol->encoded_data)) {
protocol_io_prox_xsf_decode(protocol->encoded_data, protocol->data);
result = true;
break;
}
}
return result;
};
static void protocol_io_prox_xsf_encode(const uint8_t* decoded_data, uint8_t* encoded_data) {
// Packet to transmit:
//
// 0 10 20 30 40 50 60
// v v v v v v v
// 01234567 8 90123456 7 89012345 6 78901234 5 67890123 4 56789012 3 45678901 23
// -----------------------------------------------------------------------------
// 00000000 0 11110000 1 facility 1 version_ 1 code-one 1 code-two 1 checksum 11
// Preamble.
bit_lib_set_bits(encoded_data, 0, 0b00000000, 8);
bit_lib_set_bit(encoded_data, 8, 0);
bit_lib_set_bits(encoded_data, 9, 0b11110000, 8);
bit_lib_set_bit(encoded_data, 17, 1);
// Facility code.
bit_lib_set_bits(encoded_data, 18, decoded_data[0], 8);
bit_lib_set_bit(encoded_data, 26, 1);
// Version
bit_lib_set_bits(encoded_data, 27, decoded_data[1], 8);
bit_lib_set_bit(encoded_data, 35, 1);
// Code one
bit_lib_set_bits(encoded_data, 36, decoded_data[2], 8);
bit_lib_set_bit(encoded_data, 44, 1);
// Code two
bit_lib_set_bits(encoded_data, 45, decoded_data[3], 8);
bit_lib_set_bit(encoded_data, 53, 1);
// Checksum
bit_lib_set_bits(encoded_data, 54, protocol_io_prox_xsf_compute_checksum(encoded_data), 8);
bit_lib_set_bit(encoded_data, 62, 1);
bit_lib_set_bit(encoded_data, 63, 1);
}
bool protocol_io_prox_xsf_encoder_start(ProtocolIOProxXSF* protocol) {
protocol_io_prox_xsf_encode(protocol->data, protocol->encoded_data);
protocol->encoder.encoded_index = 0;
fsk_osc_reset(protocol->encoder.fsk_osc);
return true;
};
LevelDuration protocol_io_prox_xsf_encoder_yield(ProtocolIOProxXSF* protocol) {
bool level;
uint32_t duration;
bool bit = bit_lib_get_bit(protocol->encoded_data, protocol->encoder.encoded_index);
bool advance = fsk_osc_next_half(protocol->encoder.fsk_osc, bit, &level, &duration);
if(advance) {
bit_lib_increment_index(protocol->encoder.encoded_index, IOPROXXSF_BIT_MAX_SIZE);
}
return level_duration_make(level, duration);
};
void protocol_io_prox_xsf_render_data(ProtocolIOProxXSF* protocol, string_t result) {
uint8_t* data = protocol->data;
string_printf(
result,
"FC: %u\r\n"
"VС: %u\r\n"
"Card: %u",
data[0],
data[1],
(uint16_t)((data[2] << 8) | (data[3])));
}
void protocol_io_prox_xsf_render_brief_data(ProtocolIOProxXSF* protocol, string_t result) {
uint8_t* data = protocol->data;
string_printf(
result,
"FC: %u, VС: %u\r\n"
"Card: %u",
data[0],
data[1],
(uint16_t)((data[2] << 8) | (data[3])));
}
bool protocol_io_prox_xsf_write_data(ProtocolIOProxXSF* protocol, void* data) {
LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data;
bool result = false;
protocol_io_prox_xsf_encode(protocol->data, protocol->encoded_data);
if(request->write_type == LFRFIDWriteTypeT5577) {
request->t5577.block[0] = LFRFID_T5577_MODULATION_FSK2a | LFRFID_T5577_BITRATE_RF_64 |
(2 << LFRFID_T5577_MAXBLOCK_SHIFT);
request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32);
request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32);
request->t5577.blocks_to_write = 3;
result = true;
}
return result;
};
const ProtocolBase protocol_io_prox_xsf = {
.name = "IoProxXSF",
.manufacturer = "Kantech",
.data_size = IOPROXXSF_DECODED_DATA_SIZE,
.features = LFRFIDFeatureASK,
.validate_count = 3,
.alloc = (ProtocolAlloc)protocol_io_prox_xsf_alloc,
.free = (ProtocolFree)protocol_io_prox_xsf_free,
.get_data = (ProtocolGetData)protocol_io_prox_xsf_get_data,
.decoder =
{
.start = (ProtocolDecoderStart)protocol_io_prox_xsf_decoder_start,
.feed = (ProtocolDecoderFeed)protocol_io_prox_xsf_decoder_feed,
},
.encoder =
{
.start = (ProtocolEncoderStart)protocol_io_prox_xsf_encoder_start,
.yield = (ProtocolEncoderYield)protocol_io_prox_xsf_encoder_yield,
},
.render_data = (ProtocolRenderData)protocol_io_prox_xsf_render_data,
.render_brief_data = (ProtocolRenderData)protocol_io_prox_xsf_render_brief_data,
.write_data = (ProtocolWriteData)protocol_io_prox_xsf_write_data,
};

View File

@@ -0,0 +1,4 @@
#pragma once
#include <toolbox/protocols/protocol.h>
extern const ProtocolBase protocol_io_prox_xsf;

291
lib/lfrfid/tools/bit_lib.c Normal file
View File

@@ -0,0 +1,291 @@
#include "bit_lib.h"
#include <core/check.h>
#include <stdio.h>
void bit_lib_push_bit(uint8_t* data, size_t data_size, bool bit) {
size_t last_index = data_size - 1;
for(size_t i = 0; i < last_index; ++i) {
data[i] = (data[i] << 1) | ((data[i + 1] >> 7) & 1);
}
data[last_index] = (data[last_index] << 1) | bit;
}
void bit_lib_set_bit(uint8_t* data, size_t position, bool bit) {
if(bit) {
data[position / 8] |= 1UL << (7 - (position % 8));
} else {
data[position / 8] &= ~(1UL << (7 - (position % 8)));
}
}
void bit_lib_set_bits(uint8_t* data, size_t position, uint8_t byte, uint8_t length) {
furi_check(length <= 8);
furi_check(length > 0);
for(uint8_t i = 0; i < length; ++i) {
uint8_t shift = (length - 1) - i;
bit_lib_set_bit(data, position + i, (byte >> shift) & 1);
}
}
bool bit_lib_get_bit(const uint8_t* data, size_t position) {
return (data[position / 8] >> (7 - (position % 8))) & 1;
}
uint8_t bit_lib_get_bits(const uint8_t* data, size_t position, uint8_t length) {
uint8_t shift = position % 8;
if(shift == 0) {
return data[position / 8] >> (8 - length);
} else {
// TODO fix read out of bounds
uint8_t value = (data[position / 8] << (shift));
value |= data[position / 8 + 1] >> (8 - shift);
value = value >> (8 - length);
return value;
}
}
uint16_t bit_lib_get_bits_16(const uint8_t* data, size_t position, uint8_t length) {
uint16_t value = 0;
if(length <= 8) {
value = bit_lib_get_bits(data, position, length);
} else {
value = bit_lib_get_bits(data, position, 8) << (length - 8);
value |= bit_lib_get_bits(data, position + 8, length - 8);
}
return value;
}
uint32_t bit_lib_get_bits_32(const uint8_t* data, size_t position, uint8_t length) {
uint32_t value = 0;
if(length <= 8) {
value = bit_lib_get_bits(data, position, length);
} else if(length <= 16) {
value = bit_lib_get_bits(data, position, 8) << (length - 8);
value |= bit_lib_get_bits(data, position + 8, length - 8);
} else if(length <= 24) {
value = bit_lib_get_bits(data, position, 8) << (length - 8);
value |= bit_lib_get_bits(data, position + 8, 8) << (length - 16);
value |= bit_lib_get_bits(data, position + 16, length - 16);
} else {
value = bit_lib_get_bits(data, position, 8) << (length - 8);
value |= bit_lib_get_bits(data, position + 8, 8) << (length - 16);
value |= bit_lib_get_bits(data, position + 16, 8) << (length - 24);
value |= bit_lib_get_bits(data, position + 24, length - 24);
}
return value;
}
bool bit_lib_test_parity_32(uint32_t bits, BitLibParity parity) {
#if !defined __GNUC__
#error Please, implement parity test for non-GCC compilers
#else
switch(parity) {
case BitLibParityEven:
return __builtin_parity(bits);
case BitLibParityOdd:
return !__builtin_parity(bits);
default:
furi_crash("Unknown parity");
}
#endif
}
bool bit_lib_test_parity(
const uint8_t* bits,
size_t position,
uint8_t length,
BitLibParity parity,
uint8_t parity_length) {
uint32_t parity_block;
bool result = true;
const size_t parity_blocks_count = length / parity_length;
for(size_t i = 0; i < parity_blocks_count; ++i) {
switch(parity) {
case BitLibParityEven:
case BitLibParityOdd:
parity_block = bit_lib_get_bits_32(bits, position + i * parity_length, parity_length);
if(!bit_lib_test_parity_32(parity_block, parity)) {
result = false;
}
break;
case BitLibParityAlways0:
if(bit_lib_get_bit(bits, position + i * parity_length + parity_length - 1)) {
result = false;
}
break;
case BitLibParityAlways1:
if(!bit_lib_get_bit(bits, position + i * parity_length + parity_length - 1)) {
result = false;
}
break;
}
if(!result) break;
}
return result;
}
size_t bit_lib_remove_bit_every_nth(uint8_t* data, size_t position, uint8_t length, uint8_t n) {
size_t counter = 0;
size_t result_counter = 0;
uint8_t bit_buffer = 0;
uint8_t bit_counter = 0;
while(counter < length) {
if((counter + 1) % n != 0) {
bit_buffer = (bit_buffer << 1) | bit_lib_get_bit(data, position + counter);
bit_counter++;
}
if(bit_counter == 8) {
bit_lib_set_bits(data, position + result_counter, bit_buffer, 8);
bit_counter = 0;
bit_buffer = 0;
result_counter += 8;
}
counter++;
}
if(bit_counter != 0) {
bit_lib_set_bits(data, position + result_counter, bit_buffer, bit_counter);
result_counter += bit_counter;
}
return result_counter;
}
void bit_lib_copy_bits(
uint8_t* data,
size_t position,
size_t length,
const uint8_t* source,
size_t source_position) {
for(size_t i = 0; i < length; ++i) {
bit_lib_set_bit(data, position + i, bit_lib_get_bit(source, source_position + i));
}
}
void bit_lib_reverse_bits(uint8_t* data, size_t position, uint8_t length) {
size_t i = 0;
size_t j = length - 1;
while(i < j) {
bool tmp = bit_lib_get_bit(data, position + i);
bit_lib_set_bit(data, position + i, bit_lib_get_bit(data, position + j));
bit_lib_set_bit(data, position + j, tmp);
i++;
j--;
}
}
uint8_t bit_lib_get_bit_count(uint32_t data) {
#if defined __GNUC__
return __builtin_popcountl(data);
#else
#error Please, implement popcount for non-GCC compilers
#endif
}
void bit_lib_print_bits(const uint8_t* data, size_t length) {
for(size_t i = 0; i < length; ++i) {
printf("%u", bit_lib_get_bit(data, i));
}
}
void bit_lib_print_regions(
const BitLibRegion* regions,
size_t region_count,
const uint8_t* data,
size_t length) {
// print data
bit_lib_print_bits(data, length);
printf("\r\n");
// print regions
for(size_t c = 0; c < length; ++c) {
bool print = false;
for(size_t i = 0; i < region_count; i++) {
if(regions[i].start <= c && c < regions[i].start + regions[i].length) {
print = true;
printf("%c", regions[i].mark);
break;
}
}
if(!print) {
printf(" ");
}
}
printf("\r\n");
// print regions data
for(size_t c = 0; c < length; ++c) {
bool print = false;
for(size_t i = 0; i < region_count; i++) {
if(regions[i].start <= c && c < regions[i].start + regions[i].length) {
print = true;
printf("%u", bit_lib_get_bit(data, c));
break;
}
}
if(!print) {
printf(" ");
}
}
printf("\r\n");
}
uint16_t bit_lib_reverse_16_fast(uint16_t data) {
uint16_t result = 0;
result |= (data & 0x8000) >> 15;
result |= (data & 0x4000) >> 13;
result |= (data & 0x2000) >> 11;
result |= (data & 0x1000) >> 9;
result |= (data & 0x0800) >> 7;
result |= (data & 0x0400) >> 5;
result |= (data & 0x0200) >> 3;
result |= (data & 0x0100) >> 1;
result |= (data & 0x0080) << 1;
result |= (data & 0x0040) << 3;
result |= (data & 0x0020) << 5;
result |= (data & 0x0010) << 7;
result |= (data & 0x0008) << 9;
result |= (data & 0x0004) << 11;
result |= (data & 0x0002) << 13;
result |= (data & 0x0001) << 15;
return result;
}
uint16_t bit_lib_crc16(
uint8_t const* data,
size_t data_size,
uint16_t polynom,
uint16_t init,
bool ref_in,
bool ref_out,
uint16_t xor_out) {
uint16_t crc = init;
for(size_t i = 0; i < data_size; ++i) {
uint8_t byte = data[i];
if(ref_in) byte = bit_lib_reverse_16_fast(byte) >> 8;
for(size_t j = 0; j < 8; ++j) {
bool c15 = (crc >> 15 & 1);
bool bit = (byte >> (7 - j) & 1);
crc <<= 1;
if(c15 ^ bit) crc ^= polynom;
}
}
if(ref_out) crc = bit_lib_reverse_16_fast(crc);
crc ^= xor_out;
return crc;
}

220
lib/lfrfid/tools/bit_lib.h Normal file
View File

@@ -0,0 +1,220 @@
#pragma once
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
BitLibParityEven,
BitLibParityOdd,
BitLibParityAlways0,
BitLibParityAlways1,
} BitLibParity;
/** @brief Increment and wrap around a value.
* @param index value to increment
* @param length wrap-around range
*/
#define bit_lib_increment_index(index, length) (index = (((index) + 1) % (length)))
/** @brief Test if a bit is set.
* @param data value to test
* @param index bit index to test
*/
#define bit_lib_bit_is_set(data, index) ((data & (1 << (index))) != 0)
/** @brief Test if a bit is not set.
* @param data value to test
* @param index bit index to test
*/
#define bit_lib_bit_is_not_set(data, index) ((data & (1 << (index))) == 0)
/** @brief Push a bit into a byte array.
* @param data array to push bit into
* @param data_size array size
* @param bit bit to push
*/
void bit_lib_push_bit(uint8_t* data, size_t data_size, bool bit);
/** @brief Set a bit in a byte array.
* @param data array to set bit in
* @param position The position of the bit to set.
* @param bit bit value to set
*/
void bit_lib_set_bit(uint8_t* data, size_t position, bool bit);
/** @brief Set the bit at the given position to the given value.
* @param data The data to set the bit in.
* @param position The position of the bit to set.
* @param byte The data to set the bit to.
* @param length The length of the data.
*/
void bit_lib_set_bits(uint8_t* data, size_t position, uint8_t byte, uint8_t length);
/** @brief Get the bit of a byte.
* @param data The byte to get the bits from.
* @param position The position of the bit.
* @return The bit.
*/
bool bit_lib_get_bit(const uint8_t* data, size_t position);
/**
* @brief Get the bits of a data, as uint8_t.
* @param data The data to get the bits from.
* @param position The position of the first bit.
* @param length The length of the bits.
* @return The bits.
*/
uint8_t bit_lib_get_bits(const uint8_t* data, size_t position, uint8_t length);
/**
* @brief Get the bits of a data, as uint16_t.
* @param data The data to get the bits from.
* @param position The position of the first bit.
* @param length The length of the bits.
* @return The bits.
*/
uint16_t bit_lib_get_bits_16(const uint8_t* data, size_t position, uint8_t length);
/**
* @brief Get the bits of a data, as uint32_t.
* @param data The data to get the bits from.
* @param position The position of the first bit.
* @param length The length of the bits.
* @return The bits.
*/
uint32_t bit_lib_get_bits_32(const uint8_t* data, size_t position, uint8_t length);
/**
* @brief Test parity of given bits
* @param bits Bits to test parity of
* @param parity Parity to test against
* @return true if parity is correct, false otherwise
*/
bool bit_lib_test_parity_32(uint32_t bits, BitLibParity parity);
/**
* @brief Test parity of bit array, check parity for every parity_length block from start
*
* @param data Bit array
* @param position Start position
* @param length Bit count
* @param parity Parity to test against
* @param parity_length Parity block length
* @return true
* @return false
*/
bool bit_lib_test_parity(
const uint8_t* data,
size_t position,
uint8_t length,
BitLibParity parity,
uint8_t parity_length);
/**
* @brief Remove bit every n in array and shift array left. Useful to remove parity.
*
* @param data Bit array
* @param position Start position
* @param length Bit count
* @param n every n bit will be removed
* @return size_t
*/
size_t bit_lib_remove_bit_every_nth(uint8_t* data, size_t position, uint8_t length, uint8_t n);
/**
* @brief Copy bits from source to destination.
*
* @param data destination array
* @param position position in destination array
* @param length length of bits to copy
* @param source source array
* @param source_position position in source array
*/
void bit_lib_copy_bits(
uint8_t* data,
size_t position,
size_t length,
const uint8_t* source,
size_t source_position);
/**
* @brief Reverse bits in bit array
*
* @param data Bit array
* @param position start position
* @param length length of bits to reverse
*/
void bit_lib_reverse_bits(uint8_t* data, size_t position, uint8_t length);
/**
* @brief Count 1 bits in data
*
* @param data
* @return uint8_t set bit count
*/
uint8_t bit_lib_get_bit_count(uint32_t data);
/**
* @brief Print data as bit array
*
* @param data
* @param length
*/
void bit_lib_print_bits(const uint8_t* data, size_t length);
typedef struct {
const char mark;
const size_t start;
const size_t length;
} BitLibRegion;
/**
* @brief Print data as bit array and mark regions. Regions needs to be sorted by start position.
*
* @param regions
* @param region_count
* @param data
* @param length
*/
void bit_lib_print_regions(
const BitLibRegion* regions,
size_t region_count,
const uint8_t* data,
size_t length);
/**
* @brief Reverse bits in uint16_t, faster than generic bit_lib_reverse_bits.
*
* @param data
* @return uint16_t
*/
uint16_t bit_lib_reverse_16_fast(uint16_t data);
/**
* @brief Slow, but generic CRC16 implementation
*
* @param data
* @param data_size
* @param polynom CRC polynom
* @param init init value
* @param ref_in true if the right bit is older
* @param ref_out true to reverse output
* @param xor_out xor output with this value
* @return uint16_t
*/
uint16_t bit_lib_crc16(
uint8_t const* data,
size_t data_size,
uint16_t polynom,
uint16_t init,
bool ref_in,
bool ref_out,
uint16_t xor_out);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,93 @@
#include <furi.h>
#include "fsk_demod.h"
struct FSKDemod {
uint32_t low_time;
uint32_t low_pulses;
uint32_t hi_time;
uint32_t hi_pulses;
bool invert;
uint32_t mid_time;
uint32_t time;
uint32_t count;
bool last_pulse;
};
FSKDemod*
fsk_demod_alloc(uint32_t low_time, uint32_t low_pulses, uint32_t hi_time, uint32_t hi_pulses) {
FSKDemod* demod = malloc(sizeof(FSKDemod));
demod->invert = false;
if(low_time > hi_time) {
uint32_t tmp;
tmp = hi_time;
hi_time = low_time;
low_time = tmp;
tmp = hi_pulses;
hi_pulses = low_pulses;
low_pulses = tmp;
demod->invert = true;
}
demod->low_time = low_time;
demod->low_pulses = low_pulses;
demod->hi_time = hi_time;
demod->hi_pulses = hi_pulses;
demod->mid_time = (hi_time - low_time) / 2 + low_time;
demod->time = 0;
demod->count = 0;
demod->last_pulse = false;
return demod;
}
void fsk_demod_free(FSKDemod* demod) {
free(demod);
}
void fsk_demod_feed(FSKDemod* demod, bool polarity, uint32_t time, bool* value, uint32_t* count) {
*count = 0;
if(polarity) {
// accumulate time
demod->time = time;
} else {
demod->time += time;
// check for valid pulse
if(demod->time >= demod->low_time && demod->time < demod->hi_time) {
bool pulse;
if(demod->time < demod->mid_time) {
pulse = false;
} else {
pulse = true;
}
demod->count++;
// check for edge transition
if(demod->last_pulse != pulse) {
uint32_t data_count = demod->count + 1;
if(demod->last_pulse) {
data_count /= demod->hi_pulses;
*value = !demod->invert;
} else {
data_count /= demod->low_pulses;
*value = demod->invert;
}
*count = data_count;
demod->count = 0;
demod->last_pulse = pulse;
}
} else {
demod->count = 0;
}
}
}

View File

@@ -0,0 +1,44 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct FSKDemod FSKDemod;
/**
* @brief Allocate a new FSKDemod instance
* FSKDemod is a demodulator that can decode FSK encoded data
*
* @param low_time time between rising edges for the 0 bit
* @param low_pulses rising edges count for the 0 bit
* @param hi_time time between rising edges for the 1 bit
* @param hi_pulses rising edges count for the 1 bit
* @return FSKDemod*
*/
FSKDemod*
fsk_demod_alloc(uint32_t low_time, uint32_t low_pulses, uint32_t hi_time, uint32_t hi_pulses);
/**
* @brief Free a FSKDemod instance
*
* @param fsk_demod
*/
void fsk_demod_free(FSKDemod* fsk_demod);
/**
* @brief Feed sample to demodulator
*
* @param demod FSKDemod instance
* @param polarity sample polarity
* @param time sample time
* @param value demodulated bit value
* @param count demodulated bit count
*/
void fsk_demod_feed(FSKDemod* demod, bool polarity, uint32_t time, bool* value, uint32_t* count);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,62 @@
#include "fsk_osc.h"
#include <stdlib.h>
struct FSKOsc {
uint16_t freq[2];
uint16_t osc_phase_max;
int32_t osc_phase_current;
uint32_t pulse;
};
FSKOsc* fsk_osc_alloc(uint32_t freq_low, uint32_t freq_hi, uint32_t osc_phase_max) {
FSKOsc* osc = malloc(sizeof(FSKOsc));
osc->freq[0] = freq_low;
osc->freq[1] = freq_hi;
osc->osc_phase_max = osc_phase_max;
osc->osc_phase_current = 0;
osc->pulse = 0;
return osc;
}
void fsk_osc_free(FSKOsc* osc) {
free(osc);
}
void fsk_osc_reset(FSKOsc* osc) {
osc->osc_phase_current = 0;
osc->pulse = 0;
}
bool fsk_osc_next(FSKOsc* osc, bool bit, uint32_t* period) {
bool advance = false;
*period = osc->freq[bit];
osc->osc_phase_current += *period;
if(osc->osc_phase_current > osc->osc_phase_max) {
advance = true;
osc->osc_phase_current -= osc->osc_phase_max;
}
return advance;
}
bool fsk_osc_next_half(FSKOsc* osc, bool bit, bool* level, uint32_t* duration) {
bool advance = false;
// if pulse is zero, we need to output high, otherwise we need to output low
if(osc->pulse == 0) {
uint32_t length;
advance = fsk_osc_next(osc, bit, &length);
*duration = length / 2;
osc->pulse = *duration;
*level = true;
} else {
// output low half and reset pulse
*duration = osc->pulse;
osc->pulse = 0;
*level = false;
}
return advance;
}

View File

@@ -0,0 +1,60 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct FSKOsc FSKOsc;
/**
* @brief Allocate a new FSKOsc instance
* FSKOsc is a oscillator that can provide FSK encoding
*
* @param freq_low
* @param freq_hi
* @param osc_phase_max
* @return FSKOsc*
*/
FSKOsc* fsk_osc_alloc(uint32_t freq_low, uint32_t freq_hi, uint32_t osc_phase_max);
/**
* @brief Free a FSKOsc instance
*
* @param osc
*/
void fsk_osc_free(FSKOsc* osc);
/**
* @brief Reset ocillator
*
* @param osc
*/
void fsk_osc_reset(FSKOsc* osc);
/**
* @brief Get next duration sample from oscillator
*
* @param osc
* @param bit
* @param period
* @return bool
*/
bool fsk_osc_next(FSKOsc* osc, bool bit, uint32_t* period);
/**
* @brief Get next half of sample from oscillator
* Useful when encoding high and low levels separately.
*
* @param osc
* @param bit
* @param level
* @param duration
* @return bool
*/
bool fsk_osc_next_half(FSKOsc* osc, bool bit, bool* level, uint32_t* duration);
#ifdef __cplusplus
}
#endif

94
lib/lfrfid/tools/t5577.c Normal file
View File

@@ -0,0 +1,94 @@
#include "t5577.h"
#include <furi.h>
#include <furi_hal_rfid.h>
#define T5577_TIMING_WAIT_TIME 400
#define T5577_TIMING_START_GAP 30
#define T5577_TIMING_WRITE_GAP 18
#define T5577_TIMING_DATA_0 24
#define T5577_TIMING_DATA_1 56
#define T5577_TIMING_PROGRAM 700
#define T5577_OPCODE_PAGE_0 0b10
#define T5577_OPCODE_PAGE_1 0b11
#define T5577_OPCODE_RESET 0b00
static void t5577_start() {
furi_hal_rfid_tim_read(125000, 0.5);
furi_hal_rfid_pins_read();
furi_hal_rfid_tim_read_start();
// do not ground the antenna
furi_hal_rfid_pin_pull_release();
}
static void t5577_stop() {
furi_hal_rfid_tim_read_stop();
furi_hal_rfid_tim_reset();
furi_hal_rfid_pins_reset();
}
static void t5577_write_gap(uint32_t gap_time) {
furi_hal_rfid_tim_read_stop();
furi_delay_us(gap_time * 8);
furi_hal_rfid_tim_read_start();
}
static void t5577_write_bit(bool value) {
if(value) {
furi_delay_us(T5577_TIMING_DATA_1 * 8);
} else {
furi_delay_us(T5577_TIMING_DATA_0 * 8);
}
t5577_write_gap(T5577_TIMING_WRITE_GAP);
}
static void t5577_write_opcode(uint8_t value) {
t5577_write_bit((value >> 1) & 1);
t5577_write_bit((value >> 0) & 1);
}
static void t5577_write_reset() {
t5577_write_gap(T5577_TIMING_START_GAP);
t5577_write_bit(1);
t5577_write_bit(0);
}
static void t5577_write_block(uint8_t block, bool lock_bit, uint32_t data) {
furi_delay_us(T5577_TIMING_WAIT_TIME * 8);
// start gap
t5577_write_gap(T5577_TIMING_START_GAP);
// opcode for page 0
t5577_write_opcode(T5577_OPCODE_PAGE_0);
// lock bit
t5577_write_bit(lock_bit);
// data
for(uint8_t i = 0; i < 32; i++) {
t5577_write_bit((data >> (31 - i)) & 1);
}
// block address
t5577_write_bit((block >> 2) & 1);
t5577_write_bit((block >> 1) & 1);
t5577_write_bit((block >> 0) & 1);
furi_delay_us(T5577_TIMING_PROGRAM * 8);
furi_delay_us(T5577_TIMING_WAIT_TIME * 8);
t5577_write_reset();
}
void t5577_write(LFRFIDT5577* data) {
t5577_start();
FURI_CRITICAL_ENTER();
for(size_t i = 0; i < data->blocks_to_write; i++) {
t5577_write_block(i, false, data->block[i]);
}
t5577_write_reset();
FURI_CRITICAL_EXIT();
t5577_stop();
}

56
lib/lfrfid/tools/t5577.h Normal file
View File

@@ -0,0 +1,56 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
#define LFRFID_T5577_BLOCK_COUNT 8
// T5577 block 0 definitions, thanks proxmark3!
#define LFRFID_T5577_POR_DELAY 0x00000001
#define LFRFID_T5577_ST_TERMINATOR 0x00000008
#define LFRFID_T5577_PWD 0x00000010
#define LFRFID_T5577_MAXBLOCK_SHIFT 5
#define LFRFID_T5577_AOR 0x00000200
#define LFRFID_T5577_PSKCF_RF_2 0
#define LFRFID_T5577_PSKCF_RF_4 0x00000400
#define LFRFID_T5577_PSKCF_RF_8 0x00000800
#define LFRFID_T5577_MODULATION_DIRECT 0
#define LFRFID_T5577_MODULATION_PSK1 0x00001000
#define LFRFID_T5577_MODULATION_PSK2 0x00002000
#define LFRFID_T5577_MODULATION_PSK3 0x00003000
#define LFRFID_T5577_MODULATION_FSK1 0x00004000
#define LFRFID_T5577_MODULATION_FSK2 0x00005000
#define LFRFID_T5577_MODULATION_FSK1a 0x00006000
#define LFRFID_T5577_MODULATION_FSK2a 0x00007000
#define LFRFID_T5577_MODULATION_MANCHESTER 0x00008000
#define LFRFID_T5577_MODULATION_BIPHASE 0x00010000
#define LFRFID_T5577_MODULATION_DIPHASE 0x00018000
#define LFRFID_T5577_X_MODE 0x00020000
#define LFRFID_T5577_BITRATE_RF_8 0
#define LFRFID_T5577_BITRATE_RF_16 0x00040000
#define LFRFID_T5577_BITRATE_RF_32 0x00080000
#define LFRFID_T5577_BITRATE_RF_40 0x000C0000
#define LFRFID_T5577_BITRATE_RF_50 0x00100000
#define LFRFID_T5577_BITRATE_RF_64 0x00140000
#define LFRFID_T5577_BITRATE_RF_100 0x00180000
#define LFRFID_T5577_BITRATE_RF_128 0x001C0000
#define LFRFID_T5577_TESTMODE_DISABLED 0x60000000
typedef struct {
uint32_t block[LFRFID_T5577_BLOCK_COUNT];
uint32_t blocks_to_write;
} LFRFIDT5577;
/**
* @brief Write T5577 tag data to tag
*
* @param data
*/
void t5577_write(LFRFIDT5577* data);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,77 @@
#include "varint_pair.h"
#include <toolbox/varint.h>
#define VARINT_PAIR_SIZE 10
struct VarintPair {
size_t data_length;
uint8_t data[VARINT_PAIR_SIZE];
};
VarintPair* varint_pair_alloc() {
VarintPair* pair = malloc(sizeof(VarintPair));
pair->data_length = 0;
return pair;
}
void varint_pair_free(VarintPair* pair) {
free(pair);
}
bool varint_pair_pack(VarintPair* pair, bool first, uint32_t value) {
bool result = false;
if(first) {
if(pair->data_length == 0) {
pair->data_length = varint_uint32_pack(value, pair->data);
} else {
pair->data_length = 0;
}
} else {
if(pair->data_length > 0) {
pair->data_length += varint_uint32_pack(value, pair->data + pair->data_length);
result = true;
} else {
pair->data_length = 0;
}
}
return result;
}
bool varint_pair_unpack(
uint8_t* data,
size_t data_length,
uint32_t* value_1,
uint32_t* value_2,
size_t* length) {
size_t size = 0;
uint32_t tmp_value_1;
uint32_t tmp_value_2;
size += varint_uint32_unpack(&tmp_value_1, &data[size], data_length);
if(size >= data_length) {
return false;
}
size += varint_uint32_unpack(&tmp_value_2, &data[size], (size_t)(data_length - size));
*value_1 = tmp_value_1;
*value_2 = tmp_value_2;
*length = size;
return true;
}
uint8_t* varint_pair_get_data(VarintPair* pair) {
return pair->data;
}
size_t varint_pair_get_size(VarintPair* pair) {
return pair->data_length;
}
void varint_pair_reset(VarintPair* pair) {
pair->data_length = 0;
}

View File

@@ -0,0 +1,79 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct VarintPair VarintPair;
/**
* @brief Allocate a new VarintPair instance
*
* VarintPair is a buffer that holds pair of varint values
* @return VarintPair*
*/
VarintPair* varint_pair_alloc();
/**
* @brief Free a VarintPair instance
*
* @param pair
*/
void varint_pair_free(VarintPair* pair);
/**
* @brief Write varint pair to buffer
*
* @param pair
* @param first
* @param value
* @return bool pair complete and needs to be written
*/
bool varint_pair_pack(VarintPair* pair, bool first, uint32_t value);
/**
* @brief Get pointer to varint pair buffer
*
* @param pair
* @return uint8_t*
*/
uint8_t* varint_pair_get_data(VarintPair* pair);
/**
* @brief Get size of varint pair buffer
*
* @param pair
* @return size_t
*/
size_t varint_pair_get_size(VarintPair* pair);
/**
* @brief Reset varint pair buffer
*
* @param pair
*/
void varint_pair_reset(VarintPair* pair);
/**
* @brief Unpack varint pair to uint32_t pair from buffer
*
* @param data
* @param data_length
* @param value_1
* @param value_2
* @param length
* @return bool
*/
bool varint_pair_unpack(
uint8_t* data,
size_t data_length,
uint32_t* value_1,
uint32_t* value_2,
size_t* length);
#ifdef __cplusplus
}
#endif