lift_indicator_suite/utils/ring_buffer
2026-06-23 15:02:36 +03:00
..
README.md # test_buttons: finished, all documentation refactored 2026-06-23 15:02:36 +03:00
ring_buffer.c # 4 2026-03-16 16:53:16 +03:00
ring_buffer.h # 4 2026-03-16 16:53:16 +03:00

ring_buffer — SPSC кольцевой буфер байт

Lock-free кольцевой буфер для сценария единственный producer / единственный consumer. Типичное использование: ISR пишет принятые байты, задача или main loop читает — без отключения прерываний.

Параметр Значение
Элемент 1 байт (uint8_t)
Ёмкость любая степень двойки, задаётся при ring_buffer_init
Thread-safety SPSC без блокировок; multi-producer/consumer — только с внешней синхронизацией
Зависимости <stdint.h>, <stddef.h>, <stdbool.h>

API

/* Инициализация */
bool ring_buffer_init(ring_buffer_desc_t *p_desc, uint8_t *p_buf, size_t size);
void ring_buffer_reset(ring_buffer_desc_t *p_desc);

/* Состояние */
bool   ring_buffer_is_empty(const ring_buffer_desc_t *p_desc);
bool   ring_buffer_is_full(const ring_buffer_desc_t *p_desc);
size_t ring_buffer_count(const ring_buffer_desc_t *p_desc);
size_t ring_buffer_free(const ring_buffer_desc_t *p_desc);

/* Запись (producer) */
bool   ring_buffer_put(ring_buffer_desc_t *p_desc, uint8_t byte);
size_t ring_buffer_write(ring_buffer_desc_t *p_desc, const uint8_t *p_data, size_t len);

/* Чтение (consumer) */
bool   ring_buffer_get(ring_buffer_desc_t *p_desc, uint8_t *p_byte);
size_t ring_buffer_read(ring_buffer_desc_t *p_desc, uint8_t *p_data, size_t len);

ring_buffer_init требует size — степень двойки; возвращает false при невалидных аргументах. ring_buffer_write / ring_buffer_read возвращают фактически переданное количество байт.


Быстрый старт

#include "ring_buffer/ring_buffer.h"

static uint8_t         storage[256];   /* степень двойки */
static ring_buffer_desc_t rb;

ring_buffer_init(&rb, storage, sizeof(storage));

/* Producer (например, из ISR): */
ring_buffer_put(&rb, received_byte);

/* Consumer (например, из main loop): */
uint8_t b;
if (ring_buffer_get(&rb, &b)) {
    /* обработать b */
}

Тестирование

Host unit-тесты: tests/host/ring_buffer/ — 24 теста, покрывают wraparound, граничные значения и SPSC-симуляцию.

just build::test-host

Примечания по реализации

Wraparound. Индексы head и tail — монотонно возрастающие size_t. Маскирование через & mask (где mask = size - 1) даёт корректный индекс ячейки. Беззнаковый wraparound арифметически корректен: (0 - 1) == SIZE_MAX, подсчёт заполненности через tail - head работает без явной обёртки.

Memory ordering. На Cortex-M7 (strongly-ordered) барьер памяти не нужен. На weakly-ordered архитектурах (ARM64, RISC-V) потребуется store-release / load-acquire — добавить __atomic_store_n / __atomic_load_n.