arduino-audio-tools
Loading...
Searching...
No Matches
BLESerialStream.h
Go to the documentation of this file.
1#pragma once
2
3#include "AudioToolsConfig.h"
9
11#ifndef BLE_SERIAL_MTU_OVERHEAD
12#define BLE_SERIAL_MTU_OVERHEAD 5
13#endif
14
16#define BLE_SERIAL_HEADER_SIZE 2
17
19#define BLE_SERIAL_MAX_VALUE_LEN 512
20
22#ifndef BLE_SERIAL_BUFFER_SIZE
23#define BLE_SERIAL_BUFFER_SIZE 4096
24#endif
25
27#ifndef BLE_SERIAL_PACKET_COUNT
28#define BLE_SERIAL_PACKET_COUNT 100
29#endif
30
31namespace audio_tools {
32
43 public:
44 void setMutex(MutexBase *mutex) { p_mutex = mutex; }
45
47 void resize(int bytes, int packets, bool framed) {
48 LockGuard guard(p_mutex);
49 is_framed = framed;
50 if (data.size() != (size_t)bytes) data.resize(bytes);
51 if (is_framed && sizes.size() != (size_t)packets) sizes.resize(packets);
52 }
53
54 bool isAllocated() { return data.size() > 0; }
55
57 void clear() {
58 LockGuard guard(p_mutex);
59 data.reset();
60 sizes.reset();
61 }
62
64 int write(const uint8_t *packet, int len) {
65 LockGuard guard(p_mutex);
66 if (!is_framed) return data.writeArray(packet, len);
67 if (sizes.availableForWrite() == 0 || data.availableForWrite() < len)
68 return 0;
69 sizes.write(len);
70 return data.writeArray(packet, len);
71 }
72
75 int read(uint8_t *result, int len) {
76 LockGuard guard(p_mutex);
77 if (!is_framed) return data.readArray(result, len);
78 uint16_t size = 0;
79 if (!sizes.peek(size)) return 0;
80 if (size > len) {
81 LOGE("BLESerial: read size %d too small: it must be >= %d", len, size);
82 return 0;
83 }
84 sizes.read(size);
85 return data.readArray(result, size);
86 }
87
89 int available() {
90 LockGuard guard(p_mutex);
91 if (!is_framed) return data.available();
92 uint16_t size = 0;
93 return sizes.peek(size) ? size : 0;
94 }
95
98 LockGuard guard(p_mutex);
99 if (is_framed && sizes.availableForWrite() == 0) return 0;
100 return data.availableForWrite();
101 }
102
103 protected:
106 MutexBase *p_mutex = nullptr;
107 bool is_framed = false;
108};
109
126 public:
128
129 virtual void end() = 0;
130
132 virtual bool connected() = 0;
133
134 operator bool() override { return connected(); }
135
138 void setAudioInfo(AudioInfo newInfo) override {
142 writeAudioInfo(toStr(newInfo));
143 }
144 }
145
147 void setServiceUUID(const char *uuid) { BLE_SERIAL_SERVICE_UUID = uuid; }
148
150 void setRxUUID(const char *uuid) { BLE_CH2_UUID = uuid; }
151
153 void setTxUUID(const char *uuid) { BLE_CH1_UUID = uuid; }
154
156 void setAudioInfoUUID(const char *uuid) { BLE_INFO_UUID = uuid; }
157
159 void setAudioInfoActive(bool flag) { is_audio_info_active = flag; }
160
162 void setFramed(bool flag) { is_framed = flag; }
163
165 void setMTU(int mtu) { max_transfer_size = mtu; }
166
169 void setRxBufferSize(int bytes, int packets = BLE_SERIAL_PACKET_COUNT) {
170 rx_buffer_size = bytes;
171 rx_packet_count = packets;
172 }
173
176 void setTxBufferSize(int bytes, int packets = BLE_SERIAL_PACKET_COUNT) {
177 tx_buffer_size = bytes;
178 tx_packet_count = packets;
179 }
180
185 int result = getMTU() - BLE_SERIAL_MTU_OVERHEAD;
187 return result < max ? result : max;
188 }
189
193 snprintf(audio_info_str, sizeof(audio_info_str), "%d:%d:%d",
194 (int)info.sample_rate, (int)info.channels,
195 (int)info.bits_per_sample);
196 return StrView(audio_info_str);
197 }
198
200 AudioInfo toInfo(const uint8_t *data, size_t len) {
201 AudioInfo result;
202 char str[40] = {0};
203 memcpy(str, data, len < sizeof(str) - 1 ? len : sizeof(str) - 1);
204 int sample_rate = 0, channels = 0, bits = 0;
205 if (sscanf(str, "%d:%d:%d", &sample_rate, &channels, &bits) == 3) {
206 result.sample_rate = sample_rate;
207 result.channels = channels;
208 result.bits_per_sample = bits;
209 }
210 return result;
211 }
212
213 protected:
214 // disable copy constructor
215 BLESerialStream(BLESerialStream const &other) = delete;
216 // disable assign constructor
217 void operator=(BLESerialStream const &other) = delete;
225 bool is_framed = false;
227
228 // Bluetooth LE GATT UUIDs: change them with the setters if required
229 const char *BLE_SERIAL_SERVICE_UUID = "6e400001-b5a3-f393-e0a9-e50e24dcca9e";
230 // read by the client: server -> client
231 const char *BLE_CH1_UUID = "6e400002-b5a3-f393-e0a9-e50e24dcca9e";
232 // written by the client: client -> server
233 const char *BLE_CH2_UUID = "6e400003-b5a3-f393-e0a9-e50e24dcca9e";
234 const char *BLE_INFO_UUID = "6e400004-b5a3-f393-e0a9-e50e24dcca9e";
235
237 virtual int getMTU() { return max_transfer_size; }
238
240 virtual void writeAudioInfo(StrView info) = 0;
241
243 void receiveAudioInfo(const uint8_t *data, size_t size) {
244 if (!is_audio_info_active || size == 0) return;
245 AudioInfo ai = toInfo(data, size);
246 if (!ai) {
247 LOGW("BLESerial: invalid audio info");
248 return;
249 }
250 // no echo to the other side
252 }
253
255 static void setHeader(uint8_t *packet, int len) {
256 packet[0] = len & 0xFF;
257 packet[1] = (len >> 8) & 0xFF;
258 }
259
261 static int getHeader(const uint8_t *packet, int packetLen) {
262 if (packetLen < BLE_SERIAL_HEADER_SIZE) return 0;
263 int len = packet[0] | (packet[1] << 8);
264 int max = packetLen - BLE_SERIAL_HEADER_SIZE;
265 if (len > max) {
266 LOGW("BLESerial: incomplete packet: %d of %d bytes", max, len);
267 len = max;
268 }
269 return len;
270 }
271};
272
285 public:
287
289 virtual bool begin(const char *name) = 0;
290
291 size_t readBytes(uint8_t *data, size_t len) override {
292 poll();
293 return rx_buffer.read(data, len);
294 }
295
296 int available() override {
297 poll();
298 return rx_buffer.available();
299 }
300
301 size_t write(const uint8_t *data, size_t len) override {
302 LOGD("BLESerialServer::write: %d", (int)len);
303 if (!connected()) return 0;
304 setupBuffers();
305 if (is_framed && (int)len > packetSize()) {
306 LOGE("BLESerial: frame of %d bytes > max %d", (int)len, packetSize());
307 return 0;
308 }
309 return tx_buffer.write(data, len);
310 }
311
312 int availableForWrite() override {
313 if (!connected()) return 0;
314 setupBuffers();
315 int result = tx_buffer.availableForWrite();
316 if (is_framed) return result < packetSize() ? 0 : packetSize();
317 // make sure we copy always a consistent amount of data
318 return result < DEFAULT_BUFFER_SIZE ? 0 : result;
319 }
320
321 protected:
326
328 virtual void poll() {}
329
337
339 void receiveData(const uint8_t *data, size_t len) {
340 if (len == 0) return;
341 setupBuffers();
342 uint32_t start = millis();
343 while (rx_buffer.availableForWrite() < (int)len) {
344 if (millis() - start >= (uint32_t)receive_timeout_ms) {
345 LOGW("BLESerial: receive buffer full: %d bytes lost", (int)len);
346 return;
347 }
348 // wait for the buffer to get freed up
349 delay(5);
350 }
351 rx_buffer.write(data, len);
352 }
353
356 int provideData(uint8_t *packet, int maxLen) {
357 setupBuffers();
358 int max = maxLen - BLE_SERIAL_HEADER_SIZE;
359 if (max > packetSize()) max = packetSize();
360 int len = 0;
361 if (max > 0 && tx_buffer.available() > 0) {
362 len = tx_buffer.read(packet + BLE_SERIAL_HEADER_SIZE, max);
363 }
364 setHeader(packet, len);
365 return len + BLE_SERIAL_HEADER_SIZE;
366 }
367
370 // do not send outdated data to the next client
372 }
373};
374
384 public:
386
389 bool begin(const char *localName, int seconds) {
390 TRACEI();
391 if (!startClient(localName)) {
392 LOGE("BLESerial: starting BLE failed");
393 return false;
394 }
395 is_started = true;
396 uint32_t start = millis();
397 while (!connected() && millis() - start < 1000ul * seconds) {
398 delay(10);
399 }
400 return seconds == 0 || connected();
401 }
402
403 size_t readBytes(uint8_t *data, size_t len) override {
404 TRACED();
405 if (rx_buffer.available() == 0) {
406 if (!connected()) return 0;
408 }
409 return rx_buffer.read(data, len);
410 }
411
412 int available() override {
413 int result = rx_buffer.available();
414 if (result > 0) return result;
415 // we need to read from the server to know more
416 return connected() ? packetSize() : 0;
417 }
418
419 size_t write(const uint8_t *data, size_t len) override {
420 TRACED();
421 if (!connected()) return 0;
422 if (is_framed) {
423 if ((int)len > packetSize()) {
424 LOGE("BLESerial: frame of %d bytes > max %d", (int)len, packetSize());
425 return 0;
426 }
427 return sendPacket(data, len) ? len : 0;
428 }
429 // send only packets with the max size
430 for (size_t j = 0; j < len; j++) {
431 write_buffer.write(data[j]);
432 if (write_buffer.isFull()) {
435 return j + 1;
436 }
438 }
439 }
440 return len;
441 }
442
444 void flush() override {
445 if (write_buffer.available() > 0 && connected()) {
447 }
449 }
450
451 int availableForWrite() override {
452 if (!connected()) return 0;
454 }
455
456 bool connected() override {
457 if (!is_started) return false;
458 if (isConnected()) return true;
459 if (!connect()) return false;
460 onConnected();
461 return true;
462 }
463
465 void setWriteThrottle(int ms) { write_throttle = ms; }
466
468 void setConfirmWrite(bool flag) { write_confirmation_flag = flag; }
469
470 protected:
476 bool is_started = false;
477
479 virtual bool startClient(const char *localName) = 0;
481 virtual bool isConnected() = 0;
483 virtual bool connect() = 0;
485 virtual int readPacket(uint8_t *data, int maxLen) = 0;
487 virtual bool writePacket(const uint8_t *data, int len) = 0;
489 virtual bool readAudioInfo() = 0;
490
492 void onConnected() {
493 TRACEI();
498 // the server might use a bigger MTU than we requested
501 // the side that defined the audio info is the source
504 } else {
506 }
507 }
508 }
509
513 int payload = getHeader(read_packet.data(), len);
514 if (payload > 0) {
516 }
517 }
518
519 bool sendPacket(const uint8_t *data, size_t len) {
520 bool rc = writePacket(data, len);
522 return rc;
523 }
524};
525
526} // namespace audio_tools
#define LOGW(...)
Definition AudioLoggerIDF.h:29
#define TRACEI()
Definition AudioLoggerIDF.h:32
#define TRACED()
Definition AudioLoggerIDF.h:31
#define LOGI(...)
Definition AudioLoggerIDF.h:28
#define LOGD(...)
Definition AudioLoggerIDF.h:27
#define LOGE(...)
Definition AudioLoggerIDF.h:30
#define BLE_SERIAL_HEADER_SIZE
Size of the length header in the packets which are read by the client.
Definition BLESerialStream.h:16
#define BLE_SERIAL_PACKET_COUNT
Default max number of packets in the buffers in framed mode.
Definition BLESerialStream.h:28
#define BLE_SERIAL_MTU_OVERHEAD
Bytes which are reserved in each BLE packet for the ATT protocol.
Definition BLESerialStream.h:12
#define BLE_SERIAL_MAX_VALUE_LEN
Max length of a characteristic value defined by the BLE specification.
Definition BLESerialStream.h:19
#define BLE_SERIAL_BUFFER_SIZE
Default size of the receive and transmit buffers in bytes.
Definition BLESerialStream.h:23
#define DEFAULT_BUFFER_SIZE
Definition avr.h:20
Base class for all Audio Streams. It support the boolean operator to test if the object is ready with...
Definition BaseStream.h:120
AudioInfo info
Definition BaseStream.h:171
virtual void setAudioInfo(AudioInfo newInfo) override
Defines the input AudioInfo.
Definition BaseStream.h:128
virtual AudioInfo audioInfo() override
provides the actual input AudioInfo
Definition BaseStream.h:151
Generic BLE serial client logic which is independent of the BLE API. In BLE terminology the client is...
Definition BLESerialStream.h:383
virtual bool connect()=0
Connects to the server if it was found: returns true if successful.
void flush() override
Sends the buffered data which does not fill a complete packet.
Definition BLESerialStream.h:444
virtual bool isConnected()=0
Returns true if we are connected.
virtual bool readAudioInfo()=0
Requests the audio info from the server: returns true if successful.
SingleBuffer< uint8_t > write_buffer
Definition BLESerialStream.h:472
void receivePacket()
Reads the next packet from the server into the receive buffer.
Definition BLESerialStream.h:511
virtual int readPacket(uint8_t *data, int maxLen)=0
Reads the next packet (incl. header) from the server: returns the size.
bool sendPacket(const uint8_t *data, size_t len)
Definition BLESerialStream.h:519
void setConfirmWrite(bool flag)
Writes with response: slower but with flow control.
Definition BLESerialStream.h:468
size_t readBytes(uint8_t *data, size_t len) override
Definition BLESerialStream.h:403
bool is_started
Definition BLESerialStream.h:476
void onConnected()
Common setup after the connection was established.
Definition BLESerialStream.h:492
int available() override
Definition BLESerialStream.h:412
bool begin(const char *localName, int seconds)
Definition BLESerialStream.h:389
int write_throttle
Definition BLESerialStream.h:474
size_t write(const uint8_t *data, size_t len) override
Definition BLESerialStream.h:419
int availableForWrite() override
Definition BLESerialStream.h:451
bool connected() override
Returns true if we are connected with the other side.
Definition BLESerialStream.h:456
virtual bool writePacket(const uint8_t *data, int len)=0
Writes a packet to the server.
bool write_confirmation_flag
Definition BLESerialStream.h:475
BLESerialClientBase(int mtu)
Definition BLESerialStream.h:385
Vector< uint8_t > read_packet
Definition BLESerialStream.h:473
BLESerialPacketBuffer rx_buffer
Definition BLESerialStream.h:471
void setWriteThrottle(int ms)
Waits the indicated ms after each write.
Definition BLESerialStream.h:465
virtual bool startClient(const char *localName)=0
Starts BLE and the scanning for the server.
FIFO for BLE packets: in framed mode the packet boundaries are kept, otherwise the data is handled as...
Definition BLESerialStream.h:42
bool isAllocated()
Definition BLESerialStream.h:54
void resize(int bytes, int packets, bool framed)
Allocates the buffer memory (if not already done)
Definition BLESerialStream.h:47
MutexBase * p_mutex
Definition BLESerialStream.h:106
int available()
Number of available bytes: in framed mode the size of the next packet.
Definition BLESerialStream.h:89
int read(uint8_t *result, int len)
Definition BLESerialStream.h:75
int write(const uint8_t *packet, int len)
Adds a packet: in framed mode only complete packets are added.
Definition BLESerialStream.h:64
int availableForWrite()
Number of bytes which can be written.
Definition BLESerialStream.h:97
RingBuffer< uint16_t > sizes
Definition BLESerialStream.h:105
void clear()
Removes all data.
Definition BLESerialStream.h:57
RingBuffer< uint8_t > data
Definition BLESerialStream.h:104
void setMutex(MutexBase *mutex)
Definition BLESerialStream.h:44
bool is_framed
Definition BLESerialStream.h:107
Generic BLE serial server logic which is independent of the BLE API. In BLE terminology the server is...
Definition BLESerialStream.h:284
void onDisconnected()
Called by the implementation when the client has disconnected.
Definition BLESerialStream.h:369
BLESerialServerBase(int mtu)
Definition BLESerialStream.h:286
size_t readBytes(uint8_t *data, size_t len) override
Definition BLESerialStream.h:291
int available() override
Definition BLESerialStream.h:296
size_t write(const uint8_t *data, size_t len) override
Definition BLESerialStream.h:301
void setupBuffers()
Definition BLESerialStream.h:330
BLESerialPacketBuffer tx_buffer
Definition BLESerialStream.h:323
int availableForWrite() override
Definition BLESerialStream.h:312
void receiveData(const uint8_t *data, size_t len)
Called by the implementation when the client has written data.
Definition BLESerialStream.h:339
int receive_timeout_ms
max time in ms to wait for free space in the receive buffer
Definition BLESerialStream.h:325
int provideData(uint8_t *packet, int maxLen)
Definition BLESerialStream.h:356
virtual void poll()
Process the BLE events (if necessary)
Definition BLESerialStream.h:328
BLESerialPacketBuffer rx_buffer
Definition BLESerialStream.h:322
virtual bool begin(const char *name)=0
Starts the BLE server with the indicated name.
Common functionality of the BLE serial server and client: data is exchanged via two characteristics l...
Definition BLESerialStream.h:125
int max_transfer_size
Definition BLESerialStream.h:218
void setServiceUUID(const char *uuid)
Defines the service UUID.
Definition BLESerialStream.h:147
BLESerialStream(int mtu)
Definition BLESerialStream.h:127
static int getHeader(const uint8_t *packet, int packetLen)
Determines the payload length from the 2 byte header.
Definition BLESerialStream.h:261
void setAudioInfo(AudioInfo newInfo) override
Definition BLESerialStream.h:138
void setFramed(bool flag)
Keeps the write sizes: each write is one BLE packet.
Definition BLESerialStream.h:162
const char * BLE_SERIAL_SERVICE_UUID
Definition BLESerialStream.h:229
virtual bool connected()=0
Returns true if we are connected with the other side.
int rx_buffer_size
Definition BLESerialStream.h:219
const char * BLE_INFO_UUID
Definition BLESerialStream.h:234
bool is_audio_info_defined
Definition BLESerialStream.h:224
int rx_packet_count
Definition BLESerialStream.h:220
BLESerialStream(BLESerialStream const &other)=delete
void setRxUUID(const char *uuid)
Defines the UUID of the characteristic which is written by the client.
Definition BLESerialStream.h:150
AudioInfo toInfo(const uint8_t *data, size_t len)
Converts the string from the info characteristic to the audio info.
Definition BLESerialStream.h:200
void setRxBufferSize(int bytes, int packets=100)
Definition BLESerialStream.h:169
const char * BLE_CH2_UUID
Definition BLESerialStream.h:233
char audio_info_str[40]
Definition BLESerialStream.h:226
int tx_buffer_size
Definition BLESerialStream.h:221
void receiveAudioInfo(const uint8_t *data, size_t size)
Process the audio info which was received from the other side.
Definition BLESerialStream.h:243
void setMTU(int mtu)
Defines the requested MTU (must be called before begin)
Definition BLESerialStream.h:165
void setAudioInfoActive(bool flag)
Activates the exchange of the audio info.
Definition BLESerialStream.h:159
void setTxUUID(const char *uuid)
Defines the UUID of the characteristic which is read by the client.
Definition BLESerialStream.h:153
virtual int getMTU()
Effective MTU.
Definition BLESerialStream.h:237
static void setHeader(uint8_t *packet, int len)
Copies the payload length into the 2 byte header.
Definition BLESerialStream.h:255
int packetSize()
Definition BLESerialStream.h:184
void operator=(BLESerialStream const &other)=delete
bool is_audio_info_active
Definition BLESerialStream.h:223
const char * BLE_CH1_UUID
Definition BLESerialStream.h:231
bool is_framed
Definition BLESerialStream.h:225
void setTxBufferSize(int bytes, int packets=100)
Definition BLESerialStream.h:176
void setAudioInfoUUID(const char *uuid)
Defines the UUID of the audio info characteristic.
Definition BLESerialStream.h:156
StrView toStr(AudioInfo info)
Definition BLESerialStream.h:192
virtual void writeAudioInfo(StrView info)=0
Provides the audio info to the other side.
int tx_packet_count
Definition BLESerialStream.h:222
RAII implementaion using a Mutex: Only a few microcontrollers provide lock guards,...
Definition LockGuard.h:17
Empty Mutex implementation which does nothing.
Definition Mutex.h:15
Implements a typed Ringbuffer.
Definition Buffers.h:363
virtual int readArray(T data[], int len) override
reads multiple values
Definition Buffers.h:412
virtual int writeArray(const T data[], int len) override
Fills the buffer data.
Definition Buffers.h:432
bool peek(T &result) override
peeks the actual entry from the buffer
Definition Buffers.h:383
bool read(T &result) override
reads a single value
Definition Buffers.h:370
virtual int availableForWrite() override
provides the number of entries that are available to write
Definition Buffers.h:478
virtual bool write(T data) override
write add an entry to the buffer
Definition Buffers.h:456
virtual size_t size() override
Returns the maximum capacity of the buffer.
Definition Buffers.h:493
virtual void reset() override
clears the buffer
Definition Buffers.h:468
virtual bool resize(size_t len)
Resizes the buffer if supported: returns false if not supported.
Definition Buffers.h:483
virtual int available() override
provides the number of entries that are available to read
Definition Buffers.h:475
A simple Buffer implementation which just uses a (dynamically sized) array.
Definition Buffers.h:194
bool write(T sample) override
write add an entry to the buffer
Definition Buffers.h:228
int available() override
provides the number of entries that are available to read
Definition Buffers.h:255
bool isFull() override
checks if the buffer is full
Definition Buffers.h:262
T * data()
Provides address of actual data.
Definition Buffers.h:306
bool resize(size_t size)
Resizes the buffer if supported: returns false if not supported.
Definition Buffers.h:327
void reset() override
clears the buffer
Definition Buffers.h:308
A simple wrapper to provide string functions on existing allocated char*. If the underlying char* is ...
Definition StrView.h:29
Vector implementation which provides the most important methods as defined by std::vector....
Definition Vector.h:21
bool resize(size_t newSize, T value)
Definition Vector.h:266
T * data()
Definition Vector.h:321
int size()
Definition Vector.h:178
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition LMSEchoCancellationStream.h:6
void delay(uint32_t ms)
Definition Arduino.h:259
uint32_t millis()
Returns the milliseconds since the start.
Definition Arduino.h:260
Basic Audio information which drives e.g. I2S.
Definition AudioTypes.h:56
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition AudioTypes.h:58
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition AudioTypes.h:60
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition AudioTypes.h:62