mirror of
https://github.com/bettse/seader.git
synced 2026-03-29 05:49:56 +00:00
Split host and integration test coverage
This commit is contained in:
48
Makefile
48
Makefile
@@ -9,9 +9,12 @@ asn1:
|
||||
build:
|
||||
ufbt
|
||||
|
||||
HOST_TEST_CFLAGS = -std=c11 -Wall -Wextra -Werror -DSEADER_HOST_TEST -Ilib/host_tests/vendor/munit -Ilib/host_tests -Ilib/asn1 -I.
|
||||
ASN1_TEST_CFLAGS = -std=c11 -Wall -Wextra -Werror -Wno-error=unused-function -Wno-error=unused-parameter -DASN_DISABLE_PER_SUPPORT -DASN_DISABLE_OER_SUPPORT -DASN_DISABLE_XER_SUPPORT -DASN_DISABLE_RANDOM_FILL -Ilib/host_tests/vendor/munit -Ilib/host_tests -Ilib/asn1 -Ilib/asn1_skeletons -I.
|
||||
|
||||
test-host:
|
||||
mkdir -p build/host_tests
|
||||
cc -std=c11 -Wall -Wextra -Werror -DSEADER_HOST_TEST -Ilib/host_tests/vendor/munit -Ilib/host_tests -I. \
|
||||
cc $(HOST_TEST_CFLAGS) \
|
||||
lib/host_tests/vendor/munit/munit.c \
|
||||
lib/host_tests/test_main.c \
|
||||
lib/host_tests/test_lrc.c \
|
||||
@@ -21,6 +24,7 @@ test-host:
|
||||
lib/host_tests/test_t1_protocol.c \
|
||||
lib/host_tests/test_snmp.c \
|
||||
lib/host_tests/test_uhf_status_label.c \
|
||||
lib/host_tests/test_runtime_policy.c \
|
||||
lib/host_tests/t1_test_stubs.c \
|
||||
lib/host_tests/bit_buffer_mock.c \
|
||||
lrc.c \
|
||||
@@ -34,9 +38,51 @@ test-host:
|
||||
uhf_status_label.c \
|
||||
uhf_tag_config_view.c \
|
||||
uhf_snmp_probe.c \
|
||||
runtime_policy.c \
|
||||
-o build/host_tests/seader_tests
|
||||
./build/host_tests/seader_tests
|
||||
|
||||
test-asn1-integration:
|
||||
mkdir -p build/host_tests
|
||||
cc $(ASN1_TEST_CFLAGS) \
|
||||
lib/host_tests/vendor/munit/munit.c \
|
||||
lib/host_tests/test_card_details_main.c \
|
||||
lib/host_tests/test_card_details_builder.c \
|
||||
card_details_builder.c \
|
||||
lib/asn1/CardDetails.c \
|
||||
lib/asn1/Protocol.c \
|
||||
lib/asn1/FrameProtocol.c \
|
||||
lib/asn1/RunTimerValue.c \
|
||||
lib/asn1_skeletons/OCTET_STRING.c \
|
||||
lib/asn1_skeletons/BOOLEAN.c \
|
||||
lib/asn1_skeletons/NativeInteger.c \
|
||||
lib/asn1_skeletons/NativeEnumerated.c \
|
||||
lib/asn1_skeletons/INTEGER.c \
|
||||
lib/asn1_skeletons/OPEN_TYPE.c \
|
||||
lib/asn1_skeletons/constr_CHOICE.c \
|
||||
lib/asn1_skeletons/constr_SEQUENCE.c \
|
||||
lib/asn1_skeletons/constr_TYPE.c \
|
||||
lib/asn1_skeletons/asn_application.c \
|
||||
lib/asn1_skeletons/asn_codecs_prim.c \
|
||||
lib/asn1_skeletons/ber_tlv_tag.c \
|
||||
lib/asn1_skeletons/ber_tlv_length.c \
|
||||
lib/asn1_skeletons/ber_decoder.c \
|
||||
lib/asn1_skeletons/der_encoder.c \
|
||||
lib/asn1_skeletons/constraints.c \
|
||||
lib/asn1_skeletons/asn_internal.c \
|
||||
-o build/host_tests/seader_card_details_tests
|
||||
./build/host_tests/seader_card_details_tests
|
||||
|
||||
test-runtime-integration:
|
||||
mkdir -p build/host_tests
|
||||
cc $(HOST_TEST_CFLAGS) \
|
||||
lib/host_tests/vendor/munit/munit.c \
|
||||
lib/host_tests/test_runtime_integration_main.c \
|
||||
lib/host_tests/test_hf_release_sequence.c \
|
||||
hf_release_sequence.c \
|
||||
-o build/host_tests/seader_runtime_integration_tests
|
||||
./build/host_tests/seader_runtime_integration_tests
|
||||
|
||||
launch:
|
||||
ufbt launch
|
||||
|
||||
|
||||
78
card_details_builder.c
Normal file
78
card_details_builder.c
Normal file
@@ -0,0 +1,78 @@
|
||||
#include "card_details_builder.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <FrameProtocol.h>
|
||||
|
||||
bool seader_card_details_build(
|
||||
CardDetails_t* card_details,
|
||||
uint8_t sak,
|
||||
const uint8_t* uid,
|
||||
uint8_t uid_len,
|
||||
const uint8_t* ats,
|
||||
uint8_t ats_len) {
|
||||
if(!card_details || !uid || uid_len == 0U) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(card_details, 0, sizeof(*card_details));
|
||||
|
||||
if(OCTET_STRING_fromBuf(&card_details->csn, (const char*)uid, uid_len) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t protocol_bytes[] = {0x00, 0x00};
|
||||
if(ats != NULL) {
|
||||
protocol_bytes[1] = FrameProtocol_nfc;
|
||||
if(OCTET_STRING_fromBuf(
|
||||
&card_details->protocol,
|
||||
(const char*)protocol_bytes,
|
||||
sizeof(protocol_bytes)) != 0) {
|
||||
seader_card_details_reset(card_details);
|
||||
return false;
|
||||
}
|
||||
card_details->sak = calloc(1, sizeof(*card_details->sak));
|
||||
card_details->atsOrAtqbOrAtr = calloc(1, sizeof(*card_details->atsOrAtqbOrAtr));
|
||||
if(!card_details->sak || !card_details->atsOrAtqbOrAtr ||
|
||||
OCTET_STRING_fromBuf(card_details->sak, (const char*)&sak, 1) != 0 ||
|
||||
OCTET_STRING_fromBuf(card_details->atsOrAtqbOrAtr, (const char*)ats, ats_len) != 0) {
|
||||
seader_card_details_reset(card_details);
|
||||
return false;
|
||||
}
|
||||
} else if(uid_len == 8U) {
|
||||
protocol_bytes[1] = FrameProtocol_iclass;
|
||||
if(OCTET_STRING_fromBuf(
|
||||
&card_details->protocol,
|
||||
(const char*)protocol_bytes,
|
||||
sizeof(protocol_bytes)) != 0) {
|
||||
seader_card_details_reset(card_details);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
protocol_bytes[1] = FrameProtocol_nfc;
|
||||
if(OCTET_STRING_fromBuf(
|
||||
&card_details->protocol,
|
||||
(const char*)protocol_bytes,
|
||||
sizeof(protocol_bytes)) != 0) {
|
||||
seader_card_details_reset(card_details);
|
||||
return false;
|
||||
}
|
||||
card_details->sak = calloc(1, sizeof(*card_details->sak));
|
||||
if(!card_details->sak ||
|
||||
OCTET_STRING_fromBuf(card_details->sak, (const char*)&sak, 1) != 0) {
|
||||
seader_card_details_reset(card_details);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void seader_card_details_reset(CardDetails_t* card_details) {
|
||||
if(!card_details) {
|
||||
return;
|
||||
}
|
||||
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_CardDetails, card_details);
|
||||
memset(card_details, 0, sizeof(*card_details));
|
||||
}
|
||||
21
card_details_builder.h
Normal file
21
card_details_builder.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef ASN_EMIT_DEBUG
|
||||
#define ASN_EMIT_DEBUG 0
|
||||
#endif
|
||||
|
||||
#include <CardDetails.h>
|
||||
|
||||
bool seader_card_details_build(
|
||||
CardDetails_t* card_details,
|
||||
uint8_t sak,
|
||||
const uint8_t* uid,
|
||||
uint8_t uid_len,
|
||||
const uint8_t* ats,
|
||||
uint8_t ats_len);
|
||||
|
||||
void seader_card_details_reset(CardDetails_t* card_details);
|
||||
31
hf_release_sequence.c
Normal file
31
hf_release_sequence.c
Normal file
@@ -0,0 +1,31 @@
|
||||
#include "hf_release_sequence.h"
|
||||
|
||||
static void seader_hf_release_callback_invoke(
|
||||
SeaderHfReleaseCallback callback,
|
||||
void* context) {
|
||||
if(callback) {
|
||||
callback(context);
|
||||
}
|
||||
}
|
||||
|
||||
void seader_hf_release_sequence_run(SeaderHfReleaseSequence* sequence) {
|
||||
if(!sequence) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(sequence->hf_session_state) {
|
||||
*sequence->hf_session_state = SeaderHfSessionStateTearingDown;
|
||||
}
|
||||
seader_hf_release_callback_invoke(sequence->plugin_stop, sequence->context);
|
||||
seader_hf_release_callback_invoke(sequence->host_poller_release, sequence->context);
|
||||
seader_hf_release_callback_invoke(sequence->host_picopass_release, sequence->context);
|
||||
seader_hf_release_callback_invoke(sequence->plugin_free, sequence->context);
|
||||
seader_hf_release_callback_invoke(sequence->plugin_manager_unload, sequence->context);
|
||||
seader_hf_release_callback_invoke(sequence->worker_reset, sequence->context);
|
||||
if(sequence->hf_session_state) {
|
||||
*sequence->hf_session_state = SeaderHfSessionStateUnloaded;
|
||||
}
|
||||
if(sequence->mode_runtime && *sequence->mode_runtime == SeaderModeRuntimeHF) {
|
||||
*sequence->mode_runtime = SeaderModeRuntimeNone;
|
||||
}
|
||||
}
|
||||
19
hf_release_sequence.h
Normal file
19
hf_release_sequence.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "seader.h"
|
||||
|
||||
typedef void (*SeaderHfReleaseCallback)(void* context);
|
||||
|
||||
typedef struct {
|
||||
void* context;
|
||||
SeaderHfSessionState* hf_session_state;
|
||||
SeaderModeRuntime* mode_runtime;
|
||||
SeaderHfReleaseCallback plugin_stop;
|
||||
SeaderHfReleaseCallback host_poller_release;
|
||||
SeaderHfReleaseCallback host_picopass_release;
|
||||
SeaderHfReleaseCallback plugin_free;
|
||||
SeaderHfReleaseCallback plugin_manager_unload;
|
||||
SeaderHfReleaseCallback worker_reset;
|
||||
} SeaderHfReleaseSequence;
|
||||
|
||||
void seader_hf_release_sequence_run(SeaderHfReleaseSequence* sequence);
|
||||
7
lib/host_tests/README.md
Normal file
7
lib/host_tests/README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# Host Test Layers
|
||||
|
||||
- `make test-host`: fast deterministic unit/policy tests. Keep this limited to Seader-owned helpers, formatting, parsing, and ownership-policy logic.
|
||||
- `make test-asn1-integration`: narrow integration coverage for real ASN.1 ownership/free behavior.
|
||||
- `make test-runtime-integration`: narrow mock-based integration coverage for HF release ordering and final state publication.
|
||||
|
||||
Do not add generated ASN.1 or firmware-heavy runtime dependencies to `make test-host` unless they are already a supported part of that surface.
|
||||
93
lib/host_tests/test_card_details_builder.c
Normal file
93
lib/host_tests/test_card_details_builder.c
Normal file
@@ -0,0 +1,93 @@
|
||||
#include "munit.h"
|
||||
|
||||
#include "card_details_builder.h"
|
||||
|
||||
static MunitResult test_builds_type4_with_owned_optional_fields(
|
||||
const MunitParameter params[],
|
||||
void* fixture) {
|
||||
(void)params;
|
||||
(void)fixture;
|
||||
|
||||
const uint8_t uid[] = {0x04, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
|
||||
const uint8_t ats[] = {0x75, 0x77, 0x81, 0x02};
|
||||
CardDetails_t card_details = {0};
|
||||
|
||||
munit_assert_true(
|
||||
seader_card_details_build(&card_details, 0x20U, uid, sizeof(uid), ats, sizeof(ats)));
|
||||
munit_assert_size(card_details.csn.size, ==, sizeof(uid));
|
||||
munit_assert_not_null(card_details.sak);
|
||||
munit_assert_not_null(card_details.atsOrAtqbOrAtr);
|
||||
munit_assert_size(card_details.sak->size, ==, 1U);
|
||||
munit_assert_size(card_details.atsOrAtqbOrAtr->size, ==, sizeof(ats));
|
||||
munit_assert_memory_equal(sizeof(uid), card_details.csn.buf, uid);
|
||||
munit_assert_memory_equal(sizeof(ats), card_details.atsOrAtqbOrAtr->buf, ats);
|
||||
|
||||
seader_card_details_reset(&card_details);
|
||||
munit_assert_ptr_null(card_details.sak);
|
||||
munit_assert_ptr_null(card_details.atsOrAtqbOrAtr);
|
||||
munit_assert_ptr_null(card_details.csn.buf);
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static MunitResult test_builds_picopass_without_optional_fields(
|
||||
const MunitParameter params[],
|
||||
void* fixture) {
|
||||
(void)params;
|
||||
(void)fixture;
|
||||
|
||||
const uint8_t uid[] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
CardDetails_t card_details = {0};
|
||||
|
||||
munit_assert_true(seader_card_details_build(&card_details, 0U, uid, sizeof(uid), NULL, 0U));
|
||||
munit_assert_ptr_null(card_details.sak);
|
||||
munit_assert_ptr_null(card_details.atsOrAtqbOrAtr);
|
||||
|
||||
seader_card_details_reset(&card_details);
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static MunitResult test_builds_mfc_with_owned_sak(
|
||||
const MunitParameter params[],
|
||||
void* fixture) {
|
||||
(void)params;
|
||||
(void)fixture;
|
||||
|
||||
const uint8_t uid[] = {0xDE, 0xAD, 0xBE, 0xEF};
|
||||
CardDetails_t card_details = {0};
|
||||
|
||||
munit_assert_true(seader_card_details_build(&card_details, 0x08U, uid, sizeof(uid), NULL, 0U));
|
||||
munit_assert_not_null(card_details.sak);
|
||||
munit_assert_size(card_details.sak->size, ==, 1U);
|
||||
munit_assert_ptr_null(card_details.atsOrAtqbOrAtr);
|
||||
|
||||
seader_card_details_reset(&card_details);
|
||||
munit_assert_ptr_null(card_details.sak);
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static MunitResult test_rejects_invalid_input(const MunitParameter params[], void* fixture) {
|
||||
(void)params;
|
||||
(void)fixture;
|
||||
|
||||
CardDetails_t card_details = {0};
|
||||
|
||||
munit_assert_false(seader_card_details_build(&card_details, 0U, NULL, 0U, NULL, 0U));
|
||||
munit_assert_ptr_null(card_details.csn.buf);
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static MunitTest test_card_details_builder_cases[] = {
|
||||
{(char*)"/type4-owned-optional-fields", test_builds_type4_with_owned_optional_fields, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL},
|
||||
{(char*)"/picopass-no-optional-fields", test_builds_picopass_without_optional_fields, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL},
|
||||
{(char*)"/mfc-owned-sak", test_builds_mfc_with_owned_sak, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL},
|
||||
{(char*)"/invalid-input", test_rejects_invalid_input, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL},
|
||||
{NULL, NULL, NULL, NULL, 0, NULL},
|
||||
};
|
||||
|
||||
MunitSuite test_card_details_builder_suite = {
|
||||
"",
|
||||
test_card_details_builder_cases,
|
||||
NULL,
|
||||
1,
|
||||
MUNIT_SUITE_OPTION_NONE,
|
||||
};
|
||||
15
lib/host_tests/test_card_details_main.c
Normal file
15
lib/host_tests/test_card_details_main.c
Normal file
@@ -0,0 +1,15 @@
|
||||
#include "munit.h"
|
||||
|
||||
extern MunitSuite test_card_details_builder_suite;
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
MunitSuite main_suite = {
|
||||
"/card-details",
|
||||
test_card_details_builder_suite.tests,
|
||||
NULL,
|
||||
1,
|
||||
MUNIT_SUITE_OPTION_NONE,
|
||||
};
|
||||
|
||||
return munit_suite_main(&main_suite, NULL, argc, argv);
|
||||
}
|
||||
108
lib/host_tests/test_hf_release_sequence.c
Normal file
108
lib/host_tests/test_hf_release_sequence.c
Normal file
@@ -0,0 +1,108 @@
|
||||
#include "munit.h"
|
||||
|
||||
#include "hf_release_sequence.h"
|
||||
|
||||
typedef struct {
|
||||
unsigned index;
|
||||
const char* calls[8];
|
||||
} ReleaseRecorder;
|
||||
|
||||
static void record_call(ReleaseRecorder* recorder, const char* name) {
|
||||
if(recorder && recorder->index < (sizeof(recorder->calls) / sizeof(recorder->calls[0]))) {
|
||||
recorder->calls[recorder->index++] = name;
|
||||
}
|
||||
}
|
||||
|
||||
static void record_plugin_stop(void* context) {
|
||||
record_call(context, "plugin-stop");
|
||||
}
|
||||
|
||||
static void record_host_poller_release(void* context) {
|
||||
record_call(context, "host-poller-release");
|
||||
}
|
||||
|
||||
static void record_picopass_release(void* context) {
|
||||
record_call(context, "picopass-release");
|
||||
}
|
||||
|
||||
static void record_plugin_free(void* context) {
|
||||
record_call(context, "plugin-free");
|
||||
}
|
||||
|
||||
static void record_manager_unload(void* context) {
|
||||
record_call(context, "plugin-manager-unload");
|
||||
}
|
||||
|
||||
static void record_worker_reset(void* context) {
|
||||
record_call(context, "worker-reset");
|
||||
}
|
||||
|
||||
static MunitResult test_release_sequence_orders_operations_and_finalizes_state(
|
||||
const MunitParameter params[],
|
||||
void* fixture) {
|
||||
(void)params;
|
||||
(void)fixture;
|
||||
|
||||
ReleaseRecorder recorder = {0};
|
||||
SeaderHfSessionState hf_state = SeaderHfSessionStateActive;
|
||||
SeaderModeRuntime mode_runtime = SeaderModeRuntimeHF;
|
||||
SeaderHfReleaseSequence sequence = {
|
||||
.context = &recorder,
|
||||
.hf_session_state = &hf_state,
|
||||
.mode_runtime = &mode_runtime,
|
||||
.plugin_stop = record_plugin_stop,
|
||||
.host_poller_release = record_host_poller_release,
|
||||
.host_picopass_release = record_picopass_release,
|
||||
.plugin_free = record_plugin_free,
|
||||
.plugin_manager_unload = record_manager_unload,
|
||||
.worker_reset = record_worker_reset,
|
||||
};
|
||||
|
||||
seader_hf_release_sequence_run(&sequence);
|
||||
|
||||
munit_assert_int(hf_state, ==, SeaderHfSessionStateUnloaded);
|
||||
munit_assert_int(mode_runtime, ==, SeaderModeRuntimeNone);
|
||||
munit_assert_uint(recorder.index, ==, 6);
|
||||
munit_assert_string_equal(recorder.calls[0], "plugin-stop");
|
||||
munit_assert_string_equal(recorder.calls[1], "host-poller-release");
|
||||
munit_assert_string_equal(recorder.calls[2], "picopass-release");
|
||||
munit_assert_string_equal(recorder.calls[3], "plugin-free");
|
||||
munit_assert_string_equal(recorder.calls[4], "plugin-manager-unload");
|
||||
munit_assert_string_equal(recorder.calls[5], "worker-reset");
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static MunitResult test_release_sequence_tolerates_missing_callbacks(
|
||||
const MunitParameter params[],
|
||||
void* fixture) {
|
||||
(void)params;
|
||||
(void)fixture;
|
||||
|
||||
SeaderHfSessionState hf_state = SeaderHfSessionStateLoaded;
|
||||
SeaderModeRuntime mode_runtime = SeaderModeRuntimeHF;
|
||||
SeaderHfReleaseSequence sequence = {
|
||||
.hf_session_state = &hf_state,
|
||||
.mode_runtime = &mode_runtime,
|
||||
.worker_reset = record_worker_reset,
|
||||
};
|
||||
|
||||
seader_hf_release_sequence_run(&sequence);
|
||||
|
||||
munit_assert_int(hf_state, ==, SeaderHfSessionStateUnloaded);
|
||||
munit_assert_int(mode_runtime, ==, SeaderModeRuntimeNone);
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static MunitTest test_hf_release_sequence_cases[] = {
|
||||
{(char*)"/ordering", test_release_sequence_orders_operations_and_finalizes_state, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL},
|
||||
{(char*)"/missing-callbacks", test_release_sequence_tolerates_missing_callbacks, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL},
|
||||
{NULL, NULL, NULL, NULL, 0, NULL},
|
||||
};
|
||||
|
||||
MunitSuite test_hf_release_sequence_suite = {
|
||||
"",
|
||||
test_hf_release_sequence_cases,
|
||||
NULL,
|
||||
1,
|
||||
MUNIT_SUITE_OPTION_NONE,
|
||||
};
|
||||
@@ -7,6 +7,7 @@ extern MunitSuite test_t1_existing_suite;
|
||||
extern MunitSuite test_t1_protocol_suite;
|
||||
extern MunitSuite test_snmp_suite;
|
||||
extern MunitSuite test_uhf_status_label_suite;
|
||||
extern MunitSuite test_runtime_policy_suite;
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
MunitSuite child_suites[] = {
|
||||
@@ -17,6 +18,7 @@ int main(int argc, char* argv[]) {
|
||||
{"/ccid", test_ccid_logic_suite.tests, NULL, 1, MUNIT_SUITE_OPTION_NONE},
|
||||
{"/snmp", test_snmp_suite.tests, NULL, 1, MUNIT_SUITE_OPTION_NONE},
|
||||
{"/uhf-status-label", test_uhf_status_label_suite.tests, NULL, 1, MUNIT_SUITE_OPTION_NONE},
|
||||
{"/runtime-policy", test_runtime_policy_suite.tests, NULL, 1, MUNIT_SUITE_OPTION_NONE},
|
||||
{NULL, NULL, NULL, 0, 0},
|
||||
};
|
||||
MunitSuite main_suite = {
|
||||
|
||||
15
lib/host_tests/test_runtime_integration_main.c
Normal file
15
lib/host_tests/test_runtime_integration_main.c
Normal file
@@ -0,0 +1,15 @@
|
||||
#include "munit.h"
|
||||
|
||||
extern MunitSuite test_hf_release_sequence_suite;
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
MunitSuite main_suite = {
|
||||
"/runtime-integration",
|
||||
test_hf_release_sequence_suite.tests,
|
||||
NULL,
|
||||
1,
|
||||
MUNIT_SUITE_OPTION_NONE,
|
||||
};
|
||||
|
||||
return munit_suite_main(&main_suite, NULL, argc, argv);
|
||||
}
|
||||
139
lib/host_tests/test_runtime_policy.c
Normal file
139
lib/host_tests/test_runtime_policy.c
Normal file
@@ -0,0 +1,139 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "munit.h"
|
||||
#include "runtime_policy.h"
|
||||
|
||||
static MunitResult test_reset_cached_sam_metadata_clears_all_fields(
|
||||
const MunitParameter params[],
|
||||
void* fixture) {
|
||||
(void)params;
|
||||
(void)fixture;
|
||||
|
||||
uint8_t sam_version[2] = {1U, 99U};
|
||||
char uhf_status_label[16];
|
||||
memset(uhf_status_label, 'X', sizeof(uhf_status_label));
|
||||
SeaderUhfSnmpProbe probe = {
|
||||
.stage = SeaderUhfSnmpProbeStageDone,
|
||||
.has_monza4qt = true,
|
||||
.has_higgs3 = true,
|
||||
.monza4qt_key_present = true,
|
||||
.higgs3_key_present = true,
|
||||
.ice_value_len = 7U,
|
||||
};
|
||||
|
||||
seader_runtime_reset_cached_sam_metadata(
|
||||
sam_version, uhf_status_label, sizeof(uhf_status_label), &probe);
|
||||
|
||||
munit_assert_uint8(sam_version[0], ==, 0U);
|
||||
munit_assert_uint8(sam_version[1], ==, 0U);
|
||||
munit_assert_char(uhf_status_label[0], ==, '\0');
|
||||
munit_assert_int(probe.stage, ==, SeaderUhfSnmpProbeStageDiscovery);
|
||||
munit_assert_false(probe.has_monza4qt);
|
||||
munit_assert_false(probe.has_higgs3);
|
||||
munit_assert_false(probe.monza4qt_key_present);
|
||||
munit_assert_false(probe.higgs3_key_present);
|
||||
munit_assert_size(probe.ice_value_len, ==, 0U);
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static MunitResult test_begin_uhf_probe_sets_runtime_and_initializes_probe(
|
||||
const MunitParameter params[],
|
||||
void* fixture) {
|
||||
(void)params;
|
||||
(void)fixture;
|
||||
|
||||
SeaderModeRuntime mode_runtime = SeaderModeRuntimeNone;
|
||||
SeaderUhfSnmpProbe probe = {.stage = SeaderUhfSnmpProbeStageDone};
|
||||
|
||||
munit_assert_true(seader_runtime_begin_uhf_probe(
|
||||
true, &mode_runtime, SeaderHfSessionStateUnloaded, &probe));
|
||||
munit_assert_int(mode_runtime, ==, SeaderModeRuntimeUHF);
|
||||
munit_assert_int(probe.stage, ==, SeaderUhfSnmpProbeStageDiscovery);
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static MunitResult test_begin_uhf_probe_rejects_invalid_states(
|
||||
const MunitParameter params[],
|
||||
void* fixture) {
|
||||
(void)params;
|
||||
(void)fixture;
|
||||
|
||||
SeaderModeRuntime mode_runtime = SeaderModeRuntimeNone;
|
||||
SeaderUhfSnmpProbe probe = {0};
|
||||
|
||||
munit_assert_false(seader_runtime_begin_uhf_probe(
|
||||
false, &mode_runtime, SeaderHfSessionStateUnloaded, &probe));
|
||||
munit_assert_int(mode_runtime, ==, SeaderModeRuntimeNone);
|
||||
|
||||
munit_assert_false(seader_runtime_begin_uhf_probe(
|
||||
true, &mode_runtime, SeaderHfSessionStateActive, &probe));
|
||||
munit_assert_int(mode_runtime, ==, SeaderModeRuntimeNone);
|
||||
|
||||
mode_runtime = SeaderModeRuntimeHF;
|
||||
munit_assert_false(seader_runtime_begin_uhf_probe(
|
||||
true, &mode_runtime, SeaderHfSessionStateUnloaded, &probe));
|
||||
munit_assert_int(mode_runtime, ==, SeaderModeRuntimeHF);
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static MunitResult test_finish_uhf_probe_restores_none(
|
||||
const MunitParameter params[],
|
||||
void* fixture) {
|
||||
(void)params;
|
||||
(void)fixture;
|
||||
|
||||
SeaderModeRuntime mode_runtime = SeaderModeRuntimeUHF;
|
||||
seader_runtime_finish_uhf_probe(&mode_runtime);
|
||||
munit_assert_int(mode_runtime, ==, SeaderModeRuntimeNone);
|
||||
|
||||
mode_runtime = SeaderModeRuntimeHF;
|
||||
seader_runtime_finish_uhf_probe(&mode_runtime);
|
||||
munit_assert_int(mode_runtime, ==, SeaderModeRuntimeHF);
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static MunitResult test_finalize_hf_release_sets_terminal_state(
|
||||
const MunitParameter params[],
|
||||
void* fixture) {
|
||||
(void)params;
|
||||
(void)fixture;
|
||||
|
||||
SeaderHfSessionState hf_state = SeaderHfSessionStateTearingDown;
|
||||
SeaderModeRuntime mode_runtime = SeaderModeRuntimeHF;
|
||||
|
||||
seader_runtime_finalize_hf_release(&hf_state, &mode_runtime);
|
||||
|
||||
munit_assert_int(hf_state, ==, SeaderHfSessionStateUnloaded);
|
||||
munit_assert_int(mode_runtime, ==, SeaderModeRuntimeNone);
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static MunitResult test_begin_hf_teardown_sets_state(
|
||||
const MunitParameter params[],
|
||||
void* fixture) {
|
||||
(void)params;
|
||||
(void)fixture;
|
||||
|
||||
SeaderHfSessionState hf_state = SeaderHfSessionStateActive;
|
||||
seader_runtime_begin_hf_teardown(&hf_state);
|
||||
munit_assert_int(hf_state, ==, SeaderHfSessionStateTearingDown);
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static MunitTest test_runtime_policy_cases[] = {
|
||||
{(char*)"/reset-sam-metadata", test_reset_cached_sam_metadata_clears_all_fields, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL},
|
||||
{(char*)"/begin-uhf-probe", test_begin_uhf_probe_sets_runtime_and_initializes_probe, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL},
|
||||
{(char*)"/begin-uhf-probe-invalid", test_begin_uhf_probe_rejects_invalid_states, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL},
|
||||
{(char*)"/finish-uhf-probe", test_finish_uhf_probe_restores_none, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL},
|
||||
{(char*)"/begin-hf-teardown", test_begin_hf_teardown_sets_state, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL},
|
||||
{(char*)"/finalize-hf-release", test_finalize_hf_release_sets_terminal_state, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL},
|
||||
{NULL, NULL, NULL, NULL, 0, NULL},
|
||||
};
|
||||
|
||||
MunitSuite test_runtime_policy_suite = {
|
||||
"",
|
||||
test_runtime_policy_cases,
|
||||
NULL,
|
||||
1,
|
||||
MUNIT_SUITE_OPTION_NONE,
|
||||
};
|
||||
@@ -1,3 +1,5 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "munit.h"
|
||||
#include "uhf_status_label.h"
|
||||
|
||||
@@ -19,9 +21,68 @@ static MunitResult test_formats_supported_key_states(const MunitParameter params
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static MunitResult test_handles_null_and_zero_sized_output(
|
||||
const MunitParameter params[],
|
||||
void* fixture) {
|
||||
(void)params;
|
||||
(void)fixture;
|
||||
|
||||
seader_uhf_status_label_format(true, true, false, false, NULL, 0U);
|
||||
|
||||
char label[4] = {'X', 'Y', 'Z', 'W'};
|
||||
seader_uhf_status_label_format(true, true, false, false, label, 0U);
|
||||
munit_assert_memory_equal(sizeof(label), label, ((char[]){'X', 'Y', 'Z', 'W'}));
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static MunitResult test_nul_terminates_single_byte_output(
|
||||
const MunitParameter params[],
|
||||
void* fixture) {
|
||||
(void)params;
|
||||
(void)fixture;
|
||||
|
||||
char label[1] = {'X'};
|
||||
seader_uhf_status_label_format(true, false, true, false, label, sizeof(label));
|
||||
munit_assert_char(label[0], ==, '\0');
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static MunitResult test_truncates_safely_for_small_buffers(
|
||||
const MunitParameter params[],
|
||||
void* fixture) {
|
||||
(void)params;
|
||||
(void)fixture;
|
||||
|
||||
char label[8];
|
||||
memset(label, 'Z', sizeof(label));
|
||||
seader_uhf_status_label_format(true, false, true, false, label, sizeof(label));
|
||||
|
||||
munit_assert_char(label[sizeof(label) - 1], ==, '\0');
|
||||
munit_assert_char(label[0], ==, 'U');
|
||||
munit_assert_char(label[1], ==, 'H');
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static MunitResult test_small_buffer_for_none_is_safe(const MunitParameter params[], void* fixture) {
|
||||
(void)params;
|
||||
(void)fixture;
|
||||
|
||||
char label[4];
|
||||
memset(label, 'Q', sizeof(label));
|
||||
seader_uhf_status_label_format(false, false, false, false, label, sizeof(label));
|
||||
|
||||
munit_assert_char(label[sizeof(label) - 1], ==, '\0');
|
||||
munit_assert_char(label[0], ==, 'U');
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static MunitTest test_uhf_status_label_cases[] = {
|
||||
{(char*)"/none", test_formats_none, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL},
|
||||
{(char*)"/supported-key-states", test_formats_supported_key_states, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL},
|
||||
{(char*)"/null-zero-output", test_handles_null_and_zero_sized_output, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL},
|
||||
{(char*)"/single-byte-output", test_nul_terminates_single_byte_output, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL},
|
||||
{(char*)"/small-buffer-truncation", test_truncates_safely_for_small_buffers, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL},
|
||||
{(char*)"/small-buffer-none", test_small_buffer_for_none_is_safe, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL},
|
||||
{NULL, NULL, NULL, NULL, 0, NULL},
|
||||
};
|
||||
|
||||
|
||||
70
runtime_policy.c
Normal file
70
runtime_policy.c
Normal file
@@ -0,0 +1,70 @@
|
||||
#include "runtime_policy.h"
|
||||
|
||||
void seader_runtime_reset_cached_sam_metadata(
|
||||
uint8_t sam_version[2],
|
||||
char* uhf_status_label,
|
||||
size_t label_size,
|
||||
SeaderUhfSnmpProbe* probe) {
|
||||
if(sam_version) {
|
||||
sam_version[0] = 0U;
|
||||
sam_version[1] = 0U;
|
||||
}
|
||||
|
||||
if(uhf_status_label && label_size > 0U) {
|
||||
uhf_status_label[0] = '\0';
|
||||
}
|
||||
|
||||
if(probe) {
|
||||
seader_uhf_snmp_probe_init(probe);
|
||||
}
|
||||
}
|
||||
|
||||
bool seader_runtime_begin_uhf_probe(
|
||||
bool sam_present,
|
||||
SeaderModeRuntime* mode_runtime,
|
||||
SeaderHfSessionState hf_session_state,
|
||||
SeaderUhfSnmpProbe* probe) {
|
||||
if(!sam_present || !mode_runtime || !probe) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(hf_session_state != SeaderHfSessionStateUnloaded) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(*mode_runtime != SeaderModeRuntimeNone) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*mode_runtime = SeaderModeRuntimeUHF;
|
||||
seader_uhf_snmp_probe_init(probe);
|
||||
return true;
|
||||
}
|
||||
|
||||
void seader_runtime_finish_uhf_probe(SeaderModeRuntime* mode_runtime) {
|
||||
if(!mode_runtime) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(*mode_runtime == SeaderModeRuntimeUHF) {
|
||||
*mode_runtime = SeaderModeRuntimeNone;
|
||||
}
|
||||
}
|
||||
|
||||
void seader_runtime_begin_hf_teardown(SeaderHfSessionState* hf_session_state) {
|
||||
if(hf_session_state) {
|
||||
*hf_session_state = SeaderHfSessionStateTearingDown;
|
||||
}
|
||||
}
|
||||
|
||||
void seader_runtime_finalize_hf_release(
|
||||
SeaderHfSessionState* hf_session_state,
|
||||
SeaderModeRuntime* mode_runtime) {
|
||||
if(hf_session_state) {
|
||||
*hf_session_state = SeaderHfSessionStateUnloaded;
|
||||
}
|
||||
|
||||
if(mode_runtime && *mode_runtime == SeaderModeRuntimeHF) {
|
||||
*mode_runtime = SeaderModeRuntimeNone;
|
||||
}
|
||||
}
|
||||
28
runtime_policy.h
Normal file
28
runtime_policy.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "seader.h"
|
||||
#include "uhf_snmp_probe.h"
|
||||
|
||||
void seader_runtime_reset_cached_sam_metadata(
|
||||
uint8_t sam_version[2],
|
||||
char* uhf_status_label,
|
||||
size_t label_size,
|
||||
SeaderUhfSnmpProbe* probe);
|
||||
|
||||
bool seader_runtime_begin_uhf_probe(
|
||||
bool sam_present,
|
||||
SeaderModeRuntime* mode_runtime,
|
||||
SeaderHfSessionState hf_session_state,
|
||||
SeaderUhfSnmpProbe* probe);
|
||||
|
||||
void seader_runtime_finish_uhf_probe(SeaderModeRuntime* mode_runtime);
|
||||
|
||||
void seader_runtime_begin_hf_teardown(SeaderHfSessionState* hf_session_state);
|
||||
|
||||
void seader_runtime_finalize_hf_release(
|
||||
SeaderHfSessionState* hf_session_state,
|
||||
SeaderModeRuntime* mode_runtime);
|
||||
76
sam_api.c
76
sam_api.c
@@ -4,6 +4,8 @@
|
||||
#include "sam_key_label.h"
|
||||
#include "trace_log.h"
|
||||
#include "uhf_snmp_probe.h"
|
||||
#include "runtime_policy.h"
|
||||
#include "card_details_builder.h"
|
||||
#include "uhf_status_label.h"
|
||||
#include <toolbox/path.h>
|
||||
#include <toolbox/version.h>
|
||||
@@ -76,10 +78,11 @@ static void seader_reset_cached_sam_metadata(Seader* seader) {
|
||||
return;
|
||||
}
|
||||
|
||||
seader->sam_version[0] = 0U;
|
||||
seader->sam_version[1] = 0U;
|
||||
seader->uhf_status_label[0] = '\0';
|
||||
seader_uhf_snmp_probe_init(&seader->snmp_probe);
|
||||
seader_runtime_reset_cached_sam_metadata(
|
||||
seader->sam_version,
|
||||
seader->uhf_status_label,
|
||||
sizeof(seader->uhf_status_label),
|
||||
&seader->snmp_probe);
|
||||
}
|
||||
|
||||
static bool seader_snmp_probe_send_next_request(Seader* seader) {
|
||||
@@ -110,9 +113,7 @@ static void seader_snmp_probe_finish(Seader* seader) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(seader->mode_runtime == SeaderModeRuntimeUHF) {
|
||||
seader->mode_runtime = SeaderModeRuntimeNone;
|
||||
}
|
||||
seader_runtime_finish_uhf_probe(&seader->mode_runtime);
|
||||
seader_sam_set_state(seader, SeaderSamStateIdle, SeaderSamIntentNone, SamCommand_PR_NOTHING);
|
||||
}
|
||||
|
||||
@@ -121,8 +122,14 @@ static void seader_start_snmp_probe(Seader* seader) {
|
||||
return;
|
||||
}
|
||||
|
||||
seader->mode_runtime = SeaderModeRuntimeUHF;
|
||||
seader_uhf_snmp_probe_init(&seader->snmp_probe);
|
||||
if(!seader_runtime_begin_uhf_probe(
|
||||
seader->sam_present,
|
||||
&seader->mode_runtime,
|
||||
seader->hf_session_state,
|
||||
&seader->snmp_probe)) {
|
||||
seader_snmp_probe_finish(seader);
|
||||
return;
|
||||
}
|
||||
seader_update_uhf_status_label(seader);
|
||||
seader_sam_set_state(
|
||||
seader,
|
||||
@@ -1725,12 +1732,6 @@ NfcCommand seader_worker_card_detect(
|
||||
CardDetails_t cardDetails = {0};
|
||||
FURI_LOG_D(TAG, "Build card_detect sak=%02x uid_len=%u ats_len=%u", sak, uid_len, ats_len);
|
||||
|
||||
if(OCTET_STRING_fromBuf(&cardDetails.csn, (const char*)uid, uid_len) != 0) {
|
||||
FURI_LOG_E(TAG, "Failed to encode CSN");
|
||||
return NfcCommandStop;
|
||||
}
|
||||
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
|
||||
// so it doesn't really matter
|
||||
size_t diversifier_len = uid_len;
|
||||
@@ -1742,46 +1743,9 @@ NfcCommand seader_worker_card_detect(
|
||||
memcpy(credential->diversifier, uid, diversifier_len);
|
||||
credential->diversifier_len = diversifier_len;
|
||||
|
||||
if(ats != NULL) { // type 4
|
||||
protocol_bytes[1] = FrameProtocol_nfc;
|
||||
if(OCTET_STRING_fromBuf(
|
||||
&cardDetails.protocol, (const char*)protocol_bytes, sizeof(protocol_bytes)) != 0) {
|
||||
FURI_LOG_E(TAG, "Failed to encode 14A protocol");
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_CardDetails, &cardDetails);
|
||||
return NfcCommandStop;
|
||||
}
|
||||
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
|
||||
} 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) {
|
||||
FURI_LOG_E(TAG, "Failed to encode picopass protocol");
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_CardDetails, &cardDetails);
|
||||
return NfcCommandStop;
|
||||
}
|
||||
} else { // MFC
|
||||
protocol_bytes[1] = FrameProtocol_nfc;
|
||||
if(OCTET_STRING_fromBuf(
|
||||
&cardDetails.protocol, (const char*)protocol_bytes, sizeof(protocol_bytes)) != 0) {
|
||||
FURI_LOG_E(TAG, "Failed to encode MFC protocol");
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_CardDetails, &cardDetails);
|
||||
return NfcCommandStop;
|
||||
}
|
||||
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;
|
||||
}
|
||||
if(!seader_card_details_build(&cardDetails, sak, uid, uid_len, ats, ats_len)) {
|
||||
FURI_LOG_E(TAG, "Failed to build card details");
|
||||
return NfcCommandStop;
|
||||
}
|
||||
|
||||
seader_sam_set_state(
|
||||
@@ -1800,6 +1764,6 @@ NfcCommand seader_worker_card_detect(
|
||||
version_get_version(version),
|
||||
FAP_VERSION);
|
||||
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_CardDetails, &cardDetails);
|
||||
seader_card_details_reset(&cardDetails);
|
||||
return NfcCommandContinue;
|
||||
}
|
||||
|
||||
111
seader.c
111
seader.c
@@ -1,4 +1,6 @@
|
||||
#include "seader_i.h"
|
||||
#include "runtime_policy.h"
|
||||
#include "hf_release_sequence.h"
|
||||
#include "trace_log.h"
|
||||
|
||||
#define TAG "Seader"
|
||||
@@ -375,6 +377,60 @@ static void seader_hf_session_force_unloaded(Seader* seader) {
|
||||
}
|
||||
}
|
||||
|
||||
static void seader_hf_release_plugin_stop(void* context) {
|
||||
Seader* seader = context;
|
||||
if(seader && seader->plugin_hf && seader->hf_plugin_ctx) {
|
||||
seader->plugin_hf->stop(seader->hf_plugin_ctx);
|
||||
}
|
||||
}
|
||||
|
||||
static void seader_hf_release_host_poller(void* context) {
|
||||
Seader* seader = context;
|
||||
if(seader && seader->poller) {
|
||||
FURI_LOG_I(TAG, "Stopping host NFC poller");
|
||||
nfc_poller_stop(seader->poller);
|
||||
nfc_poller_free(seader->poller);
|
||||
seader->poller = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void seader_hf_release_host_picopass(void* context) {
|
||||
Seader* seader = context;
|
||||
if(seader && 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;
|
||||
}
|
||||
}
|
||||
|
||||
static void seader_hf_release_plugin_free(void* context) {
|
||||
Seader* seader = context;
|
||||
if(seader && seader->plugin_hf && seader->hf_plugin_ctx) {
|
||||
seader->plugin_hf->free(seader->hf_plugin_ctx);
|
||||
}
|
||||
if(seader) {
|
||||
seader->hf_plugin_ctx = NULL;
|
||||
seader->plugin_hf = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void seader_hf_release_plugin_manager(void* context) {
|
||||
Seader* seader = context;
|
||||
if(seader && seader->hf_plugin_manager) {
|
||||
FURI_LOG_I(TAG, "Unloading HF plugin");
|
||||
plugin_manager_free(seader->hf_plugin_manager);
|
||||
seader->hf_plugin_manager = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void seader_hf_release_worker_reset(void* context) {
|
||||
Seader* seader = context;
|
||||
if(seader && seader->worker) {
|
||||
seader_worker_reset_poller_session(seader->worker);
|
||||
}
|
||||
}
|
||||
|
||||
bool seader_custom_event_callback(void* context, uint32_t event) {
|
||||
furi_assert(context);
|
||||
Seader* seader = context;
|
||||
@@ -795,7 +851,7 @@ static void seader_hf_teardown_blocking(Seader* seader) {
|
||||
return;
|
||||
}
|
||||
|
||||
seader->hf_session_state = SeaderHfSessionStateTearingDown;
|
||||
seader_runtime_begin_hf_teardown(&seader->hf_session_state);
|
||||
if(!seader_worker_acquire(seader) || !seader->worker || !seader->uart) {
|
||||
FURI_LOG_W(TAG, "HF blocking teardown fallback");
|
||||
seader_hf_plugin_release(seader);
|
||||
@@ -810,47 +866,18 @@ static void seader_hf_teardown_blocking(Seader* seader) {
|
||||
|
||||
void seader_hf_plugin_release(Seader* seader) {
|
||||
furi_assert(seader);
|
||||
|
||||
seader->hf_session_state = SeaderHfSessionStateTearingDown;
|
||||
|
||||
if(seader->plugin_hf && seader->hf_plugin_ctx) {
|
||||
seader->plugin_hf->stop(seader->hf_plugin_ctx);
|
||||
}
|
||||
|
||||
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->plugin_hf && seader->hf_plugin_ctx) {
|
||||
seader->plugin_hf->free(seader->hf_plugin_ctx);
|
||||
}
|
||||
seader->hf_plugin_ctx = NULL;
|
||||
seader->plugin_hf = 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->worker) {
|
||||
seader_worker_reset_poller_session(seader->worker);
|
||||
}
|
||||
|
||||
if(seader->mode_runtime == SeaderModeRuntimeHF) {
|
||||
seader->mode_runtime = SeaderModeRuntimeNone;
|
||||
}
|
||||
seader->hf_session_state = SeaderHfSessionStateUnloaded;
|
||||
SeaderHfReleaseSequence release_sequence = {
|
||||
.context = seader,
|
||||
.hf_session_state = &seader->hf_session_state,
|
||||
.mode_runtime = &seader->mode_runtime,
|
||||
.plugin_stop = seader_hf_release_plugin_stop,
|
||||
.host_poller_release = seader_hf_release_host_poller,
|
||||
.host_picopass_release = seader_hf_release_host_picopass,
|
||||
.plugin_free = seader_hf_release_plugin_free,
|
||||
.plugin_manager_unload = seader_hf_release_plugin_manager,
|
||||
.worker_reset = seader_hf_release_worker_reset,
|
||||
};
|
||||
seader_hf_release_sequence_run(&release_sequence);
|
||||
}
|
||||
|
||||
bool seader_hf_finish_teardown_action(Seader* seader) {
|
||||
|
||||
Reference in New Issue
Block a user