mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-22 05:14:46 -07:00
NFC: Implement Type 4 Tag writing biolerplate and structure
This commit is contained in:
@@ -129,9 +129,10 @@ static void nfc_scene_read_on_enter_type_4_tag(NfcApp* instance) {
|
|||||||
static void nfc_scene_read_and_saved_menu_on_enter_type_4_tag(NfcApp* instance) {
|
static void nfc_scene_read_and_saved_menu_on_enter_type_4_tag(NfcApp* instance) {
|
||||||
Submenu* submenu = instance->submenu;
|
Submenu* submenu = instance->submenu;
|
||||||
|
|
||||||
|
// FIXME: standardize this and the write scenes into protocol support helper
|
||||||
submenu_add_item(
|
submenu_add_item(
|
||||||
submenu,
|
submenu,
|
||||||
"Write (Not Implemented)",
|
"Write",
|
||||||
SubmenuIndexWrite,
|
SubmenuIndexWrite,
|
||||||
nfc_protocol_support_common_submenu_callback,
|
nfc_protocol_support_common_submenu_callback,
|
||||||
instance);
|
instance);
|
||||||
@@ -144,8 +145,7 @@ static bool
|
|||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == SubmenuIndexWrite) {
|
if(event.event == SubmenuIndexWrite) {
|
||||||
// TODO: Implement write
|
scene_manager_next_scene(instance->scene_manager, NfcSceneType4TagWrite);
|
||||||
// scene_manager_next_scene(instance->scene_manager, NfcSceneType4TagWrite);
|
|
||||||
consumed = true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,4 +67,8 @@ ADD_SCENE(nfc, slix_key_input, SlixKeyInput)
|
|||||||
ADD_SCENE(nfc, slix_unlock, SlixUnlock)
|
ADD_SCENE(nfc, slix_unlock, SlixUnlock)
|
||||||
ADD_SCENE(nfc, slix_unlock_success, SlixUnlockSuccess)
|
ADD_SCENE(nfc, slix_unlock_success, SlixUnlockSuccess)
|
||||||
|
|
||||||
|
ADD_SCENE(nfc, type_4_tag_write, Type4TagWrite)
|
||||||
|
ADD_SCENE(nfc, type_4_tag_write_success, Type4TagWriteSuccess)
|
||||||
|
ADD_SCENE(nfc, type_4_tag_write_fail, Type4TagWriteFail)
|
||||||
|
|
||||||
ADD_SCENE(nfc, generate_info, GenerateInfo)
|
ADD_SCENE(nfc, generate_info, GenerateInfo)
|
||||||
|
|||||||
105
applications/main/nfc/scenes/nfc_scene_type_4_tag_write.c
Normal file
105
applications/main/nfc/scenes/nfc_scene_type_4_tag_write.c
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
#include "../nfc_app_i.h"
|
||||||
|
|
||||||
|
#include <nfc/protocols/type_4_tag/type_4_tag_poller.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
NfcSceneType4TagWriteStateCardSearch,
|
||||||
|
NfcSceneType4TagWriteStateCardFound,
|
||||||
|
};
|
||||||
|
|
||||||
|
NfcCommand nfc_scene_type_4_tag_write_worker_callback(NfcGenericEvent event, void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
furi_assert(event.event_data);
|
||||||
|
furi_assert(event.protocol == NfcProtocolType4Tag);
|
||||||
|
|
||||||
|
NfcCommand command = NfcCommandContinue;
|
||||||
|
NfcApp* instance = context;
|
||||||
|
Type4TagPollerEvent* t4t_event = event.event_data;
|
||||||
|
|
||||||
|
if(t4t_event->type == Type4TagPollerEventTypeRequestMode) {
|
||||||
|
t4t_event->data->poller_mode.mode = Type4TagPollerModeWrite;
|
||||||
|
t4t_event->data->poller_mode.data =
|
||||||
|
nfc_device_get_data(instance->nfc_device, NfcProtocolType4Tag);
|
||||||
|
view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventCardDetected);
|
||||||
|
} else if(t4t_event->type == Type4TagPollerEventTypeWriteFail) {
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
instance->scene_manager, NfcSceneType4TagWriteFail, t4t_event->data->error);
|
||||||
|
view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerFailure);
|
||||||
|
command = NfcCommandStop;
|
||||||
|
} else if(t4t_event->type == Type4TagPollerEventTypeWriteSuccess) {
|
||||||
|
view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerSuccess);
|
||||||
|
command = NfcCommandStop;
|
||||||
|
}
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nfc_scene_type_4_tag_write_setup_view(NfcApp* instance) {
|
||||||
|
Popup* popup = instance->popup;
|
||||||
|
popup_reset(popup);
|
||||||
|
uint32_t state = scene_manager_get_scene_state(instance->scene_manager, NfcSceneType4TagWrite);
|
||||||
|
|
||||||
|
if(state == NfcSceneType4TagWriteStateCardSearch) {
|
||||||
|
popup_set_header(instance->popup, "Writing", 95, 20, AlignCenter, AlignCenter);
|
||||||
|
popup_set_text(
|
||||||
|
instance->popup, "Apply card\nto the back", 95, 38, AlignCenter, AlignCenter);
|
||||||
|
popup_set_icon(instance->popup, 0, 8, &I_NFC_manual_60x50);
|
||||||
|
} else {
|
||||||
|
popup_set_header(popup, "Writing\nDon't move...", 52, 32, AlignLeft, AlignCenter);
|
||||||
|
popup_set_icon(popup, 12, 23, &A_Loading_24);
|
||||||
|
}
|
||||||
|
|
||||||
|
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_type_4_tag_write_on_enter(void* context) {
|
||||||
|
NfcApp* instance = context;
|
||||||
|
dolphin_deed(DolphinDeedNfcEmulate);
|
||||||
|
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
instance->scene_manager, NfcSceneType4TagWrite, NfcSceneType4TagWriteStateCardSearch);
|
||||||
|
nfc_scene_type_4_tag_write_setup_view(instance);
|
||||||
|
|
||||||
|
// Setup and start worker
|
||||||
|
instance->poller = nfc_poller_alloc(instance->nfc, NfcProtocolType4Tag);
|
||||||
|
nfc_poller_start(instance->poller, nfc_scene_type_4_tag_write_worker_callback, instance);
|
||||||
|
|
||||||
|
nfc_blink_emulate_start(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nfc_scene_type_4_tag_write_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
NfcApp* instance = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == NfcCustomEventCardDetected) {
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
instance->scene_manager,
|
||||||
|
NfcSceneType4TagWrite,
|
||||||
|
NfcSceneType4TagWriteStateCardFound);
|
||||||
|
nfc_scene_type_4_tag_write_setup_view(instance);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == NfcCustomEventPollerSuccess) {
|
||||||
|
scene_manager_next_scene(instance->scene_manager, NfcSceneType4TagWriteSuccess);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == NfcCustomEventPollerFailure) {
|
||||||
|
scene_manager_next_scene(instance->scene_manager, NfcSceneType4TagWriteFail);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_type_4_tag_write_on_exit(void* context) {
|
||||||
|
NfcApp* instance = context;
|
||||||
|
|
||||||
|
nfc_poller_stop(instance->poller);
|
||||||
|
nfc_poller_free(instance->poller);
|
||||||
|
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
instance->scene_manager, NfcSceneType4TagWrite, NfcSceneType4TagWriteStateCardSearch);
|
||||||
|
// Clear view
|
||||||
|
popup_reset(instance->popup);
|
||||||
|
|
||||||
|
nfc_blink_stop(instance);
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
#include "../nfc_app_i.h"
|
||||||
|
|
||||||
|
#include <nfc/protocols/type_4_tag/type_4_tag_poller.h>
|
||||||
|
|
||||||
|
void nfc_scene_type_4_tag_write_fail_widget_callback(
|
||||||
|
GuiButtonType result,
|
||||||
|
InputType type,
|
||||||
|
void* context) {
|
||||||
|
NfcApp* instance = context;
|
||||||
|
if(type == InputTypeShort) {
|
||||||
|
view_dispatcher_send_custom_event(instance->view_dispatcher, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_type_4_tag_write_fail_on_enter(void* context) {
|
||||||
|
NfcApp* instance = context;
|
||||||
|
Widget* widget = instance->widget;
|
||||||
|
|
||||||
|
notification_message(instance->notifications, &sequence_error);
|
||||||
|
|
||||||
|
widget_add_icon_element(widget, 83, 22, &I_WarningDolphinFlip_45x42);
|
||||||
|
widget_add_string_element(
|
||||||
|
widget, 7, 4, AlignLeft, AlignTop, FontPrimary, "Writing gone wrong!");
|
||||||
|
Type4TagError error =
|
||||||
|
scene_manager_get_scene_state(instance->scene_manager, NfcSceneType4TagWriteFail);
|
||||||
|
widget_add_string_multiline_element(
|
||||||
|
widget,
|
||||||
|
7,
|
||||||
|
17,
|
||||||
|
AlignLeft,
|
||||||
|
AlignTop,
|
||||||
|
FontSecondary,
|
||||||
|
error == Type4TagErrorCardLocked ? "Card does not\nallow writing\nnew data" :
|
||||||
|
"Failed to\nwrite new data");
|
||||||
|
|
||||||
|
widget_add_button_element(
|
||||||
|
widget,
|
||||||
|
GuiButtonTypeLeft,
|
||||||
|
"Finish",
|
||||||
|
nfc_scene_type_4_tag_write_fail_widget_callback,
|
||||||
|
instance);
|
||||||
|
|
||||||
|
// Setup and start worker
|
||||||
|
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool nfc_scene_type_4_tag_write_fail_move_to_back_scene(const NfcApp* const instance) {
|
||||||
|
bool was_saved = scene_manager_has_previous_scene(instance->scene_manager, NfcSceneSavedMenu);
|
||||||
|
uint32_t scene_id = was_saved ? NfcSceneSavedMenu : NfcSceneReadMenu;
|
||||||
|
|
||||||
|
return scene_manager_search_and_switch_to_previous_scene(instance->scene_manager, scene_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nfc_scene_type_4_tag_write_fail_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
NfcApp* instance = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == GuiButtonTypeLeft) {
|
||||||
|
consumed = nfc_scene_type_4_tag_write_fail_move_to_back_scene(instance);
|
||||||
|
}
|
||||||
|
} else if(event.type == SceneManagerEventTypeBack) {
|
||||||
|
consumed = nfc_scene_type_4_tag_write_fail_move_to_back_scene(instance);
|
||||||
|
}
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_type_4_tag_write_fail_on_exit(void* context) {
|
||||||
|
NfcApp* instance = context;
|
||||||
|
|
||||||
|
widget_reset(instance->widget);
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
#include "../nfc_app_i.h"
|
||||||
|
|
||||||
|
void nfc_scene_type_4_tag_write_success_popup_callback(void* context) {
|
||||||
|
NfcApp* instance = context;
|
||||||
|
view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventViewExit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_type_4_tag_write_success_on_enter(void* context) {
|
||||||
|
NfcApp* instance = context;
|
||||||
|
dolphin_deed(DolphinDeedNfcSave);
|
||||||
|
|
||||||
|
notification_message(instance->notifications, &sequence_success);
|
||||||
|
|
||||||
|
Popup* popup = instance->popup;
|
||||||
|
popup_set_icon(popup, 48, 6, &I_DolphinDone_80x58);
|
||||||
|
popup_set_header(popup, "Successfully\nwritten", 5, 22, AlignLeft, AlignBottom);
|
||||||
|
popup_set_timeout(popup, 1500);
|
||||||
|
popup_set_context(popup, instance);
|
||||||
|
popup_set_callback(popup, nfc_scene_type_4_tag_write_success_popup_callback);
|
||||||
|
popup_enable_timeout(popup);
|
||||||
|
|
||||||
|
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nfc_scene_type_4_tag_write_success_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
NfcApp* instance = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == NfcCustomEventViewExit) {
|
||||||
|
bool was_saved =
|
||||||
|
scene_manager_has_previous_scene(instance->scene_manager, NfcSceneSavedMenu);
|
||||||
|
|
||||||
|
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||||
|
instance->scene_manager, was_saved ? NfcSceneSavedMenu : NfcSceneReadSuccess);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_type_4_tag_write_success_on_exit(void* context) {
|
||||||
|
NfcApp* instance = context;
|
||||||
|
|
||||||
|
// Clear view
|
||||||
|
popup_reset(instance->popup);
|
||||||
|
}
|
||||||
@@ -14,6 +14,7 @@ typedef enum {
|
|||||||
Type4TagErrorWrongFormat,
|
Type4TagErrorWrongFormat,
|
||||||
Type4TagErrorNotSupported,
|
Type4TagErrorNotSupported,
|
||||||
Type4TagErrorApduFailed,
|
Type4TagErrorApduFailed,
|
||||||
|
Type4TagErrorCardLocked,
|
||||||
Type4TagErrorCustomCommand,
|
Type4TagErrorCustomCommand,
|
||||||
} Type4TagError;
|
} Type4TagError;
|
||||||
|
|
||||||
|
|||||||
@@ -45,10 +45,27 @@ static NfcCommand type_4_tag_poller_handler_idle(Type4TagPoller* instance) {
|
|||||||
instance->data->iso14443_4a_data,
|
instance->data->iso14443_4a_data,
|
||||||
iso14443_4a_poller_get_data(instance->iso14443_4a_poller));
|
iso14443_4a_poller_get_data(instance->iso14443_4a_poller));
|
||||||
|
|
||||||
instance->state = Type4TagPollerStateSelectApplication;
|
instance->state = Type4TagPollerStateRequestMode;
|
||||||
return NfcCommandContinue;
|
return NfcCommandContinue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NfcCommand type_4_tag_poller_handler_request_mode(Type4TagPoller* instance) {
|
||||||
|
NfcCommand command = NfcCommandContinue;
|
||||||
|
|
||||||
|
instance->type_4_tag_event.type = Type4TagPollerEventTypeRequestMode;
|
||||||
|
instance->type_4_tag_event.data->poller_mode.mode = Type4TagPollerModeRead;
|
||||||
|
instance->type_4_tag_event.data->poller_mode.data = NULL;
|
||||||
|
|
||||||
|
command = instance->callback(instance->general_event, instance->context);
|
||||||
|
instance->mode = instance->type_4_tag_event.data->poller_mode.mode;
|
||||||
|
if(instance->mode == Type4TagPollerModeWrite) {
|
||||||
|
type_4_tag_copy(instance->data, instance->type_4_tag_event.data->poller_mode.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
instance->state = Type4TagPollerStateSelectApplication;
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
static NfcCommand type_4_tag_poller_handler_select_app(Type4TagPoller* instance) {
|
static NfcCommand type_4_tag_poller_handler_select_app(Type4TagPoller* instance) {
|
||||||
instance->error = type_4_tag_poller_select_app(instance);
|
instance->error = type_4_tag_poller_select_app(instance);
|
||||||
if(instance->error == Type4TagErrorNone) {
|
if(instance->error == Type4TagErrorNone) {
|
||||||
@@ -56,8 +73,12 @@ static NfcCommand type_4_tag_poller_handler_select_app(Type4TagPoller* instance)
|
|||||||
instance->state = Type4TagPollerStateReadCapabilityContainer;
|
instance->state = Type4TagPollerStateReadCapabilityContainer;
|
||||||
} else {
|
} else {
|
||||||
FURI_LOG_E(TAG, "Failed to select application");
|
FURI_LOG_E(TAG, "Failed to select application");
|
||||||
iso14443_4a_poller_halt(instance->iso14443_4a_poller);
|
if(instance->mode == Type4TagPollerModeWrite &&
|
||||||
instance->state = Type4TagPollerStateReadFailed;
|
instance->error == Type4TagErrorApduFailed) {
|
||||||
|
instance->state = Type4TagPollerStateCreateApplication;
|
||||||
|
} else {
|
||||||
|
instance->state = Type4TagPollerStateFailed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NfcCommandContinue;
|
return NfcCommandContinue;
|
||||||
@@ -67,11 +88,17 @@ static NfcCommand type_4_tag_poller_handler_read_cc(Type4TagPoller* instance) {
|
|||||||
instance->error = type_4_tag_poller_read_cc(instance);
|
instance->error = type_4_tag_poller_read_cc(instance);
|
||||||
if(instance->error == Type4TagErrorNone) {
|
if(instance->error == Type4TagErrorNone) {
|
||||||
FURI_LOG_D(TAG, "Read CC success");
|
FURI_LOG_D(TAG, "Read CC success");
|
||||||
instance->state = Type4TagPollerStateReadNdefMessage;
|
instance->state = instance->mode == Type4TagPollerModeRead ?
|
||||||
|
Type4TagPollerStateReadNdefMessage :
|
||||||
|
Type4TagPollerStateWriteNdefMessage;
|
||||||
} else {
|
} else {
|
||||||
FURI_LOG_E(TAG, "Failed to read CC");
|
FURI_LOG_E(TAG, "Failed to read CC");
|
||||||
iso14443_4a_poller_halt(instance->iso14443_4a_poller);
|
if(instance->mode == Type4TagPollerModeWrite &&
|
||||||
instance->state = Type4TagPollerStateReadFailed;
|
instance->error == Type4TagErrorApduFailed) {
|
||||||
|
instance->state = Type4TagPollerStateCreateCapabilityContainer;
|
||||||
|
} else {
|
||||||
|
instance->state = Type4TagPollerStateFailed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NfcCommandContinue;
|
return NfcCommandContinue;
|
||||||
@@ -81,41 +108,115 @@ static NfcCommand type_4_tag_poller_handler_read_ndef(Type4TagPoller* instance)
|
|||||||
instance->error = type_4_tag_poller_read_ndef(instance);
|
instance->error = type_4_tag_poller_read_ndef(instance);
|
||||||
if(instance->error == Type4TagErrorNone) {
|
if(instance->error == Type4TagErrorNone) {
|
||||||
FURI_LOG_D(TAG, "Read NDEF success");
|
FURI_LOG_D(TAG, "Read NDEF success");
|
||||||
instance->state = Type4TagPollerStateReadSuccess;
|
instance->state = Type4TagPollerStateSuccess;
|
||||||
} else {
|
} else {
|
||||||
FURI_LOG_E(TAG, "Failed to read NDEF");
|
FURI_LOG_E(TAG, "Failed to read NDEF");
|
||||||
iso14443_4a_poller_halt(instance->iso14443_4a_poller);
|
instance->state = Type4TagPollerStateFailed;
|
||||||
instance->state = Type4TagPollerStateReadFailed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NfcCommandContinue;
|
return NfcCommandContinue;
|
||||||
}
|
}
|
||||||
|
|
||||||
static NfcCommand type_4_tag_poller_handler_read_fail(Type4TagPoller* instance) {
|
static NfcCommand type_4_tag_poller_handler_create_app(Type4TagPoller* instance) {
|
||||||
FURI_LOG_D(TAG, "Read Failed");
|
instance->error = type_4_tag_poller_create_app(instance);
|
||||||
|
if(instance->error == Type4TagErrorNone) {
|
||||||
|
FURI_LOG_D(TAG, "Create application success");
|
||||||
|
instance->state = Type4TagPollerStateSelectApplication;
|
||||||
|
} else {
|
||||||
|
FURI_LOG_E(TAG, "Failed to create application");
|
||||||
|
if(instance->error == Type4TagErrorApduFailed) {
|
||||||
|
instance->error = Type4TagErrorCardLocked;
|
||||||
|
}
|
||||||
|
instance->state = Type4TagPollerStateFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NfcCommandContinue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NfcCommand type_4_tag_poller_handler_create_cc(Type4TagPoller* instance) {
|
||||||
|
instance->error = type_4_tag_poller_create_cc(instance);
|
||||||
|
if(instance->error == Type4TagErrorNone) {
|
||||||
|
FURI_LOG_D(TAG, "Create CC success");
|
||||||
|
instance->state = Type4TagPollerStateReadCapabilityContainer;
|
||||||
|
} else {
|
||||||
|
FURI_LOG_E(TAG, "Failed to create CC");
|
||||||
|
if(instance->error == Type4TagErrorApduFailed) {
|
||||||
|
instance->error = Type4TagErrorCardLocked;
|
||||||
|
}
|
||||||
|
instance->state = Type4TagPollerStateFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NfcCommandContinue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NfcCommand type_4_tag_poller_handler_create_ndef(Type4TagPoller* instance) {
|
||||||
|
instance->error = type_4_tag_poller_create_ndef(instance);
|
||||||
|
if(instance->error == Type4TagErrorNone) {
|
||||||
|
FURI_LOG_D(TAG, "Create NDEF success");
|
||||||
|
instance->state = Type4TagPollerStateWriteNdefMessage;
|
||||||
|
} else {
|
||||||
|
FURI_LOG_E(TAG, "Failed to create NDEF");
|
||||||
|
if(instance->error == Type4TagErrorApduFailed) {
|
||||||
|
instance->error = Type4TagErrorCardLocked;
|
||||||
|
}
|
||||||
|
instance->state = Type4TagPollerStateFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NfcCommandContinue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NfcCommand type_4_tag_poller_handler_write_ndef(Type4TagPoller* instance) {
|
||||||
|
instance->error = type_4_tag_poller_write_ndef(instance);
|
||||||
|
if(instance->error == Type4TagErrorNone) {
|
||||||
|
FURI_LOG_D(TAG, "Write NDEF success");
|
||||||
|
instance->state = Type4TagPollerStateSuccess;
|
||||||
|
} else {
|
||||||
|
FURI_LOG_E(TAG, "Failed to write NDEF");
|
||||||
|
if(instance->mode == Type4TagPollerModeWrite &&
|
||||||
|
instance->error == Type4TagErrorApduFailed) {
|
||||||
|
instance->state = Type4TagPollerStateCreateNdefMessage;
|
||||||
|
} else {
|
||||||
|
instance->state = Type4TagPollerStateFailed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NfcCommandContinue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NfcCommand type_4_tag_poller_handler_fail(Type4TagPoller* instance) {
|
||||||
|
FURI_LOG_D(TAG, "Operation Failed");
|
||||||
iso14443_4a_poller_halt(instance->iso14443_4a_poller);
|
iso14443_4a_poller_halt(instance->iso14443_4a_poller);
|
||||||
instance->type_4_tag_event.type = Type4TagPollerEventTypeReadFailed;
|
instance->type_4_tag_event.type = instance->mode == Type4TagPollerModeRead ?
|
||||||
|
Type4TagPollerEventTypeReadFailed :
|
||||||
|
Type4TagPollerEventTypeWriteFail;
|
||||||
instance->type_4_tag_event.data->error = instance->error;
|
instance->type_4_tag_event.data->error = instance->error;
|
||||||
NfcCommand command = instance->callback(instance->general_event, instance->context);
|
NfcCommand command = instance->callback(instance->general_event, instance->context);
|
||||||
instance->state = Type4TagPollerStateIdle;
|
instance->state = Type4TagPollerStateIdle;
|
||||||
return command;
|
return command;
|
||||||
}
|
}
|
||||||
|
|
||||||
static NfcCommand type_4_tag_poller_handler_read_success(Type4TagPoller* instance) {
|
static NfcCommand type_4_tag_poller_handler_success(Type4TagPoller* instance) {
|
||||||
FURI_LOG_D(TAG, "Read success.");
|
FURI_LOG_D(TAG, "Operation succeeded");
|
||||||
iso14443_4a_poller_halt(instance->iso14443_4a_poller);
|
iso14443_4a_poller_halt(instance->iso14443_4a_poller);
|
||||||
instance->type_4_tag_event.type = Type4TagPollerEventTypeReadSuccess;
|
instance->type_4_tag_event.type = instance->mode == Type4TagPollerModeRead ?
|
||||||
|
Type4TagPollerEventTypeReadSuccess :
|
||||||
|
Type4TagPollerEventTypeWriteSuccess;
|
||||||
NfcCommand command = instance->callback(instance->general_event, instance->context);
|
NfcCommand command = instance->callback(instance->general_event, instance->context);
|
||||||
return command;
|
return command;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const Type4TagPollerReadHandler type_4_tag_poller_read_handler[Type4TagPollerStateNum] = {
|
static const Type4TagPollerReadHandler type_4_tag_poller_read_handler[Type4TagPollerStateNum] = {
|
||||||
[Type4TagPollerStateIdle] = type_4_tag_poller_handler_idle,
|
[Type4TagPollerStateIdle] = type_4_tag_poller_handler_idle,
|
||||||
|
[Type4TagPollerStateRequestMode] = type_4_tag_poller_handler_request_mode,
|
||||||
[Type4TagPollerStateSelectApplication] = type_4_tag_poller_handler_select_app,
|
[Type4TagPollerStateSelectApplication] = type_4_tag_poller_handler_select_app,
|
||||||
[Type4TagPollerStateReadCapabilityContainer] = type_4_tag_poller_handler_read_cc,
|
[Type4TagPollerStateReadCapabilityContainer] = type_4_tag_poller_handler_read_cc,
|
||||||
[Type4TagPollerStateReadNdefMessage] = type_4_tag_poller_handler_read_ndef,
|
[Type4TagPollerStateReadNdefMessage] = type_4_tag_poller_handler_read_ndef,
|
||||||
[Type4TagPollerStateReadFailed] = type_4_tag_poller_handler_read_fail,
|
[Type4TagPollerStateCreateApplication] = type_4_tag_poller_handler_create_app,
|
||||||
[Type4TagPollerStateReadSuccess] = type_4_tag_poller_handler_read_success,
|
[Type4TagPollerStateCreateCapabilityContainer] = type_4_tag_poller_handler_create_cc,
|
||||||
|
[Type4TagPollerStateCreateNdefMessage] = type_4_tag_poller_handler_create_ndef,
|
||||||
|
[Type4TagPollerStateWriteNdefMessage] = type_4_tag_poller_handler_write_ndef,
|
||||||
|
[Type4TagPollerStateFailed] = type_4_tag_poller_handler_fail,
|
||||||
|
[Type4TagPollerStateSuccess] = type_4_tag_poller_handler_success,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void type_4_tag_poller_set_callback(
|
static void type_4_tag_poller_set_callback(
|
||||||
|
|||||||
@@ -15,15 +15,37 @@ typedef struct Type4TagPoller Type4TagPoller;
|
|||||||
* @brief Enumeration of possible Type4Tag poller event types.
|
* @brief Enumeration of possible Type4Tag poller event types.
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
Type4TagPollerEventTypeRequestMode, /**< Poller requests for operating mode. */
|
||||||
Type4TagPollerEventTypeReadSuccess, /**< Card was read successfully. */
|
Type4TagPollerEventTypeReadSuccess, /**< Card was read successfully. */
|
||||||
Type4TagPollerEventTypeReadFailed, /**< Poller failed to read card. */
|
Type4TagPollerEventTypeReadFailed, /**< Poller failed to read card. */
|
||||||
|
Type4TagPollerEventTypeWriteSuccess, /**< Poller wrote card successfully. */
|
||||||
|
Type4TagPollerEventTypeWriteFail, /**< Poller failed to write card. */
|
||||||
} Type4TagPollerEventType;
|
} Type4TagPollerEventType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enumeration of possible Type4Tag poller operating modes.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
Type4TagPollerModeRead, /**< Poller will only read card. It's a default mode. */
|
||||||
|
Type4TagPollerModeWrite, /**< Poller will write already saved card to another presented card. */
|
||||||
|
} Type4TagPollerMode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Type4Tag poller request mode event data.
|
||||||
|
*
|
||||||
|
* This instance of this structure must be filled on Type4TagPollerEventTypeRequestMode event.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
Type4TagPollerMode mode; /**< Mode to be used by poller. */
|
||||||
|
const Type4TagData* data; /**< Data to be used by poller. */
|
||||||
|
} Type4TagPollerEventDataRequestMode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Type4Tag poller event data.
|
* @brief Type4Tag poller event data.
|
||||||
*/
|
*/
|
||||||
typedef union {
|
typedef union {
|
||||||
Type4TagError error; /**< Error code indicating card reading fail reason. */
|
Type4TagError error; /**< Error code indicating card reading fail reason. */
|
||||||
|
Type4TagPollerEventDataRequestMode poller_mode; /**< Poller mode context. */
|
||||||
} Type4TagPollerEventData;
|
} Type4TagPollerEventData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -198,11 +198,28 @@ Type4TagError type_4_tag_poller_read_ndef(Type4TagPoller* instance) {
|
|||||||
if(error != Type4TagErrorNone) break;
|
if(error != Type4TagErrorNone) break;
|
||||||
|
|
||||||
FURI_LOG_D(
|
FURI_LOG_D(
|
||||||
TAG,
|
TAG, "Read %hu bytes from NDEF file 0x%04X", ndef_len, instance->data->ndef_file_id);
|
||||||
"Read NDEF file 0x%04X of %lu bytes",
|
|
||||||
instance->data->ndef_file_id,
|
|
||||||
simple_array_get_count(instance->data->ndef_data));
|
|
||||||
} while(false);
|
} while(false);
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Type4TagError type_4_tag_poller_create_app(Type4TagPoller* instance) {
|
||||||
|
UNUSED(instance);
|
||||||
|
return Type4TagErrorNotSupported;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type4TagError type_4_tag_poller_create_cc(Type4TagPoller* instance) {
|
||||||
|
UNUSED(instance);
|
||||||
|
return Type4TagErrorNotSupported;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type4TagError type_4_tag_poller_create_ndef(Type4TagPoller* instance) {
|
||||||
|
UNUSED(instance);
|
||||||
|
return Type4TagErrorNotSupported;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type4TagError type_4_tag_poller_write_ndef(Type4TagPoller* instance) {
|
||||||
|
UNUSED(instance);
|
||||||
|
return Type4TagErrorNotSupported;
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,11 +10,16 @@ extern "C" {
|
|||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
Type4TagPollerStateIdle,
|
Type4TagPollerStateIdle,
|
||||||
|
Type4TagPollerStateRequestMode,
|
||||||
Type4TagPollerStateSelectApplication,
|
Type4TagPollerStateSelectApplication,
|
||||||
Type4TagPollerStateReadCapabilityContainer,
|
Type4TagPollerStateReadCapabilityContainer,
|
||||||
Type4TagPollerStateReadNdefMessage,
|
Type4TagPollerStateReadNdefMessage,
|
||||||
Type4TagPollerStateReadFailed,
|
Type4TagPollerStateCreateApplication,
|
||||||
Type4TagPollerStateReadSuccess,
|
Type4TagPollerStateCreateCapabilityContainer,
|
||||||
|
Type4TagPollerStateCreateNdefMessage,
|
||||||
|
Type4TagPollerStateWriteNdefMessage,
|
||||||
|
Type4TagPollerStateFailed,
|
||||||
|
Type4TagPollerStateSuccess,
|
||||||
|
|
||||||
Type4TagPollerStateNum,
|
Type4TagPollerStateNum,
|
||||||
} Type4TagPollerState;
|
} Type4TagPollerState;
|
||||||
@@ -22,6 +27,7 @@ typedef enum {
|
|||||||
struct Type4TagPoller {
|
struct Type4TagPoller {
|
||||||
Iso14443_4aPoller* iso14443_4a_poller;
|
Iso14443_4aPoller* iso14443_4a_poller;
|
||||||
Type4TagPollerState state;
|
Type4TagPollerState state;
|
||||||
|
Type4TagPollerMode mode;
|
||||||
Type4TagError error;
|
Type4TagError error;
|
||||||
Type4TagData* data;
|
Type4TagData* data;
|
||||||
BitBuffer* tx_buffer;
|
BitBuffer* tx_buffer;
|
||||||
@@ -41,6 +47,14 @@ Type4TagError type_4_tag_poller_read_cc(Type4TagPoller* instance);
|
|||||||
|
|
||||||
Type4TagError type_4_tag_poller_read_ndef(Type4TagPoller* instance);
|
Type4TagError type_4_tag_poller_read_ndef(Type4TagPoller* instance);
|
||||||
|
|
||||||
|
Type4TagError type_4_tag_poller_create_app(Type4TagPoller* instance);
|
||||||
|
|
||||||
|
Type4TagError type_4_tag_poller_create_cc(Type4TagPoller* instance);
|
||||||
|
|
||||||
|
Type4TagError type_4_tag_poller_create_ndef(Type4TagPoller* instance);
|
||||||
|
|
||||||
|
Type4TagError type_4_tag_poller_write_ndef(Type4TagPoller* instance);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user