add more unit tests for tu_fifo

This commit is contained in:
hathach
2025-11-21 12:58:28 +07:00
parent 30198b2ab9
commit d4cdc096ca
7 changed files with 429 additions and 109 deletions

View File

@ -84,6 +84,7 @@ MaxEmptyLinesToKeep: 2
NamespaceIndentation: All
PenaltyBreakBeforeFirstCallParameter: 1000000
PenaltyBreakOpenParenthesis: 1000000
PPIndentWidth: 2
QualifierAlignment: Custom
QualifierOrder: ['static', 'const', 'volatile', 'restrict', 'type']
SpaceAfterTemplateKeyword: false

View File

@ -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

View File

@ -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

View File

@ -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_ */
/** @} */

View File

@ -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/<name>/.
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()

View File

@ -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.

View File

@ -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<sizeof(test_data); i++) test_data[i] = i;
for (size_t i = 0; i < sizeof(test_data); i++) {
test_data[i] = i;
}
memset(rd_buf, 0, sizeof(rd_buf));
}
void tearDown(void)
{
void tearDown(void) {
}
//--------------------------------------------------------------------+
// Tests
//--------------------------------------------------------------------+
void test_normal(void)
{
for(uint8_t i=0; i < FIFO_SIZE; i++) tu_fifo_write(ff, &i);
void test_normal(void) {
for (uint8_t i = 0; i < FIFO_SIZE; i++) {
tu_fifo_write(ff, &i);
}
for(uint8_t i=0; i < FIFO_SIZE; i++)
{
for (uint8_t i = 0; i < FIFO_SIZE; i++) {
uint8_t c;
tu_fifo_read(ff, &c);
TEST_ASSERT_EQUAL(i, c);
}
}
void test_item_size(void)
{
uint8_t ff4_buf[FIFO_SIZE * sizeof(uint32_t)];
void test_item_size(void) {
uint8_t ff4_buf[FIFO_SIZE * sizeof(uint32_t)];
tu_fifo_t ff4 = TU_FIFO_INIT(ff4_buf, FIFO_SIZE, uint32_t, false);
uint32_t data4[2*FIFO_SIZE];
for(uint32_t i=0; i<sizeof(data4)/4; i++) data4[i] = i;
uint32_t data4[2 * FIFO_SIZE];
for (uint32_t i = 0; i < sizeof(data4) / 4; i++) {
data4[i] = i;
}
// fill up fifo
tu_fifo_write_n(&ff4, data4, FIFO_SIZE);
@ -84,78 +85,77 @@ void test_item_size(void)
// read 0 -> 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 *)&reg, 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 *)&reg, 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, &reg, 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, &reg, 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);
}