【C语言开源库】在CLion上使用一个轻量的适合嵌入式系统的环形缓冲库ring buffer 和C语言Unity单元测试框架

  • Post author:
  • Post category:其他


项目地址:

ring buffer

documentation:

LwRB latest-develop documentation



Features

  • Written in ANSI C99, compatible with

    size_t

    for size data types
  • Platform independent, no architecture specific code
  • FIFO (First In First Out) buffer implementation
  • No dynamic memory allocation, data is static array
  • Uses optimized memory copy instead of loops to read/write data from/to memory
  • Thread safe when used as pipe with single write and single read entries
  • Interrupt safe when used as pipe with single write and single read entries
  • Suitable for DMA transfers from and to memory with zero-copy overhead between buffer and application memory
  • Supports data peek, skip for read and advance for write
  • Implements support for event notifications
  • User friendly MIT license

该库其实只依赖两个文件:

lwrb.c



lwrb.h

(之前文件名是

ringbuff.c



ringbuff.h

,不知道为什么又改了文件名和函数名)

我们只需要将这两个文件添加到我们的项目中即可。不过注意要改一下lwrb.c中的头文件包含

#include "lwrb/lwrb.h"  改成 #include "lwrb.h" 

因为CLion使用cmake来管理的,我们还要在CMakeLists.txt中添加lwrb.c

cmake_minimum_required(VERSION 3.21)
project(ringbuffer_clion C)

set(CMAKE_C_STANDARD 99)

add_executable(ringbuffer_clion main.c  lwrb.c)

项目文件目录如下

image-20210730191407449

实例代码

首先我们用帮助文档中的Example code来测试一下是否可以正常使用,修改main.c

#include <stdio.h>
#include "lwrb.h"

int main() {
    /* Declare rb instance & raw data */
    lwrb_t buff;
    uint8_t buff_data[8];

    /* Application variables */
    uint8_t data[2];
    size_t len;

    /* Application code ... */
    lwrb_init(&buff, buff_data, sizeof(buff_data)); /* Initialize buffer */

    /* Write 4 bytes of data */
    lwrb_write(&buff, "0123", 4);

    /* Try to read buffer */
    /* len holds number of bytes read */
    /* Read until len == 0, when buffer is empty */
    while ((len = lwrb_read(&buff, data, sizeof(data))) > 0) {
            printf("Successfully read %d bytes\r\n", (int)len);
        }
}

image-20210730191431168

发现是可以正常编译运行的,说明我们可以使用这个开源库了。


在这个环形缓冲库中存在一个单元测试模块,单元测试使用的是Unity测试框架。

Unity测试框架GitHub地址:

Unity

Unity学习教程:

Unity单元测试框架



C单元测试Unity

Unity是一个单元测试框架,Unity设计者团队的目标是让它保持

小型化和功能性

。核心的

Unity测试框架只有三个文件

:单个C文件和两个头文件。Unity提供了函数和宏,使得单元测试更加容易。

Unity被设计成跨平台,它努力坚持C标准,同时仍然支持许多违法规则的嵌入式C编译器。Unity可以在许多编译器环境中使用,比如GCC,IAR,Clang,Green Hills,Microchip, MS Visual Studio。适配Unity在一个新的目标平台协同工作并不需要很多工作量。

我们将Unity单元测试框架的三个文件加入到我们的项目中

image-20210730224842908

将main.c函数修改成test.c中的内容

/**
 * @file test.c
 *
 * Unit tests for the lwrb library
 *
 * @author Tofik Sonono (tofik@sonono.me)
 *
 */

/*======= Includes ==========================================================*/

#include <stdint.h>
#include <stdlib.h>
#include "unity.h"
#include "lwrb.h"

/*======= Local Macro Definitions ===========================================*/
/*======= Local function prototypes =========================================*/

void basic_read_and_write(lwrb_t *buff, uint8_t *data_to_write, size_t data_size);

/*======= Local variable declarations =======================================*/
/*======= Global function implementations ===================================*/

/* Requires a definition for Unity to compile */

void setUp(void) { }

void tearDown(void) { }

/*======= Tests ==============================================================*/

