一款常用buffer程序
2024-11-06
红尘客
标签: buffer 缓存

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


可能会用到的工具/仪表
本站简介 | 意见建议 | 免责声明 | 版权声明 | 联系我们
CopyRight@2024-2039 嵌入式资源网
蜀ICP备2021025729号