commit 966fed011ccef41f8ff19404289adb659987132f Author: guishenking Date: Fri Aug 15 17:41:19 2025 +0800 新增动态申请内存方法,可进行内存回收。完善注释 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f3d6549 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/build/ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100755 index 0000000..b66b478 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,36 @@ +cmake_minimum_required(VERSION 3.20) + +project(My_ptotocol VERSION 0.1 LANGUAGES CXX C) + +set(CMAKE_C_STANDARD 11) +set(CMAKE_C_COMPILER gcc) +set(CMAKE_C_STANDARD_REQUIRED ON) +# set(CMAKE_CXX_STANDARD 23) +# set(CMAKE_CXX_COMPILER g++) +# set(CMAKE_CXX_STANDARD_REQUIRED ON) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0") + +include_directories( + . + src/lib +) +set(PROJECT_SOURCES + src/main.c + src/lib/kfifo/kfifo.c +) +add_executable(${PROJECT_NAME} + ${PROJECT_SOURCES} +) +target_link_libraries(${PROJECT_NAME} +) + +include(GNUInstallDirs) +install(TARGETS ${PROJECT_NAME} + BUNDLE DESTINATION . + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) \ No newline at end of file diff --git a/src/lib/kfifo/kfifo.c b/src/lib/kfifo/kfifo.c new file mode 100755 index 0000000..6fd955f --- /dev/null +++ b/src/lib/kfifo/kfifo.c @@ -0,0 +1,366 @@ +/** + * @file kfifo.c + * @author guishenking (guishenking@outlook.com) + * @brief + * @version 0.1 + * @date 2025-08-15 + * + * @copyright Copyright (c) 2025 + * + */ + +#include "kfifo.h" +#include +#include + +/** + * @brief 获取 FIFO 数据起始位置 + * + */ +#define KFIFO_POOL_PTR(_fifo) ((uint8_t *)_fifo->pool) + +/** + * @brief 获取写入位置偏移量 + * + * @param[in] fifo + * @return uint32_t + */ +#define kfifo_offset_in(_fifo_ptr) ((_fifo_ptr)->in & (_fifo_ptr)->mask) + +/** + * @brief 获取读取位置偏移量 + * + * @param[in] fifo + * @return uint32_t + */ +#define kfifo_offset_out(_fifo_ptr) ((_fifo_ptr)->out & (_fifo_ptr)->mask) + +/** + * @brief 计算从当前读取位置偏移 _seek 后的新位置在缓冲区中的实际偏移。 + * + */ +#define kfifo_offset_seek_out(_fifo_ptr, _seek) \ + (((_fifo_ptr)->out + (_seek)) & (_fifo_ptr)->mask) + +/** + * @brief 获取写入位置到缓冲区末尾的空间大小 + * + * @param[in] fifo + * @return uint32_t + */ +#define kfifo_remain_in(_fifo_ptr) \ + (kfifo_size(_fifo_ptr) - kfifo_offset_in(_fifo_ptr)) + +/** + * @brief 获取读取位置到缓冲区末尾的空间大小 + * + * @param[in] fifo + * @return uint32_t + */ +#define kfifo_remain_out(_fifo_ptr) \ + (kfifo_size(_fifo_ptr) - kfifo_offset_out(_fifo_ptr)) + +/** + * @brief + * + */ +#define kfifo_remain_seek_out(_fifo_ptr, _seek) \ + (kfifo_size(_fifo_ptr) - kfifo_offset_seek_out(_fifo_ptr, _seek)) + +/** + * @brief 通过申请内存的方式初始化 FIFO,使得内存可回收 + * + * @param size + * @return kfifo_t* + */ +kfifo_t* kfifo_init_dynamic(uint32_t size) { + // 检查size是否为2的幂 + if ((size & (size - 1)) != 0) return NULL; + + // 分配缓冲区和控制结构 + uint8_t *pool = (uint8_t*)malloc(size); + if (!pool) return NULL; + + kfifo_t *fifo = (kfifo_t*)malloc(sizeof(kfifo_t)); + if (!fifo) { free(pool); return NULL; } + + // 初始化结构体 + fifo->in = 0; + fifo->out = 0; + fifo->mask = size - 1; + fifo->pool = pool; + fifo->method = KFIFO_CREATED_METHOD_DYNAMIC; // 设置为动态创建方法 + return fifo; +} + +/** + * @brief 销毁通过申请内存方式创建的 FIFO + * + * @param fifo + * @return true success destroyed memory + * @return false failed Memery was created by static method + */ +bool kfifo_destroy(kfifo_t *fifo) { + if (fifo->method == KFIFO_CREATED_METHOD_STATIC) { + return false; // 静态创建的 FIFO 不允许销毁 + } + if (fifo) { + if(fifo->pool == NULL) { + free(fifo); // 如果 pool 已经是 NULL,直接释放 fifo + return false; // 如果 pool 已经是 NULL,直接返回 + } + free(fifo->pool); + fifo->pool = NULL; // 清空指针,避免悬挂指针 + free(fifo); + fifo = NULL; // 清空指针,避免悬挂指针 + return true; // 成功销毁 + } + return false; // 如果 fifo 是 NULL,直接返回 false +} + +/** + * @brief 初始化FIFO + * @note 使用@kfifo_def 定义的fifo无需调用此函数 + * @param[in] fifo + * @param[in] pool fifo 数据缓冲区 + * @param[in] size fifo 大小,必须是2的幂次 + * @return int + * @retval -1 参数错误、pool对齐错误 + * @retval 0 初始化完成 + */ +bool kfifo_init_static(kfifo_t *fifo, uint8_t *pool, uint32_t size) { + /* 判断参数是否正确 */ + if ((NULL == fifo) || (NULL == pool) || (size & size - 1)) { + return false; + } + fifo->in = 0; + fifo->out = 0; + fifo->pool = pool; + fifo->mask = size - 1; + fifo->method = KFIFO_CREATED_METHOD_STATIC; // 设置为静态创建方法 + + return true; // 初始化成功 +} + +/** + * @brief 向 in 位置写入一个字节 + * + * @param fifo + * @param data + * @return true + * @return false + */ +bool kfifo_put_byte(kfifo_t *fifo, uint8_t data) { + if (NULL == fifo) { + return false; // 参数错误 + } + if (kfifo_is_full(fifo)) { + return false; + } + + KFIFO_POOL_PTR(fifo)[kfifo_offset_in(fifo)] = data; + fifo->in++; + + return true; +} + +/** + * @brief 从 out 位置获取一个字节 + * + * @param fifo + * @param data + * @return int + */ +bool kfifo_get_byte(kfifo_t *fifo, uint8_t *data) { + if ((NULL == fifo) || (NULL == data)) { + return false; // 参数错误 + } + if (kfifo_is_empty(fifo)) { + return false; + } + + *data = KFIFO_POOL_PTR(fifo)[kfifo_offset_out(fifo)]; + fifo->out++; + + return true; +} + +/** + * @brief 写入数据块 + * @note 当fifo空间不足时会对 data 进行截断处理 + * @param[in] fifo + * @param[in] data + * @param[in] len + * @return int 返回写入的数据大小 + */ +int kfifo_in(kfifo_t *fifo, const uint8_t *data, uint32_t len) { + uint32_t avail = kfifo_avail(fifo); + + if (len > avail) { + len = avail; + } + if (len == 0) { + return 0; + } + + if (kfifo_remain_in(fifo) < len) { + memcpy(fifo->pool + kfifo_offset_in(fifo), + data, + kfifo_remain_in(fifo)); + memcpy(fifo->pool, + data + kfifo_remain_in(fifo), + len - kfifo_remain_in(fifo)); + } else { + memcpy(fifo->pool + kfifo_offset_in(fifo), + data, + len); + } + + fifo->in += len; + + return len; +} + +/** + * @brief 读取数据块 + * + * @param fifo + * @param buffer + * @param size + * @return int + */ +int kfifo_out(kfifo_t *fifo, uint8_t *buffer, uint32_t size) { + uint32_t used = kfifo_used(fifo); + if (size > used) { + size = used; + } + if (0 == size) { + return 0; + } + + if (kfifo_remain_out(fifo) < size) { + memcpy(buffer, fifo->pool + kfifo_offset_out(fifo), kfifo_remain_out(fifo)); + memcpy(buffer + kfifo_remain_out(fifo), + fifo->pool, + size - kfifo_remain_out(fifo)); + } else { + memcpy(buffer, + fifo->pool + kfifo_offset_out(fifo), + size); + } + + fifo->out += size; + + return size; +} + +/** + * @brief 获取 fifo 数据指针偏移位置 + * + * @param[in] fifo + * @param[in] ptr + * @return int 可连续读取的数据数量 + * @retval 0 fifo is empty + */ +int kfifo_peek(kfifo_t *fifo, const uint8_t **ptr) { + int linear; + + *ptr = NULL; + + if (kfifo_is_empty(fifo)) { + return 0; + } + + *ptr = &KFIFO_POOL_PTR(fifo)[kfifo_offset_out(fifo)]; + if (kfifo_offset_in(fifo) <= kfifo_offset_out(fifo)) { + linear = kfifo_remain_out(fifo);// 数据在缓冲区末尾 + } else { + linear = kfifo_used(fifo);// 数据未跨缓冲区末尾 + } + + return linear; +} + +/** + * @brief 获取偏移 seek 后的数据指针(模拟读取后位置)。 + * + * @param fifo + * @param ptr + * @param seek + * @return int + */ +int kfifo_peek_seek(kfifo_t *fifo, const uint8_t **ptr, uint32_t seek) { + *ptr = NULL; + + if (kfifo_used(fifo) < seek) { + return 0; + } + + // *ptr = &KFIFO_POOL_PTR(fifo)[kfifo_offset_seek_out(fifo, seek)]; + *ptr = (uint8_t*)fifo->pool + kfifo_offset_seek_out(fifo, seek); + if (kfifo_remain_out(fifo) > seek) { + seek = kfifo_remain_seek_out(fifo, seek); + } else { + seek = kfifo_used(fifo) - seek; + } + + return seek; +} + +/** + * @brief 复制数据到 buffer 但不移动 out 指针。 + * + * @param[in] fifo + * @param[in] buffer 存储数据的缓冲区 + * @param[in] size 需要复制的数据量 + * @return int + * @return -1 参数错误 + */ +int kfifo_peek_block(kfifo_t *fifo, uint8_t *buffer, uint32_t size) { + int temp; + + if ((NULL == fifo) || (NULL == buffer) || (0 == size)) { + return -1; + } + + /* FIFO 中的数据量 */ + temp = kfifo_used(fifo); + if (!temp) { + return 0; + } + + if (size > temp) { + size = temp; + } + + temp = kfifo_remain_out(fifo); + + if (size > temp) { + memcpy(buffer, fifo->pool + kfifo_offset_out(fifo), temp); + memcpy(buffer + temp, + fifo->pool, + size - temp); + } else { + memcpy(buffer, + fifo->pool + kfifo_offset_out(fifo), + size); + } + + return size; +} + +/** + * @brief 丢弃seek个字节 + * + * @param fifo + * @param seek 偏移量 + * @return int + */ +int kfifo_seek(kfifo_t *fifo, uint32_t seek) { + if (kfifo_used(fifo) < seek) { + seek = kfifo_used(fifo); + } + + fifo->out += seek; + return seek; +} diff --git a/src/lib/kfifo/kfifo.h b/src/lib/kfifo/kfifo.h new file mode 100755 index 0000000..7b119e8 --- /dev/null +++ b/src/lib/kfifo/kfifo.h @@ -0,0 +1,143 @@ +/** + * @file kfifo.h + * @author guishenking (guishenking@outlook.com) + * @brief + * @version 0.1 + * @date 2025-08-15 + * + * @copyright Copyright (c) 2025 + * + */ + +#ifndef _KFIFO_H_ +#define _KFIFO_H_ + +#include +#include + +enum kfifo_created_method { + KFIFO_CREATED_METHOD_STATIC = 0, /*!< 静态创建 */ + KFIFO_CREATED_METHOD_DYNAMIC, /*!< 动态创建 */ +}; + +/** + * @brief kfifo 结构定义 + * + */ +typedef struct kfifo { + uint32_t in; /*!< 输入数据下标, 对于单片机使用 volatile 修饰 */ + uint32_t out; /*!< 输出数据下标, 对于单片机使用 volatile 修饰 */ + uint32_t mask;/*!< 缓冲区大小掩码, size - 1 */ + uint8_t *pool;/*!< 数据缓冲区指针 */ + enum kfifo_created_method method;/*!< FIFO 创建方法 */ +}kfifo_t; + +/** + * @brief kfifo 初始化器 + * + * @param[in] _pool FIFO数据缓冲区 + * @param[in] _size 缓冲区大小 + */ +#define kfifo_initializer(_pool, _size) \ + { 0, 0, _size - 1, _pool, KFIFO_CREATED_METHOD_STATIC, } + +/** + * @brief 定义 KFIFO + * + * @param[in] _name FIFO名称 + * @param[in] _size 缓冲区大小,必须是2的幂次 + */ +#define kfifo_def(_name, _size) \ + static uint8_t _##_name##_pool[_size]; \ + static kfifo_t _name = kfifo_initializer(_##_name##_pool, _size)//初始化fifo + +#ifdef __cplusplus + extern "C" { +#endif +//静态创建fifo +bool kfifo_init_static(kfifo_t *fifo, uint8_t *pool, uint32_t size); +//动态创建fifo +kfifo_t* kfifo_init_dynamic(uint32_t size); +//销毁动态创建的fifo +bool kfifo_destroy(kfifo_t *fifo) ; + +//向fifo写入一个字节 +bool kfifo_put_byte(kfifo_t *fifo, uint8_t data); + +//从fifo读取一个字节 +bool kfifo_get_byte(kfifo_t *fifo, uint8_t *data); + +//写入数据块 +int kfifo_in(kfifo_t *fifo, const uint8_t *data, uint32_t len); + +//读取数据块 +int kfifo_out(kfifo_t *fifo, uint8_t *data, uint32_t size); + +//获取fifo数据指针 +int kfifo_peek(kfifo_t *fifo, const uint8_t **ptr); + +//从获取偏移位置的数据指针 +int kfifo_peek_seek(kfifo_t *fifo, const uint8_t **ptr, uint32_t seek); + +//从fifo读取数据块,不改变 fifo 状态 +int kfifo_peek_block(kfifo_t *fifo, uint8_t *buffer, uint32_t size); + +//丢弃fifo部分数据 +int kfifo_seek(kfifo_t *fifo, uint32_t seek); + + +/** + * @brief 清空 FIFO + * + */ +#define kfifo_clear(_fifo_ptr) \ + do { \ + (_fifo_ptr)->in = 0; \ + (_fifo_ptr)->out = 0; \ + } while(0) + +/** + * @brief 获取fifo大小 + * + * @param[in] fifo + * @return uint32_t + */ +#define kfifo_size(_fifo_ptr) ((_fifo_ptr)->mask + 1) + +/** + * @brief 获取当前存储的数据量 + * + * @param[in] fifo + * @return uint32_t + */ +#define kfifo_used(_fifo_ptr) \ + (((kfifo_size(_fifo_ptr)) + (_fifo_ptr)->out) == (_fifo_ptr)->in \ + ? kfifo_size(_fifo_ptr) \ + : (((_fifo_ptr)->in - (_fifo_ptr)->out) & (_fifo_ptr)->mask)) + +/** + * @brief 获取空闲空间大小 + * + * @param[in] fifo + * @return uint32_t + */ +#define kfifo_avail(_fifo_ptr) (kfifo_size(_fifo_ptr) - kfifo_used(_fifo_ptr)) + +/** + * @brief 判断 FIFO 是否已满 + * + */ +#define kfifo_is_full(_fifo_ptr) (kfifo_avail(_fifo_ptr) == 0) + +/** + * @brief 判断 FIFO 是否为空 + * + */ +#define kfifo_is_empty(_fifo_ptr) (kfifo_used(_fifo_ptr) == 0) + +#ifdef __cplusplus + } +#endif + +#endif +/* !_KFIFO_H_ */ diff --git a/src/main.c b/src/main.c new file mode 100755 index 0000000..bc54a62 --- /dev/null +++ b/src/main.c @@ -0,0 +1,40 @@ +/** + * @file main.c + * @author guishenking (guishenking@outlook.com) + * @brief + * @version 0.1 + * @date 2025-07-24 + * + * @copyright Copyright (c) 2025 + * + */ + + +#include "lib/kfifo/kfifo.h" +#include +#include +#include + +kfifo_def(fifo,1024); + + int main(){ + // 示例数据 + uint8_t src_data[] = {0x01, 0x02, 0x03, 0x04, 0x05}; + size_t src_length = sizeof(src_data); + uint8_t dest_data[1024]; + size_t dest_length = sizeof(dest_data); + uint32_t offset; + + memset(dest_data, 0, dest_length); // 清空目标数据缓冲区 + + kfifo_in(&fifo, dest_data, dest_length); // 将数据写入FIFO + + int ret = kfifo_peek_block(&fifo, dest_data, dest_length); // 从FIFO读取数据 + + memset(src_data, 0, src_length); // 清空源数据缓冲区 + + // 解码数据 + kfifo_seek(&fifo, offset); // 根据偏移量调整FIFO读取位置 + + return 0; + } \ No newline at end of file