Skip to content

Commit a4b37f4

Browse files
lemreyMirkoCovizzi
andcommitted
lib: bm_fifo: a FIFO queue implementation
A simple FIFO queue implementation using a circular buffer, that is ISR-safe. Signed-off-by: Emanuele Di Santo <[email protected]> Co-Authored-by: Mirko Covizzi <[email protected]>
1 parent 281ea45 commit a4b37f4

File tree

11 files changed

+807
-0
lines changed

11 files changed

+807
-0
lines changed

CODEOWNERS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
/lib/ble_qwr/ @nrfconnect/ncs-bm
4545
/lib/ble_racp/ @nrfconnect/ncs-bm
4646
/lib/bm_buttons/ @nrfconnect/ncs-bm
47+
/lib/bm_fifo/ @nrfconnect/ncs-bm
4748
/lib/bm_timer/ @nrfconnect/ncs-bm
4849
/lib/boot_banner/ @nrfconnect/ncs-bm
4950
/lib/event_scheduler/ @nrfconnect/ncs-bm
@@ -76,6 +77,7 @@
7677
# Tests
7778
/tests/lib/ble_qwr/ @nrfconnect/ncs-bm
7879
/tests/lib/ble_racp/ @nrfconnect/ncs-bm
80+
/tests/lib/bm_fifo/ @nrfconnect/ncs-bm
7981

8082
# Zephyr module
8183
/zephyr/ @nrfconnect/ncs-co-build-system

include/bm_fifo.h

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
*/
6+
#include <stddef.h>
7+
#include <stdint.h>
8+
9+
struct bm_fifo {
10+
/**
11+
* @brief FIFO buffer.
12+
*/
13+
void *buf;
14+
/**
15+
* @brief FIFO maximum capacity (number of items).
16+
*/
17+
uint32_t capacity;
18+
/**
19+
* @brief FIFO item size.
20+
*/
21+
size_t item_size;
22+
/**
23+
* @brief Number of items in the queue.
24+
*/
25+
uint32_t count;
26+
/**
27+
* @brief FIFO head.
28+
*/
29+
int head;
30+
/**
31+
* @brief FIFO tail.
32+
*/
33+
int tail;
34+
};
35+
36+
/**
37+
* @brief Statically define a FIFO.
38+
*
39+
* Avoids the @ref bm_fifo_init() call.
40+
*/
41+
#define BM_FIFO_INIT(_name, _capacity, _item_size) \
42+
static uint8_t _name_buf[_item_size * _capacity]; \
43+
static struct bm_fifo _name = { \
44+
.buf = _name_buf, \
45+
.item_size = _item_size, \
46+
.capacity = _capacity, \
47+
}
48+
49+
/**
50+
* @brief Initialize a queue.
51+
*
52+
* @param fifo FIFO queue.
53+
* @param buf Queue buffer.
54+
* @param capacity Buffer capacity, in number of items.
55+
* @param item_size Size of a queue element, in bytes.
56+
*
57+
* @retval 0 on success.
58+
* @retval -EFAULT If @p fifo or @p buf are @c NULL.
59+
* @retval -EINVAL If @p capacity or @p item_size are 0.
60+
*/
61+
uint32_t bm_fifo_init(struct bm_fifo *fifo, void *buf, size_t capacity, size_t item_size);
62+
63+
/**
64+
* @brief Check whether the queue is full.
65+
*
66+
* @param fifo FIFO queue.
67+
*
68+
* @return true Queue is full.
69+
* @return false Queue is not full.
70+
*/
71+
bool bm_fifo_is_full(const struct bm_fifo *const fifo);
72+
73+
/**
74+
* @brief Check whether the queue is empty.
75+
*
76+
* @param fifo FIFO queue.
77+
*
78+
* @return true Queue is empty.
79+
* @return false Queue is not empty.
80+
*/
81+
bool bm_fifo_is_empty(const struct bm_fifo *const fifo);
82+
83+
/**
84+
* @brief Queue an element.
85+
*
86+
* The element is copied into the queue's own buffer.
87+
* Interrupts are disabled during the copy.
88+
*
89+
* @param fifo FIFO queue.
90+
* @param buf Buffer pointing to the element.
91+
*
92+
* @retval 0 on success.
93+
* @retval -EFAULT If @p fifo or @p buf are @c NULL.
94+
* @retval -ENOBUFS If there are no buffers available in the queue.
95+
*/
96+
uint32_t bm_fifo_enqueue(struct bm_fifo *fifo, void *buf);
97+
98+
/**
99+
* @brief Dequeue an element.
100+
*
101+
* Dequeue an element from the queue's head.
102+
*
103+
* @param fifo FIFO queue.
104+
* @param buf Buffer to copy the element into.
105+
*
106+
* @retval 0 on success.
107+
* @retval -EFAULT If @p fifo or @p buf are @c NULL.
108+
* @retval -ENOENT If the queue is empty.
109+
*/
110+
uint32_t bm_fifo_dequeue(struct bm_fifo *fifo, void *buf);
111+
112+
/**
113+
* @brief Peek at the queue.
114+
*
115+
* Peek at the queue's head.
116+
*
117+
* @param fifo FIFO queue.
118+
* @param buf Buffer to copy the element into.
119+
*
120+
* @retval 0 on success.
121+
* @retval -EFAULT If @p fifo or @p buf are @c NULL.
122+
* @retval -ENOENT If the queue is empty.
123+
*/
124+
uint32_t bm_fifo_peek(const struct bm_fifo *fifo, void *buf);
125+
126+
/**
127+
* @brief Dequeue one element and discard it.
128+
*
129+
* Dequeue an element and discard it.
130+
*
131+
* @param fifo FIFO queue.
132+
*
133+
* @retval 0 on success.
134+
* @retval -EFAULT If @p fifo is @c NULL.
135+
* @retval -ENOENT If the queue is empty.
136+
*/
137+
uint32_t bm_fifo_discard(struct bm_fifo *fifo);
138+
139+
/**
140+
* @brief Clear the queue, discarding all elements.
141+
*
142+
* @param fifo FIFO queue.
143+
*
144+
* @retval 0 on success.
145+
* @retval -EFAULT If @p fifo is @c NULL.
146+
*/
147+
uint32_t bm_fifo_clear(struct bm_fifo *fifo);

