 0b806c2360
			
		
	
	
		0b806c2360
		
			
		
	
	
	
	
		
			
			* Storage: count opened files * Storage: sd mount * Storage: prompt to mount SD card if not mounted * F18: update API * F18: update API version * Fix logger naming scheme * Storage: storage_files_count -> storage_open_files_count Co-authored-by: あく <alleteam@gmail.com>
		
			
				
	
	
		
			636 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			636 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #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;
 | |
| 
 | |
|     if(feature & LFRFIDFeatureASK) {
 | |
|         furi_hal_rfid_tim_read_start(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_start(62500, 0.25);
 | |
|         FURI_LOG_D(TAG, "Start PSK");
 | |
|         if(worker->read_cb) {
 | |
|             worker->read_cb(LFRFIDWorkerReadStartPSK, PROTOCOL_NO, worker->cb_ctx);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // 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.2f && average < 0.8f) {
 | |
|                             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},
 | |
| };
 |