s3-blob-utils/ADC/kitty-rx/main/ring_buf.h

85 lines
2.1 KiB
C

/*
* Lock-free SPSC ring buffer for audio transport.
* Producer: WiFi ISR/promisc callback (writes 16-bit truncated samples).
* Consumer: UAC mic callback (reads arbitrary byte counts).
*
* Byte-granularity. Single writer, single reader, no locks.
*/
#pragma once
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include "esp_attr.h"
#define RING_BUF_SIZE (48000 * 4 * 1) /* 1 second of 48kHz 16-bit stereo */
typedef struct {
uint8_t buf[RING_BUF_SIZE];
volatile uint32_t wr;
volatile uint32_t rd;
} ring_buf_t;
static inline void ring_buf_init(ring_buf_t *rb)
{
rb->wr = 0;
rb->rd = 0;
}
static inline uint32_t ring_buf_fill(const ring_buf_t *rb)
{
uint32_t w = rb->wr;
uint32_t r = rb->rd;
return (w >= r) ? (w - r) : (RING_BUF_SIZE - r + w);
}
static inline uint32_t ring_buf_free(const ring_buf_t *rb)
{
return RING_BUF_SIZE - 1 - ring_buf_fill(rb);
}
/* Write contiguous block. Returns bytes actually written. */
static inline size_t IRAM_ATTR ring_buf_write(ring_buf_t *rb, const uint8_t *data, size_t len)
{
uint32_t free = ring_buf_free(rb);
if (len > free) len = free;
if (len == 0) return 0;
uint32_t w = rb->wr;
uint32_t tail = RING_BUF_SIZE - w;
if (len <= tail) {
memcpy(rb->buf + w, data, len);
} else {
memcpy(rb->buf + w, data, tail);
memcpy(rb->buf, data + tail, len - tail);
}
__asm__ __volatile__("memw" ::: "memory");
rb->wr = (w + len) % RING_BUF_SIZE;
return len;
}
/* Read up to len bytes. Returns bytes actually read. */
static inline size_t ring_buf_read(ring_buf_t *rb, uint8_t *dst, size_t len)
{
uint32_t fill = ring_buf_fill(rb);
if (len > fill) len = fill;
if (len == 0) return 0;
uint32_t r = rb->rd;
uint32_t tail = RING_BUF_SIZE - r;
if (len <= tail) {
memcpy(dst, rb->buf + r, len);
} else {
memcpy(dst, rb->buf + r, tail);
memcpy(dst + tail, rb->buf, len - tail);
}
__asm__ __volatile__("memw" ::: "memory");
rb->rd = (r + len) % RING_BUF_SIZE;
return len;
}