一常用的buffer程序, buffer为FIFO,支持循环读写,支持边读边写(注意线程安全)。 通过xbuf_pop_xxx函数,能实现栈的功能
xbuf.c如下:
/** * \file xbuf.c * \brief 缓存 * \author 红尘客 * \date 2023-08-11 * \note xbuf_free只能释放由xbuf_create创建的buffer * * - buffer为FIFO,支持循环读写,支持边读边写(注意线程安全)。 \n * - 通过xbuf_pop_xxx函数,能实现栈的功能 \n * - 一个字四个字节,半个字两个字节 \n */ #include <string.h> #include <stdio.h> #include "mm_conf.h" #include "lib_c/xbuf.h" /** \brief 初始化缓存 * \param xb 缓存结构指针 * \param len 缓存存储空间的长度,净数据长度 * \note 此函数需要注意线程安全 */ void xbuf_init(xbuf_t *xb, uint16_t len) { if (xb == NULL) { return; } xb->len = len; xb->count = 0; xb->rdpos = 0; xb->dm = 0; xb->locked = 0; xb->line = 0; xb->string = 0; xb->ud = 0; xb->ftype = BUF_FRAME_TYPE_FULL; } #if LIBC_MM_EN == 1 /** \brief 创建一个缓存 * \param len 缓存存储空间的长度,净数据长度 * \return 创建的缓存 * \note 此函数需要注意线程安全 */ xbuf_t *xbuf_create(uint16_t len) { xbuf_t *xb; xb = (xbuf_t *)MALLOC(sizeof(xbuf_t) + len); if (xb != NULL) { xbuf_init(xb, len); xb->dm = 1; //标记动态内存分配 } return xb; } /** \brief 创建一个缓存 * \param len 缓存存储空间的长度,净数据长度 * \return 创建的缓存 */ xbuf_t *xbuf_create_cp(uint16_t len) { _CRITICAL_VAR_ALLOC(); xbuf_t *xb; XBUF_ENTER_CRITICAL(); xb = xbuf_create(len); XBUF_EXIT_CRITICAL(); return xb; } /** \brief 调整缓存大小 * \param xb 缓存结构指针 * \param len 缓存存储空间的长度,净数据长度 * \return 调整后的缓存 * \note 此函数需要注意线程安全 */ xbuf_t *xbuf_resize(xbuf_t *xb, uint16_t len) { xbuf_t *buf_new = NULL; if (len > 0) { buf_new = xbuf_create(len); } else { FREE(xb); } if (buf_new != NULL) { //复制原来数据 if (xb != NULL) { if (len > xb->len) { len = xb->len; } xbuf_write(buf_new, xb->pl, len); FREE(xb); } } return buf_new; } /** \brief 释放缓存 * \param xb 缓存结构指针 * \note 此函数需要注意线程安全 */ void xbuf_free(xbuf_t *xb) { if (xb == NULL) { return; } if (xb->dm) { FREE(xb); } } /** \brief 释放缓存 * \param xb 缓存结构指针 */ void xbuf_free_cp(xbuf_t *xb) { _CRITICAL_VAR_ALLOC(); XBUF_ENTER_CRITICAL(); xbuf_free(xb); XBUF_EXIT_CRITICAL(); } #endif /** \brief 写数据 * \param xb 缓存结构指针 * \param dat 写入的数据缓存 * \param len 要写入的数据长度 * \return 写入数据量 * \note 超过剩余缓存的数据,会截断数据 */ uint16_t xbuf_write(xbuf_t *xb, const void *dat, uint16_t len) { uint16_t rlen; uint16_t wrpos; if ((xb == NULL) || (dat == NULL) || (xb->locked) || (xb->len == xb->count)) { return 0; } rlen = xb->len - xb->count; if (len > rlen) { len = rlen; } wrpos = (uint32_t)(xb->rdpos + xb->count) % xb->len; rlen = xb->len - wrpos; if (rlen > len) { rlen = len; } memcpy(xb->pl + wrpos, dat, rlen); xb->count += rlen; if (len - rlen > 0) { dat = (const uint8_t *)dat + rlen; rlen = len - rlen; memcpy(xb->pl, dat, rlen); xb->count += rlen; } return len; } /** \brief 写数据 * \param xb 缓存结构指针 * \param dat 写入的数据缓存 * \param len 要写入的数据长度 * \return 写入数据量 * \note 超过剩余缓存的数据,会截断数据 * * 此函数支持多任务写 */ uint16_t xbuf_write_cp(xbuf_t *xb, const void *dat, uint16_t len) { uint16_t ret; _CRITICAL_VAR_ALLOC(); XBUF_ENTER_CRITICAL(); ret = xbuf_write(xb, dat, len); XBUF_EXIT_CRITICAL(); return ret; } /** \brief 读缓存 * \param xb 缓存结构指针 * \param[out] rp 读取数据缓存 * \param len 最大读取长度 * \return 读取是否成功 * \retval !0 实际读取数量,数据有效 * \retval 0 读取失败缓存为空,数据无效 */ uint16_t xbuf_read(xbuf_t *xb, void *rp, uint16_t len) { uint16_t rlen; if ((xb == NULL) || (rp == NULL) || (xb->count == 0)) { return 0; } if (xb->count < len) { len = xb->count; } rlen = xb->len - xb->rdpos; if (rlen > len) { rlen = len; } memcpy(rp, xb->pl + xb->rdpos, rlen); xb->count -= rlen; xb->rdpos = (xb->rdpos + rlen) % xb->len; if (len - rlen > 0) { rp = (uint8_t *)rp + rlen; rlen = len - rlen; memcpy(rp, xb->pl + xb->rdpos, rlen); xb->count -= rlen; xb->rdpos = (xb->rdpos + rlen) % xb->len; } return len; } /** \brief 读缓存 * \param xb 缓存结构指针 * \param[out] rp 读取数据缓存 * \param len 最大读取长度 * \return 读取是否成功 * \retval !0 读取成功,数据有效 * \retval 0 读取失败缓存为空,数据无效 * * 此函数支持多任务读 */ uint16_t xbuf_read_cp(xbuf_t *xb, void *rp, uint16_t len) { uint16_t ret; _CRITICAL_VAR_ALLOC(); XBUF_ENTER_CRITICAL(); ret = xbuf_read(xb, rp, len); XBUF_EXIT_CRITICAL(); return ret; } /** \brief 读最近写入的数据 * \param xb 缓存结构指针 * \param[out] rp 读取数据缓存 * \return 读取是否成功 * \retval 1 读取成功,数据有效 * \retval 0 读取失败缓存为空,数据无效 * * 此函数实现栈的功能 */ uint16_t xbuf_pop_byte(xbuf_t *xb, void *rp) { uint16_t wrpos; if ((xb == NULL) || (xb->count == 0)) { return 0; } wrpos = (uint32_t)(xb->rdpos + xb->count - 1) % xb->len; if (rp != NULL) { *(uint8_t *)rp = xb->pl[wrpos]; } xb->count -= 1; return 1; } /** \brief 读最近写入的数据 * \param xb 缓存结构指针 * \param[out] rp 读取数据缓存 * \param len 最大读取长度 * \return 读取是否成功 * \retval !0 读取成功,数据有效 * \retval 0 读取失败缓存为空,数据无效 * * 此函数实现栈的功能 */ uint16_t xbuf_pop(xbuf_t *xb, void *rp, uint16_t len) { uint16_t i; if ((xb == NULL) || (xb->count == 0)) { return 0; } if (len > xb->count) { len = xb->count; } for (i = 0; i < len; i++) { xbuf_pop_byte(xb, (uint8_t *)rp + i); } return len; } /** \brief 读最近写入的数据 * \param xb 缓存结构指针 * \param[out] rp 读取数据缓存 * \param len 最大读取长度 * \return 读取是否成功 * \retval !0 读取成功,数据有效 * \retval 0 读取失败缓存为空,数据无效 * * 此函数实现栈的功能 */ uint16_t xbuf_pop_cp(xbuf_t *xb, void *rp, uint16_t len) { uint16_t ret; _CRITICAL_VAR_ALLOC(); XBUF_ENTER_CRITICAL(); ret = xbuf_pop(xb, rp, len); XBUF_EXIT_CRITICAL(); return ret; } /** \brief 写缓存 * \param xb 缓存结构指针 * \param dat 写入的数据 * \return 当前缓存数据量 * \retval 0 缓存满或缓存写锁定,写入失败 * \retval 其它 缓存写入成功缓存总字节数 * \note 此函数需要注意线程安全 */ uint16_t xbuf_write_byte(xbuf_t *xb, uint8_t dat) { return xbuf_write(xb, &dat, 1); } /** \brief 写半字 * \param xb 缓存结构指针 * \param dat 写入的数据 * \return 当前缓存数据量 * \retval 0 缓存满或缓存写锁定,写入失败 * \retval 其它 缓存写入成功缓存总字节数 * \note 此函数需要注意线程安全 */ uint16_t xbuf_write_half(xbuf_t *xb, uint16_t dat) { return xbuf_write(xb, &dat, 2); } /** \brief 写一个字 * \param xb 缓存结构指针 * \param dat 写入的数据 * \return 当前缓存数据量 * \retval 0 缓存满或缓存写锁定,写入失败 * \retval 其它 缓存写入成功缓存总字节数 * \note 此函数需要注意线程安全 */ uint16_t xbuf_write_word(xbuf_t *xb, uint32_t dat) { return xbuf_write(xb, &dat, 4); } /** \brief 写缓存-更新标志位 * \param xb 缓存结构指针 * \param dat 写入的数据 * \return 当前缓存数据量 * \retval 0 缓存满或缓存写锁定,写入失败 * \retval 其它 缓存写入成功缓存总字节数 * \note 此函数需要注意线程安全 * */ uint16_t xbuf_write_byte_update_flag(xbuf_t *xb, uint8_t dat) { uint16_t ret; if (xb == NULL) { return 0; } ret = xbuf_write_byte(xb, dat); if (ret) { if (dat == '\n') { xb->line = 1; } else if (dat == '\0') { xb->string = 1; } } return ret; } /** \brief 写缓存-带临界保护 * \param xb 缓存结构指针 * \param dat 写入的数据 * \return 当前缓存数据量 * \retval 0 缓存满或缓存写锁定,写入失败 * \retval 其它 缓存写入成功缓存总字节数 */ uint16_t xbuf_write_byte_cp(xbuf_t *xb, uint8_t dat) { uint16_t ret; _CRITICAL_VAR_ALLOC(); XBUF_ENTER_CRITICAL(); ret = xbuf_write_byte(xb, dat); XBUF_EXIT_CRITICAL(); return ret; } /** \brief 读一个字节 * \param xb 缓存结构指针 * \param[out] rp 读取数据缓存 * \return 读取是否成功 * \retval 1 读取成功,数据有效 * \retval 0 读取失败缓存为空,数据无效 * \note 此函数需要注意线程安全 */ uint16_t xbuf_read_byte(xbuf_t *xb, void *rp) { return xbuf_read(xb, rp, 1); } /** \brief 读半个字 * \param xb 缓存结构指针 * \param[out] rp 读取数据缓存 * \return 读取是否成功 * \retval !0 读取成功,数据有效 * \retval 0 读取失败缓存为空,数据无效 * \note 此函数需要注意线程安全 */ uint16_t xbuf_read_half(xbuf_t *xb, void *rp) { if ((xb == NULL) || (xb->count < 2)) { return 0; } return xbuf_read(xb, rp, 2); } /** \brief 读一个字 * \param xb 缓存结构指针 * \param[out] rp 读取数据缓存 * \return 读取是否成功 * \retval !0 读取成功,数据有效 * \retval 0 读取失败缓存为空,数据无效 * \note 此函数需要注意线程安全 */ uint16_t xbuf_read_word(xbuf_t *xb, void *rp) { if ((xb == NULL) || (xb->count < 4)) { return 0; } return xbuf_read(xb, rp, 4); } /** \brief 读缓存-带临界保护 * \param xb 缓存结构指针 * \param[out] rp 读取数据缓存 * \return 读取是否成功 * \retval 1 读取成功,数据有效 * \retval 0 读取失败缓存为空,数据无效 */ uint16_t xbuf_read_byte_cp(xbuf_t *xb, void *rp) { uint16_t ret; _CRITICAL_VAR_ALLOC(); XBUF_ENTER_CRITICAL(); ret = xbuf_read_byte(xb, rp); XBUF_EXIT_CRITICAL(); return ret; } /** \brief 读最近写入的数据 * \param xb 缓存结构指针 * \param[out] rp 读取数据缓存 * \return 读取是否成功 * \retval 1 读取成功,数据有效 * \retval 0 读取失败缓存为空,数据无效 * * 此函数实现栈的功能 */ uint16_t xbuf_pop_byte_cp(xbuf_t *xb, void *rp) { uint16_t ret; _CRITICAL_VAR_ALLOC(); XBUF_ENTER_CRITICAL(); ret = xbuf_pop_byte(xb, rp); XBUF_EXIT_CRITICAL(); return ret; } /** \brief 缓存重置 * \param xb 缓存结构指针 * \note 此函数需要注意线程安全 */ void xbuf_reset(xbuf_t *xb) { if (xb == NULL) { return; } xb->count = 0; xb->rdpos = 0; xb->locked = 0; xb->line = 0; xb->string = 0; xb->ud = 0; xb->ftype = BUF_FRAME_TYPE_FULL; } /** \brief 写锁定 * \param xb 缓存结构指针 */ void xbuf_lock(xbuf_t *xb) { _CRITICAL_VAR_ALLOC(); if (xb == NULL) { return; } XBUF_ENTER_CRITICAL(); xb->locked = 1; XBUF_EXIT_CRITICAL(); } /** \brief 写解锁 * \param xb 缓存结构指针 */ void xbuf_unlock(xbuf_t *xb) { _CRITICAL_VAR_ALLOC(); if (xb == NULL) { return; } XBUF_ENTER_CRITICAL(); xb->locked = 0; XBUF_EXIT_CRITICAL(); } /** \brief 是否写锁定 * \param xb 缓存结构指针 * \return 是否锁定 * \retval 1 写锁定 * \retval 0 非写锁定 */ uint8_t xbuf_islock(xbuf_t *xb) { uint8_t ret; _CRITICAL_VAR_ALLOC(); if (xb == NULL) { return 1; } XBUF_ENTER_CRITICAL(); ret = xb->locked; XBUF_EXIT_CRITICAL(); return ret; } #if LIBC_MM_EN == 1 /** \brief 格式化写入 * \param xb 缓存结构指针 * \param fmt 格式化字符串 * \param ap 可变参数表 * \return 实际写入字节数量 * \note 在循环读写时,不能使用此函数 */ uint16_t xbuf_vprintf(xbuf_t *xb, const char *fmt, va_list ap) { uint16_t count; char *tbuf; if (xb == NULL) { return 0; } tbuf = MALLOC(XBUF_PRINTF_SIZE); if (xb == NULL) { return 0; } count = vsnprintf(tbuf, XBUF_PRINTF_SIZE, fmt, ap); if (count >= XBUF_PRINTF_SIZE) { count = XBUF_PRINTF_SIZE - 1; } count = xbuf_write(xb, tbuf, count); FREE(tbuf); return count; } /** \brief 格式化写入 * \param xb 缓存结构指针 * \param fmt 格式化字符串 * \param ... 可变参数 * \return 实际写入字节数量 * \note 在循环读写时,不能使用此函数 */ uint16_t xbuf_printf(xbuf_t *xb, const char *fmt, ...) { va_list vp; uint16_t cnt; if (xb == NULL) { return 0; } va_start(vp, fmt); cnt = xbuf_vprintf(xb, fmt, vp); va_end(vp); return cnt; } #endif /* LIBC_MM_EN */
xbuf.h:
/** * \file xbuf.h * \brief 缓存头文件 * \author 红尘客 * \date 2023-08-11 * * xbuf_write_update_flag更新标志位后,如果读出则相应标志位不会改变。 */ #ifndef __XBUF_H__ #define __XBUF_H__ #include <stdint.h> #include "lib_common.h" #define XBUF_PRINTF_SIZE 256 ///< PRINTF缓存长度 #define XBUF_ENTER_CRITICAL() _ENTER_CRITICAL() ///< 进入临界段,禁止中断,与CPU和编译器有关 #define XBUF_EXIT_CRITICAL() _EXIT_CRITICAL() ///< 退出临界段,允计中断,与CPU和编译器有关 #define XBUF_EXTERN(buf_name) extern xbuf_t *buf_name /** \brief 定义一个buffer * \param buf_name 缓存名称 * \param buf_len 缓存长度,净数据长度 * \note 这是一组定义,必须放在程序的定义和声明位置 * * 会产一个名称为__buf_buf_name的数组, 会产生一个buffer指针名称为buf_name, \n * 并指向定义的数组,此定义需要初始化。 */ #define XBUF_DEFINE(buf_name, buf_len) \ _ALIGN(4) static uint8_t __buf_ ## buf_name[sizeof(xbuf_t) + (buf_len)]; \ xbuf_t *buf_name = (xbuf_t *)&__buf_ ## buf_name /** \brief 初始化一个buffer * \note 只能初始化由XBUF_DEFINE定义的buffer */ #define XBUF_INIT(buf_name) xbuf_init(buf_name, sizeof(__buf_ ## buf_name) - sizeof(xbuf_t)) /** \brief 帧类型 */ enum { BUF_FRAME_TYPE_FULL, ///< 完整的数据帧 BUF_FRAME_TYPE_PORTION, ///< 部分的数据帧 BUF_FRAME_TYPE_END, ///< 部分的数据帧的最后一帧 }; /** \brief 缓存数据结构 */ typedef struct { uint16_t len; ///< 缓存总长度,净数据长度 uint16_t count; ///< 缓存当前字节数 uint16_t rdpos; ///< 读取位置 uint8_t ud; ///< 用户数据 //标志 uint8_t dm : 1; ///< 动态内存分配,此位不受复位函数影响 uint8_t locked : 1; ///< 缓存写锁定,读不锁定 uint8_t line : 1; ///< 行标志位,收到'\n'字符,此标志置位,必须由xbuf_write_update_flag \n ///< 方法写入时才能影响此位 uint8_t string : 1; ///< 收到'\0'字符,必须由xbuf_write_update_flag方法写入时才能影响此位 uint8_t ftype : 3; ///< 帧类型,用于标记多帧数据 uint8_t pl[]; ///< 缓存开始 } xbuf_t; #define xbuf_write_half_be(xb, dat) xbuf_write_half((xb), htons((dat))); ///< 以大端模式写入半字 #define xbuf_write_word_be(xb, dat) xbuf_write_word((xb), htonl((dat))); ///< 以大端模式写一个字 extern void xbuf_init(xbuf_t *xb, uint16_t length); extern xbuf_t *xbuf_create(uint16_t len); extern xbuf_t *xbuf_create_cp(uint16_t len); extern xbuf_t *xbuf_resize(xbuf_t *xb, uint16_t len); extern void xbuf_free(xbuf_t *xb); extern void xbuf_free_cp(xbuf_t *xb); extern uint16_t xbuf_write(xbuf_t *xb, const void *dat, uint16_t len); extern uint16_t xbuf_write_cp(xbuf_t *xb, const void *dat, uint16_t len); extern uint16_t xbuf_read(xbuf_t *xb, void *rp, uint16_t len); extern uint16_t xbuf_read_cp(xbuf_t *xb, void *rp, uint16_t len); extern uint16_t xbuf_pop(xbuf_t *xb, void *rp, uint16_t len); extern uint16_t xbuf_write_byte(xbuf_t *xb, uint8_t c); extern uint16_t xbuf_write_byte_cp(xbuf_t *xb, uint8_t c); extern uint16_t xbuf_write_half(xbuf_t *xb, uint16_t dat); extern uint16_t xbuf_write_word(xbuf_t *xb, uint32_t dat); extern uint16_t xbuf_write_byte_update_flag(xbuf_t *xb, uint8_t dat); extern uint16_t xbuf_read_byte(xbuf_t *xb, void *rp); extern uint16_t xbuf_read_byte_cp(xbuf_t *xb, void *rp); extern uint16_t xbuf_read_half(xbuf_t *xb, void *rp); extern uint16_t xbuf_read_word(xbuf_t *xb, void *rp); extern uint16_t xbuf_pop_byte(xbuf_t *xb, void *rp); extern uint16_t xbuf_pop_byte_cp(xbuf_t *xb, void *rp); extern void xbuf_reset(xbuf_t *xb); extern void xbuf_lock(xbuf_t *xb); extern void xbuf_unlock(xbuf_t *xb); extern uint8_t xbuf_islock(xbuf_t *xb); extern uint16_t xbuf_printf(xbuf_t *xb, const char *fmt, ...); extern uint16_t xbuf_vprintf(xbuf_t *xb, const char *fmt, va_list ap); #endif