Skip to content

Commit 4c99119

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 aa62055 commit 4c99119

File tree

11 files changed

+830
-0
lines changed

11 files changed

+830
-0
lines changed

CODEOWNERS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
/lib/ble_qwr/ @nrfconnect/ncs-bm
4848
/lib/ble_racp/ @nrfconnect/ncs-bm
4949
/lib/bm_buttons/ @nrfconnect/ncs-bm
50+
/lib/bm_fifo/ @nrfconnect/ncs-bm
5051
/lib/bm_timer/ @nrfconnect/ncs-bm
5152
/lib/boot_banner/ @nrfconnect/ncs-bm
5253
/lib/event_scheduler/ @nrfconnect/ncs-bm
@@ -83,6 +84,7 @@
8384
# Tests
8485
/tests/lib/ble_qwr/ @nrfconnect/ncs-bm
8586
/tests/lib/ble_racp/ @nrfconnect/ncs-bm
87+
/tests/lib/bm_fifo/ @nrfconnect/ncs-bm
8688

8789
# Zephyr module
8890
/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 NRF_SUCCESS on success.
58+
* @retval NRF_ERROR_NULL If @p fifo or @p buf are @c NULL.
59+
* @retval NRF_ERROR_INVALID_PARAM 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 *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 *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 NRF_SUCCESS on success.
93+
* @retval NRF_ERROR_NULL If @p fifo or @p buf are @c NULL.
94+
* @retval NRF_ERROR_NO_MEM 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 NRF_SUCCESS on success.
107+
* @retval NRF_ERROR_NULL If @p fifo or @p buf are @c NULL.
108+
* @retval NRF_ERROR_NOT_FOUND 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 NRF_SUCCESS on success.
121+
* @retval NRF_ERROR_NULL If @p fifo or @p buf are @c NULL.
122+
* @retval NRF_ERROR_NOT_FOUND 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 NRF_SUCCESS on success.
134+
* @retval NRF_ERROR_NULL If @p fifo is @c NULL.
135+
* @retval NRF_ERROR_NOT_FOUND 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 NRF_SUCCESS on success.
145+
* @retval NRF_ERROR_NULL 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: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
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 <s115/nrf_error.h>
12+
13+
/* We don't want to include this in unit tests. */
14+
#if CONFIG_HAS_NRFX
15+
#include <nrfx.h>
16+
#else
17+
#define NRFX_CRITICAL_SECTION_ENTER(...)
18+
#define NRFX_CRITICAL_SECTION_EXIT(...)
19+
#endif
20+
21+
#include <bm_fifo.h>
22+
23+
bool bm_fifo_is_full(const struct bm_fifo *fifo)
24+
{
25+
__ASSERT_NO_MSG(fifo);
26+
return (fifo->count == fifo->capacity);
27+
}
28+
29+
bool bm_fifo_is_empty(const struct bm_fifo *fifo)
30+
{
31+
__ASSERT_NO_MSG(fifo);
32+
return (fifo->count == 0);
33+
}
34+
35+
uint32_t bm_fifo_init(struct bm_fifo *fifo, void *buf, size_t capacity, size_t item_size)
36+
{
37+
if (!fifo || !buf) {
38+
return NRF_ERROR_NULL;
39+
}
40+
if (!item_size || !capacity) {
41+
return NRF_ERROR_INVALID_PARAM;
42+
}
43+
44+
memset(fifo, 0x00, sizeof(*fifo));
45+
46+
fifo->buf = buf;
47+
fifo->item_size = item_size;
48+
fifo->capacity = capacity;
49+
50+
return NRF_SUCCESS;
51+
}
52+
53+
uint32_t bm_fifo_enqueue(struct bm_fifo *fifo, void *buf)
54+
{
55+
uint32_t err;
56+
void *item;
57+
58+
if (!fifo || !buf) {
59+
return NRF_ERROR_NULL;
60+
}
61+
62+
NRFX_CRITICAL_SECTION_ENTER();
63+
64+
if (bm_fifo_is_full(fifo)) {
65+
err = NRF_ERROR_NO_MEM;
66+
goto out;
67+
}
68+
69+
fifo->count++;
70+
__ASSERT(fifo->count <= fifo->capacity, "Queue overflow");
71+
72+
item = (uint8_t *)fifo->buf + (fifo->tail * fifo->item_size);
73+
fifo->tail = (fifo->tail + 1) % fifo->capacity;
74+
memcpy(item, buf, fifo->item_size);
75+
76+
err = NRF_SUCCESS;
77+
78+
out:
79+
NRFX_CRITICAL_SECTION_EXIT();
80+
return err;
81+
}
82+
83+
uint32_t bm_fifo_dequeue(struct bm_fifo *fifo, void *buf)
84+
{
85+
uint32_t err;
86+
void *item;
87+
88+
if (!fifo || !buf) {
89+
return NRF_ERROR_NULL;
90+
}
91+
92+
NRFX_CRITICAL_SECTION_ENTER();
93+
94+
if (bm_fifo_is_empty(fifo)) {
95+
err = NRF_ERROR_NOT_FOUND;
96+
goto out;
97+
}
98+
99+
fifo->count--;
100+
__ASSERT(fifo->count <= fifo->capacity, "Queue underflow");
101+
102+
item = (uint8_t *)fifo->buf + (fifo->head * fifo->item_size);
103+
fifo->head = (fifo->head + 1) % fifo->capacity;
104+
memcpy(buf, item, fifo->item_size);
105+
106+
err = NRF_SUCCESS;
107+
108+
out:
109+
NRFX_CRITICAL_SECTION_EXIT();
110+
return err;
111+
}
112+
113+
uint32_t bm_fifo_peek(const struct bm_fifo *fifo, void *buf)
114+
{
115+
uint32_t err;
116+
void *item;
117+
118+
if (!fifo || !buf) {
119+
return NRF_ERROR_NULL;
120+
}
121+
122+
NRFX_CRITICAL_SECTION_ENTER();
123+
124+
if (bm_fifo_is_empty(fifo)) {
125+
err = NRF_ERROR_NOT_FOUND;
126+
goto out;
127+
}
128+
129+
item = (uint8_t *)fifo->buf + (fifo->head * fifo->item_size);
130+
memcpy(buf, item, fifo->item_size);
131+
132+
err = NRF_SUCCESS;
133+
134+
out:
135+
NRFX_CRITICAL_SECTION_EXIT();
136+
return err;
137+
}
138+
139+
uint32_t bm_fifo_discard(struct bm_fifo *fifo)
140+
{
141+
uint32_t err;
142+
143+
if (!fifo) {
144+
return NRF_ERROR_NULL;
145+
}
146+
147+
NRFX_CRITICAL_SECTION_ENTER();
148+
149+
if (bm_fifo_is_empty(fifo)) {
150+
err = NRF_ERROR_NOT_FOUND;
151+
goto out;
152+
}
153+
154+
fifo->count--;
155+
__ASSERT(fifo->count <= fifo->capacity, "Queue underflow");
156+
157+
fifo->head = (fifo->head + 1) % fifo->capacity;
158+
159+
err = NRF_SUCCESS;
160+
161+
out:
162+
NRFX_CRITICAL_SECTION_EXIT();
163+
return err;
164+
}
165+
166+
uint32_t bm_fifo_clear(struct bm_fifo *fifo)
167+
{
168+
if (!fifo) {
169+
return NRF_ERROR_NULL;
170+
}
171+
172+
NRFX_CRITICAL_SECTION_ENTER();
173+
174+
fifo->head = 0;
175+
fifo->tail = 0;
176+
fifo->count = 0;
177+
178+
NRFX_CRITICAL_SECTION_EXIT();
179+
180+
return NRF_SUCCESS;
181+
}

0 commit comments

Comments
 (0)