arduino-audio-tools
Loading...
Searching...
No Matches
Public Types | Public Member Functions | Protected Types | Protected Member Functions | Static Protected Member Functions | Protected Attributes | List of all members
SPIAudioSlave Class Reference

SPI Audio Slave endpoint matching SPIAudioMaster protocol. More...

#include <SPIAudioSlave.h>

Inheritance diagram for SPIAudioSlave:
AudioStream BaseStream AudioInfoSupport AudioInfoSource Stream Print

Public Types

enum  StatusCode : uint8_t {
  Ok = 0 , InvalidCommand = 1 , InvalidPayload = 2 , BufferOverflow = 3 ,
  InternalError = 4
}
 

Public Member Functions

 SPIAudioSlave (BaseBuffer< uint8_t > &buffer)
 Constructor using an externally provided buffer implementation.
 
virtual void addNotifyAudioChange (AudioInfoSupport &bi)
 Adds target to be notified about audio changes.
 
virtual AudioInfo audioInfo () override
 provides the actual input AudioInfo
 
virtual AudioInfo audioInfoOut ()
 
int available () override
 Returns readable bytes currently buffered.
 
int availableForWrite () override
 Returns remaining writable bytes in the input buffer.
 
virtual bool begin ()
 
bool begin (SPIAudioSlaveConfig cfg=SPIAudioSlaveConfig())
 Initializes protocol state, buffers and optional HW slave support.
 
void clearBuffer ()
 Clears local buffered audio data.
 
virtual void clearNotifyAudioChange ()
 Deletes all change notify subscriptions.
 
void end () override
 Stops the slave and releases all resources.
 
virtual void flush () override
 
bool isActive () const
 Returns true when the slave is active.
 
bool isNotifyActive ()
 Checks if the automatic AudioInfo update is active.
 
const charmimeType ()
 Returns the currently configured mime type.
 
uint8_t onTransfer (uint8_t in)
 Byte-wise SPI handler. Call this for each received SPI byte.
 
virtual operator bool ()
 
bool process ()
 
bool processFrame (const uint8_t *request_frame, uint16_t request_frame_len, uint8_t *response_frame, uint16_t response_frame_max, uint16_t *response_frame_len=nullptr)
 Frame-based helper (same wire format as master, useful for tests)
 
size_t readBytes (uint8_t *data, size_t len) override
 Reads buffered audio bytes.
 
virtual size_t readSilence (uint8_t *buffer, size_t length)
 Source to generate silence: just sets the buffer to 0.
 
virtual bool removeNotifyAudioChange (AudioInfoSupport &bi)
 Removes a target in order not to be notified about audio changes.
 
void setAudioInfo (AudioInfo info) override
 Updates current audio format and mirrors it into config.
 
void setNotifyActive (bool flag)
 Deactivate/Reactivate automatic AudioInfo updates: (default is active)
 
void setWriteBufferSize (int size)
 
size_t write (const uint8_t *data, size_t len) override
 Writes bytes directly into the local slave buffer.
 
virtual size_t write (uint8_t ch) override
 
virtual void writeSilence (size_t len)
 Writes len bytes of silence (=0).
 

Protected Types

enum  ProtocolState : uint8_t {
  RxCmd , RxLenLo , RxLenHi , RxPayload ,
  TxStatus , TxLenLo , TxLenHi , TxPayload
}
 

Protected Member Functions

virtual int not_supported (int out, const char *msg="")
 
void notifyAudioChange (AudioInfo info)
 
void prepareResponse ()
 Evaluates current request payload and prepares response payload.
 
uint8_t processCommand (SPIAudioCommand cmd, const uint8_t *payload, uint16_t payload_len, uint8_t *response, uint16_t response_max, uint16_t &response_len)
 Executes one protocol command and writes response payload.
 
void refillReadBuffer ()
 Refill small read buffer (e.g. 8 bytes) to avoid single byte reads when calling read()
 
void resetProtocolState ()
 Resets internal request/response parser state.
 

Static Protected Member Functions

