马上加入IBC程序猿 各种源码随意下,各种教程随便看! 注册 每日签到 加入编程讨论群

C#教程 ASP.NET教程 C#视频教程程序源码享受不尽 C#技术求助 ASP.NET技术求助

【源码下载】 社群合作 申请版主 程序开发 【远程协助】 每天乐一乐 每日签到 【承接外包项目】 面试-葵花宝典下载

官方一群:

官方二群:

基于Linux的kfifo移植到STM32(支持os的互斥访问)

[复制链接]
查看2005 | 回复1 | 2019-10-17 09:45:09 | 显示全部楼层 |阅读模式

基于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中的队尾

  1. <code>typedef struct ringbuff
  2. {
  3. uint8_t *buffer; /* 数据区域 */
  4. uint32_t size; /* 环形缓冲区巨细 */
  5. uint32_t in; /* 数据入队指针 (in % size) */
  6. uint32_t out; /* 数据出队指针 (out % size) */
  7. #if USE_MUTEX
  8. MUTEX_T *mutex; /* 支持rtos的互斥 */
  9. #endif
  10. }RingBuff_t ;</code>
复制代码

Create_RingBuff

创建一个环形缓冲区,为了顺应后续对缓冲区入队出队的高效操作,环形缓冲区的巨细应为2^n字节,
如果不是这个巨细,则体系默认裁剪以对应缓冲区字节。
当然还可以优化,不外我现在并未做,思绪如下:如果体系支持动态分配内存,则向上对齐,制止浪费内存空间,否则就按照我默认的向下对齐,当内存越大,对齐导致内存走漏则会越多。对齐接纳的函数是roundup_pow_of_two。如果体系支持互斥量,那么还将创建一个互斥量用来做互斥访问,防止多线程同时使用导致数据丢失。

  1. <code>/************************************************************
  2. * @brief Create_RingBuff
  3. * @param rb:环形缓冲区句柄
  4. * buffer:环形缓冲区的数据区域
  5. * size:环形缓冲区的巨细,缓冲区巨细要为2^n
  6. * @return err_t:ERR_OK表现创建成功,其他表现失败
  7. * @author jiejie
  8. * @github https://github.com/jiejieTop
  9. * @date 2018-xx-xx
  10. * @version v1.0
  11. * @note 用于创建一个环形缓冲区
  12. ***********************************************************/
  13. err_t Create_RingBuff(RingBuff_t* rb,
  14. uint8_t *buffer,
  15. uint32_t size
  16. )
  17. {
  18. if((rb == NULL)||(buffer == NULL)||(size == 0))
  19. {
  20. PRINT_ERR("data is null!");
  21. return ERR_NULL;
  22. }
  23. PRINT_DEBUG("ringbuff size is %d!",size);
  24. /* 缓冲区巨细必须为2^n字节,体系会强制转换,
  25. 否则大概会导致指针访问非法地点。
  26. 空间巨细越大,强转时丢失内存越多 */
  27. if(size&(size - 1))
  28. {
  29. size = roundup_pow_of_two(size);
  30. PRINT_DEBUG("change ringbuff size is %d!",size);
  31. }
  32. rb->buffer = buffer;
  33. rb->size = size;
  34. rb->in = rb->out = 0;
  35. #if USE_MUTEX
  36. /* 创建信号量不成功 */
  37. if(!create_mutex(rb->mutex))
  38. {
  39. PRINT_ERR("create mutex fail!");
  40. ASSERT(ASSERT_ERR);
  41. return ERR_NOK;
  42. }
  43. #endif
  44. PRINT_DEBUG("create ringBuff ok!");
  45. return ERR_OK;
  46. }</code>
复制代码

roundup_pow_of_two

  1. <code>/************************************************************
  2. * @brief roundup_pow_of_two
  3. * @param size:通报进来的数据长度
  4. * @return size:返回处理惩罚之后的数据长度
  5. * @author jiejie
  6. * @github https://github.com/jiejieTop
  7. * @date 2018-xx-xx
  8. * @version v1.0
  9. * @note 用于处理惩罚数据,使数据长度必须为 2^n
  10. * 如果不是,则转换,丢弃多余部分,如
  11. * roundup_pow_of_two(66) -> 返回 64
  12. ***********************************************************/
  13. static unsigned long roundup_pow_of_two(unsigned long x)
  14. {
  15. return (1 << (fls(x-1)-1)); //向下对齐
  16. //return (1UL << fls(x - 1)); //向上对齐,用动态内存可用使用
  17. }</code>
