arduino-audio-tools
Loading...
Searching...
No Matches
SPIAudioMaster.h
Go to the documentation of this file.
1#pragma once
2
3#include <SPI.h>
4
10#include "SPIAudioCommand.h"
11
12#if defined(ESP32)
13#include "driver/spi_slave.h"
14#endif
15
16namespace audio_tools {
17
22#if defined(SS)
23 int cs_pin = SS;
24#else
25 int cs_pin = 10;
26#endif
27 uint32_t clock_hz = 8000000;
30 size_t max_payload = 1024;
31 bool is_blocking_write = false;
32 void log() const {
33 LOGI(
34 "SPIAudioMasterConfig: sample_rate=%d, channels=%d, "
35 "bits_per_sample=%d, cs_pin=%d, clock_hz=%d, bit_order=%s, "
36 "data_mode=%s, max_payload=%d, is_blocking_write=%s",
38 bit_order == MSBFIRST ? "MSBFIRST" : "LSBFIRST",
39 data_mode == SPI_MODE0 ? "SPI_MODE0"
40 : data_mode == SPI_MODE1 ? "SPI_MODE1"
41 : data_mode == SPI_MODE2 ? "SPI_MODE2"
42 : data_mode == SPI_MODE3 ? "SPI_MODE3"
43 : "UNKNOWN",
44 (int)max_payload, is_blocking_write ? "true" : "false");
45 }
46};
47
137 public:
139 SPIAudioMaster() = default;
142
145 config = cfg;
146 config.log();
147 if (p_spi == nullptr) {
148 p_spi = &SPI;
149 }
150 if (config.cs_pin >= 0) {
153 }
154 p_spi->begin();
155 active = true;
156
157 clear(); // Clear remote buffer on start
159 LOGI("SPIAudioMaster started with remote buffer size: %d bytes",
161 return true;
162 }
163
165 void end() {
166 clear();
167 if (p_spi != nullptr) {
168 p_spi->end();
169 }
170 active = false;
171 }
172
174 bool isActive() const { return active; }
175
177 bool setMime(const char* mime) {
178 if (mime == nullptr) return false;
180 reinterpret_cast<const uint8_t*>(mime), strlen(mime) + 1,
181 nullptr, nullptr);
182 }
183
185 void setAudioInfo(AudioInfo info) override {
187 uint8_t payload[6];
189 payload[4] = static_cast<uint8_t>(info.channels);
190 payload[5] = static_cast<uint8_t>(info.bits_per_sample);
192 nullptr, nullptr);
193 }
194
196 size_t write(const uint8_t* data, size_t len) {
197 if (!active) return 0;
198 if (data == nullptr || len == 0) return 0;
199 if (len > buffer_size) {
200 LOGE("Attempting to write %d bytes, but remote buffer size is only %d",
201 (int)len, buffer_size);
202 return 0;
203 }
204
205 size_t chunk = min(config.max_payload, len);
206 if (chunk == 0) return 0;
207
210 chunk = min(chunk, available);
211 if (chunk == 0) return 0;
212 return sendCommand(SPIAudioCommand::WriteData, data, chunk, nullptr,
213 nullptr)
214 ? chunk
215 : 0;
216 }
217
218 // wait until enough space is available for the chunk
219 while (getAvailableBufferSize() < chunk) {
220 delay(10);
221 }
222 return sendCommand(SPIAudioCommand::WriteData, data, chunk, nullptr,
223 nullptr)
224 ? chunk
225 : 0;
226 }
227
230 return active ? static_cast<int>(getAvailableBufferSize()) : 0;
231 }
232
234 bool clear() {
235 return sendCommand(SPIAudioCommand::Clear, nullptr, 0, nullptr, nullptr);
236 }
237
239 int available() {
240 return active ? static_cast<int>(getFilledBufferSize()) : 0;
241 }
242
243 protected:
245 bool active = false;
246 SPIClass* p_spi = nullptr;
247 int buffer_size = 0;
248
251 uint8_t response[4] = {0, 0, 0, 0};
255 return 0;
256 }
257 if (response_len < 4) {
258 return 0;
259 }
260 return readU32LE(response);
261 }
262
265 uint8_t response[4] = {0, 0, 0, 0};
268 &response_len)) {
269 return 0;
270 }
271 if (response_len < 4) {
272 return 0;
273 }
274 return readU32LE(response);
275 }
276
281 if (!active || p_spi == nullptr) return false;
282
284 p_spi->beginTransaction(settings);
285 if (config.cs_pin >= 0) {
287 }
288
289 p_spi->transfer(static_cast<uint8_t>(command));
291
292 for (uint16_t i = 0; i < payload_len; i++) {
293 p_spi->transfer(payload != nullptr ? payload[i] : 0);
294 }
295
296 uint8_t status = p_spi->transfer(0x00);
297 uint16_t len = transferU16LE(0);
299
300 if (response != nullptr && response_len != nullptr) {
302 }
303
304 if (response_len != nullptr) {
305 *response_len = len;
306 }
307
308 for (uint16_t i = 0; i < len; i++) {
309 uint8_t value = p_spi->transfer(0x00);
310 if (response != nullptr && i < response_capacity) {
311 response[i] = value;
312 }
313 }
314
315 if (config.cs_pin >= 0) {
317 }
318 p_spi->endTransaction();
319
320 return status == 0;
321 }
322
325 uint8_t lo = p_spi->transfer(static_cast<uint8_t>(value & 0xFF));
326 uint8_t hi = p_spi->transfer(static_cast<uint8_t>((value >> 8) & 0xFF));
327 return static_cast<uint16_t>(lo) | (static_cast<uint16_t>(hi) << 8);
328 }
329
331 static void writeU32LE(uint8_t* out, uint32_t value) {
332 out[0] = static_cast<uint8_t>(value & 0xFF);
333 out[1] = static_cast<uint8_t>((value >> 8) & 0xFF);
334 out[2] = static_cast<uint8_t>((value >> 16) & 0xFF);
335 out[3] = static_cast<uint8_t>((value >> 24) & 0xFF);
336 }
337
339 static uint32_t readU32LE(const uint8_t* in) {
340 return static_cast<uint32_t>(in[0]) | (static_cast<uint32_t>(in[1]) << 8) |
341 (static_cast<uint32_t>(in[2]) << 16) |
342 (static_cast<uint32_t>(in[3]) << 24);
343 }
344};
345
346} // namespace audio_tools
#define LOGI(...)
Definition AudioLoggerIDF.h:28
#define LOGE(...)
Definition AudioLoggerIDF.h:30
#define HIGH
Definition NoArduino.h:50
#define OUTPUT
Definition NoArduino.h:42
#define LOW
Definition NoArduino.h:53
void pinMode(int pin, int mode)
Definition NoArduino.h:210
void digitalWrite(int pin, int value)
Definition NoArduino.h:206
Abstract Audio Ouptut class.
Definition AudioOutput.h:25
AudioInfo cfg
Definition AudioOutput.h:88
virtual void setAudioInfo(AudioInfo newInfo) override
Defines the input AudioInfo.
Definition AudioOutput.h:49
SPI master endpoint for remote audio sink configuration and PCM data transfer.
Definition SPIAudioMaster.h:136
bool active
Definition SPIAudioMaster.h:245
uint16_t transferU16LE(uint16_t value)
Transfers and/or receives a 16-bit little-endian value over SPI.
Definition SPIAudioMaster.h:324
bool begin(SPIAudioMasterConfig cfg=SPIAudioMasterConfig())
Initializes SPI and stores the master configuration.
Definition SPIAudioMaster.h:144
bool isActive() const
Returns true when the master is active.
Definition SPIAudioMaster.h:174
static void writeU32LE(uint8_t *out, uint32_t value)
Writes a 32-bit little-endian integer to the target buffer.
Definition SPIAudioMaster.h:331
int available()
Queries how many bytes are currently filled/readable in the remote buffer.
Definition SPIAudioMaster.h:239
static uint32_t readU32LE(const uint8_t *in)
Reads a 32-bit little-endian integer from the source buffer.
Definition SPIAudioMaster.h:339
SPIAudioMaster()=default
Default constructor.
uint32_t getAvailableBufferSize()
Queries available space in the remote buffer in bytes.
Definition SPIAudioMaster.h:250
SPIClass * p_spi
Definition SPIAudioMaster.h:246
bool sendCommand(SPIAudioCommand command, const uint8_t *payload, uint16_t payload_len, uint8_t *response, uint16_t *response_len)
Sends a protocol command and reads the optional response.
Definition SPIAudioMaster.h:278
int availableForWrite()
Returns writable bytes on the remote side.
Definition SPIAudioMaster.h:229
bool clear()
Clears the remote audio buffer.
Definition SPIAudioMaster.h:234
void end()
Stops the master and closes the SPI bus.
Definition SPIAudioMaster.h:165
bool setMime(const char *mime)
Set stream mime type (e.g. "audio/wav", "audio/mp3")
Definition SPIAudioMaster.h:177
void setAudioInfo(AudioInfo info) override
Sends audio format information to the remote slave.
Definition SPIAudioMaster.h:185
SPIAudioMaster(SPIClass &spi)
Constructor with explicit SPI bus instance.
Definition SPIAudioMaster.h:141
uint32_t getFilledBufferSize()
Queries how many bytes are filled/readable in the remote buffer.
Definition SPIAudioMaster.h:264
int buffer_size
Definition SPIAudioMaster.h:247
size_t write(const uint8_t *data, size_t len)
Writes audio bytes in chunks using WriteData command.
Definition SPIAudioMaster.h:196
SPIAudioMasterConfig config
Definition SPIAudioMaster.h:244
SPIAudioCommand
SPI command ids used by SPIAudioMaster.
Definition SPIAudioCommand.h:19
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10
void delay(unsigned long ms)
Definition Time.h:23
size_t writeData(Print *p_out, T *data, int samples, int maxSamples=512)
Definition AudioTypes.h:512
Basic Audio information which drives e.g. I2S.
Definition AudioTypes.h:55
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 SPIAudioMaster.
Definition SPIAudioMaster.h:21
uint32_t clock_hz
Definition SPIAudioMaster.h:27
uint8_t data_mode
Definition SPIAudioMaster.h:29
void log() const
Definition SPIAudioMaster.h:32
int cs_pin
Definition SPIAudioMaster.h:25
bool is_blocking_write
Definition SPIAudioMaster.h:31
uint8_t bit_order
Definition SPIAudioMaster.h:28
size_t max_payload
Definition SPIAudioMaster.h:30