项目地址:
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)
项目文件目录如下
实例代码
首先我们用帮助文档中的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);
}
}
发现是可以正常编译运行的,说明我们可以使用这个开源库了。
在这个环形缓冲库中存在一个单元测试模块,单元测试使用的是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单元测试框架的三个文件加入到我们的项目中
将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);
}
运行之后
可以看到,我们测试的函数都通过了。