复制代码

Delete_RingBuff

删除一个环形缓冲区,删除之后,缓冲区真正存储地点是不会被改变的(现在我是使用自定义数组做缓冲区的),但是删除之后,就无法对缓冲区举行读写操作。而且如果支持os的话,创建的互斥量会被删除。

  1. <code>/************************************************************
  2. * @brief Delete_RingBuff
  3. * @param rb:环形缓冲区句柄
  4. * @return err_t:ERR_OK表现成功,其他表现失败
  5. * @author jiejie
  6. * @github https://github.com/jiejieTop
  7. * @date 2018-xx-xx
  8. * @version v1.0
  9. * @note 删除一个环形缓冲区
  10. ***********************************************************/
  11. err_t Delete_RingBuff(RingBuff_t *rb)
  12. {
  13. if(rb == NULL)
  14. {
  15. PRINT_ERR("ringbuff is null!");
  16. return ERR_NULL;
  17. }
  18. rb->buffer = NULL;
  19. rb->size = 0;
  20. rb->in = rb->out = 0;
  21. #if USE_MUTEX
  22. if(!deleta_mutex(rb->mutex))
  23. {
  24. PRINT_DEBUG("deleta mutex is fail!");
  25. return ERR_NOK;
  26. }
  27. #endif
  28. return ERR_OK;
  29. }</code>
复制代码

Write_RingBuff

向环形缓冲区写入指定命据,支持线程互斥访问。用户想要写入缓冲区的数据长度不肯定是真正入队的长度,在完成的时间还要看看返回值是否与用户必要的长度同等~
这个函数很故意思,也是比力高效的入队操作,将指定区域的数据拷贝到指定的缓冲区中,过程看注释即可

  1. <code>/************************************************************
  2. * @brief Write_RingBuff
  3. * @param rb:环形缓冲区句柄
  4. * @param wbuff:写入的数据起始地点
  5. * @param len:写入数据的长度(字节)
  6. * @return len:实际写入数据的长度(字节)
  7. * @author jiejie
  8. * @github https://github.com/jiejieTop
  9. * @date 2018-xx-xx
  10. * @version v1.0
  11. * @note 这个函数会从buff空间拷贝len字节长度的数据到
  12. rb环形缓冲区中的空闲空间。
  13. ***********************************************************/
  14. uint32_t Write_RingBuff(RingBuff_t *rb,
  15. uint8_t *wbuff,
  16. uint32_t len)
  17. {
  18. uint32_t l;
  19. #if USE_MUTEX
  20. /* 请求互斥量,成功才华举行ringbuff的访问 */
  21. if(!request_mutex(rb->mutex))
  22. {
  23. PRINT_DEBUG("request mutex fail!");
  24. return 0;
  25. }
  26. else /* 获取互斥量成功 */
  27. {
  28. #endif
  29. len = min(len, rb->size - rb->in + rb->out);
  30. /* 第一部分的拷贝:从环形缓冲区写入数据直至缓冲区末了一个地点 */
  31. l = min(len, rb->size - (rb->in & (rb->size - 1)));
  32. memcpy(rb->buffer + (rb->in & (rb->size - 1)), wbuff, l);
  33. /* 如果溢出则在缓冲区头写入剩余的部分
  34. 如果没溢出这句代码相当于无效 */
  35. memcpy(rb->buffer, wbuff + l, len - l);
  36. rb->in += len;
  37. PRINT_DEBUG("write ringBuff len is %d!",len);
  38. #if USE_MUTEX
  39. }
  40. /* 开释互斥量 */
  41. release_mutex(rb->mutex);
  42. #endif
  43. return len;
  44. }</code>
复制代码

Read_RingBuff

