mirror of
https://github.com/bettse/seader.git
synced 2026-08-28 10:34:05 +00:00
Stabilize HF plugin lifecycle and SAM cleanup
This commit is contained in:
@@ -1717,8 +1717,6 @@ NfcCommand seader_worker_card_detect(
|
||||
FURI_LOG_E(TAG, "Failed to encode CSN");
|
||||
return NfcCommandStop;
|
||||
}
|
||||
OCTET_STRING_t sak_string = {.buf = &sak, .size = 1};
|
||||
OCTET_STRING_t ats_string = {.buf = ats, .size = ats_len};
|
||||
uint8_t protocol_bytes[] = {0x00, 0x00};
|
||||
|
||||
// this won't hold true for Seos cards, but then we won't see the SIO from Seos cards anyway
|
||||
@@ -1742,9 +1740,16 @@ NfcCommand seader_worker_card_detect(
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_CardDetails, &cardDetails);
|
||||
return NfcCommandStop;
|
||||
}
|
||||
cardDetails.sak = &sak_string;
|
||||
cardDetails.sak = calloc(1, sizeof(*cardDetails.sak));
|
||||
cardDetails.atsOrAtqbOrAtr = calloc(1, sizeof(*cardDetails.atsOrAtqbOrAtr));
|
||||
if(!cardDetails.sak || !cardDetails.atsOrAtqbOrAtr ||
|
||||
OCTET_STRING_fromBuf(cardDetails.sak, (const char*)&sak, 1) != 0 ||
|
||||
OCTET_STRING_fromBuf(cardDetails.atsOrAtqbOrAtr, (const char*)ats, ats_len) != 0) {
|
||||
FURI_LOG_E(TAG, "Failed to encode 14A optional card details");
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_CardDetails, &cardDetails);
|
||||
return NfcCommandStop;
|
||||
}
|
||||
// TODO: Update asn1 to change atqa to ats
|
||||
cardDetails.atsOrAtqbOrAtr = &ats_string;
|
||||
} else if(uid_len == 8) { // picopass
|
||||
protocol_bytes[1] = FrameProtocol_iclass;
|
||||
if(OCTET_STRING_fromBuf(&cardDetails.protocol, (const char*)protocol_bytes, sizeof(protocol_bytes)) != 0) {
|
||||
@@ -1759,7 +1764,12 @@ NfcCommand seader_worker_card_detect(
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_CardDetails, &cardDetails);
|
||||
return NfcCommandStop;
|
||||
}
|
||||
cardDetails.sak = &sak_string;
|
||||
cardDetails.sak = calloc(1, sizeof(*cardDetails.sak));
|
||||
if(!cardDetails.sak || OCTET_STRING_fromBuf(cardDetails.sak, (const char*)&sak, 1) != 0) {
|
||||
FURI_LOG_E(TAG, "Failed to encode MFC SAK");
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_CardDetails, &cardDetails);
|
||||
return NfcCommandStop;
|
||||
}
|
||||
}
|
||||
|
||||
seader_sam_set_state(
|
||||
|
||||
@@ -88,8 +88,7 @@ bool seader_scene_card_menu_on_event(void* context, SceneManagerEvent event) {
|
||||
consumed = true;
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
seader->scene_manager, SeaderSceneSamPresent);
|
||||
consumed = scene_manager_previous_scene(seader->scene_manager);
|
||||
}
|
||||
|
||||
return consumed;
|
||||
|
||||
@@ -39,6 +39,11 @@ bool seader_scene_read_on_event(void* context, SceneManagerEvent event) {
|
||||
if(event.event == SeaderCustomEventWorkerExit) {
|
||||
scene_manager_next_scene(seader->scene_manager, SeaderSceneReadCardSuccess);
|
||||
consumed = true;
|
||||
} else if(event.event == SeaderWorkerEventFail) {
|
||||
scene_manager_next_scene(seader->scene_manager, SeaderSceneReadCardSuccess);
|
||||
consumed = true;
|
||||
} else if(event.event == SeaderWorkerEventHfTeardownComplete) {
|
||||
consumed = seader_hf_finish_teardown_action(seader);
|
||||
} else if(event.event == SeaderCustomEventPollerDetect) {
|
||||
Popup* popup = seader->popup;
|
||||
popup_set_header(popup, "DON'T\nMOVE", 68, 30, AlignLeft, AlignTop);
|
||||
@@ -51,13 +56,9 @@ bool seader_scene_read_on_event(void* context, SceneManagerEvent event) {
|
||||
consumed = true;
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
seader_hf_mode_set_selected_read_type(seader, SeaderCredentialTypeNone);
|
||||
seader_hf_mode_clear_detected_types(seader);
|
||||
seader_hf_mode_deactivate(seader);
|
||||
seader_hf_plugin_release(seader);
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
seader->scene_manager, SeaderSceneSamPresent);
|
||||
consumed = true;
|
||||
seader_scene_read_cleanup(seader);
|
||||
seader->hf_teardown_skip_read_cleanup = true;
|
||||
consumed = seader_hf_request_teardown(seader, SeaderHfTeardownActionSamPresent);
|
||||
}
|
||||
|
||||
return consumed;
|
||||
@@ -65,8 +66,9 @@ bool seader_scene_read_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
void seader_scene_read_on_exit(void* context) {
|
||||
Seader* seader = context;
|
||||
if(seader->worker) {
|
||||
seader_worker_stop(seader->worker);
|
||||
if(seader->hf_teardown_skip_read_cleanup) {
|
||||
seader->hf_teardown_skip_read_cleanup = false;
|
||||
return;
|
||||
}
|
||||
seader_scene_read_cleanup(seader);
|
||||
seader_worker_release(seader);
|
||||
|
||||
@@ -20,7 +20,6 @@ void seader_scene_read_card_success_on_enter(void* context) {
|
||||
SeaderCredential* credential = seader->credential;
|
||||
PluginWiegand* plugin = seader_wiegand_plugin_acquire(seader) ? seader->plugin_wiegand : NULL;
|
||||
Widget* widget = seader->widget;
|
||||
seader_hf_mode_deactivate(seader);
|
||||
|
||||
// Use reusable strings instead of allocating new ones
|
||||
FuriString* type_str = seader->temp_string1;
|
||||
@@ -134,23 +133,25 @@ bool seader_scene_read_card_success_on_event(void* context, SceneManagerEvent ev
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == GuiButtonTypeLeft) {
|
||||
consumed = scene_manager_previous_scene(seader->scene_manager);
|
||||
consumed = seader_hf_request_teardown(seader, SeaderHfTeardownActionRestartRead);
|
||||
} else if(event.event == GuiButtonTypeRight) {
|
||||
if(seader->credential->bit_length > 0) {
|
||||
scene_manager_next_scene(seader->scene_manager, SeaderSceneCardMenu);
|
||||
} else {
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
seader->scene_manager, SeaderSceneSamPresent);
|
||||
consumed =
|
||||
seader_hf_request_teardown(seader, SeaderHfTeardownActionSamPresent);
|
||||
}
|
||||
if(seader->credential->bit_length > 0) {
|
||||
consumed = true;
|
||||
}
|
||||
consumed = true;
|
||||
} else if(event.event == GuiButtonTypeCenter) {
|
||||
scene_manager_next_scene(seader->scene_manager, SeaderSceneFormats);
|
||||
consumed = true;
|
||||
} else if(event.event == SeaderWorkerEventHfTeardownComplete) {
|
||||
consumed = seader_hf_finish_teardown_action(seader);
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
seader->scene_manager, SeaderSceneSamPresent);
|
||||
consumed = true;
|
||||
consumed = seader_hf_request_teardown(seader, SeaderHfTeardownActionSamPresent);
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
@@ -44,7 +44,9 @@ bool seader_scene_read_card_type_on_event(void* context, SceneManagerEvent event
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
const SeaderCredentialType type = event.event;
|
||||
if(type == SeaderCredentialType14A || type == SeaderCredentialTypeMifareClassic ||
|
||||
if(event.event == SeaderWorkerEventHfTeardownComplete) {
|
||||
consumed = seader_hf_finish_teardown_action(seader);
|
||||
} else if(type == SeaderCredentialType14A || type == SeaderCredentialTypeMifareClassic ||
|
||||
type == SeaderCredentialTypePicopass) {
|
||||
seader_hf_mode_set_selected_read_type(seader, type);
|
||||
seader_hf_mode_clear_detected_types(seader);
|
||||
@@ -52,13 +54,7 @@ bool seader_scene_read_card_type_on_event(void* context, SceneManagerEvent event
|
||||
consumed = true;
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
seader_hf_mode_set_selected_read_type(seader, SeaderCredentialTypeNone);
|
||||
seader_hf_mode_clear_detected_types(seader);
|
||||
seader_hf_mode_deactivate(seader);
|
||||
seader_hf_plugin_release(seader);
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
seader->scene_manager, SeaderSceneSamPresent);
|
||||
consumed = true;
|
||||
consumed = seader_hf_request_teardown(seader, SeaderHfTeardownActionSamPresent);
|
||||
}
|
||||
|
||||
return consumed;
|
||||
|
||||
@@ -42,6 +42,10 @@ bool seader_scene_read_config_card_on_event(void* context, SceneManagerEvent eve
|
||||
if(event.event == SeaderCustomEventWorkerExit || event.event == SeaderWorkerEventSuccess) {
|
||||
scene_manager_next_scene(seader->scene_manager, SeaderSceneReadConfigCardSuccess);
|
||||
consumed = true;
|
||||
} else if(event.event == SeaderWorkerEventFail) {
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
seader->scene_manager, SeaderSceneSamPresent);
|
||||
consumed = true;
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
|
||||
@@ -9,14 +9,9 @@ enum SubmenuIndex {
|
||||
|
||||
static uint8_t fwChecks = 3;
|
||||
|
||||
void seader_scene_sam_present_submenu_callback(void* context, uint32_t index) {
|
||||
Seader* seader = context;
|
||||
view_dispatcher_send_custom_event(seader->view_dispatcher, index);
|
||||
}
|
||||
|
||||
void seader_scene_sam_present_on_update(void* context) {
|
||||
Seader* seader = context;
|
||||
void seader_scene_sam_present_submenu_callback(void* context, uint32_t index);
|
||||
|
||||
static void seader_scene_sam_present_rebuild_menu(Seader* seader, uint32_t selected_item) {
|
||||
Submenu* submenu = seader->submenu;
|
||||
submenu_reset(submenu);
|
||||
|
||||
@@ -42,29 +37,32 @@ void seader_scene_sam_present_on_update(void* context) {
|
||||
seader_scene_sam_present_submenu_callback,
|
||||
seader);
|
||||
}
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
seader->sam_key_label,
|
||||
SubmenuIndexSamInfo,
|
||||
seader_scene_sam_present_submenu_callback,
|
||||
seader);
|
||||
|
||||
if(seader->sam_version[0] != 0 && seader->sam_version[1] != 0) {
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
seader->sam_key_label,
|
||||
SubmenuIndexSamInfo,
|
||||
seader_scene_sam_present_submenu_callback,
|
||||
seader);
|
||||
fwChecks = 0;
|
||||
} else {
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
seader->sam_key_label,
|
||||
SubmenuIndexSamInfo,
|
||||
seader_scene_sam_present_submenu_callback,
|
||||
seader);
|
||||
}
|
||||
|
||||
submenu_set_selected_item(
|
||||
submenu, scene_manager_get_scene_state(seader->scene_manager, SeaderSceneSamPresent));
|
||||
|
||||
submenu_set_selected_item(submenu, selected_item);
|
||||
view_dispatcher_switch_to_view(seader->view_dispatcher, SeaderViewMenu);
|
||||
}
|
||||
|
||||
void seader_scene_sam_present_submenu_callback(void* context, uint32_t index) {
|
||||
Seader* seader = context;
|
||||
view_dispatcher_send_custom_event(seader->view_dispatcher, index);
|
||||
}
|
||||
|
||||
void seader_scene_sam_present_on_update(void* context) {
|
||||
Seader* seader = context;
|
||||
seader_scene_sam_present_rebuild_menu(
|
||||
seader, scene_manager_get_scene_state(seader->scene_manager, SeaderSceneSamPresent));
|
||||
}
|
||||
|
||||
void seader_scene_sam_present_on_enter(void* context) {
|
||||
seader_scene_sam_present_on_update(context);
|
||||
}
|
||||
@@ -102,18 +100,19 @@ bool seader_scene_sam_present_on_event(void* context, SceneManagerEvent event) {
|
||||
seader->scene_manager, SeaderSceneSamPresent, event.event);
|
||||
scene_manager_next_scene(seader->scene_manager, SeaderSceneAPDURunner);
|
||||
consumed = true;
|
||||
} else if(event.event == SeaderWorkerEventHfTeardownComplete) {
|
||||
consumed = seader_hf_finish_teardown_action(seader);
|
||||
} else if(event.event == SeaderCustomEventSamStatusUpdated) {
|
||||
seader_scene_sam_present_on_update(context);
|
||||
seader_scene_sam_present_rebuild_menu(
|
||||
seader, submenu_get_selected_item(seader->submenu));
|
||||
consumed = true;
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
scene_manager_stop(seader->scene_manager);
|
||||
view_dispatcher_stop(seader->view_dispatcher);
|
||||
consumed = true;
|
||||
consumed = seader_hf_request_teardown(seader, SeaderHfTeardownActionStopApp);
|
||||
} else if(event.type == SceneManagerEventTypeTick) {
|
||||
if(fwChecks > 0 && seader->sam_version[0] != 0 && seader->sam_version[1] != 0) {
|
||||
fwChecks--;
|
||||
seader_scene_sam_present_on_update(context);
|
||||
seader_scene_sam_present_rebuild_menu(seader, submenu_get_selected_item(seader->submenu));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,10 +7,13 @@
|
||||
#define SEADER_HF_PLUGIN_PATH APP_ASSETS_PATH("plugins/plugin_hf.fal")
|
||||
|
||||
typedef struct {
|
||||
bool done;
|
||||
bool detected;
|
||||
volatile bool done;
|
||||
volatile bool detected;
|
||||
} SeaderHfPicopassDetectContext;
|
||||
|
||||
static void seader_hf_worker_event_callback(uint32_t event, void* context);
|
||||
static void seader_hf_teardown_blocking(Seader* seader);
|
||||
|
||||
static NfcCommand seader_hf_picopass_detect_callback(PicopassPollerEvent event, void* context) {
|
||||
SeaderHfPicopassDetectContext* detect_context = context;
|
||||
|
||||
@@ -215,13 +218,18 @@ static bool seader_hf_plugin_picopass_detect(void* host_ctx) {
|
||||
PicopassPoller* poller = picopass_poller_alloc(seader->nfc);
|
||||
SeaderHfPicopassDetectContext detect_context = {0};
|
||||
|
||||
if(!poller) {
|
||||
FURI_LOG_W(TAG, "Failed to allocate Picopass detect poller");
|
||||
return false;
|
||||
}
|
||||
|
||||
picopass_poller_start(poller, seader_hf_picopass_detect_callback, &detect_context);
|
||||
for(uint8_t i = 0; i < 10 && !detect_context.done; i++) {
|
||||
furi_delay_ms(10);
|
||||
}
|
||||
|
||||
detected = detect_context.detected;
|
||||
picopass_poller_stop(poller);
|
||||
detected = detect_context.detected;
|
||||
picopass_poller_free(poller);
|
||||
|
||||
return detected;
|
||||
@@ -343,6 +351,15 @@ static const PluginHfHostApi seader_hf_plugin_host_api = {
|
||||
.set_read_error = seader_hf_plugin_set_read_error,
|
||||
};
|
||||
|
||||
static void seader_hf_worker_event_callback(uint32_t event, void* context) {
|
||||
Seader* seader = context;
|
||||
if(!seader || !seader->view_dispatcher) {
|
||||
return;
|
||||
}
|
||||
|
||||
view_dispatcher_send_custom_event(seader->view_dispatcher, event);
|
||||
}
|
||||
|
||||
bool seader_custom_event_callback(void* context, uint32_t event) {
|
||||
furi_assert(context);
|
||||
Seader* seader = context;
|
||||
@@ -384,8 +401,8 @@ Seader* seader_alloc() {
|
||||
seader_uhf_status_label_format(
|
||||
false, false, false, false, seader->uhf_status_label, sizeof(seader->uhf_status_label));
|
||||
seader_uhf_snmp_probe_init(&seader->snmp_probe);
|
||||
seader->nfc = NULL;
|
||||
seader->nfc_device = NULL;
|
||||
seader->nfc = nfc_alloc();
|
||||
seader->nfc_device = seader->nfc ? nfc_device_alloc() : NULL;
|
||||
seader->scratch.offset = 0U;
|
||||
seader->scratch.high_water = 0U;
|
||||
seader->hf_mode = NULL;
|
||||
@@ -405,8 +422,13 @@ Seader* seader_alloc() {
|
||||
|
||||
seader->credential = seader_credential_alloc();
|
||||
|
||||
seader->nfc = NULL;
|
||||
seader->nfc_device = NULL;
|
||||
if(!seader->nfc || !seader->nfc_device) {
|
||||
FURI_LOG_W(
|
||||
TAG,
|
||||
"HF host NFC objects unavailable at startup nfc=%p device=%p",
|
||||
seader->nfc,
|
||||
seader->nfc_device);
|
||||
}
|
||||
|
||||
// Open GUI record
|
||||
seader->gui = furi_record_open(RECORD_GUI);
|
||||
@@ -458,6 +480,9 @@ Seader* seader_alloc() {
|
||||
seader->hf_plugin_manager = NULL;
|
||||
seader->plugin_hf = NULL;
|
||||
seader->hf_plugin_ctx = NULL;
|
||||
seader->hf_session_state = SeaderHfSessionStateUnloaded;
|
||||
seader->hf_teardown_action = SeaderHfTeardownActionNone;
|
||||
seader->hf_teardown_skip_read_cleanup = false;
|
||||
|
||||
return seader;
|
||||
}
|
||||
@@ -469,21 +494,31 @@ void seader_free(Seader* seader) {
|
||||
furi_hal_power_disable_otg();
|
||||
}
|
||||
|
||||
seader_uart_free(seader->uart);
|
||||
seader->uart = NULL;
|
||||
seader_hf_teardown_blocking(seader);
|
||||
seader_hf_mode_deactivate(seader);
|
||||
seader_worker_release(seader);
|
||||
if(seader->worker) {
|
||||
seader_worker_free(seader->worker);
|
||||
seader->worker = NULL;
|
||||
}
|
||||
|
||||
seader_credential_free(seader->credential);
|
||||
seader->credential = NULL;
|
||||
seader_wiegand_plugin_release(seader);
|
||||
|
||||
if(seader->nfc_device) {
|
||||
nfc_device_free(seader->nfc_device);
|
||||
seader->nfc_device = NULL;
|
||||
}
|
||||
|
||||
if(seader->nfc) {
|
||||
nfc_free(seader->nfc);
|
||||
seader->nfc = NULL;
|
||||
}
|
||||
|
||||
if(seader->nfc_device) {
|
||||
nfc_device_free(seader->nfc_device);
|
||||
seader->nfc_device = NULL;
|
||||
}
|
||||
seader_uart_free(seader->uart);
|
||||
seader->uart = NULL;
|
||||
|
||||
seader_credential_free(seader->credential);
|
||||
seader->credential = NULL;
|
||||
|
||||
// Submenu
|
||||
view_dispatcher_remove_view(seader->view_dispatcher, SeaderViewMenu);
|
||||
@@ -516,13 +551,6 @@ void seader_free(Seader* seader) {
|
||||
furi_string_free(seader->temp_string3);
|
||||
furi_string_free(seader->temp_string4);
|
||||
|
||||
seader_hf_mode_deactivate(seader);
|
||||
seader_worker_release(seader);
|
||||
if(seader->worker) {
|
||||
seader_worker_free(seader->worker);
|
||||
seader->worker = NULL;
|
||||
}
|
||||
|
||||
// View Dispatcher
|
||||
view_dispatcher_free(seader->view_dispatcher);
|
||||
|
||||
@@ -537,9 +565,6 @@ void seader_free(Seader* seader) {
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
seader->notifications = NULL;
|
||||
|
||||
seader_wiegand_plugin_release(seader);
|
||||
seader_hf_plugin_release(seader);
|
||||
|
||||
free(seader);
|
||||
}
|
||||
|
||||
@@ -651,26 +676,36 @@ void seader_wiegand_plugin_release(Seader* seader) {
|
||||
bool seader_hf_plugin_acquire(Seader* seader) {
|
||||
furi_assert(seader);
|
||||
|
||||
if(seader->hf_session_state == SeaderHfSessionStateTearingDown) {
|
||||
FURI_LOG_W(TAG, "Reject HF plugin acquire during teardown");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(seader->plugin_hf && seader->hf_plugin_ctx) {
|
||||
if(seader->hf_session_state == SeaderHfSessionStateUnloaded) {
|
||||
seader->hf_session_state = SeaderHfSessionStateLoaded;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if(!seader->nfc) {
|
||||
seader->nfc = nfc_alloc();
|
||||
if(!seader->nfc) {
|
||||
FURI_LOG_E(TAG, "Failed to allocate host NFC");
|
||||
return false;
|
||||
}
|
||||
if(seader->hf_plugin_manager || seader->plugin_hf || seader->hf_plugin_ctx) {
|
||||
FURI_LOG_W(
|
||||
TAG,
|
||||
"Normalize partial HF session manager=%p plugin=%p ctx=%p state=%d",
|
||||
(void*)seader->hf_plugin_manager,
|
||||
(void*)seader->plugin_hf,
|
||||
seader->hf_plugin_ctx,
|
||||
seader->hf_session_state);
|
||||
seader_hf_plugin_release(seader);
|
||||
}
|
||||
|
||||
if(!seader->nfc_device) {
|
||||
seader->nfc_device = nfc_device_alloc();
|
||||
if(!seader->nfc_device) {
|
||||
FURI_LOG_E(TAG, "Failed to allocate host NFC device");
|
||||
nfc_free(seader->nfc);
|
||||
seader->nfc = NULL;
|
||||
return false;
|
||||
}
|
||||
if(!seader->nfc || !seader->nfc_device) {
|
||||
FURI_LOG_E(
|
||||
TAG,
|
||||
"Host NFC objects unavailable nfc=%p device=%p",
|
||||
seader->nfc,
|
||||
seader->nfc_device);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!seader->hf_plugin_manager) {
|
||||
@@ -688,6 +723,9 @@ bool seader_hf_plugin_acquire(Seader* seader) {
|
||||
FURI_LOG_E(TAG, "Failed to load HF plugin");
|
||||
plugin_manager_free(seader->hf_plugin_manager);
|
||||
seader->hf_plugin_manager = NULL;
|
||||
seader->plugin_hf = NULL;
|
||||
seader->hf_plugin_ctx = NULL;
|
||||
seader->hf_session_state = SeaderHfSessionStateUnloaded;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -697,6 +735,8 @@ bool seader_hf_plugin_acquire(Seader* seader) {
|
||||
FURI_LOG_E(TAG, "Failed to resolve HF plugin entry point");
|
||||
plugin_manager_free(seader->hf_plugin_manager);
|
||||
seader->hf_plugin_manager = NULL;
|
||||
seader->hf_plugin_ctx = NULL;
|
||||
seader->hf_session_state = SeaderHfSessionStateUnloaded;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -706,13 +746,44 @@ bool seader_hf_plugin_acquire(Seader* seader) {
|
||||
plugin_manager_free(seader->hf_plugin_manager);
|
||||
seader->hf_plugin_manager = NULL;
|
||||
seader->plugin_hf = NULL;
|
||||
seader->hf_session_state = SeaderHfSessionStateUnloaded;
|
||||
return false;
|
||||
}
|
||||
|
||||
seader->hf_session_state = SeaderHfSessionStateLoaded;
|
||||
FURI_LOG_I(TAG, "HF plugin loaded: %s", seader->plugin_hf->name);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool seader_hf_has_runtime(const Seader* seader) {
|
||||
return seader &&
|
||||
(seader->hf_plugin_manager || seader->plugin_hf || seader->hf_plugin_ctx ||
|
||||
seader->poller || seader->picopass_poller);
|
||||
}
|
||||
|
||||
static void seader_hf_teardown_blocking(Seader* seader) {
|
||||
if(!seader || !seader_hf_has_runtime(seader)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!seader_worker_acquire(seader) || !seader->worker || !seader->uart) {
|
||||
FURI_LOG_W(TAG, "HF blocking teardown fallback");
|
||||
seader_hf_plugin_release(seader);
|
||||
return;
|
||||
}
|
||||
|
||||
seader->hf_session_state = SeaderHfSessionStateTearingDown;
|
||||
seader_worker_stop(seader->worker);
|
||||
FURI_LOG_I(TAG, "HF teardown blocking");
|
||||
seader_worker_start(
|
||||
seader->worker,
|
||||
SeaderWorkerStateHfTeardown,
|
||||
seader->uart,
|
||||
NULL,
|
||||
seader);
|
||||
seader_worker_join(seader->worker);
|
||||
}
|
||||
|
||||
void seader_hf_plugin_release(Seader* seader) {
|
||||
furi_assert(seader);
|
||||
|
||||
@@ -727,23 +798,98 @@ void seader_hf_plugin_release(Seader* seader) {
|
||||
seader->hf_plugin_ctx = NULL;
|
||||
seader->plugin_hf = NULL;
|
||||
|
||||
if(seader->poller) {
|
||||
FURI_LOG_I(TAG, "Stopping host NFC poller");
|
||||
nfc_poller_stop(seader->poller);
|
||||
nfc_poller_free(seader->poller);
|
||||
seader->poller = NULL;
|
||||
}
|
||||
|
||||
if(seader->picopass_poller) {
|
||||
FURI_LOG_I(TAG, "Stopping host Picopass poller");
|
||||
picopass_poller_stop(seader->picopass_poller);
|
||||
picopass_poller_free(seader->picopass_poller);
|
||||
seader->picopass_poller = NULL;
|
||||
}
|
||||
|
||||
if(seader->hf_plugin_manager) {
|
||||
FURI_LOG_I(TAG, "Unloading HF plugin");
|
||||
plugin_manager_free(seader->hf_plugin_manager);
|
||||
seader->hf_plugin_manager = NULL;
|
||||
}
|
||||
|
||||
if(seader->nfc_device) {
|
||||
nfc_device_free(seader->nfc_device);
|
||||
seader->nfc_device = NULL;
|
||||
seader->hf_session_state = SeaderHfSessionStateUnloaded;
|
||||
}
|
||||
|
||||
bool seader_hf_finish_teardown_action(Seader* seader) {
|
||||
if(!seader) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(seader->nfc) {
|
||||
nfc_free(seader->nfc);
|
||||
seader->nfc = NULL;
|
||||
FURI_LOG_I(TAG, "HF teardown complete action=%d", seader->hf_teardown_action);
|
||||
seader_show_loading_popup(seader, false);
|
||||
seader->hf_teardown_skip_read_cleanup = false;
|
||||
seader_hf_mode_set_selected_read_type(seader, SeaderCredentialTypeNone);
|
||||
seader_hf_mode_clear_detected_types(seader);
|
||||
seader_hf_mode_deactivate(seader);
|
||||
|
||||
const SeaderHfTeardownAction action = seader->hf_teardown_action;
|
||||
seader->hf_teardown_action = SeaderHfTeardownActionNone;
|
||||
|
||||
switch(action) {
|
||||
case SeaderHfTeardownActionSamPresent:
|
||||
return scene_manager_search_and_switch_to_another_scene(
|
||||
seader->scene_manager, SeaderSceneSamPresent);
|
||||
case SeaderHfTeardownActionRestartRead:
|
||||
scene_manager_next_scene(seader->scene_manager, SeaderSceneRead);
|
||||
return true;
|
||||
case SeaderHfTeardownActionStopApp:
|
||||
scene_manager_stop(seader->scene_manager);
|
||||
view_dispatcher_stop(seader->view_dispatcher);
|
||||
return true;
|
||||
case SeaderHfTeardownActionNone:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool seader_hf_request_teardown(Seader* seader, SeaderHfTeardownAction action) {
|
||||
furi_assert(seader);
|
||||
|
||||
FURI_LOG_I(
|
||||
TAG,
|
||||
"HF teardown requested action=%d state=%d worker_state=%d",
|
||||
action,
|
||||
seader->hf_session_state,
|
||||
seader->worker ? seader_worker_get_state(seader->worker) : -1);
|
||||
|
||||
seader->hf_teardown_action = action;
|
||||
if(!seader_hf_has_runtime(seader)) {
|
||||
seader->hf_session_state = SeaderHfSessionStateUnloaded;
|
||||
return seader_hf_finish_teardown_action(seader);
|
||||
}
|
||||
|
||||
if(!seader_worker_acquire(seader)) {
|
||||
return seader_hf_finish_teardown_action(seader);
|
||||
}
|
||||
|
||||
if(seader->hf_session_state == SeaderHfSessionStateTearingDown ||
|
||||
(seader->worker &&
|
||||
seader_worker_get_state(seader->worker) == SeaderWorkerStateHfTeardown)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
seader->hf_session_state = SeaderHfSessionStateTearingDown;
|
||||
seader_worker_stop(seader->worker);
|
||||
seader_worker_start(
|
||||
seader->worker,
|
||||
SeaderWorkerStateHfTeardown,
|
||||
seader->uart,
|
||||
seader_hf_worker_event_callback,
|
||||
seader);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool seader_worker_acquire(Seader* seader) {
|
||||
furi_assert(seader);
|
||||
|
||||
|
||||
@@ -6,6 +6,20 @@
|
||||
typedef struct Seader Seader;
|
||||
typedef struct SeaderPollerContainer SeaderPollerContainer;
|
||||
|
||||
typedef enum {
|
||||
SeaderHfSessionStateUnloaded,
|
||||
SeaderHfSessionStateLoaded,
|
||||
SeaderHfSessionStateActive,
|
||||
SeaderHfSessionStateTearingDown,
|
||||
} SeaderHfSessionState;
|
||||
|
||||
typedef enum {
|
||||
SeaderHfTeardownActionNone,
|
||||
SeaderHfTeardownActionSamPresent,
|
||||
SeaderHfTeardownActionRestartRead,
|
||||
SeaderHfTeardownActionStopApp,
|
||||
} SeaderHfTeardownAction;
|
||||
|
||||
bool seader_worker_acquire(Seader* seader);
|
||||
void seader_worker_release(Seader* seader);
|
||||
void seader_scratch_reset(Seader* seader);
|
||||
@@ -14,3 +28,5 @@ bool seader_wiegand_plugin_acquire(Seader* seader);
|
||||
void seader_wiegand_plugin_release(Seader* seader);
|
||||
bool seader_hf_plugin_acquire(Seader* seader);
|
||||
void seader_hf_plugin_release(Seader* seader);
|
||||
bool seader_hf_request_teardown(Seader* seader, SeaderHfTeardownAction action);
|
||||
bool seader_hf_finish_teardown_action(Seader* seader);
|
||||
|
||||
@@ -187,6 +187,9 @@ struct Seader {
|
||||
PluginManager* hf_plugin_manager;
|
||||
PluginHf* plugin_hf;
|
||||
void* hf_plugin_ctx;
|
||||
SeaderHfSessionState hf_session_state;
|
||||
SeaderHfTeardownAction hf_teardown_action;
|
||||
bool hf_teardown_skip_read_cleanup;
|
||||
|
||||
APDULog* apdu_log;
|
||||
SeaderAPDURunnerContext apdu_runner_ctx;
|
||||
|
||||
+52
-6
@@ -18,11 +18,33 @@
|
||||
void seader_send_card_detected(SeaderUartBridge* seader_uart, CardDetails_t* cardDetails);
|
||||
void seader_worker_reading(Seader* seader);
|
||||
|
||||
static void seader_worker_release_hf_session(Seader* seader) {
|
||||
if(!seader) {
|
||||
return;
|
||||
}
|
||||
|
||||
seader_hf_plugin_release(seader);
|
||||
if(seader->worker) {
|
||||
seader_worker_reset_poller_session(seader->worker);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
bool done;
|
||||
bool detected;
|
||||
volatile bool done;
|
||||
volatile bool detected;
|
||||
} SeaderPicopassDetectContext;
|
||||
|
||||
static void seader_worker_clear_active_card(Seader* seader, const char* reason) {
|
||||
if(!seader) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(seader_sam_has_active_card(seader)) {
|
||||
FURI_LOG_I(TAG, "Clear active SAM card (%s)", reason ? reason : "worker");
|
||||
seader_send_no_card_detected(seader);
|
||||
}
|
||||
}
|
||||
|
||||
static NfcCommand
|
||||
seader_worker_picopass_detect_callback(PicopassPollerEvent event, void* context) {
|
||||
SeaderPicopassDetectContext* detect_context = context;
|
||||
@@ -45,14 +67,19 @@ static bool seader_worker_detect_picopass(Nfc* nfc) {
|
||||
PicopassPoller* poller = picopass_poller_alloc(nfc);
|
||||
SeaderPicopassDetectContext detect_context = {0};
|
||||
|
||||
if(!poller) {
|
||||
FURI_LOG_W(TAG, "Failed to allocate Picopass detect poller");
|
||||
return false;
|
||||
}
|
||||
|
||||
picopass_poller_start(poller, seader_worker_picopass_detect_callback, &detect_context);
|
||||
|
||||
for(uint8_t i = 0; i < 10 && !detect_context.done; i++) {
|
||||
furi_delay_ms(10);
|
||||
}
|
||||
|
||||
detected = detect_context.detected;
|
||||
picopass_poller_stop(poller);
|
||||
detected = detect_context.detected;
|
||||
picopass_poller_free(poller);
|
||||
|
||||
return detected;
|
||||
@@ -213,6 +240,15 @@ void seader_worker_stop(SeaderWorker* seader_worker) {
|
||||
furi_thread_join(seader_worker->thread);
|
||||
}
|
||||
|
||||
void seader_worker_join(SeaderWorker* seader_worker) {
|
||||
furi_assert(seader_worker);
|
||||
if(furi_thread_get_state(seader_worker->thread) == FuriThreadStateStopped) {
|
||||
return;
|
||||
}
|
||||
|
||||
furi_thread_join(seader_worker->thread);
|
||||
}
|
||||
|
||||
void seader_worker_change_state(SeaderWorker* seader_worker, SeaderWorkerState state) {
|
||||
seader_worker->state = state;
|
||||
}
|
||||
@@ -427,6 +463,12 @@ int32_t seader_worker_task(void* context) {
|
||||
FURI_LOG_D(TAG, "APDU Runner");
|
||||
seader_apdu_runner_init(seader);
|
||||
return 0;
|
||||
} else if(seader_worker->state == SeaderWorkerStateHfTeardown) {
|
||||
FURI_LOG_I(TAG, "HF teardown started");
|
||||
seader_worker_release_hf_session(seader);
|
||||
if(seader_worker->callback) {
|
||||
seader_worker->callback(SeaderWorkerEventHfTeardownComplete, seader_worker->context);
|
||||
}
|
||||
} else if(seader_worker->state == SeaderWorkerStateReading) {
|
||||
FURI_LOG_D(TAG, "Reading mode started");
|
||||
seader_worker_reading(seader);
|
||||
@@ -442,6 +484,7 @@ void seader_worker_reading(Seader* seader) {
|
||||
|
||||
if(!seader_hf_plugin_acquire(seader) || !seader->plugin_hf || !seader->hf_plugin_ctx) {
|
||||
FURI_LOG_E(TAG, "HF plugin unavailable");
|
||||
strlcpy(seader->read_error, "HF plugin unavailable", sizeof(seader->read_error));
|
||||
if(seader_worker->callback) {
|
||||
seader_worker->callback(SeaderWorkerEventFail, seader_worker->context);
|
||||
}
|
||||
@@ -475,6 +518,9 @@ void seader_worker_reading(Seader* seader) {
|
||||
if(type_to_read != SeaderCredentialTypeNone) {
|
||||
FURI_LOG_I(TAG, "HF start read for type=%d", type_to_read);
|
||||
detected = seader->plugin_hf->start_read_for_type(seader->hf_plugin_ctx, type_to_read);
|
||||
if(detected) {
|
||||
seader->hf_session_state = SeaderHfSessionStateActive;
|
||||
}
|
||||
FURI_LOG_I(TAG, "HF start read result=%d", detected);
|
||||
}
|
||||
|
||||
@@ -488,8 +534,9 @@ void seader_worker_reading(Seader* seader) {
|
||||
furi_delay_ms(10);
|
||||
}
|
||||
result_stage = seader_worker->stage;
|
||||
|
||||
seader->plugin_hf->stop(seader->hf_plugin_ctx);
|
||||
seader_worker_clear_active_card(
|
||||
seader,
|
||||
result_stage == SeaderPollerEventTypeComplete ? "read-complete" : "read-abort");
|
||||
|
||||
if(result_stage == SeaderPollerEventTypeComplete) {
|
||||
// Notify UI of success
|
||||
@@ -504,7 +551,6 @@ void seader_worker_reading(Seader* seader) {
|
||||
furi_delay_ms(50);
|
||||
}
|
||||
}
|
||||
seader->plugin_hf->stop(seader->hf_plugin_ctx);
|
||||
|
||||
FURI_LOG_I(TAG, "Reading loop stopped");
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ typedef enum {
|
||||
SeaderWorkerStateVirtualCredential,
|
||||
SeaderWorkerStateAPDURunner,
|
||||
SeaderWorkerStateReading,
|
||||
SeaderWorkerStateHfTeardown,
|
||||
// Transition
|
||||
SeaderWorkerStateStop,
|
||||
} SeaderWorkerState;
|
||||
@@ -44,6 +45,7 @@ typedef enum {
|
||||
SeaderWorkerEventAPDURunnerUpdate,
|
||||
SeaderWorkerEventAPDURunnerSuccess,
|
||||
SeaderWorkerEventAPDURunnerError,
|
||||
SeaderWorkerEventHfTeardownComplete,
|
||||
} SeaderWorkerEvent;
|
||||
|
||||
typedef enum {
|
||||
@@ -71,6 +73,7 @@ void seader_worker_start(
|
||||
void* context);
|
||||
|
||||
void seader_worker_stop(SeaderWorker* seader_worker);
|
||||
void seader_worker_join(SeaderWorker* seader_worker);
|
||||
bool seader_worker_process_sam_message(Seader* seader, uint8_t* apdu, uint32_t len);
|
||||
void seader_worker_send_version(Seader* seader);
|
||||
void seader_worker_cancel_poller_session(SeaderWorker* seader_worker);
|
||||
|
||||
Reference in New Issue
Block a user