static uint32_t readU32LE (const uint8_t *in)
 Reads a 32-bit little-endian integer from the source buffer.
 
static void writeU32LE (uint8_t *out, uint32_t value)
 Writes a 32-bit little-endian integer to the target buffer.
 

Protected Attributes

int _timeout = 10
 
bool active = false
 
SPIAudioSlaveConfig config
 
uint8_t current_cmd = 0
 
bool esp32_spi_active = false
 
uint16_t expected_payload_len = 0
 
AudioInfo info
 
bool is_notify_active = true
 
Str mime
 
Vector< AudioInfoSupport * > notify_vector
 
BaseBuffer< uint8_t > * p_buffer = nullptr
 
Vector< uint8_trequest_payload {0}
 
Vector< uint8_tresponse_payload {0}
 
uint16_t rx_pos = 0
 
uint8_t spi_rx_byte = 0
 
uint8_t spi_tx_byte = 0
 
ProtocolState state = RxCmd
 
RingBuffer< uint8_ttmp_in {0}
 
RingBuffer< uint8_ttmp_out {0}
 
uint16_t tx_len = 0
 
uint16_t tx_pos = 0
 
uint8_t tx_status = Ok
 
int write_buffer_size = MAX_SINGLE_CHARS
 

Detailed Description

SPI Audio Slave endpoint matching SPIAudioMaster protocol.

This class implements the slave side of a binary request/response protocol over SPI. It receives commands from a remote SPIAudioMaster and manages an externally-provided audio buffer.

Protocol Role

SPIAudioSlave responds passively to SPI transactions initiated by the master. It parses incoming command frames, executes commands, and sends response frames back. The slave does not control the SPI bus clock or timing.

Supported Commands

Buffer Management

The slave requires an externally-provided BaseBuffer<uint8_t> passed via constructor. The slave does NOT manage buffer memory or sizing; the caller is responsible for:

This design decouples protocol handling from buffer implementation, allowing flexible buffer strategies (ring, linear, DMA-based, etc.).

Protocol Processing Modes

The slave supports two processing patterns:

1. Byte-wise Handler (Flexible)

Call onTransfer(byte) for each SPI byte received (e.g., from an ISR):

slave.begin(cfg);
void spi_isr() {
uint8_t rx_byte = SPI.transfer(0);
uint8_t tx_byte = slave.onTransfer(rx_byte);
SPI.transfer(tx_byte);
}
SPI Audio Slave endpoint matching SPIAudioMaster protocol.
Definition SPIAudioSlave.h:235
size_t writeData(Print *p_out, T *data, int samples, int maxSamples=512)
Definition AudioTypes.h:512

Returns the response byte to send back on the next SPI clock cycle.

2. Frame-based Helper (Testing/Integration)

Use processFrame() to handle complete request/response frames at once:

uint8_t request[256], response[256];
slave.processFrame(request, req_len, response, sizeof(response),

Useful for unit tests or SPI drivers that buffer complete transactions.

3. ESP32 Hardware Slave Mode (Optional)

On ESP32 with use_hw_slave=true, call process() in your main loop:

while (1) {
slave.process(); // Performs one byte transaction with HW SPI slave
}

The hardware SPI slave driver handles all clock/timing; process() just feeds bytes to onTransfer().

State Machine

The slave uses an 8-state machine for parsing request/response frames:

After completing a response, the state machine loops back to RxCmd.

Audio Data Access

After the slave has accepted audio via WriteData commands, retrieve it using:

Error Handling

Commands may fail with status codes (see StatusCode enum):

ESP32-Specific Configuration

When use_hw_slave=true (default on ESP32):

Typical Usage

// Create a ring buffer for incoming audio
RingBuffer<uint8_t> audio_buffer(48000 * 2); // 1 second @ 48kHz stereo
16-bit
cfg.sample_rate = 48000;
cfg.channels = 2;
cfg.bits_per_sample = 16;
slave.begin(cfg);
// Option A: Byte-wise in SPI ISR
uint8_t tx = slave.onTransfer(rx);
}
// Option B: Frame-based polling
while (1) {
if (spi_has_frame()) {
slave.processFrame(request, req_len, response, resp_max, &resp_len);
}
if (slave.available() > 0) {
}
}
// Option C: ESP32 hardware SPI slave (most efficient)
while (1) {
slave.process(); // One byte transaction
if (slave.available() > threshold) {
}
}
slave.end();
Implements a typed Ringbuffer.
Definition Buffers.h:341
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition AudioTypes.h:57
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition AudioTypes.h:59
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition AudioTypes.h:61
Configuration for SPIAudioSlave.
Definition SPIAudioSlave.h:31

