Program Listing for File ring_buf.c
↰ Return to documentation for file (components/wifi_sniffer/ring_buf.c)
#include "ring_buf.h"
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "esp_heap_caps.h"
#include "esp_log.h"
static const char *TAG = "RING_BUF";
struct ring_buf {
uint32_t head, tail, cap, slot_size;
uint8_t *slots;
SemaphoreHandle_t lock;
};
static inline uint32_t nxt(uint32_t i, uint32_t cap){
return (i+1U) % cap;
}
esp_err_t ring_buf_create(ring_buf_t **out, uint32_t cap, uint32_t slot_size, bool try_psram)
{
if (!out || !cap || !slot_size)
return ESP_ERR_INVALID_ARG;
ring_buf_t *rb = heap_caps_malloc(sizeof(*rb), MALLOC_CAP_8BIT);
if (!rb)
return ESP_ERR_NO_MEM;
memset(rb, 0, sizeof(*rb));
rb->cap = cap;
rb->slot_size = slot_size;
rb->lock = xSemaphoreCreateMutex();
if (!rb->lock) {
free(rb);
return ESP_ERR_NO_MEM;
}
int caps = MALLOC_CAP_8BIT | (try_psram ? MALLOC_CAP_SPIRAM : 0);
size_t bytes = (size_t)cap * slot_size;
rb->slots = heap_caps_malloc(bytes, caps);
if (!rb->slots) {
vSemaphoreDelete(rb->lock);
free(rb);
return ESP_ERR_NO_MEM;
}
*out = rb;
return ESP_OK;
}
void ring_buf_destroy(ring_buf_t *rb)
{
if (!rb) return;
if (rb->slots) free(rb->slots);
if (rb->lock) vSemaphoreDelete(rb->lock);
free(rb);
}
bool ring_buf_push(ring_buf_t *rb, const ring_slot_hdr_t *hdr, const uint8_t *payload)
{
if (!rb || !hdr || !payload) return false;
bool ok=false;
if (xSemaphoreTake(rb->lock, 0) == pdTRUE) {
uint32_t next = nxt(rb->head, rb->cap);
if (next != rb->tail) {
uint8_t *slot = rb->slots + ((size_t)rb->head * rb->slot_size);
memcpy(slot, hdr, sizeof(*hdr));
memcpy(slot + sizeof(*hdr), payload, hdr->len);
rb->head = next;
ok=true;
}
xSemaphoreGive(rb->lock);
}
return ok;
}
bool ring_buf_pop(ring_buf_t *rb, ring_slot_hdr_t *hdr, uint8_t *payload)
{
if (!rb || !hdr || !payload) return false;
bool ok=false;
if (xSemaphoreTake(rb->lock, pdMS_TO_TICKS(1)) == pdTRUE) {
if (rb->tail != rb->head) {
uint8_t *slot = rb->slots + ((size_t)rb->tail * rb->slot_size);
memcpy(hdr, slot, sizeof(*hdr));
memcpy(payload, slot + sizeof(*hdr), hdr->len);
rb->tail = nxt(rb->tail, rb->cap);
ok=true;
}
xSemaphoreGive(rb->lock);
}
return ok;
}
uint32_t ring_buf_size(const ring_buf_t *rb)
{
if (!rb) return 0;
int32_t diff = (int32_t)rb->head - (int32_t)rb->tail;
if (diff < 0) diff += (int32_t)rb->cap;
return (uint32_t)diff;
}
uint32_t ring_buf_cap(const ring_buf_t *rb)
{
return rb ? rb->cap : 0;
}
uint32_t ring_buf_free(const ring_buf_t *rb)
{
if (!rb) return 0;
return rb->cap - ring_buf_size(rb) - 1;
}
void ring_buf_reset(ring_buf_t *rb)
{
if (!rb) return;
if (xSemaphoreTake(rb->lock, portMAX_DELAY) == pdTRUE) {
rb->head = 0;
rb->tail = 0;
// 필요하면 버퍼 내용도 지우고 싶을 때:
// memset(rb->slots, 0, (size_t)rb->cap * rb->slot_size);
xSemaphoreGive(rb->lock);
}
}