lwrb.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712
  1. /**
  2. * \file lwrb.c
  3. * \brief Lightweight ring buffer
  4. */
  5. /*
  6. * Copyright (c) 2024 Tilen MAJERLE
  7. *
  8. * Permission is hereby granted, free of charge, to any person
  9. * obtaining a copy of this software and associated documentation
  10. * files (the "Software"), to deal in the Software without restriction,
  11. * including without limitation the rights to use, copy, modify, merge,
  12. * publish, distribute, sublicense, and/or sell copies of the Software,
  13. * and to permit persons to whom the Software is furnished to do so,
  14. * subject to the following conditions:
  15. *
  16. * The above copyright notice and this permission notice shall be
  17. * included in all copies or substantial portions of the Software.
  18. *
  19. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  20. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  21. * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
  22. * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  23. * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  24. * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  25. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  26. * OTHER DEALINGS IN THE SOFTWARE.
  27. *
  28. * This file is part of LwRB - Lightweight ring buffer library.
  29. *
  30. * Author: Tilen MAJERLE <[email protected]>
  31. * Version: v3.2.0
  32. */
  33. #define LWRB_DISABLE_ATOMIC
  34. #include "lwrb.h"
  35. /* Memory set and copy functions */
  36. #define BUF_MEMSET memset
  37. #define BUF_MEMCPY memcpy
  38. #define BUF_IS_VALID(b) ((b) != NULL && (b)->buff != NULL && (b)->size > 0)
  39. #define BUF_MIN(x, y) ((x) < (y) ? (x) : (y))
  40. #define BUF_MAX(x, y) ((x) > (y) ? (x) : (y))
  41. #define BUF_SEND_EVT(b, type, bp) \
  42. do { \
  43. if ((b)->evt_fn != NULL) { \
  44. (b)->evt_fn((void*)(b), (type), (bp)); \
  45. } \
  46. } while (0)
  47. /* Optional atomic opeartions */
  48. #ifdef LWRB_DISABLE_ATOMIC
  49. #define LWRB_INIT(var, val) (var) = (val)
  50. #define LWRB_LOAD(var, type) (var)
  51. #define LWRB_STORE(var, val, type) (var) = (val)
  52. #else
  53. #define LWRB_INIT(var, val) atomic_init(&(var), (val))
  54. #define LWRB_LOAD(var, type) atomic_load_explicit(&(var), (type))
  55. #define LWRB_STORE(var, val, type) atomic_store_explicit(&(var), (val), (type))
  56. #endif
  57. /**
  58. * \brief Initialize buffer handle to default values with size and buffer data array
  59. * \param[in] buff: Ring buffer instance
  60. * \param[in] buffdata: Pointer to memory to use as buffer data
  61. * \param[in] size: Size of `buffdata` in units of bytes
  62. * Maximum number of bytes buffer can hold is `size - 1`
  63. * \return `1` on success, `0` otherwise
  64. */
  65. uint8_t
  66. lwrb_init(lwrb_t* buff, void* buffdata, lwrb_sz_t size) {
  67. if (buff == NULL || buffdata == NULL || size == 0) {
  68. return 0;
  69. }
  70. buff->evt_fn = NULL;
  71. buff->size = size;
  72. buff->buff = buffdata;
  73. LWRB_INIT(buff->w_ptr, 0);
  74. LWRB_INIT(buff->r_ptr, 0);
  75. return 1;
  76. }
  77. /**
  78. * \brief Check if buff is initialized and ready to use
  79. * \param[in] buff: Ring buffer instance
  80. * \return `1` if ready, `0` otherwise
  81. */
  82. uint8_t
  83. lwrb_is_ready(lwrb_t* buff) {
  84. return BUF_IS_VALID(buff);
  85. }
  86. /**
  87. * \brief Free buffer memory
  88. * \note Since implementation does not use dynamic allocation,
  89. * it just sets buffer handle to `NULL`
  90. * \param[in] buff: Ring buffer instance
  91. */
  92. void
  93. lwrb_free(lwrb_t* buff) {
  94. if (BUF_IS_VALID(buff)) {
  95. buff->buff = NULL;
  96. }
  97. }
  98. /**
  99. * \brief Set event function callback for different buffer operations
  100. * \param[in] buff: Ring buffer instance
  101. * \param[in] evt_fn: Callback function
  102. */
  103. void
  104. lwrb_set_evt_fn(lwrb_t* buff, lwrb_evt_fn evt_fn) {
  105. if (BUF_IS_VALID(buff)) {
  106. buff->evt_fn = evt_fn;
  107. }
  108. }
  109. /**
  110. * \brief Set custom buffer argument, that can be retrieved in the event function
  111. * \param[in] buff: Ring buffer instance
  112. * \param[in] arg: Custom user argument
  113. */
  114. void
  115. lwrb_set_arg(lwrb_t* buff, void* arg) {
  116. if (BUF_IS_VALID(buff)) {
  117. buff->arg = arg;
  118. }
  119. }
  120. /**
  121. * \brief Get custom buffer argument, previously set with \ref lwrb_set_arg
  122. * \param[in] buff: Ring buffer instance
  123. * \return User argument, previously set with \ref lwrb_set_arg
  124. */
  125. void*
  126. lwrb_get_arg(lwrb_t* buff) {
  127. return buff != NULL ? buff->arg : NULL;
  128. }
  129. /**
  130. * \brief Write data to buffer.
  131. * Copies data from `data` array to buffer and advances the write pointer for a maximum of `btw` number of bytes.
  132. *
  133. * It copies less if there is less memory available in the buffer.
  134. * User must check the return value of the function and compare it to
  135. * the requested write length, to determine if everything has been written
  136. *
  137. * \note Use \ref lwrb_write_ex for more advanced usage
  138. *
  139. * \param[in] buff: Ring buffer instance
  140. * \param[in] data: Pointer to data to write into buffer
  141. * \param[in] btw: Number of bytes to write
  142. * \return Number of bytes written to buffer.
  143. * When returned value is less than `btw`, there was no enough memory available
  144. * to copy full data array.
  145. */
  146. lwrb_sz_t
  147. lwrb_write(lwrb_t* buff, const void* data, lwrb_sz_t btw) {
  148. lwrb_sz_t written = 0;
  149. if (lwrb_write_ex(buff, data, btw, &written, 0)) {
  150. return written;
  151. }
  152. return 0;
  153. }
  154. /**
  155. * \brief Write extended functionality
  156. *
  157. * \param buff: Ring buffer instance
  158. * \param data: Pointer to data to write into buffer
  159. * \param btw: Number of bytes to write
  160. * \param bwritten: Output pointer to write number of bytes written into the buffer
  161. * \param flags: Optional flags.
  162. * \ref LWRB_FLAG_WRITE_ALL: Request to write all data (up to btw).
  163. * Will early return if no memory available
  164. * \return `1` if write operation OK, `0` otherwise
  165. */
  166. uint8_t
  167. lwrb_write_ex(lwrb_t* buff, const void* data, lwrb_sz_t btw, lwrb_sz_t* bwritten, uint16_t flags) {
  168. lwrb_sz_t tocopy = 0, free = 0, w_ptr = 0;
  169. const uint8_t* d_ptr = data;
  170. if (!BUF_IS_VALID(buff) || data == NULL || btw == 0) {
  171. return 0;
  172. }
  173. /* Calculate maximum number of bytes available to write */
  174. free = lwrb_get_free(buff);
  175. /* If no memory, or if user wants to write ALL data but no enough space, exit early */
  176. if (free == 0 || (free < btw && (flags & LWRB_FLAG_WRITE_ALL))) {
  177. return 0;
  178. }
  179. btw = BUF_MIN(free, btw);
  180. w_ptr = LWRB_LOAD(buff->w_ptr, memory_order_acquire);
  181. /* Step 1: Write data to linear part of buffer */
  182. tocopy = BUF_MIN(buff->size - w_ptr, btw);
  183. BUF_MEMCPY(&buff->buff[w_ptr], d_ptr, tocopy);
  184. d_ptr += tocopy;
  185. w_ptr += tocopy;
  186. btw -= tocopy;
  187. /* Step 2: Write data to beginning of buffer (overflow part) */
  188. if (btw > 0) {
  189. BUF_MEMCPY(buff->buff, d_ptr, btw);
  190. w_ptr = btw;
  191. }
  192. /* Step 3: Check end of buffer */
  193. if (w_ptr >= buff->size) {
  194. w_ptr = 0;
  195. }
  196. /*
  197. * Write final value to the actual running variable.
  198. * This is to ensure no read operation can access intermediate data
  199. */
  200. LWRB_STORE(buff->w_ptr, w_ptr, memory_order_release);
  201. BUF_SEND_EVT(buff, LWRB_EVT_WRITE, tocopy + btw);
  202. if (bwritten != NULL) {
  203. *bwritten = tocopy + btw;
  204. }
  205. return 1;
  206. }
  207. /**
  208. * \brief Read data from buffer.
  209. * Copies data from `data` array to buffer and advances the read pointer for a maximum of `btr` number of bytes.
  210. *
  211. * It copies less if there is less data available in the buffer.
  212. *
  213. * \note Use \ref lwrb_read_ex for more advanced usage
  214. *
  215. * \param[in] buff: Ring buffer instance
  216. * \param[out] data: Pointer to output memory to copy buffer data to
  217. * \param[in] btr: Number of bytes to read
  218. * \return Number of bytes read and copied to data array
  219. */
  220. lwrb_sz_t
  221. lwrb_read(lwrb_t* buff, void* data, lwrb_sz_t btr) {
  222. lwrb_sz_t read = 0;
  223. if (lwrb_read_ex(buff, data, btr, &read, 0)) {
  224. return read;
  225. }
  226. return 0;
  227. }
  228. /**
  229. * \brief Read extended functionality
  230. *
  231. * \param buff: Ring buffer instance
  232. * \param data: Pointer to memory to write read data from buffer
  233. * \param btr: Number of bytes to read
  234. * \param bread: Output pointer to write number of bytes read from buffer and written to the
  235. * output `data` variable
  236. * \param flags: Optional flags
  237. * \ref LWRB_FLAG_READ_ALL: Request to read all data (up to btr).
  238. * Will early return if no enough bytes in the buffer
  239. * \return `1` if read operation OK, `0` otherwise
  240. */
  241. uint8_t
  242. lwrb_read_ex(lwrb_t* buff, void* data, lwrb_sz_t btr, lwrb_sz_t* bread, uint16_t flags) {
  243. lwrb_sz_t tocopy = 0, full = 0, r_ptr = 0;
  244. uint8_t* d_ptr = data;
  245. if (!BUF_IS_VALID(buff) || data == NULL || btr == 0) {
  246. return 0;
  247. }
  248. /* Calculate maximum number of bytes available to read */
  249. full = lwrb_get_full(buff);
  250. if (full == 0 || (full < btr && (flags & LWRB_FLAG_READ_ALL))) {
  251. return 0;
  252. }
  253. btr = BUF_MIN(full, btr);
  254. r_ptr = LWRB_LOAD(buff->r_ptr, memory_order_acquire);
  255. /* Step 1: Read data from linear part of buffer */
  256. tocopy = BUF_MIN(buff->size - r_ptr, btr);
  257. BUF_MEMCPY(d_ptr, &buff->buff[r_ptr], tocopy);
  258. d_ptr += tocopy;
  259. r_ptr += tocopy;
  260. btr -= tocopy;
  261. /* Step 2: Read data from beginning of buffer (overflow part) */
  262. if (btr > 0) {
  263. BUF_MEMCPY(d_ptr, buff->buff, btr);
  264. r_ptr = btr;
  265. }
  266. /* Step 3: Check end of buffer */
  267. if (r_ptr >= buff->size) {
  268. r_ptr = 0;
  269. }
  270. /*
  271. * Write final value to the actual running variable.
  272. * This is to ensure no write operation can access intermediate data
  273. */
  274. LWRB_STORE(buff->r_ptr, r_ptr, memory_order_release);
  275. BUF_SEND_EVT(buff, LWRB_EVT_READ, tocopy + btr);
  276. if (bread != NULL) {
  277. *bread = tocopy + btr;
  278. }
  279. return 1;
  280. }
  281. /**
  282. * \brief Read from buffer without changing read pointer (peek only)
  283. * \param[in] buff: Ring buffer instance
  284. * \param[in] skip_count: Number of bytes to skip before reading data
  285. * \param[out] data: Pointer to output memory to copy buffer data to
  286. * \param[in] btp: Number of bytes to peek
  287. * \return Number of bytes peeked and written to output array
  288. */
  289. lwrb_sz_t
  290. lwrb_peek(const lwrb_t* buff, lwrb_sz_t skip_count, void* data, lwrb_sz_t btp) {
  291. lwrb_sz_t full = 0, tocopy = 0, r_ptr = 0;
  292. uint8_t* d_ptr = data;
  293. if (!BUF_IS_VALID(buff) || data == NULL || btp == 0) {
  294. return 0;
  295. }
  296. /*
  297. * Calculate maximum number of bytes available to read
  298. * and check if we can even fit to it
  299. */
  300. full = lwrb_get_full(buff);
  301. if (skip_count >= full) {
  302. return 0;
  303. }
  304. r_ptr = LWRB_LOAD(buff->r_ptr, memory_order_relaxed);
  305. r_ptr += skip_count;
  306. full -= skip_count;
  307. if (r_ptr >= buff->size) {
  308. r_ptr -= buff->size;
  309. }
  310. /* Check maximum number of bytes available to read after skip */
  311. btp = BUF_MIN(full, btp);
  312. if (btp == 0) {
  313. return 0;
  314. }
  315. /* Step 1: Read data from linear part of buffer */
  316. tocopy = BUF_MIN(buff->size - r_ptr, btp);
  317. BUF_MEMCPY(d_ptr, &buff->buff[r_ptr], tocopy);
  318. d_ptr += tocopy;
  319. btp -= tocopy;
  320. /* Step 2: Read data from beginning of buffer (overflow part) */
  321. if (btp > 0) {
  322. BUF_MEMCPY(d_ptr, buff->buff, btp);
  323. }
  324. return tocopy + btp;
  325. }
  326. /**
  327. * \brief Get available size in buffer for write operation
  328. * \param[in] buff: Ring buffer instance
  329. * \return Number of free bytes in memory
  330. */
  331. lwrb_sz_t
  332. lwrb_get_free(const lwrb_t* buff) {
  333. lwrb_sz_t size = 0, w_ptr = 0, r_ptr = 0;
  334. if (!BUF_IS_VALID(buff)) {
  335. return 0;
  336. }
  337. /*
  338. * Copy buffer pointers to local variables with atomic access.
  339. *
  340. * To ensure thread safety (only when in single-entry, single-exit FIFO mode use case),
  341. * it is important to write buffer r and w values to local w and r variables.
  342. *
  343. * Local variables will ensure below if statements will always use the same value,
  344. * even if buff->w or buff->r get changed during interrupt processing.
  345. *
  346. * They may change during load operation, important is that
  347. * they do not change during if-else operations following these assignments.
  348. *
  349. * lwrb_get_free is only called for write purpose, and when in FIFO mode, then:
  350. * - buff->w pointer will not change by another process/interrupt because we are in write mode just now
  351. * - buff->r pointer may change by another process. If it gets changed after buff->r has been loaded to local variable,
  352. * buffer will see "free size" less than it actually is. This is not a problem, application can
  353. * always try again to write more data to remaining free memory that was read just during copy operation
  354. */
  355. w_ptr = LWRB_LOAD(buff->w_ptr, memory_order_relaxed);
  356. r_ptr = LWRB_LOAD(buff->r_ptr, memory_order_relaxed);
  357. if (w_ptr >= r_ptr) {
  358. size = buff->size - (w_ptr - r_ptr);
  359. } else {
  360. size = r_ptr - w_ptr;
  361. }
  362. /* Buffer free size is always 1 less than actual size */
  363. return size - 1;
  364. }
  365. /**
  366. * \brief Get number of bytes currently available in buffer
  367. * \param[in] buff: Ring buffer instance
  368. * \return Number of bytes ready to be read
  369. */
  370. lwrb_sz_t
  371. lwrb_get_full(const lwrb_t* buff) {
  372. lwrb_sz_t size = 0, w_ptr = 0, r_ptr = 0;
  373. if (!BUF_IS_VALID(buff)) {
  374. return 0;
  375. }
  376. /*
  377. * Copy buffer pointers to local variables.
  378. *
  379. * To ensure thread safety (only when in single-entry, single-exit FIFO mode use case),
  380. * it is important to write buffer r and w values to local w and r variables.
  381. *
  382. * Local variables will ensure below if statements will always use the same value,
  383. * even if buff->w or buff->r get changed during interrupt processing.
  384. *
  385. * They may change during load operation, important is that
  386. * they do not change during if-else operations following these assignments.
  387. *
  388. * lwrb_get_full is only called for read purpose, and when in FIFO mode, then:
  389. * - buff->r pointer will not change by another process/interrupt because we are in read mode just now
  390. * - buff->w pointer may change by another process. If it gets changed after buff->w has been loaded to local variable,
  391. * buffer will see "full size" less than it really is. This is not a problem, application can
  392. * always try again to read more data from remaining full memory that was written just during copy operation
  393. */
  394. w_ptr = LWRB_LOAD(buff->w_ptr, memory_order_relaxed);
  395. r_ptr = LWRB_LOAD(buff->r_ptr, memory_order_relaxed);
  396. if (w_ptr >= r_ptr) {
  397. size = w_ptr - r_ptr;
  398. } else {
  399. size = buff->size - (r_ptr - w_ptr);
  400. }
  401. return size;
  402. }
  403. /**
  404. * \brief Resets buffer to default values. Buffer size is not modified
  405. * \note This function is not thread safe.
  406. * When used, application must ensure there is no active read/write operation
  407. * \param[in] buff: Ring buffer instance
  408. */
  409. void
  410. lwrb_reset(lwrb_t* buff) {
  411. if (BUF_IS_VALID(buff)) {
  412. LWRB_STORE(buff->w_ptr, 0, memory_order_release);
  413. LWRB_STORE(buff->r_ptr, 0, memory_order_release);
  414. BUF_SEND_EVT(buff, LWRB_EVT_RESET, 0);
  415. }
  416. }
  417. /**
  418. * \brief Get linear address for buffer for fast read
  419. * \param[in] buff: Ring buffer instance
  420. * \return Linear buffer start address
  421. */
  422. void*
  423. lwrb_get_linear_block_read_address(const lwrb_t* buff) {
  424. lwrb_sz_t ptr = 0;
  425. if (!BUF_IS_VALID(buff)) {
  426. return NULL;
  427. }
  428. ptr = LWRB_LOAD(buff->r_ptr, memory_order_relaxed);
  429. return &buff->buff[ptr];
  430. }
  431. /**
  432. * \brief Get length of linear block address before it overflows for read operation
  433. * \param[in] buff: Ring buffer instance
  434. * \return Linear buffer size in units of bytes for read operation
  435. */
  436. lwrb_sz_t
  437. lwrb_get_linear_block_read_length(const lwrb_t* buff) {
  438. lwrb_sz_t len = 0, w_ptr = 0, r_ptr = 0;
  439. if (!BUF_IS_VALID(buff)) {
  440. return 0;
  441. }
  442. /*
  443. * Use temporary values in case they are changed during operations.
  444. * See lwrb_buff_free or lwrb_buff_full functions for more information why this is OK.
  445. */
  446. w_ptr = LWRB_LOAD(buff->w_ptr, memory_order_relaxed);
  447. r_ptr = LWRB_LOAD(buff->r_ptr, memory_order_relaxed);
  448. if (w_ptr > r_ptr) {
  449. len = w_ptr - r_ptr;
  450. } else if (r_ptr > w_ptr) {
  451. len = buff->size - r_ptr;
  452. } else {
  453. len = 0;
  454. }
  455. return len;
  456. }
  457. /**
  458. * \brief Skip (ignore; advance read pointer) buffer data
  459. * Marks data as read in the buffer and increases free memory for up to `len` bytes
  460. *
  461. * \note Useful at the end of streaming transfer such as DMA
  462. * \param[in] buff: Ring buffer instance
  463. * \param[in] len: Number of bytes to skip and mark as read
  464. * \return Number of bytes skipped
  465. */
  466. lwrb_sz_t
  467. lwrb_skip(lwrb_t* buff, lwrb_sz_t len) {
  468. lwrb_sz_t full = 0, r_ptr = 0;
  469. if (!BUF_IS_VALID(buff) || len == 0) {
  470. return 0;
  471. }
  472. full = lwrb_get_full(buff);
  473. len = BUF_MIN(len, full);
  474. r_ptr = LWRB_LOAD(buff->r_ptr, memory_order_acquire);
  475. r_ptr += len;
  476. if (r_ptr >= buff->size) {
  477. r_ptr -= buff->size;
  478. }
  479. LWRB_STORE(buff->r_ptr, r_ptr, memory_order_release);
  480. BUF_SEND_EVT(buff, LWRB_EVT_READ, len);
  481. return len;
  482. }
  483. /**
  484. * \brief Get linear address for buffer for fast read
  485. * \param[in] buff: Ring buffer instance
  486. * \return Linear buffer start address
  487. */
  488. void*
  489. lwrb_get_linear_block_write_address(const lwrb_t* buff) {
  490. lwrb_sz_t ptr = 0;
  491. if (!BUF_IS_VALID(buff)) {
  492. return NULL;
  493. }
  494. ptr = LWRB_LOAD(buff->w_ptr, memory_order_relaxed);
  495. return &buff->buff[ptr];
  496. }
  497. /**
  498. * \brief Get length of linear block address before it overflows for write operation
  499. * \param[in] buff: Ring buffer instance
  500. * \return Linear buffer size in units of bytes for write operation
  501. */
  502. lwrb_sz_t
  503. lwrb_get_linear_block_write_length(const lwrb_t* buff) {
  504. lwrb_sz_t len = 0, w_ptr = 0, r_ptr = 0;
  505. if (!BUF_IS_VALID(buff)) {
  506. return 0;
  507. }
  508. /*
  509. * Use temporary values in case they are changed during operations.
  510. * See lwrb_buff_free or lwrb_buff_full functions for more information why this is OK.
  511. */
  512. w_ptr = LWRB_LOAD(buff->w_ptr, memory_order_relaxed);
  513. r_ptr = LWRB_LOAD(buff->r_ptr, memory_order_relaxed);
  514. if (w_ptr >= r_ptr) {
  515. len = buff->size - w_ptr;
  516. /*
  517. * When read pointer is 0,
  518. * maximal length is one less as if too many bytes
  519. * are written, buffer would be considered empty again (r == w)
  520. */
  521. if (r_ptr == 0) {
  522. /*
  523. * Cannot overflow:
  524. * - If r is not 0, statement does not get called
  525. * - buff->size cannot be 0 and if r is 0, len is greater 0
  526. */
  527. --len;
  528. }
  529. } else {
  530. len = r_ptr - w_ptr - 1;
  531. }
  532. return len;
  533. }
  534. /**
  535. * \brief Advance write pointer in the buffer.
  536. * Similar to skip function but modifies write pointer instead of read
  537. *
  538. * \note Useful when hardware is writing to buffer and application needs to increase number
  539. * of bytes written to buffer by hardware
  540. * \param[in] buff: Ring buffer instance
  541. * \param[in] len: Number of bytes to advance
  542. * \return Number of bytes advanced for write operation
  543. */
  544. lwrb_sz_t
  545. lwrb_advance(lwrb_t* buff, lwrb_sz_t len) {
  546. lwrb_sz_t free = 0, w_ptr = 0;
  547. if (!BUF_IS_VALID(buff) || len == 0) {
  548. return 0;
  549. }
  550. /* Use local variables before writing back to main structure */
  551. free = lwrb_get_free(buff);
  552. len = BUF_MIN(len, free);
  553. w_ptr = LWRB_LOAD(buff->w_ptr, memory_order_acquire);
  554. w_ptr += len;
  555. if (w_ptr >= buff->size) {
  556. w_ptr -= buff->size;
  557. }
  558. LWRB_STORE(buff->w_ptr, w_ptr, memory_order_release);
  559. BUF_SEND_EVT(buff, LWRB_EVT_WRITE, len);
  560. return len;
  561. }
  562. /**
  563. * \brief Searches for a *needle* in an array, starting from given offset.
  564. *
  565. * \note This function is not thread-safe.
  566. *
  567. * \param buff: Ring buffer to search for needle in
  568. * \param bts: Constant byte array sequence to search for in a buffer
  569. * \param len: Length of the \arg bts array
  570. * \param start_offset: Start offset in the buffer
  571. * \param found_idx: Pointer to variable to write index in array where bts has been found
  572. * Must not be set to `NULL`
  573. * \return `1` if \arg bts found, `0` otherwise
  574. */
  575. uint8_t
  576. lwrb_find(const lwrb_t* buff, const void* bts, lwrb_sz_t len, lwrb_sz_t start_offset, lwrb_sz_t* found_idx) {
  577. lwrb_sz_t full = 0, r_ptr = 0, buff_r_ptr = 0, max_x = 0;
  578. uint8_t found = 0;
  579. const uint8_t* needle = bts;
  580. if (!BUF_IS_VALID(buff) || needle == NULL || len == 0 || found_idx == NULL) {
  581. return 0;
  582. }
  583. *found_idx = 0;
  584. full = lwrb_get_full(buff);
  585. /* Verify initial conditions */
  586. if (full < (len + start_offset)) {
  587. return 0;
  588. }
  589. /* Get actual buffer read pointer for this search */
  590. buff_r_ptr = LWRB_LOAD(buff->r_ptr, memory_order_relaxed);
  591. /* Max number of for loops is buff_full - input_len - start_offset of buffer length */
  592. max_x = full - len;
  593. for (lwrb_sz_t skip_x = start_offset; !found && skip_x <= max_x; ++skip_x) {
  594. found = 1; /* Found by default */
  595. /* Prepare the starting point for reading */
  596. r_ptr = buff_r_ptr + skip_x;
  597. if (r_ptr >= buff->size) {
  598. r_ptr -= buff->size;
  599. }
  600. /* Search in the buffer */
  601. for (lwrb_sz_t idx = 0; idx < len; ++idx) {
  602. if (buff->buff[r_ptr] != needle[idx]) {
  603. found = 0;
  604. break;
  605. }
  606. if (++r_ptr >= buff->size) {
  607. r_ptr = 0;
  608. }
  609. }
  610. if (found) {
  611. *found_idx = skip_x;
  612. }
  613. }
  614. return found;
  615. }
  616. #if 1 //²âÊÔº¯Êý
  617. #include <stdio.h>
  618. int main()
  619. {
  620. lwrb_t buff;
  621. uint8_t buff_data[8]={0};
  622. lwrb_init(&buff, buff_data, sizeof(buff_data)); /* Initialize buffer */
  623. printf("³õʼ»¯³¤¶È: %d\r\n", buff.size);
  624. lwrb_write(&buff, "0123456789", 10);
  625. printf("дÈë%2d: %s\r\n", 10, buff_data);
  626. printf("µ±Ç°³¤¶È: %d, Ê£Ó೤¶È: %d\r\n", lwrb_get_full(&buff), lwrb_get_free(&buff));
  627. uint8_t data[8]={0}; /* Application working data */
  628. size_t len;
  629. len = lwrb_read(&buff, data, sizeof(data));
  630. printf("¶ÁÈ¡%2d: %s\r\n", len, data);
  631. printf("µ±Ç°³¤¶È: %d, Ê£Ó೤¶È: %d\r\n", lwrb_get_full(&buff), lwrb_get_free(&buff));
  632. return 0;
  633. }
  634. #endif