基于Linux的kfifo移植到STM32(支持os的互斥访问)
关于kfifo
kfifo是内核里面的一个First In First Out数据布局,它接纳环形循环队列的数据布局来实现;它提供一个无边界的字节省服务,最重要的一点是,它使用并行无锁编程技术,即当它用于只有一个入队线程和一个出队线程的场情时,两个线程可以并发操作,而不必要任何加锁活动,就可以包管kfifo的线程安全。
具体什么是环形缓冲区,请看我以前的文章
说明
关于kfifo的相干概念我不会介绍,有爱好可以看他的相干文档,我只将其实现过程移植重写,移植到实用stm32开辟板上,而且按照我个人习惯重新定名,RingBuff->意为环形缓冲区
RingBuff_t
环形缓冲区的布局体成员变量,具体寄义看注释。
buffer: 用于存放数据的缓存
size: buffer空间的巨细
in, out: 和buffer一起构成一个循环队列。 in指向buffer中队头,而且out指向buffer中的队尾 - <code>typedef struct ringbuff
- {
- uint8_t *buffer; /* 数据区域 */
- uint32_t size; /* 环形缓冲区巨细 */
- uint32_t in; /* 数据入队指针 (in % size) */
- uint32_t out; /* 数据出队指针 (out % size) */
- #if USE_MUTEX
- MUTEX_T *mutex; /* 支持rtos的互斥 */
- #endif
- }RingBuff_t ;</code>
复制代码Create_RingBuff
创建一个环形缓冲区,为了顺应后续对缓冲区入队出队的高效操作,环形缓冲区的巨细应为2^n字节,
如果不是这个巨细,则体系默认裁剪以对应缓冲区字节。
当然还可以优化,不外我现在并未做,思绪如下:如果体系支持动态分配内存,则向上对齐,制止浪费内存空间,否则就按照我默认的向下对齐,当内存越大,对齐导致内存走漏则会越多。对齐接纳的函数是roundup_pow_of_two 。如果体系支持互斥量,那么还将创建一个互斥量用来做互斥访问,防止多线程同时使用导致数据丢失。 - <code>/************************************************************
- * @brief Create_RingBuff
- * @param rb:环形缓冲区句柄
- * buffer:环形缓冲区的数据区域
- * size:环形缓冲区的巨细,缓冲区巨细要为2^n
- * @return err_t:ERR_OK表现创建成功,其他表现失败
- * @author jiejie
- * @github https://github.com/jiejieTop
- * @date 2018-xx-xx
- * @version v1.0
- * @note 用于创建一个环形缓冲区
- ***********************************************************/
- err_t Create_RingBuff(RingBuff_t* rb,
- uint8_t *buffer,
- uint32_t size
- )
- {
- if((rb == NULL)||(buffer == NULL)||(size == 0))
- {
- PRINT_ERR("data is null!");
- return ERR_NULL;
- }
-
- PRINT_DEBUG("ringbuff size is %d!",size);
- /* 缓冲区巨细必须为2^n字节,体系会强制转换,
- 否则大概会导致指针访问非法地点。
- 空间巨细越大,强转时丢失内存越多 */
- if(size&(size - 1))
- {
- size = roundup_pow_of_two(size);
- PRINT_DEBUG("change ringbuff size is %d!",size);
- }
- rb->buffer = buffer;
- rb->size = size;
- rb->in = rb->out = 0;
- #if USE_MUTEX
- /* 创建信号量不成功 */
- if(!create_mutex(rb->mutex))
- {
- PRINT_ERR("create mutex fail!");
- ASSERT(ASSERT_ERR);
- return ERR_NOK;
- }
- #endif
- PRINT_DEBUG("create ringBuff ok!");
- return ERR_OK;
- }</code>
复制代码roundup_pow_of_two- <code>/************************************************************
- * @brief roundup_pow_of_two
- * @param size:通报进来的数据长度
- * @return size:返回处理惩罚之后的数据长度
- * @author jiejie
- * @github https://github.com/jiejieTop
- * @date 2018-xx-xx
- * @version v1.0
- * @note 用于处理惩罚数据,使数据长度必须为 2^n
- * 如果不是,则转换,丢弃多余部分,如
- * roundup_pow_of_two(66) -> 返回 64
- ***********************************************************/
- static unsigned long roundup_pow_of_two(unsigned long x)
- {
- return (1 << (fls(x-1)-1)); //向下对齐
- //return (1UL << fls(x - 1)); //向上对齐,用动态内存可用使用
- }</code>
复制代码Delete_RingBuff
删除一个环形缓冲区,删除之后,缓冲区真正存储地点是不会被改变的(现在我是使用自定义数组做缓冲区的),但是删除之后,就无法对缓冲区举行读写操作。而且如果支持os的话,创建的互斥量会被删除。 - <code>/************************************************************
- * @brief Delete_RingBuff
- * @param rb:环形缓冲区句柄
- * @return err_t:ERR_OK表现成功,其他表现失败
- * @author jiejie
- * @github https://github.com/jiejieTop
- * @date 2018-xx-xx
- * @version v1.0
- * @note 删除一个环形缓冲区
- ***********************************************************/
- err_t Delete_RingBuff(RingBuff_t *rb)
- {
- if(rb == NULL)
- {
- PRINT_ERR("ringbuff is null!");
- return ERR_NULL;
- }
-
- rb->buffer = NULL;
- rb->size = 0;
- rb->in = rb->out = 0;
- #if USE_MUTEX
- if(!deleta_mutex(rb->mutex))
- {
- PRINT_DEBUG("deleta mutex is fail!");
- return ERR_NOK;
- }
- #endif
- return ERR_OK;
- }</code>
复制代码Write_RingBuff
向环形缓冲区写入指定命据,支持线程互斥访问。用户想要写入缓冲区的数据长度不肯定是真正入队的长度,在完成的时间还要看看返回值是否与用户必要的长度同等~
这个函数很故意思,也是比力高效的入队操作,将指定区域的数据拷贝到指定的缓冲区中,过程看注释即可 - <code>/************************************************************
- * @brief Write_RingBuff
- * @param rb:环形缓冲区句柄
- * @param wbuff:写入的数据起始地点
- * @param len:写入数据的长度(字节)
- * @return len:实际写入数据的长度(字节)
- * @author jiejie
- * @github https://github.com/jiejieTop
- * @date 2018-xx-xx
- * @version v1.0
- * @note 这个函数会从buff空间拷贝len字节长度的数据到
- rb环形缓冲区中的空闲空间。
- ***********************************************************/
- uint32_t Write_RingBuff(RingBuff_t *rb,
- uint8_t *wbuff,
- uint32_t len)
- {
- uint32_t l;
- #if USE_MUTEX
- /* 请求互斥量,成功才华举行ringbuff的访问 */
- if(!request_mutex(rb->mutex))
- {
- PRINT_DEBUG("request mutex fail!");
- return 0;
- }
- else /* 获取互斥量成功 */
- {
- #endif
- len = min(len, rb->size - rb->in + rb->out);
- /* 第一部分的拷贝:从环形缓冲区写入数据直至缓冲区末了一个地点 */
- l = min(len, rb->size - (rb->in & (rb->size - 1)));
- memcpy(rb->buffer + (rb->in & (rb->size - 1)), wbuff, l);
- /* 如果溢出则在缓冲区头写入剩余的部分
- 如果没溢出这句代码相当于无效 */
- memcpy(rb->buffer, wbuff + l, len - l);
- rb->in += len;
-
- PRINT_DEBUG("write ringBuff len is %d!",len);
- #if USE_MUTEX
- }
- /* 开释互斥量 */
- release_mutex(rb->mutex);
- #endif
- return len;
- }</code>
复制代码Read_RingBuff
读取缓冲区数据到指定区域,用户指定读取长度,用户想要读取的长度不肯定是真正读取的长度,在读取完成的时间还要看看返回值是否与用户必要的长度同等~也支持多线程互斥访问。
也是缓冲区出队的高效操作。过程看代码注释即可 - <code>/************************************************************
- * @brief Read_RingBuff
- * @param rb:环形缓冲区句柄
- * @param wbuff:读取数据生存的起始地点
- * @param len:想要读取数据的长度(字节)
- * @return len:实际读取数据的长度(字节)
- * @author jiejie
- * @github https://github.com/jiejieTop
- * @date 2018-xx-xx
- * @version v1.0
- * @note 这个函数会从rb环形缓冲区中的数据区域拷贝len字节
- 长度的数据到rbuff空间。
- ***********************************************************/
- uint32_t Read_RingBuff(RingBuff_t *rb,
- uint8_t *rbuff,
- uint32_t len)
- {
- uint32_t l;
- #if USE_MUTEX
- /* 请求互斥量,成功才华举行ringbuff的访问 */
- if(!request_mutex(rb->mutex))
- {
- PRINT_DEBUG("request mutex fail!");
- return 0;
- }
- else
- {
- #endif
- len = min(len, rb->in - rb->out);
- /* 第一部分的拷贝:从环形缓冲区读取数据直至缓冲区末了一个 */
- l = min(len, rb->size - (rb->out & (rb->size - 1)));
- memcpy(rbuff, rb->buffer + (rb->out & (rb->size - 1)), l);
- /* 如果溢出则在缓冲区头读取剩余的部分
- 如果没溢出这句代码相当于无效 */
- memcpy(rbuff + l, rb->buffer, len - l);
- rb->out += len;
-
- PRINT_DEBUG("read ringBuff len is %d!",len);
- #if USE_MUTEX
- }
- /* 开释互斥量 */
- release_mutex(rb->mutex);
- #endif
- return len;
- }</code>
复制代码获取缓冲区信息
这些就比力简单了,看看缓冲区可读可写的数据有多少 - <code>/************************************************************
- * @brief CanRead_RingBuff
- * @param rb:环形缓冲区句柄
- * @return uint32:可读数据长度 0 / len
- * @author jiejie
- * @github https://github.com/jiejieTop
- * @date 2018-xx-xx
- * @version v1.0
- * @note 可读数据长度
- ***********************************************************/
- uint32_t CanRead_RingBuff(RingBuff_t *rb)
- {
- if(NULL == rb)
- {
- PRINT_ERR("ringbuff is null!");
- return 0;
- }
- if(rb->in == rb->out)
- return 0;
-
- if(rb->in > rb->out)
- return (rb->in - rb->out);
-
- return (rb->size - (rb->out - rb->in));
- }
- /************************************************************
- * @brief CanRead_RingBuff
- * @param rb:环形缓冲区句柄
- * @return uint32:可写数据长度 0 / len
- * @author jiejie
- * @github https://github.com/jiejieTop
- * @date 2018-xx-xx
- * @version v1.0
- * @note 可写数据长度
- ***********************************************************/
- uint32_t CanWrite_RingBuff(RingBuff_t *rb)
- {
- if(NULL == rb)
- {
- PRINT_ERR("ringbuff is null!");
- return 0;
- }
- return (rb->size - CanRead_RingBuff(rb));
- }</code>
复制代码附带
这里的代码我是用于测试的,随便写的 - <code> RingBuff_t ringbuff_handle;
-
- uint8_t rb[64];
- uint8_t res[64];
- Create_RingBuff(&ringbuff_handle,
- rb,
- sizeof(rb));
- Write_RingBuff(&ringbuff_handle,
- res,
- datapack.data_length);
-
- PRINT_DEBUG("CanRead_RingBuff = %d!",CanRead_RingBuff(&ringbuff_handle));
- PRINT_DEBUG("CanWrite_RingBuff = %d!",CanWrite_RingBuff(&ringbuff_handle));
-
- Read_RingBuff(&ringbuff_handle,
- res,
- datapack.data_length);</code>
复制代码支持多个os的互斥量操作
此处模仿了文件体系的互斥操作 - <code>#if USE_MUTEX
- #define MUTEX_TIMEOUT 1000 /* 超时时间 */
- #define MUTEX_T mutex_t /* 互斥量控制块 */
- #endif
- /*********************************** mutex **************************************************/
- #if USE_MUTEX
- /************************************************************
- * @brief create_mutex
- * @param mutex:创建信号量句柄
- * @return 创建成功为1,0为不成功。
- * @author jiejie
- * @github https://github.com/jiejieTop
- * @date 2018-xx-xx
- * @version v1.0
- * @note 创建一个互斥量,用户在os中互斥使用ringbuff,
- * 支持的os有rtt、win32、ucos、FreeRTOS、LiteOS
- ***********************************************************/
- static err_t create_mutex(MUTEX_T *mutex)
- {
- err_t ret = 0;
- // *mutex = rt_mutex_create("test_mux",RT_IPC_FLAG_PRIO); /* rtt */
- // ret = (err_t)(*mutex != RT_NULL);
-
- // *mutex = CreateMutex(NULL, FALSE, NULL); /* Win32 */
- // ret = (err_t)(*mutex != INVALID_HANDLE_VALUE);
- // *mutex = OSMutexCreate(0, &err); /* uC/OS-II */
- // ret = (err_t)(err == OS_NO_ERR);
- // *mutex = xSemaphoreCreateMutex(); /* FreeRTOS */
- // ret = (err_t)(*mutex != NULL);
- // ret = LOS_MuxCreate(&mutex); /* LiteOS */
- // ret = (err_t)(ret != LOS_OK);
- return ret;
- }
- /************************************************************
- * @brief deleta_mutex
- * @param mutex:互斥量句柄
- * @return NULL
- * @author jiejie
- * @github https://github.com/jiejieTop
- * @date 2018-xx-xx
- * @version v1.0
- * @note 删除一个互斥量,支持的os有rtt、win32、ucos、FreeRTOS、LiteOS
- ***********************************************************/
- static err_t deleta_mutex(MUTEX_T *mutex)
- {
- err_t ret;
-
- // ret = rt_mutex_delete(mutex); /* rtt */
-
- // ret = CloseHandle(mutex); /* Win32 */
- // OSMutexDel(mutex, OS_DEL_ALWAYS, &err); /* uC/OS-II */
- // ret = (err_t)(err == OS_NO_ERR);
- // vSemaphoreDelete(mutex); /* FreeRTOS */
- // ret = 1;
- // ret = LOS_MuxDelete(&mutex); /* LiteOS */
- // ret = (err_t)(ret != LOS_OK);
- return ret;
- }
- /************************************************************
- * @brief request_mutex
- * @param mutex:互斥量句柄
- * @return NULL
- * @author jiejie
- * @github https://github.com/jiejieTop
- * @date 2018-xx-xx
- * @version v1.0
- * @note 请求一个互斥量,得到互斥量的线程才答应举行访问缓冲区
- * 支持的os有rtt、win32、ucos、FreeRTOS、LiteOS
- ***********************************************************/
- static err_t request_mutex(MUTEX_T *mutex)
- {
- err_t ret;
- // ret = (err_t)(rt_mutex_take(mutex, MUTEX_TIMEOUT) == RT_EOK);/* rtt */
-
- // ret = (err_t)(WaitForSingleObject(mutex, MUTEX_TIMEOUT) == WAIT_OBJECT_0); /* Win32 */
- // OSMutexPend(mutex, MUTEX_TIMEOUT, &err)); /* uC/OS-II */
- // ret = (err_t)(err == OS_NO_ERR);
- // ret = (err_t)(xSemaphoreTake(mutex, MUTEX_TIMEOUT) == pdTRUE); /* FreeRTOS */
- // ret = (err_t)(LOS_MuxPend(mutex,MUTEX_TIMEOUT) == LOS_OK); /* LiteOS */
- return ret;
- }
- /************************************************************
- * @brief release_mutex
- * @param mutex:互斥量句柄
- * @return NULL
- * @author jiejie
- * @github https://github.com/jiejieTop
- * @date 2018-xx-xx
- * @version v1.0
- * @note 开释互斥量,当线程使用完资源必须开释互斥量
- * 支持的os有rtt、win32、ucos、FreeRTOS、LiteOS
- ***********************************************************/
- static void release_mutex(MUTEX_T *mutex)
- {
- // rt_mutex_release(mutex);/* rtt */
-
- // ReleaseMutex(mutex); /* Win32 */
- // OSMutexPost(mutex); /* uC/OS-II */
- // xSemaphoreGive(mutex); /* FreeRTOS */
- // LOS_MuxPost(mutex); /* LiteOS */
- }
- #endif
- /*********************************** mutex **************************************************/</code>
复制代码debug.h
末了送一份debug的简便操作源码,由于前文许多时间会调用
PRINT_ERR
PRINT_DEBUG - <code>#ifndef _DEBUG_H
- #define _DEBUG_H
- /************************************************************
- * @brief debug.h
- * @author jiejie
- * @github https://github.com/jiejieTop
- * @date 2018-xx-xx
- * @version v1.0
- * @note 此文件用于打印日记信息
- ***********************************************************/
- /**
- * @name Debug print
- * @{
- */
- #define PRINT_DEBUG_ENABLE 1 /* 打印调试信息 */
- #define PRINT_ERR_ENABLE 1 /* 打印错误信息 */
- #define PRINT_INFO_ENABLE 0 /* 打印个人信息 */
- #if PRINT_DEBUG_ENABLE
- #define PRINT_DEBUG(fmt, args...) do{(printf("\n[DEBUG] >> "), printf(fmt, ##args));}while(0)
- #else
- #define PRINT_DEBUG(fmt, args...)
- #endif
- #if PRINT_ERR_ENABLE
- #define PRINT_ERR(fmt, args...) do{(printf("\n[ERR] >> "), printf(fmt, ##args));}while(0)
- #else
- #define PRINT_ERR(fmt, args...)
- #endif
- #if PRINT_INFO_ENABLE
- #define PRINT_INFO(fmt, args...) do{(printf("\n[INFO] >> "), printf(fmt, ##args));}while(0)
- #else
- #define PRINT_INFO(fmt, args...)
- #endif
- /**@} */
-
- //针对差别的编译器调用差别的stdint.h文件
- #if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
- #include <stdint.h>
- #endif
- /* 断言 Assert */
- #define AssertCalled(char,int) printf("\nError:%s,%d\r\n",char,int)
- #define ASSERT(x) if((x)==0) AssertCalled(__FILE__,__LINE__)
-
- typedef enum
- {
- ASSERT_ERR = 0, /* 错误 */
- ASSERT_SUCCESS = !ASSERT_ERR /* 精确 */
- } Assert_ErrorStatus;
- typedef enum
- {
- FALSE = 0, /* 假 */
- TRUE = !FALSE /* 真 */
- }ResultStatus;
- #endif /* __DEBUG_H */</code>
复制代码喜好就关注我吧!
相干代码可以在公众号背景获取。
更多资料欢迎关注“物联网IoT开辟”公众号!
来源:https://www.cnblogs.com/iot-dev/p/11688794.html |