1
0

ringbuffer.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. /*
  2. * Copyright (c) 2006-2023, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2012-09-30 Bernard first version.
  9. * 2013-05-08 Grissiom reimplement
  10. * 2016-08-18 heyuanjie add interface
  11. * 2021-07-20 arminker fix write_index bug in function rt_ringbuffer_put_force
  12. * 2021-08-14 Jackistang add comments for function interface.
  13. */
  14. #include <rtdevice.h>
  15. #include <string.h>
  16. rt_inline enum rt_ringbuffer_state rt_ringbuffer_status(struct rt_ringbuffer *rb)
  17. {
  18. if (rb->read_index == rb->write_index)
  19. {
  20. if (rb->read_mirror == rb->write_mirror)
  21. return RT_RINGBUFFER_EMPTY;
  22. else
  23. return RT_RINGBUFFER_FULL;
  24. }
  25. return RT_RINGBUFFER_HALFFULL;
  26. }
  27. /**
  28. * @brief Initialize the ring buffer object.
  29. *
  30. * @param rb A pointer to the ring buffer object.
  31. * @param pool A pointer to the buffer.
  32. * @param size The size of the buffer in bytes.
  33. */
  34. void rt_ringbuffer_init(struct rt_ringbuffer *rb,
  35. rt_uint8_t *pool,
  36. rt_int32_t size)
  37. {
  38. RT_ASSERT(rb != RT_NULL);
  39. RT_ASSERT(size > 0);
  40. /* initialize read and write index */
  41. rb->read_mirror = rb->read_index = 0;
  42. rb->write_mirror = rb->write_index = 0;
  43. /* set buffer pool and size */
  44. rb->buffer_ptr = pool;
  45. rb->buffer_size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
  46. }
  47. RTM_EXPORT(rt_ringbuffer_init);
  48. /**
  49. * @brief Put a block of data into the ring buffer. If the capacity of ring buffer is insufficient, it will discard out-of-range data.
  50. *
  51. * @param rb A pointer to the ring buffer object.
  52. * @param ptr A pointer to the data buffer.
  53. * @param length The size of data in bytes.
  54. *
  55. * @return Return the data size we put into the ring buffer.
  56. */
  57. rt_size_t rt_ringbuffer_put(struct rt_ringbuffer *rb,
  58. const rt_uint8_t *ptr,
  59. rt_uint32_t length)
  60. {
  61. rt_uint32_t size;
  62. RT_ASSERT(rb != RT_NULL);
  63. /* whether has enough space */
  64. size = rt_ringbuffer_space_len(rb);
  65. /* no space */
  66. if (size == 0)
  67. return 0;
  68. /* drop some data */
  69. if (size < length)
  70. length = size;
  71. if (rb->buffer_size - rb->write_index > length)
  72. {
  73. /* read_index - write_index = empty space */
  74. rt_memcpy(&rb->buffer_ptr[rb->write_index], ptr, length);
  75. /* this should not cause overflow because there is enough space for
  76. * length of data in current mirror */
  77. rb->write_index += length;
  78. return length;
  79. }
  80. rt_memcpy(&rb->buffer_ptr[rb->write_index],
  81. &ptr[0],
  82. rb->buffer_size - rb->write_index);
  83. rt_memcpy(&rb->buffer_ptr[0],
  84. &ptr[rb->buffer_size - rb->write_index],
  85. length - (rb->buffer_size - rb->write_index));
  86. /* we are going into the other side of the mirror */
  87. rb->write_mirror = ~rb->write_mirror;
  88. rb->write_index = length - (rb->buffer_size - rb->write_index);
  89. return length;
  90. }
  91. RTM_EXPORT(rt_ringbuffer_put);
  92. /**
  93. * @brief Put a block of data into the ring buffer. If the capacity of ring buffer is insufficient, it will overwrite the existing data in the ring buffer.
  94. *
  95. * @param rb A pointer to the ring buffer object.
  96. * @param ptr A pointer to the data buffer.
  97. * @param length The size of data in bytes.
  98. *
  99. * @return Return the data size we put into the ring buffer.
  100. */
  101. rt_size_t rt_ringbuffer_put_force(struct rt_ringbuffer *rb,
  102. const rt_uint8_t *ptr,
  103. rt_uint32_t length)
  104. {
  105. rt_uint32_t space_length;
  106. RT_ASSERT(rb != RT_NULL);
  107. space_length = rt_ringbuffer_space_len(rb);
  108. if (length > rb->buffer_size)
  109. {
  110. ptr = &ptr[length - rb->buffer_size];
  111. length = rb->buffer_size;
  112. }
  113. if (rb->buffer_size - rb->write_index > length)
  114. {
  115. /* read_index - write_index = empty space */
  116. rt_memcpy(&rb->buffer_ptr[rb->write_index], ptr, length);
  117. /* this should not cause overflow because there is enough space for
  118. * length of data in current mirror */
  119. rb->write_index += length;
  120. if (length > space_length)
  121. rb->read_index = rb->write_index;
  122. return length;
  123. }
  124. rt_memcpy(&rb->buffer_ptr[rb->write_index],
  125. &ptr[0],
  126. rb->buffer_size - rb->write_index);
  127. rt_memcpy(&rb->buffer_ptr[0],
  128. &ptr[rb->buffer_size - rb->write_index],
  129. length - (rb->buffer_size - rb->write_index));
  130. /* we are going into the other side of the mirror */
  131. rb->write_mirror = ~rb->write_mirror;
  132. rb->write_index = length - (rb->buffer_size - rb->write_index);
  133. if (length > space_length)
  134. {
  135. if (rb->write_index <= rb->read_index)
  136. rb->read_mirror = ~rb->read_mirror;
  137. rb->read_index = rb->write_index;
  138. }
  139. return length;
  140. }
  141. RTM_EXPORT(rt_ringbuffer_put_force);
  142. /**
  143. * @brief Get data from the ring buffer.
  144. *
  145. * @param rb A pointer to the ring buffer.
  146. * @param ptr A pointer to the data buffer.
  147. * @param length The size of the data we want to read from the ring buffer.
  148. *
  149. * @return Return the data size we read from the ring buffer.
  150. */
  151. rt_size_t rt_ringbuffer_get(struct rt_ringbuffer *rb,
  152. rt_uint8_t *ptr,
  153. rt_uint32_t length)
  154. {
  155. rt_size_t size;
  156. RT_ASSERT(rb != RT_NULL);
  157. /* whether has enough data */
  158. size = rt_ringbuffer_data_len(rb);
  159. /* no data */
  160. if (size == 0)
  161. return 0;
  162. /* less data */
  163. if (size < length)
  164. length = size;
  165. if (rb->buffer_size - rb->read_index > length)
  166. {
  167. /* copy all of data */
  168. rt_memcpy(ptr, &rb->buffer_ptr[rb->read_index], length);
  169. /* this should not cause overflow because there is enough space for
  170. * length of data in current mirror */
  171. rb->read_index += length;
  172. return length;
  173. }
  174. rt_memcpy(&ptr[0],
  175. &rb->buffer_ptr[rb->read_index],
  176. rb->buffer_size - rb->read_index);
  177. rt_memcpy(&ptr[rb->buffer_size - rb->read_index],
  178. &rb->buffer_ptr[0],
  179. length - (rb->buffer_size - rb->read_index));
  180. /* we are going into the other side of the mirror */
  181. rb->read_mirror = ~rb->read_mirror;
  182. rb->read_index = length - (rb->buffer_size - rb->read_index);
  183. return length;
  184. }
  185. RTM_EXPORT(rt_ringbuffer_get);
  186. /**
  187. * @brief Get the first readable byte of the ring buffer.
  188. *
  189. * @param rb A pointer to the ringbuffer.
  190. * @param ptr When this function return, *ptr is a pointer to the first readable byte of the ring buffer.
  191. *
  192. * @note It is recommended to read only one byte, otherwise it may cause buffer overflow.
  193. *
  194. * @return Return the size of the ring buffer.
  195. */
  196. rt_size_t rt_ringbuffer_peek(struct rt_ringbuffer *rb, rt_uint8_t **ptr)
  197. {
  198. rt_size_t size;
  199. RT_ASSERT(rb != RT_NULL);
  200. *ptr = RT_NULL;
  201. /* whether has enough data */
  202. size = rt_ringbuffer_data_len(rb);
  203. /* no data */
  204. if (size == 0)
  205. return 0;
  206. *ptr = &rb->buffer_ptr[rb->read_index];
  207. if ((rt_size_t)(rb->buffer_size - rb->read_index) > size)
  208. {
  209. rb->read_index += size;
  210. return size;
  211. }
  212. size = rb->buffer_size - rb->read_index;
  213. /* we are going into the other side of the mirror */
  214. rb->read_mirror = ~rb->read_mirror;
  215. rb->read_index = 0;
  216. return size;
  217. }
  218. RTM_EXPORT(rt_ringbuffer_peek);
  219. /**
  220. * @brief Put a byte into the ring buffer. If ring buffer is full, this operation will fail.
  221. *
  222. * @param rb A pointer to the ring buffer object.
  223. * @param ch A byte put into the ring buffer.
  224. *
  225. * @return Return the data size we put into the ring buffer. The ring buffer is full if returns 0. Otherwise, it will return 1.
  226. */
  227. rt_size_t rt_ringbuffer_putchar(struct rt_ringbuffer *rb, const rt_uint8_t ch)
  228. {
  229. RT_ASSERT(rb != RT_NULL);
  230. /* whether has enough space */
  231. if (!rt_ringbuffer_space_len(rb))
  232. return 0;
  233. rb->buffer_ptr[rb->write_index] = ch;
  234. /* flip mirror */
  235. if (rb->write_index == rb->buffer_size - 1)
  236. {
  237. rb->write_mirror = ~rb->write_mirror;
  238. rb->write_index = 0;
  239. }
  240. else
  241. {
  242. rb->write_index++;
  243. }
  244. return 1;
  245. }
  246. RTM_EXPORT(rt_ringbuffer_putchar);
  247. /**
  248. * @brief Put a byte into the ring buffer. If ring buffer is full, it will discard an old data and put into a new data.
  249. *
  250. * @param rb A pointer to the ring buffer object.
  251. * @param ch A byte put into the ring buffer.
  252. *
  253. * @return Return the data size we put into the ring buffer. Always return 1.
  254. */
  255. rt_size_t rt_ringbuffer_putchar_force(struct rt_ringbuffer *rb, const rt_uint8_t ch)
  256. {
  257. enum rt_ringbuffer_state old_state;
  258. RT_ASSERT(rb != RT_NULL);
  259. old_state = rt_ringbuffer_status(rb);
  260. rb->buffer_ptr[rb->write_index] = ch;
  261. /* flip mirror */
  262. if (rb->write_index == rb->buffer_size - 1)
  263. {
  264. rb->write_mirror = ~rb->write_mirror;
  265. rb->write_index = 0;
  266. if (old_state == RT_RINGBUFFER_FULL)
  267. {
  268. rb->read_mirror = ~rb->read_mirror;
  269. rb->read_index = rb->write_index;
  270. }
  271. }
  272. else
  273. {
  274. rb->write_index++;
  275. if (old_state == RT_RINGBUFFER_FULL)
  276. rb->read_index = rb->write_index;
  277. }
  278. return 1;
  279. }
  280. RTM_EXPORT(rt_ringbuffer_putchar_force);
  281. /**
  282. * @brief Get a byte from the ring buffer.
  283. *
  284. * @param rb The pointer to the ring buffer object.
  285. * @param ch A pointer to the buffer, used to store one byte.
  286. *
  287. * @return 0 The ring buffer is empty.
  288. * @return 1 Success
  289. */
  290. rt_size_t rt_ringbuffer_getchar(struct rt_ringbuffer *rb, rt_uint8_t *ch)
  291. {
  292. RT_ASSERT(rb != RT_NULL);
  293. /* ringbuffer is empty */
  294. if (!rt_ringbuffer_data_len(rb))
  295. return 0;
  296. /* put byte */
  297. *ch = rb->buffer_ptr[rb->read_index];
  298. if (rb->read_index == rb->buffer_size - 1)
  299. {
  300. rb->read_mirror = ~rb->read_mirror;
  301. rb->read_index = 0;
  302. }
  303. else
  304. {
  305. rb->read_index++;
  306. }
  307. return 1;
  308. }
  309. RTM_EXPORT(rt_ringbuffer_getchar);
  310. /**
  311. * @brief Get the size of data in the ring buffer in bytes.
  312. *
  313. * @param rb The pointer to the ring buffer object.
  314. *
  315. * @return Return the size of data in the ring buffer in bytes.
  316. */
  317. rt_size_t rt_ringbuffer_data_len(struct rt_ringbuffer *rb)
  318. {
  319. switch (rt_ringbuffer_status(rb))
  320. {
  321. case RT_RINGBUFFER_EMPTY:
  322. return 0;
  323. case RT_RINGBUFFER_FULL:
  324. return rb->buffer_size;
  325. case RT_RINGBUFFER_HALFFULL:
  326. default:
  327. {
  328. rt_size_t wi = rb->write_index, ri = rb->read_index;
  329. if (wi > ri)
  330. return wi - ri;
  331. else
  332. return rb->buffer_size - (ri - wi);
  333. }
  334. }
  335. }
  336. RTM_EXPORT(rt_ringbuffer_data_len);
  337. /**
  338. * @brief Reset the ring buffer object, and clear all contents in the buffer.
  339. *
  340. * @param rb A pointer to the ring buffer object.
  341. */
  342. void rt_ringbuffer_reset(struct rt_ringbuffer *rb)
  343. {
  344. RT_ASSERT(rb != RT_NULL);
  345. rb->read_mirror = 0;
  346. rb->read_index = 0;
  347. rb->write_mirror = 0;
  348. rb->write_index = 0;
  349. }
  350. RTM_EXPORT(rt_ringbuffer_reset);
  351. #ifdef RT_USING_HEAP
  352. /**
  353. * @brief Create a ring buffer object with a given size.
  354. *
  355. * @param size The size of the buffer in bytes.
  356. *
  357. * @return Return a pointer to ring buffer object. When the return value is RT_NULL, it means this creation failed.
  358. */
  359. struct rt_ringbuffer *rt_ringbuffer_create(rt_uint32_t size)
  360. {
  361. struct rt_ringbuffer *rb;
  362. rt_uint8_t *pool;
  363. RT_ASSERT(size > 0);
  364. size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
  365. rb = (struct rt_ringbuffer *)rt_malloc(sizeof(struct rt_ringbuffer));
  366. if (rb == RT_NULL)
  367. goto exit;
  368. pool = (rt_uint8_t *)rt_malloc(size);
  369. if (pool == RT_NULL)
  370. {
  371. rt_free(rb);
  372. rb = RT_NULL;
  373. goto exit;
  374. }
  375. rt_ringbuffer_init(rb, pool, size);
  376. exit:
  377. return rb;
  378. }
  379. RTM_EXPORT(rt_ringbuffer_create);
  380. /**
  381. * @brief Destroy the ring buffer object, which is created by rt_ringbuffer_create() .
  382. *
  383. * @param rb A pointer to the ring buffer object.
  384. */
  385. void rt_ringbuffer_destroy(struct rt_ringbuffer *rb)
  386. {
  387. RT_ASSERT(rb != RT_NULL);
  388. rt_free(rb->buffer_ptr);
  389. rt_free(rb);
  390. }
  391. RTM_EXPORT(rt_ringbuffer_destroy);
  392. #endif