void testNullInputToInit_should_fail(void) {
    uint8_t ret;
    lwrb_t buff = { 0 };
    uint8_t buff_data[1];

    ret = lwrb_init(NULL, buff_data, sizeof(buff_data));
    TEST_ASSERT_EQUAL(0, ret);

    ret = lwrb_init(&buff, NULL, sizeof(buff_data));
    TEST_ASSERT_EQUAL(0, ret);

    ret = lwrb_init(&buff, buff_data, 0);
    TEST_ASSERT_EQUAL(0, ret);

    ret = lwrb_is_ready(&buff);
    TEST_ASSERT_EQUAL(0, ret);
}

void testNormalInputToInit_should_succeed(void) {
    uint8_t ret;
    lwrb_t buff = { 0 };
    uint8_t buff_data[1];

    ret = lwrb_init(&buff, buff_data, sizeof(buff_data));
    TEST_ASSERT_EQUAL(1, ret);

    ret = lwrb_is_ready(&buff);
    TEST_ASSERT_EQUAL(1, ret);
}

void testAddElementsToQueueAndRead_should_succeed(void) {
    uint8_t data_to_write[] = {0, 1, 2, 3, 4, 5, 6, 7};
    lwrb_t buff = { 0 };
    basic_read_and_write(&buff, data_to_write, sizeof(data_to_write));
}

void testAddElementsToQueueAndReadAndVerifyEmpty_should_succeed(void) {
    uint8_t data_to_write[] = {0, 1, 2, 3, 4, 5, 6, 7};
    lwrb_t buff = { 0 };
    basic_read_and_write(&buff, data_to_write, sizeof(data_to_write));

    size_t n_free_bytes = lwrb_get_free(&buff);
    TEST_ASSERT_EQUAL(sizeof(data_to_write), n_free_bytes);
}

void testAddElementsToQueueAndReadTooSmallBuffer_should_fail(void) {
    uint8_t data_to_write[] = {0, 1, 2, 3, 4, 5, 6, 7};
    lwrb_t buff = { 0 };

    uint8_t ret;
    uint8_t buff_data[sizeof(data_to_write)];

    ret = lwrb_init(&buff, buff_data, sizeof(buff_data));
    TEST_ASSERT_EQUAL(1, ret);

    ret = lwrb_is_ready(&buff);
    TEST_ASSERT_EQUAL(1, ret);

    size_t  n_written = lwrb_write(&buff, data_to_write, sizeof(data_to_write));
    TEST_ASSERT_EQUAL(sizeof(data_to_write) - 1, n_written);
}

/*======= Main ===============================================================*/

int main (void) {
    UNITY_BEGIN();
    RUN_TEST(testNullInputToInit_should_fail);
    RUN_TEST(testNormalInputToInit_should_succeed);
    RUN_TEST(testAddElementsToQueueAndRead_should_succeed);
    RUN_TEST(testAddElementsToQueueAndReadAndVerifyEmpty_should_succeed);
    RUN_TEST(testAddElementsToQueueAndReadTooSmallBuffer_should_fail);
    return UNITY_END();
}

/*======= Local function implementations =====================================*/

void basic_read_and_write(lwrb_t *buff, uint8_t *data_to_write, size_t data_size) {
    uint8_t ret;
    size_t buffer_size = (sizeof(uint8_t) * data_size) + 1;
    uint8_t *buff_data = malloc(buffer_size);

    ret = lwrb_init(buff, buff_data, buffer_size);
    TEST_ASSERT_EQUAL(1, ret);

    ret = lwrb_is_ready(buff);
    TEST_ASSERT_EQUAL(1, ret);

    size_t  n_written = lwrb_write(buff, data_to_write, sizeof(data_to_write));
    TEST_ASSERT_EQUAL(sizeof(data_to_write), n_written);

    size_t n_bytes_in_queue = lwrb_get_full(buff);
    TEST_ASSERT_EQUAL(n_written, n_bytes_in_queue);

    uint8_t read_buffer[sizeof(data_to_write)];
    size_t n_read = lwrb_read(buff, read_buffer, n_bytes_in_queue);
    TEST_ASSERT_EQUAL(n_bytes_in_queue, n_read);

    TEST_ASSERT_EQUAL_UINT8_ARRAY(data_to_write, read_buffer, sizeof(data_to_write));

    free(buff_data);
}

运行之后

image-20210730225027192

可以看到,我们测试的函数都通过了。



版权声明:本文为qq_41854911原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。