Skip to content

Commit 761ddd7

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 ea272d3 commit 761ddd7

File tree

9 files changed

+793
-0
lines changed

9 files changed

+793
-0
lines changed

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

tests/lib/bm_fifo/CMakeLists.txt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#
2+
# Copyright (c) 2025 Nordic Semiconductor ASA
3+
#
4+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
#
6+
7+
cmake_minimum_required(VERSION 3.20.0)
8+
9+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
10+
11+
project(bm_fifo)
12+
13+
target_include_directories(app PRIVATE ${ZEPHYR_NRF_BM_MODULE_DIR}/include)
14+
15+
# Generate and add test file
16+
test_runner_generate(src/unity_test.c)
17+
target_sources(app PRIVATE src/unity_test.c)
18+
19+
# Unit under test
20+
target_sources(app PRIVATE ${ZEPHYR_NRF_BM_MODULE_DIR}/lib/bm_fifo/bm_fifo.c)

tests/lib/bm_fifo/prj.conf

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

0 commit comments

Comments
 (0)