读取缓冲区数据到指定区域,用户指定读取长度,用户想要读取的长度不肯定是真正读取的长度,在读取完成的时间还要看看返回值是否与用户必要的长度同等~也支持多线程互斥访问。
也是缓冲区出队的高效操作。过程看代码注释即可

  1. <code>/************************************************************
  2. * @brief Read_RingBuff
  3. * @param rb:环形缓冲区句柄
  4. * @param wbuff:读取数据生存的起始地点
  5. * @param len:想要读取数据的长度(字节)
  6. * @return len:实际读取数据的长度(字节)
  7. * @author jiejie
  8. * @github https://github.com/jiejieTop
  9. * @date 2018-xx-xx
  10. * @version v1.0
  11. * @note 这个函数会从rb环形缓冲区中的数据区域拷贝len字节
  12. 长度的数据到rbuff空间。
  13. ***********************************************************/
  14. uint32_t Read_RingBuff(RingBuff_t *rb,
  15. uint8_t *rbuff,
  16. uint32_t len)
  17. {
  18. uint32_t l;
  19. #if USE_MUTEX
  20. /* 请求互斥量,成功才华举行ringbuff的访问 */
  21. if(!request_mutex(rb->mutex))
  22. {
  23. PRINT_DEBUG("request mutex fail!");
  24. return 0;
  25. }
  26. else
  27. {
  28. #endif
  29. len = min(len, rb->in - rb->out);
  30. /* 第一部分的拷贝:从环形缓冲区读取数据直至缓冲区末了一个 */
  31. l = min(len, rb->size - (rb->out & (rb->size - 1)));
  32. memcpy(rbuff, rb->buffer + (rb->out & (rb->size - 1)), l);
  33. /* 如果溢出则在缓冲区头读取剩余的部分
  34. 如果没溢出这句代码相当于无效 */
  35. memcpy(rbuff + l, rb->buffer, len - l);
  36. rb->out += len;
  37. PRINT_DEBUG("read ringBuff len is %d!",len);
  38. #if USE_MUTEX
  39. }
  40. /* 开释互斥量 */
  41. release_mutex(rb->mutex);
  42. #endif
  43. return len;
  44. }</code>
复制代码

获取缓冲区信息

这些就比力简单了,看看缓冲区可读可写的数据有多少

  1. <code>/************************************************************
  2. * @brief CanRead_RingBuff
  3. * @param rb:环形缓冲区句柄
  4. * @return uint32:可读数据长度 0 / len
  5. * @author jiejie
  6. * @github https://github.com/jiejieTop
  7. * @date 2018-xx-xx
  8. * @version v1.0
  9. * @note 可读数据长度
  10. ***********************************************************/
  11. uint32_t CanRead_RingBuff(RingBuff_t *rb)
  12. {
  13. if(NULL == rb)
  14. {
  15. PRINT_ERR("ringbuff is null!");
  16. return 0;
  17. }
  18. if(rb->in == rb->out)
  19. return 0;
  20. if(rb->in > rb->out)
  21. return (rb->in - rb->out);
  22. return (rb->size - (rb->out - rb->in));
  23. }
  24. /************************************************************
  25. * @brief CanRead_RingBuff
  26. * @param rb:环形缓冲区句柄
  27. * @return uint32:可写数据长度 0 / len
  28. * @author jiejie
  29. * @github https://github.com/jiejieTop
  30. * @date 2018-xx-xx
  31. * @version v1.0
  32. * @note 可写数据长度
  33. ***********************************************************/
  34. uint32_t CanWrite_RingBuff(RingBuff_t *rb)
  35. {
  36. if(NULL == rb)
  37. {
  38. PRINT_ERR("ringbuff is null!");
  39. return 0;
  40. }
  41. return (rb->size - CanRead_RingBuff(rb));
  42. }</code>
复制代码

附带

这里的代码我是用于测试的,随便写的

  1. <code> RingBuff_t ringbuff_handle;
  2. uint8_t rb[64];
  3. uint8_t res[64];
  4. Create_RingBuff(&ringbuff_handle,
  5. rb,
  6. sizeof(rb));
  7. Write_RingBuff(&ringbuff_handle,
  8. res,
  9. datapack.data_length);
  10. PRINT_DEBUG("CanRead_RingBuff = %d!",CanRead_RingBuff(&ringbuff_handle));
  11. PRINT_DEBUG("CanWrite_RingBuff = %d!",CanWrite_RingBuff(&ringbuff_handle));
  12. Read_RingBuff(&ringbuff_handle,
  13. res,
  14. datapack.data_length);</code>
