ST25TB poller refining + write support (#3239)
* 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>
This commit is contained in:
		
							parent
							
								
									890c9e87ce
								
							
						
					
					
						commit
						c1e0d02afc
					
				| @ -29,7 +29,9 @@ static NfcCommand nfc_scene_read_poller_callback_st25tb(NfcGenericEvent event, v | |||||||
|     NfcApp* instance = context; |     NfcApp* instance = context; | ||||||
|     const St25tbPollerEvent* st25tb_event = event.event_data; |     const St25tbPollerEvent* st25tb_event = event.event_data; | ||||||
| 
 | 
 | ||||||
|     if(st25tb_event->type == St25tbPollerEventTypeReady) { |     if(st25tb_event->type == St25tbPollerEventTypeRequestMode) { | ||||||
|  |         st25tb_event->data->mode_request.mode = St25tbPollerModeRead; | ||||||
|  |     } else if(st25tb_event->type == St25tbPollerEventTypeSuccess) { | ||||||
|         nfc_device_set_data( |         nfc_device_set_data( | ||||||
|             instance->nfc_device, NfcProtocolSt25tb, nfc_poller_get_data(instance->poller)); |             instance->nfc_device, NfcProtocolSt25tb, nfc_poller_get_data(instance->poller)); | ||||||
|         view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerSuccess); |         view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerSuccess); | ||||||
|  | |||||||
| @ -42,6 +42,7 @@ env.Append( | |||||||
|         File("protocols/iso14443_3a/iso14443_3a_poller_sync.h"), |         File("protocols/iso14443_3a/iso14443_3a_poller_sync.h"), | ||||||
|         File("protocols/mf_ultralight/mf_ultralight_poller_sync.h"), |         File("protocols/mf_ultralight/mf_ultralight_poller_sync.h"), | ||||||
|         File("protocols/mf_classic/mf_classic_poller_sync.h"), |         File("protocols/mf_classic/mf_classic_poller_sync.h"), | ||||||
|  |         File("protocols/st25tb/st25tb_poller_sync.h"), | ||||||
|         # Misc |         # Misc | ||||||
|         File("helpers/nfc_util.h"), |         File("helpers/nfc_util.h"), | ||||||
|         File("helpers/iso14443_crc.h"), |         File("helpers/iso14443_crc.h"), | ||||||
|  | |||||||
| @ -232,3 +232,23 @@ St25tbData* st25tb_get_base_data(const St25tbData* data) { | |||||||
|     UNUSED(data); |     UNUSED(data); | ||||||
|     furi_crash("No base data"); |     furi_crash("No base data"); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | St25tbType st25tb_get_type_from_uid(const uint8_t* uid) { | ||||||
|  |     switch(uid[2] >> 2) { | ||||||
|  |     case 0x0: | ||||||
|  |     case 0x3: | ||||||
|  |         return St25tbTypeX4k; | ||||||
|  |     case 0x4: | ||||||
|  |         return St25tbTypeX512; | ||||||
|  |     case 0x6: | ||||||
|  |         return St25tbType512Ac; | ||||||
|  |     case 0x7: | ||||||
|  |         return St25tbType04k; | ||||||
|  |     case 0xc: | ||||||
|  |         return St25tbType512At; | ||||||
|  |     case 0xf: | ||||||
|  |         return St25tbType02k; | ||||||
|  |     default: | ||||||
|  |         furi_crash("unsupported st25tb type"); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | |||||||
| @ -1,6 +1,5 @@ | |||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include <toolbox/bit_buffer.h> |  | ||||||
| #include <nfc/protocols/nfc_device_base_i.h> | #include <nfc/protocols/nfc_device_base_i.h> | ||||||
| 
 | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| @ -27,6 +26,7 @@ typedef enum { | |||||||
|     St25tbErrorFieldOff, |     St25tbErrorFieldOff, | ||||||
|     St25tbErrorWrongCrc, |     St25tbErrorWrongCrc, | ||||||
|     St25tbErrorTimeout, |     St25tbErrorTimeout, | ||||||
|  |     St25tbErrorWriteFailed, | ||||||
| } St25tbError; | } St25tbError; | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
| @ -44,7 +44,6 @@ typedef struct { | |||||||
|     St25tbType type; |     St25tbType type; | ||||||
|     uint32_t blocks[ST25TB_MAX_BLOCKS]; |     uint32_t blocks[ST25TB_MAX_BLOCKS]; | ||||||
|     uint32_t system_otp_block; |     uint32_t system_otp_block; | ||||||
|     uint8_t chip_id; |  | ||||||
| } St25tbData; | } St25tbData; | ||||||
| 
 | 
 | ||||||
| extern const NfcDeviceBase nfc_device_st25tb; | extern const NfcDeviceBase nfc_device_st25tb; | ||||||
| @ -75,6 +74,8 @@ bool st25tb_set_uid(St25tbData* data, const uint8_t* uid, size_t uid_len); | |||||||
| 
 | 
 | ||||||
| St25tbData* st25tb_get_base_data(const St25tbData* data); | St25tbData* st25tb_get_base_data(const St25tbData* data); | ||||||
| 
 | 
 | ||||||
|  | St25tbType st25tb_get_type_from_uid(const uint8_t* uid); | ||||||
|  | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -1,13 +1,12 @@ | |||||||
| #include "protocols/nfc_protocol.h" | #include "st25tb_poller.h" | ||||||
| #include "protocols/st25tb/st25tb.h" |  | ||||||
| #include "st25tb_poller_i.h" | #include "st25tb_poller_i.h" | ||||||
| 
 | 
 | ||||||
| #include <nfc/protocols/nfc_poller_base.h> | #include <nfc/protocols/nfc_poller_base.h> | ||||||
| 
 | 
 | ||||||
| #include <furi.h> |  | ||||||
| 
 |  | ||||||
| #define TAG "ST25TBPoller" | #define TAG "ST25TBPoller" | ||||||
| 
 | 
 | ||||||
|  | typedef NfcCommand (*St25tbPollerStateHandler)(St25tbPoller* instance); | ||||||
|  | 
 | ||||||
| const St25tbData* st25tb_poller_get_data(St25tbPoller* instance) { | const St25tbData* st25tb_poller_get_data(St25tbPoller* instance) { | ||||||
|     furi_assert(instance); |     furi_assert(instance); | ||||||
|     furi_assert(instance->data); |     furi_assert(instance->data); | ||||||
| @ -20,6 +19,7 @@ static St25tbPoller* st25tb_poller_alloc(Nfc* nfc) { | |||||||
| 
 | 
 | ||||||
|     St25tbPoller* instance = malloc(sizeof(St25tbPoller)); |     St25tbPoller* instance = malloc(sizeof(St25tbPoller)); | ||||||
|     instance->nfc = nfc; |     instance->nfc = nfc; | ||||||
|  |     instance->state = St25tbPollerStateSelect; | ||||||
|     instance->tx_buffer = bit_buffer_alloc(ST25TB_POLLER_MAX_BUFFER_SIZE); |     instance->tx_buffer = bit_buffer_alloc(ST25TB_POLLER_MAX_BUFFER_SIZE); | ||||||
|     instance->rx_buffer = bit_buffer_alloc(ST25TB_POLLER_MAX_BUFFER_SIZE); |     instance->rx_buffer = bit_buffer_alloc(ST25TB_POLLER_MAX_BUFFER_SIZE); | ||||||
| 
 | 
 | ||||||
| @ -60,6 +60,128 @@ static void | |||||||
|     instance->context = context; |     instance->context = context; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static NfcCommand st25tb_poller_select_handler(St25tbPoller* instance) { | ||||||
|  |     NfcCommand command = NfcCommandContinue; | ||||||
|  | 
 | ||||||
|  |     do { | ||||||
|  |         St25tbError error = st25tb_poller_select(instance, NULL); | ||||||
|  |         if(error != St25tbErrorNone) { | ||||||
|  |             instance->state = St25tbPollerStateFailure; | ||||||
|  |             instance->st25tb_event_data.error = error; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         instance->st25tb_event.type = St25tbPollerEventTypeReady; | ||||||
|  |         instance->st25tb_event.data->ready.type = instance->data->type; | ||||||
|  |         command = instance->callback(instance->general_event, instance->context); | ||||||
|  |         instance->state = St25tbPollerStateRequestMode; | ||||||
|  |     } while(false); | ||||||
|  | 
 | ||||||
|  |     return command; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static NfcCommand st25tb_poller_request_mode_handler(St25tbPoller* instance) { | ||||||
|  |     NfcCommand command = NfcCommandContinue; | ||||||
|  |     instance->st25tb_event.type = St25tbPollerEventTypeRequestMode; | ||||||
|  |     command = instance->callback(instance->general_event, instance->context); | ||||||
|  | 
 | ||||||
|  |     St25tbPollerEventDataModeRequest* mode_request_data = | ||||||
|  |         &instance->st25tb_event_data.mode_request; | ||||||
|  | 
 | ||||||
|  |     furi_assert(mode_request_data->mode < St25tbPollerModeNum); | ||||||
|  | 
 | ||||||
|  |     if(mode_request_data->mode == St25tbPollerModeRead) { | ||||||
|  |         instance->state = St25tbPollerStateRead; | ||||||
|  |         instance->poller_ctx.read.current_block = 0; | ||||||
|  |     } else { | ||||||
|  |         instance->state = St25tbPollerStateWrite; | ||||||
|  |         instance->poller_ctx.write.block_number = | ||||||
|  |             mode_request_data->params.write_params.block_number; | ||||||
|  |         instance->poller_ctx.write.block_data = mode_request_data->params.write_params.block_data; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return command; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static NfcCommand st25tb_poller_read_handler(St25tbPoller* instance) { | ||||||
|  |     St25tbError error = St25tbErrorNone; | ||||||
|  | 
 | ||||||
|  |     do { | ||||||
|  |         uint8_t total_blocks = st25tb_get_block_count(instance->data->type); | ||||||
|  |         uint8_t* current_block = &instance->poller_ctx.read.current_block; | ||||||
|  |         if(*current_block == total_blocks) { | ||||||
|  |             error = st25tb_poller_read_block( | ||||||
|  |                 instance, &instance->data->system_otp_block, ST25TB_SYSTEM_OTP_BLOCK); | ||||||
|  |             if(error != St25tbErrorNone) { | ||||||
|  |                 FURI_LOG_E(TAG, "Failed to read OTP block"); | ||||||
|  |                 instance->state = St25tbPollerStateFailure; | ||||||
|  |                 instance->st25tb_event_data.error = error; | ||||||
|  |                 break; | ||||||
|  |             } else { | ||||||
|  |                 instance->state = St25tbPollerStateSuccess; | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             error = st25tb_poller_read_block( | ||||||
|  |                 instance, &instance->data->blocks[*current_block], *current_block); | ||||||
|  |             if(error != St25tbErrorNone) { | ||||||
|  |                 FURI_LOG_E(TAG, "Failed to read block %d", *current_block); | ||||||
|  |                 instance->state = St25tbPollerStateFailure; | ||||||
|  |                 instance->st25tb_event_data.error = error; | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             *current_block += 1; | ||||||
|  |         } | ||||||
|  |     } while(false); | ||||||
|  | 
 | ||||||
|  |     return NfcCommandContinue; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static NfcCommand st25tb_poller_write_handler(St25tbPoller* instance) { | ||||||
|  |     St25tbPollerWriteContext* write_ctx = &instance->poller_ctx.write; | ||||||
|  |     St25tbError error = | ||||||
|  |         st25tb_poller_write_block(instance, write_ctx->block_data, write_ctx->block_number); | ||||||
|  | 
 | ||||||
|  |     if(error == St25tbErrorNone) { | ||||||
|  |         instance->state = St25tbPollerStateSuccess; | ||||||
|  |     } else { | ||||||
|  |         instance->state = St25tbPollerStateFailure; | ||||||
|  |         instance->st25tb_event_data.error = error; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return NfcCommandContinue; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | NfcCommand st25tb_poller_success_handler(St25tbPoller* instance) { | ||||||
|  |     NfcCommand command = NfcCommandContinue; | ||||||
|  |     instance->st25tb_event.type = St25tbPollerEventTypeSuccess; | ||||||
|  |     command = instance->callback(instance->general_event, instance->context); | ||||||
|  |     furi_delay_ms(100); | ||||||
|  |     instance->state = St25tbPollerStateRequestMode; | ||||||
|  | 
 | ||||||
|  |     return command; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | NfcCommand st25tb_poller_failure_handler(St25tbPoller* instance) { | ||||||
|  |     NfcCommand command = NfcCommandContinue; | ||||||
|  |     instance->st25tb_event.type = St25tbPollerEventTypeFailure; | ||||||
|  |     command = instance->callback(instance->general_event, instance->context); | ||||||
|  |     furi_delay_ms(100); | ||||||
|  |     instance->state = St25tbPollerStateSelect; | ||||||
|  | 
 | ||||||
|  |     return command; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static St25tbPollerStateHandler st25tb_poller_state_handlers[St25tbPollerStateNum] = { | ||||||
|  |     [St25tbPollerStateSelect] = st25tb_poller_select_handler, | ||||||
|  |     [St25tbPollerStateRequestMode] = st25tb_poller_request_mode_handler, | ||||||
|  |     [St25tbPollerStateRead] = st25tb_poller_read_handler, | ||||||
|  |     [St25tbPollerStateWrite] = st25tb_poller_write_handler, | ||||||
|  |     [St25tbPollerStateSuccess] = st25tb_poller_success_handler, | ||||||
|  |     [St25tbPollerStateFailure] = st25tb_poller_failure_handler, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| static NfcCommand st25tb_poller_run(NfcGenericEvent event, void* context) { | static NfcCommand st25tb_poller_run(NfcGenericEvent event, void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     furi_assert(event.protocol == NfcProtocolInvalid); |     furi_assert(event.protocol == NfcProtocolInvalid); | ||||||
| @ -69,26 +191,10 @@ static NfcCommand st25tb_poller_run(NfcGenericEvent event, void* context) { | |||||||
|     NfcEvent* nfc_event = event.event_data; |     NfcEvent* nfc_event = event.event_data; | ||||||
|     NfcCommand command = NfcCommandContinue; |     NfcCommand command = NfcCommandContinue; | ||||||
| 
 | 
 | ||||||
|     if(nfc_event->type == NfcEventTypePollerReady) { |     furi_assert(instance->state < St25tbPollerStateNum); | ||||||
|         if(instance->state != St25tbPollerStateActivated) { |  | ||||||
|             St25tbError error = st25tb_poller_activate(instance, instance->data); |  | ||||||
| 
 | 
 | ||||||
|             if(error == St25tbErrorNone) { |     if(nfc_event->type == NfcEventTypePollerReady) { | ||||||
|                 instance->st25tb_event.type = St25tbPollerEventTypeReady; |         command = st25tb_poller_state_handlers[instance->state](instance); | ||||||
|                 instance->st25tb_event_data.error = error; |  | ||||||
|                 command = instance->callback(instance->general_event, instance->context); |  | ||||||
|             } else { |  | ||||||
|                 instance->st25tb_event.type = St25tbPollerEventTypeError; |  | ||||||
|                 instance->st25tb_event_data.error = error; |  | ||||||
|                 command = instance->callback(instance->general_event, instance->context); |  | ||||||
|                 // Add delay to switch context
 |  | ||||||
|                 furi_delay_ms(100); |  | ||||||
|             } |  | ||||||
|         } else { |  | ||||||
|             instance->st25tb_event.type = St25tbPollerEventTypeReady; |  | ||||||
|             instance->st25tb_event_data.error = St25tbErrorNone; |  | ||||||
|             command = instance->callback(instance->general_event, instance->context); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return command; |     return command; | ||||||
| @ -103,7 +209,7 @@ static bool st25tb_poller_detect(NfcGenericEvent event, void* context) { | |||||||
|     bool protocol_detected = false; |     bool protocol_detected = false; | ||||||
|     St25tbPoller* instance = context; |     St25tbPoller* instance = context; | ||||||
|     NfcEvent* nfc_event = event.event_data; |     NfcEvent* nfc_event = event.event_data; | ||||||
|     furi_assert(instance->state == St25tbPollerStateIdle); |     furi_assert(instance->state == St25tbPollerStateSelect); | ||||||
| 
 | 
 | ||||||
|     if(nfc_event->type == NfcEventTypePollerReady) { |     if(nfc_event->type == NfcEventTypePollerReady) { | ||||||
|         St25tbError error = st25tb_poller_initiate(instance, NULL); |         St25tbError error = st25tb_poller_initiate(instance, NULL); | ||||||
|  | |||||||
| @ -3,8 +3,6 @@ | |||||||
| #include "st25tb.h" | #include "st25tb.h" | ||||||
| #include <lib/nfc/nfc.h> | #include <lib/nfc/nfc.h> | ||||||
| 
 | 
 | ||||||
| #include <nfc/nfc_poller.h> |  | ||||||
| 
 |  | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| extern "C" { | extern "C" { | ||||||
| #endif | #endif | ||||||
| @ -12,11 +10,40 @@ extern "C" { | |||||||
| typedef struct St25tbPoller St25tbPoller; | typedef struct St25tbPoller St25tbPoller; | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     St25tbPollerEventTypeError, |  | ||||||
|     St25tbPollerEventTypeReady, |     St25tbPollerEventTypeReady, | ||||||
|  |     St25tbPollerEventTypeRequestMode, | ||||||
|  |     St25tbPollerEventTypeFailure, | ||||||
|  |     St25tbPollerEventTypeSuccess, | ||||||
| } St25tbPollerEventType; | } St25tbPollerEventType; | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|  |     St25tbType type; | ||||||
|  | } St25tbPollerReadyData; | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     St25tbPollerModeRead, | ||||||
|  |     St25tbPollerModeWrite, | ||||||
|  | 
 | ||||||
|  |     St25tbPollerModeNum, | ||||||
|  | } St25tbPollerMode; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     uint8_t block_number; | ||||||
|  |     uint32_t block_data; | ||||||
|  | } St25tbPollerEventDataModeRequestWriteParams; | ||||||
|  | 
 | ||||||
|  | typedef union { | ||||||
|  |     St25tbPollerEventDataModeRequestWriteParams write_params; | ||||||
|  | } St25tbPollerEventDataModeRequestParams; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     St25tbPollerMode mode; | ||||||
|  |     St25tbPollerEventDataModeRequestParams params; | ||||||
|  | } St25tbPollerEventDataModeRequest; | ||||||
|  | 
 | ||||||
|  | typedef union { | ||||||
|  |     St25tbPollerReadyData ready; | ||||||
|  |     St25tbPollerEventDataModeRequest mode_request; | ||||||
|     St25tbError error; |     St25tbError error; | ||||||
| } St25tbPollerEventData; | } St25tbPollerEventData; | ||||||
| 
 | 
 | ||||||
| @ -31,15 +58,18 @@ St25tbError st25tb_poller_send_frame( | |||||||
|     BitBuffer* rx_buffer, |     BitBuffer* rx_buffer, | ||||||
|     uint32_t fwt); |     uint32_t fwt); | ||||||
| 
 | 
 | ||||||
| St25tbError st25tb_poller_initiate(St25tbPoller* instance, uint8_t* chip_id); | St25tbError st25tb_poller_initiate(St25tbPoller* instance, uint8_t* chip_id_ptr); | ||||||
| 
 | 
 | ||||||
| St25tbError st25tb_poller_activate(St25tbPoller* instance, St25tbData* data); | St25tbError st25tb_poller_select(St25tbPoller* instance, uint8_t* chip_id_ptr); | ||||||
| 
 | 
 | ||||||
| St25tbError st25tb_poller_get_uid(St25tbPoller* instance, uint8_t* uid); | St25tbError st25tb_poller_get_uid(St25tbPoller* instance, uint8_t* uid); | ||||||
| 
 | 
 | ||||||
| St25tbError | St25tbError | ||||||
|     st25tb_poller_read_block(St25tbPoller* instance, uint32_t* block, uint8_t block_number); |     st25tb_poller_read_block(St25tbPoller* instance, uint32_t* block, uint8_t block_number); | ||||||
| 
 | 
 | ||||||
|  | St25tbError | ||||||
|  |     st25tb_poller_write_block(St25tbPoller* instance, uint32_t block, uint8_t block_number); | ||||||
|  | 
 | ||||||
| St25tbError st25tb_poller_halt(St25tbPoller* instance); | St25tbError st25tb_poller_halt(St25tbPoller* instance); | ||||||
| 
 | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
|  | |||||||
| @ -1,8 +1,5 @@ | |||||||
| #include "st25tb_poller_i.h" | #include "st25tb_poller_i.h" | ||||||
| 
 | 
 | ||||||
| #include "bit_buffer.h" |  | ||||||
| #include "core/core_defines.h" |  | ||||||
| #include "protocols/st25tb/st25tb.h" |  | ||||||
| #include <nfc/helpers/iso14443_crc.h> | #include <nfc/helpers/iso14443_crc.h> | ||||||
| 
 | 
 | ||||||
| #define TAG "ST25TBPoller" | #define TAG "ST25TBPoller" | ||||||
| @ -18,17 +15,7 @@ static St25tbError st25tb_poller_process_error(NfcError error) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static St25tbError st25tb_poller_prepare_trx(St25tbPoller* instance) { | St25tbError st25tb_poller_send_frame( | ||||||
|     furi_assert(instance); |  | ||||||
| 
 |  | ||||||
|     if(instance->state == St25tbPollerStateIdle) { |  | ||||||
|         return st25tb_poller_activate(instance, NULL); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return St25tbErrorNone; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static St25tbError st25tb_poller_frame_exchange( |  | ||||||
|     St25tbPoller* instance, |     St25tbPoller* instance, | ||||||
|     const BitBuffer* tx_buffer, |     const BitBuffer* tx_buffer, | ||||||
|     BitBuffer* rx_buffer, |     BitBuffer* rx_buffer, | ||||||
| @ -48,7 +35,7 @@ static St25tbError st25tb_poller_frame_exchange( | |||||||
|         NfcError error = |         NfcError error = | ||||||
|             nfc_poller_trx(instance->nfc, instance->tx_buffer, instance->rx_buffer, fwt); |             nfc_poller_trx(instance->nfc, instance->tx_buffer, instance->rx_buffer, fwt); | ||||||
|         if(error != NfcErrorNone) { |         if(error != NfcErrorNone) { | ||||||
|             FURI_LOG_D(TAG, "error during trx: %d", error); |             FURI_LOG_T(TAG, "error during trx: %d", error); | ||||||
|             ret = st25tb_poller_process_error(error); |             ret = st25tb_poller_process_error(error); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| @ -65,32 +52,11 @@ static St25tbError st25tb_poller_frame_exchange( | |||||||
|     return ret; |     return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| St25tbType st25tb_get_type_from_uid(const uint8_t uid[ST25TB_UID_SIZE]) { | St25tbError st25tb_poller_initiate(St25tbPoller* instance, uint8_t* chip_id_ptr) { | ||||||
|     switch(uid[2] >> 2) { |  | ||||||
|     case 0x0: |  | ||||||
|     case 0x3: |  | ||||||
|         return St25tbTypeX4k; |  | ||||||
|     case 0x4: |  | ||||||
|         return St25tbTypeX512; |  | ||||||
|     case 0x6: |  | ||||||
|         return St25tbType512Ac; |  | ||||||
|     case 0x7: |  | ||||||
|         return St25tbType04k; |  | ||||||
|     case 0xc: |  | ||||||
|         return St25tbType512At; |  | ||||||
|     case 0xf: |  | ||||||
|         return St25tbType02k; |  | ||||||
|     default: |  | ||||||
|         furi_crash("unsupported st25tb type"); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| St25tbError st25tb_poller_initiate(St25tbPoller* instance, uint8_t* chip_id) { |  | ||||||
|     // Send Initiate()
 |     // Send Initiate()
 | ||||||
|     furi_assert(instance); |     furi_assert(instance); | ||||||
|     furi_assert(instance->nfc); |     furi_assert(instance->nfc); | ||||||
| 
 | 
 | ||||||
|     instance->state = St25tbPollerStateInitiateInProgress; |  | ||||||
|     bit_buffer_reset(instance->tx_buffer); |     bit_buffer_reset(instance->tx_buffer); | ||||||
|     bit_buffer_reset(instance->rx_buffer); |     bit_buffer_reset(instance->rx_buffer); | ||||||
|     bit_buffer_append_byte(instance->tx_buffer, 0x06); |     bit_buffer_append_byte(instance->tx_buffer, 0x06); | ||||||
| @ -98,77 +64,90 @@ St25tbError st25tb_poller_initiate(St25tbPoller* instance, uint8_t* chip_id) { | |||||||
| 
 | 
 | ||||||
|     St25tbError ret; |     St25tbError ret; | ||||||
|     do { |     do { | ||||||
|         ret = st25tb_poller_frame_exchange( |         ret = st25tb_poller_send_frame( | ||||||
|             instance, instance->tx_buffer, instance->rx_buffer, ST25TB_FDT_FC); |             instance, instance->tx_buffer, instance->rx_buffer, ST25TB_FDT_FC); | ||||||
|         if(ret != St25tbErrorNone) { |         if(ret != St25tbErrorNone) { | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if(bit_buffer_get_size_bytes(instance->rx_buffer) != 1) { |         if(bit_buffer_get_size_bytes(instance->rx_buffer) != 1) { | ||||||
|             FURI_LOG_D(TAG, "Unexpected Initiate response size"); |             FURI_LOG_E(TAG, "Unexpected Initiate response size"); | ||||||
|             ret = St25tbErrorCommunication; |             ret = St25tbErrorCommunication; | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         if(chip_id) { |         uint8_t chip_id = bit_buffer_get_byte(instance->rx_buffer, 0); | ||||||
|             *chip_id = bit_buffer_get_byte(instance->rx_buffer, 0); |         FURI_LOG_D(TAG, "Got chip_id=0x%02X", chip_id); | ||||||
|  |         if(chip_id_ptr) { | ||||||
|  |             *chip_id_ptr = bit_buffer_get_byte(instance->rx_buffer, 0); | ||||||
|         } |         } | ||||||
|     } while(false); |     } while(false); | ||||||
| 
 | 
 | ||||||
|     return ret; |     return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| St25tbError st25tb_poller_activate(St25tbPoller* instance, St25tbData* data) { | St25tbError st25tb_poller_select(St25tbPoller* instance, uint8_t* chip_id_ptr) { | ||||||
|     furi_assert(instance); |     furi_assert(instance); | ||||||
|     furi_assert(instance->nfc); |     furi_assert(instance->nfc); | ||||||
| 
 | 
 | ||||||
|     st25tb_reset(data); |  | ||||||
| 
 |  | ||||||
|     St25tbError ret; |     St25tbError ret; | ||||||
| 
 | 
 | ||||||
|     do { |     do { | ||||||
|         ret = st25tb_poller_initiate(instance, &data->chip_id); |         uint8_t chip_id; | ||||||
|  | 
 | ||||||
|  |         if(chip_id_ptr != NULL) { | ||||||
|  |             chip_id = *chip_id_ptr; | ||||||
|  |         } else { | ||||||
|  |             ret = st25tb_poller_initiate(instance, &chip_id); | ||||||
|             if(ret != St25tbErrorNone) { |             if(ret != St25tbErrorNone) { | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
| 
 |         } | ||||||
|         instance->state = St25tbPollerStateActivationInProgress; |  | ||||||
| 
 | 
 | ||||||
|         bit_buffer_reset(instance->tx_buffer); |         bit_buffer_reset(instance->tx_buffer); | ||||||
|         bit_buffer_reset(instance->rx_buffer); |         bit_buffer_reset(instance->rx_buffer); | ||||||
| 
 | 
 | ||||||
|         // Send Select(Chip_ID), let's just assume that collisions won't ever happen :D
 |         // Send Select(Chip_ID), let's just assume that collisions won't ever happen :D
 | ||||||
|         bit_buffer_append_byte(instance->tx_buffer, 0x0E); |         bit_buffer_append_byte(instance->tx_buffer, 0x0E); | ||||||
|         bit_buffer_append_byte(instance->tx_buffer, data->chip_id); |         bit_buffer_append_byte(instance->tx_buffer, chip_id); | ||||||
| 
 | 
 | ||||||
|         ret = st25tb_poller_frame_exchange( |         ret = st25tb_poller_send_frame( | ||||||
|             instance, instance->tx_buffer, instance->rx_buffer, ST25TB_FDT_FC); |             instance, instance->tx_buffer, instance->rx_buffer, ST25TB_FDT_FC); | ||||||
|         if(ret != St25tbErrorNone) { |         if(ret != St25tbErrorNone) { | ||||||
|             instance->state = St25tbPollerStateActivationFailed; |  | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if(bit_buffer_get_size_bytes(instance->rx_buffer) != 1) { |         if(bit_buffer_get_size_bytes(instance->rx_buffer) != 1) { | ||||||
|             FURI_LOG_D(TAG, "Unexpected Select response size"); |             FURI_LOG_E(TAG, "Unexpected Select response size"); | ||||||
|             instance->state = St25tbPollerStateActivationFailed; |  | ||||||
|             ret = St25tbErrorCommunication; |             ret = St25tbErrorCommunication; | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if(bit_buffer_get_byte(instance->rx_buffer, 0) != data->chip_id) { |         if(bit_buffer_get_byte(instance->rx_buffer, 0) != chip_id) { | ||||||
|             FURI_LOG_D(TAG, "ChipID mismatch"); |             FURI_LOG_E(TAG, "ChipID mismatch"); | ||||||
|             instance->state = St25tbPollerStateActivationFailed; |  | ||||||
|             ret = St25tbErrorColResFailed; |             ret = St25tbErrorColResFailed; | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         instance->state = St25tbPollerStateActivated; |  | ||||||
| 
 | 
 | ||||||
|         ret = st25tb_poller_get_uid(instance, data->uid); |         ret = st25tb_poller_get_uid(instance, instance->data->uid); | ||||||
|         if(ret != St25tbErrorNone) { |         if(ret != St25tbErrorNone) { | ||||||
|             instance->state = St25tbPollerStateActivationFailed; |  | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         data->type = st25tb_get_type_from_uid(data->uid); |  | ||||||
| 
 | 
 | ||||||
|  |         instance->data->type = st25tb_get_type_from_uid(instance->data->uid); | ||||||
|  |     } while(false); | ||||||
|  | 
 | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | St25tbError st25tb_poller_read(St25tbPoller* instance, St25tbData* data) { | ||||||
|  |     furi_assert(instance); | ||||||
|  |     furi_assert(instance->nfc); | ||||||
|  | 
 | ||||||
|  |     St25tbError ret; | ||||||
|  | 
 | ||||||
|  |     memcpy(data, instance->data, sizeof(St25tbData)); | ||||||
|  | 
 | ||||||
|  |     do { | ||||||
|         bool read_blocks = true; |         bool read_blocks = true; | ||||||
|         for(uint8_t i = 0; i < st25tb_get_block_count(data->type); i++) { |         for(uint8_t i = 0; i < st25tb_get_block_count(data->type); i++) { | ||||||
|             ret = st25tb_poller_read_block(instance, &data->blocks[i], i); |             ret = st25tb_poller_read_block(instance, &data->blocks[i], i); | ||||||
| @ -181,6 +160,9 @@ St25tbError st25tb_poller_activate(St25tbPoller* instance, St25tbData* data) { | |||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         ret = st25tb_poller_read_block(instance, &data->system_otp_block, ST25TB_SYSTEM_OTP_BLOCK); |         ret = st25tb_poller_read_block(instance, &data->system_otp_block, ST25TB_SYSTEM_OTP_BLOCK); | ||||||
|  |         if(ret != St25tbErrorNone) { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|     } while(false); |     } while(false); | ||||||
| 
 | 
 | ||||||
|     return ret; |     return ret; | ||||||
| @ -198,15 +180,14 @@ St25tbError st25tb_poller_get_uid(St25tbPoller* instance, uint8_t* uid) { | |||||||
| 
 | 
 | ||||||
|         bit_buffer_append_byte(instance->tx_buffer, 0x0B); |         bit_buffer_append_byte(instance->tx_buffer, 0x0B); | ||||||
| 
 | 
 | ||||||
|         ret = st25tb_poller_frame_exchange( |         ret = st25tb_poller_send_frame( | ||||||
|             instance, instance->tx_buffer, instance->rx_buffer, ST25TB_FDT_FC); |             instance, instance->tx_buffer, instance->rx_buffer, ST25TB_FDT_FC); | ||||||
|         if(ret != St25tbErrorNone) { |         if(ret != St25tbErrorNone) { | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if(bit_buffer_get_size_bytes(instance->rx_buffer) != ST25TB_UID_SIZE) { |         if(bit_buffer_get_size_bytes(instance->rx_buffer) != ST25TB_UID_SIZE) { | ||||||
|             FURI_LOG_D(TAG, "Unexpected Get_UID() response size"); |             FURI_LOG_E(TAG, "Unexpected Get_UID() response size"); | ||||||
|             instance->state = St25tbPollerStateActivationFailed; |  | ||||||
|             ret = St25tbErrorCommunication; |             ret = St25tbErrorCommunication; | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| @ -215,6 +196,17 @@ St25tbError st25tb_poller_get_uid(St25tbPoller* instance, uint8_t* uid) { | |||||||
|         FURI_SWAP(uid[1], uid[6]); |         FURI_SWAP(uid[1], uid[6]); | ||||||
|         FURI_SWAP(uid[2], uid[5]); |         FURI_SWAP(uid[2], uid[5]); | ||||||
|         FURI_SWAP(uid[3], uid[4]); |         FURI_SWAP(uid[3], uid[4]); | ||||||
|  |         FURI_LOG_I( | ||||||
|  |             TAG, | ||||||
|  |             "Got tag with uid: %02X %02X %02X %02X %02X %02X %02X %02X", | ||||||
|  |             uid[0], | ||||||
|  |             uid[1], | ||||||
|  |             uid[2], | ||||||
|  |             uid[3], | ||||||
|  |             uid[4], | ||||||
|  |             uid[5], | ||||||
|  |             uid[6], | ||||||
|  |             uid[7]); | ||||||
|     } while(false); |     } while(false); | ||||||
|     return ret; |     return ret; | ||||||
| } | } | ||||||
| @ -227,7 +219,7 @@ St25tbError | |||||||
|     furi_assert( |     furi_assert( | ||||||
|         (block_number <= st25tb_get_block_count(instance->data->type)) || |         (block_number <= st25tb_get_block_count(instance->data->type)) || | ||||||
|         block_number == ST25TB_SYSTEM_OTP_BLOCK); |         block_number == ST25TB_SYSTEM_OTP_BLOCK); | ||||||
|     FURI_LOG_D(TAG, "reading block %d", block_number); |     FURI_LOG_T(TAG, "reading block %d", block_number); | ||||||
|     bit_buffer_reset(instance->tx_buffer); |     bit_buffer_reset(instance->tx_buffer); | ||||||
|     bit_buffer_reset(instance->rx_buffer); |     bit_buffer_reset(instance->rx_buffer); | ||||||
| 
 | 
 | ||||||
| @ -236,19 +228,64 @@ St25tbError | |||||||
|     bit_buffer_append_byte(instance->tx_buffer, block_number); |     bit_buffer_append_byte(instance->tx_buffer, block_number); | ||||||
|     St25tbError ret; |     St25tbError ret; | ||||||
|     do { |     do { | ||||||
|         ret = st25tb_poller_frame_exchange( |         ret = st25tb_poller_send_frame( | ||||||
|             instance, instance->tx_buffer, instance->rx_buffer, ST25TB_FDT_FC); |             instance, instance->tx_buffer, instance->rx_buffer, ST25TB_FDT_FC); | ||||||
|         if(ret != St25tbErrorNone) { |         if(ret != St25tbErrorNone) { | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if(bit_buffer_get_size_bytes(instance->rx_buffer) != ST25TB_BLOCK_SIZE) { |         if(bit_buffer_get_size_bytes(instance->rx_buffer) != ST25TB_BLOCK_SIZE) { | ||||||
|             FURI_LOG_D(TAG, "Unexpected Read_block(Addr) response size"); |             FURI_LOG_E(TAG, "Unexpected Read_block(Addr) response size"); | ||||||
|             ret = St25tbErrorCommunication; |             ret = St25tbErrorCommunication; | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         bit_buffer_write_bytes(instance->rx_buffer, block, ST25TB_BLOCK_SIZE); |         bit_buffer_write_bytes(instance->rx_buffer, block, ST25TB_BLOCK_SIZE); | ||||||
|         FURI_LOG_D(TAG, "read result: %08lX", *block); |         FURI_LOG_D(TAG, "Read_block(%d) result: %08lX", block_number, *block); | ||||||
|  |     } while(false); | ||||||
|  | 
 | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | St25tbError | ||||||
|  |     st25tb_poller_write_block(St25tbPoller* instance, uint32_t block, uint8_t block_number) { | ||||||
|  |     furi_assert(instance); | ||||||
|  |     furi_assert(instance->nfc); | ||||||
|  |     furi_assert( | ||||||
|  |         (block_number <= st25tb_get_block_count(instance->data->type)) || | ||||||
|  |         block_number == ST25TB_SYSTEM_OTP_BLOCK); | ||||||
|  |     FURI_LOG_T(TAG, "writing block %d", block_number); | ||||||
|  |     bit_buffer_reset(instance->tx_buffer); | ||||||
|  | 
 | ||||||
|  |     // Send Write_block(Addr, Data)
 | ||||||
|  |     bit_buffer_append_byte(instance->tx_buffer, 0x09); | ||||||
|  |     bit_buffer_append_byte(instance->tx_buffer, block_number); | ||||||
|  |     bit_buffer_append_bytes(instance->tx_buffer, (uint8_t*)&block, ST25TB_BLOCK_SIZE); | ||||||
|  |     St25tbError ret; | ||||||
|  |     do { | ||||||
|  |         ret = st25tb_poller_send_frame( | ||||||
|  |             instance, instance->tx_buffer, instance->rx_buffer, ST25TB_FDT_FC); | ||||||
|  |         if(ret != St25tbErrorTimeout) { // tag doesn't ack writes so timeout are expected.
 | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         furi_delay_ms(7); // 7ms is the max programming time as per datasheet
 | ||||||
|  | 
 | ||||||
|  |         uint32_t block_check; | ||||||
|  |         ret = st25tb_poller_read_block(instance, &block_check, block_number); | ||||||
|  |         if(ret != St25tbErrorNone) { | ||||||
|  |             FURI_LOG_E(TAG, "write verification failed: read error"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         if(block_check != block) { | ||||||
|  |             FURI_LOG_E( | ||||||
|  |                 TAG, | ||||||
|  |                 "write verification failed: wrote %08lX but read back %08lX", | ||||||
|  |                 block, | ||||||
|  |                 block_check); | ||||||
|  |             ret = St25tbErrorWriteFailed; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         FURI_LOG_D(TAG, "wrote %08lX to block %d", block, block_number); | ||||||
|     } while(false); |     } while(false); | ||||||
| 
 | 
 | ||||||
|     return ret; |     return ret; | ||||||
| @ -266,30 +303,13 @@ St25tbError st25tb_poller_halt(St25tbPoller* instance) { | |||||||
|     St25tbError ret; |     St25tbError ret; | ||||||
| 
 | 
 | ||||||
|     do { |     do { | ||||||
|         ret = st25tb_poller_frame_exchange( |         ret = st25tb_poller_send_frame( | ||||||
|             instance, instance->tx_buffer, instance->rx_buffer, ST25TB_FDT_FC); |             instance, instance->tx_buffer, instance->rx_buffer, ST25TB_FDT_FC); | ||||||
|         if(ret != St25tbErrorTimeout) { |         if(ret != St25tbErrorTimeout) { | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         instance->state = St25tbPollerStateIdle; |         instance->state = St25tbPollerStateSelect; | ||||||
|     } while(false); |  | ||||||
| 
 |  | ||||||
|     return ret; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| St25tbError st25tb_poller_send_frame( |  | ||||||
|     St25tbPoller* instance, |  | ||||||
|     const BitBuffer* tx_buffer, |  | ||||||
|     BitBuffer* rx_buffer, |  | ||||||
|     uint32_t fwt) { |  | ||||||
|     St25tbError ret; |  | ||||||
| 
 |  | ||||||
|     do { |  | ||||||
|         ret = st25tb_poller_prepare_trx(instance); |  | ||||||
|         if(ret != St25tbErrorNone) break; |  | ||||||
| 
 |  | ||||||
|         ret = st25tb_poller_frame_exchange(instance, tx_buffer, rx_buffer, fwt); |  | ||||||
|     } while(false); |     } while(false); | ||||||
| 
 | 
 | ||||||
|     return ret; |     return ret; | ||||||
|  | |||||||
| @ -1,8 +1,9 @@ | |||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include "protocols/st25tb/st25tb.h" |  | ||||||
| #include "st25tb_poller.h" | #include "st25tb_poller.h" | ||||||
| 
 | 
 | ||||||
|  | #include <nfc/nfc_poller.h> | ||||||
|  | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| extern "C" { | extern "C" { | ||||||
| #endif | #endif | ||||||
| @ -10,14 +11,30 @@ extern "C" { | |||||||
| #define ST25TB_POLLER_MAX_BUFFER_SIZE (16U) | #define ST25TB_POLLER_MAX_BUFFER_SIZE (16U) | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     St25tbPollerStateIdle, |     St25tbPollerStateSelect, | ||||||
|     St25tbPollerStateInitiateInProgress, |     St25tbPollerStateRequestMode, | ||||||
|     St25tbPollerStateInitiateFailed, |     St25tbPollerStateRead, | ||||||
|     St25tbPollerStateActivationInProgress, |     St25tbPollerStateWrite, | ||||||
|     St25tbPollerStateActivationFailed, |     St25tbPollerStateSuccess, | ||||||
|     St25tbPollerStateActivated, |     St25tbPollerStateFailure, | ||||||
|  | 
 | ||||||
|  |     St25tbPollerStateNum, | ||||||
| } St25tbPollerState; | } St25tbPollerState; | ||||||
| 
 | 
 | ||||||
|  | typedef struct { | ||||||
|  |     uint8_t current_block; | ||||||
|  | } St25tbPollerReadContext; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     uint8_t block_number; | ||||||
|  |     uint32_t block_data; | ||||||
|  | } St25tbPollerWriteContext; | ||||||
|  | 
 | ||||||
|  | typedef union { | ||||||
|  |     St25tbPollerReadContext read; | ||||||
|  |     St25tbPollerWriteContext write; | ||||||
|  | } St25tbPollerContext; | ||||||
|  | 
 | ||||||
| struct St25tbPoller { | struct St25tbPoller { | ||||||
|     Nfc* nfc; |     Nfc* nfc; | ||||||
|     St25tbPollerState state; |     St25tbPollerState state; | ||||||
| @ -25,6 +42,8 @@ struct St25tbPoller { | |||||||
|     BitBuffer* tx_buffer; |     BitBuffer* tx_buffer; | ||||||
|     BitBuffer* rx_buffer; |     BitBuffer* rx_buffer; | ||||||
| 
 | 
 | ||||||
|  |     St25tbPollerContext poller_ctx; | ||||||
|  | 
 | ||||||
|     NfcGenericEvent general_event; |     NfcGenericEvent general_event; | ||||||
|     St25tbPollerEvent st25tb_event; |     St25tbPollerEvent st25tb_event; | ||||||
|     St25tbPollerEventData st25tb_event_data; |     St25tbPollerEventData st25tb_event_data; | ||||||
|  | |||||||
							
								
								
									
										211
									
								
								lib/nfc/protocols/st25tb/st25tb_poller_sync.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										211
									
								
								lib/nfc/protocols/st25tb/st25tb_poller_sync.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,211 @@ | |||||||
|  | #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; | ||||||
|  | } | ||||||
							
								
								
									
										20
									
								
								lib/nfc/protocols/st25tb/st25tb_poller_sync.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								lib/nfc/protocols/st25tb/st25tb_poller_sync.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "st25tb.h" | ||||||
|  | #include <nfc/nfc.h> | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | St25tbError st25tb_poller_sync_read_block(Nfc* nfc, uint8_t block_num, uint32_t* block); | ||||||
|  | 
 | ||||||
|  | St25tbError st25tb_poller_sync_write_block(Nfc* nfc, uint8_t block_num, uint32_t block); | ||||||
|  | 
 | ||||||
|  | St25tbError st25tb_poller_sync_detect_type(Nfc* nfc, St25tbType* type); | ||||||
|  | 
 | ||||||
|  | St25tbError st25tb_poller_sync_read(Nfc* nfc, St25tbData* data); | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
| @ -1,5 +1,5 @@ | |||||||
| entry,status,name,type,params | entry,status,name,type,params | ||||||
| Version,+,48.0,, | Version,+,49.0,, | ||||||
| Header,+,applications/services/bt/bt_service/bt.h,, | Header,+,applications/services/bt/bt_service/bt.h,, | ||||||
| Header,+,applications/services/cli/cli.h,, | Header,+,applications/services/cli/cli.h,, | ||||||
| Header,+,applications/services/cli/cli_vcp.h,, | Header,+,applications/services/cli/cli_vcp.h,, | ||||||
|  | |||||||
| 
 | 
| @ -1,5 +1,5 @@ | |||||||
| entry,status,name,type,params | entry,status,name,type,params | ||||||
| Version,+,48.0,, | Version,+,49.0,, | ||||||
| Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, | Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, | ||||||
| Header,+,applications/services/bt/bt_service/bt.h,, | Header,+,applications/services/bt/bt_service/bt.h,, | ||||||
| Header,+,applications/services/cli/cli.h,, | Header,+,applications/services/cli/cli.h,, | ||||||
| @ -145,6 +145,7 @@ Header,+,lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.h,, | |||||||
| Header,+,lib/nfc/protocols/slix/slix.h,, | Header,+,lib/nfc/protocols/slix/slix.h,, | ||||||
| Header,+,lib/nfc/protocols/st25tb/st25tb.h,, | Header,+,lib/nfc/protocols/st25tb/st25tb.h,, | ||||||
| Header,+,lib/nfc/protocols/st25tb/st25tb_poller.h,, | Header,+,lib/nfc/protocols/st25tb/st25tb_poller.h,, | ||||||
|  | Header,+,lib/nfc/protocols/st25tb/st25tb_poller_sync.h,, | ||||||
| Header,+,lib/one_wire/maxim_crc.h,, | Header,+,lib/one_wire/maxim_crc.h,, | ||||||
| Header,+,lib/one_wire/one_wire_host.h,, | Header,+,lib/one_wire/one_wire_host.h,, | ||||||
| Header,+,lib/one_wire/one_wire_slave.h,, | Header,+,lib/one_wire/one_wire_slave.h,, | ||||||
| @ -2810,15 +2811,21 @@ Function,+,st25tb_free,void,St25tbData* | |||||||
| Function,+,st25tb_get_base_data,St25tbData*,const St25tbData* | Function,+,st25tb_get_base_data,St25tbData*,const St25tbData* | ||||||
| Function,+,st25tb_get_block_count,uint8_t,St25tbType | Function,+,st25tb_get_block_count,uint8_t,St25tbType | ||||||
| Function,+,st25tb_get_device_name,const char*,"const St25tbData*, NfcDeviceNameType" | Function,+,st25tb_get_device_name,const char*,"const St25tbData*, NfcDeviceNameType" | ||||||
|  | Function,+,st25tb_get_type_from_uid,St25tbType,const uint8_t* | ||||||
| Function,+,st25tb_get_uid,const uint8_t*,"const St25tbData*, size_t*" | Function,+,st25tb_get_uid,const uint8_t*,"const St25tbData*, size_t*" | ||||||
| Function,+,st25tb_is_equal,_Bool,"const St25tbData*, const St25tbData*" | Function,+,st25tb_is_equal,_Bool,"const St25tbData*, const St25tbData*" | ||||||
| Function,+,st25tb_load,_Bool,"St25tbData*, FlipperFormat*, uint32_t" | Function,+,st25tb_load,_Bool,"St25tbData*, FlipperFormat*, uint32_t" | ||||||
| Function,+,st25tb_poller_activate,St25tbError,"St25tbPoller*, St25tbData*" |  | ||||||
| Function,+,st25tb_poller_get_uid,St25tbError,"St25tbPoller*, uint8_t*" | Function,+,st25tb_poller_get_uid,St25tbError,"St25tbPoller*, uint8_t*" | ||||||
| Function,+,st25tb_poller_halt,St25tbError,St25tbPoller* | Function,+,st25tb_poller_halt,St25tbError,St25tbPoller* | ||||||
| Function,+,st25tb_poller_initiate,St25tbError,"St25tbPoller*, uint8_t*" | Function,+,st25tb_poller_initiate,St25tbError,"St25tbPoller*, uint8_t*" | ||||||
| Function,+,st25tb_poller_read_block,St25tbError,"St25tbPoller*, uint32_t*, uint8_t" | Function,+,st25tb_poller_read_block,St25tbError,"St25tbPoller*, uint32_t*, uint8_t" | ||||||
|  | Function,+,st25tb_poller_select,St25tbError,"St25tbPoller*, uint8_t*" | ||||||
| Function,+,st25tb_poller_send_frame,St25tbError,"St25tbPoller*, const BitBuffer*, BitBuffer*, uint32_t" | Function,+,st25tb_poller_send_frame,St25tbError,"St25tbPoller*, const BitBuffer*, BitBuffer*, uint32_t" | ||||||
|  | Function,+,st25tb_poller_sync_detect_type,St25tbError,"Nfc*, St25tbType*" | ||||||
|  | Function,+,st25tb_poller_sync_read,St25tbError,"Nfc*, St25tbData*" | ||||||
|  | Function,+,st25tb_poller_sync_read_block,St25tbError,"Nfc*, uint8_t, uint32_t*" | ||||||
|  | Function,+,st25tb_poller_sync_write_block,St25tbError,"Nfc*, uint8_t, uint32_t" | ||||||
|  | Function,+,st25tb_poller_write_block,St25tbError,"St25tbPoller*, uint32_t, uint8_t" | ||||||
| Function,+,st25tb_reset,void,St25tbData* | Function,+,st25tb_reset,void,St25tbData* | ||||||
| Function,+,st25tb_save,_Bool,"const St25tbData*, FlipperFormat*" | Function,+,st25tb_save,_Bool,"const St25tbData*, FlipperFormat*" | ||||||
| Function,+,st25tb_set_uid,_Bool,"St25tbData*, const uint8_t*, size_t" | Function,+,st25tb_set_uid,_Bool,"St25tbData*, const uint8_t*, size_t" | ||||||
|  | |||||||
| 
 | 
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Augusto Zanellato
						Augusto Zanellato