Performance Notes

Member Enumeration Documentation

◆ ProtocolState

enum ProtocolState : uint8_t
protected
Enumerator
RxCmd 
RxLenLo 
RxLenHi 
RxPayload 
TxStatus 
TxLenLo 
TxLenHi 
TxPayload 

◆ StatusCode

Enumerator
Ok 
InvalidCommand 
InvalidPayload 
BufferOverflow 
InternalError 

Constructor & Destructor Documentation

◆ SPIAudioSlave()

SPIAudioSlave ( BaseBuffer< uint8_t > &  buffer)
inline

Constructor using an externally provided buffer implementation.

Member Function Documentation

◆ addNotifyAudioChange()

virtual void addNotifyAudioChange ( AudioInfoSupport bi)
inlinevirtualinherited

◆ audioInfo()

virtual AudioInfo audioInfo ( )
inlineoverridevirtualinherited

◆ audioInfoOut()

virtual AudioInfo audioInfoOut ( )
inlinevirtualinherited

◆ available()

int available ( )
inlineoverridevirtual

Returns readable bytes currently buffered.

Reimplemented from BaseStream.

◆ availableForWrite()

int availableForWrite ( )
inlineoverridevirtual

Returns remaining writable bytes in the input buffer.

Reimplemented from BaseStream.

◆ begin() [1/2]

virtual bool begin ( )
inlinevirtualinherited

◆ begin() [2/2]

bool begin ( SPIAudioSlaveConfig  cfg = SPIAudioSlaveConfig())
inline

Initializes protocol state, buffers and optional HW slave support.

◆ clearBuffer()

void clearBuffer ( )
inline

Clears local buffered audio data.

◆ clearNotifyAudioChange()

virtual void clearNotifyAudioChange ( )
inlinevirtualinherited

Deletes all change notify subscriptions.

Reimplemented in RTSPClient< TcpClient, UdpSocket >.

◆ end()

void end ( )
inlineoverridevirtual

Stops the slave and releases all resources.

Reimplemented from BaseStream.

◆ flush()

virtual void flush ( )
inlineoverridevirtualinherited

◆ isActive()

bool isActive ( ) const
inline

Returns true when the slave is active.

◆ isNotifyActive()

bool isNotifyActive ( )
inlineinherited

Checks if the automatic AudioInfo update is active.

◆ mimeType()

const char * mimeType ( )
inline

Returns the currently configured mime type.

◆ not_supported()

virtual int not_supported ( int  out,
const char msg = "" 
)
inlineprotectedvirtualinherited

◆ notifyAudioChange()

void notifyAudioChange ( AudioInfo  info)
inlineprotectedinherited

◆ onTransfer()

uint8_t onTransfer ( uint8_t  in)
inline

Byte-wise SPI handler. Call this for each received SPI byte.

◆ operator bool()

virtual operator bool ( )
inlinevirtualinherited

◆ prepareResponse()

void prepareResponse ( )
inlineprotected

Evaluates current request payload and prepares response payload.

◆ process()

bool process ( )
inline

Processes one hardware SPI byte transaction when HW slave mode is active and forwards it through onTransfer(). Returns false when no byte was processed.

◆ processCommand()

uint8_t processCommand ( SPIAudioCommand  cmd,
const uint8_t payload,
uint16_t  payload_len,
uint8_t response,
uint16_t  response_max,
uint16_t response_len 
)
inlineprotected

Executes one protocol command and writes response payload.

◆ processFrame()

