|
arduino-audio-tools
|
SPI Audio Slave endpoint matching SPIAudioMaster protocol. More...
#include <SPIAudioSlave.h>
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 char * | mimeType () |
| 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_t > | request_payload {0} |
| Vector< uint8_t > | response_payload {0} |
| uint16_t | rx_pos = 0 |
| uint8_t | spi_rx_byte = 0 |
| uint8_t | spi_tx_byte = 0 |
| ProtocolState | state = RxCmd |
| RingBuffer< uint8_t > | tmp_in {0} |
| RingBuffer< uint8_t > | tmp_out {0} |
| uint16_t | tx_len = 0 |
| uint16_t | tx_pos = 0 |
| uint8_t | tx_status = Ok |
| int | write_buffer_size = MAX_SINGLE_CHARS |
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.
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.
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:
readBytes() on your scheduleThis design decouples protocol handling from buffer implementation, allowing flexible buffer strategies (ring, linear, DMA-based, etc.).
The slave supports two processing patterns:
Call onTransfer(byte) for each SPI byte received (e.g., from an ISR):
Returns the response byte to send back on the next SPI clock cycle.
Use processFrame() to handle complete request/response frames at once:
Useful for unit tests or SPI drivers that buffer complete transactions.
On ESP32 with use_hw_slave=true, call process() in your main loop:
The hardware SPI slave driver handles all clock/timing; process() just feeds bytes to onTransfer().
The slave uses an 8-state machine for parsing request/response frames:
After completing a response, the state machine loops back to RxCmd.
After the slave has accepted audio via WriteData commands, retrieve it using:
available(): Returns bytes ready to readreadBytes(buf, len): Read up to len bytes into bufavailableForWrite(): Check space before master sends more datawrite(buf, len): Directly write to buffer (for local testing)clearBuffer(): Empty the bufferCommands may fail with status codes (see StatusCode enum):
When use_hw_slave=true (default on ESP32):
available() regularly to prevent overflow.
|
protected |
|
inline |
Constructor using an externally provided buffer implementation.
|
inlinevirtualinherited |
Adds target to be notified about audio changes.
Reimplemented in CodecNOP, EncodedAudioOutput, EncodedAudioStream, AACDecoderFDK, DecoderBasic, CodecChain, MP3DecoderHelix, MP3DecoderMAD, OggContainerDecoder, RTSPClient< TcpClient, UdpSocket >, Pipeline, and Pipeline::ModifyingStreamAdapter.
provides the actual input AudioInfo
Implements AudioInfoSupport.
Reimplemented in JupyterAudioT< T >, MozziStream, TimerCallbackAudioStream, EncodedAudioStream, PureDataStream, AdapterAudioOutputToAudioStream, GeneratedSoundStream< T >, GeneratedSoundStream< int16_t >, and InputMerge< T >.
provides the actual output AudioInfo: this is usually the same as audioInfo() unless we use a transforming stream
Reimplemented in PureDataStream, PWMAudioOutput, ChannelFormatConverterStreamT< T >, ChannelFormatConverterStream, NumberFormatConverterStreamT< TFrom, TTo >, NumberFormatConverterStream, FormatConverterStream, Pipeline, ResampleStream, and ResampleStreamT< TInterpolator >.
|
inlineoverridevirtual |
Returns readable bytes currently buffered.
Reimplemented from BaseStream.
|
inlineoverridevirtual |
Returns remaining writable bytes in the input buffer.
Reimplemented from BaseStream.
Reimplemented in AudioOutputWithCallback, AudioMP34DT05, I2SCodecStream, MozziStream, PureDataStream, SPDIFOutput, VS1053Stream, WM8960Stream, AdaptiveResamplingStream, AudioLoRa, ESPNowStream, VBANStream, AudioEffectStreamT< T >, Equalizer3Bands, Equalizer3BandsPerChannel, I2SStream, AudioStreamWrapper, TimerCallbackAudioStream, FrequencyDetectorAutoCorrelation, GoertzelStream, ResampleStreamT< TInterpolator >, FileLoopT< FileType >, FileLoopT< File >, LoRaStream, EncodedAudioStream, AudioBoardStream, AudioFFTBase, AudioKitStream, MiniAudioStream, PortAudioStream, StdioStream, HLSStreamT< URLStream >, AnalogAudioArduino, AnalogAudioStream, AdapterAudioOutputToAudioStream, TimedStream, MemoryStream, GeneratedSoundStream< T >, GeneratedSoundStream< int16_t >, MeasuringStream, ProgressStream, Throttle, InputMerge< T >, CallbackStream, FilteredStream< T, TF >, FilteredStream< int16_t, int16_t >, VolumeMeter, AudioInputMonitor, ChannelFormatConverterStreamT< T >, ChannelFormatConverterStream, NumberFormatConverterStreamT< TFrom, TTo >, NumberFormatConverterStream, FormatConverterStream, CatStream, QueueStream< T >, QueueStream< uint8_t >, DynamicMemoryStream, Pipeline, Pipeline::ModifyingStreamAdapter, ResampleStream, VolumeStream, and EqualizerNBands< SampleT, AccT, NUM_TAPS, NUM_BANDS >.
|
inline |
Initializes protocol state, buffers and optional HW slave support.
|
inline |
Clears local buffered audio data.
Deletes all change notify subscriptions.
Reimplemented in RTSPClient< TcpClient, UdpSocket >.
|
inlineoverridevirtual |
Stops the slave and releases all resources.
Reimplemented from BaseStream.
Reimplemented from Print.
Reimplemented in PureDataStream, URLStreamBufferedT< T >, URLStreamBufferedT< ICYStream >, ReformatBaseStream, AudioStreamWrapper, ResampleStream, EncodedAudioStream, URLStream, BufferedTaskStream, I2SStream, MemoryStream, RingBufferStream, GeneratedSoundStream< T >, GeneratedSoundStream< int16_t >, and BufferedStream.
|
inline |
Returns true when the slave is active.
Byte-wise SPI handler. Call this for each received SPI byte.
|
inlineprotected |
Evaluates current request payload and prepares response payload.
|
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.
|
inlineprotected |
Executes one protocol command and writes response payload.
|
inline |
Frame-based helper (same wire format as master, useful for tests)
Reads buffered audio bytes.
Reimplemented from AudioStream.
Source to generate silence: just sets the buffer to 0.
Reads a 32-bit little-endian integer from the source buffer.
|
inlineprotectedinherited |
Refill small read buffer (e.g. 8 bytes) to avoid single byte reads when calling read()
|
inlinevirtualinherited |
Removes a target in order not to be notified about audio changes.
Reimplemented in RTSPClient< TcpClient, UdpSocket >.
|
inlineprotected |
Resets internal request/response parser state.
Updates current audio format and mirrors it into config.
Reimplemented from AudioStream.
Deactivate/Reactivate automatic AudioInfo updates: (default is active)
Writes bytes directly into the local slave buffer.
Reimplemented from AudioStream.
Reimplemented in MemoryStream, AudioStreamWrapper, BufferedTaskStream, RingBufferStream, BufferedStream, and URLStream.
Writes a 32-bit little-endian integer to the target buffer.
|
protectedinherited |
|
protected |
|
protected |
|
protected |
|
protectedinherited |
|
protected |
|
protectedinherited |
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |
|
protectedinherited |
|
protectedinherited |
|
protected |
|
protected |
|
protectedinherited |