lib/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ add_subdirectory_ifdef(CONFIG_BLE_RACP ble_racp)
1111
add_subdirectory_ifdef(CONFIG_EVENT_SCHEDULER event_scheduler)
1212
add_subdirectory_ifdef(CONFIG_BM_BUTTONS bm_buttons)
1313
add_subdirectory_ifdef(CONFIG_BM_TIMER bm_timer)
14+
add_subdirectory_ifdef(CONFIG_BM_FIFO bm_fifo)
1415
add_subdirectory_ifdef(CONFIG_BLE_QWR ble_qwr)
1516
add_subdirectory_ifdef(CONFIG_SENSORSIM sensorsim)
1617
add_subdirectory_ifdef(CONFIG_NCS_BARE_METAL_BOOT_BANNER boot_banner)

lib/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ rsource "ble_racp/Kconfig"
1212
rsource "event_scheduler/Kconfig"
1313
rsource "bm_buttons/Kconfig"
1414
rsource "bm_timer/Kconfig"
15+
rsource "bm_fifo/Kconfig"
1516
rsource "ble_qwr/Kconfig"
1617
rsource "sensorsim/Kconfig"
1718
rsource "boot_banner/Kconfig"

lib/bm_fifo/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#
2+
# Copyright (c) 2025 Nordic Semiconductor ASA
3+
#
4+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
#
6+
zephyr_library()
7+
zephyr_library_sources(bm_fifo.c)

lib/bm_fifo/Kconfig

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#
2+
# Copyright (c) 2025 Nordic Semiconductor
3+
#
4+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
#
6+
menuconfig BM_FIFO
7+
bool "FIFO queue library"
8+
help
9+
A simple FIFO queue using a circular buffer.
10+
11+
if BM_FIFO
12+
13+
module=BM_FIFO
14+
module-dep=LOG
15+
module-str=FIFO library
16+
source "${ZEPHYR_BASE}/subsys/logging/Kconfig.template.log_config"
17+
18+
endif

