 c1e0d02afc
			
		
	
	
		c1e0d02afc
		
			
		
	
	
	
	
		
			
			* nfc: st25tb: rework async poller * nfc: st25tb: introduce sync poller * nfc: st25tb: add write support * nfc: st25tb: rewrite poller to use better states * nfc: st25tb: move to mode request state after success * nfc: st25tb: minor bug fixes * type wasn't properly set on ready event * sending NfcCustomEventPollerFailure on St25tbPollerEventTypeFailure caused poller to being freed and ultimately resulted in a thread crash Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
		
			
				
	
	
		
			211 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			211 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include "st25tb_poller_sync.h"
 | |
| #include "st25tb_poller_i.h"
 | |
| 
 | |
| #define ST25TB_POLLER_FLAG_COMMAND_COMPLETE (1UL << 0)
 | |
| 
 | |
| typedef enum {
 | |
|     St25tbPollerCmdTypeDetectType,
 | |
|     St25tbPollerCmdTypeReadBlock,
 | |
|     St25tbPollerCmdTypeWriteBlock,
 | |
| 
 | |
|     St25tbPollerCmdTypeNum,
 | |
| } St25tbPollerCmdType;
 | |
| 
 | |
| typedef struct {
 | |
|     St25tbType* type;
 | |
| } St25tbPollerCmdDetectTypeData;
 | |
| 
 | |
| typedef struct {
 | |
|     St25tbData* data;
 | |
| } St25tbPollerCmdReadData;
 | |
| 
 | |
| typedef struct {
 | |
|     uint8_t block_num;
 | |
|     uint32_t* block;
 | |
| } St25tbPollerCmdReadBlockData;
 | |
| 
 | |
| typedef struct {
 | |
|     uint8_t block_num;
 | |
|     uint32_t block;
 | |
| } St25tbPollerCmdWriteBlockData;
 | |
| 
 | |
| typedef union {
 | |
|     St25tbPollerCmdDetectTypeData detect_type;
 | |
|     St25tbPollerCmdReadData read;
 | |
|     St25tbPollerCmdReadBlockData read_block;
 | |
|     St25tbPollerCmdWriteBlockData write_block;
 | |
| } St25tbPollerCmdData;
 | |
| 
 | |
| typedef struct {
 | |
|     FuriThreadId thread_id;
 | |
|     St25tbError error;
 | |
|     St25tbPollerCmdType cmd_type;
 | |
|     St25tbPollerCmdData cmd_data;
 | |
| } St25tbPollerSyncContext;
 | |
| 
 | |
| typedef St25tbError (*St25tbPollerCmdHandler)(St25tbPoller* poller, St25tbPollerCmdData* data);
 | |
| 
 | |
| static St25tbError st25tb_poller_detect_handler(St25tbPoller* poller, St25tbPollerCmdData* data) {
 | |
|     uint8_t uid[ST25TB_UID_SIZE];
 | |
|     St25tbError error = st25tb_poller_get_uid(poller, uid);
 | |
|     if(error == St25tbErrorNone) {
 | |
|         *data->detect_type.type = st25tb_get_type_from_uid(uid);
 | |
|     }
 | |
|     return error;
 | |
| }
 | |
| 
 | |
| static St25tbError
 | |
|     st25tb_poller_read_block_handler(St25tbPoller* poller, St25tbPollerCmdData* data) {
 | |
|     return st25tb_poller_read_block(poller, data->read_block.block, data->read_block.block_num);
 | |
| }
 | |
| 
 | |
| static St25tbError
 | |
|     st25tb_poller_write_block_handler(St25tbPoller* poller, St25tbPollerCmdData* data) {
 | |
|     return st25tb_poller_write_block(poller, data->write_block.block, data->write_block.block_num);
 | |
| }
 | |
| 
 | |
| static St25tbPollerCmdHandler st25tb_poller_cmd_handlers[St25tbPollerCmdTypeNum] = {
 | |
|     [St25tbPollerCmdTypeDetectType] = st25tb_poller_detect_handler,
 | |
|     [St25tbPollerCmdTypeReadBlock] = st25tb_poller_read_block_handler,
 | |
|     [St25tbPollerCmdTypeWriteBlock] = st25tb_poller_write_block_handler,
 | |
| };
 | |
| 
 | |
| static NfcCommand st25tb_poller_cmd_callback(NfcGenericEvent event, void* context) {
 | |
|     furi_assert(context);
 | |
|     furi_assert(event.event_data);
 | |
|     furi_assert(event.instance);
 | |
|     furi_assert(event.protocol == NfcProtocolSt25tb);
 | |
| 
 | |
|     St25tbPollerSyncContext* poller_context = context;
 | |
|     St25tbPoller* st25tb_poller = event.instance;
 | |
|     St25tbPollerEvent* st25tb_event = event.event_data;
 | |
| 
 | |
|     if(st25tb_event->type == St25tbPollerEventTypeReady) {
 | |
|         poller_context->error = st25tb_poller_cmd_handlers[poller_context->cmd_type](
 | |
|             st25tb_poller, &poller_context->cmd_data);
 | |
|     } else {
 | |
|         poller_context->error = st25tb_event->data->error;
 | |
|     }
 | |
| 
 | |
|     furi_thread_flags_set(poller_context->thread_id, ST25TB_POLLER_FLAG_COMMAND_COMPLETE);
 | |
| 
 | |
|     return NfcCommandStop;
 | |
| }
 | |
| 
 | |