bool processFrame ( const uint8_t request_frame,
uint16_t  request_frame_len,
uint8_t response_frame,
uint16_t  response_frame_max,
uint16_t response_frame_len = nullptr 
)
inline

Frame-based helper (same wire format as master, useful for tests)

◆ readBytes()

size_t readBytes ( uint8_t data,
size_t  len 
)
inlineoverridevirtual

Reads buffered audio bytes.

Reimplemented from AudioStream.

◆ readSilence()

virtual size_t readSilence ( uint8_t buffer,
size_t  length 
)
inlinevirtualinherited

Source to generate silence: just sets the buffer to 0.

◆ readU32LE()

static uint32_t readU32LE ( const uint8_t in)
inlinestaticprotected

Reads a 32-bit little-endian integer from the source buffer.

◆ refillReadBuffer()

void refillReadBuffer ( )
inlineprotectedinherited

Refill small read buffer (e.g. 8 bytes) to avoid single byte reads when calling read()

◆ removeNotifyAudioChange()

virtual bool removeNotifyAudioChange ( AudioInfoSupport bi)
inlinevirtualinherited

Removes a target in order not to be notified about audio changes.

Reimplemented in RTSPClient< TcpClient, UdpSocket >.

◆ resetProtocolState()

void resetProtocolState ( )
inlineprotected

Resets internal request/response parser state.

◆ setAudioInfo()

void setAudioInfo ( AudioInfo  info)
inlineoverridevirtual

Updates current audio format and mirrors it into config.

Reimplemented from AudioStream.

◆ setNotifyActive()

void setNotifyActive ( bool  flag)
inlineinherited

Deactivate/Reactivate automatic AudioInfo updates: (default is active)

◆ setWriteBufferSize()

void setWriteBufferSize ( int  size)
inlineinherited

◆ write() [1/2]

size_t write ( const uint8_t data,
size_t  len 
)
inlineoverridevirtual

Writes bytes directly into the local slave buffer.

Reimplemented from AudioStream.

◆ write() [2/2]

virtual size_t write ( uint8_t  ch)
inlineoverridevirtualinherited

◆ writeSilence()

virtual void writeSilence ( size_t  len)
inlinevirtualinherited

Writes len bytes of silence (=0).

◆ writeU32LE()

static void writeU32LE ( uint8_t out,
uint32_t  value 
)
inlinestaticprotected

Writes a 32-bit little-endian integer to the target buffer.

Member Data Documentation

◆ _timeout

int _timeout = 10
protectedinherited

◆ active

bool active = false
protected

◆ config

SPIAudioSlaveConfig config
protected

◆ current_cmd

uint8_t current_cmd = 0
protected

◆ esp32_spi_active

bool esp32_spi_active = false
protected

◆ expected_payload_len

uint16_t expected_payload_len = 0
protected

◆ info

AudioInfo info
protectedinherited

◆ is_notify_active

bool is_notify_active = true
protectedinherited

◆ mime

Str mime
protected

◆ notify_vector

Vector<AudioInfoSupport*> notify_vector
protectedinherited

◆ p_buffer

BaseBuffer<uint8_t>* p_buffer = nullptr
protected

◆ request_payload

Vector<uint8_t> request_payload {0}
protected

◆ response_payload

Vector<uint8_t> response_payload {0}
protected

◆ rx_pos

uint16_t rx_pos = 0
protected

◆ spi_rx_byte

uint8_t spi_rx_byte = 0
protected

◆ spi_tx_byte

uint8_t spi_tx_byte = 0
protected

◆ state

ProtocolState state = RxCmd
protected

◆ tmp_in

RingBuffer<uint8_t> tmp_in {0}
protectedinherited

◆ tmp_out

RingBuffer<uint8_t> tmp_out {0}
protectedinherited

◆ tx_len

uint16_t tx_len = 0
protected

◆ tx_pos

uint16_t tx_pos = 0
protected

◆ tx_status

uint8_t tx_status = Ok
protected

◆ write_buffer_size

int write_buffer_size = MAX_SINGLE_CHARS
protectedinherited

The documentation for this class was generated from the following file: