#include "mf_ultralight_poller_sync.h" #include "mf_ultralight_poller_i.h" #include #include #define MF_ULTRALIGHT_POLLER_COMPLETE_EVENT (1UL << 0) typedef enum { MfUltralightPollerCmdTypeReadPage, MfUltralightPollerCmdTypeWritePage, MfUltralightPollerCmdTypeReadVersion, MfUltralightPollerCmdTypeReadSignature, MfUltralightPollerCmdTypeReadCounter, MfUltralightPollerCmdTypeReadTearingFlag, MfUltralightPollerCmdTypeNum, } MfUltralightPollerCmdType; typedef struct { MfUltralightPollerCmdType cmd_type; FuriThreadId thread_id; MfUltralightError error; MfUltralightPollerContextData data; } MfUltralightPollerContext; typedef MfUltralightError (*MfUltralightPollerCmdHandler)( MfUltralightPoller* poller, MfUltralightPollerContextData* data); MfUltralightError mf_ultralight_poller_read_page_handler( MfUltralightPoller* poller, MfUltralightPollerContextData* data) { return mf_ultralight_poller_read_page(poller, data->read_cmd.start_page, &data->read_cmd.data); } MfUltralightError mf_ultralight_poller_write_page_handler( MfUltralightPoller* poller, MfUltralightPollerContextData* data) { return mf_ultralight_poller_write_page( poller, data->write_cmd.page_to_write, &data->write_cmd.page); } MfUltralightError mf_ultralight_poller_read_version_handler( MfUltralightPoller* poller, MfUltralightPollerContextData* data) { return mf_ultralight_poller_read_version(poller, &data->version); } MfUltralightError mf_ultralight_poller_read_signature_handler( MfUltralightPoller* poller, MfUltralightPollerContextData* data) { return mf_ultralight_poller_read_signature(poller, &data->signature); } MfUltralightError mf_ultralight_poller_read_counter_handler( MfUltralightPoller* poller, MfUltralightPollerContextData* data) { return mf_ultralight_poller_read_counter( poller, data->counter_cmd.counter_num, &data->counter_cmd.data); } MfUltralightError mf_ultralight_poller_read_tearing_flag_handler( MfUltralightPoller* poller, MfUltralightPollerContextData* data) { return mf_ultralight_poller_read_tearing_flag( poller, data->tearing_flag_cmd.tearing_flag_num, &data->tearing_flag_cmd.data); } static const MfUltralightPollerCmdHandler mf_ultralight_poller_cmd_handlers[MfUltralightPollerCmdTypeNum] = { [MfUltralightPollerCmdTypeReadPage] = mf_ultralight_poller_read_page_handler, [MfUltralightPollerCmdTypeWritePage] = mf_ultralight_poller_write_page_handler, [MfUltralightPollerCmdTypeReadVersion] = mf_ultralight_poller_read_version_handler, [MfUltralightPollerCmdTypeReadSignature] = mf_ultralight_poller_read_signature_handler, [MfUltralightPollerCmdTypeReadCounter] = mf_ultralight_poller_read_counter_handler, [MfUltralightPollerCmdTypeReadTearingFlag] = mf_ultralight_poller_read_tearing_flag_handler, }; static NfcCommand mf_ultralight_poller_cmd_callback(NfcGenericEventEx event, void* context) { furi_assert(event.poller); furi_assert(event.parent_event_data); furi_assert(context); MfUltralightPollerContext* poller_context = context; Iso14443_3aPollerEvent* iso14443_3a_event = event.parent_event_data; MfUltralightPoller* mfu_poller = event.poller; if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeReady) { poller_context->error = mf_ultralight_poller_cmd_handlers[poller_context->cmd_type]( mfu_poller, &poller_context->data); } else if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeError) { poller_context->error = mf_ultralight_process_error(iso14443_3a_event->data->error); } furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); return NfcCommandStop; } static MfUltralightError mf_ultralight_poller_cmd_execute(Nfc* nfc, MfUltralightPollerContext* poller_ctx) { furi_assert(poller_ctx->cmd_type < MfUltralightPollerCmdTypeNum); poller_ctx->thread_id = furi_thread_get_current_id(); NfcPoller* poller = nfc_poller_alloc(nfc, NfcProtocolMfUltralight); nfc_poller_start_ex(poller, mf_ultralight_poller_cmd_callback, poller_ctx); furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); furi_thread_flags_clear(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); nfc_poller_stop(poller); nfc_poller_free(poller); return poller_ctx->error; } MfUltralightError mf_ultralight_poller_sync_read_page(Nfc* nfc, uint16_t page, MfUltralightPage* data) { furi_assert(nfc); furi_assert(data); MfUltralightPollerContext poller_context = { .cmd_type = MfUltralightPollerCmdTypeReadPage, .data.read_cmd.start_page = page, }; MfUltralightError error = mf_ultralight_poller_cmd_execute(nfc, &poller_context); if(error == MfUltralightErrorNone) { *data = poller_context.data.read_cmd.data.page[0]; } return error; } MfUltralightError mf_ultralight_poller_sync_write_page(Nfc* nfc, uint16_t page, MfUltralightPage* data) { furi_assert(nfc); furi_assert(data); MfUltralightPollerContext poller_context = { .cmd_type = MfUltralightPollerCmdTypeWritePage, .data.write_cmd = { .page_to_write = page, .page = *data, }, }; MfUltralightError error = mf_ultralight_poller_cmd_execute(nfc, &poller_context); return error; } MfUltralightError mf_ultralight_poller_sync_read_version(Nfc* nfc, MfUltralightVersion* data) { furi_assert(nfc); furi_assert(data); MfUltralightPollerContext poller_context = { .cmd_type = MfUltralightPollerCmdTypeReadVersion, }; MfUltralightError error = mf_ultralight_poller_cmd_execute(nfc, &poller_context); if(error == MfUltralightErrorNone) { *data = poller_context.data.version; } return error; } MfUltralightError mf_ultralight_poller_sync_read_signature(Nfc* nfc, MfUltralightSignature* data) { furi_assert(nfc); furi_assert(data); MfUltralightPollerContext poller_context = { .cmd_type = MfUltralightPollerCmdTypeReadSignature, }; MfUltralightError error = mf_ultralight_poller_cmd_execute(nfc, &poller_context); if(error == MfUltralightErrorNone) { *data = poller_context.data.signature; } return error; } MfUltralightError mf_ultralight_poller_sync_read_counter( Nfc* nfc, uint8_t counter_num, MfUltralightCounter* data) { furi_assert(nfc); furi_assert(data); MfUltralightPollerContext poller_context = { .cmd_type = MfUltralightPollerCmdTypeReadCounter, .data.counter_cmd.counter_num = counter_num, }; MfUltralightError error = mf_ultralight_poller_cmd_execute(nfc, &poller_context); if(error == MfUltralightErrorNone) { *data = poller_context.data.counter_cmd.data; } return error; } MfUltralightError mf_ultralight_poller_sync_read_tearing_flag( Nfc* nfc, uint8_t flag_num, MfUltralightTearingFlag* data) { furi_assert(nfc); furi_assert(data); MfUltralightPollerContext poller_context = { .cmd_type = MfUltralightPollerCmdTypeReadTearingFlag, .data.tearing_flag_cmd.tearing_flag_num = flag_num, }; MfUltralightError error = mf_ultralight_poller_cmd_execute(nfc, &poller_context); if(error == MfUltralightErrorNone) { *data = poller_context.data.tearing_flag_cmd.data; } return error; } static NfcCommand mf_ultralight_poller_read_callback(NfcGenericEvent event, void* context) { furi_assert(context); furi_assert(event.instance); furi_assert(event.event_data); furi_assert(event.protocol == NfcProtocolMfUltralight); NfcCommand command = NfcCommandContinue; MfUltralightPollerContext* poller_context = context; MfUltralightPoller* mfu_poller = event.instance; MfUltralightPollerEvent* mfu_event = event.event_data; if(mfu_event->type == MfUltralightPollerEventTypeReadSuccess) { mf_ultralight_copy(poller_context->data.data, mf_ultralight_poller_get_data(mfu_poller)); poller_context->error = MfUltralightErrorNone; command = NfcCommandStop; } else if(mfu_event->type == MfUltralightPollerEventTypeReadFailed) { poller_context->error = mfu_event->data->error; command = NfcCommandStop; } else if(mfu_event->type == MfUltralightPollerEventTypeAuthRequest) { mfu_event->data->auth_context.skip_auth = true; } if(command == NfcCommandStop) { furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); } return command; } MfUltralightError mf_ultralight_poller_sync_read_card(Nfc* nfc, MfUltralightData* data) { furi_assert(nfc); furi_assert(data); MfUltralightPollerContext poller_context = {}; poller_context.thread_id = furi_thread_get_current_id(); poller_context.data.data = mf_ultralight_alloc(); NfcPoller* poller = nfc_poller_alloc(nfc, NfcProtocolMfUltralight); nfc_poller_start(poller, mf_ultralight_poller_read_callback, &poller_context); furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); furi_thread_flags_clear(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); nfc_poller_stop(poller); nfc_poller_free(poller); if(poller_context.error == MfUltralightErrorNone) { mf_ultralight_copy(data, poller_context.data.data); } mf_ultralight_free(poller_context.data.data); return poller_context.error; }