lib/bm_fifo/bm_fifo.c

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
*/
6+
#include <stddef.h>
7+
#include <stdbool.h>
8+
#include <stdint.h>
9+
#include <string.h>
10+
#include <zephyr/sys/__assert.h> /* __ASSERT */
11+
#include <nrfx_glue.h>
12+
#include <nrf_error.h>
13+
14+
#include <bm_fifo.h>
15+
16+
bool bm_fifo_is_full(const struct bm_fifo *const fifo)
17+
{
18+
__ASSERT_NO_MSG(fifo);
19+
return (fifo->count == fifo->capacity);
20+
}
21+
22+
bool bm_fifo_is_empty(const struct bm_fifo *const fifo)
23+
{
24+
__ASSERT_NO_MSG(fifo);
25+
return (fifo->count == 0);
26+
}
27+
28+
uint32_t bm_fifo_init(struct bm_fifo *fifo, void *buf, size_t capacity, size_t item_size)
29+
{
30+
if (!fifo) {
31+
return NRF_ERROR_NULL;
32+
}
33+
if (!item_size || !capacity) {
34+
return NRF_ERROR_INVALID_PARAM;
35+
}
36+
37+
memset(fifo, 0x00, sizeof(*fifo));
38+
39+
fifo->buf = buf;
40+
fifo->item_size = item_size;
41+
fifo->capacity = capacity;
42+
43+
return NRF_SUCCESS;
44+
}
45+
46+
uint32_t bm_fifo_enqueue(struct bm_fifo *fifo, void *buf)
47+
{
48+
int err;
49+
void *item;
50+
51+
if (!fifo || !buf) {
52+
return NRF_ERROR_NULL;
53+
}
54+
55+
NRFX_CRITICAL_SECTION_ENTER();
56+
57+
if (bm_fifo_is_full(fifo)) {
58+
err = NRF_ERROR_NO_MEM;
59+
goto out;
60+
}
61+
62+
fifo->count++;
63+
__ASSERT(fifo->count <= fifo->capacity, "Queue overflow");
64+
65+
item = (uint8_t *)fifo->buf + (fifo->tail * fifo->item_size);
66+
fifo->tail = (fifo->tail + 1) % fifo->capacity;
67+
memcpy(item, buf, fifo->item_size);
68+
69+
err = NRF_SUCCESS;
70+
71+
out:
72+
NRFX_CRITICAL_SECTION_EXIT();
73+
return err;
74+
}
75+
76+
uint32_t bm_fifo_dequeue(struct bm_fifo *fifo, void *buf)
77+
{
78+
int err;
79+
void *item;
80+
81+
if (!fifo || !buf) {
82+
return NRF_ERROR_NULL;
83+
}
84+
85+
NRFX_CRITICAL_SECTION_ENTER();
86+
87+
if (bm_fifo_is_empty(fifo)) {
88+
err = NRF_ERROR_NOT_FOUND;
89+
goto out;
90+
}
91+
92+
fifo->count--;
93+
__ASSERT(fifo->count <= fifo->capacity, "Queue underflow");
94+
95+
item = (uint8_t *)fifo->buf + (fifo->head * fifo->item_size);
96+
fifo->head = (fifo->head + 1) % fifo->capacity;
97+
memcpy(buf, item, fifo->item_size);
98+
99+
err = NRF_SUCCESS;
100+
101+
out:
102+
NRFX_CRITICAL_SECTION_EXIT();
103+
return err;
104+
}
105+
106+
uint32_t bm_fifo_peek(const struct bm_fifo *fifo, void *buf)
107+
{
108+
int err;
109+
void *item;
110+
111+
if (!fifo || !buf) {
112+
return NRF_ERROR_NULL;
113+
}
114+
115+
NRFX_CRITICAL_SECTION_ENTER();
116+
117+
if (bm_fifo_is_empty(fifo)) {
118+
err = NRF_ERROR_NOT_FOUND;
119+
goto out;
120+
}
121+
122+
item = (uint8_t *)fifo->buf + (fifo->head * fifo->item_size);
123+
memcpy(buf, item, fifo->item_size);
124+
125+
err = NRF_SUCCESS;
126+
127+
out:
128+
NRFX_CRITICAL_SECTION_EXIT();
129+
return err;
130+
}
131+
132+
uint32_t bm_fifo_discard(struct bm_fifo *fifo)
133+
{
134+
int err;
135+
136+
if (!fifo) {
137+
return NRF_ERROR_NULL;
138+
}
139+
140+
NRFX_CRITICAL_SECTION_ENTER();
141+
142+
if (bm_fifo_is_empty(fifo)) {
143+
err = NRF_ERROR_NOT_FOUND;
144+
goto out;
145+
}
146+
147+
fifo->count--;
148+
__ASSERT(fifo->count <= fifo->capacity, "Queue underflow");
149+
150+
fifo->head = (fifo->head + 1) % fifo->capacity;
151+
152+
err = NRF_SUCCESS;
153+
154+
out:
155+
NRFX_CRITICAL_SECTION_EXIT();
156+
return err;
157+
}
158+
159+
uint32_t bm_fifo_clear(struct bm_fifo *fifo)
160+
{
161+
if (!fifo) {
162+
return NRF_ERROR_NULL;
163+
}
164+
165+
NRFX_CRITICAL_SECTION_ENTER();
166+
167+
fifo->head = 0;
168+
fifo->tail = 0;
169+
fifo->count = 0;
170+
171+
NRFX_CRITICAL_SECTION_EXIT();
172+
173+
return NRF_SUCCESS;
174+
}

0 commit comments

Comments
 (0)