ringbuffer.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  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 data from the ring buffer in zero-copy mode.
  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 This function returns a direct pointer to the internal buffer and consumes the data
  193. * (advances read_index). It returns the contiguous readable data length. If data wraps
  194. * around the buffer end, call this function again to get the remaining segment.
  195. *
  196. * @return Return the contiguous readable data size we consumed from the ring buffer.
  197. */
  198. rt_size_t rt_ringbuffer_get_direct(struct rt_ringbuffer *rb, rt_uint8_t **ptr)
  199. {
  200. rt_size_t size;
  201. RT_ASSERT(rb != RT_NULL);
  202. *ptr = RT_NULL;
  203. /* whether has enough data */
  204. size = rt_ringbuffer_data_len(rb);
  205. /* no data */
  206. if (size == 0)
  207. return 0;
  208. *ptr = &rb->buffer_ptr[rb->read_index];
  209. if ((rt_size_t)(rb->buffer_size - rb->read_index) > size)
  210. {
  211. rb->read_index += size;
  212. return size;
  213. }
  214. size = rb->buffer_size - rb->read_index;
  215. /* we are going into the other side of the mirror */
  216. rb->read_mirror = ~rb->read_mirror;
  217. rb->read_index = 0;
  218. return size;
  219. }
  220. RTM_EXPORT(rt_ringbuffer_get_direct);
  221. /**
  222. * @brief Get the first readable byte of the ring buffer.
  223. *
  224. * @param rb A pointer to the ringbuffer.
  225. * @param ptr When this function return, *ptr is a pointer to the first readable byte of the ring buffer.
  226. *
  227. * @note It is recommended to read only one byte, otherwise it may cause buffer overflow.
  228. *
  229. * @return Return the size of the ring buffer.
  230. */
  231. rt_size_t rt_ringbuffer_peek(struct rt_ringbuffer *rb, rt_uint8_t **ptr)
  232. {
  233. rt_size_t size;
  234. RT_ASSERT(rb != RT_NULL);
  235. *ptr = RT_NULL;
  236. /* whether has enough data */
  237. size = rt_ringbuffer_data_len(rb);
  238. /* no data */
  239. if (size == 0)
  240. return 0;
  241. *ptr = &rb->buffer_ptr[rb->read_index];
  242. if ((rt_size_t)(rb->buffer_size - rb->read_index) > size)
  243. {
  244. return size;
  245. }
  246. size = rb->buffer_size - rb->read_index;
  247. return size;
  248. }
  249. RTM_EXPORT(rt_ringbuffer_peek);
  250. /**
  251. * @brief Put a byte into the ring buffer. If ring buffer is full, this operation will fail.
  252. *
  253. * @param rb A pointer to the ring buffer object.
  254. * @param ch A byte put into the ring buffer.
  255. *
  256. * @return Return the data size we put into the ring buffer. The ring buffer is full if returns 0. Otherwise, it will return 1.
  257. */
  258. rt_size_t rt_ringbuffer_putchar(struct rt_ringbuffer *rb, const rt_uint8_t ch)
  259. {
  260. RT_ASSERT(rb != RT_NULL);
  261. /* whether has enough space */
  262. if (!rt_ringbuffer_space_len(rb))
  263. return 0;
  264. rb->buffer_ptr[rb->write_index] = ch;
  265. /* flip mirror */
  266. if (rb->write_index == rb->buffer_size - 1)
  267. {
  268. rb->write_mirror = ~rb->write_mirror;
  269. rb->write_index = 0;
  270. }
  271. else
  272. {
  273. rb->write_index++;
  274. }
  275. return 1;
  276. }
  277. RTM_EXPORT(rt_ringbuffer_putchar);
  278. /**
  279. * @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.
  280. *
  281. * @param rb A pointer to the ring buffer object.
  282. * @param ch A byte put into the ring buffer.
  283. *
  284. * @return Return the data size we put into the ring buffer. Always return 1.
  285. */
  286. rt_size_t rt_ringbuffer_putchar_force(struct rt_ringbuffer *rb, const rt_uint8_t ch)
  287. {
  288. enum rt_ringbuffer_state old_state;
  289. RT_ASSERT(rb != RT_NULL);
  290. old_state = rt_ringbuffer_status(rb);
  291. rb->buffer_ptr[rb->write_index] = ch;
  292. /* flip mirror */
  293. if (rb->write_index == rb->buffer_size - 1)
  294. {
  295. rb->write_mirror = ~rb->write_mirror;
  296. rb->write_index = 0;
  297. if (old_state == RT_RINGBUFFER_FULL)
  298. {
  299. rb->read_mirror = ~rb->read_mirror;
  300. rb->read_index = rb->write_index;
  301. }
  302. }
  303. else
  304. {
  305. rb->write_index++;
  306. if (old_state == RT_RINGBUFFER_FULL)
  307. rb->read_index = rb->write_index;
  308. }
  309. return 1;
  310. }
  311. RTM_EXPORT(rt_ringbuffer_putchar_force);
  312. /**
  313. * @brief Get a byte from the ring buffer.
  314. *
  315. * @param rb The pointer to the ring buffer object.
  316. * @param ch A pointer to the buffer, used to store one byte.
  317. *
  318. * @return 0 The ring buffer is empty.
  319. * @return 1 Success
  320. */
  321. rt_size_t rt_ringbuffer_getchar(struct rt_ringbuffer *rb, rt_uint8_t *ch)
  322. {
  323. RT_ASSERT(rb != RT_NULL);
  324. /* ringbuffer is empty */
  325. if (!rt_ringbuffer_data_len(rb))
  326. return 0;
  327. /* put byte */
  328. *ch = rb->buffer_ptr[rb->read_index];
  329. if (rb->read_index == rb->buffer_size - 1)
  330. {
  331. rb->read_mirror = ~rb->read_mirror;
  332. rb->read_index = 0;
  333. }
  334. else
  335. {
  336. rb->read_index++;
  337. }
  338. return 1;
  339. }
  340. RTM_EXPORT(rt_ringbuffer_getchar);
  341. /**
  342. * @brief Get the size of data in the ring buffer in bytes.
  343. *
  344. * @param rb The pointer to the ring buffer object.
  345. *
  346. * @return Return the size of data in the ring buffer in bytes.
  347. */
  348. rt_size_t rt_ringbuffer_data_len(struct rt_ringbuffer *rb)
  349. {
  350. switch (rt_ringbuffer_status(rb))
  351. {
  352. case RT_RINGBUFFER_EMPTY:
  353. return 0;
  354. case RT_RINGBUFFER_FULL:
  355. return rb->buffer_size;
  356. case RT_RINGBUFFER_HALFFULL:
  357. default:
  358. {
  359. rt_size_t wi = rb->write_index, ri = rb->read_index;
  360. if (wi > ri)
  361. return wi - ri;
  362. else
  363. return rb->buffer_size - (ri - wi);
  364. }
  365. }
  366. }
  367. RTM_EXPORT(rt_ringbuffer_data_len);
  368. /**
  369. * @brief Reset the ring buffer object, and clear all contents in the buffer.
  370. *
  371. * @param rb A pointer to the ring buffer object.
  372. */
  373. void rt_ringbuffer_reset(struct rt_ringbuffer *rb)
  374. {
  375. RT_ASSERT(rb != RT_NULL);
  376. rb->read_mirror = 0;
  377. rb->read_index = 0;
  378. rb->write_mirror = 0;
  379. rb->write_index = 0;
  380. }
  381. RTM_EXPORT(rt_ringbuffer_reset);
  382. #ifdef RT_USING_HEAP
  383. /**
  384. * @brief Create a ring buffer object with a given size.
  385. *
  386. * @param size The size of the buffer in bytes.
  387. *
  388. * @return Return a pointer to ring buffer object. When the return value is RT_NULL, it means this creation failed.
  389. */
  390. struct rt_ringbuffer *rt_ringbuffer_create(rt_uint32_t size)
  391. {
  392. struct rt_ringbuffer *rb;
  393. rt_uint8_t *pool;
  394. RT_ASSERT(size > 0);
  395. size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
  396. rb = (struct rt_ringbuffer *)rt_malloc(sizeof(struct rt_ringbuffer));
  397. if (rb == RT_NULL)
  398. goto exit;
  399. pool = (rt_uint8_t *)rt_malloc(size);
  400. if (pool == RT_NULL)
  401. {
  402. rt_free(rb);
  403. rb = RT_NULL;
  404. goto exit;
  405. }
  406. rt_ringbuffer_init(rb, pool, size);
  407. exit:
  408. return rb;
  409. }
  410. RTM_EXPORT(rt_ringbuffer_create);
  411. /**
  412. * @brief Destroy the ring buffer object, which is created by rt_ringbuffer_create() .
  413. *
  414. * @param rb A pointer to the ring buffer object.
  415. */
  416. void rt_ringbuffer_destroy(struct rt_ringbuffer *rb)
  417. {
  418. RT_ASSERT(rb != RT_NULL);
  419. rt_free(rb->buffer_ptr);
  420. rt_free(rb);
  421. }
  422. RTM_EXPORT(rt_ringbuffer_destroy);
  423. #endif