复制代码

支持多个os的互斥量操作

此处模仿了文件体系的互斥操作

  1. <code>#if USE_MUTEX
  2. #define MUTEX_TIMEOUT 1000 /* 超时时间 */
  3. #define MUTEX_T mutex_t /* 互斥量控制块 */
  4. #endif
  5. /*********************************** mutex **************************************************/
  6. #if USE_MUTEX
  7. /************************************************************
  8. * @brief create_mutex
  9. * @param mutex:创建信号量句柄
  10. * @return 创建成功为1,0为不成功。
  11. * @author jiejie
  12. * @github https://github.com/jiejieTop
  13. * @date 2018-xx-xx
  14. * @version v1.0
  15. * @note 创建一个互斥量,用户在os中互斥使用ringbuff,
  16. * 支持的os有rtt、win32、ucos、FreeRTOS、LiteOS
  17. ***********************************************************/
  18. static err_t create_mutex(MUTEX_T *mutex)
  19. {
  20. err_t ret = 0;
  21. // *mutex = rt_mutex_create("test_mux",RT_IPC_FLAG_PRIO); /* rtt */
  22. // ret = (err_t)(*mutex != RT_NULL);
  23. // *mutex = CreateMutex(NULL, FALSE, NULL); /* Win32 */
  24. // ret = (err_t)(*mutex != INVALID_HANDLE_VALUE);
  25. // *mutex = OSMutexCreate(0, &err); /* uC/OS-II */
  26. // ret = (err_t)(err == OS_NO_ERR);
  27. // *mutex = xSemaphoreCreateMutex(); /* FreeRTOS */
  28. // ret = (err_t)(*mutex != NULL);
  29. // ret = LOS_MuxCreate(&mutex); /* LiteOS */
  30. // ret = (err_t)(ret != LOS_OK);
  31. return ret;
  32. }
  33. /************************************************************
  34. * @brief deleta_mutex
  35. * @param mutex:互斥量句柄
  36. * @return NULL
  37. * @author jiejie
  38. * @github https://github.com/jiejieTop
  39. * @date 2018-xx-xx
  40. * @version v1.0
  41. * @note 删除一个互斥量,支持的os有rtt、win32、ucos、FreeRTOS、LiteOS
  42. ***********************************************************/
  43. static err_t deleta_mutex(MUTEX_T *mutex)
  44. {
  45. err_t ret;
  46. // ret = rt_mutex_delete(mutex); /* rtt */
  47. // ret = CloseHandle(mutex); /* Win32 */
  48. // OSMutexDel(mutex, OS_DEL_ALWAYS, &err); /* uC/OS-II */
  49. // ret = (err_t)(err == OS_NO_ERR);
  50. // vSemaphoreDelete(mutex); /* FreeRTOS */
  51. // ret = 1;
  52. // ret = LOS_MuxDelete(&mutex); /* LiteOS */
  53. // ret = (err_t)(ret != LOS_OK);
  54. return ret;
  55. }
  56. /************************************************************
  57. * @brief request_mutex
  58. * @param mutex:互斥量句柄
  59. * @return NULL
  60. * @author jiejie
  61. * @github https://github.com/jiejieTop
  62. * @date 2018-xx-xx
  63. * @version v1.0
  64. * @note 请求一个互斥量,得到互斥量的线程才答应举行访问缓冲区
  65. * 支持的os有rtt、win32、ucos、FreeRTOS、LiteOS
  66. ***********************************************************/
  67. static err_t request_mutex(MUTEX_T *mutex)
  68. {
  69. err_t ret;
  70. // ret = (err_t)(rt_mutex_take(mutex, MUTEX_TIMEOUT) == RT_EOK);/* rtt */
  71. // ret = (err_t)(WaitForSingleObject(mutex, MUTEX_TIMEOUT) == WAIT_OBJECT_0); /* Win32 */
  72. // OSMutexPend(mutex, MUTEX_TIMEOUT, &err)); /* uC/OS-II */
  73. // ret = (err_t)(err == OS_NO_ERR);
  74. // ret = (err_t)(xSemaphoreTake(mutex, MUTEX_TIMEOUT) == pdTRUE); /* FreeRTOS */
  75. // ret = (err_t)(LOS_MuxPend(mutex,MUTEX_TIMEOUT) == LOS_OK); /* LiteOS */
  76. return ret;
  77. }
  78. /************************************************************
  79. * @brief release_mutex
  80. * @param mutex:互斥量句柄
  81. * @return NULL
  82. * @author jiejie
  83. * @github https://github.com/jiejieTop
  84. * @date 2018-xx-xx
  85. * @version v1.0
  86. * @note 开释互斥量,当线程使用完资源必须开释互斥量
  87. * 支持的os有rtt、win32、ucos、FreeRTOS、LiteOS
  88. ***********************************************************/
  89. static void release_mutex(MUTEX_T *mutex)
  90. {
  91. // rt_mutex_release(mutex);/* rtt */
  92. // ReleaseMutex(mutex); /* Win32 */
  93. // OSMutexPost(mutex); /* uC/OS-II */
  94. // xSemaphoreGive(mutex); /* FreeRTOS */
  95. // LOS_MuxPost(mutex); /* LiteOS */
  96. }
  97. #endif
  98. /*********************************** mutex **************************************************/</code>
