arduino-audio-tools
Loading...
Searching...
No Matches
BLESerialClientArduinoBLE.h
Go to the documentation of this file.
1#pragma once
2
3#include <ArduinoBLE.h>
4#include "BLESerialStream.h"
5
7#ifndef BLE_SERIAL_MAX_READ_ERRORS
8#define BLE_SERIAL_MAX_READ_ERRORS 3
9#endif
10
12#ifndef BLE_SERIAL_SCAN_RESTART_MS
13#define BLE_SERIAL_SCAN_RESTART_MS 10000
14#endif
15
16namespace audio_tools {
17
27 public:
31
32 void end() override {
33 TRACEI();
34 flush();
35 is_started = false;
36 is_setup = false;
37 is_scanning = false;
38 if (peripheral) peripheral.disconnect();
39 BLE.end();
40 }
41
42 protected:
43 BLEDevice peripheral;
44 BLECharacteristic ch01_char; // read
45 BLECharacteristic ch02_char; // write
46 BLECharacteristic info_char;
47 bool is_setup = false;
48 bool is_scanning = false;
49 int read_errors = 0;
51 const char *local_name = "";
52
54 static BLESerialClientArduinoBLE *self = nullptr;
55 return self;
56 }
57
58 bool startClient(const char *localName) override {
59 if (!BLE.begin()) return false;
60 local_name = localName;
61 BLE.setLocalName(localName);
62 is_scanning = false;
63 startScan();
64 return is_scanning;
65 }
66
67 bool isConnected() override {
68 // BLEDevice::connected() also processes the BLE events
69 return is_setup && peripheral.connected();
70 }
71
72 bool connect() override {
73 // we lost the connection or the scan could not be started yet
74 is_setup = false;
75 startScan();
76 BLEDevice device = BLE.available();
77 if (!device) return false;
78 TRACEI();
79 BLE.stopScan();
80 is_scanning = false;
81 peripheral = device;
82
83 LOGI("BLESerial: connecting to %s", peripheral.address().c_str());
84 if (!peripheral.connect()) {
85 LOGE("BLESerial: connect failed");
86 return reconnectLater();
87 }
88
89 if (!peripheral.discoverService(BLE_SERIAL_SERVICE_UUID)) {
90 LOGE("BLESerial: service not found: %s", BLE_SERIAL_SERVICE_UUID);
91 return reconnectLater();
92 }
93
94 ch01_char = peripheral.characteristic(BLE_CH1_UUID);
95 ch02_char = peripheral.characteristic(BLE_CH2_UUID);
96 if (!ch01_char || !ch02_char) {
97 LOGE("BLESerial: characteristics not found");
98 return reconnectLater();
99 }
100
102 info_char = peripheral.characteristic(BLE_INFO_UUID);
103 if (!info_char) {
104 LOGW("BLESerial: audio info not supported by server");
105 } else if (info_char.canSubscribe()) {
106 info_char.setEventHandler(BLEUpdated, onInfoUpdatedCB);
107 info_char.subscribe();
108 }
109 }
110
111 LOGI("BLESerial: connected");
112 read_errors = 0;
113 is_setup = true;
114 return true;
115 }
116
119 is_setup = false;
120 if (peripheral) peripheral.disconnect();
121 startScan();
122 return false;
123 }
124
125 void startScan() {
126 if (is_scanning) {
127 // the scan can get stuck after a lost connection: restart it
129 BLE.stopScan();
130 }
131 // with duplicates: a server that was seen before is reported again
132 is_scanning = BLE.scanForUuid(BLE_SERIAL_SERVICE_UUID, true) != 0;
133 if (!is_scanning && is_started) {
134 // the BLE stack can get stuck after a lost connection: restart it
135 LOGW("BLESerial: scan failed: restarting BLE");
136 BLE.end();
137 if (BLE.begin()) {
138 BLE.setLocalName(local_name);
139 is_scanning = BLE.scanForUuid(BLE_SERIAL_SERVICE_UUID, true) != 0;
140 }
141 }
143 if (is_scanning) LOGI("BLESerial: scanning for %s", BLE_SERIAL_SERVICE_UUID);
144 }
145
146 int readPacket(uint8_t *data, int maxLen) override {
147 if (!ch01_char.read()) {
148 // e.g. the server was reset without disconnecting
150 LOGW("BLESerial: %d read errors: reconnecting", read_errors);
152 }
153 return 0;
154 }
155 read_errors = 0;
156 int len = ch01_char.valueLength();
157 if (len > maxLen) len = maxLen;
158 memcpy(data, ch01_char.value(), len);
159 return len;
160 }
161
162 bool writePacket(const uint8_t *data, int len) override {
163 // returns 1 if successful
164 return ch02_char.writeValue(data, len, write_confirmation_flag) != 0;
165 }
166
167 void writeAudioInfo(StrView str) override {
168 TRACEI();
169 if (!isConnected() || !info_char) return;
170 info_char.writeValue((const uint8_t *)str.c_str(), str.length() + 1);
171 }
172
173 bool readAudioInfo() override {
174 if (!info_char || !info_char.read()) return false;
175 receiveAudioInfo(info_char.value(), info_char.valueLength());
176 return info_char.valueLength() > 0;
177 }
178
179 static void onInfoUpdatedCB(BLEDevice device,
180 BLECharacteristic characteristic) {
181 TRACEI();
183 if (self == nullptr) return;
184 self->receiveAudioInfo(characteristic.value(),
185 characteristic.valueLength());
186 }
187};
188
189} // namespace audio_tools
#define LOGW(...)
Definition AudioLoggerIDF.h:29
#define TRACEI()
Definition AudioLoggerIDF.h:32
#define LOGI(...)
Definition AudioLoggerIDF.h:28
#define LOGE(...)
Definition AudioLoggerIDF.h:30
#define BLE_SERIAL_MAX_READ_ERRORS
Number of consecutive failed reads after which we reconnect.
Definition BLESerialClientArduinoBLE.h:8
#define BLE_SERIAL_SCAN_RESTART_MS
Time in ms after which a scan without result is restarted.
Definition BLESerialClientArduinoBLE.h:13
A BLE client that implements a serial protocol, so that it can be used to send and receive audio....
Definition BLESerialClientArduinoBLE.h:26
void writeAudioInfo(StrView str) override
Provides the audio info to the other side.
Definition BLESerialClientArduinoBLE.h:167
bool writePacket(const uint8_t *data, int len) override
Writes a packet to the server.
Definition BLESerialClientArduinoBLE.h:162
BLEDevice peripheral
Definition BLESerialClientArduinoBLE.h:43
BLECharacteristic ch01_char
Definition BLESerialClientArduinoBLE.h:44
BLECharacteristic ch02_char
Definition BLESerialClientArduinoBLE.h:45
void startScan()
Definition BLESerialClientArduinoBLE.h:125
uint32_t scan_start_ms
Definition BLESerialClientArduinoBLE.h:50
void end() override
Definition BLESerialClientArduinoBLE.h:32
static void onInfoUpdatedCB(BLEDevice device, BLECharacteristic characteristic)
Definition BLESerialClientArduinoBLE.h:179
int readPacket(uint8_t *data, int maxLen) override
Reads the next packet (incl. header) from the server: returns the size.
Definition BLESerialClientArduinoBLE.h:146
bool connect() override
Connects to the server if it was found: returns true if successful.
Definition BLESerialClientArduinoBLE.h:72
int read_errors
Definition BLESerialClientArduinoBLE.h:49
bool is_scanning
Definition BLESerialClientArduinoBLE.h:48
bool startClient(const char *localName) override
Starts BLE and the scanning for the server.
Definition BLESerialClientArduinoBLE.h:58
bool readAudioInfo() override
Requests the audio info from the server: returns true if successful.
Definition BLESerialClientArduinoBLE.h:173
BLESerialClientArduinoBLE(int mtu=242)
Definition BLESerialClientArduinoBLE.h:28
bool is_setup
Definition BLESerialClientArduinoBLE.h:47
bool isConnected() override
Returns true if we are connected.
Definition BLESerialClientArduinoBLE.h:67
BLECharacteristic info_char
Definition BLESerialClientArduinoBLE.h:46
bool reconnectLater()
disconnect and scan again
Definition BLESerialClientArduinoBLE.h:118
const char * local_name
Definition BLESerialClientArduinoBLE.h:51
static BLESerialClientArduinoBLE *& selfBLESerialClientArduinoBLE()
Definition BLESerialClientArduinoBLE.h:53
Generic BLE serial client logic which is independent of the BLE API. In BLE terminology the client is...
Definition BLESerialStream.h:383
void flush() override
Sends the buffered data which does not fill a complete packet.
Definition BLESerialStream.h:444
bool is_started
Definition BLESerialStream.h:476
bool write_confirmation_flag
Definition BLESerialStream.h:475
const char * BLE_SERIAL_SERVICE_UUID
Definition BLESerialStream.h:229
const char * BLE_INFO_UUID
Definition BLESerialStream.h:234
const char * BLE_CH2_UUID
Definition BLESerialStream.h:233
void receiveAudioInfo(const uint8_t *data, size_t size)
Process the audio info which was received from the other side.
Definition BLESerialStream.h:243
bool is_audio_info_active
Definition BLESerialStream.h:223
const char * BLE_CH1_UUID
Definition BLESerialStream.h:231
A simple wrapper to provide string functions on existing allocated char*. If the underlying char* is ...
Definition StrView.h:29
virtual int length()
Definition StrView.h:460
virtual const char * c_str()
provides the string value as const char*
Definition StrView.h:456
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition LMSEchoCancellationStream.h:6
uint32_t millis()
Returns the milliseconds since the start.
Definition Arduino.h:260