[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
@ -12,6 +12,7 @@ enum {
|
|||||||
SubmenuIndexUnlock = SubmenuIndexCommonMax,
|
SubmenuIndexUnlock = SubmenuIndexCommonMax,
|
||||||
SubmenuIndexUnlockByReader,
|
SubmenuIndexUnlockByReader,
|
||||||
SubmenuIndexUnlockByPassword,
|
SubmenuIndexUnlockByPassword,
|
||||||
|
SubmenuIndexWrite,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void nfc_scene_info_on_enter_mf_ultralight(NfcApp* instance) {
|
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,
|
SubmenuIndexUnlock,
|
||||||
nfc_protocol_support_common_submenu_callback,
|
nfc_protocol_support_common_submenu_callback,
|
||||||
instance);
|
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) {
|
if(event == SubmenuIndexUnlock) {
|
||||||
scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightUnlockMenu);
|
scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightUnlockMenu);
|
||||||
return true;
|
return true;
|
||||||
|
} else if(event == SubmenuIndexWrite) {
|
||||||
|
scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightWrite);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,6 +24,10 @@ ADD_SCENE(nfc, field, Field)
|
|||||||
ADD_SCENE(nfc, retry_confirm, RetryConfirm)
|
ADD_SCENE(nfc, retry_confirm, RetryConfirm)
|
||||||
ADD_SCENE(nfc, exit_confirm, ExitConfirm)
|
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_menu, MfUltralightUnlockMenu)
|
||||||
ADD_SCENE(nfc, mf_ultralight_unlock_warn, MfUltralightUnlockWarn)
|
ADD_SCENE(nfc, mf_ultralight_unlock_warn, MfUltralightUnlockWarn)
|
||||||
ADD_SCENE(nfc, mf_ultralight_key_input, MfUltralightKeyInput)
|
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_read = 0;
|
||||||
instance->tearing_flag_total = 3;
|
instance->tearing_flag_total = 3;
|
||||||
instance->pages_read = 0;
|
instance->pages_read = 0;
|
||||||
instance->state = MfUltralightPollerStateReadVersion;
|
instance->state = MfUltralightPollerStateRequestMode;
|
||||||
|
instance->current_page = 0;
|
||||||
return NfcCommandContinue;
|
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) {
|
static NfcCommand mf_ultralight_poller_handler_read_version(MfUltralightPoller* instance) {
|
||||||
instance->error = mf_ultralight_poller_read_version(instance, &instance->data->version);
|
instance->error = mf_ultralight_poller_read_version(instance, &instance->data->version);
|
||||||
if(instance->error == MfUltralightErrorNone) {
|
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) {
|
static NfcCommand mf_ultralight_poller_handler_check_ntag_203(MfUltralightPoller* instance) {
|
||||||
|
MfUltralightPollerState next_state = MfUltralightPollerStateGetFeatureSet;
|
||||||
MfUltralightPageReadCommandData data = {};
|
MfUltralightPageReadCommandData data = {};
|
||||||
instance->error = mf_ultralight_poller_read_page(instance, 41, &data);
|
instance->error = mf_ultralight_poller_read_page(instance, 41, &data);
|
||||||
if(instance->error == MfUltralightErrorNone) {
|
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");
|
FURI_LOG_D(TAG, "Original Ultralight detected");
|
||||||
iso14443_3a_poller_halt(instance->iso14443_3a_poller);
|
iso14443_3a_poller_halt(instance->iso14443_3a_poller);
|
||||||
instance->data->type = MfUltralightTypeUnknown;
|
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;
|
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) {
|
static NfcCommand mf_ultralight_poller_handler_read_fail(MfUltralightPoller* instance) {
|
||||||
FURI_LOG_D(TAG, "Read Failed");
|
FURI_LOG_D(TAG, "Read Failed");
|
||||||
iso14443_3a_poller_halt(instance->iso14443_3a_poller);
|
iso14443_3a_poller_halt(instance->iso14443_3a_poller);
|
||||||
|
instance->mfu_event.type = MfUltralightPollerEventTypeReadFailed;
|
||||||
instance->mfu_event.data->error = instance->error;
|
instance->mfu_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 = MfUltralightPollerStateIdle;
|
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) {
|
static NfcCommand mf_ultralight_poller_handler_read_success(MfUltralightPoller* instance) {
|
||||||
FURI_LOG_D(TAG, "Read success");
|
FURI_LOG_D(TAG, "Read success");
|
||||||
iso14443_3a_poller_halt(instance->iso14443_3a_poller);
|
|
||||||
instance->mfu_event.type = MfUltralightPollerEventTypeReadSuccess;
|
instance->mfu_event.type = MfUltralightPollerEventTypeReadSuccess;
|
||||||
NfcCommand command = instance->callback(instance->general_event, instance->context);
|
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;
|
return command;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const MfUltralightPollerReadHandler
|
static const MfUltralightPollerReadHandler
|
||||||
mf_ultralight_poller_read_handler[MfUltralightPollerStateNum] = {
|
mf_ultralight_poller_read_handler[MfUltralightPollerStateNum] = {
|
||||||
[MfUltralightPollerStateIdle] = mf_ultralight_poller_handler_idle,
|
[MfUltralightPollerStateIdle] = mf_ultralight_poller_handler_idle,
|
||||||
|
[MfUltralightPollerStateRequestMode] = mf_ultralight_poller_handler_request_mode,
|
||||||
[MfUltralightPollerStateReadVersion] = mf_ultralight_poller_handler_read_version,
|
[MfUltralightPollerStateReadVersion] = mf_ultralight_poller_handler_read_version,
|
||||||
[MfUltralightPollerStateDetectMfulC] = mf_ultralight_poller_handler_check_ultralight_c,
|
[MfUltralightPollerStateDetectMfulC] = mf_ultralight_poller_handler_check_ultralight_c,
|
||||||
[MfUltralightPollerStateDetectNtag203] = mf_ultralight_poller_handler_check_ntag_203,
|
[MfUltralightPollerStateDetectNtag203] = mf_ultralight_poller_handler_check_ntag_203,
|
||||||
@ -538,6 +664,11 @@ static const MfUltralightPollerReadHandler
|
|||||||
[MfUltralightPollerStateReadPages] = mf_ultralight_poller_handler_read_pages,
|
[MfUltralightPollerStateReadPages] = mf_ultralight_poller_handler_read_pages,
|
||||||
[MfUltralightPollerStateReadFailed] = mf_ultralight_poller_handler_read_fail,
|
[MfUltralightPollerStateReadFailed] = mf_ultralight_poller_handler_read_fail,
|
||||||
[MfUltralightPollerStateReadSuccess] = mf_ultralight_poller_handler_read_success,
|
[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.
|
* @brief Enumeration of possible MfUltralight poller event types.
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
MfUltralightPollerEventTypeRequestMode, /**< Poller requests for operating mode. */
|
||||||
MfUltralightPollerEventTypeAuthRequest, /**< Poller requests to fill authentication context. */
|
MfUltralightPollerEventTypeAuthRequest, /**< Poller requests to fill authentication context. */
|
||||||
MfUltralightPollerEventTypeAuthSuccess, /**< Authentication succeeded. */
|
MfUltralightPollerEventTypeAuthSuccess, /**< Authentication succeeded. */
|
||||||
MfUltralightPollerEventTypeAuthFailed, /**< Authentication failed. */
|
MfUltralightPollerEventTypeAuthFailed, /**< Authentication failed. */
|
||||||
MfUltralightPollerEventTypeReadSuccess, /**< Poller read card successfully. */
|
MfUltralightPollerEventTypeReadSuccess, /**< Poller read card successfully. */
|
||||||
MfUltralightPollerEventTypeReadFailed, /**< Poller failed to read card. */
|
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;
|
} 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.
|
* @brief MfUltralight poller authentication context.
|
||||||
*/
|
*/
|
||||||
@ -39,6 +53,8 @@ typedef struct {
|
|||||||
typedef union {
|
typedef union {
|
||||||
MfUltralightPollerAuthContext auth_context; /**< Authentication context. */
|
MfUltralightPollerAuthContext auth_context; /**< Authentication context. */
|
||||||
MfUltralightError error; /**< Error code indicating reading fail reason. */
|
MfUltralightError error; /**< Error code indicating reading fail reason. */
|
||||||
|
const MfUltralightData* write_data;
|
||||||
|
MfUltralightPollerMode poller_mode;
|
||||||
} MfUltralightPollerEventData;
|
} MfUltralightPollerEventData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -49,6 +49,7 @@ typedef union {
|
|||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
MfUltralightPollerStateIdle,
|
MfUltralightPollerStateIdle,
|
||||||
|
MfUltralightPollerStateRequestMode,
|
||||||
MfUltralightPollerStateReadVersion,
|
MfUltralightPollerStateReadVersion,
|
||||||
MfUltralightPollerStateDetectMfulC,
|
MfUltralightPollerStateDetectMfulC,
|
||||||
MfUltralightPollerStateDetectNtag203,
|
MfUltralightPollerStateDetectNtag203,
|
||||||
@ -61,6 +62,10 @@ typedef enum {
|
|||||||
MfUltralightPollerStateTryDefaultPass,
|
MfUltralightPollerStateTryDefaultPass,
|
||||||
MfUltralightPollerStateReadFailed,
|
MfUltralightPollerStateReadFailed,
|
||||||
MfUltralightPollerStateReadSuccess,
|
MfUltralightPollerStateReadSuccess,
|
||||||
|
MfUltralightPollerStateRequestWriteData,
|
||||||
|
MfUltralightPollerStateWritePages,
|
||||||
|
MfUltralightPollerStateWriteFail,
|
||||||
|
MfUltralightPollerStateWriteSuccess,
|
||||||
|
|
||||||
MfUltralightPollerStateNum,
|
MfUltralightPollerStateNum,
|
||||||
} MfUltralightPollerState;
|
} MfUltralightPollerState;
|
||||||
@ -68,6 +73,7 @@ typedef enum {
|
|||||||
struct MfUltralightPoller {
|
struct MfUltralightPoller {
|
||||||
Iso14443_3aPoller* iso14443_3a_poller;
|
Iso14443_3aPoller* iso14443_3a_poller;
|
||||||
MfUltralightPollerState state;
|
MfUltralightPollerState state;
|
||||||
|
MfUltralightPollerMode mode;
|
||||||
BitBuffer* tx_buffer;
|
BitBuffer* tx_buffer;
|
||||||
BitBuffer* rx_buffer;
|
BitBuffer* rx_buffer;
|
||||||
MfUltralightData* data;
|
MfUltralightData* data;
|
||||||
@ -79,6 +85,7 @@ struct MfUltralightPoller {
|
|||||||
uint8_t counters_total;
|
uint8_t counters_total;
|
||||||
uint8_t tearing_flag_read;
|
uint8_t tearing_flag_read;
|
||||||
uint8_t tearing_flag_total;
|
uint8_t tearing_flag_total;
|
||||||
|
uint16_t current_page;
|
||||||
MfUltralightError error;
|
MfUltralightError error;
|
||||||
|
|
||||||
NfcGenericEvent general_event;
|
NfcGenericEvent general_event;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user