| static St25tbError st25tb_poller_cmd_execute(Nfc* nfc, St25tbPollerSyncContext* poller_ctx) {
 | |
|     furi_assert(nfc);
 | |
|     furi_assert(poller_ctx->cmd_type < St25tbPollerCmdTypeNum);
 | |
|     poller_ctx->thread_id = furi_thread_get_current_id();
 | |
| 
 | |
|     NfcPoller* poller = nfc_poller_alloc(nfc, NfcProtocolSt25tb);
 | |
|     nfc_poller_start(poller, st25tb_poller_cmd_callback, poller_ctx);
 | |
|     furi_thread_flags_wait(ST25TB_POLLER_FLAG_COMMAND_COMPLETE, FuriFlagWaitAny, FuriWaitForever);
 | |
|     furi_thread_flags_clear(ST25TB_POLLER_FLAG_COMMAND_COMPLETE);
 | |
| 
 | |
|     nfc_poller_stop(poller);
 | |
|     nfc_poller_free(poller);
 | |
| 
 | |
|     return poller_ctx->error;
 | |
| }
 | |
| 
 | |
| St25tbError st25tb_poller_sync_read_block(Nfc* nfc, uint8_t block_num, uint32_t* block) {
 | |
|     furi_assert(block);
 | |
|     St25tbPollerSyncContext poller_context = {
 | |
|         .cmd_type = St25tbPollerCmdTypeReadBlock,
 | |
|         .cmd_data =
 | |
|             {
 | |
|                 .read_block =
 | |
|                     {
 | |
|                         .block = block,
 | |
|                         .block_num = block_num,
 | |
|                     },
 | |
|             },
 | |
|     };
 | |
|     return st25tb_poller_cmd_execute(nfc, &poller_context);
 | |
| }
 | |
| 
 | |
| St25tbError st25tb_poller_sync_write_block(Nfc* nfc, uint8_t block_num, uint32_t block) {
 | |
|     St25tbPollerSyncContext poller_context = {
 | |
|         .cmd_type = St25tbPollerCmdTypeWriteBlock,
 | |
|         .cmd_data =
 | |
|             {
 | |
|                 .write_block =
 | |
|                     {
 | |
|                         .block = block,
 | |
|                         .block_num = block_num,
 | |
|                     },
 | |
|             },
 | |
|     };
 | |
|     return st25tb_poller_cmd_execute(nfc, &poller_context);
 | |
| }
 | |
| 
 | |
| St25tbError st25tb_poller_sync_detect_type(Nfc* nfc, St25tbType* type) {
 | |
|     furi_assert(type);
 | |
|     St25tbPollerSyncContext poller_context = {
 | |
|         .cmd_type = St25tbPollerCmdTypeDetectType,
 | |
|         .cmd_data =
 | |
|             {
 | |
|                 .detect_type =
 | |
|                     {
 | |
|                         .type = type,
 | |
|                     },
 | |
|             },
 | |
|     };
 | |
|     return st25tb_poller_cmd_execute(nfc, &poller_context);
 | |
| }
 | |
| 
 | |
| static NfcCommand nfc_scene_read_poller_callback_st25tb(NfcGenericEvent event, void* context) {
 | |
|     furi_assert(context);
 | |
|     furi_assert(event.event_data);
 | |
|     furi_assert(event.instance);
 | |
|     furi_assert(event.protocol == NfcProtocolSt25tb);
 | |
| 
 | |
|     St25tbPollerSyncContext* poller_context = context;
 | |
|     St25tbPollerEvent* st25tb_event = event.event_data;
 | |
| 
 | |
|     NfcCommand command = NfcCommandContinue;
 | |
|     if(st25tb_event->type == St25tbPollerEventTypeRequestMode) {
 | |
|         st25tb_event->data->mode_request.mode = St25tbPollerModeRead;
 | |
|     } else if(
 | |
|         st25tb_event->type == St25tbPollerEventTypeSuccess ||
 | |
|         st25tb_event->type == St25tbPollerEventTypeFailure) {
 | |
|         if(st25tb_event->type == St25tbPollerEventTypeSuccess) {
 | |
|             memcpy(
 | |
|                 poller_context->cmd_data.read.data,
 | |
|                 st25tb_poller_get_data(event.instance),
 | |
|                 sizeof(St25tbData));
 | |
|         } else {
 | |
|             poller_context->error = st25tb_event->data->error;
 | |
|         }
 | |
|         command = NfcCommandStop;
 | |
|         furi_thread_flags_set(poller_context->thread_id, ST25TB_POLLER_FLAG_COMMAND_COMPLETE);
 | |
|     }
 | |
| 
 | |
|     return command;
 | |
| }
 | |
| 
 | |
| St25tbError st25tb_poller_sync_read(Nfc* nfc, St25tbData* data) {
 | |
|     furi_assert(nfc);
 | |
|     furi_assert(data);
 | |
| 
 | |
|     St25tbPollerSyncContext poller_context = {
 | |
|         .thread_id = furi_thread_get_current_id(),
 | |
|         .cmd_data =
 | |
|             {
 | |
|                 .read =
 | |
|                     {
 | |
|                         .data = data,
 | |
|                     },
 | |
|             },
 | |
|     };
 | |
| 
 | |
|     NfcPoller* poller = nfc_poller_alloc(nfc, NfcProtocolSt25tb);
 | |
|     nfc_poller_start(poller, nfc_scene_read_poller_callback_st25tb, &poller_context);
 | |
|     furi_thread_flags_wait(ST25TB_POLLER_FLAG_COMMAND_COMPLETE, FuriFlagWaitAny, FuriWaitForever);
 | |
|     furi_thread_flags_clear(ST25TB_POLLER_FLAG_COMMAND_COMPLETE);
 | |
| 
 | |
|     nfc_poller_stop(poller);
 | |
|     nfc_poller_free(poller);
 | |
| 
 | |
|     return poller_context.error;
 | |
| } |