3.3.7
This commit is contained in:
@@ -0,0 +1,280 @@
|
||||
/*
|
||||
* BLE Client and Server Coexistence Example
|
||||
*
|
||||
* This example demonstrates how to run both BLE client and server
|
||||
* functionality on the same ESP32 device simultaneously.
|
||||
*
|
||||
* The device will:
|
||||
* - Act as a BLE server, advertising a service with a characteristic
|
||||
* - Act as a BLE client, scanning for other BLE servers
|
||||
* - Connect to found servers and interact with their services
|
||||
* - Handle both incoming and outgoing connections
|
||||
*
|
||||
* You can test this example by uploading it to two ESP32 boards.
|
||||
*
|
||||
* Author: lucasssvaz
|
||||
* Based on Arduino BLE examples
|
||||
*/
|
||||
|
||||
#include <BLEDevice.h>
|
||||
#include <BLEUtils.h>
|
||||
#include <BLEServer.h>
|
||||
#include <BLEClient.h>
|
||||
#include <BLEScan.h>
|
||||
|
||||
// Server-side definitions
|
||||
#define SERVER_SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
|
||||
#define SERVER_CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
|
||||
|
||||
// Client-side definitions (looking for the same service)
|
||||
static BLEUUID clientServiceUUID(SERVER_SERVICE_UUID);
|
||||
static BLEUUID clientCharUUID(SERVER_CHARACTERISTIC_UUID);
|
||||
|
||||
// Server objects
|
||||
BLEServer *pServer = nullptr;
|
||||
BLECharacteristic *pServerCharacteristic = nullptr;
|
||||
|
||||
// Client objects
|
||||
static boolean doConnect = false;
|
||||
static boolean clientConnected = false;
|
||||
static BLERemoteCharacteristic *pRemoteCharacteristic;
|
||||
static BLEAdvertisedDevice *targetDevice;
|
||||
static BLEClient *pClient = nullptr;
|
||||
BLEScan *pBLEScan = nullptr;
|
||||
|
||||
// Server callbacks
|
||||
class ServerCallbacks : public BLEServerCallbacks {
|
||||
void onConnect(BLEServer *pServer) {
|
||||
Serial.println("Server: Client connected");
|
||||
}
|
||||
|
||||
void onDisconnect(BLEServer *pServer) {
|
||||
Serial.println("Server: Client disconnected");
|
||||
// Restart advertising
|
||||
BLEDevice::startAdvertising();
|
||||
}
|
||||
};
|
||||
|
||||
// Characteristic callbacks for server
|
||||
class CharacteristicCallbacks : public BLECharacteristicCallbacks {
|
||||
void onWrite(BLECharacteristic *pCharacteristic) {
|
||||
String value = pCharacteristic->getValue();
|
||||
Serial.print("Server: Characteristic written, value: ");
|
||||
Serial.println(value.c_str());
|
||||
}
|
||||
|
||||
void onRead(BLECharacteristic *pCharacteristic) {
|
||||
Serial.println("Server: Characteristic read");
|
||||
}
|
||||
};
|
||||
|
||||
// Client callbacks
|
||||
class ClientCallbacks : public BLEClientCallbacks {
|
||||
void onConnect(BLEClient *pClient) {
|
||||
Serial.println("Client: Connected to server");
|
||||
clientConnected = true;
|
||||
}
|
||||
|
||||
void onDisconnect(BLEClient *pClient) {
|
||||
Serial.println("Client: Disconnected from server");
|
||||
clientConnected = false;
|
||||
}
|
||||
};
|
||||
|
||||
// Client notification callback
|
||||
static void notifyCallback(BLERemoteCharacteristic *pBLERemoteCharacteristic, uint8_t *pData, size_t length, bool isNotify) {
|
||||
Serial.print("Client: Notify callback for characteristic ");
|
||||
Serial.print(pBLERemoteCharacteristic->getUUID().toString().c_str());
|
||||
Serial.print(" of data length ");
|
||||
Serial.println(length);
|
||||
Serial.print("Client: Data: ");
|
||||
Serial.write(pData, length);
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
// Scan callbacks
|
||||
class AdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks {
|
||||
void onResult(BLEAdvertisedDevice advertisedDevice) {
|
||||
Serial.print("Client: Found device: ");
|
||||
Serial.println(advertisedDevice.toString().c_str());
|
||||
|
||||
// Check if this device has our target service
|
||||
if (advertisedDevice.haveServiceUUID() && advertisedDevice.isAdvertisingService(clientServiceUUID) && !clientConnected) {
|
||||
|
||||
Serial.println("Client: Found target service, attempting connection...");
|
||||
BLEDevice::getScan()->stop();
|
||||
targetDevice = new BLEAdvertisedDevice(advertisedDevice);
|
||||
doConnect = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
bool connectToServer() {
|
||||
Serial.print("Client: Forming connection to ");
|
||||
Serial.println(targetDevice->getAddress().toString().c_str());
|
||||
|
||||
// Create client if it doesn't exist, otherwise reuse existing one
|
||||
if (pClient == nullptr) {
|
||||
pClient = BLEDevice::createClient();
|
||||
pClient->setClientCallbacks(new ClientCallbacks());
|
||||
Serial.println("Client: Created new client");
|
||||
} else {
|
||||
Serial.println("Client: Reusing existing client");
|
||||
}
|
||||
|
||||
if (!pClient->connect(targetDevice)) {
|
||||
Serial.println("Client: Failed to connect");
|
||||
return false;
|
||||
}
|
||||
|
||||
Serial.println("Client: Connected to server");
|
||||
pClient->setMTU(517); // Request maximum MTU
|
||||
|
||||
// Get the service
|
||||
BLERemoteService *pRemoteService = pClient->getService(clientServiceUUID);
|
||||
if (pRemoteService == nullptr) {
|
||||
Serial.print("Client: Failed to find service UUID: ");
|
||||
Serial.println(clientServiceUUID.toString().c_str());
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
Serial.println("Client: Found service");
|
||||
|
||||
// Get the characteristic
|
||||
pRemoteCharacteristic = pRemoteService->getCharacteristic(clientCharUUID);
|
||||
if (pRemoteCharacteristic == nullptr) {
|
||||
Serial.print("Client: Failed to find characteristic UUID: ");
|
||||
Serial.println(clientCharUUID.toString().c_str());
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
Serial.println("Client: Found characteristic");
|
||||
|
||||
// Read the initial value
|
||||
if (pRemoteCharacteristic->canRead()) {
|
||||
String value = pRemoteCharacteristic->readValue();
|
||||
Serial.print("Client: Initial characteristic value: ");
|
||||
Serial.println(value.c_str());
|
||||
}
|
||||
|
||||
// Register for notifications if available
|
||||
if (pRemoteCharacteristic->canNotify()) {
|
||||
pRemoteCharacteristic->registerForNotify(notifyCallback);
|
||||
Serial.println("Client: Registered for notifications");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void setupServer() {
|
||||
Serial.println("Setting up BLE Server...");
|
||||
|
||||
// Create server
|
||||
pServer = BLEDevice::createServer();
|
||||
pServer->setCallbacks(new ServerCallbacks());
|
||||
|
||||
// Create service
|
||||
BLEService *pService = pServer->createService(SERVER_SERVICE_UUID);
|
||||
|
||||
// Create characteristic
|
||||
pServerCharacteristic = pService->createCharacteristic(
|
||||
SERVER_CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_NOTIFY
|
||||
);
|
||||
|
||||
pServerCharacteristic->setCallbacks(new CharacteristicCallbacks());
|
||||
pServerCharacteristic->setValue("Hello from Coexistence Server");
|
||||
|
||||
// Start service
|
||||
pService->start();
|
||||
|
||||
// Start advertising
|
||||
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
|
||||
pAdvertising->addServiceUUID(SERVER_SERVICE_UUID);
|
||||
pAdvertising->setScanResponse(true);
|
||||
pAdvertising->setMinPreferred(0x06);
|
||||
pAdvertising->setMinPreferred(0x12);
|
||||
|
||||
BLEDevice::startAdvertising();
|
||||
|
||||
Serial.println("Server: Advertising started");
|
||||
}
|
||||
|
||||
void setupClient() {
|
||||
Serial.println("Setting up BLE Client...");
|
||||
|
||||
// Create scanner
|
||||
pBLEScan = BLEDevice::getScan();
|
||||
pBLEScan->setAdvertisedDeviceCallbacks(new AdvertisedDeviceCallbacks());
|
||||
pBLEScan->setActiveScan(true);
|
||||
pBLEScan->setInterval(100);
|
||||
pBLEScan->setWindow(99);
|
||||
|
||||
Serial.println("Client: Scanner configured");
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Serial.println("Starting BLE Client-Server Coexistence Example...");
|
||||
|
||||
// Initialize BLE device with a name
|
||||
BLEDevice::init("ESP32-Coexistence");
|
||||
|
||||
// Setup both server and client
|
||||
setupServer();
|
||||
setupClient();
|
||||
|
||||
// Start initial scan
|
||||
pBLEScan->start(10, false); // Scan for 10 seconds, don't repeat
|
||||
|
||||
Serial.println("Setup complete. Device is advertising as server and scanning as client.");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
static unsigned long lastServerUpdate = 0;
|
||||
static unsigned long lastClientWrite = 0;
|
||||
static unsigned long lastScanStart = 0;
|
||||
unsigned long currentTime = millis();
|
||||
|
||||
// Handle client connection attempts
|
||||
if (doConnect && !clientConnected) {
|
||||
if (connectToServer()) {
|
||||
Serial.println("Client: Successfully connected to remote server");
|
||||
} else {
|
||||
Serial.println("Client: Failed to connect, will retry scanning");
|
||||
// Restart scanning after failed connection
|
||||
pBLEScan->start(10, false);
|
||||
}
|
||||
doConnect = false;
|
||||
}
|
||||
|
||||
// Update server characteristic periodically
|
||||
if (currentTime - lastServerUpdate > 5000) { // Every 5 seconds
|
||||
String value = "Server time: " + String(millis() / 1000);
|
||||
pServerCharacteristic->setValue(value.c_str());
|
||||
pServerCharacteristic->notify(); // Notify connected clients
|
||||
Serial.print("Server: Updated characteristic to: ");
|
||||
Serial.println(value);
|
||||
|
||||
lastServerUpdate = currentTime;
|
||||
}
|
||||
|
||||
// Write to remote characteristic if connected as client
|
||||
if (clientConnected && pRemoteCharacteristic && currentTime - lastClientWrite > 3000) {
|
||||
if (pRemoteCharacteristic->canWrite()) {
|
||||
String clientValue = "Client msg: " + String(millis() / 1000);
|
||||
pRemoteCharacteristic->writeValue(clientValue.c_str(), clientValue.length());
|
||||
Serial.print("Client: Wrote to remote characteristic: ");
|
||||
Serial.println(clientValue);
|
||||
lastClientWrite = currentTime;
|
||||
}
|
||||
}
|
||||
|
||||
// Restart scanning periodically if not connected
|
||||
if (!clientConnected && currentTime - lastScanStart > 15000) { // Every 15 seconds
|
||||
Serial.println("Client: Restarting scan...");
|
||||
pBLEScan->start(10, false);
|
||||
lastScanStart = currentTime;
|
||||
}
|
||||
|
||||
delay(100);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
fqbn_append: PartitionScheme=huge_app
|
||||
|
||||
requires_any:
|
||||
- CONFIG_SOC_BLE_SUPPORTED=y
|
||||
- CONFIG_ESP_HOSTED_ENABLE_BT_NIMBLE=y
|
||||
Reference in New Issue
Block a user