From ec2c8fa1137f2b706f93a03391c9a215b31255ff Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 3 Jun 2026 13:06:59 +0000 Subject: [PATCH 1/7] Initial plan From b04430b5ecd41c4528f0b5631c4b21d773884b2c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 3 Jun 2026 13:11:09 +0000 Subject: [PATCH 2/7] feat: add DMF test module for dm_sw_ring API --- CMakeLists.txt | 3 +- tests/CMakeLists.txt | 15 ++++++ tests/test_dm_sw_ring.c | 110 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 tests/CMakeLists.txt create mode 100644 tests/test_dm_sw_ring.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 231de13..8e26aa3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -87,5 +87,4 @@ target_include_directories(${DMOD_MODULE_NAME} PRIVATE # ====================================================================== # test_dm_sw_ring Application # ====================================================================== -# Add test_dm_sw_ring application subdirectory -# add_subdirectory(apps/test_dm_sw_ring) +add_subdirectory(tests) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..7984a89 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,15 @@ +set(DMOD_MODULE_NAME test_dm_sw_ring) +set(DMOD_MODULE_VERSION ${PROJECT_VERSION}) +set(DMOD_AUTHOR_NAME "Patryk Kubiak") +set(DMOD_STACK_SIZE 1024) +set(DMOD_PRIORITY 0) + +dmod_add_executable(${DMOD_MODULE_NAME} ${DMOD_MODULE_VERSION} + test_dm_sw_ring.c +) + +target_include_directories(${DMOD_MODULE_NAME} PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/../include +) + +target_link_libraries(${DMOD_MODULE_NAME} dm_sw_ring_if) diff --git a/tests/test_dm_sw_ring.c b/tests/test_dm_sw_ring.c new file mode 100644 index 0000000..da0978e --- /dev/null +++ b/tests/test_dm_sw_ring.c @@ -0,0 +1,110 @@ +#define DMOD_ENABLE_REGISTRATION ON +#include "dmod.h" +#include "dm_sw_ring.h" +#include +#include + +static int g_failures = 0; + +#define EXPECT_TRUE(expr) \ + do \ + { \ + if (!(expr)) \ + { \ + DMOD_LOG_ERROR("Expectation failed: %s at %s:%d\n", #expr, __FILE__, __LINE__); \ + g_failures++; \ + } \ + } while (0) + +#define EXPECT_EQ_U32(actual, expected) EXPECT_TRUE((uint32_t)(actual) == (uint32_t)(expected)) +#define EXPECT_EQ_I32(actual, expected) EXPECT_TRUE((int32_t)(actual) == (int32_t)(expected)) +#define EXPECT_EQ_BOOL(actual, expected) EXPECT_TRUE(((actual) ? true : false) == ((expected) ? true : false)) +#define EXPECT_EQ_U8(actual, expected) EXPECT_TRUE((uint8_t)(actual) == (uint8_t)(expected)) + +int main(int argc, char** argv) +{ + (void)argc; + (void)argv; + + dm_sw_ring_flags_t flags = dm_sw_ring_flags_drop_old_data | dm_sw_ring_flags_mutex_sync; + dm_sw_ring_t ring = dm_sw_ring_create(4, flags); + EXPECT_TRUE(ring != NULL); + EXPECT_TRUE(dm_sw_ring_create(0, flags) == NULL); + + EXPECT_EQ_U32(dm_sw_ring_capacity(ring), 4); + EXPECT_EQ_U32(dm_sw_ring_size(ring), 0); + EXPECT_EQ_U32(dm_sw_ring_available_space(ring), 4); + EXPECT_EQ_BOOL(dm_sw_ring_is_empty(ring), true); + EXPECT_EQ_BOOL(dm_sw_ring_is_full(ring), false); + + { + const uint8_t input1[] = {1, 2, 3}; + uint8_t buffer[4] = {0}; + EXPECT_EQ_U32(dm_sw_ring_write(ring, input1, 3), 3); + EXPECT_EQ_U32(dm_sw_ring_size(ring), 3); + EXPECT_EQ_U32(dm_sw_ring_available_space(ring), 1); + + EXPECT_EQ_I32(dm_sw_ring_peek(ring, buffer, 2), 2); + EXPECT_EQ_U8(buffer[0], 1); + EXPECT_EQ_U8(buffer[1], 2); + EXPECT_EQ_U32(dm_sw_ring_size(ring), 3); + + buffer[0] = 0; + buffer[1] = 0; + EXPECT_EQ_U32(dm_sw_ring_read(ring, buffer, 2), 2); + EXPECT_EQ_U8(buffer[0], 1); + EXPECT_EQ_U8(buffer[1], 2); + EXPECT_EQ_U32(dm_sw_ring_size(ring), 1); + } + + EXPECT_EQ_I32(dm_sw_ring_discard(ring, 0), 0); + EXPECT_EQ_I32(dm_sw_ring_discard(ring, 1), 1); + EXPECT_EQ_U32(dm_sw_ring_size(ring), 0); + EXPECT_EQ_BOOL(dm_sw_ring_is_empty(ring), true); + + { + const uint8_t input2[] = {7, 8, 9, 10}; + EXPECT_EQ_U32(dm_sw_ring_write(ring, input2, 4), 4); + EXPECT_EQ_BOOL(dm_sw_ring_is_full(ring), true); + EXPECT_EQ_I32(dm_sw_ring_clear(ring), 0); + EXPECT_EQ_BOOL(dm_sw_ring_is_empty(ring), true); + EXPECT_EQ_U32(dm_sw_ring_available_space(ring), 4); + } + + { + const uint8_t input3[] = {11, 12, 13, 14, 15}; + uint8_t buffer[4] = {0}; + EXPECT_EQ_U32(dm_sw_ring_write(ring, input3, 5), 5); + EXPECT_EQ_U32(dm_sw_ring_size(ring), 4); + EXPECT_EQ_BOOL(dm_sw_ring_is_full(ring), true); + + EXPECT_EQ_I32(dm_sw_ring_peek(ring, buffer, 4), 4); + EXPECT_EQ_U8(buffer[0], 12); + EXPECT_EQ_U8(buffer[1], 13); + EXPECT_EQ_U8(buffer[2], 14); + EXPECT_EQ_U8(buffer[3], 15); + + buffer[0] = 0; + buffer[1] = 0; + buffer[2] = 0; + buffer[3] = 0; + EXPECT_EQ_U32(dm_sw_ring_read(ring, buffer, 4), 4); + EXPECT_EQ_U8(buffer[0], 12); + EXPECT_EQ_U8(buffer[1], 13); + EXPECT_EQ_U8(buffer[2], 14); + EXPECT_EQ_U8(buffer[3], 15); + EXPECT_EQ_U32(dm_sw_ring_read(ring, buffer, 1), 0); + EXPECT_EQ_I32(dm_sw_ring_peek(ring, buffer, 0), 0); + } + + dm_sw_ring_destroy(ring); + + if (g_failures == 0) + { + DMOD_LOG_INFO("All dm_sw_ring API checks passed\n"); + return 0; + } + + DMOD_LOG_ERROR("dm_sw_ring API checks failed: %d\n", g_failures); + return 1; +} From 73c17577a50601f430647df9bde4605d6e15420a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 3 Jun 2026 13:15:23 +0000 Subject: [PATCH 3/7] refactor: improve dm_sw_ring test diagnostics --- tests/test_dm_sw_ring.c | 125 +++++++++++++++++++++++++++------------- 1 file changed, 85 insertions(+), 40 deletions(-) diff --git a/tests/test_dm_sw_ring.c b/tests/test_dm_sw_ring.c index da0978e..79ca276 100644 --- a/tests/test_dm_sw_ring.c +++ b/tests/test_dm_sw_ring.c @@ -16,20 +16,65 @@ static int g_failures = 0; } \ } while (0) -#define EXPECT_EQ_U32(actual, expected) EXPECT_TRUE((uint32_t)(actual) == (uint32_t)(expected)) -#define EXPECT_EQ_I32(actual, expected) EXPECT_TRUE((int32_t)(actual) == (int32_t)(expected)) -#define EXPECT_EQ_BOOL(actual, expected) EXPECT_TRUE(((actual) ? true : false) == ((expected) ? true : false)) -#define EXPECT_EQ_U8(actual, expected) EXPECT_TRUE((uint8_t)(actual) == (uint8_t)(expected)) +#define EXPECT_EQ_U32(actual, expected) \ + do \ + { \ + uint32_t _actual = (uint32_t)(actual); \ + uint32_t _expected = (uint32_t)(expected); \ + if (_actual != _expected) \ + { \ + DMOD_LOG_ERROR("Expectation failed: %s == %s (actual=%u expected=%u) at %s:%d\n", \ + #actual, #expected, _actual, _expected, __FILE__, __LINE__); \ + g_failures++; \ + } \ + } while (0) +#define EXPECT_EQ_I32(actual, expected) \ + do \ + { \ + int32_t _actual = (int32_t)(actual); \ + int32_t _expected = (int32_t)(expected); \ + if (_actual != _expected) \ + { \ + DMOD_LOG_ERROR("Expectation failed: %s == %s (actual=%d expected=%d) at %s:%d\n", \ + #actual, #expected, _actual, _expected, __FILE__, __LINE__); \ + g_failures++; \ + } \ + } while (0) +#define EXPECT_EQ_BOOL(actual, expected) \ + do \ + { \ + bool _actual = ((actual) ? true : false); \ + bool _expected = ((expected) ? true : false); \ + if (_actual != _expected) \ + { \ + DMOD_LOG_ERROR("Expectation failed: %s == %s (actual=%d expected=%d) at %s:%d\n", \ + #actual, #expected, (int)_actual, (int)_expected, __FILE__, __LINE__); \ + g_failures++; \ + } \ + } while (0) +#define EXPECT_EQ_U8(actual, expected) \ + do \ + { \ + uint8_t _actual = (uint8_t)(actual); \ + uint8_t _expected = (uint8_t)(expected); \ + if (_actual != _expected) \ + { \ + DMOD_LOG_ERROR("Expectation failed: %s == %s (actual=%u expected=%u) at %s:%d\n", \ + #actual, #expected, _actual, _expected, __FILE__, __LINE__); \ + g_failures++; \ + } \ + } while (0) int main(int argc, char** argv) { (void)argc; (void)argv; - dm_sw_ring_flags_t flags = dm_sw_ring_flags_drop_old_data | dm_sw_ring_flags_mutex_sync; - dm_sw_ring_t ring = dm_sw_ring_create(4, flags); + // Disable waiting flags to keep tests deterministic and non-blocking. + dm_sw_ring_flags_t ring_flags = dm_sw_ring_flags_drop_old_data | dm_sw_ring_flags_mutex_sync; + dm_sw_ring_t ring = dm_sw_ring_create(4, ring_flags); EXPECT_TRUE(ring != NULL); - EXPECT_TRUE(dm_sw_ring_create(0, flags) == NULL); + EXPECT_TRUE(dm_sw_ring_create(0, ring_flags) == NULL); EXPECT_EQ_U32(dm_sw_ring_capacity(ring), 4); EXPECT_EQ_U32(dm_sw_ring_size(ring), 0); @@ -38,22 +83,22 @@ int main(int argc, char** argv) EXPECT_EQ_BOOL(dm_sw_ring_is_full(ring), false); { - const uint8_t input1[] = {1, 2, 3}; - uint8_t buffer[4] = {0}; - EXPECT_EQ_U32(dm_sw_ring_write(ring, input1, 3), 3); + const uint8_t test_data_basic[] = {1, 2, 3}; + uint8_t io_buffer[4] = {0}; + EXPECT_EQ_U32(dm_sw_ring_write(ring, test_data_basic, 3), 3); EXPECT_EQ_U32(dm_sw_ring_size(ring), 3); EXPECT_EQ_U32(dm_sw_ring_available_space(ring), 1); - EXPECT_EQ_I32(dm_sw_ring_peek(ring, buffer, 2), 2); - EXPECT_EQ_U8(buffer[0], 1); - EXPECT_EQ_U8(buffer[1], 2); + EXPECT_EQ_I32(dm_sw_ring_peek(ring, io_buffer, 2), 2); + EXPECT_EQ_U8(io_buffer[0], 1); + EXPECT_EQ_U8(io_buffer[1], 2); EXPECT_EQ_U32(dm_sw_ring_size(ring), 3); - buffer[0] = 0; - buffer[1] = 0; - EXPECT_EQ_U32(dm_sw_ring_read(ring, buffer, 2), 2); - EXPECT_EQ_U8(buffer[0], 1); - EXPECT_EQ_U8(buffer[1], 2); + io_buffer[0] = 0; + io_buffer[1] = 0; + EXPECT_EQ_U32(dm_sw_ring_read(ring, io_buffer, 2), 2); + EXPECT_EQ_U8(io_buffer[0], 1); + EXPECT_EQ_U8(io_buffer[1], 2); EXPECT_EQ_U32(dm_sw_ring_size(ring), 1); } @@ -63,8 +108,8 @@ int main(int argc, char** argv) EXPECT_EQ_BOOL(dm_sw_ring_is_empty(ring), true); { - const uint8_t input2[] = {7, 8, 9, 10}; - EXPECT_EQ_U32(dm_sw_ring_write(ring, input2, 4), 4); + const uint8_t test_data_full_capacity[] = {7, 8, 9, 10}; + EXPECT_EQ_U32(dm_sw_ring_write(ring, test_data_full_capacity, 4), 4); EXPECT_EQ_BOOL(dm_sw_ring_is_full(ring), true); EXPECT_EQ_I32(dm_sw_ring_clear(ring), 0); EXPECT_EQ_BOOL(dm_sw_ring_is_empty(ring), true); @@ -72,29 +117,29 @@ int main(int argc, char** argv) } { - const uint8_t input3[] = {11, 12, 13, 14, 15}; - uint8_t buffer[4] = {0}; - EXPECT_EQ_U32(dm_sw_ring_write(ring, input3, 5), 5); + const uint8_t test_data_overflow[] = {11, 12, 13, 14, 15}; + uint8_t io_buffer[4] = {0}; + EXPECT_EQ_U32(dm_sw_ring_write(ring, test_data_overflow, 5), 5); EXPECT_EQ_U32(dm_sw_ring_size(ring), 4); EXPECT_EQ_BOOL(dm_sw_ring_is_full(ring), true); - EXPECT_EQ_I32(dm_sw_ring_peek(ring, buffer, 4), 4); - EXPECT_EQ_U8(buffer[0], 12); - EXPECT_EQ_U8(buffer[1], 13); - EXPECT_EQ_U8(buffer[2], 14); - EXPECT_EQ_U8(buffer[3], 15); - - buffer[0] = 0; - buffer[1] = 0; - buffer[2] = 0; - buffer[3] = 0; - EXPECT_EQ_U32(dm_sw_ring_read(ring, buffer, 4), 4); - EXPECT_EQ_U8(buffer[0], 12); - EXPECT_EQ_U8(buffer[1], 13); - EXPECT_EQ_U8(buffer[2], 14); - EXPECT_EQ_U8(buffer[3], 15); - EXPECT_EQ_U32(dm_sw_ring_read(ring, buffer, 1), 0); - EXPECT_EQ_I32(dm_sw_ring_peek(ring, buffer, 0), 0); + EXPECT_EQ_I32(dm_sw_ring_peek(ring, io_buffer, 4), 4); + EXPECT_EQ_U8(io_buffer[0], 12); + EXPECT_EQ_U8(io_buffer[1], 13); + EXPECT_EQ_U8(io_buffer[2], 14); + EXPECT_EQ_U8(io_buffer[3], 15); + + io_buffer[0] = 0; + io_buffer[1] = 0; + io_buffer[2] = 0; + io_buffer[3] = 0; + EXPECT_EQ_U32(dm_sw_ring_read(ring, io_buffer, 4), 4); + EXPECT_EQ_U8(io_buffer[0], 12); + EXPECT_EQ_U8(io_buffer[1], 13); + EXPECT_EQ_U8(io_buffer[2], 14); + EXPECT_EQ_U8(io_buffer[3], 15); + EXPECT_EQ_U32(dm_sw_ring_read(ring, io_buffer, 1), 0); + EXPECT_EQ_I32(dm_sw_ring_peek(ring, io_buffer, 0), 0); } dm_sw_ring_destroy(ring); From 9ccacd7b288d6fb9f31c5feeabdfeb07d7a359a6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 3 Jun 2026 13:24:19 +0000 Subject: [PATCH 4/7] refactor tests into API steps with setup teardown --- .github/workflows/release.yml | 1 + manifest.dmm | 2 +- tests/test_dm_sw_ring.c | 228 ++++++++++++++++++++++++---------- 3 files changed, 166 insertions(+), 65 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 332e177..d04030d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -137,6 +137,7 @@ jobs: # Add $version-available directives for the modules echo "\$version-available dm_sw_ring $VERSIONS" >> versions.dmm + echo "\$version-available test_dm_sw_ring $VERSIONS" >> versions.dmm echo "Generated versions.dmm:" cat versions.dmm diff --git a/manifest.dmm b/manifest.dmm index 4009c3f..fb32aa9 100644 --- a/manifest.dmm +++ b/manifest.dmm @@ -5,4 +5,4 @@ $include https://github.com/choco-technologies/dm_sw_ring/releases/download/vlat dm_sw_ring https://github.com/choco-technologies/dm_sw_ring/releases/download/v/dm_sw_ring-v-.zip # Test application -# test_dm_sw_ring https://github.com/choco-technologies/dm_sw_ring/releases/download/v/dm_sw_ring-v-.zip +test_dm_sw_ring https://github.com/choco-technologies/dm_sw_ring/releases/download/v/dm_sw_ring-v-.zip diff --git a/tests/test_dm_sw_ring.c b/tests/test_dm_sw_ring.c index 79ca276..9f35147 100644 --- a/tests/test_dm_sw_ring.c +++ b/tests/test_dm_sw_ring.c @@ -3,6 +3,7 @@ #include "dm_sw_ring.h" #include #include +#include static int g_failures = 0; @@ -65,84 +66,183 @@ static int g_failures = 0; } \ } while (0) -int main(int argc, char** argv) +typedef struct test_context { - (void)argc; - (void)argv; + dm_sw_ring_t ring; + dm_sw_ring_flags_t ring_flags; + uint8_t io_buffer[8]; +} test_context_t; - // Disable waiting flags to keep tests deterministic and non-blocking. - dm_sw_ring_flags_t ring_flags = dm_sw_ring_flags_drop_old_data | dm_sw_ring_flags_mutex_sync; - dm_sw_ring_t ring = dm_sw_ring_create(4, ring_flags); - EXPECT_TRUE(ring != NULL); - EXPECT_TRUE(dm_sw_ring_create(0, ring_flags) == NULL); +typedef void (*test_setup_fn)(test_context_t* context); +typedef void (*test_step_fn)(test_context_t* context); +typedef void (*test_teardown_fn)(test_context_t* context); - EXPECT_EQ_U32(dm_sw_ring_capacity(ring), 4); - EXPECT_EQ_U32(dm_sw_ring_size(ring), 0); - EXPECT_EQ_U32(dm_sw_ring_available_space(ring), 4); - EXPECT_EQ_BOOL(dm_sw_ring_is_empty(ring), true); - EXPECT_EQ_BOOL(dm_sw_ring_is_full(ring), false); +static void setup_ring_capacity_4(test_context_t* context) +{ + context->ring = dm_sw_ring_create(4, context->ring_flags); + EXPECT_TRUE(context->ring != NULL); +} +static void teardown_ring(test_context_t* context) +{ + if (context->ring != NULL) { - const uint8_t test_data_basic[] = {1, 2, 3}; - uint8_t io_buffer[4] = {0}; - EXPECT_EQ_U32(dm_sw_ring_write(ring, test_data_basic, 3), 3); - EXPECT_EQ_U32(dm_sw_ring_size(ring), 3); - EXPECT_EQ_U32(dm_sw_ring_available_space(ring), 1); - - EXPECT_EQ_I32(dm_sw_ring_peek(ring, io_buffer, 2), 2); - EXPECT_EQ_U8(io_buffer[0], 1); - EXPECT_EQ_U8(io_buffer[1], 2); - EXPECT_EQ_U32(dm_sw_ring_size(ring), 3); - - io_buffer[0] = 0; - io_buffer[1] = 0; - EXPECT_EQ_U32(dm_sw_ring_read(ring, io_buffer, 2), 2); - EXPECT_EQ_U8(io_buffer[0], 1); - EXPECT_EQ_U8(io_buffer[1], 2); - EXPECT_EQ_U32(dm_sw_ring_size(ring), 1); + dm_sw_ring_destroy(context->ring); + context->ring = NULL; } +} - EXPECT_EQ_I32(dm_sw_ring_discard(ring, 0), 0); - EXPECT_EQ_I32(dm_sw_ring_discard(ring, 1), 1); - EXPECT_EQ_U32(dm_sw_ring_size(ring), 0); - EXPECT_EQ_BOOL(dm_sw_ring_is_empty(ring), true); +static void run_test_step(const char* name, test_context_t* context, test_setup_fn setup, test_step_fn step, test_teardown_fn teardown) +{ + int failures_before = g_failures; + DMOD_LOG_STEP_BEGIN("%s\n", name); + if (setup != NULL) + { + setup(context); + } + if (step != NULL && context->ring != NULL) { - const uint8_t test_data_full_capacity[] = {7, 8, 9, 10}; - EXPECT_EQ_U32(dm_sw_ring_write(ring, test_data_full_capacity, 4), 4); - EXPECT_EQ_BOOL(dm_sw_ring_is_full(ring), true); - EXPECT_EQ_I32(dm_sw_ring_clear(ring), 0); - EXPECT_EQ_BOOL(dm_sw_ring_is_empty(ring), true); - EXPECT_EQ_U32(dm_sw_ring_available_space(ring), 4); + step(context); } + if (teardown != NULL) + { + teardown(context); + } + + DMOD_LOG_STEP((g_failures > failures_before) ? 1 : 0, "%s\n", name); +} +static void test_create_step(test_context_t* context) +{ + dm_sw_ring_t ring = dm_sw_ring_create(4, context->ring_flags); + EXPECT_TRUE(ring != NULL); + EXPECT_TRUE(dm_sw_ring_create(0, context->ring_flags) == NULL); + if (ring != NULL) { - const uint8_t test_data_overflow[] = {11, 12, 13, 14, 15}; - uint8_t io_buffer[4] = {0}; - EXPECT_EQ_U32(dm_sw_ring_write(ring, test_data_overflow, 5), 5); - EXPECT_EQ_U32(dm_sw_ring_size(ring), 4); - EXPECT_EQ_BOOL(dm_sw_ring_is_full(ring), true); - - EXPECT_EQ_I32(dm_sw_ring_peek(ring, io_buffer, 4), 4); - EXPECT_EQ_U8(io_buffer[0], 12); - EXPECT_EQ_U8(io_buffer[1], 13); - EXPECT_EQ_U8(io_buffer[2], 14); - EXPECT_EQ_U8(io_buffer[3], 15); - - io_buffer[0] = 0; - io_buffer[1] = 0; - io_buffer[2] = 0; - io_buffer[3] = 0; - EXPECT_EQ_U32(dm_sw_ring_read(ring, io_buffer, 4), 4); - EXPECT_EQ_U8(io_buffer[0], 12); - EXPECT_EQ_U8(io_buffer[1], 13); - EXPECT_EQ_U8(io_buffer[2], 14); - EXPECT_EQ_U8(io_buffer[3], 15); - EXPECT_EQ_U32(dm_sw_ring_read(ring, io_buffer, 1), 0); - EXPECT_EQ_I32(dm_sw_ring_peek(ring, io_buffer, 0), 0); + dm_sw_ring_destroy(ring); } +} + +static void test_destroy_step(test_context_t* context) +{ + EXPECT_TRUE(context->ring != NULL); + dm_sw_ring_destroy(context->ring); + context->ring = NULL; +} + +static void test_write_step(test_context_t* context) +{ + const uint8_t data[] = {10, 11, 12, 13, 14}; + EXPECT_EQ_U32(dm_sw_ring_write(context->ring, NULL, 1), 0); + EXPECT_EQ_U32(dm_sw_ring_write(context->ring, data, 5), 5); + EXPECT_EQ_U32(dm_sw_ring_size(context->ring), 4); +} + +static void test_read_step(test_context_t* context) +{ + const uint8_t data[] = {1, 2, 3}; + memset(context->io_buffer, 0, sizeof(context->io_buffer)); + EXPECT_EQ_U32(dm_sw_ring_write(context->ring, data, 3), 3); + EXPECT_EQ_U32(dm_sw_ring_read(context->ring, NULL, 1), 0); + EXPECT_EQ_U32(dm_sw_ring_read(context->ring, context->io_buffer, 2), 2); + EXPECT_EQ_U8(context->io_buffer[0], 1); + EXPECT_EQ_U8(context->io_buffer[1], 2); +} + +static void test_capacity_step(test_context_t* context) +{ + EXPECT_EQ_U32(dm_sw_ring_capacity(context->ring), 4); +} + +static void test_size_step(test_context_t* context) +{ + const uint8_t data[] = {1, 2, 3}; + EXPECT_EQ_U32(dm_sw_ring_size(context->ring), 0); + EXPECT_EQ_U32(dm_sw_ring_write(context->ring, data, 3), 3); + EXPECT_EQ_U32(dm_sw_ring_size(context->ring), 3); + EXPECT_EQ_U32(dm_sw_ring_discard(context->ring, 1), 1); + EXPECT_EQ_U32(dm_sw_ring_size(context->ring), 2); +} + +static void test_available_space_step(test_context_t* context) +{ + const uint8_t data[] = {1, 2, 3}; + EXPECT_EQ_U32(dm_sw_ring_available_space(context->ring), 4); + EXPECT_EQ_U32(dm_sw_ring_write(context->ring, data, 3), 3); + EXPECT_EQ_U32(dm_sw_ring_available_space(context->ring), 1); +} + +static void test_peek_step(test_context_t* context) +{ + const uint8_t data[] = {1, 2, 3, 4}; + memset(context->io_buffer, 0, sizeof(context->io_buffer)); + EXPECT_EQ_U32(dm_sw_ring_write(context->ring, data, 4), 4); + EXPECT_EQ_I32(dm_sw_ring_peek(context->ring, NULL, 1), -1); + EXPECT_EQ_I32(dm_sw_ring_peek(context->ring, context->io_buffer, 4), 4); + EXPECT_EQ_U8(context->io_buffer[0], 1); + EXPECT_EQ_U8(context->io_buffer[3], 4); + EXPECT_EQ_U32(dm_sw_ring_size(context->ring), 4); +} + +static void test_discard_step(test_context_t* context) +{ + const uint8_t data[] = {4, 5, 6}; + EXPECT_EQ_U32(dm_sw_ring_write(context->ring, data, 3), 3); + EXPECT_EQ_I32(dm_sw_ring_discard(context->ring, 0), 0); + EXPECT_EQ_I32(dm_sw_ring_discard(context->ring, 1), 1); + EXPECT_EQ_U32(dm_sw_ring_size(context->ring), 2); +} + +static void test_clear_step(test_context_t* context) +{ + const uint8_t data[] = {1, 2, 3, 4}; + EXPECT_EQ_U32(dm_sw_ring_write(context->ring, data, 4), 4); + EXPECT_EQ_I32(dm_sw_ring_clear(context->ring), 0); + EXPECT_EQ_U32(dm_sw_ring_size(context->ring), 0); +} + +static void test_is_full_step(test_context_t* context) +{ + const uint8_t data[] = {1, 2, 3, 4}; + EXPECT_EQ_BOOL(dm_sw_ring_is_full(context->ring), false); + EXPECT_EQ_U32(dm_sw_ring_write(context->ring, data, 4), 4); + EXPECT_EQ_BOOL(dm_sw_ring_is_full(context->ring), true); +} + +static void test_is_empty_step(test_context_t* context) +{ + const uint8_t data[] = {1}; + EXPECT_EQ_BOOL(dm_sw_ring_is_empty(context->ring), true); + EXPECT_EQ_U32(dm_sw_ring_write(context->ring, data, 1), 1); + EXPECT_EQ_BOOL(dm_sw_ring_is_empty(context->ring), false); + EXPECT_EQ_U32(dm_sw_ring_read(context->ring, context->io_buffer, 1), 1); + EXPECT_EQ_BOOL(dm_sw_ring_is_empty(context->ring), true); +} + +int main(int argc, char** argv) +{ + (void)argc; + (void)argv; - dm_sw_ring_destroy(ring); + test_context_t context = { + .ring = NULL, + .ring_flags = dm_sw_ring_flags_drop_old_data | dm_sw_ring_flags_mutex_sync, + .io_buffer = {0} + }; + + run_test_step("dm_sw_ring_create", &context, NULL, test_create_step, NULL); + run_test_step("dm_sw_ring_destroy", &context, setup_ring_capacity_4, test_destroy_step, teardown_ring); + run_test_step("dm_sw_ring_write", &context, setup_ring_capacity_4, test_write_step, teardown_ring); + run_test_step("dm_sw_ring_read", &context, setup_ring_capacity_4, test_read_step, teardown_ring); + run_test_step("dm_sw_ring_capacity", &context, setup_ring_capacity_4, test_capacity_step, teardown_ring); + run_test_step("dm_sw_ring_size", &context, setup_ring_capacity_4, test_size_step, teardown_ring); + run_test_step("dm_sw_ring_available_space", &context, setup_ring_capacity_4, test_available_space_step, teardown_ring); + run_test_step("dm_sw_ring_peek", &context, setup_ring_capacity_4, test_peek_step, teardown_ring); + run_test_step("dm_sw_ring_discard", &context, setup_ring_capacity_4, test_discard_step, teardown_ring); + run_test_step("dm_sw_ring_clear", &context, setup_ring_capacity_4, test_clear_step, teardown_ring); + run_test_step("dm_sw_ring_is_full", &context, setup_ring_capacity_4, test_is_full_step, teardown_ring); + run_test_step("dm_sw_ring_is_empty", &context, setup_ring_capacity_4, test_is_empty_step, teardown_ring); if (g_failures == 0) { From 3ae8980b30e7cc9e6b2051787d1a43af0db0bd3c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 3 Jun 2026 13:26:23 +0000 Subject: [PATCH 5/7] update test steps and manifest entries --- tests/test_dm_sw_ring.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_dm_sw_ring.c b/tests/test_dm_sw_ring.c index 9f35147..9458cd6 100644 --- a/tests/test_dm_sw_ring.c +++ b/tests/test_dm_sw_ring.c @@ -135,6 +135,7 @@ static void test_write_step(test_context_t* context) { const uint8_t data[] = {10, 11, 12, 13, 14}; EXPECT_EQ_U32(dm_sw_ring_write(context->ring, NULL, 1), 0); + EXPECT_EQ_U32(dm_sw_ring_size(context->ring), 0); EXPECT_EQ_U32(dm_sw_ring_write(context->ring, data, 5), 5); EXPECT_EQ_U32(dm_sw_ring_size(context->ring), 4); } @@ -145,6 +146,7 @@ static void test_read_step(test_context_t* context) memset(context->io_buffer, 0, sizeof(context->io_buffer)); EXPECT_EQ_U32(dm_sw_ring_write(context->ring, data, 3), 3); EXPECT_EQ_U32(dm_sw_ring_read(context->ring, NULL, 1), 0); + EXPECT_EQ_U32(dm_sw_ring_size(context->ring), 3); EXPECT_EQ_U32(dm_sw_ring_read(context->ring, context->io_buffer, 2), 2); EXPECT_EQ_U8(context->io_buffer[0], 1); EXPECT_EQ_U8(context->io_buffer[1], 2); From c3b7cbdaa6b8d48ef8dbc7a51defbcc9008e09ef Mon Sep 17 00:00:00 2001 From: Patryk Kubiak Date: Wed, 3 Jun 2026 15:42:37 +0200 Subject: [PATCH 6/7] feat: enhance initialization and deinitialization logging for DM Software Ring module --- src/dm_sw_ring.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/dm_sw_ring.c b/src/dm_sw_ring.c index 5a8ed9a..9517393 100644 --- a/src/dm_sw_ring.c +++ b/src/dm_sw_ring.c @@ -1,3 +1,4 @@ +#define DMOD_ENABLE_REGISTRATION ON #include "dmod.h" #include "dm_sw_ring.h" @@ -59,21 +60,17 @@ void dmod_preinit(void) // Nothing to do } -/** - * @brief Module initialization - */ + int dmod_init(const Dmod_Config_t *Config) { - (void)Config; + DMOD_LOG_INFO("DM Software Ring module initialized\n"); return 0; } -/** - * @brief Module deinitialization - */ -void dmod_deinit(void) +int dmod_deinit(void) { - // Nothing to do + DMOD_LOG_INFO("DM Software Ring module deinitialized\n"); + return 0; } // ============================================================================ From c8dc4cd77ba7bd9cf051fb19d5f0764dcb840b17 Mon Sep 17 00:00:00 2001 From: Patryk Kubiak Date: Wed, 3 Jun 2026 15:58:48 +0200 Subject: [PATCH 7/7] feat: add count tracking to dm_sw_ring for improved buffer management --- src/dm_sw_ring.c | 57 +++++++++++++++++++----------------------------- 1 file changed, 22 insertions(+), 35 deletions(-) diff --git a/src/dm_sw_ring.c b/src/dm_sw_ring.c index 9517393..9416a8d 100644 --- a/src/dm_sw_ring.c +++ b/src/dm_sw_ring.c @@ -17,6 +17,7 @@ struct dm_sw_ring dm_sw_ring_capacity_t capacity; // Capacity of the ring buffer (number of elements) dm_sw_ring_capacity_t head; // Index of the head (next element to read) dm_sw_ring_capacity_t tail; // Index of the tail (next element to write) + dm_sw_ring_capacity_t count; // Number of elements currently stored in the ring buffer uint8_t* buffer; // Pointer to the buffer memory dm_sw_ring_flags_t flags; // Flags for ring buffer behavior void* mutex; // Mutex for synchronization (if enabled) @@ -106,6 +107,7 @@ dmod_dm_sw_ring_api_declaration(1.0, dm_sw_ring_t, _create, (dm_sw_ring_capacity ring->capacity = capacity; ring->head = 0; ring->tail = 0; + ring->count = 0; ring->flags = flags; ring->mutex = NULL; ring->space_semaphore = NULL; @@ -153,16 +155,21 @@ dmod_dm_sw_ring_api_declaration(1.0, void, _destroy, (dm_sw_ring_t ring)) if (lock_ring(ring)) { ring->magic = 0; + void* mutex = ring->mutex; + ring->mutex = NULL; - if (ring->mutex != NULL) + if (mutex != NULL) + { + Dmod_Mutex_Unlock(mutex); + Dmod_Mutex_Delete(mutex); + } + else { - Dmod_Mutex_Delete(ring->mutex); + Dmod_ExitCritical(); } Dmod_Free(ring->buffer); Dmod_Free(ring); - - // No need to unlock since the instance is being destroyed } } @@ -243,14 +250,7 @@ dmod_dm_sw_ring_api_declaration(1.0, dm_sw_ring_capacity_t, _size, (dm_sw_ring_t dm_sw_ring_capacity_t size = 0; if(lock_ring(ring)) { - if (ring->tail >= ring->head) - { - size = ring->tail - ring->head; - } - else - { - size = ring->capacity - (ring->head - ring->tail); - } + size = ring->count; unlock_ring(ring); } return size; @@ -312,6 +312,7 @@ dmod_dm_sw_ring_api_declaration(1.0, int32_t, _clear, (dm_sw_ring_t ring)) { ring->head = 0; ring->tail = 0; + ring->count = 0; result = 0; // Success unlock_ring(ring); } @@ -433,14 +434,7 @@ static bool validate_ring(dm_sw_ring_t ring) */ static dm_sw_ring_capacity_t available_space(dm_sw_ring_t ring) { - if (ring->tail >= ring->head) - { - return ring->capacity - (ring->tail - ring->head); - } - else - { - return ring->head - ring->tail; - } + return ring->capacity - ring->count; } /** @@ -450,14 +444,7 @@ static dm_sw_ring_capacity_t available_space(dm_sw_ring_t ring) */ static dm_sw_ring_capacity_t available_data(dm_sw_ring_t ring) { - if (ring->tail >= ring->head) - { - return ring->tail - ring->head; - } - else - { - return ring->capacity - (ring->head - ring->tail); - } + return ring->count; } /** @@ -467,7 +454,7 @@ static dm_sw_ring_capacity_t available_data(dm_sw_ring_t ring) */ static bool is_full(dm_sw_ring_t ring) { - return available_space(ring) == 0; + return ring->count == ring->capacity; } /** @@ -477,7 +464,7 @@ static bool is_full(dm_sw_ring_t ring) */ static bool is_empty(dm_sw_ring_t ring) { - return ring->head == ring->tail; + return ring->count == 0; } /** @@ -489,6 +476,7 @@ static void put_byte(dm_sw_ring_t ring, uint8_t data) { ring->buffer[ring->tail] = data; ring->tail = (ring->tail + 1) % ring->capacity; + ring->count++; } /** @@ -500,6 +488,7 @@ static uint8_t get_byte(dm_sw_ring_t ring) { uint8_t data = ring->buffer[ring->head]; ring->head = (ring->head + 1) % ring->capacity; + ring->count--; return data; } @@ -520,6 +509,7 @@ static void discard(dm_sw_ring_t ring, dm_sw_ring_capacity_t length) wait_for_data(ring, length); ring->head = (ring->head + length) % ring->capacity; + ring->count -= length; } @@ -631,13 +621,10 @@ static dm_sw_ring_capacity_t peek_data(dm_sw_ring_t ring, uint8_t* buffer, dm_sw { dm_sw_ring_capacity_t peeked = 0; dm_sw_ring_capacity_t index = ring->head; + dm_sw_ring_capacity_t available = ring->count; - for (peeked = 0; peeked < length; peeked++) + for (peeked = 0; peeked < length && peeked < available; peeked++) { - if (index == ring->tail) - { - break; // Buffer is empty - } buffer[peeked] = ring->buffer[index]; index = (index + 1) % ring->capacity; }