mirror of
https://github.com/DarkFlippers/unleashed-firmware
synced 2025-02-16 21:38:39 +00:00
[FL-3675] Ntag21x write (#3246)
* New scenes for ultralight poller write mode * Added new button and transition logic for write operation For now write is only possible for NTAG21x cards with default password and no AUTHLIM set * Poller states extended * Enums and datatypes extended for new poller mode * Added mode field to poller instance datatype * New states for poller added in order to implement write mode * Added new event type for locked cards in order to simplify state flow * New logic for poller write commands * Scenes adjustments * Scenes renamed * New field added to poller instance * Now we write in 'page per call' mode * Now function takes callback return value into account * Callback will be called only in write mode * Event type added * Log adjusted and start page to write set * Logs added and check in now false at start, then it moves to true * Now mf_ultralight_poller_handler_request_write_data halts card in case of check failure and stops poller * All fail events now returns NfcCommandStop callback * In case of fail we move back properly * Remove garbage Co-authored-by: gornekich <n.gorbadey@gmail.com> Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
parent
b51a754fd9
commit
6a5d63803a
9 changed files with 462 additions and 4 deletions
|
@ -12,6 +12,7 @@ enum {
|
|||
SubmenuIndexUnlock = SubmenuIndexCommonMax,
|
||||
SubmenuIndexUnlockByReader,
|
||||
SubmenuIndexUnlockByPassword,
|
||||
SubmenuIndexWrite,
|
||||
};
|
||||
|
||||
static void nfc_scene_info_on_enter_mf_ultralight(NfcApp* instance) {
|
||||
|
@ -106,6 +107,15 @@ static void nfc_scene_read_and_saved_menu_on_enter_mf_ultralight(NfcApp* instanc
|
|||
SubmenuIndexUnlock,
|
||||
nfc_protocol_support_common_submenu_callback,
|
||||
instance);
|
||||
} else if(
|
||||
data->type == MfUltralightTypeNTAG213 || data->type == MfUltralightTypeNTAG215 ||
|
||||
data->type == MfUltralightTypeNTAG216) {
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Write",
|
||||
SubmenuIndexWrite,
|
||||
nfc_protocol_support_common_submenu_callback,
|
||||
instance);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,6 +156,9 @@ static bool
|
|||
if(event == SubmenuIndexUnlock) {
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightUnlockMenu);
|
||||
return true;
|
||||
} else if(event == SubmenuIndexWrite) {
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightWrite);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,10 @@ ADD_SCENE(nfc, field, Field)
|
|||
ADD_SCENE(nfc, retry_confirm, RetryConfirm)
|
||||
ADD_SCENE(nfc, exit_confirm, ExitConfirm)
|
||||
|
||||
ADD_SCENE(nfc, mf_ultralight_write, MfUltralightWrite)
|
||||
ADD_SCENE(nfc, mf_ultralight_write_success, MfUltralightWriteSuccess)
|
||||
ADD_SCENE(nfc, mf_ultralight_write_fail, MfUltralightWriteFail)
|
||||
ADD_SCENE(nfc, mf_ultralight_wrong_card, MfUltralightWrongCard)
|
||||
ADD_SCENE(nfc, mf_ultralight_unlock_menu, MfUltralightUnlockMenu)
|
||||
ADD_SCENE(nfc, mf_ultralight_unlock_warn, MfUltralightUnlockWarn)
|
||||
ADD_SCENE(nfc, mf_ultralight_key_input, MfUltralightKeyInput)
|
||||
|
|
119
applications/main/nfc/scenes/nfc_scene_mf_ultralight_write.c
Normal file
119
applications/main/nfc/scenes/nfc_scene_mf_ultralight_write.c
Normal file
|
@ -0,0 +1,119 @@
|
|||
#include "../nfc_app_i.h"
|
||||
|
||||
#include <nfc/protocols/mf_ultralight/mf_ultralight_poller.h>
|
||||
|
||||
enum {
|
||||
NfcSceneMfUltralightWriteStateCardSearch,
|
||||
NfcSceneMfUltralightWriteStateCardFound,
|
||||
};
|
||||
|
||||
NfcCommand nfc_scene_mf_ultralight_write_worker_callback(NfcGenericEvent event, void* context) {
|
||||
furi_assert(context);
|
||||
furi_assert(event.event_data);
|
||||
furi_assert(event.protocol == NfcProtocolMfUltralight);
|
||||
|
||||
NfcCommand command = NfcCommandContinue;
|
||||
NfcApp* instance = context;
|
||||
MfUltralightPollerEvent* mfu_event = event.event_data;
|
||||
|
||||
if(mfu_event->type == MfUltralightPollerEventTypeRequestMode) {
|
||||
mfu_event->data->poller_mode = MfUltralightPollerModeWrite;
|
||||
view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventCardDetected);
|
||||
} else if(mfu_event->type == MfUltralightPollerEventTypeAuthRequest) {
|
||||
mfu_event->data->auth_context.skip_auth = true;
|
||||
} else if(mfu_event->type == MfUltralightPollerEventTypeRequestWriteData) {
|
||||
mfu_event->data->write_data =
|
||||
nfc_device_get_data(instance->nfc_device, NfcProtocolMfUltralight);
|
||||
} else if(mfu_event->type == MfUltralightPollerEventTypeCardMismatch) {
|
||||
view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventWrongCard);
|
||||
command = NfcCommandStop;
|
||||
} else if(mfu_event->type == MfUltralightPollerEventTypeCardLocked) {
|
||||
view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerFailure);
|
||||
command = NfcCommandStop;
|
||||
} else if(mfu_event->type == MfUltralightPollerEventTypeWriteFail) {
|
||||
command = NfcCommandStop;
|
||||
} else if(mfu_event->type == MfUltralightPollerEventTypeWriteSuccess) {
|
||||
view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerSuccess);
|
||||
command = NfcCommandStop;
|
||||
}
|
||||
return command;
|
||||
}
|
||||
|
||||
static void nfc_scene_mf_ultralight_write_setup_view(NfcApp* instance) {
|
||||
Popup* popup = instance->popup;
|
||||
popup_reset(popup);
|
||||
uint32_t state =
|
||||
scene_manager_get_scene_state(instance->scene_manager, NfcSceneMfUltralightWrite);
|
||||
|
||||
if(state == NfcSceneMfUltralightWriteStateCardSearch) {
|
||||
popup_set_text(
|
||||
instance->popup, "Apply the initial\ncard only", 128, 32, AlignRight, 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_mf_ultralight_write_on_enter(void* context) {
|
||||
NfcApp* instance = context;
|
||||
dolphin_deed(DolphinDeedNfcEmulate);
|
||||
|
||||
scene_manager_set_scene_state(
|
||||
instance->scene_manager,
|
||||
NfcSceneMfUltralightWrite,
|
||||
NfcSceneMfUltralightWriteStateCardSearch);
|
||||
nfc_scene_mf_ultralight_write_setup_view(instance);
|
||||
|
||||
// Setup and start worker
|
||||
FURI_LOG_D("WMFU", "Card searching...");
|
||||
instance->poller = nfc_poller_alloc(instance->nfc, NfcProtocolMfUltralight);
|
||||
nfc_poller_start(instance->poller, nfc_scene_mf_ultralight_write_worker_callback, instance);
|
||||
|
||||
nfc_blink_emulate_start(instance);
|
||||
}
|
||||
|
||||
bool nfc_scene_mf_ultralight_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,
|
||||
NfcSceneMfUltralightWrite,
|
||||
NfcSceneMfUltralightWriteStateCardFound);
|
||||
nfc_scene_mf_ultralight_write_setup_view(instance);
|
||||
consumed = true;
|
||||
} else if(event.event == NfcCustomEventWrongCard) {
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightWrongCard);
|
||||
consumed = true;
|
||||
} else if(event.event == NfcCustomEventPollerSuccess) {
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightWriteSuccess);
|
||||
consumed = true;
|
||||
} else if(event.event == NfcCustomEventPollerFailure) {
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightWriteFail);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_mf_ultralight_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,
|
||||
NfcSceneMfUltralightWrite,
|
||||
NfcSceneMfUltralightWriteStateCardSearch);
|
||||
// Clear view
|
||||
popup_reset(instance->popup);
|
||||
|
||||
nfc_blink_stop(instance);
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
#include "../nfc_app_i.h"
|
||||
|
||||
void nfc_scene_mf_ultralight_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_mf_ultralight_write_fail_on_enter(void* context) {
|
||||
NfcApp* instance = context;
|
||||
Widget* widget = instance->widget;
|
||||
|
||||
notification_message(instance->notifications, &sequence_error);
|
||||
|
||||
widget_add_icon_element(widget, 72, 17, &I_DolphinCommon_56x48);
|
||||
widget_add_string_element(
|
||||
widget, 7, 4, AlignLeft, AlignTop, FontPrimary, "Writing gone wrong!");
|
||||
widget_add_string_multiline_element(
|
||||
widget,
|
||||
7,
|
||||
17,
|
||||
AlignLeft,
|
||||
AlignTop,
|
||||
FontSecondary,
|
||||
"Card protected by\npassword, AUTH0\nor lock bits");
|
||||
|
||||
widget_add_button_element(
|
||||
widget,
|
||||
GuiButtonTypeLeft,
|
||||
"Finish",
|
||||
nfc_scene_mf_ultralight_write_fail_widget_callback,
|
||||
instance);
|
||||
|
||||
// Setup and start worker
|
||||
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewWidget);
|
||||
}
|
||||
|
||||
static bool nfc_scene_mf_ultralight_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_mf_ultralight_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_mf_ultralight_write_fail_move_to_back_scene(instance);
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
consumed = nfc_scene_mf_ultralight_write_fail_move_to_back_scene(instance);
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_mf_ultralight_write_fail_on_exit(void* context) {
|
||||
NfcApp* instance = context;
|
||||
|
||||
widget_reset(instance->widget);
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
#include "../nfc_app_i.h"
|
||||
|
||||
void nfc_scene_mf_ultralight_write_success_popup_callback(void* context) {
|
||||
NfcApp* instance = context;
|
||||
view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventViewExit);
|
||||
}
|
||||
|
||||
void nfc_scene_mf_ultralight_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, 32, 5, &I_DolphinNice_96x59);
|
||||
popup_set_header(popup, "Successfully\nwritten", 13, 22, AlignLeft, AlignBottom);
|
||||
popup_set_timeout(popup, 1500);
|
||||
popup_set_context(popup, instance);
|
||||
popup_set_callback(popup, nfc_scene_mf_ultralight_write_success_popup_callback);
|
||||
popup_enable_timeout(popup);
|
||||
|
||||
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup);
|
||||
}
|
||||
|
||||
bool nfc_scene_mf_ultralight_write_success_on_event(void* context, SceneManagerEvent event) {
|
||||
NfcApp* instance = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == NfcCustomEventViewExit) {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
instance->scene_manager, NfcSceneSavedMenu);
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_mf_ultralight_write_success_on_exit(void* context) {
|
||||
NfcApp* instance = context;
|
||||
|
||||
// Clear view
|
||||
popup_reset(instance->popup);
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
#include "../nfc_app_i.h"
|
||||
|
||||
void nfc_scene_mf_ultralight_wrong_card_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_mf_ultralight_wrong_card_on_enter(void* context) {
|
||||
NfcApp* instance = context;
|
||||
Widget* widget = instance->widget;
|
||||
|
||||
notification_message(instance->notifications, &sequence_error);
|
||||
|
||||
widget_add_icon_element(widget, 73, 17, &I_DolphinCommon_56x48);
|
||||
widget_add_string_element(
|
||||
widget, 3, 4, AlignLeft, AlignTop, FontPrimary, "This is wrong card");
|
||||
widget_add_string_multiline_element(
|
||||
widget,
|
||||
4,
|
||||
17,
|
||||
AlignLeft,
|
||||
AlignTop,
|
||||
FontSecondary,
|
||||
"Card of the same\ntype should be\n presented");
|
||||
//"Data management\nis only possible\nwith card of same type");
|
||||
widget_add_button_element(
|
||||
widget,
|
||||
GuiButtonTypeLeft,
|
||||
"Retry",
|
||||
nfc_scene_mf_ultralight_wrong_card_widget_callback,
|
||||
instance);
|
||||
|
||||
// Setup and start worker
|
||||
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewWidget);
|
||||
}
|
||||
|
||||
bool nfc_scene_mf_ultralight_wrong_card_on_event(void* context, SceneManagerEvent event) {
|
||||
NfcApp* instance = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == GuiButtonTypeLeft) {
|
||||
consumed = scene_manager_previous_scene(instance->scene_manager);
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_mf_ultralight_wrong_card_on_exit(void* context) {
|
||||
NfcApp* instance = context;
|
||||
|
||||
widget_reset(instance->widget);
|
||||
}
|
|
@ -224,11 +224,24 @@ static NfcCommand mf_ultralight_poller_handler_idle(MfUltralightPoller* instance
|
|||
instance->tearing_flag_read = 0;
|
||||
instance->tearing_flag_total = 3;
|
||||
instance->pages_read = 0;
|
||||
instance->state = MfUltralightPollerStateReadVersion;
|
||||
|
||||
instance->state = MfUltralightPollerStateRequestMode;
|
||||
instance->current_page = 0;
|
||||
return NfcCommandContinue;
|
||||
}
|
||||
|
||||
static NfcCommand mf_ultralight_poller_handler_request_mode(MfUltralightPoller* instance) {
|
||||
NfcCommand command = NfcCommandContinue;
|
||||
|
||||
instance->mfu_event.type = MfUltralightPollerEventTypeRequestMode;
|
||||
instance->mfu_event.data->poller_mode = MfUltralightPollerModeRead;
|
||||
|
||||
command = instance->callback(instance->general_event, instance->context);
|
||||
instance->mode = instance->mfu_event.data->poller_mode;
|
||||
|
||||
instance->state = MfUltralightPollerStateReadVersion;
|
||||
return command;
|
||||
}
|
||||
|
||||
static NfcCommand mf_ultralight_poller_handler_read_version(MfUltralightPoller* instance) {
|
||||
instance->error = mf_ultralight_poller_read_version(instance, &instance->data->version);
|
||||
if(instance->error == MfUltralightErrorNone) {
|
||||
|
@ -259,6 +272,7 @@ static NfcCommand mf_ultralight_poller_handler_check_ultralight_c(MfUltralightPo
|
|||
}
|
||||
|
||||
static NfcCommand mf_ultralight_poller_handler_check_ntag_203(MfUltralightPoller* instance) {
|
||||
MfUltralightPollerState next_state = MfUltralightPollerStateGetFeatureSet;
|
||||
MfUltralightPageReadCommandData data = {};
|
||||
instance->error = mf_ultralight_poller_read_page(instance, 41, &data);
|
||||
if(instance->error == MfUltralightErrorNone) {
|
||||
|
@ -268,8 +282,13 @@ static NfcCommand mf_ultralight_poller_handler_check_ntag_203(MfUltralightPoller
|
|||
FURI_LOG_D(TAG, "Original Ultralight detected");
|
||||
iso14443_3a_poller_halt(instance->iso14443_3a_poller);
|
||||
instance->data->type = MfUltralightTypeUnknown;
|
||||
if(instance->mode == MfUltralightPollerModeWrite) {
|
||||
instance->mfu_event.type = MfUltralightPollerEventTypeCardMismatch;
|
||||
instance->callback(instance->general_event, instance->context);
|
||||
next_state = MfUltralightPollerStateWriteFail;
|
||||
}
|
||||
}
|
||||
instance->state = MfUltralightPollerStateGetFeatureSet;
|
||||
instance->state = next_state;
|
||||
|
||||
return NfcCommandContinue;
|
||||
}
|
||||
|
@ -508,6 +527,7 @@ static NfcCommand mf_ultralight_poller_handler_try_default_pass(MfUltralightPoll
|
|||
static NfcCommand mf_ultralight_poller_handler_read_fail(MfUltralightPoller* instance) {
|
||||
FURI_LOG_D(TAG, "Read Failed");
|
||||
iso14443_3a_poller_halt(instance->iso14443_3a_poller);
|
||||
instance->mfu_event.type = MfUltralightPollerEventTypeReadFailed;
|
||||
instance->mfu_event.data->error = instance->error;
|
||||
NfcCommand command = instance->callback(instance->general_event, instance->context);
|
||||
instance->state = MfUltralightPollerStateIdle;
|
||||
|
@ -516,15 +536,121 @@ static NfcCommand mf_ultralight_poller_handler_read_fail(MfUltralightPoller* ins
|
|||
|
||||
static NfcCommand mf_ultralight_poller_handler_read_success(MfUltralightPoller* instance) {
|
||||
FURI_LOG_D(TAG, "Read success");
|
||||
iso14443_3a_poller_halt(instance->iso14443_3a_poller);
|
||||
instance->mfu_event.type = MfUltralightPollerEventTypeReadSuccess;
|
||||
NfcCommand command = instance->callback(instance->general_event, instance->context);
|
||||
|
||||
if(instance->mode == MfUltralightPollerModeRead) {
|
||||
iso14443_3a_poller_halt(instance->iso14443_3a_poller);
|
||||
instance->state = MfUltralightPollerStateIdle;
|
||||
} else {
|
||||
instance->state = MfUltralightPollerStateRequestWriteData;
|
||||
}
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
static NfcCommand mf_ultralight_poller_handler_request_write_data(MfUltralightPoller* instance) {
|
||||
FURI_LOG_D(TAG, "Check writing capability");
|
||||
NfcCommand command = NfcCommandContinue;
|
||||
MfUltralightPollerState next_state = MfUltralightPollerStateWritePages;
|
||||
instance->current_page = 4;
|
||||
|
||||
instance->mfu_event.type = MfUltralightPollerEventTypeRequestWriteData;
|
||||
instance->callback(instance->general_event, instance->context);
|
||||
|
||||
const MfUltralightData* write_data = instance->mfu_event.data->write_data;
|
||||
const MfUltralightData* tag_data = instance->data;
|
||||
uint32_t features = mf_ultralight_get_feature_support_set(tag_data->type);
|
||||
|
||||
bool check_passed = false;
|
||||
do {
|
||||
if(write_data->type != tag_data->type) {
|
||||
FURI_LOG_D(TAG, "Incorrect tag type");
|
||||
instance->mfu_event.type = MfUltralightPollerEventTypeCardMismatch;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!instance->auth_context.auth_success) {
|
||||
FURI_LOG_D(TAG, "Unknown password");
|
||||
instance->mfu_event.type = MfUltralightPollerEventTypeCardLocked;
|
||||
break;
|
||||
}
|
||||
|
||||
const MfUltralightPage staticlock_page = tag_data->page[2];
|
||||
if(staticlock_page.data[2] != 0 || staticlock_page.data[3] != 0) {
|
||||
FURI_LOG_D(TAG, "Static lock bits are set");
|
||||
instance->mfu_event.type = MfUltralightPollerEventTypeCardLocked;
|
||||
break;
|
||||
}
|
||||
|
||||
if(mf_ultralight_support_feature(features, MfUltralightFeatureSupportDynamicLock)) {
|
||||
uint8_t dynlock_num = mf_ultralight_get_config_page_num(tag_data->type) - 1;
|
||||
const MfUltralightPage dynlock_page = tag_data->page[dynlock_num];
|
||||
if(dynlock_page.data[0] != 0 || dynlock_page.data[1] != 0) {
|
||||
FURI_LOG_D(TAG, "Dynamic lock bits are set");
|
||||
instance->mfu_event.type = MfUltralightPollerEventTypeCardLocked;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
check_passed = true;
|
||||
} while(false);
|
||||
|
||||
if(!check_passed) {
|
||||
iso14443_3a_poller_halt(instance->iso14443_3a_poller);
|
||||
command = instance->callback(instance->general_event, instance->context);
|
||||
next_state = MfUltralightPollerStateWriteFail;
|
||||
}
|
||||
|
||||
instance->state = next_state;
|
||||
return command;
|
||||
}
|
||||
|
||||
static NfcCommand mf_ultralight_poller_handler_write_pages(MfUltralightPoller* instance) {
|
||||
NfcCommand command = NfcCommandContinue;
|
||||
|
||||
do {
|
||||
const MfUltralightData* write_data = instance->mfu_event.data->write_data;
|
||||
uint8_t end_page = mf_ultralight_get_config_page_num(write_data->type) - 1;
|
||||
if(instance->current_page == end_page) {
|
||||
instance->state = MfUltralightPollerStateWriteSuccess;
|
||||
break;
|
||||
}
|
||||
FURI_LOG_D(TAG, "Writing page %d", instance->current_page);
|
||||
MfUltralightError error = mf_ultralight_poller_write_page(
|
||||
instance, instance->current_page, &write_data->page[instance->current_page]);
|
||||
if(error != MfUltralightErrorNone) {
|
||||
instance->state = MfUltralightPollerStateWriteFail;
|
||||
instance->error = error;
|
||||
break;
|
||||
}
|
||||
instance->current_page++;
|
||||
} while(false);
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
static NfcCommand mf_ultralight_poller_handler_write_fail(MfUltralightPoller* instance) {
|
||||
FURI_LOG_D(TAG, "Write failed");
|
||||
iso14443_3a_poller_halt(instance->iso14443_3a_poller);
|
||||
instance->mfu_event.data->error = instance->error;
|
||||
instance->mfu_event.type = MfUltralightPollerEventTypeWriteFail;
|
||||
NfcCommand command = instance->callback(instance->general_event, instance->context);
|
||||
return command;
|
||||
}
|
||||
|
||||
static NfcCommand mf_ultralight_poller_handler_write_success(MfUltralightPoller* instance) {
|
||||
FURI_LOG_D(TAG, "Write success");
|
||||
iso14443_3a_poller_halt(instance->iso14443_3a_poller);
|
||||
instance->mfu_event.type = MfUltralightPollerEventTypeWriteSuccess;
|
||||
NfcCommand command = instance->callback(instance->general_event, instance->context);
|
||||
return command;
|
||||
}
|
||||
|
||||
static const MfUltralightPollerReadHandler
|
||||
mf_ultralight_poller_read_handler[MfUltralightPollerStateNum] = {
|
||||
[MfUltralightPollerStateIdle] = mf_ultralight_poller_handler_idle,
|
||||
[MfUltralightPollerStateRequestMode] = mf_ultralight_poller_handler_request_mode,
|
||||
[MfUltralightPollerStateReadVersion] = mf_ultralight_poller_handler_read_version,
|
||||
[MfUltralightPollerStateDetectMfulC] = mf_ultralight_poller_handler_check_ultralight_c,
|
||||
[MfUltralightPollerStateDetectNtag203] = mf_ultralight_poller_handler_check_ntag_203,
|
||||
|
@ -538,6 +664,11 @@ static const MfUltralightPollerReadHandler
|
|||
[MfUltralightPollerStateReadPages] = mf_ultralight_poller_handler_read_pages,
|
||||
[MfUltralightPollerStateReadFailed] = mf_ultralight_poller_handler_read_fail,
|
||||
[MfUltralightPollerStateReadSuccess] = mf_ultralight_poller_handler_read_success,
|
||||
[MfUltralightPollerStateRequestWriteData] =
|
||||
mf_ultralight_poller_handler_request_write_data,
|
||||
[MfUltralightPollerStateWritePages] = mf_ultralight_poller_handler_write_pages,
|
||||
[MfUltralightPollerStateWriteFail] = mf_ultralight_poller_handler_write_fail,
|
||||
[MfUltralightPollerStateWriteSuccess] = mf_ultralight_poller_handler_write_success,
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -16,13 +16,27 @@ typedef struct MfUltralightPoller MfUltralightPoller;
|
|||
* @brief Enumeration of possible MfUltralight poller event types.
|
||||
*/
|
||||
typedef enum {
|
||||
MfUltralightPollerEventTypeRequestMode, /**< Poller requests for operating mode. */
|
||||
MfUltralightPollerEventTypeAuthRequest, /**< Poller requests to fill authentication context. */
|
||||
MfUltralightPollerEventTypeAuthSuccess, /**< Authentication succeeded. */
|
||||
MfUltralightPollerEventTypeAuthFailed, /**< Authentication failed. */
|
||||
MfUltralightPollerEventTypeReadSuccess, /**< Poller read card successfully. */
|
||||
MfUltralightPollerEventTypeReadFailed, /**< Poller failed to read card. */
|
||||
MfUltralightPollerEventTypeRequestWriteData, /**< Poller request card data for write operation. */
|
||||
MfUltralightPollerEventTypeCardMismatch, /**< Type of card for writing differs from presented one. */
|
||||
MfUltralightPollerEventTypeCardLocked, /**< Presented card is locked by password, AUTH0 or lock bytes. */
|
||||
MfUltralightPollerEventTypeWriteSuccess, /**< Poller wrote card successfully. */
|
||||
MfUltralightPollerEventTypeWriteFail, /**< Poller failed to write card. */
|
||||
} MfUltralightPollerEventType;
|
||||
|
||||
/**
|
||||
* @brief Enumeration of possible MfUltralight poller operating modes.
|
||||
*/
|
||||
typedef enum {
|
||||
MfUltralightPollerModeRead, /**< Poller will only read card. It's a default mode. */
|
||||
MfUltralightPollerModeWrite, /**< Poller will write already saved card to another presented card. */
|
||||
} MfUltralightPollerMode;
|
||||
|
||||
/**
|
||||
* @brief MfUltralight poller authentication context.
|
||||
*/
|
||||
|
@ -39,6 +53,8 @@ typedef struct {
|
|||
typedef union {
|
||||
MfUltralightPollerAuthContext auth_context; /**< Authentication context. */
|
||||
MfUltralightError error; /**< Error code indicating reading fail reason. */
|
||||
const MfUltralightData* write_data;
|
||||
MfUltralightPollerMode poller_mode;
|
||||
} MfUltralightPollerEventData;
|
||||
|
||||
/**
|
||||
|
|
|
@ -49,6 +49,7 @@ typedef union {
|
|||
|
||||
typedef enum {
|
||||
MfUltralightPollerStateIdle,
|
||||
MfUltralightPollerStateRequestMode,
|
||||
MfUltralightPollerStateReadVersion,
|
||||
MfUltralightPollerStateDetectMfulC,
|
||||
MfUltralightPollerStateDetectNtag203,
|
||||
|
@ -61,6 +62,10 @@ typedef enum {
|
|||
MfUltralightPollerStateTryDefaultPass,
|
||||
MfUltralightPollerStateReadFailed,
|
||||
MfUltralightPollerStateReadSuccess,
|
||||
MfUltralightPollerStateRequestWriteData,
|
||||
MfUltralightPollerStateWritePages,
|
||||
MfUltralightPollerStateWriteFail,
|
||||
MfUltralightPollerStateWriteSuccess,
|
||||
|
||||
MfUltralightPollerStateNum,
|
||||
} MfUltralightPollerState;
|
||||
|
@ -68,6 +73,7 @@ typedef enum {
|
|||
struct MfUltralightPoller {
|
||||
Iso14443_3aPoller* iso14443_3a_poller;
|
||||
MfUltralightPollerState state;
|
||||
MfUltralightPollerMode mode;
|
||||
BitBuffer* tx_buffer;
|
||||
BitBuffer* rx_buffer;
|
||||
MfUltralightData* data;
|
||||
|
@ -79,6 +85,7 @@ struct MfUltralightPoller {
|
|||
uint8_t counters_total;
|
||||
uint8_t tearing_flag_read;
|
||||
uint8_t tearing_flag_total;
|
||||
uint16_t current_page;
|
||||
MfUltralightError error;
|
||||
|
||||
NfcGenericEvent general_event;
|
||||
|
|
Loading…
Add table
Reference in a new issue