/* * 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 #include #include #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; }