| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638 |
- #include <furi.h>
- #include <furi_hal.h>
- #include "lfrfid_worker_i.h"
- #include "tools/t5577.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 2000
- #define LFRFID_WORKER_WRITE_VERIFY_TIME_MS 2000
- #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 16
- #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
- 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));
- varint_pair_reset(ctx->pair);
- }
- }
- 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);
- furi_hal_gpio_write(LFRFID_WORKER_READ_DEBUG_GPIO_VALUE, false);
- furi_hal_gpio_write(LFRFID_WORKER_READ_DEBUG_GPIO_LOAD, false);
- #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);
- #ifdef LFRFID_WORKER_READ_DEBUG_GPIO
- furi_hal_gpio_write(LFRFID_WORKER_READ_DEBUG_GPIO_LOAD, false);
- #endif
- continue;
- }
- if(buffer == NULL) {
- #ifdef LFRFID_WORKER_READ_DEBUG_GPIO
- furi_hal_gpio_write(LFRFID_WORKER_READ_DEBUG_GPIO_LOAD, false);
- #endif
- 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;
- }
- if(furi_log_get_level() >= FuriLogLevelDebug) {
- FuriString* string_info;
- string_info = furi_string_alloc();
- for(uint8_t i = 0; i < protocol_data_size; i++) {
- if(i != 0) {
- furi_string_cat_printf(string_info, " ");
- }
- furi_string_cat_printf(string_info, "%02X", protocol_data[i]);
- }
- FURI_LOG_D(
- TAG,
- "%s, %zu, [%s]",
- protocol_dict_get_name(worker->protocols, protocol),
- last_read_count,
- furi_string_get_cstr(string_info));
- furi_string_free(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_write(LFRFID_WORKER_READ_DEBUG_GPIO_VALUE, false);
- furi_hal_gpio_write(LFRFID_WORKER_READ_DEBUG_GPIO_LOAD, false);
- 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) {
- ProtocolId read_result = PROTOCOL_NO;
- LFRFIDWorkerReadState state;
- LFRFIDFeature feature;
- 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) {
- FuriStreamBuffer* stream = context;
- uint32_t flag = half ? HalfTransfer : TransferComplete;
- furi_stream_buffer_send(stream, &flag, sizeof(uint32_t), 0);
- }
- static void lfrfid_worker_mode_emulate_process(LFRFIDWorker* worker) {
- LFRFIDWorkerEmulateBuffer* buffer = malloc(sizeof(LFRFIDWorkerEmulateBuffer));
- FuriStreamBuffer* stream = furi_stream_buffer_alloc(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 = furi_stream_buffer_receive(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);
- furi_stream_buffer_free(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) {
- bool read_success = false;
- if(read_result == protocol) {
- protocol_dict_get_data(worker->protocols, protocol, read_data, data_size);
- if(memcmp(read_data, verify_data, data_size) == 0) {
- read_success = true;
- }
- }
- if(read_success) {
- if(worker->write_cb) {
- worker->write_cb(LFRFIDWorkerWriteOK, worker->cb_ctx);
- }
- break;
- } else {
- unsuccessful_reads++;
- if(unsuccessful_reads == LFRFID_WORKER_WRITE_MAX_UNSUCCESSFUL_READS) {
- if(worker->write_cb) {
- worker->write_cb(LFRFIDWorkerWriteFobCannotBeWritten, worker->cb_ctx);
- }
- }
- }
- } else if(state == LFRFIDWorkerReadExit) {
- break;
- }
- 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},
- };
|