diff --git a/Makefile b/Makefile index 0f62294..59aa89c 100644 --- a/Makefile +++ b/Makefile @@ -24,6 +24,7 @@ test-host: lib/host_tests/test_sam_startup_ui.c \ lib/host_tests/test_sam_key_label.c \ lib/host_tests/test_ccid_logic.c \ + lib/host_tests/test_uart_tx_logic.c \ lib/host_tests/test_t1_existing.c \ lib/host_tests/test_t1_protocol.c \ lib/host_tests/test_snmp.c \ @@ -40,6 +41,7 @@ test-host: board_power_lifecycle.c \ sam_startup_ui.c \ ccid_logic.c \ + uart_tx_logic.c \ allocation_policy.c \ worker_loop_policy.c \ credential_sio_label.c \ diff --git a/lib/host_tests/test_main.c b/lib/host_tests/test_main.c index 3ce337e..057675b 100644 --- a/lib/host_tests/test_main.c +++ b/lib/host_tests/test_main.c @@ -6,6 +6,7 @@ extern MunitSuite test_board_power_lifecycle_suite; extern MunitSuite test_hf_read_lifecycle_suite; extern MunitSuite test_sam_startup_ui_suite; extern MunitSuite test_ccid_logic_suite; +extern MunitSuite test_uart_tx_logic_suite; extern MunitSuite test_sam_key_label_suite; extern MunitSuite test_t1_existing_suite; extern MunitSuite test_t1_protocol_suite; @@ -40,6 +41,7 @@ int main(int argc, char* argv[]) { {"/t1", test_t1_existing_suite.tests, NULL, 1, MUNIT_SUITE_OPTION_NONE}, {"/t1", test_t1_protocol_suite.tests, NULL, 1, MUNIT_SUITE_OPTION_NONE}, {"/ccid", test_ccid_logic_suite.tests, NULL, 1, MUNIT_SUITE_OPTION_NONE}, + {"/uart-tx", test_uart_tx_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}, {"/credential-sio-label", test_credential_sio_label_suite.tests, NULL, 1, MUNIT_SUITE_OPTION_NONE}, diff --git a/lib/host_tests/test_uart_tx_logic.c b/lib/host_tests/test_uart_tx_logic.c new file mode 100644 index 0000000..d303b3d --- /dev/null +++ b/lib/host_tests/test_uart_tx_logic.c @@ -0,0 +1,114 @@ +#include + +#include "munit.h" +#include "uart_tx_logic.h" + +static MunitResult test_tx_frame_copy_rejects_invalid_inputs( + const MunitParameter params[], + void* fixture) { + (void)params; + (void)fixture; + + SeaderUartTxFrame frame = {0}; + const uint8_t data[] = {0x01U}; + + munit_assert_false(seader_uart_tx_frame_copy(NULL, data, sizeof(data), sizeof(data))); + munit_assert_false(seader_uart_tx_frame_copy(&frame, NULL, sizeof(data), sizeof(data))); + munit_assert_false(seader_uart_tx_frame_copy(&frame, data, 0U, sizeof(data))); + munit_assert_false(seader_uart_tx_frame_copy(&frame, data, sizeof(data), 0U)); + return MUNIT_OK; +} + +static MunitResult test_tx_frame_copy_preserves_frame_bytes( + const MunitParameter params[], + void* fixture) { + (void)params; + (void)fixture; + + SeaderUartTxFrame frame = {0}; + const uint8_t data[] = {0x01U, 0x02U, 0x03U}; + + munit_assert_true(seader_uart_tx_frame_copy(&frame, data, sizeof(data), sizeof(frame.data))); + munit_assert_size(frame.len, ==, sizeof(data)); + munit_assert_memory_equal(sizeof(data), frame.data, data); + return MUNIT_OK; +} + +static MunitResult test_tx_frame_copy_is_immutable_after_source_reuse( + const MunitParameter params[], + void* fixture) { + (void)params; + (void)fixture; + + SeaderUartTxFrame frame = {0}; + uint8_t scratch[] = {0xAAU, 0xBBU, 0xCCU}; + const uint8_t expected[] = {0xAAU, 0xBBU, 0xCCU}; + + munit_assert_true( + seader_uart_tx_frame_copy(&frame, scratch, sizeof(scratch), sizeof(frame.data))); + memset(scratch, 0x11, sizeof(scratch)); + + munit_assert_size(frame.len, ==, sizeof(expected)); + munit_assert_memory_equal(sizeof(expected), frame.data, expected); + return MUNIT_OK; +} + +static MunitResult test_back_to_back_copies_preserve_distinct_frames( + const MunitParameter params[], + void* fixture) { + (void)params; + (void)fixture; + + SeaderUartTxFrame first = {0}; + SeaderUartTxFrame second = {0}; + uint8_t scratch[] = {0x10U, 0x20U}; + const uint8_t first_expected[] = {0x10U, 0x20U}; + const uint8_t second_expected[] = {0x30U, 0x40U}; + + munit_assert_true( + seader_uart_tx_frame_copy(&first, scratch, sizeof(scratch), sizeof(first.data))); + scratch[0] = 0x30U; + scratch[1] = 0x40U; + munit_assert_true( + seader_uart_tx_frame_copy(&second, scratch, sizeof(scratch), sizeof(second.data))); + + munit_assert_memory_equal(sizeof(first_expected), first.data, first_expected); + munit_assert_memory_equal(sizeof(second_expected), second.data, second_expected); + return MUNIT_OK; +} + +static MunitTest test_uart_tx_logic_cases[] = { + {(char*)"/copy/rejects-invalid", + test_tx_frame_copy_rejects_invalid_inputs, + NULL, + NULL, + MUNIT_TEST_OPTION_NONE, + NULL}, + {(char*)"/copy/preserves-bytes", + test_tx_frame_copy_preserves_frame_bytes, + NULL, + NULL, + MUNIT_TEST_OPTION_NONE, + NULL}, + {(char*)"/copy/immutable-after-source-reuse", + test_tx_frame_copy_is_immutable_after_source_reuse, + NULL, + NULL, + MUNIT_TEST_OPTION_NONE, + NULL}, + {(char*)"/copy/back-to-back-distinct", + test_back_to_back_copies_preserve_distinct_frames, + NULL, + NULL, + MUNIT_TEST_OPTION_NONE, + NULL}, + {NULL, NULL, NULL, NULL, 0, NULL}, +}; + +MunitSuite test_uart_tx_logic_suite = { + "", + test_uart_tx_logic_cases, + NULL, + 1, + MUNIT_SUITE_OPTION_NONE, +}; diff --git a/uart_tx_logic.c b/uart_tx_logic.c new file mode 100644 index 0000000..ca437d7 --- /dev/null +++ b/uart_tx_logic.c @@ -0,0 +1,17 @@ +#include "uart_tx_logic.h" + +#include + +bool seader_uart_tx_frame_copy( + SeaderUartTxFrame* out, + const uint8_t* data, + size_t len, + size_t max_len) { + if(!out || !data || len == 0U || len > max_len || len > sizeof(out->data)) { + return false; + } + + out->len = len; + memcpy(out->data, data, len); + return true; +} diff --git a/uart_tx_logic.h b/uart_tx_logic.h new file mode 100644 index 0000000..1721a98 --- /dev/null +++ b/uart_tx_logic.h @@ -0,0 +1,18 @@ +#pragma once + +#include +#include +#include + +#define SEADER_UART_TX_FRAME_MAX_SIZE (272U) + +typedef struct { + size_t len; + uint8_t data[SEADER_UART_TX_FRAME_MAX_SIZE]; +} SeaderUartTxFrame; + +bool seader_uart_tx_frame_copy( + SeaderUartTxFrame* out, + const uint8_t* data, + size_t len, + size_t max_len);