复制代码

debug.h

末了送一份debug的简便操作源码,由于前文许多时间会调用
PRINT_ERR
PRINT_DEBUG

  1. <code>#ifndef _DEBUG_H
  2. #define _DEBUG_H
  3. /************************************************************
  4. * @brief debug.h
  5. * @author jiejie
  6. * @github https://github.com/jiejieTop
  7. * @date 2018-xx-xx
  8. * @version v1.0
  9. * @note 此文件用于打印日记信息
  10. ***********************************************************/
  11. /**
  12. * @name Debug print
  13. * @{
  14. */
  15. #define PRINT_DEBUG_ENABLE 1 /* 打印调试信息 */
  16. #define PRINT_ERR_ENABLE 1 /* 打印错误信息 */
  17. #define PRINT_INFO_ENABLE 0 /* 打印个人信息 */
  18. #if PRINT_DEBUG_ENABLE
  19. #define PRINT_DEBUG(fmt, args...) do{(printf("\n[DEBUG] >> "), printf(fmt, ##args));}while(0)
  20. #else
  21. #define PRINT_DEBUG(fmt, args...)
  22. #endif
  23. #if PRINT_ERR_ENABLE
  24. #define PRINT_ERR(fmt, args...) do{(printf("\n[ERR] >> "), printf(fmt, ##args));}while(0)
  25. #else
  26. #define PRINT_ERR(fmt, args...)
  27. #endif
  28. #if PRINT_INFO_ENABLE
  29. #define PRINT_INFO(fmt, args...) do{(printf("\n[INFO] >> "), printf(fmt, ##args));}while(0)
  30. #else
  31. #define PRINT_INFO(fmt, args...)
  32. #endif
  33. /**@} */
  34. //针对差别的编译器调用差别的stdint.h文件
  35. #if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
  36. #include <stdint.h>
  37. #endif
  38. /* 断言 Assert */
  39. #define AssertCalled(char,int) printf("\nError:%s,%d\r\n",char,int)
  40. #define ASSERT(x) if((x)==0) AssertCalled(__FILE__,__LINE__)
  41. typedef enum
  42. {
  43. ASSERT_ERR = 0, /* 错误 */
  44. ASSERT_SUCCESS = !ASSERT_ERR /* 精确 */
  45. } Assert_ErrorStatus;
  46. typedef enum
  47. {
  48. FALSE = 0, /* 假 */
  49. TRUE = !FALSE /* 真 */
  50. }ResultStatus;
  51. #endif /* __DEBUG_H */</code>
复制代码

喜好就关注我吧!

094509zldmdnzmd74kjdzm.jpg

相干代码可以在公众号背景获取。
更多资料欢迎关注“物联网IoT开辟”公众号!







来源:https://www.cnblogs.com/iot-dev/p/11688794.html
C#论坛 www.ibcibc.com IBC编程社区
C#
C#论坛
IBC编程社区
*滑块验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则