热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

项目地址:ringbufferdocumentation:LwRBlatest-developdocumentationFeaturesWritt

项目地址: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.clwrb.h (之前文件名是ringbuff.cringbuff.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
#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
#include
#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

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


推荐阅读
  • 本文介绍了C++中省略号类型和参数个数不确定函数参数的使用方法,并提供了一个范例。通过宏定义的方式,可以方便地处理不定参数的情况。文章中给出了具体的代码实现,并对代码进行了解释和说明。这对于需要处理不定参数的情况的程序员来说,是一个很有用的参考资料。 ... [详细]
  • 如何自行分析定位SAP BSP错误
    The“BSPtag”Imentionedintheblogtitlemeansforexamplethetagchtmlb:configCelleratorbelowwhichi ... [详细]
  • 本文介绍了使用kotlin实现动画效果的方法,包括上下移动、放大缩小、旋转等功能。通过代码示例演示了如何使用ObjectAnimator和AnimatorSet来实现动画效果,并提供了实现抖动效果的代码。同时还介绍了如何使用translationY和translationX来实现上下和左右移动的效果。最后还提供了一个anim_small.xml文件的代码示例,可以用来实现放大缩小的效果。 ... [详细]
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 本文介绍了为什么要使用多进程处理TCP服务端,多进程的好处包括可靠性高和处理大量数据时速度快。然而,多进程不能共享进程空间,因此有一些变量不能共享。文章还提供了使用多进程实现TCP服务端的代码,并对代码进行了详细注释。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • 本文介绍了PE文件结构中的导出表的解析方法,包括获取区段头表、遍历查找所在的区段等步骤。通过该方法可以准确地解析PE文件中的导出表信息。 ... [详细]
  • 本文为Codeforces 1294A题目的解析,主要讨论了Collecting Coins整除+不整除问题。文章详细介绍了题目的背景和要求,并给出了解题思路和代码实现。同时提供了在线测评地址和相关参考链接。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • JavaSE笔试题-接口、抽象类、多态等问题解答
    本文解答了JavaSE笔试题中关于接口、抽象类、多态等问题。包括Math类的取整数方法、接口是否可继承、抽象类是否可实现接口、抽象类是否可继承具体类、抽象类中是否可以有静态main方法等问题。同时介绍了面向对象的特征,以及Java中实现多态的机制。 ... [详细]
  • 本文介绍了C函数ispunct()的用法及示例代码。ispunct()函数用于检查传递的字符是否是标点符号,如果是标点符号则返回非零值,否则返回零。示例代码演示了如何使用ispunct()函数来判断字符是否为标点符号。 ... [详细]
author-avatar
继续微笑丶保持硪的骄傲_195
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有