一常用的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