diff --git a/.clang-format b/.clang-format index 924516e13..2cd0e1554 100644 --- a/.clang-format +++ b/.clang-format @@ -84,6 +84,7 @@ MaxEmptyLinesToKeep: 2 NamespaceIndentation: All PenaltyBreakBeforeFirstCallParameter: 1000000 PenaltyBreakOpenParenthesis: 1000000 +PPIndentWidth: 2 QualifierAlignment: Custom QualifierOrder: ['static', 'const', 'volatile', 'restrict', 'type'] SpaceAfterTemplateKeyword: false diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index a3e89bbc2..ef2344801 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -85,7 +85,7 @@ bool tu_fifo_config(tu_fifo_t *f, void *buffer, uint16_t depth, uint16_t item_si // Pull & Push //--------------------------------------------------------------------+ -#ifdef TUP_MEM_CONST_ADDR +#ifdef CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32 // Intended to be used to read from hardware USB FIFO in e.g. STM32 where all data is read from a constant address // Code adapted from dcd_synopsys.c // TODO generalize with configurable 1 byte or 4 byte each read @@ -164,7 +164,7 @@ static void _ff_push_n(tu_fifo_t *f, const void *app_buf, uint16_t n, uint16_t w } break; -#ifdef TUP_MEM_CONST_ADDR +#ifdef CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32 case TU_FIFO_FIXED_ADDR_RW32: // Intended for hardware buffers from which it can be read word by word only if (n <= lin_count) { @@ -244,7 +244,7 @@ static void _ff_pull_n(tu_fifo_t *f, void *app_buf, uint16_t n, uint16_t rd_ptr, } break; -#ifdef TUP_MEM_CONST_ADDR +#ifdef CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32 case TU_FIFO_FIXED_ADDR_RW32: if (n <= lin_count) { // Linear only diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h index 002cd3a0e..34977378c 100644 --- a/src/common/tusb_mcu.h +++ b/src/common/tusb_mcu.h @@ -24,8 +24,7 @@ * This file is part of the TinyUSB stack. */ -#ifndef TUSB_MCU_H_ -#define TUSB_MCU_H_ +#pragma once //--------------------------------------------------------------------+ // Port/Platform Specific @@ -697,9 +696,3 @@ #ifndef TUP_DCD_EDPT_CLOSE_API #define TUP_DCD_EDPT_ISO_ALLOC #endif - -#if defined(TUP_USBIP_DWC2) // && CFG_TUD_DWC2_DMA_ENABLE == 0 - #define TUP_MEM_CONST_ADDR -#endif - -#endif diff --git a/src/tusb_option.h b/src/tusb_option.h index dd5f17dfc..e2eaecd2d 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -24,8 +24,7 @@ * This file is part of the TinyUSB stack. */ -#ifndef TUSB_OPTION_H_ -#define TUSB_OPTION_H_ +#pragma once #include "common/tusb_compiler.h" @@ -305,15 +304,26 @@ #define CFG_TUH_DWC2_DMA_ENABLE CFG_TUH_DWC2_DMA_ENABLE_DEFAULT #endif -#if defined(TUP_USBIP_DWC2) && CFG_TUD_DWC2_SLAVE_ENABLE == 1 -#define TUP_DCD_EDPT_DEDICATED_FIFO +#if defined(TUP_USBIP_DWC2) + #if CFG_TUD_DWC2_SLAVE_ENABLE + #define CFG_TUD_EDPT_DEDICATED_FIFO + #endif + + #if CFG_TUD_DWC2_SLAVE_ENABLE + #define CFG_TUH_EDPT_DEDICATED_FIFO + #endif +#endif + +#if defined(CFG_TUD_EDPT_DEDICATED_FIFO) || defined(CFG_TUH_EDPT_DEDICATED_FIFO) + #define CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32 #endif //------------- ChipIdea -------------// -// Enable CI_HS VBUS Charge. Set this to 1 if the USB_VBUS pin is not connected to 5V VBUS (note: 3.3V is insufficient). +// Enable CI_HS VBUS Charge. Set this to 1 if the USB_VBUS pin is not connected to 5V VBUS (note: 3.3V is +// insufficient). #ifndef CFG_TUD_CI_HS_VBUS_CHARGE #ifndef CFG_TUD_CI_HS_VBUS_CHARGE_DEFAULT - #define CFG_TUD_CI_HS_VBUS_CHARGE_DEFAULT 0 + #define CFG_TUD_CI_HS_VBUS_CHARGE_DEFAULT 0 #endif #define CFG_TUD_CI_HS_VBUS_CHARGE CFG_TUD_CI_HS_VBUS_CHARGE_DEFAULT @@ -738,7 +748,3 @@ // To avoid GCC compiler warnings when -pedantic option is used (strict ISO C) typedef int make_iso_compilers_happy; - -#endif /* TUSB_OPTION_H_ */ - -/** @} */ diff --git a/test/unit-test/CMakeLists.txt b/test/unit-test/CMakeLists.txt new file mode 100644 index 000000000..7172f5575 --- /dev/null +++ b/test/unit-test/CMakeLists.txt @@ -0,0 +1,132 @@ +cmake_minimum_required(VERSION 3.20) + +project(tinyusb_unit_tests LANGUAGES C) + +set(CMAKE_C_STANDARD 99) +set(CMAKE_C_STANDARD_REQUIRED ON) +set(CMAKE_C_EXTENSIONS ON) + +# Command to invoke Ceedling. Supports multi-word commands such as "bundle exec ceedling". +set(CEEDLING_COMMAND "ceedling" CACHE STRING "Command used to invoke Ceedling (Ruby gem).") +separate_arguments(CEEDLING_COMMAND_LIST NATIVE_COMMAND "${CEEDLING_COMMAND}") +if (CEEDLING_COMMAND_LIST STREQUAL "") + message(FATAL_ERROR "CEEDLING_COMMAND is empty; set it to a valid Ceedling invocation.") +endif () + +list(GET CEEDLING_COMMAND_LIST 0 CEEDLING_LAUNCHER) +find_program(CEEDLING_LAUNCHER_PATH NAMES ${CEEDLING_LAUNCHER}) +if (NOT CEEDLING_LAUNCHER_PATH) + message(FATAL_ERROR "Could not find '${CEEDLING_LAUNCHER}' on PATH; adjust CEEDLING_COMMAND or PATH.") +endif () +list(REMOVE_AT CEEDLING_COMMAND_LIST 0) +list(INSERT CEEDLING_COMMAND_LIST 0 ${CEEDLING_LAUNCHER_PATH}) + +set(CEEDLING_WORKDIR ${CMAKE_CURRENT_LIST_DIR}) +set(CEEDLING_BUILD_DIR ${CEEDLING_WORKDIR}/_build) + +# Helper to add a Ceedling-backed test target that compiles into a real CMake executable. +function(add_ceedling_test TARGET_NAME TEST_SOURCE PRODUCT_SOURCES MOCK_SOURCES) + set(runner ${CEEDLING_BUILD_DIR}/test/runners/${TARGET_NAME}_runner.c) + + add_custom_target(ceedling_gen_${TARGET_NAME} + COMMAND ${CEEDLING_COMMAND_LIST} test:${TARGET_NAME} + WORKING_DIRECTORY ${CEEDLING_WORKDIR} + BYPRODUCTS ${runner} + USES_TERMINAL + COMMENT "Generate Ceedling runner/mocks for ${TARGET_NAME}" + ) + + add_executable(${TARGET_NAME} + ${TEST_SOURCE} + ${runner} + ${MOCK_SOURCES} + ${CEEDLING_BUILD_DIR}/vendor/unity/src/unity.c + ${CEEDLING_BUILD_DIR}/vendor/cmock/src/cmock.c + ${PRODUCT_SOURCES} + ) + + set_source_files_properties( + ${runner} + ${MOCK_SOURCES} + ${CEEDLING_BUILD_DIR}/vendor/unity/src/unity.c + ${CEEDLING_BUILD_DIR}/vendor/cmock/src/cmock.c + PROPERTIES GENERATED TRUE + ) + + add_dependencies(${TARGET_NAME} ceedling_gen_${TARGET_NAME}) + + target_include_directories(${TARGET_NAME} PRIVATE + ${CEEDLING_WORKDIR}/test + ${CEEDLING_WORKDIR}/test/support + ${CEEDLING_BUILD_DIR}/test/runners + ${CEEDLING_BUILD_DIR}/test/mocks/${TARGET_NAME} + ${CEEDLING_BUILD_DIR}/vendor/unity/src + ${CEEDLING_BUILD_DIR}/vendor/cmock/src + ${CEEDLING_WORKDIR}/../../src + ${CEEDLING_WORKDIR}/../../src/common + ${CEEDLING_WORKDIR}/../../src/device + ${CEEDLING_WORKDIR}/../../src/class + ${CEEDLING_WORKDIR}/../../src/class/msc + ${CEEDLING_WORKDIR}/../../src/host + ${CEEDLING_WORKDIR}/../../src/typec + ${CEEDLING_WORKDIR}/../../src/osal + ) + + target_compile_definitions(${TARGET_NAME} PRIVATE _UNITY_TEST_) + target_compile_options(${TARGET_NAME} PRIVATE -Wall -Wextra) + add_test(NAME ${TARGET_NAME} COMMAND ${TARGET_NAME}) +endfunction() + +# Custom targets to keep plain Ceedling entry-points available. +add_custom_target(ceedling_all + COMMAND ${CEEDLING_COMMAND_LIST} test:all + WORKING_DIRECTORY ${CEEDLING_WORKDIR} + USES_TERMINAL + COMMENT "Run Ceedling (Unity) unit tests" + ) + +add_custom_target(ceedling_clean + COMMAND ${CEEDLING_COMMAND_LIST} clean + WORKING_DIRECTORY ${CEEDLING_WORKDIR} + USES_TERMINAL + COMMENT "Clean Ceedling build outputs" + ) + +add_custom_target(ceedling_clobber + COMMAND ${CEEDLING_COMMAND_LIST} clobber + WORKING_DIRECTORY ${CEEDLING_WORKDIR} + USES_TERMINAL + COMMENT "Clobber Ceedling build outputs" + ) + +# Per-test wiring: mocks are generated under _build/test/mocks//. +add_ceedling_test( + test_common_func + ${CEEDLING_WORKDIR}/test/test_common_func.c + "" + "" + ) + +add_ceedling_test( + test_fifo + ${CEEDLING_WORKDIR}/test/test_fifo.c + ${CEEDLING_WORKDIR}/../../src/common/tusb_fifo.c + "" + ) +target_compile_definitions(test_fifo PRIVATE CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32=1) + +add_ceedling_test( + test_usbd + ${CEEDLING_WORKDIR}/test/device/usbd/test_usbd.c + "${CEEDLING_WORKDIR}/../../src/tusb.c;${CEEDLING_WORKDIR}/../../src/device/usbd.c;${CEEDLING_WORKDIR}/../../src/device/usbd_control.c;${CEEDLING_WORKDIR}/../../src/common/tusb_fifo.c" + "${CEEDLING_BUILD_DIR}/test/mocks/test_usbd/mock_dcd.c;${CEEDLING_BUILD_DIR}/test/mocks/test_usbd/mock_msc_device.c" + ) + +add_ceedling_test( + test_msc_device + ${CEEDLING_WORKDIR}/test/device/msc/test_msc_device.c + "${CEEDLING_WORKDIR}/../../src/tusb.c;${CEEDLING_WORKDIR}/../../src/device/usbd.c;${CEEDLING_WORKDIR}/../../src/device/usbd_control.c;${CEEDLING_WORKDIR}/../../src/class/msc/msc_device.c;${CEEDLING_WORKDIR}/../../src/common/tusb_fifo.c" + "${CEEDLING_BUILD_DIR}/test/mocks/test_msc_device/mock_dcd.c" + ) + +enable_testing() diff --git a/test/unit-test/project.yml b/test/unit-test/project.yml index 6c86b0205..d971d098d 100644 --- a/test/unit-test/project.yml +++ b/test/unit-test/project.yml @@ -128,6 +128,7 @@ :defines: :test: - _UNITY_TEST_ + - CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32 :release: [] # Enable to inject name of a test as a unique compilation symbol into its respective executable build. diff --git a/test/unit-test/test/test_fifo.c b/test/unit-test/test/test_fifo.c index 3b4deb33e..83db10454 100644 --- a/test/unit-test/test/test_fifo.c +++ b/test/unit-test/test/test_fifo.c @@ -30,51 +30,52 @@ #include "osal/osal.h" #include "tusb_fifo.h" -#define FIFO_SIZE 64 -uint8_t tu_ff_buf[FIFO_SIZE * sizeof(uint8_t)]; +#define FIFO_SIZE 64 +uint8_t tu_ff_buf[FIFO_SIZE * sizeof(uint8_t)]; tu_fifo_t tu_ff = TU_FIFO_INIT(tu_ff_buf, FIFO_SIZE, uint8_t, false); -tu_fifo_t* ff = &tu_ff; +tu_fifo_t *ff = &tu_ff; tu_fifo_buffer_info_t info; uint8_t test_data[4096]; uint8_t rd_buf[FIFO_SIZE]; -void setUp(void) -{ +void setUp(void) { tu_fifo_clear(ff); memset(&info, 0, sizeof(tu_fifo_buffer_info_t)); - for(int i=0; i 4 rd_count = tu_fifo_read_n(&ff4, rd_buf4, 5); - TEST_ASSERT_EQUAL( 5, rd_count ); - TEST_ASSERT_EQUAL_UINT32_ARRAY( data4, rd_buf4, rd_count ); // 0 -> 4 + TEST_ASSERT_EQUAL(5, rd_count); + TEST_ASSERT_EQUAL_UINT32_ARRAY(data4, rd_buf4, rd_count); // 0 -> 4 - tu_fifo_write_n(&ff4, data4+FIFO_SIZE, 5); + tu_fifo_write_n(&ff4, data4 + FIFO_SIZE, 5); // read all 5 -> 68 rd_count = tu_fifo_read_n(&ff4, rd_buf4, FIFO_SIZE); - TEST_ASSERT_EQUAL( FIFO_SIZE, rd_count ); - TEST_ASSERT_EQUAL_UINT32_ARRAY( data4+5, rd_buf4, rd_count ); // 5 -> 68 + TEST_ASSERT_EQUAL(FIFO_SIZE, rd_count); + TEST_ASSERT_EQUAL_UINT32_ARRAY(data4 + 5, rd_buf4, rd_count); // 5 -> 68 } -void test_read_n(void) -{ +void test_read_n(void) { uint16_t rd_count; // fill up fifo - for(uint8_t i=0; i < FIFO_SIZE; i++) tu_fifo_write(ff, test_data+i); + for (uint8_t i = 0; i < FIFO_SIZE; i++) { + tu_fifo_write(ff, test_data + i); + } // case 1: Read index + count < depth // read 0 -> 4 rd_count = tu_fifo_read_n(ff, rd_buf, 5); - TEST_ASSERT_EQUAL( 5, rd_count ); - TEST_ASSERT_EQUAL_MEMORY( test_data, rd_buf, rd_count ); // 0 -> 4 + TEST_ASSERT_EQUAL(5, rd_count); + TEST_ASSERT_EQUAL_MEMORY(test_data, rd_buf, rd_count); // 0 -> 4 // case 2: Read index + count > depth // write 10, 11, 12 - tu_fifo_write(ff, test_data+FIFO_SIZE); - tu_fifo_write(ff, test_data+FIFO_SIZE+1); - tu_fifo_write(ff, test_data+FIFO_SIZE+2); + tu_fifo_write(ff, test_data + FIFO_SIZE); + tu_fifo_write(ff, test_data + FIFO_SIZE + 1); + tu_fifo_write(ff, test_data + FIFO_SIZE + 2); rd_count = tu_fifo_read_n(ff, rd_buf, 7); - TEST_ASSERT_EQUAL( 7, rd_count ); + TEST_ASSERT_EQUAL(7, rd_count); - TEST_ASSERT_EQUAL_MEMORY( test_data+5, rd_buf, rd_count ); // 5 -> 11 + TEST_ASSERT_EQUAL_MEMORY(test_data + 5, rd_buf, rd_count); // 5 -> 11 // Should only read until empty - TEST_ASSERT_EQUAL( FIFO_SIZE-5+3-7, tu_fifo_read_n(ff, rd_buf, 100) ); + TEST_ASSERT_EQUAL(FIFO_SIZE - 5 + 3 - 7, tu_fifo_read_n(ff, rd_buf, 100)); } -void test_write_n(void) -{ +void test_write_n(void) { // case 1: wr + count < depth tu_fifo_write_n(ff, test_data, 32); // wr = 32, count = 32 uint16_t rd_count; rd_count = tu_fifo_read_n(ff, rd_buf, 16); // wr = 32, count = 16 - TEST_ASSERT_EQUAL( 16, rd_count ); - TEST_ASSERT_EQUAL_MEMORY( test_data, rd_buf, rd_count ); + TEST_ASSERT_EQUAL(16, rd_count); + TEST_ASSERT_EQUAL_MEMORY(test_data, rd_buf, rd_count); // case 2: wr + count > depth - tu_fifo_write_n(ff, test_data+32, 40); // wr = 72 -> 8, count = 56 + tu_fifo_write_n(ff, test_data + 32, 40); // wr = 72 -> 8, count = 56 - tu_fifo_read_n(ff, rd_buf, 32); // count = 24 - TEST_ASSERT_EQUAL_MEMORY( test_data+16, rd_buf, rd_count); + tu_fifo_read_n(ff, rd_buf, 32); // count = 24 + TEST_ASSERT_EQUAL_MEMORY(test_data + 16, rd_buf, rd_count); TEST_ASSERT_EQUAL(24, tu_fifo_count(ff)); } -void test_write_double_overflowed(void) -{ +void test_write_double_overflowed(void) { tu_fifo_set_overwritable(ff, true); - uint8_t rd_buf[FIFO_SIZE] = { 0 }; - uint8_t* buf = test_data; + uint8_t rd_buf[FIFO_SIZE] = {0}; + uint8_t *buf = test_data; // full buf += tu_fifo_write_n(ff, buf, FIFO_SIZE); TEST_ASSERT_EQUAL(FIFO_SIZE, tu_fifo_count(ff)); // write more, should still full - buf += tu_fifo_write_n(ff, buf, FIFO_SIZE-8); + buf += tu_fifo_write_n(ff, buf, FIFO_SIZE - 8); TEST_ASSERT_EQUAL(FIFO_SIZE, tu_fifo_count(ff)); // double overflowed: in total, write more than > 2*FIFO_SIZE @@ -165,14 +165,13 @@ void test_write_double_overflowed(void) // reading back should give back data from last FIFO_SIZE write tu_fifo_read_n(ff, rd_buf, FIFO_SIZE); - TEST_ASSERT_EQUAL_MEMORY(buf-16, rd_buf+FIFO_SIZE-16, 16); + TEST_ASSERT_EQUAL_MEMORY(buf - 16, rd_buf + FIFO_SIZE - 16, 16); // TODO whole buffer should match, but we deliberately not implement it // TEST_ASSERT_EQUAL_MEMORY(buf-FIFO_SIZE, rd_buf, FIFO_SIZE); } -static uint16_t help_write(uint16_t total, uint16_t n) -{ +static uint16_t help_write(uint16_t total, uint16_t n) { tu_fifo_write_n(ff, test_data, n); total = tu_min16(FIFO_SIZE, total + n); @@ -182,12 +181,11 @@ static uint16_t help_write(uint16_t total, uint16_t n) return total; } -void test_write_overwritable2(void) -{ - tu_fifo_set_overwritable(ff, true); +void test_write_overwritable2(void) { +tu_fifo_set_overwritable(ff, true); - // based on actual crash tests detected by fuzzing - uint16_t total = 0; +// based on actual crash tests detected by fuzzing +uint16_t total = 0; total = help_write(total, 12); total = help_write(total, 55); @@ -202,13 +200,15 @@ void test_write_overwritable2(void) total = help_write(total, 192); } -void test_peek(void) -{ +void test_peek(void) { uint8_t temp; - temp = 10; tu_fifo_write(ff, &temp); - temp = 20; tu_fifo_write(ff, &temp); - temp = 30; tu_fifo_write(ff, &temp); + temp = 10; + tu_fifo_write(ff, &temp); + temp = 20; + tu_fifo_write(ff, &temp); + temp = 30; + tu_fifo_write(ff, &temp); temp = 0; @@ -222,12 +222,13 @@ void test_peek(void) TEST_ASSERT_EQUAL(30, temp); } -void test_get_read_info_when_no_wrap() -{ +void test_get_read_info_when_no_wrap() { uint8_t ch = 1; // write 6 items - for(uint8_t i=0; i < 6; i++) tu_fifo_write(ff, &ch); + for (uint8_t i = 0; i < 6; i++) { + tu_fifo_write(ff, &ch); + } // read 2 items tu_fifo_read(ff, &ch); @@ -238,19 +239,22 @@ void test_get_read_info_when_no_wrap() TEST_ASSERT_EQUAL(4, info.len_lin); TEST_ASSERT_EQUAL(0, info.len_wrap); - TEST_ASSERT_EQUAL_PTR(ff->buffer+2, info.ptr_lin); + TEST_ASSERT_EQUAL_PTR(ff->buffer + 2, info.ptr_lin); TEST_ASSERT_NULL(info.ptr_wrap); } -void test_get_read_info_when_wrapped() -{ +void test_get_read_info_when_wrapped() { uint8_t ch = 1; // make fifo full - for(uint8_t i=0; i < FIFO_SIZE; i++) tu_fifo_write(ff, &ch); + for (uint8_t i = 0; i < FIFO_SIZE; i++) { + tu_fifo_write(ff, &ch); + } // read 6 items - for(uint8_t i=0; i < 6; i++) tu_fifo_read(ff, &ch); + for (uint8_t i = 0; i < 6; i++) { + tu_fifo_read(ff, &ch); + } // write 2 items tu_fifo_write(ff, &ch); @@ -258,15 +262,14 @@ void test_get_read_info_when_wrapped() tu_fifo_get_read_info(ff, &info); - TEST_ASSERT_EQUAL(FIFO_SIZE-6, info.len_lin); + TEST_ASSERT_EQUAL(FIFO_SIZE - 6, info.len_lin); TEST_ASSERT_EQUAL(2, info.len_wrap); - TEST_ASSERT_EQUAL_PTR(ff->buffer+6, info.ptr_lin); + TEST_ASSERT_EQUAL_PTR(ff->buffer + 6, info.ptr_lin); TEST_ASSERT_EQUAL_PTR(ff->buffer, info.ptr_wrap); } -void test_get_write_info_when_no_wrap() -{ +void test_get_write_info_when_no_wrap() { uint8_t ch = 1; // write 2 items @@ -275,20 +278,21 @@ void test_get_write_info_when_no_wrap() tu_fifo_get_write_info(ff, &info); - TEST_ASSERT_EQUAL(FIFO_SIZE-2, info.len_lin); + TEST_ASSERT_EQUAL(FIFO_SIZE - 2, info.len_lin); TEST_ASSERT_EQUAL(0, info.len_wrap); - TEST_ASSERT_EQUAL_PTR(ff->buffer+2, info .ptr_lin); + TEST_ASSERT_EQUAL_PTR(ff->buffer + 2, info.ptr_lin); // application should check len instead of ptr. // TEST_ASSERT_NULL(info.ptr_wrap); } -void test_get_write_info_when_wrapped() -{ +void test_get_write_info_when_wrapped() { uint8_t ch = 1; // write 6 items - for(uint8_t i=0; i < 6; i++) tu_fifo_write(ff, &ch); + for (uint8_t i = 0; i < 6; i++) { + tu_fifo_write(ff, &ch); + } // read 2 items tu_fifo_read(ff, &ch); @@ -296,15 +300,14 @@ void test_get_write_info_when_wrapped() tu_fifo_get_write_info(ff, &info); - TEST_ASSERT_EQUAL(FIFO_SIZE-6, info.len_lin); + TEST_ASSERT_EQUAL(FIFO_SIZE - 6, info.len_lin); TEST_ASSERT_EQUAL(2, info.len_wrap); - TEST_ASSERT_EQUAL_PTR(ff->buffer+6, info .ptr_lin); + TEST_ASSERT_EQUAL_PTR(ff->buffer + 6, info.ptr_lin); TEST_ASSERT_EQUAL_PTR(ff->buffer, info.ptr_wrap); } -void test_empty(void) -{ +void test_empty(void) { uint8_t temp; TEST_ASSERT_TRUE(tu_fifo_empty(ff)); @@ -323,7 +326,7 @@ void test_empty(void) TEST_ASSERT_EQUAL(FIFO_SIZE, info.len_lin); TEST_ASSERT_EQUAL(0, info.len_wrap); - TEST_ASSERT_EQUAL_PTR(ff->buffer, info .ptr_lin); + TEST_ASSERT_EQUAL_PTR(ff->buffer, info.ptr_lin); // application should check len instead of ptr. // TEST_ASSERT_NULL(info.ptr_wrap); @@ -332,11 +335,12 @@ void test_empty(void) TEST_ASSERT_FALSE(tu_fifo_empty(ff)); } -void test_full(void) -{ +void test_full(void) { TEST_ASSERT_FALSE(tu_fifo_full(ff)); - for(uint8_t i=0; i < FIFO_SIZE; i++) tu_fifo_write(ff, &i); + for (uint8_t i = 0; i < FIFO_SIZE; i++) { + tu_fifo_write(ff, &i); + } TEST_ASSERT_TRUE(tu_fifo_full(ff)); @@ -353,11 +357,10 @@ void test_full(void) // write info } -void test_rd_idx_wrap() -{ +void test_rd_idx_wrap(void) { tu_fifo_t ff10; - uint8_t buf[10]; - uint8_t dst[10]; + uint8_t buf[10]; + uint8_t dst[10]; tu_fifo_config(&ff10, buf, 10, 1, 1); @@ -376,3 +379,187 @@ void test_rd_idx_wrap() TEST_ASSERT_EQUAL(n, 2); TEST_ASSERT_EQUAL(ff10.rd_idx, 6); } + +void test_advance_write_pointer_cases(void) { + tu_fifo_clear(ff); + + tu_fifo_advance_write_pointer(ff, 3); + TEST_ASSERT_EQUAL(3, ff->wr_idx); + TEST_ASSERT_EQUAL(3, tu_fifo_count(ff)); + + // advance to cross depth but stay within 0..2*depth window + ff->wr_idx = FIFO_SIZE - 2; // 62 + ff->rd_idx = 0; + tu_fifo_advance_write_pointer(ff, 10); // 62 + 10 = 72 within window + TEST_ASSERT_EQUAL(72, ff->wr_idx); + TEST_ASSERT_EQUAL(FIFO_SIZE, tu_fifo_count(ff)); + + // advance past the unused index space (beyond 2*depth) + ff->wr_idx = (uint16_t)(2 * FIFO_SIZE - 3); // 125 + ff->rd_idx = 0; + tu_fifo_advance_write_pointer(ff, 6); // forces wrap across unused space + TEST_ASSERT_EQUAL(3, ff->wr_idx); + TEST_ASSERT_EQUAL(3, tu_fifo_count(ff)); +} + +void test_advance_read_pointer_cases(void) { + tu_fifo_clear(ff); + + ff->wr_idx = 6; + tu_fifo_advance_read_pointer(ff, 3); + TEST_ASSERT_EQUAL(3, ff->rd_idx); + TEST_ASSERT_EQUAL(3, tu_fifo_count(ff)); + + ff->wr_idx = FIFO_SIZE + 10; // 74 + ff->rd_idx = FIFO_SIZE - 10; // 54 + tu_fifo_advance_read_pointer(ff, 20); // move to match write index within window + TEST_ASSERT_EQUAL(74, ff->rd_idx); + TEST_ASSERT_EQUAL(0, tu_fifo_count(ff)); + + ff->wr_idx = 9; + ff->rd_idx = (uint16_t)(2 * FIFO_SIZE - 1); // 127 + tu_fifo_advance_read_pointer(ff, 6); // crosses unused index space + TEST_ASSERT_EQUAL(5, ff->rd_idx); + TEST_ASSERT_EQUAL(4, tu_fifo_count(ff)); +} + +void test_write_n_fixed_addr_rw32_nowrap(void) { + tu_fifo_clear(ff); + + volatile uint32_t reg = 0x11223344; + uint8_t expected[8] = {0x44, 0x33, 0x22, 0x11, 0x44, 0x33, 0x22, 0x11}; + + for (uint8_t n = 1; n <= 8; n++) { + tu_fifo_clear(ff); + uint16_t written = tu_fifo_write_n_access(ff, (const void *)®, n, TU_FIFO_FIXED_ADDR_RW32); + TEST_ASSERT_EQUAL(n, written); + TEST_ASSERT_EQUAL(n, tu_fifo_count(ff)); + + uint8_t out[8] = {0}; + tu_fifo_read_n(ff, out, n); + TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, out, n); + } +} + +void test_write_n_fixed_addr_rw32_wrapped(void) { + tu_fifo_clear(ff); + + volatile uint32_t reg = 0xA1B2C3D4; + uint8_t expected[8] = {0xD4, 0xC3, 0xB2, 0xA1, 0xD4, 0xC3, 0xB2, 0xA1}; + + for (uint8_t n = 1; n <= 8; n++) { + tu_fifo_clear(ff); + // Position the fifo near the end so writes wrap + ff->wr_idx = FIFO_SIZE - 3; + ff->rd_idx = FIFO_SIZE - 3; + + uint16_t written = tu_fifo_write_n_access(ff, (const void *)®, n, TU_FIFO_FIXED_ADDR_RW32); + TEST_ASSERT_EQUAL(n, written); + TEST_ASSERT_EQUAL(n, tu_fifo_count(ff)); + + uint8_t out[8] = {0}; + tu_fifo_read_n(ff, out, n); + TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, out, n); + } +} + +void test_read_n_fixed_addr_rw32_nowrap(void) { + uint8_t pattern[8] = {0x10, 0x21, 0x32, 0x43, 0x54, 0x65, 0x76, 0x87}; + uint32_t reg_expected[8] = { + 0x00000010, 0x00002110, 0x00322110, 0x43322110, 0x00000054, 0x00006554, 0x00766554, 0x87766554}; + + for (uint8_t n = 1; n <= 8; n++) { + tu_fifo_clear(ff); + tu_fifo_write_n(ff, pattern, 8); + + uint32_t reg = 0; + uint16_t read_cnt = tu_fifo_read_n_access(ff, ®, n, TU_FIFO_FIXED_ADDR_RW32); + TEST_ASSERT_EQUAL(n, read_cnt); + TEST_ASSERT_EQUAL(8 - n, tu_fifo_count(ff)); + + TEST_ASSERT_EQUAL_HEX32(reg_expected[n - 1], reg); + } +} + +void test_read_n_fixed_addr_rw32_wrapped(void) { + uint8_t pattern[8] = {0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5, 0x96, 0x87}; + uint32_t reg_expected[8] = { + 0x000000F0, 0x0000E1F0, 0x00D2E1F0, 0xC3D2E1F0, 0x000000B4, 0x0000A5B4, 0x0096A5B4, 0x8796A5B4}; + + for (uint8_t n = 1; n <= 8; n++) { + tu_fifo_clear(ff); + ff->rd_idx = FIFO_SIZE - 2; + ff->wr_idx = (uint16_t)(ff->rd_idx + n); + + for (uint8_t i = 0; i < n; i++) { + uint8_t idx = (uint8_t)((ff->rd_idx + i) % FIFO_SIZE); + ff->buffer[idx] = pattern[i]; + } + + uint32_t reg = 0; + uint16_t read_cnt = tu_fifo_read_n_access(ff, ®, n, TU_FIFO_FIXED_ADDR_RW32); + TEST_ASSERT_EQUAL(n, read_cnt); + TEST_ASSERT_EQUAL(0, tu_fifo_count(ff)); + + TEST_ASSERT_EQUAL_HEX32(reg_expected[n - 1], reg); + } +} + +void test_get_read_info_advanced_cases(void) { + tu_fifo_clear(ff); + + ff->wr_idx = 20; + ff->rd_idx = 2; + tu_fifo_get_read_info(ff, &info); + TEST_ASSERT_EQUAL(18, info.len_lin); + TEST_ASSERT_EQUAL(0, info.len_wrap); + TEST_ASSERT_EQUAL_PTR(ff->buffer + 2, info.ptr_lin); + TEST_ASSERT_NULL(info.ptr_wrap); + + ff->wr_idx = 68; // ptr = 4 + ff->rd_idx = 56; // ptr = 56 + tu_fifo_get_read_info(ff, &info); + TEST_ASSERT_EQUAL(8, info.len_lin); + TEST_ASSERT_EQUAL(4, info.len_wrap); + TEST_ASSERT_EQUAL_PTR(ff->buffer + 56, info.ptr_lin); + TEST_ASSERT_EQUAL_PTR(ff->buffer, info.ptr_wrap); +} + +void test_get_write_info_advanced_cases(void) { + tu_fifo_clear(ff); + + ff->wr_idx = 10; + ff->rd_idx = 104; // ptr = 40 + tu_fifo_get_write_info(ff, &info); + TEST_ASSERT_EQUAL(30, info.len_lin); + TEST_ASSERT_EQUAL(0, info.len_wrap); + TEST_ASSERT_EQUAL_PTR(ff->buffer + 10, info.ptr_lin); + TEST_ASSERT_NULL(info.ptr_wrap); + + ff->wr_idx = 60; + ff->rd_idx = 20; + tu_fifo_get_write_info(ff, &info); + TEST_ASSERT_EQUAL(4, info.len_lin); + TEST_ASSERT_EQUAL(20, info.len_wrap); + TEST_ASSERT_EQUAL_PTR(ff->buffer + 60, info.ptr_lin); + TEST_ASSERT_EQUAL_PTR(ff->buffer, info.ptr_wrap); +} + +void test_correct_read_pointer_cases(void) { + tu_fifo_clear(ff); + + // wr beyond depth: rd should be wr - depth + ff->wr_idx = FIFO_SIZE + 6; // 70 + tu_fifo_correct_read_pointer(ff); + TEST_ASSERT_EQUAL(6, ff->rd_idx); + + // wr exactly at depth: rd should wrap to zero + ff->wr_idx = FIFO_SIZE; + tu_fifo_correct_read_pointer(ff); + TEST_ASSERT_EQUAL(0, ff->rd_idx); + + // wr below depth: rd should be wr + depth + ff->wr_idx = 10; + tu_fifo_correct_read_pointer(ff); + TEST_ASSERT_EQUAL(FIFO_SIZE + 10, ff->rd_idx); +}