From 0eecee13a75bf13fd1752d3d9b6bc60709a265d2 Mon Sep 17 00:00:00 2001 From: kolban Date: Sun, 10 Sep 2017 13:41:31 -0500 Subject: 0.2.0 --- .../examples/Arduino/BLE_client/BLE_client.ino | 128 -- .../examples/Arduino/BLE_notify/BLE_notify.ino | 93 -- .../examples/Arduino/BLE_scan/BLE_scan.ino | 36 - .../examples/Arduino/BLE_server/BLE_server.ino | 41 - .../examples/Arduino/BLE_uart/BLE_uart.ino | 111 -- .../examples/Arduino/BLE_write/BLE_write.ino | 68 - ESP32_BLE_Arduino/library.properties | 11 - ESP32_BLE_Arduino/src/BLE2902.cpp | 69 - ESP32_BLE_Arduino/src/BLE2902.h | 34 - ESP32_BLE_Arduino/src/BLEAddress.cpp | 93 -- ESP32_BLE_Arduino/src/BLEAddress.h | 34 - ESP32_BLE_Arduino/src/BLEAdvertisedDevice.cpp | 410 ------ ESP32_BLE_Arduino/src/BLEAdvertisedDevice.h | 106 -- ESP32_BLE_Arduino/src/BLEAdvertising.cpp | 155 --- ESP32_BLE_Arduino/src/BLEAdvertising.h | 34 - ESP32_BLE_Arduino/src/BLECharacteristic.cpp | 693 ---------- ESP32_BLE_Arduino/src/BLECharacteristic.h | 132 -- .../src/BLECharacteristicCallbacks.cpp | 34 - ESP32_BLE_Arduino/src/BLECharacteristicMap.cpp | 136 -- ESP32_BLE_Arduino/src/BLEClient.cpp | 327 ----- ESP32_BLE_Arduino/src/BLEClient.h | 76 -- ESP32_BLE_Arduino/src/BLEDescriptor.cpp | 278 ---- ESP32_BLE_Arduino/src/BLEDescriptor.h | 54 - ESP32_BLE_Arduino/src/BLEDescriptorMap.cpp | 149 --- ESP32_BLE_Arduino/src/BLEDevice.cpp | 222 ---- ESP32_BLE_Arduino/src/BLEDevice.h | 54 - ESP32_BLE_Arduino/src/BLERemoteCharacteristic.cpp | 336 ----- ESP32_BLE_Arduino/src/BLERemoteCharacteristic.h | 63 - ESP32_BLE_Arduino/src/BLERemoteDescriptor.cpp | 11 - ESP32_BLE_Arduino/src/BLERemoteDescriptor.h | 20 - ESP32_BLE_Arduino/src/BLERemoteService.cpp | 220 ---- ESP32_BLE_Arduino/src/BLERemoteService.h | 63 - ESP32_BLE_Arduino/src/BLEScan.cpp | 276 ---- ESP32_BLE_Arduino/src/BLEScan.h | 67 - ESP32_BLE_Arduino/src/BLEServer.cpp | 353 ----- ESP32_BLE_Arduino/src/BLEServer.h | 117 -- ESP32_BLE_Arduino/src/BLEServerCallbacks.cpp | 22 - ESP32_BLE_Arduino/src/BLEService.cpp | 353 ----- ESP32_BLE_Arduino/src/BLEService.h | 99 -- ESP32_BLE_Arduino/src/BLEServiceMap.cpp | 95 -- ESP32_BLE_Arduino/src/BLEUUID.cpp | 326 ----- ESP32_BLE_Arduino/src/BLEUUID.h | 37 - ESP32_BLE_Arduino/src/BLEUtils.cpp | 1352 -------------------- ESP32_BLE_Arduino/src/BLEUtils.h | 60 - ESP32_BLE_Arduino/src/BLEValue.cpp | 116 -- ESP32_BLE_Arduino/src/BLEValue.h | 36 - ESP32_BLE_Arduino/src/FreeRTOS.cpp | 165 --- ESP32_BLE_Arduino/src/FreeRTOS.h | 49 - ESP32_BLE_Arduino/src/GeneralUtils.cpp | 388 ------ ESP32_BLE_Arduino/src/GeneralUtils.h | 28 - examples/Arduino/BLE_client/BLE_client.ino | 128 ++ examples/Arduino/BLE_notify/BLE_notify.ino | 93 ++ examples/Arduino/BLE_scan/BLE_scan.ino | 36 + examples/Arduino/BLE_server/BLE_server.ino | 41 + examples/Arduino/BLE_uart/BLE_uart.ino | 111 ++ examples/Arduino/BLE_write/BLE_write.ino | 68 + library.properties | 11 + src/BLE2902.cpp | 69 + src/BLE2902.h | 34 + src/BLEAddress.cpp | 93 ++ src/BLEAddress.h | 34 + src/BLEAdvertisedDevice.cpp | 410 ++++++ src/BLEAdvertisedDevice.h | 106 ++ src/BLEAdvertising.cpp | 155 +++ src/BLEAdvertising.h | 34 + src/BLECharacteristic.cpp | 693 ++++++++++ src/BLECharacteristic.h | 132 ++ src/BLECharacteristicCallbacks.cpp | 34 + src/BLECharacteristicMap.cpp | 136 ++ src/BLEClient.cpp | 327 +++++ src/BLEClient.h | 76 ++ src/BLEDescriptor.cpp | 278 ++++ src/BLEDescriptor.h | 54 + src/BLEDescriptorMap.cpp | 149 +++ src/BLEDevice.cpp | 222 ++++ src/BLEDevice.h | 54 + src/BLERemoteCharacteristic.cpp | 336 +++++ src/BLERemoteCharacteristic.h | 63 + src/BLERemoteDescriptor.cpp | 11 + src/BLERemoteDescriptor.h | 20 + src/BLERemoteService.cpp | 220 ++++ src/BLERemoteService.h | 63 + src/BLEScan.cpp | 276 ++++ src/BLEScan.h | 67 + src/BLEServer.cpp | 353 +++++ src/BLEServer.h | 117 ++ src/BLEServerCallbacks.cpp | 22 + src/BLEService.cpp | 353 +++++ src/BLEService.h | 99 ++ src/BLEServiceMap.cpp | 95 ++ src/BLEUUID.cpp | 326 +++++ src/BLEUUID.h | 37 + src/BLEUtils.cpp | 1352 ++++++++++++++++++++ src/BLEUtils.h | 60 + src/BLEValue.cpp | 116 ++ src/BLEValue.h | 36 + src/FreeRTOS.cpp | 165 +++ src/FreeRTOS.h | 49 + src/GeneralUtils.cpp | 388 ++++++ src/GeneralUtils.h | 28 + 100 files changed, 8230 insertions(+), 8230 deletions(-) delete mode 100644 ESP32_BLE_Arduino/examples/Arduino/BLE_client/BLE_client.ino delete mode 100644 ESP32_BLE_Arduino/examples/Arduino/BLE_notify/BLE_notify.ino delete mode 100644 ESP32_BLE_Arduino/examples/Arduino/BLE_scan/BLE_scan.ino delete mode 100644 ESP32_BLE_Arduino/examples/Arduino/BLE_server/BLE_server.ino delete mode 100644 ESP32_BLE_Arduino/examples/Arduino/BLE_uart/BLE_uart.ino delete mode 100644 ESP32_BLE_Arduino/examples/Arduino/BLE_write/BLE_write.ino delete mode 100644 ESP32_BLE_Arduino/library.properties delete mode 100644 ESP32_BLE_Arduino/src/BLE2902.cpp delete mode 100644 ESP32_BLE_Arduino/src/BLE2902.h delete mode 100644 ESP32_BLE_Arduino/src/BLEAddress.cpp delete mode 100644 ESP32_BLE_Arduino/src/BLEAddress.h delete mode 100644 ESP32_BLE_Arduino/src/BLEAdvertisedDevice.cpp delete mode 100644 ESP32_BLE_Arduino/src/BLEAdvertisedDevice.h delete mode 100644 ESP32_BLE_Arduino/src/BLEAdvertising.cpp delete mode 100644 ESP32_BLE_Arduino/src/BLEAdvertising.h delete mode 100644 ESP32_BLE_Arduino/src/BLECharacteristic.cpp delete mode 100644 ESP32_BLE_Arduino/src/BLECharacteristic.h delete mode 100644 ESP32_BLE_Arduino/src/BLECharacteristicCallbacks.cpp delete mode 100644 ESP32_BLE_Arduino/src/BLECharacteristicMap.cpp delete mode 100644 ESP32_BLE_Arduino/src/BLEClient.cpp delete mode 100644 ESP32_BLE_Arduino/src/BLEClient.h delete mode 100644 ESP32_BLE_Arduino/src/BLEDescriptor.cpp delete mode 100644 ESP32_BLE_Arduino/src/BLEDescriptor.h delete mode 100644 ESP32_BLE_Arduino/src/BLEDescriptorMap.cpp delete mode 100644 ESP32_BLE_Arduino/src/BLEDevice.cpp delete mode 100644 ESP32_BLE_Arduino/src/BLEDevice.h delete mode 100644 ESP32_BLE_Arduino/src/BLERemoteCharacteristic.cpp delete mode 100644 ESP32_BLE_Arduino/src/BLERemoteCharacteristic.h delete mode 100644 ESP32_BLE_Arduino/src/BLERemoteDescriptor.cpp delete mode 100644 ESP32_BLE_Arduino/src/BLERemoteDescriptor.h delete mode 100644 ESP32_BLE_Arduino/src/BLERemoteService.cpp delete mode 100644 ESP32_BLE_Arduino/src/BLERemoteService.h delete mode 100644 ESP32_BLE_Arduino/src/BLEScan.cpp delete mode 100644 ESP32_BLE_Arduino/src/BLEScan.h delete mode 100644 ESP32_BLE_Arduino/src/BLEServer.cpp delete mode 100644 ESP32_BLE_Arduino/src/BLEServer.h delete mode 100644 ESP32_BLE_Arduino/src/BLEServerCallbacks.cpp delete mode 100644 ESP32_BLE_Arduino/src/BLEService.cpp delete mode 100644 ESP32_BLE_Arduino/src/BLEService.h delete mode 100644 ESP32_BLE_Arduino/src/BLEServiceMap.cpp delete mode 100644 ESP32_BLE_Arduino/src/BLEUUID.cpp delete mode 100644 ESP32_BLE_Arduino/src/BLEUUID.h delete mode 100644 ESP32_BLE_Arduino/src/BLEUtils.cpp delete mode 100644 ESP32_BLE_Arduino/src/BLEUtils.h delete mode 100644 ESP32_BLE_Arduino/src/BLEValue.cpp delete mode 100644 ESP32_BLE_Arduino/src/BLEValue.h delete mode 100644 ESP32_BLE_Arduino/src/FreeRTOS.cpp delete mode 100644 ESP32_BLE_Arduino/src/FreeRTOS.h delete mode 100644 ESP32_BLE_Arduino/src/GeneralUtils.cpp delete mode 100644 ESP32_BLE_Arduino/src/GeneralUtils.h create mode 100644 examples/Arduino/BLE_client/BLE_client.ino create mode 100644 examples/Arduino/BLE_notify/BLE_notify.ino create mode 100644 examples/Arduino/BLE_scan/BLE_scan.ino create mode 100644 examples/Arduino/BLE_server/BLE_server.ino create mode 100644 examples/Arduino/BLE_uart/BLE_uart.ino create mode 100644 examples/Arduino/BLE_write/BLE_write.ino create mode 100644 library.properties create mode 100644 src/BLE2902.cpp create mode 100644 src/BLE2902.h create mode 100644 src/BLEAddress.cpp create mode 100644 src/BLEAddress.h create mode 100644 src/BLEAdvertisedDevice.cpp create mode 100644 src/BLEAdvertisedDevice.h create mode 100644 src/BLEAdvertising.cpp create mode 100644 src/BLEAdvertising.h create mode 100644 src/BLECharacteristic.cpp create mode 100644 src/BLECharacteristic.h create mode 100644 src/BLECharacteristicCallbacks.cpp create mode 100644 src/BLECharacteristicMap.cpp create mode 100644 src/BLEClient.cpp create mode 100644 src/BLEClient.h create mode 100644 src/BLEDescriptor.cpp create mode 100644 src/BLEDescriptor.h create mode 100644 src/BLEDescriptorMap.cpp create mode 100644 src/BLEDevice.cpp create mode 100644 src/BLEDevice.h create mode 100644 src/BLERemoteCharacteristic.cpp create mode 100644 src/BLERemoteCharacteristic.h create mode 100644 src/BLERemoteDescriptor.cpp create mode 100644 src/BLERemoteDescriptor.h create mode 100644 src/BLERemoteService.cpp create mode 100644 src/BLERemoteService.h create mode 100644 src/BLEScan.cpp create mode 100644 src/BLEScan.h create mode 100644 src/BLEServer.cpp create mode 100644 src/BLEServer.h create mode 100644 src/BLEServerCallbacks.cpp create mode 100644 src/BLEService.cpp create mode 100644 src/BLEService.h create mode 100644 src/BLEServiceMap.cpp create mode 100644 src/BLEUUID.cpp create mode 100644 src/BLEUUID.h create mode 100644 src/BLEUtils.cpp create mode 100644 src/BLEUtils.h create mode 100644 src/BLEValue.cpp create mode 100644 src/BLEValue.h create mode 100644 src/FreeRTOS.cpp create mode 100644 src/FreeRTOS.h create mode 100644 src/GeneralUtils.cpp create mode 100644 src/GeneralUtils.h diff --git a/ESP32_BLE_Arduino/examples/Arduino/BLE_client/BLE_client.ino b/ESP32_BLE_Arduino/examples/Arduino/BLE_client/BLE_client.ino deleted file mode 100644 index 3fc5efa..0000000 --- a/ESP32_BLE_Arduino/examples/Arduino/BLE_client/BLE_client.ino +++ /dev/null @@ -1,128 +0,0 @@ -/** - * A BLE client example that is rich in capabilities. - */ - -#include "BLEDevice.h" -//#include "BLEScan.h" - -// The remote service we wish to connect to. -static BLEUUID serviceUUID("91bad492-b950-4226-aa2b-4ede9fa42f59"); -// The characteristic of the remote service we are interested in. -static BLEUUID charUUID("0d563a58-196a-48ce-ace2-dfec78acc814"); - -static BLEAddress *pServerAddress; -static boolean doConnect = false; -static boolean connected = false; -static BLERemoteCharacteristic* pRemoteCharacteristic; - -static void notifyCallback( - BLERemoteCharacteristic* pBLERemoteCharacteristic, - uint8_t* pData, - size_t length, - bool isNotify) { - Serial.print("Notify callback for characteristic "); - Serial.print(pBLERemoteCharacteristic->getUUID().toString().c_str()); - Serial.print(" of data length "); - Serial.println(length); -} - -void connectToServer(BLEAddress pAddress) { - Serial.print("Forming a connection to "); - Serial.println(pAddress.toString().c_str()); - - BLEClient* pClient = BLEDevice::createClient(); - Serial.println(" - Created client"); - - // Connect to the remove BLE Server. - pClient->connect(pAddress); - Serial.println(" - Connected to server"); - - // Obtain a reference to the service we are after in the remote BLE server. - BLERemoteService* pRemoteService = pClient->getService(serviceUUID); - if (pRemoteService == nullptr) { - Serial.print("Failed to find our service UUID: "); - Serial.println(serviceUUID.toString().c_str()); - return; - } - - - // Obtain a reference to the characteristic in the service of the remote BLE server. - pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID); - if (pRemoteCharacteristic == nullptr) { - Serial.print("Failed to find our characteristic UUID: "); - Serial.println(charUUID.toString().c_str()); - return; - } - - // Read the value of the characteristic. - std::string value = pRemoteCharacteristic->readValue(); - Serial.print("The characteristic value was: "); - Serial.println(value.c_str()); - - pRemoteCharacteristic->registerForNotify(notifyCallback); -} -/** - * Scan for BLE servers and find the first one that advertises the service we are looking for. - */ -class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks { - /** - * Called for each advertising BLE server. - */ - void onResult(BLEAdvertisedDevice advertisedDevice) { - Serial.print("BLE Advertised Device found: "); - Serial.println(advertisedDevice.toString().c_str()); - - // We have found a device, let us now see if it contains the service we are looking for. - if (advertisedDevice.haveServiceUUID() && advertisedDevice.getServiceUUID().equals(serviceUUID)) { - - // - Serial.print("Found our device! address: "); - advertisedDevice.getScan()->stop(); - - pServerAddress = new BLEAddress(advertisedDevice.getAddress()); - doConnect = true; - - } // Found our server - } // onResult -}; // MyAdvertisedDeviceCallbacks - - -void setup() { - Serial.begin(115200); - Serial.println("Starting Arduino BLE Client application..."); - BLEDevice::init(""); - - // Retrieve a Scanner and set the callback we want to use to be informed when we - // have detected a new device. Specify that we want active scanning and start the - // scan to run for 30 seconds. - BLEScan* pBLEScan = BLEDevice::getScan(); - pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks()); - pBLEScan->setActiveScan(true); - pBLEScan->start(30); -} // End of setup. - - -// This is the Arduino main loop function. -void loop() { - - // If the flag "doConnect" is true then we have scanned for and found the desired - // BLE Server with which we wish to connect. Now we connect to it. Once we are - // connected we set the connected flag to be true. - if (doConnect == true) { - connectToServer(*pServerAddress); - doConnect = false; - connected = true; - } - - // If we are connected to a peer BLE Server, update the characteristic each time we are reached - // with the current time since boot. - if (connected) { - String newValue = "Time since boot: " + String(millis()/1000); - Serial.println("Setting new characteristic value to \"" + newValue + "\""); - - // Set the characteristic's value to be the array of bytes that is actually a string. - pRemoteCharacteristic->writeValue(newValue.c_str(), newValue.length()); - } - - delay(1000); // Delay a second between loops. -} // End of loop diff --git a/ESP32_BLE_Arduino/examples/Arduino/BLE_notify/BLE_notify.ino b/ESP32_BLE_Arduino/examples/Arduino/BLE_notify/BLE_notify.ino deleted file mode 100644 index 44506c2..0000000 --- a/ESP32_BLE_Arduino/examples/Arduino/BLE_notify/BLE_notify.ino +++ /dev/null @@ -1,93 +0,0 @@ -/* - Video: https://www.youtube.com/watch?v=oCMOYS71NIU - Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp - Ported to Arduino ESP32 by Evandro Copercini - - Create a BLE server that, once we receive a connection, will send periodic notifications. - The service advertises itself as: 4fafc201-1fb5-459e-8fcc-c5c9c331914b - And has a characteristic of: beb5483e-36e1-4688-b7f5-ea07361b26a8 - - The design of creating the BLE server is: - 1. Create a BLE Server - 2. Create a BLE Service - 3. Create a BLE Characteristic on the Service - 4. Create a BLE Descriptor on the characteristic - 5. Start the service. - 6. Start advertising. - - A connect hander associated with the server starts a background task that performs notification - every couple of seconds. -*/ -#include -#include -#include -#include - -BLECharacteristic *pCharacteristic; -bool deviceConnected = false; -uint8_t value = 0; - -// See the following for generating UUIDs: -// https://www.uuidgenerator.net/ - -#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" -#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" - - -class MyServerCallbacks: public BLEServerCallbacks { - void onConnect(BLEServer* pServer) { - deviceConnected = true; - }; - - void onDisconnect(BLEServer* pServer) { - deviceConnected = false; - } -}; - - - -void setup() { - Serial.begin(115200); - - // Create the BLE Device - BLEDevice::init("MyESP32"); - - // Create the BLE Server - BLEServer *pServer = new BLEServer(); - pServer->setCallbacks(new MyServerCallbacks()); - - // Create the BLE Service - BLEService *pService = pServer->createService(SERVICE_UUID); - - // Create a BLE Characteristic - pCharacteristic = pService->createCharacteristic( - CHARACTERISTIC_UUID, - BLECharacteristic::PROPERTY_READ | - BLECharacteristic::PROPERTY_WRITE | - BLECharacteristic::PROPERTY_NOTIFY | - BLECharacteristic::PROPERTY_INDICATE - ); - - // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml - // Create a BLE Descriptor - pCharacteristic->addDescriptor(new BLE2902()); - - // Start the service - pService->start(); - - // Start advertising - pServer->getAdvertising()->start(); - Serial.println("Waiting a client connection to notify..."); -} - -void loop() { - - if (deviceConnected) { - Serial.printf("*** NOTIFY: %d ***\n", value); - pCharacteristic->setValue(&value, 1); - pCharacteristic->notify(); - //pCharacteristic->indicate(); - value++; - } - delay(2000); -} \ No newline at end of file diff --git a/ESP32_BLE_Arduino/examples/Arduino/BLE_scan/BLE_scan.ino b/ESP32_BLE_Arduino/examples/Arduino/BLE_scan/BLE_scan.ino deleted file mode 100644 index ef7d892..0000000 --- a/ESP32_BLE_Arduino/examples/Arduino/BLE_scan/BLE_scan.ino +++ /dev/null @@ -1,36 +0,0 @@ -/* - Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleScan.cpp - Ported to Arduino ESP32 by Evandro Copercini -*/ - -#include -#include -#include -#include - -int scanTime = 30; //In seconds - -class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks { - void onResult(BLEAdvertisedDevice advertisedDevice) { - Serial.printf("Advertised Device: %s \n", advertisedDevice.toString().c_str()); - } -}; - -void setup() { - Serial.begin(115200); - Serial.println("Scanning..."); - - BLEDevice::init(""); - BLEScan* pBLEScan = BLEDevice::getScan(); //create new scan - pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks()); - pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster - BLEScanResults foundDevices = pBLEScan->start(scanTime); - Serial.print("Devices found: "); - Serial.println(foundDevices.getCount()); - Serial.println("Scan done!"); -} - -void loop() { - // put your main code here, to run repeatedly: - delay(2000); -} \ No newline at end of file diff --git a/ESP32_BLE_Arduino/examples/Arduino/BLE_server/BLE_server.ino b/ESP32_BLE_Arduino/examples/Arduino/BLE_server/BLE_server.ino deleted file mode 100644 index 45ebf99..0000000 --- a/ESP32_BLE_Arduino/examples/Arduino/BLE_server/BLE_server.ino +++ /dev/null @@ -1,41 +0,0 @@ -/* - Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleServer.cpp - Ported to Arduino ESP32 by Evandro Copercini -*/ - -#include -#include -#include - -BLEDevice ble; - -// See the following for generating UUIDs: -// https://www.uuidgenerator.net/ - -#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" -#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" - -void setup() { - Serial.begin(115200); - Serial.println("Starting BLE work!"); - - ble.init("MyESP32"); - BLEServer *pServer = new BLEServer(); - BLEService *pService = pServer->createService(SERVICE_UUID); - BLECharacteristic *pCharacteristic = pService->createCharacteristic( - CHARACTERISTIC_UUID, - BLECharacteristic::PROPERTY_READ | - BLECharacteristic::PROPERTY_WRITE - ); - - pCharacteristic->setValue("Hello World says Neil"); - pService->start(); - BLEAdvertising *pAdvertising = pServer->getAdvertising(); - pAdvertising->start(); - Serial.println("Characteristic defined! Now you can read it in your phone!"); -} - -void loop() { - // put your main code here, to run repeatedly: - delay(2000); -} \ No newline at end of file diff --git a/ESP32_BLE_Arduino/examples/Arduino/BLE_uart/BLE_uart.ino b/ESP32_BLE_Arduino/examples/Arduino/BLE_uart/BLE_uart.ino deleted file mode 100644 index a8ab2d7..0000000 --- a/ESP32_BLE_Arduino/examples/Arduino/BLE_uart/BLE_uart.ino +++ /dev/null @@ -1,111 +0,0 @@ -/* - Video: https://www.youtube.com/watch?v=oCMOYS71NIU - Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp - Ported to Arduino ESP32 by Evandro Copercini - - Create a BLE server that, once we receive a connection, will send periodic notifications. - The service advertises itself as: 6E400001-B5A3-F393-E0A9-E50E24DCCA9E - Has a characteristic of: 6E400002-B5A3-F393-E0A9-E50E24DCCA9E - used for receiving data with "WRITE" - Has a characteristic of: 6E400003-B5A3-F393-E0A9-E50E24DCCA9E - used to send data with "NOTIFY" - - The design of creating the BLE server is: - 1. Create a BLE Server - 2. Create a BLE Service - 3. Create a BLE Characteristic on the Service - 4. Create a BLE Descriptor on the characteristic - 5. Start the service. - 6. Start advertising. - - In this example rxValue is the data received (only accessible inside that function). - And txValue is the data to be sent, in this example just a byte incremented every second. -*/ -#include -#include -#include -#include - -BLECharacteristic *pCharacteristic; -bool deviceConnected = false; -uint8_t txValue = 0; - -// See the following for generating UUIDs: -// https://www.uuidgenerator.net/ - -#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID -#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E" -#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E" - - -class MyServerCallbacks: public BLEServerCallbacks { - void onConnect(BLEServer* pServer) { - deviceConnected = true; - }; - - void onDisconnect(BLEServer* pServer) { - deviceConnected = false; - } -}; - -class MyCallbacks: public BLECharacteristicCallbacks { - void onWrite(BLECharacteristic *pCharacteristic) { - std::string rxValue = pCharacteristic->getValue(); - - if (rxValue.length() > 0) { - Serial.println("*********"); - Serial.print("Received Value: "); - for (int i = 0; i < rxValue.length(); i++) - Serial.print(rxValue[i]); - - Serial.println(); - Serial.println("*********"); - } - } -}; - - -void setup() { - Serial.begin(115200); - - // Create the BLE Device - BLEDevice::init("UART Service"); - - // Create the BLE Server - BLEServer *pServer = new BLEServer(); - pServer->setCallbacks(new MyServerCallbacks()); - - // Create the BLE Service - BLEService *pService = pServer->createService(SERVICE_UUID); - - // Create a BLE Characteristic - pCharacteristic = pService->createCharacteristic( - CHARACTERISTIC_UUID_TX, - BLECharacteristic::PROPERTY_NOTIFY - ); - - pCharacteristic->addDescriptor(new BLE2902()); - - BLECharacteristic *pCharacteristic = pService->createCharacteristic( - CHARACTERISTIC_UUID_RX, - BLECharacteristic::PROPERTY_WRITE - ); - - pCharacteristic->setCallbacks(new MyCallbacks()); - - // Start the service - pService->start(); - - // Start advertising - pServer->getAdvertising()->start(); - Serial.println("Waiting a client connection to notify..."); -} - -void loop() { - - if (deviceConnected) { - Serial.printf("*** Sent Value: %d ***\n", txValue); - pCharacteristic->setValue(&txValue, 1); - pCharacteristic->notify(); - txValue++; - } - delay(1000); -} diff --git a/ESP32_BLE_Arduino/examples/Arduino/BLE_write/BLE_write.ino b/ESP32_BLE_Arduino/examples/Arduino/BLE_write/BLE_write.ino deleted file mode 100644 index ed5ebc6..0000000 --- a/ESP32_BLE_Arduino/examples/Arduino/BLE_write/BLE_write.ino +++ /dev/null @@ -1,68 +0,0 @@ -/* - Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleWrite.cpp - Ported to Arduino ESP32 by Evandro Copercini -*/ - -#include -#include -#include - -BLEDevice ble; - -// See the following for generating UUIDs: -// https://www.uuidgenerator.net/ - -#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" -#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" - - -class MyCallbacks: public BLECharacteristicCallbacks { - void onWrite(BLECharacteristic *pCharacteristic) { - std::string value = pCharacteristic->getValue(); - - if (value.length() > 0) { - Serial.println("*********"); - Serial.print("New value: "); - for (int i = 0; i < value.length(); i++) - Serial.print(value[i]); - - Serial.println(); - Serial.println("*********"); - } - } -}; - -void setup() { - Serial.begin(115200); - - Serial.println("1- Download and install an BLE scanner app in your phone"); - Serial.println("2- Scan for BLE devices in the app"); - Serial.println("3- Connect to MyESP32"); - Serial.println("4- Go to CUSTOM CHARACTERISTIC in CUSTOM SERVICE and write something"); - Serial.println("5- See the magic =)"); - - //ble.begin("MyESP32"); - ble.init("MyESP32"); - BLEServer *pServer = new BLEServer(); - - BLEService *pService = pServer->createService(SERVICE_UUID); - - BLECharacteristic *pCharacteristic = pService->createCharacteristic( - CHARACTERISTIC_UUID, - BLECharacteristic::PROPERTY_READ | - BLECharacteristic::PROPERTY_WRITE - ); - - pCharacteristic->setCallbacks(new MyCallbacks()); - - pCharacteristic->setValue("Hello World"); - pService->start(); - - BLEAdvertising *pAdvertising = pServer->getAdvertising(); - pAdvertising->start(); -} - -void loop() { - // put your main code here, to run repeatedly: - delay(2000); -} \ No newline at end of file diff --git a/ESP32_BLE_Arduino/library.properties b/ESP32_BLE_Arduino/library.properties deleted file mode 100644 index 09a02ba..0000000 --- a/ESP32_BLE_Arduino/library.properties +++ /dev/null @@ -1,11 +0,0 @@ -name=ESP32 BLE Arduino -version=0.1.0 -author=Neil Kolban -maintainer=Neil Kolban -sentence=BLE functions for ESP32 -paragraph=BLE functions for ESP32 -category=Communication -url=https://github.com/nkolban/ESP32_BLE_Arduino -architectures=esp32 -includes=BLE.h BLEUtils.h BLEScan.h BLEAdvertisedDevice.h -dot_a_linkage=true \ No newline at end of file diff --git a/ESP32_BLE_Arduino/src/BLE2902.cpp b/ESP32_BLE_Arduino/src/BLE2902.cpp deleted file mode 100644 index 8984da8..0000000 --- a/ESP32_BLE_Arduino/src/BLE2902.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - * BLE2902.cpp - * - * Created on: Jun 25, 2017 - * Author: kolban - */ - -/* - * See also: - * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml - */ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) - -#include "BLE2902.h" - -BLE2902::BLE2902() : BLEDescriptor(BLEUUID((uint16_t) 0x2902)) { - uint8_t data[2] = {0,0}; - setValue(data, 2); -} // BLE2902 - - -/** - * @brief Get the notifications value. - * @return The notifications value. True if notifications are enabled and false if not. - */ -bool BLE2902::getNotifications() { - return (getValue()[0] & (1 << 0)) != 0; -} // getNotifications - - -/** - * @brief Get the indications value. - * @return The indications value. True if indications are enabled and false if not. - */ -bool BLE2902::getIndications() { - return (getValue()[0] & (1 << 1)) != 0; -} // getIndications - - -/** - * @brief Set the indications flag. - * @param [in] flag The indications flag. - */ -void BLE2902::setIndications(bool flag) { - uint8_t *pValue = getValue(); - if (flag) { - pValue[0] |= 1<<1; - } else { - pValue[0] &= ~(1<<1); - } -} // setIndications - - -/** - * @brief Set the notifications flag. - * @param [in] flag The notifications flag. - */ -void BLE2902::setNotifications(bool flag) { - uint8_t *pValue = getValue(); - if (flag) { - pValue[0] |= 1<<0; - } else { - pValue[0] &= ~(1<<0); - } -} // setNotifications - - -#endif diff --git a/ESP32_BLE_Arduino/src/BLE2902.h b/ESP32_BLE_Arduino/src/BLE2902.h deleted file mode 100644 index 397360a..0000000 --- a/ESP32_BLE_Arduino/src/BLE2902.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * BLE2902.h - * - * Created on: Jun 25, 2017 - * Author: kolban - */ - -#ifndef COMPONENTS_CPP_UTILS_BLE2902_H_ -#define COMPONENTS_CPP_UTILS_BLE2902_H_ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) - -#include "BLEDescriptor.h" - -/** - * @brief Descriptor for Client Characteristic Configuration. - * - * This is a convenience descriptor for the Client Characteristic Configuration which has a UUID of 0x2902. - * - * See also: - * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml - */ -class BLE2902: public BLEDescriptor { -public: - BLE2902(); - bool getNotifications(); - bool getIndications(); - void setNotifications(bool flag); - void setIndications(bool flag); - -}; // BLE2902 - -#endif /* CONFIG_BT_ENABLED */ -#endif /* COMPONENTS_CPP_UTILS_BLE2902_H_ */ diff --git a/ESP32_BLE_Arduino/src/BLEAddress.cpp b/ESP32_BLE_Arduino/src/BLEAddress.cpp deleted file mode 100644 index d2f7f8b..0000000 --- a/ESP32_BLE_Arduino/src/BLEAddress.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* - * BLEAddress.cpp - * - * Created on: Jul 2, 2017 - * Author: kolban - */ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) - -#include "BLEAddress.h" -#include -#include -#include -#include -#include - - -/** - * @brief Create an address from the native ESP32 representation. - * @param [in] address The native representation. - */ -BLEAddress::BLEAddress(esp_bd_addr_t address) { - memcpy(m_address, address, ESP_BD_ADDR_LEN); -} // BLEAddress - - -/** - * @brief Create an address from a hex string - * - * A hex string is of the format: - * ``` - * 00:00:00:00:00:00 - * ``` - * which is 17 characters in length. - * - * @param [in] stringAddress The hex representation of the address. - */ -BLEAddress::BLEAddress(std::string stringAddress) { - if (stringAddress.length() != 17) { - return; - } - int data[6]; - sscanf(stringAddress.c_str(), "%x:%x:%x:%x:%x:%x", &data[0], &data[1], &data[2], &data[3], &data[4], &data[5]); - m_address[0] = (uint8_t)data[0]; - m_address[1] = (uint8_t)data[1]; - m_address[2] = (uint8_t)data[2]; - m_address[3] = (uint8_t)data[3]; - m_address[4] = (uint8_t)data[4]; - m_address[5] = (uint8_t)data[5]; -} // BLEAddress - - -/** - * @brief Determine if this address equals another. - * @param [in] otherAddress The other address to compare against. - * @return True if the addresses are equal. - */ -bool BLEAddress::equals(BLEAddress otherAddress) { - return memcmp(otherAddress.getNative(), m_address, 6) == 0; -} // equals - - -/** - * @brief Return the native representation of the address. - * @return The native representation of the address. - */ -esp_bd_addr_t *BLEAddress::getNative() { - return &m_address; -} // getNative - - -/** - * @brief Convert a BLE address to a string. - * - * A string representation of an address is in the format: - * - * ``` - * xx:xx:xx:xx:xx:xx - * ``` - * - * @return The string representation of the address. - */ -std::string BLEAddress::toString() { - std::stringstream stream; - stream << std::setfill('0') << std::setw(2) << std::hex << (int)((uint8_t *)(m_address))[0] << ':'; - stream << std::setfill('0') << std::setw(2) << std::hex << (int)((uint8_t *)(m_address))[1] << ':'; - stream << std::setfill('0') << std::setw(2) << std::hex << (int)((uint8_t *)(m_address))[2] << ':'; - stream << std::setfill('0') << std::setw(2) << std::hex << (int)((uint8_t *)(m_address))[3] << ':'; - stream << std::setfill('0') << std::setw(2) << std::hex << (int)((uint8_t *)(m_address))[4] << ':'; - stream << std::setfill('0') << std::setw(2) << std::hex << (int)((uint8_t *)(m_address))[5]; - return stream.str(); -} // toString -#endif diff --git a/ESP32_BLE_Arduino/src/BLEAddress.h b/ESP32_BLE_Arduino/src/BLEAddress.h deleted file mode 100644 index 7eff4da..0000000 --- a/ESP32_BLE_Arduino/src/BLEAddress.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * BLEAddress.h - * - * Created on: Jul 2, 2017 - * Author: kolban - */ - -#ifndef COMPONENTS_CPP_UTILS_BLEADDRESS_H_ -#define COMPONENTS_CPP_UTILS_BLEADDRESS_H_ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) -#include // ESP32 BLE -#include - - -/** - * @brief A %BLE device address. - * - * Every %BLE device has a unique address which can be used to identify it and form connections. - */ -class BLEAddress { -public: - BLEAddress(esp_bd_addr_t address); - BLEAddress(std::string stringAddress); - bool equals(BLEAddress otherAddress); - esp_bd_addr_t* getNative(); - std::string toString(); - -private: - esp_bd_addr_t m_address; -}; - -#endif /* CONFIG_BT_ENABLED */ -#endif /* COMPONENTS_CPP_UTILS_BLEADDRESS_H_ */ diff --git a/ESP32_BLE_Arduino/src/BLEAdvertisedDevice.cpp b/ESP32_BLE_Arduino/src/BLEAdvertisedDevice.cpp deleted file mode 100644 index 97ec1e3..0000000 --- a/ESP32_BLE_Arduino/src/BLEAdvertisedDevice.cpp +++ /dev/null @@ -1,410 +0,0 @@ -/* - * BLEAdvertisedDevice.cpp - * - * During the scanning procedure, we will be finding advertised BLE devices. This class - * models a found device. - * - * - * See also: - * https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile - * - * Created on: Jul 3, 2017 - * Author: kolban - */ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) -#include -#include -#include "BLEAdvertisedDevice.h" -#include "BLEUtils.h" -static const char* LOG_TAG="BLEAdvertisedDevice"; - -BLEAdvertisedDevice::BLEAdvertisedDevice() { - m_adFlag = 0; - m_appearance = 0; - m_deviceType = 0; - m_manufacturerData = ""; - m_name = ""; - m_rssi = -9999; - m_txPower = 0; - m_pScan = nullptr; - - m_haveAppearance = false; - m_haveManufacturerData = false; - m_haveName = false; - m_haveRSSI = false; - m_haveServiceUUID = false; - m_haveTXPower = false; - -} // BLEAdvertisedDevice - - -/** - * @brief Get the address. - * - * Every %BLE device exposes an address that is used to identify it and subsequently connect to it. - * Call this function to obtain the address of the advertised device. - * - * @return The address of the advertised device. - */ -BLEAddress BLEAdvertisedDevice::getAddress() { - return m_address; -} // getAddress - - -/** - * @brief Get the appearance. - * - * A %BLE device can declare its own appearance. The appearance is how it would like to be shown to an end user - * typcially in the form of an icon. - * - * @return The appearance of the advertised device. - */ -uint16_t BLEAdvertisedDevice::getApperance() { - return m_appearance; -} - - -/** - * @brief Get the manufacturer data. - * @return The manufacturer data of the advertised device. - */ -std::string BLEAdvertisedDevice::getManufacturerData() { - return m_manufacturerData; -} - - -/** - * @brief Get the name. - * @return The name of the advertised device. - */ -std::string BLEAdvertisedDevice::getName() { - return m_name; -} // getName - - -/** - * @brief Get the RSSI. - * @return The RSSI of the advertised device. - */ -int BLEAdvertisedDevice::getRSSI() { - return m_rssi; -} // getRSSI - - -/** - * @brief Get the scan object that created this advertisement. - * @return The scan object. - */ -BLEScan* BLEAdvertisedDevice::getScan() { - return m_pScan; -} // getScan - - -/** - * @brief Get the Service UUID. - * @return The Service UUID of the advertised device. - */ -BLEUUID BLEAdvertisedDevice::getServiceUUID() { - return m_serviceUUID; -} // getServiceUUID - - -/** - * @brief Get the TX Power. - * @return The TX Power of the advertised device. - */ -int8_t BLEAdvertisedDevice::getTXPower() { - return m_txPower; -} // getTXPower - -/** - * @brief Does this advertisement have an appearance value? - * @return True if there is an appearance value present. - */ -bool BLEAdvertisedDevice::haveAppearance() { - return m_haveAppearance; -} // haveAppearance - - -/** - * @brief Does this advertisement have manufacturer data? - * @return True if there is manufacturer data present. - */ -bool BLEAdvertisedDevice::haveManufacturerData() { - return m_haveManufacturerData; -} // haveManufacturerData - - -/** - * @brief Does this advertisement have a name value? - * @return True if there is a name value present. - */ -bool BLEAdvertisedDevice::haveName() { - return m_haveName; -} // haveName - - -/** - * @brief Does this advertisement have a signal strength value? - * @return True if there is a signal strength value present. - */ -bool BLEAdvertisedDevice::haveRSSI() { - return m_haveRSSI; -} // haveRSSI - - -/** - * @brief Does this advertisement have a service UUID value? - * @return True if there is a service UUID value present. - */ -bool BLEAdvertisedDevice::haveServiceUUID() { - return m_haveServiceUUID; -} // haveServiceUUID - - -/** - * @brief Does this advertisement have a transmission power value? - * @return True if there is a transmission power value present. - */ -bool BLEAdvertisedDevice::haveTXPower() { - return m_haveTXPower; -} // haveTXPower - - -/** - * @brief Parse the advertising pay load. - * - * The pay load is a buffer of bytes that is either 31 bytes long or terminated by - * a 0 length value. Each entry in the buffer has the format: - * [length][type][data...] - * - * The length does not include itself but does include everything after it until the next record. A record - * with a length value of 0 indicates a terminator. - * - * https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile - */ -void BLEAdvertisedDevice::parseAdvertisement(uint8_t* payload) { - uint8_t length; - uint8_t ad_type; - uint8_t sizeConsumed = 0; - bool finished = false; - - while(!finished) { - length = *payload; // Retrieve the length of the record. - payload++; // Skip to type - sizeConsumed += 1 + length; // increase the size consumed. - - if (length != 0) { // A length of 0 indicate that we have reached the end. - ad_type = *payload; - payload++; - length--; - - char* pHex = BLEUtils::buildHexData(nullptr, payload, length); - ESP_LOGD(LOG_TAG, "Type: 0x%.2x (%s), length: %d, data: %s", - ad_type, BLEUtils::advTypeToString(ad_type), length, pHex); - free(pHex); - - - - switch(ad_type) { - case ESP_BLE_AD_TYPE_NAME_CMPL: { // Adv Data Type: 0x09 - setName(std::string(reinterpret_cast(payload), length)); - break; - } // ESP_BLE_AD_TYPE_NAME_CMPL - - case ESP_BLE_AD_TYPE_TX_PWR: { // Adv Data Type: 0x0A - setTXPower(*payload); - break; - } // ESP_BLE_AD_TYPE_TX_PWR - - case ESP_BLE_AD_TYPE_APPEARANCE: { // Adv Data Type: 0x19 - setAppearance(*reinterpret_cast(payload)); - break; - } // ESP_BLE_AD_TYPE_APPEARANCE - - case ESP_BLE_AD_TYPE_FLAG: { // Adv Data Type: 0x01 - setAdFlag(*payload); - break; - } // ESP_BLE_AD_TYPE_FLAG - - case ESP_BLE_AD_TYPE_16SRV_CMPL: { // Adv Data Type: 0x03 - setServiceUUID(BLEUUID(*reinterpret_cast(payload))); - break; - } // ESP_BLE_AD_TYPE_16SRV_CMPL - - case ESP_BLE_AD_TYPE_16SRV_PART: { // Adv Data Type: 0x02 - setServiceUUID(BLEUUID(*reinterpret_cast(payload))); - break; - } // ESP_BLE_AD_TYPE_16SRV_PART - - case ESP_BLE_AD_TYPE_32SRV_CMPL: { // Adv Data Type: 0x05 - setServiceUUID(BLEUUID(*reinterpret_cast(payload))); - break; - } // ESP_BLE_AD_TYPE_32SRV_CMPL - - case ESP_BLE_AD_TYPE_32SRV_PART: { // Adv Data Type: 0x04 - setServiceUUID(BLEUUID(*reinterpret_cast(payload))); - break; - } // ESP_BLE_AD_TYPE_32SRV_PART - - case ESP_BLE_AD_TYPE_128SRV_CMPL: { // Adv Data Type: 0x07 - setServiceUUID(BLEUUID(payload, 16, false)); - break; - } // ESP_BLE_AD_TYPE_128SRV_CMPL - - case ESP_BLE_AD_TYPE_128SRV_PART: { // Adv Data Type: 0x06 - setServiceUUID(BLEUUID(payload, 16, false)); - break; - } // ESP_BLE_AD_TYPE_128SRV_PART - - // See CSS Part A 1.4 Manufacturer Specific Data - case ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE: { - setManufacturerData(std::string(reinterpret_cast(payload), length)); - break; - } // ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE - - default: { - ESP_LOGD(LOG_TAG, "Unhandled type"); - break; - } - } // switch - payload += length; - } // Length <> 0 - - - if (sizeConsumed >=31 || length == 0) { - finished = true; - } - } // !finished -} // parseAdvertisement - - -/** - * @brief Set the address of the advertised device. - * @param [in] address The address of the advertised device. - */ -void BLEAdvertisedDevice::setAddress(BLEAddress address) { - m_address = address; -} // setAddress - - -/** - * @brief Set the adFlag for this device. - * @param [in] The discovered adFlag. - */ -void BLEAdvertisedDevice::setAdFlag(uint8_t adFlag) { - m_adFlag = adFlag; -} // setAdFlag - - -/** - * @brief Set the appearance for this device. - * @param [in] The discovered appearance. - */ -void BLEAdvertisedDevice::setAppearance(uint16_t appearance) { - m_appearance = appearance; - m_haveAppearance = true; - ESP_LOGD(LOG_TAG, "- appearance: %d", m_appearance); -} // setAppearance - - -/** - * @brief Set the manufacturer data for this device. - * @param [in] The discovered manufacturer data. - */ -void BLEAdvertisedDevice::setManufacturerData(std::string manufacturerData) { - m_manufacturerData = manufacturerData; - m_haveManufacturerData = true; - char* pHex = BLEUtils::buildHexData(nullptr, (uint8_t*)m_manufacturerData.data(), (uint8_t)m_manufacturerData.length()); - ESP_LOGD(LOG_TAG, "- manufacturer data: %s", pHex); - free(pHex); -} // setManufacturerData - - -/** - * @brief Set the name for this device. - * @param [in] name The discovered name. - */ -void BLEAdvertisedDevice::setName(std::string name) { - m_name = name; - m_haveName = true; - ESP_LOGD(LOG_TAG, "- name: %s", m_name.c_str()); -} // setName - - -/** - * @brief Set the RSSI for this device. - * @param [in] rssi The discovered RSSI. - */ -void BLEAdvertisedDevice::setRSSI(int rssi) { - m_rssi = rssi; - m_haveRSSI = true; - ESP_LOGD(LOG_TAG, "- rssi: %d", m_rssi); -} // setRSSI - - -/** - * @brief Set the Scan that created this advertised device. - * @param pScan The Scan that created this advertised device. - */ -void BLEAdvertisedDevice::setScan(BLEScan* pScan) { - m_pScan = pScan; -} // setScan - -/** - * @brief Set the Service UUID for this device. - * @param [in] serviceUUID The discovered serviceUUID - */ -void BLEAdvertisedDevice::setServiceUUID(const char* serviceUUID) { - return setServiceUUID(BLEUUID(serviceUUID)); -} // setRSSI - -/** - * @brief Set the Service UUID for this device. - * @param [in] serviceUUID The discovered serviceUUID - */ -void BLEAdvertisedDevice::setServiceUUID(BLEUUID serviceUUID) { - m_serviceUUID = serviceUUID; - m_haveServiceUUID = true; - ESP_LOGD(LOG_TAG, "- serviceUUID: %s", serviceUUID.toString().c_str()); -} // setRSSI - - -/** - * @brief Set the power level for this device. - * @param [in] txPower The discovered power level. - */ -void BLEAdvertisedDevice::setTXPower(int8_t txPower) { - m_txPower = txPower; - m_haveTXPower = true; - ESP_LOGD(LOG_TAG, "- txPower: %d", m_txPower); -} // setTXPower - - -/** - * @brief Create a string representation of this device. - * @return A string representation of this device. - */ -std::string BLEAdvertisedDevice::toString() { - std::stringstream ss; - ss << "Name: " << getName() << ", Address: " << getAddress().toString(); - if (haveAppearance()) { - ss << ", appearance: " << getApperance(); - } - if (haveManufacturerData()) { - char *pHex = BLEUtils::buildHexData(nullptr, (uint8_t*)getManufacturerData().data(), getManufacturerData().length()); - ss << ", manufacturer data: " << pHex; - free(pHex); - } - if (haveServiceUUID()) { - ss << ", serviceUUID: " << getServiceUUID().toString(); - } - if (haveTXPower()) { - ss << ", txPower: " << (int)getTXPower(); - } - return ss.str(); -} // toString - -#endif /* CONFIG_BT_ENABLED */ - diff --git a/ESP32_BLE_Arduino/src/BLEAdvertisedDevice.h b/ESP32_BLE_Arduino/src/BLEAdvertisedDevice.h deleted file mode 100644 index 2fb2652..0000000 --- a/ESP32_BLE_Arduino/src/BLEAdvertisedDevice.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * BLEAdvertisedDevice.h - * - * Created on: Jul 3, 2017 - * Author: kolban - */ - -#ifndef COMPONENTS_CPP_UTILS_BLEADVERTISEDDEVICE_H_ -#define COMPONENTS_CPP_UTILS_BLEADVERTISEDDEVICE_H_ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) -#include - -#include - -#include "BLEAddress.h" -#include "BLEScan.h" -#include "BLEUUID.h" - - -class BLEScan; -/** - * @brief A representation of a %BLE advertised device found by a scan. - * - * When we perform a %BLE scan, the result will be a set of devices that are advertising. This - * class provides a model of a detected device. - */ -class BLEAdvertisedDevice { -public: - BLEAdvertisedDevice(); - - BLEAddress getAddress(); - uint16_t getApperance(); - std::string getManufacturerData(); - std::string getName(); - int getRSSI(); - BLEScan* getScan(); - BLEUUID getServiceUUID(); - int8_t getTXPower(); - - bool haveAppearance(); - bool haveManufacturerData(); - bool haveName(); - bool haveRSSI(); - bool haveServiceUUID(); - bool haveTXPower(); - - std::string toString(); - -private: - friend class BLEScan; - - void parseAdvertisement(uint8_t* payload); - void setAddress(BLEAddress address); - void setAdFlag(uint8_t adFlag); - void setAdvertizementResult(uint8_t* payload); - void setAppearance(uint16_t appearance); - void setManufacturerData(std::string manufacturerData); - void setName(std::string name); - void setRSSI(int rssi); - void setScan(BLEScan* pScan); - void setServiceUUID(const char* serviceUUID); - void setServiceUUID(BLEUUID serviceUUID); - void setTXPower(int8_t txPower); - - bool m_haveAppearance; - bool m_haveManufacturerData; - bool m_haveName; - bool m_haveRSSI; - bool m_haveServiceUUID; - bool m_haveTXPower; - - - BLEAddress m_address = BLEAddress((uint8_t*)"\0\0\0\0\0\0"); - uint8_t m_adFlag; - uint16_t m_appearance; - int m_deviceType; - std::string m_manufacturerData; - std::string m_name; - BLEScan* m_pScan; - int m_rssi; - BLEUUID m_serviceUUID; - int8_t m_txPower; -}; - -/** - * @brief A callback handler for callbacks associated device scanning. - * - * When we are performing a scan as a %BLE client, we may wish to know when a new device that is advertising - * has been found. This class can be sub-classed and registered such that when a scan is performed and - * a new advertised device has been found, we will be called back to be notified. - */ -class BLEAdvertisedDeviceCallbacks { -public: - virtual ~BLEAdvertisedDeviceCallbacks() {} - /** - * @brief Called when a new scan result is detected. - * - * As we are scanning, we will find new devices. When found, this call back is invoked with a reference to the - * device that was found. During any individual scan, a device will only be detected one time. - */ - virtual void onResult(BLEAdvertisedDevice advertisedDevice) = 0; -}; - -#endif /* CONFIG_BT_ENABLED */ -#endif /* COMPONENTS_CPP_UTILS_BLEADVERTISEDDEVICE_H_ */ diff --git a/ESP32_BLE_Arduino/src/BLEAdvertising.cpp b/ESP32_BLE_Arduino/src/BLEAdvertising.cpp deleted file mode 100644 index ad076dd..0000000 --- a/ESP32_BLE_Arduino/src/BLEAdvertising.cpp +++ /dev/null @@ -1,155 +0,0 @@ -/* - * BLEAdvertising.cpp - * - * This class encapsulates advertising a BLE Server. - * Created on: Jun 21, 2017 - * Author: kolban - */ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) -#include "BLEAdvertising.h" -#include -#include -#include "BLEUtils.h" -#include "GeneralUtils.h" - -static const char* LOG_TAG = "BLEAdvertising"; - - -/** - * @brief Construct a default advertising object. - * - */ -BLEAdvertising::BLEAdvertising() { - m_advData.set_scan_rsp = false; - m_advData.include_name = true; - m_advData.include_txpower = true; - m_advData.min_interval = 0x20; - m_advData.max_interval = 0x40; - m_advData.appearance = 0x00; - m_advData.manufacturer_len = 0; - m_advData.p_manufacturer_data = nullptr; - m_advData.service_data_len = 0; - m_advData.p_service_data = nullptr; - m_advData.service_uuid_len = 0; - m_advData.p_service_uuid = nullptr; - m_advData.flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT); - - m_advParams.adv_int_min = 0x20; - m_advParams.adv_int_max = 0x40; - m_advParams.adv_type = ADV_TYPE_IND; - m_advParams.own_addr_type = BLE_ADDR_TYPE_PUBLIC; - m_advParams.channel_map = ADV_CHNL_ALL; - m_advParams.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY; -} // BLEAdvertising - - -/** - * @brief Set the device appearance in the advertising data. - * The appearance attribute is of type 0x19. The codes for distinct appearances can be found here: - * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.gap.appearance.xml. - * @param [in] appearance The appearance of the device in the advertising data. - * @return N/A. - */ -void BLEAdvertising::setAppearance(uint16_t appearance) { - m_advData.appearance = appearance; -} // setAppearance - - -/** - * @brief Set the service UUID. - * We maintain a class member called m_advData (esp_ble_adv_data_t) that is passed to the - * ESP-IDF advertising functions. In this method, we see two fields within that structure - * namely service_uuid_len and p_service_uuid to be the information supplied in the passed - * in service uuid. - * @param [in] uuid The UUID of the service. - * @return N/A. - */ -void BLEAdvertising::setServiceUUID(const char* serviceUUID) { - return setServiceUUID(BLEUUID(serviceUUID)); -} -/** - * @brief Set the service UUID. - * We maintain a class member called m_advData (esp_ble_adv_data_t) that is passed to the - * ESP-IDF advertising functions. In this method, we see two fields within that structure - * namely service_uuid_len and p_service_uuid to be the information supplied in the passed - * in service uuid. - * @param [in] uuid The UUID of the service. - * @return N/A. - */ -void BLEAdvertising::setServiceUUID(BLEUUID serviceUUID) { - ESP_LOGD(LOG_TAG, ">> setServiceUUID - %s", serviceUUID.toString().c_str()); - m_serviceUUID = serviceUUID; // Save the new service UUID - esp_bt_uuid_t* espUUID = m_serviceUUID.getNative(); - switch(espUUID->len) { - case ESP_UUID_LEN_16: { - m_advData.service_uuid_len = 2; - m_advData.p_service_uuid = reinterpret_cast(&espUUID->uuid.uuid16); - break; - } - case ESP_UUID_LEN_32: { - m_advData.service_uuid_len = 4; - m_advData.p_service_uuid = reinterpret_cast(&espUUID->uuid.uuid32); - break; - } - case ESP_UUID_LEN_128: { - m_advData.service_uuid_len = 16; - m_advData.p_service_uuid = reinterpret_cast(&espUUID->uuid.uuid128); - break; - } - } // switch - ESP_LOGD(LOG_TAG, "<< setServiceUUID"); -} // setServiceUUID - - -/** - * @brief Start advertising. - * Start advertising. - * @return N/A. - */ -void BLEAdvertising::start() { - ESP_LOGD(LOG_TAG, ">> start"); - - if (m_advData.service_uuid_len > 0) { - uint8_t hexData[16*2+1]; - BLEUtils::buildHexData(hexData, m_advData.p_service_uuid, m_advData.service_uuid_len); - ESP_LOGD(LOG_TAG, " - Service: service_uuid_len=%d, p_service_uuid=0x%x (data=%s)", - m_advData.service_uuid_len, - (uint32_t)m_advData.p_service_uuid, - (m_advData.service_uuid_len > 0?(char *)hexData:"N/A") - ); - } // We have a service to advertise - - - // Set the configuration for advertising. - esp_err_t errRc = ::esp_ble_gap_config_adv_data(&m_advData); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "<< esp_ble_gap_config_adv_data: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return; - } - - // Start advertising. - errRc = ::esp_ble_gap_start_advertising(&m_advParams); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "<< esp_ble_gap_start_advertising: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return; - } - ESP_LOGD(LOG_TAG, "<< start"); -} // start - - -/** - * @brief Stop advertising. - * Stop advertising. - * @return N/A. - */ -void BLEAdvertising::stop() { - ESP_LOGD(LOG_TAG, ">> stop"); - esp_err_t errRc = ::esp_ble_gap_stop_advertising(); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_ble_gap_stop_advertising: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return; - } - ESP_LOGD(LOG_TAG, "<< stop"); -} // stop -#endif /* CONFIG_BT_ENABLED */ diff --git a/ESP32_BLE_Arduino/src/BLEAdvertising.h b/ESP32_BLE_Arduino/src/BLEAdvertising.h deleted file mode 100644 index 2d0b51c..0000000 --- a/ESP32_BLE_Arduino/src/BLEAdvertising.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * BLEAdvertising.h - * - * Created on: Jun 21, 2017 - * Author: kolban - */ - -#ifndef COMPONENTS_CPP_UTILS_BLEADVERTISING_H_ -#define COMPONENTS_CPP_UTILS_BLEADVERTISING_H_ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) -#include -#include "BLEUUID.h" - -/** - * @brief Perform and manage %BLE advertising. - * - * A %BLE server will want to perform advertising in order to make itself known to %BLE clients. - */ -class BLEAdvertising { -public: - BLEAdvertising(); - void start(); - void stop(); - void setAppearance(uint16_t appearance); - void setServiceUUID(const char* serviceUUID); - void setServiceUUID(BLEUUID serviceUUID); -private: - esp_ble_adv_data_t m_advData; - esp_ble_adv_params_t m_advParams; - BLEUUID m_serviceUUID; -}; -#endif /* CONFIG_BT_ENABLED */ -#endif /* COMPONENTS_CPP_UTILS_BLEADVERTISING_H_ */ diff --git a/ESP32_BLE_Arduino/src/BLECharacteristic.cpp b/ESP32_BLE_Arduino/src/BLECharacteristic.cpp deleted file mode 100644 index f5b8200..0000000 --- a/ESP32_BLE_Arduino/src/BLECharacteristic.cpp +++ /dev/null @@ -1,693 +0,0 @@ -/* - * BLECharacteristic.cpp - * - * Created on: Jun 22, 2017 - * Author: kolban - */ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) -#include -#include -#include -#include -#include "sdkconfig.h" -#include -#include -#include "BLECharacteristic.h" -#include "BLEService.h" -#include "BLEUtils.h" -#include "BLE2902.h" -#include "GeneralUtils.h" - -static const char* LOG_TAG = "BLECharacteristic"; - -#define NULL_HANDLE (0xffff) - - -/** - * @brief Construct a characteristic - * @param [in] uuid - UUID (const char*) for the characteristic. - * @param [in] properties - Properties for the characteristic. - */ -BLECharacteristic::BLECharacteristic(const char* uuid, uint32_t properties) : BLECharacteristic(BLEUUID(uuid), properties) { -} - -/** - * @brief Construct a characteristic - * @param [in] uuid - UUID for the characteristic. - * @param [in] properties - Properties for the characteristic. - */ -BLECharacteristic::BLECharacteristic(BLEUUID uuid, uint32_t properties) { - m_bleUUID = uuid; - m_handle = NULL_HANDLE; - m_properties = (esp_gatt_char_prop_t)0; - m_pCallbacks = nullptr; - - setBroadcastProperty((properties & PROPERTY_BROADCAST) !=0); - setReadProperty((properties & PROPERTY_READ) !=0); - setWriteProperty((properties & PROPERTY_WRITE) !=0); - setNotifyProperty((properties & PROPERTY_NOTIFY) !=0); - setIndicateProperty((properties & PROPERTY_INDICATE) !=0); - setWriteNoResponseProperty((properties & PROPERTY_WRITE_NR) !=0); -} // BLECharacteristic - -/** - * @brief Destructor. - */ -BLECharacteristic::~BLECharacteristic() { - //free(m_value.attr_value); // Release the storage for the value. -} // ~BLECharacteristic - - -/** - * @brief Associate a descriptor with this characteristic. - * @param [in] pDescriptor - * @return N/A. - */ -void BLECharacteristic::addDescriptor(BLEDescriptor* pDescriptor) { - ESP_LOGD(LOG_TAG, ">> addDescriptor(): Adding %s to %s", pDescriptor->toString().c_str(), toString().c_str()); - m_descriptorMap.setByUUID(pDescriptor->getUUID(), pDescriptor); - ESP_LOGD(LOG_TAG, "<< addDescriptor()"); -} // addDescriptor - - -/** - * @brief Register a new characteristic with the ESP runtime. - * @param [in] pService The service with which to associate this characteristic. - */ -void BLECharacteristic::executeCreate(BLEService* pService) { - ESP_LOGD(LOG_TAG, ">> executeCreate()"); - - if (m_handle != NULL_HANDLE) { - ESP_LOGE(LOG_TAG, "Characteristic already has a handle."); - return; - } - - m_pService = pService; // Save the service for to which this characteristic belongs. - - ESP_LOGD(LOG_TAG, "Registering characteristic (esp_ble_gatts_add_char): uuid: %s, service: %s", - getUUID().toString().c_str(), - m_pService->toString().c_str()); - - esp_attr_control_t control; - control.auto_rsp = ESP_GATT_RSP_BY_APP; - - m_semaphoreCreateEvt.take("executeCreate"); - - std::string strValue = m_value.getValue(); - - esp_attr_value_t value; - value.attr_len = strValue.length(); - value.attr_max_len = ESP_GATT_MAX_ATTR_LEN; - value.attr_value = (uint8_t*)strValue.data(); - - esp_err_t errRc = ::esp_ble_gatts_add_char( - m_pService->getHandle(), - getUUID().getNative(), - static_cast(ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE), - getProperties(), - &value, - &control); // Whether to auto respond or not. - - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "<< esp_ble_gatts_add_char: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return; - } - - m_semaphoreCreateEvt.wait("executeCreate"); - - // Now that we have registered the characteristic, we must also register all the descriptors associated with this - // characteristic. We iterate through each of those and invoke the registration call to register them with the - // ESP environment. - - BLEDescriptor* pDescriptor = m_descriptorMap.getFirst(); - - while (pDescriptor != nullptr) { - pDescriptor->executeCreate(this); - pDescriptor = m_descriptorMap.getNext(); - } // End while - - ESP_LOGD(LOG_TAG, "<< executeCreate"); -} // executeCreate - - - -/** - * @brief Return the BLE Descriptor for the given UUID if associated with this characteristic. - * @param [in] descriptorUUID The UUID of the descriptor that we wish to retrieve. - * @return The BLE Descriptor. If no such descriptor is associated with the characteristic, nullptr is returned. - */ -BLEDescriptor* BLECharacteristic::getDescriptorByUUID(const char* descriptorUUID) { - return m_descriptorMap.getByUUID(BLEUUID(descriptorUUID)); -} // getDescriptorByUUID - -/** - * @brief Return the BLE Descriptor for the given UUID if associated with this characteristic. - * @param [in] descriptorUUID The UUID of the descriptor that we wish to retrieve. - * @return The BLE Descriptor. If no such descriptor is associated with the characteristic, nullptr is returned. - */ -BLEDescriptor* BLECharacteristic::getDescriptorByUUID(BLEUUID descriptorUUID) { - return m_descriptorMap.getByUUID(descriptorUUID); -} // getDescriptorByUUID - - -/** - * @brief Get the handle of the characteristic. - * @return The handle of the characteristic. - */ -uint16_t BLECharacteristic::getHandle() { - return m_handle; -} // getHandle - - -esp_gatt_char_prop_t BLECharacteristic::getProperties() { - return m_properties; -} // getProperties - - -/** - * @brief Get the service associated with this characteristic. - */ -BLEService* BLECharacteristic::getService() { - return m_pService; -} // getService - - -/** - * @brief Get the UUID of the characteristic. - * @return The UUID of the characteristic. - */ -BLEUUID BLECharacteristic::getUUID() { - return m_bleUUID; -} // getUUID - - -/** - * @brief Retrieve the current value of the characteristic. - * @return A pointer to storage containing the current characteristic value. - */ -std::string BLECharacteristic::getValue() { - return m_value.getValue(); -} // getValue - - -void BLECharacteristic::handleGATTServerEvent( - esp_gatts_cb_event_t event, - esp_gatt_if_t gatts_if, - esp_ble_gatts_cb_param_t* param) { - switch(event) { - // Events handled: - // ESP_GATTS_ADD_CHAR_EVT - // ESP_GATTS_WRITE_EVT - // ESP_GATTS_READ_EVT - // - - // ESP_GATTS_EXEC_WRITE_EVT - // When we receive this event it is an indication that a previous write long needs to be committed. - // - // exec_write: - // - uint16_t conn_id - // - uint32_t trans_id - // - esp_bd_addr_t bda - // - uint8_t exec_write_flag - // - case ESP_GATTS_EXEC_WRITE_EVT: { - if (param->exec_write.exec_write_flag == ESP_GATT_PREP_WRITE_EXEC) { - m_value.commit(); - if (m_pCallbacks != nullptr) { - m_pCallbacks->onWrite(this); // Invoke the onWrite callback handler. - } - } else { - m_value.cancel(); - } - - esp_err_t errRc = ::esp_ble_gatts_send_response( - gatts_if, - param->write.conn_id, - param->write.trans_id, ESP_GATT_OK, nullptr); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_ble_gatts_send_response: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - } - break; - } // ESP_GATTS_EXEC_WRITE_EVT - - - // ESP_GATTS_ADD_CHAR_EVT - Indicate that a characteristic was added to the service. - // add_char: - // - esp_gatt_status_t status - // - uint16_t attr_handle - // - uint16_t service_handle - // - esp_bt_uuid_t char_uuid - case ESP_GATTS_ADD_CHAR_EVT: { - if (getUUID().equals(BLEUUID(param->add_char.char_uuid)) && - getService()->getHandle()==param->add_char.service_handle) { - m_semaphoreCreateEvt.give(); - } - break; - } // ESP_GATTS_ADD_CHAR_EVT - - - // ESP_GATTS_WRITE_EVT - A request to write the value of a characteristic has arrived. - // - // write: - // - uint16_t conn_id - // - uint16_t trans_id - // - esp_bd_addr_t bda - // - uint16_t handle - // - uint16_t offset - // - bool need_rsp - // - bool is_prep - // - uint16_t len - // - uint8_t *value - // - case ESP_GATTS_WRITE_EVT: { -// We check if this write request is for us by comparing the handles in the event. If it is for us -// we save the new value. Next we look at the need_rsp flag which indicates whether or not we need -// to send a response. If we do, then we formulate a response and send it. - if (param->write.handle == m_handle) { - if (param->write.is_prep) { - m_value.addPart(param->write.value, param->write.len); - } else { - setValue(param->write.value, param->write.len); - } - - ESP_LOGD(LOG_TAG, " - Response to write event: New value: handle: %.2x, uuid: %s", - getHandle(), getUUID().toString().c_str()); - - char *pHexData = BLEUtils::buildHexData(nullptr, param->write.value, param->write.len); - ESP_LOGD(LOG_TAG, " - Data: length: %d, data: %s", param->write.len, pHexData); - free(pHexData); - - if (param->write.need_rsp) { - esp_gatt_rsp_t rsp; - - rsp.attr_value.len = param->write.len; - rsp.attr_value.handle = m_handle; - rsp.attr_value.offset = param->write.offset; - rsp.attr_value.auth_req = ESP_GATT_AUTH_REQ_NONE; - memcpy(rsp.attr_value.value, param->write.value, param->write.len); - - esp_err_t errRc = ::esp_ble_gatts_send_response( - gatts_if, - param->write.conn_id, - param->write.trans_id, ESP_GATT_OK, &rsp); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_ble_gatts_send_response: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - } - } // Response needed - - if (m_pCallbacks != nullptr && param->write.is_prep != true) { - m_pCallbacks->onWrite(this); // Invoke the onWrite callback handler. - } - } // Match on handles. - break; - } // ESP_GATTS_WRITE_EVT - - - // ESP_GATTS_READ_EVT - A request to read the value of a characteristic has arrived. - // - // read: - // - uint16_t conn_id - // - uint32_t trans_id - // - esp_bd_addr_t bda - // - uint16_t handle - // - uint16_t offset - // - bool is_long - // - bool need_rsp - // - case ESP_GATTS_READ_EVT: { - ESP_LOGD(LOG_TAG, "- Testing: 0x%.2x == 0x%.2x", param->read.handle, m_handle); - if (param->read.handle == m_handle) { - - if (m_pCallbacks != nullptr) { - m_pCallbacks->onRead(this); // Invoke the read callback. - } - -// Here's an interesting thing. The read request has the option of saying whether we need a response -// or not. What would it "mean" to receive a read request and NOT send a response back? That feels like -// a very strange read. -// -// We have to handle the case where the data we wish to send back to the client is greater than the maximum -// packet size of 22 bytes. In this case, we become responsible for chunking the data into uints of 22 bytes. -// The apparent algorithm is as follows. -// If the is_long flag is set then this is a follow on from an original read and we will already have sent at least 22 bytes. -// If the is_long flag is not set then we need to check how much data we are going to send. If we are sending LESS than -// 22 bytes, then we "just" send it and thats the end of the story. -// If we are sending 22 bytes exactly, we just send it BUT we will get a follow on request. -// If we are sending more than 22 bytes, we send the first 22 bytes and we will get a follow on request. -// Because of follow on request processing, we need to maintain an offset of how much data we have already sent -// so that when a follow on request arrives, we know where to start in the data to send the next sequence. -// Note that the indication that the client will send a follow on request is that we sent exactly 22 bytes as a response. -// If our payload is divisible by 22 then the last response will be a response of 0 bytes in length. -// -// The following code has deliberately not been factored to make it fewer statements because this would cloud the -// the logic flow comprehension. -// - if (param->read.need_rsp) { - ESP_LOGD(LOG_TAG, "Sending a response (esp_ble_gatts_send_response)"); - esp_gatt_rsp_t rsp; - std::string value = m_value.getValue(); - if (param->read.is_long) { - if (value.length() - m_value.getReadOffset() < 22) { - // This is the last in the chain - rsp.attr_value.len = value.length() - m_value.getReadOffset(); - rsp.attr_value.offset = m_value.getReadOffset(); - memcpy(rsp.attr_value.value, value.data() + rsp.attr_value.offset, rsp.attr_value.len); - m_value.setReadOffset(0); - } else { - // There will be more to come. - rsp.attr_value.len = 22; - rsp.attr_value.offset = m_value.getReadOffset(); - memcpy(rsp.attr_value.value, value.data() + rsp.attr_value.offset, rsp.attr_value.len); - m_value.setReadOffset(rsp.attr_value.offset + 22); - } - } else { - if (value.length() > 21) { - // Too big for a single shot entry. - m_value.setReadOffset(22); - rsp.attr_value.len = 22; - rsp.attr_value.offset = 0; - memcpy(rsp.attr_value.value, value.data(), rsp.attr_value.len); - } else { - // Will fit in a single packet with no callbacks required. - rsp.attr_value.len = value.length(); - rsp.attr_value.offset = 0; - memcpy(rsp.attr_value.value, value.data(), rsp.attr_value.len); - } - } - rsp.attr_value.handle = param->read.handle; - rsp.attr_value.auth_req = ESP_GATT_AUTH_REQ_NONE; - - char *pHexData = BLEUtils::buildHexData(nullptr, rsp.attr_value.value, rsp.attr_value.len); - ESP_LOGD(LOG_TAG, " - Data: length=%d, data=%s, offset=%d", rsp.attr_value.len, pHexData, rsp.attr_value.offset); - free(pHexData); - - esp_err_t errRc = ::esp_ble_gatts_send_response( - gatts_if, param->read.conn_id, - param->read.trans_id, - ESP_GATT_OK, - &rsp); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_ble_gatts_send_response: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - } - } // Response needed - } // Handle matches this characteristic. - break; - } // ESP_GATTS_READ_EVT - - // ESP_GATTS_CONF_EVT - // - // conf: - // - esp_gatt_status_t status – The status code. - // - uint16_t conn_id – The connection used. - // - case ESP_GATTS_CONF_EVT: { - m_semaphoreConfEvt.give(); - break; - } - - default: { - break; - } // default - - } // switch event - - // Give each of the descriptors associated with this characteristic the opportunity to handle the - // event. - BLEDescriptor *pDescriptor = m_descriptorMap.getFirst(); - while(pDescriptor != nullptr) { - pDescriptor->handleGATTServerEvent(event, gatts_if, param); - pDescriptor = m_descriptorMap.getNext(); - } - -} // handleGATTServerEvent - -/** - * @brief Send an indication. - * An indication is a transmission of up to the first 20 bytes of the characteristic value. An indication - * will block waiting a positive confirmation from the client. - * @return N/A - */ -void BLECharacteristic::indicate() { - - ESP_LOGD(LOG_TAG, ">> indicate: length: %d", m_value.getValue().length()); - - assert(getService() != nullptr); - assert(getService()->getServer() != nullptr); - - GeneralUtils::hexDump((uint8_t*)m_value.getValue().data(), m_value.getValue().length()); - - if (getService()->getServer()->getConnectedCount() == 0) { - ESP_LOGD(LOG_TAG, "<< indicate: No connected clients."); - return; - } - - // Test to see if we have a 0x2902 descriptor. If we do, then check to see if indications are enabled - // and, if not, prevent the indication. - - BLE2902 *p2902 = (BLE2902*)getDescriptorByUUID((uint16_t)0x2902); - if (p2902 != nullptr && !p2902->getIndications()) { - ESP_LOGD(LOG_TAG, "<< indications disabled; ignoring"); - return; - } - - if (m_value.getValue().length() > 20) { - ESP_LOGD(LOG_TAG, "- Truncating to 20 bytes (maximum notify size)"); - } - - size_t length = m_value.getValue().length(); - if (length > 20) { - length = 20; - } - - m_semaphoreConfEvt.take("indicate"); - - esp_err_t errRc = ::esp_ble_gatts_send_indicate( - getService()->getServer()->getGattsIf(), - getService()->getServer()->getConnId(), - getHandle(), length, (uint8_t*)m_value.getValue().data(), true); // The need_confirm = true makes this an indication. - - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "<< esp_ble_gatts_send_indicate: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return; - } - - m_semaphoreConfEvt.wait("indicate"); - ESP_LOGD(LOG_TAG, "<< indicate"); -} // indicate - - -/** - * @brief Send a notify. - * A notification is a transmission of up to the first 20 bytes of the characteristic value. An notification - * will not block; it is a fire and forget. - * @return N/A. - */ -void BLECharacteristic::notify() { - ESP_LOGD(LOG_TAG, ">> notify: length: %d", m_value.getValue().length()); - - - assert(getService() != nullptr); - assert(getService()->getServer() != nullptr); - - - GeneralUtils::hexDump((uint8_t*)m_value.getValue().data(), m_value.getValue().length()); - - if (getService()->getServer()->getConnectedCount() == 0) { - ESP_LOGD(LOG_TAG, "<< notify: No connected clients."); - return; - } - - // Test to see if we have a 0x2902 descriptor. If we do, then check to see if notification is enabled - // and, if not, prevent the notification. - - BLE2902 *p2902 = (BLE2902*)getDescriptorByUUID((uint16_t)0x2902); - if (p2902 != nullptr && !p2902->getNotifications()) { - ESP_LOGD(LOG_TAG, "<< notifications disabled; ignoring"); - return; - } - - if (m_value.getValue().length() > 20) { - ESP_LOGD(LOG_TAG, "- Truncating to 20 bytes (maximum notify size)"); - } - - size_t length = m_value.getValue().length(); - if (length > 20) { - length = 20; - } - - esp_err_t errRc = ::esp_ble_gatts_send_indicate( - getService()->getServer()->getGattsIf(), - getService()->getServer()->getConnId(), - getHandle(), length, (uint8_t*)m_value.getValue().data(), false); // The need_confirm = false makes this a notify. - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "<< esp_ble_gatts_send_indicate: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return; - } - - ESP_LOGD(LOG_TAG, "<< notify"); -} // Notify - - -/** - * @brief Set the permission to broadcast. - * A characteristics has properties associated with it which define what it is capable of doing. - * One of these is the broadcast flag. - * @param [in] value The flag value of the property. - * @return N/A - */ -void BLECharacteristic::setBroadcastProperty(bool value) { - //ESP_LOGD(LOG_TAG, "setBroadcastProperty(%d)", value); - if (value) { - m_properties = (esp_gatt_char_prop_t)(m_properties | ESP_GATT_CHAR_PROP_BIT_BROADCAST); - } else { - m_properties = (esp_gatt_char_prop_t)(m_properties & ~ESP_GATT_CHAR_PROP_BIT_BROADCAST); - } -} // setBroadcastProperty - - -/** - * @brief Set the callback handlers for this characteristic. - * @param [in] pCallbacks An instance of a callbacks structure used to define any callbacks for the characteristic. - */ -void BLECharacteristic::setCallbacks(BLECharacteristicCallbacks* pCallbacks) { - m_pCallbacks = pCallbacks; -} // setCallbacks - - -/** - * @brief Set the BLE handle associated with this characteristic. - * A user program will request that a characteristic be created against a service. When the characteristic has been - * registered, the service will be given a "handle" that it knows the characteristic as. This handle is unique to the - * server/service but it is told to the service, not the characteristic associated with the service. This internally - * exposed function can be invoked by the service against this model of the characteristic to allow the characteristic - * to learn its own handle. Once the characteristic knows its own handle, it will be able to see incoming GATT events - * that will be propagated down to it which contain a handle value and now know that the event is destined for it. - * @param [in] handle The handle associated with this characteristic. - */ -void BLECharacteristic::setHandle(uint16_t handle) { - ESP_LOGD(LOG_TAG, ">> setHandle: handle=0x%.2x, characteristic uuid=%s", handle, getUUID().toString().c_str()); - m_handle = handle; - ESP_LOGD(LOG_TAG, "<< setHandle"); -} // setHandle - - -/** - * @brief Set the Indicate property value. - * @param [in] value Set to true if we are to allow indicate messages. - */ -void BLECharacteristic::setIndicateProperty(bool value) { - //ESP_LOGD(LOG_TAG, "setIndicateProperty(%d)", value); - if (value) { - m_properties = (esp_gatt_char_prop_t)(m_properties | ESP_GATT_CHAR_PROP_BIT_INDICATE); - } else { - m_properties = (esp_gatt_char_prop_t)(m_properties & ~ESP_GATT_CHAR_PROP_BIT_INDICATE); - } -} // setIndicateProperty - - -/** - * @brief Set the Notify property value. - * @param [in] value Set to true if we are to allow notification messages. - */ -void BLECharacteristic::setNotifyProperty(bool value) { - //ESP_LOGD(LOG_TAG, "setNotifyProperty(%d)", value); - if (value) { - m_properties = (esp_gatt_char_prop_t)(m_properties | ESP_GATT_CHAR_PROP_BIT_NOTIFY); - } else { - m_properties = (esp_gatt_char_prop_t)(m_properties & ~ESP_GATT_CHAR_PROP_BIT_NOTIFY); - } -} // setNotifyProperty - - -/** - * @brief Set the Read property value. - * @param [in] value Set to true if we are to allow reads. - */ -void BLECharacteristic::setReadProperty(bool value) { - //ESP_LOGD(LOG_TAG, "setReadProperty(%d)", value); - if (value) { - m_properties = (esp_gatt_char_prop_t)(m_properties | ESP_GATT_CHAR_PROP_BIT_READ); - } else { - m_properties = (esp_gatt_char_prop_t)(m_properties & ~ESP_GATT_CHAR_PROP_BIT_READ); - } -} // setReadProperty - - -/** - * @brief Set the value of the characteristic. - * @param [in] data The data to set for the characteristic. - * @param [in] length The length of the data in bytes. - */ -void BLECharacteristic::setValue(uint8_t* data, size_t length) { - char *pHex = BLEUtils::buildHexData(nullptr, data, length); - ESP_LOGD(LOG_TAG, ">> setValue: length=%d, data=%s, characteristic UUID=%s", length, pHex, getUUID().toString().c_str()); - free(pHex); - if (length > ESP_GATT_MAX_ATTR_LEN) { - ESP_LOGE(LOG_TAG, "Size %d too large, must be no bigger than %d", length, ESP_GATT_MAX_ATTR_LEN); - return; - } - m_value.setValue(data, length); - ESP_LOGD(LOG_TAG, "<< setValue"); -} // setValue - - -/** - * @brief Set the value of the characteristic from string data. - * We set the value of the characteristic from the bytes contained in the - * string. - * @param [in] Set the value of the characteristic. - * @return N/A. - */ -void BLECharacteristic::setValue(std::string value) { - setValue((uint8_t*)(value.data()), value.length()); -} // setValue - - -/** - * @brief Set the Write No Response property value. - * @param [in] value Set to true if we are to allow writes with no response. - */ -void BLECharacteristic::setWriteNoResponseProperty(bool value) { - //ESP_LOGD(LOG_TAG, "setWriteNoResponseProperty(%d)", value); - if (value) { - m_properties = (esp_gatt_char_prop_t)(m_properties | ESP_GATT_CHAR_PROP_BIT_WRITE_NR); - } else { - m_properties = (esp_gatt_char_prop_t)(m_properties & ~ESP_GATT_CHAR_PROP_BIT_WRITE_NR); - } -} // setWriteNoResponseProperty - - -/** - * @brief Set the Write property value. - * @param [in] value Set to true if we are to allow writes. - */ -void BLECharacteristic::setWriteProperty(bool value) { - //ESP_LOGD(LOG_TAG, "setWriteProperty(%d)", value); - if (value) { - m_properties = (esp_gatt_char_prop_t)(m_properties | ESP_GATT_CHAR_PROP_BIT_WRITE); - } else { - m_properties = (esp_gatt_char_prop_t)(m_properties & ~ESP_GATT_CHAR_PROP_BIT_WRITE); - } -} // setWriteProperty - - -/** - * @brief Return a string representation of the characteristic. - * @return A string representation of the characteristic. - */ -std::string BLECharacteristic::toString() { - std::stringstream stringstream; - stringstream << std::hex << std::setfill('0'); - stringstream << "UUID: " << m_bleUUID.toString() + ", handle: 0x" << std::setw(2) << m_handle; - stringstream << " " << - ((m_properties & ESP_GATT_CHAR_PROP_BIT_READ)?"Read ":"") << - ((m_properties & ESP_GATT_CHAR_PROP_BIT_WRITE)?"Write ":"") << - ((m_properties & ESP_GATT_CHAR_PROP_BIT_WRITE_NR)?"WriteNoResponse ":"") << - ((m_properties & ESP_GATT_CHAR_PROP_BIT_BROADCAST)?"Broadcast ":"") << - ((m_properties & ESP_GATT_CHAR_PROP_BIT_NOTIFY)?"Notify ":"") << - ((m_properties & ESP_GATT_CHAR_PROP_BIT_INDICATE)?"Indicate ":""); - return stringstream.str(); -} // toString - -#endif /* CONFIG_BT_ENABLED */ diff --git a/ESP32_BLE_Arduino/src/BLECharacteristic.h b/ESP32_BLE_Arduino/src/BLECharacteristic.h deleted file mode 100644 index b39c022..0000000 --- a/ESP32_BLE_Arduino/src/BLECharacteristic.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * BLECharacteristic.h - * - * Created on: Jun 22, 2017 - * Author: kolban - */ - -#ifndef COMPONENTS_CPP_UTILS_BLECHARACTERISTIC_H_ -#define COMPONENTS_CPP_UTILS_BLECHARACTERISTIC_H_ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) -#include -#include -#include "BLEUUID.h" -#include -#include "BLEDescriptor.h" -#include "BLEValue.h" -#include "FreeRTOS.h" - -class BLEService; -class BLEDescriptor; -class BLECharacteristicCallbacks; - -/** - * @brief A management structure for %BLE descriptors. - */ -class BLEDescriptorMap { -public: - void setByUUID(const char* uuid, BLEDescriptor *pDescriptor); - void setByUUID(BLEUUID uuid, BLEDescriptor *pDescriptor); - void setByHandle(uint16_t handle, BLEDescriptor *pDescriptor); - BLEDescriptor *getByUUID(const char* uuid); - BLEDescriptor *getByUUID(BLEUUID uuid); - BLEDescriptor *getByHandle(uint16_t handle); - std::string toString(); - void handleGATTServerEvent( - esp_gatts_cb_event_t event, - esp_gatt_if_t gatts_if, - esp_ble_gatts_cb_param_t *param); - BLEDescriptor *getFirst(); - BLEDescriptor *getNext(); -private: - std::map m_uuidMap; - std::map m_handleMap; - std::map::iterator m_iterator; -}; - - -/** - * @brief The model of a %BLE Characteristic. - * - * A %BLE Characteristic is an identified value container that manages a value. It is exposed by a %BLE server and - * can be read and written to by a %BLE client. - */ -class BLECharacteristic { -public: - BLECharacteristic(const char* uuid, uint32_t properties = 0); - BLECharacteristic(BLEUUID uuid, uint32_t properties = 0); - virtual ~BLECharacteristic(); - - void addDescriptor(BLEDescriptor* pDescriptor); - BLEDescriptor* getDescriptorByUUID(const char* descriptorUUID); - BLEDescriptor* getDescriptorByUUID(BLEUUID descriptorUUID); - //size_t getLength(); - BLEUUID getUUID(); - std::string getValue(); - - void indicate(); - void notify(); - void setBroadcastProperty(bool value); - void setCallbacks(BLECharacteristicCallbacks* pCallbacks); - void setIndicateProperty(bool value); - void setNotifyProperty(bool value); - void setReadProperty(bool value); - void setValue(uint8_t* data, size_t size); - void setValue(std::string value); - void setWriteProperty(bool value); - void setWriteNoResponseProperty(bool value); - std::string toString(); - - - static const uint32_t PROPERTY_READ = 1<<0; - static const uint32_t PROPERTY_WRITE = 1<<1; - static const uint32_t PROPERTY_NOTIFY = 1<<2; - static const uint32_t PROPERTY_BROADCAST = 1<<3; - static const uint32_t PROPERTY_INDICATE = 1<<4; - static const uint32_t PROPERTY_WRITE_NR = 1<<5; - -private: - friend class BLEServer; - friend class BLEService; - friend class BLEDescriptor; - friend class BLECharacteristicMap; - - BLEUUID m_bleUUID; - BLEDescriptorMap m_descriptorMap; - uint16_t m_handle; - esp_gatt_char_prop_t m_properties; - BLECharacteristicCallbacks* m_pCallbacks; - BLEService* m_pService; - BLEValue m_value; - - void handleGATTServerEvent( - esp_gatts_cb_event_t event, - esp_gatt_if_t gatts_if, - esp_ble_gatts_cb_param_t* param); - - void executeCreate(BLEService* pService); - uint16_t getHandle(); - esp_gatt_char_prop_t getProperties(); - BLEService* getService(); - void setHandle(uint16_t handle); - FreeRTOS::Semaphore m_semaphoreCreateEvt = FreeRTOS::Semaphore("CreateEvt"); - FreeRTOS::Semaphore m_semaphoreConfEvt = FreeRTOS::Semaphore("ConfEvt"); -}; // BLECharacteristic - - -/** - * @brief Callbacks that can be associated with a %BLE characteristic to inform of events. - * - * When a server application creates a %BLE characteristic, we may wish to be informed when there is either - * a read or write request to the characteristic's value. An application can register a - * sub-classed instance of this class and will be notified when such an event happens. - */ -class BLECharacteristicCallbacks { -public: - virtual ~BLECharacteristicCallbacks(); - virtual void onRead(BLECharacteristic* pCharacteristic); - virtual void onWrite(BLECharacteristic* pCharacteristic); -}; -#endif /* CONFIG_BT_ENABLED */ -#endif /* COMPONENTS_CPP_UTILS_BLECHARACTERISTIC_H_ */ diff --git a/ESP32_BLE_Arduino/src/BLECharacteristicCallbacks.cpp b/ESP32_BLE_Arduino/src/BLECharacteristicCallbacks.cpp deleted file mode 100644 index b733865..0000000 --- a/ESP32_BLE_Arduino/src/BLECharacteristicCallbacks.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/* - * BLECharacteristicCallbacks.cpp - * - * Created on: Jul 2, 2017 - * Author: kolban - */ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) -#include "BLECharacteristic.h" -#include -static const char* LOG_TAG = "BLECharacteristicCallbacks"; - - -BLECharacteristicCallbacks::~BLECharacteristicCallbacks() {} - -/** - * @brief Callback function to support a read request. - * @param [in] pCharacteristic The characteristic that is the source of the event. - */ -void BLECharacteristicCallbacks::onRead(BLECharacteristic *pCharacteristic) { - ESP_LOGD(LOG_TAG, ">> onRead: default"); - ESP_LOGD(LOG_TAG, "<< onRead"); -} // onRead - - -/** - * @brief Callback function to support a write request. - * @param [in] pCharacteristic The characteristic that is the source of the event. - */ -void BLECharacteristicCallbacks::onWrite(BLECharacteristic *pCharacteristic) { - ESP_LOGD(LOG_TAG, ">> onWrite: default"); - ESP_LOGD(LOG_TAG, "<< onWrite"); -} // onWrite -#endif /* CONFIG_BT_ENABLED */ diff --git a/ESP32_BLE_Arduino/src/BLECharacteristicMap.cpp b/ESP32_BLE_Arduino/src/BLECharacteristicMap.cpp deleted file mode 100644 index f475e83..0000000 --- a/ESP32_BLE_Arduino/src/BLECharacteristicMap.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/* - * BLECharacteristicMap.cpp - * - * Created on: Jun 22, 2017 - * Author: kolban - */ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) -#include -#include -#include "BLEService.h" - -/** - * @brief Return the characteristic by UUID. - * @param [in] UUID The UUID to look up the characteristic. - * @return The characteristic. - */ -BLECharacteristic* BLECharacteristicMap::getByUUID(const char* uuid) { - return getByUUID(BLEUUID(uuid)); -} - -/** - * @brief Return the characteristic by UUID. - * @param [in] UUID The UUID to look up the characteristic. - * @return The characteristic. - */ -BLECharacteristic* BLECharacteristicMap::getByUUID(BLEUUID uuid) { - for (auto &myPair : m_uuidMap) { - if (myPair.second->getUUID().equals(uuid)) { - return myPair.second; - } - } - //return m_uuidMap.at(uuid.toString()); - return nullptr; -} // getByUUID - - -/** - * @brief Return the characteristic by handle. - * @param [in] handle The handle to look up the characteristic. - * @return The characteristic. - */ -BLECharacteristic* BLECharacteristicMap::getByHandle(uint16_t handle) { - return m_handleMap.at(handle); -} // getByHandle - - -/** - * @brief Set the characteristic by UUID. - * @param [in] uuid The uuid of the characteristic. - * @param [in] characteristic The characteristic to cache. - * @return N/A. - */ -void BLECharacteristicMap::setByUUID( - BLEUUID uuid, - BLECharacteristic *pCharacteristic) { - m_uuidMap.insert(std::pair(uuid.toString(), pCharacteristic)); -} // setByUUID - - -/** - * @brief Set the characteristic by handle. - * @param [in] handle The handle of the characteristic. - * @param [in] characteristic The characteristic to cache. - * @return N/A. - */ -void BLECharacteristicMap::setByHandle(uint16_t handle, - BLECharacteristic *characteristic) { - m_handleMap.insert(std::pair(handle, characteristic)); -} // setByHandle - - -/** - * @brief Return a string representation of the characteristic map. - * @return A string representation of the characteristic map. - */ -std::string BLECharacteristicMap::toString() { - std::stringstream stringStream; - stringStream << std::hex << std::setfill('0'); - int count=0; - for (auto &myPair: m_uuidMap) { - if (count > 0) { - stringStream << "\n"; - } - count++; - stringStream << "handle: 0x" << std::setw(2) << myPair.second->getHandle() << ", uuid: " + myPair.second->getUUID().toString(); - } - return stringStream.str(); -} // toString - - -/** - * @breif Pass the GATT server event onwards to each of the characteristics found in the mapping - * @param [in] event - * @param [in] gatts_if - * @param [in] param - */ -void BLECharacteristicMap::handleGATTServerEvent( - esp_gatts_cb_event_t event, - esp_gatt_if_t gatts_if, - esp_ble_gatts_cb_param_t *param) { - // Invoke the handler for every Service we have. - for (auto &myPair : m_uuidMap) { - myPair.second->handleGATTServerEvent(event, gatts_if, param); - } -} // handleGATTServerEvent - - -/** - * @brief Get the first characteristic in the map. - * @return The first characteristic in the map. - */ -BLECharacteristic* BLECharacteristicMap::getFirst() { - m_iterator = m_uuidMap.begin(); - if (m_iterator == m_uuidMap.end()) { - return nullptr; - } - BLECharacteristic *pRet = m_iterator->second; - m_iterator++; - return pRet; -} // getFirst - - -/** - * @brief Get the next characteristic in the map. - * @return The next characteristic in the map. - */ -BLECharacteristic* BLECharacteristicMap::getNext() { - if (m_iterator == m_uuidMap.end()) { - return nullptr; - } - BLECharacteristic *pRet = m_iterator->second; - m_iterator++; - return pRet; -} // getNext -#endif /* CONFIG_BT_ENABLED */ diff --git a/ESP32_BLE_Arduino/src/BLEClient.cpp b/ESP32_BLE_Arduino/src/BLEClient.cpp deleted file mode 100644 index a5d60cf..0000000 --- a/ESP32_BLE_Arduino/src/BLEClient.cpp +++ /dev/null @@ -1,327 +0,0 @@ -/* - * BLEDevice.cpp - * - * Created on: Mar 22, 2017 - * Author: kolban - */ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) -#include -#include -#include -#include -#include -#include "BLEClient.h" -#include "BLEUtils.h" -#include "BLEService.h" -#include "GeneralUtils.h" -#include -#include -#include - -/* - * Design - * ------ - * When we perform a searchService() requests, we are asking the BLE server to return each of the services - * that it exposes. For each service, we received an ESP_GATTC_SEARCH_RES_EVT event which contains details - * of the exposed service including its UUID. - * - * The objects we will invent for a BLEClient will be as follows: - * * BLERemoteService - A model of a remote service. - * * BLERemoteCharacteristic - A model of a remote characteristic - * * BLERemoteDescriptor - A model of a remote descriptor. - * - * Since there is a hierarchical relationship here, we will have the idea that from a BLERemoteService will own - * zero or more remote characteristics and a BLERemoteCharacteristic will own zero or more remote BLEDescriptors. - * - * We will assume that a BLERemoteService contains a map that maps BLEUUIDs to the set of owned characteristics - * and that a BLECharacteristic contains a map that maps BLEUUIDs to the set of owned descriptors. - * - * - */ -static const char* LOG_TAG = "BLEClient"; - -BLEClient::BLEClient() { - m_pClientCallbacks = nullptr; - m_conn_id = 0; - m_gattc_if = 0; - m_haveServices = false; -} // BLEClient - -/** - * @brief Connect to the partner. - * @param [in] address The address of the partner. - */ -bool BLEClient::connect(BLEAddress address) { - ESP_LOGD(LOG_TAG, ">> connect(%s)", address.toString().c_str()); -// We need the connection handle that we get from registering the application. We register the app -// and then block on its completion. When the event has arrived, we will have the handle. - m_semaphoreRegEvt.take("connect"); - esp_err_t errRc = esp_ble_gattc_app_register(0); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_ble_gattc_app_register: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return false; - } - m_semaphoreRegEvt.wait("connect"); - - m_peerAddress = address; - - m_semaphoreOpenEvt.take("connect"); - errRc = ::esp_ble_gattc_open( - getGattcIf(), - *getPeerAddress().getNative(), // address - 1 // direct connection - ); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_ble_gattc_open: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return false; - } - - uint32_t rc = m_semaphoreOpenEvt.wait("connect"); - ESP_LOGD(LOG_TAG, "<< connect(), rc=%d", rc==ESP_GATT_OK); - return rc == ESP_GATT_OK; -} // connect - - -/** - * @brief Disconnect from the peer. - * @return N/A. - */ -void BLEClient::disconnect() { - ESP_LOGD(LOG_TAG, ">> disconnect()"); - esp_err_t errRc = ::esp_ble_gattc_close(getGattcIf(), getConnId()); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_ble_gattc_close: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return; - } - m_peerAddress = BLEAddress("00:00:00:00:00:00"); - ESP_LOGD(LOG_TAG, "<< disconnect()"); -} // disconnect - - -/** - * @brief Handle GATT Client events - */ -void BLEClient::gattClientEventHandler( - esp_gattc_cb_event_t event, - esp_gatt_if_t gattc_if, - esp_ble_gattc_cb_param_t* evtParam) { - - // Execute handler code based on the type of event received. - switch(event) { - // - // ESP_GATTC_NOTIFY_EVT - // - // notify - // uint16_t conn_id - // esp_bd_addr_t remote_bda - // esp_gatt_srvc_id_t srvc_id - // esp_gatt_id_t char_id - // esp_gatt_id_t descr_id - // uint16_t value_len - // uint8_t* value - // bool is_notify - // - case ESP_GATTC_NOTIFY_EVT: { - BLERemoteService *pBLERemoteService = getService(BLEUUID(evtParam->notify.srvc_id.id.uuid)); - if (pBLERemoteService == nullptr) { - ESP_LOGE(LOG_TAG, "Could not find service with UUID %s for notification", BLEUUID(evtParam->notify.srvc_id.id.uuid).toString().c_str()); - break; - } - BLERemoteCharacteristic* pBLERemoteCharacteristic = pBLERemoteService->getCharacteristic(BLEUUID(evtParam->notify.char_id.uuid)); - if (pBLERemoteCharacteristic == nullptr) { - ESP_LOGE(LOG_TAG, "Could not find characteristic with UUID %s for notification", BLEUUID(evtParam->notify.char_id.uuid).toString().c_str()); - break; - } - if (pBLERemoteCharacteristic->m_notifyCallback != nullptr) { - pBLERemoteCharacteristic->m_notifyCallback(pBLERemoteCharacteristic, evtParam->notify.value, evtParam->notify.value_len, evtParam->notify.is_notify); - } - break; - } // ESP_GATTC_NOTIFY_EVT - - // - // ESP_GATTC_OPEN_EVT - // - // open: - // - esp_gatt_status_t status - // - uint16_t conn_id - // - esp_bd_addr_t remote_bda - // - uint16_t mtu - // - case ESP_GATTC_OPEN_EVT: { - m_conn_id = evtParam->open.conn_id; - if (m_pClientCallbacks != nullptr) { - m_pClientCallbacks->onConnect(this); - } - m_semaphoreOpenEvt.give(); - break; - } // ESP_GATTC_OPEN_EVT - - - // - // ESP_GATTC_REG_EVT - // - // reg: - // esp_gatt_status_t status - // uint16_t app_id - // - case ESP_GATTC_REG_EVT: { - m_gattc_if = gattc_if; - m_semaphoreRegEvt.give(); - break; - } // ESP_GATTC_REG_EVT - - - // - // ESP_GATTC_SEARCH_CMPL_EVT - // - // search_cmpl: - // - esp_gatt_status_t status - // - uint16_t conn_id - // - case ESP_GATTC_SEARCH_CMPL_EVT: { - m_semaphoreSearchCmplEvt.give(); - break; - } // ESP_GATTC_SEARCH_CMPL_EVT - - - // - // ESP_GATTC_SEARCH_RES_EVT - // - // search_res: - // - uint16_t conn_id - // - esp_gatt_srvc_id_t srvc_id - // - case ESP_GATTC_SEARCH_RES_EVT: { - BLEUUID uuid = BLEUUID(evtParam->search_res.srvc_id); - BLERemoteService* pRemoteService = new BLERemoteService(evtParam->search_res.srvc_id, this); - m_servicesMap.insert(std::pair(uuid.toString(), pRemoteService)); - break; - } // ESP_GATTC_SEARCH_RES_EVT - - - default: { - break; - } - } // Switch - - for (auto &myPair : m_servicesMap) { - myPair.second->gattClientEventHandler(event, gattc_if, evtParam); - } - -} // gattClientEventHandler - - -/** - * @brief Retrieve the address of the peer. - * - * Returns the address of the %BLE peer to which this client is connected. - */ -BLEAddress BLEClient::getPeerAddress() { - return m_peerAddress; -} // getAddress - - -uint16_t BLEClient::getConnId() { - return m_conn_id; -} // getConnId - - -esp_gatt_if_t BLEClient::getGattcIf() { - return m_gattc_if; -} // getGattcIf - - - -/** - * @brief Get the service object corresponding to the uuid. - * @param [in] uuid The UUID of the service being sought. - * @return A reference to the Service or nullptr if don't know about it. - */ -BLERemoteService* BLEClient::getService(const char* uuid) { - return getService(BLEUUID(uuid)); -} - - -/** - * @brief Get the service object corresponding to the uuid. - * @param [in] uuid The UUID of the service being sought. - * @return A reference to the Service or nullptr if don't know about it. - */ -BLERemoteService* BLEClient::getService(BLEUUID uuid) { -// Design -// ------ -// We wish to retrieve the service given its UUID. It is possible that we have not yet asked the -// device what services it has in which case we have nothing to match against. If we have not -// asked the device about its services, then we do that now. Once we get the results we can then -// examine the services map to see if it has the service we are looking for. - if (!m_haveServices) { - getServices(); - } - std::string v = uuid.toString(); - for (auto &myPair : m_servicesMap) { - if (myPair.first == v) { - return myPair.second; - } - } - return nullptr; -} // getService - - -/** - * @brief Ask the remote %BLE server for its services. - * A %BLE Server exposes a set of services for its partners. Here we ask the server for its set of - * services and wait until we have received them all. - * @return N/A - */ -std::map* BLEClient::getServices() { -/* - * Design - * ------ - * We invoke esp_ble_gattc_search_service. This will request a list of the service exposed by the - * peer BLE partner to be returned as events. Each event will be an an instance of ESP_GATTC_SEARCH_RES_EVT - * and will culminate with an ESP_GATTC_SEARCH_CMPL_EVT when all have been received. - */ - ESP_LOGD(LOG_TAG, ">> getServices"); - m_servicesMap.empty(); - esp_err_t errRc = esp_ble_gattc_search_service( - getGattcIf(), - getConnId(), - NULL // Filter UUID - ); - m_semaphoreSearchCmplEvt.take("getServices"); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_ble_gattc_search_service: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return &m_servicesMap; - } - m_semaphoreSearchCmplEvt.wait("getServices"); - m_haveServices = true; // Remember that we now have services. - ESP_LOGD(LOG_TAG, "<< getServices"); - return &m_servicesMap; -} // getServices - - -/** - * @brief Set the callbacks that will be invoked. - */ -void BLEClient::setClientCallbacks(BLEClientCallbacks* pClientCallbacks) { - m_pClientCallbacks = pClientCallbacks; -} // setClientCallbacks - - -/** - * @brief Return a string representation of this client. - * @return A string representation of this client. - */ -std::string BLEClient::toString() { - std::ostringstream ss; - ss << "peer address: " << m_peerAddress.toString(); - ss << "\nServices:\n"; - for (auto &myPair : m_servicesMap) { - ss << myPair.second->toString() << "\n"; - // myPair.second is the value - } - return ss.str(); -} // toString - -#endif // CONFIG_BT_ENABLED diff --git a/ESP32_BLE_Arduino/src/BLEClient.h b/ESP32_BLE_Arduino/src/BLEClient.h deleted file mode 100644 index 898f98c..0000000 --- a/ESP32_BLE_Arduino/src/BLEClient.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * BLEDevice.h - * - * Created on: Mar 22, 2017 - * Author: kolban - */ - -#ifndef MAIN_BLEDEVICE_H_ -#define MAIN_BLEDEVICE_H_ - -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) - -#include -#include -#include -#include -#include -#include "BLEService.h" -#include "BLEAddress.h" - -class BLERemoteService; -class BLEClientCallbacks; - -/** - * @brief A model of a %BLE client. - */ -class BLEClient { -public: - BLEClient(); - bool connect(BLEAddress address); - void disconnect(); - BLEAddress getPeerAddress(); - std::map* getServices(); - BLERemoteService* getService(const char* uuid); - BLERemoteService* getService(BLEUUID uuid); - void setClientCallbacks(BLEClientCallbacks *pClientCallbacks); - std::string toString(); - -private: - friend class BLEDevice; - friend class BLERemoteCharacteristic; - friend class BLERemoteService; - - void gattClientEventHandler( - esp_gattc_cb_event_t event, - esp_gatt_if_t gattc_if, - esp_ble_gattc_cb_param_t* param); - - uint16_t getConnId(); - esp_gatt_if_t getGattcIf(); - BLEAddress m_peerAddress = BLEAddress((uint8_t*)"\0\0\0\0\0\0"); - uint16_t m_conn_id; -// int m_deviceType; - esp_gatt_if_t m_gattc_if; - - BLEClientCallbacks* m_pClientCallbacks; - FreeRTOS::Semaphore m_semaphoreRegEvt = FreeRTOS::Semaphore("RegEvt"); - FreeRTOS::Semaphore m_semaphoreOpenEvt = FreeRTOS::Semaphore("OpenEvt"); - FreeRTOS::Semaphore m_semaphoreSearchCmplEvt = FreeRTOS::Semaphore("SearchCmplEvt"); - std::map m_servicesMap; - bool m_haveServices; // Have we previously obtain the set of services. -}; // class BLEDevice - - -/** - * @brief Callbacks associated with a %BLE client. - */ -class BLEClientCallbacks { -public: - virtual ~BLEClientCallbacks() {}; - virtual void onConnect(BLEClient *pClient) = 0; -}; - -#endif // CONFIG_BT_ENABLED -#endif /* MAIN_BLEDEVICE_H_ */ diff --git a/ESP32_BLE_Arduino/src/BLEDescriptor.cpp b/ESP32_BLE_Arduino/src/BLEDescriptor.cpp deleted file mode 100644 index 4a7fda6..0000000 --- a/ESP32_BLE_Arduino/src/BLEDescriptor.cpp +++ /dev/null @@ -1,278 +0,0 @@ -/* - * BLEDescriptor.cpp - * - * Created on: Jun 22, 2017 - * Author: kolban - */ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) -#include -#include -#include -#include -#include "sdkconfig.h" -#include -#include -#include "BLEService.h" -#include "BLEDescriptor.h" -#include "GeneralUtils.h" - -static const char* LOG_TAG = "BLEDescriptor"; - - -#define NULL_HANDLE (0xffff) - - -/** - * @brief BLEDescriptor constructor. - */ -BLEDescriptor::BLEDescriptor(const char* uuid) : BLEDescriptor(BLEUUID(uuid)) { -} - -/** - * @brief BLEDescriptor constructor. - */ -BLEDescriptor::BLEDescriptor(BLEUUID uuid) { - m_bleUUID = uuid; - m_value.attr_value = (uint8_t *)malloc(ESP_GATT_MAX_ATTR_LEN); // Allocate storage for the value. - m_value.attr_len = 0; - m_value.attr_max_len = ESP_GATT_MAX_ATTR_LEN; - m_handle = NULL_HANDLE; - m_pCharacteristic = nullptr; // No initial characteristic. - -} // BLEDescriptor - - -/** - * @brief BLEDescriptor destructor. - */ -BLEDescriptor::~BLEDescriptor() { - free(m_value.attr_value); -} // ~BLEDescriptor - - -/** - * @brief Execute the creation of the descriptor with the BLE runtime in ESP. - * @param [in] pCharacteristic The characteristic to which to register this descriptor. - */ -void BLEDescriptor::executeCreate(BLECharacteristic* pCharacteristic) { - ESP_LOGD(LOG_TAG, ">> executeCreate(): %s", toString().c_str()); - - if (m_handle != NULL_HANDLE) { - ESP_LOGE(LOG_TAG, "Descriptor already has a handle."); - return; - } - - m_pCharacteristic = pCharacteristic; // Save the characteristic associated with this service. - - esp_attr_control_t control; - control.auto_rsp = ESP_GATT_RSP_BY_APP; - m_semaphoreCreateEvt.take("executeCreate"); - esp_err_t errRc = ::esp_ble_gatts_add_char_descr( - pCharacteristic->getService()->getHandle(), - getUUID().getNative(), - (esp_gatt_perm_t)(ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE), - &m_value, - &control); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "<< esp_ble_gatts_add_char_descr: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return; - } - - m_semaphoreCreateEvt.wait("executeCreate"); - ESP_LOGD(LOG_TAG, "<< executeCreate"); -} // executeCreate - - -/** - * @brief Get the BLE handle for this descriptor. - * @return The handle for this descriptor. - */ -uint16_t BLEDescriptor::getHandle() { - return m_handle; -} // getHandle - - -/** - * @brief Get the length of the value of this descriptor. - * @return The length (in bytes) of the value of this descriptor. - */ -size_t BLEDescriptor::getLength() { - return m_value.attr_len; -} // getLength - - -/** - * @brief Get the UUID of the descriptor. - */ -BLEUUID BLEDescriptor::getUUID() { - return m_bleUUID; -} // getUUID - - - -/** - * @brief Get the value of this descriptor. - * @return A pointer to the value of this descriptor. - */ -uint8_t* BLEDescriptor::getValue() { - return m_value.attr_value; -} // getValue - - -/** - * @brief Handle GATT server events for the descripttor. - * @param [in] event - * @param [in] gatts_if - * @param [in] param - */ -void BLEDescriptor::handleGATTServerEvent( - esp_gatts_cb_event_t event, - esp_gatt_if_t gatts_if, - esp_ble_gatts_cb_param_t *param) { - switch(event) { - // ESP_GATTS_ADD_CHAR_DESCR_EVT - // - // add_char_descr: - // - esp_gatt_status_t status - // - uint16_t attr_handle - // - uint16_t service_handle - // - esp_bt_uuid_t char_uuid - case ESP_GATTS_ADD_CHAR_DESCR_EVT: { - /* - ESP_LOGD(LOG_TAG, "DEBUG: m_pCharacteristic: %x", (uint32_t)m_pCharacteristic); - ESP_LOGD(LOG_TAG, "DEBUG: m_bleUUID: %s, add_char_descr.char_uuid: %s, equals: %d", - m_bleUUID.toString().c_str(), - BLEUUID(param->add_char_descr.char_uuid).toString().c_str(), - m_bleUUID.equals(BLEUUID(param->add_char_descr.char_uuid))); - ESP_LOGD(LOG_TAG, "DEBUG: service->getHandle: %x, add_char_descr.service_handle: %x", - m_pCharacteristic->getService()->getHandle(), param->add_char_descr.service_handle); - ESP_LOGD(LOG_TAG, "DEBUG: service->lastCharacteristic: %x", - (uint32_t)m_pCharacteristic->getService()->getLastCreatedCharacteristic()); - */ - if (m_pCharacteristic != nullptr && - m_bleUUID.equals(BLEUUID(param->add_char_descr.char_uuid)) && - m_pCharacteristic->getService()->getHandle() == param->add_char_descr.service_handle && - m_pCharacteristic == m_pCharacteristic->getService()->getLastCreatedCharacteristic()) { - setHandle(param->add_char_descr.attr_handle); - m_semaphoreCreateEvt.give(); - } - break; - } // ESP_GATTS_ADD_CHAR_DESCR_EVT - - // ESP_GATTS_WRITE_EVT - A request to write the value of a descriptor has arrived. - // - // write: - // - uint16_t conn_id - // - uint16_t trans_id - // - esp_bd_addr_t bda - // - uint16_t handle - // - uint16_t offset - // - bool need_rsp - // - bool is_prep - // - uint16_t len - // - uint8_t *value - case ESP_GATTS_WRITE_EVT: { - if (param->write.handle == m_handle) { - setValue(param->write.value, param->write.len); - esp_gatt_rsp_t rsp; - rsp.attr_value.len = getLength(); - rsp.attr_value.handle = m_handle; - rsp.attr_value.offset = 0; - rsp.attr_value.auth_req = ESP_GATT_AUTH_REQ_NONE; - memcpy(rsp.attr_value.value, getValue(), rsp.attr_value.len); - esp_err_t errRc = ::esp_ble_gatts_send_response( - gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, &rsp); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_ble_gatts_send_response: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - } - } - break; - } // ESP_GATTS_WRITE_EVT - - // ESP_GATTS_READ_EVT - A request to read the value of a descriptor has arrived. - // - // read: - // - uint16_t conn_id - // - uint32_t trans_id - // - esp_bd_addr_t bda - // - uint16_t handle - // - uint16_t offset - // - bool is_long - // - bool need_rsp - // - case ESP_GATTS_READ_EVT: { - ESP_LOGD(LOG_TAG, "- Testing: Sought handle: 0x%.2x == descriptor handle: 0x%.2x ?", param->read.handle, m_handle); - if (param->read.handle == m_handle) { - ESP_LOGD(LOG_TAG, "Sending a response (esp_ble_gatts_send_response)"); - if (param->read.need_rsp) { - esp_gatt_rsp_t rsp; - rsp.attr_value.len = getLength(); - rsp.attr_value.handle = param->read.handle; - rsp.attr_value.offset = 0; - rsp.attr_value.auth_req = ESP_GATT_AUTH_REQ_NONE; - memcpy(rsp.attr_value.value, getValue(), rsp.attr_value.len); - esp_err_t errRc = ::esp_ble_gatts_send_response( - gatts_if, param->read.conn_id, param->read.trans_id, ESP_GATT_OK, &rsp); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_ble_gatts_send_response: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - } - } - } // ESP_GATTS_READ_EVT - break; - } // ESP_GATTS_READ_EVT - default: { - break; - } - }// switch event -} // handleGATTServerEvent - - -/** - * @brief Set the handle of this descriptor. - * Set the handle of this descriptor to be the supplied value. - * @param [in] handle The handle to be associated with this descriptor. - * @return N/A. - */ -void BLEDescriptor::setHandle(uint16_t handle) { - ESP_LOGD(LOG_TAG, ">> setHandle(0x%.2x): Setting descriptor handle to be 0x%.2x", handle, handle); - m_handle = handle; - ESP_LOGD(LOG_TAG, "<< setHandle()"); -} // setHandle - - -/** - * @brief Set the value of the descriptor. - * @param [in] data The data to set for the descriptor. - * @param [in] length The length of the data in bytes. - */ -void BLEDescriptor::setValue(uint8_t* data, size_t length) { - if (length > ESP_GATT_MAX_ATTR_LEN) { - ESP_LOGE(LOG_TAG, "Size %d too large, must be no bigger than %d", length, ESP_GATT_MAX_ATTR_LEN); - return; - } - m_value.attr_len = length; - memcpy(m_value.attr_value, data, length); -} // setValue - - -/** - * @brief Set the value of the descriptor. - * @param [in] value The value of the descriptor in string form. - */ -void BLEDescriptor::setValue(std::string value) { - setValue((uint8_t *)value.data(), value.length()); -} // setValue - - -/** - * @brief Return a string representation of the descriptor. - * @return A string representation of the descriptor. - */ -std::string BLEDescriptor::toString() { - std::stringstream stringstream; - stringstream << std::hex << std::setfill('0'); - stringstream << "UUID: " << m_bleUUID.toString() + ", handle: 0x" << std::setw(2) << m_handle; - return stringstream.str(); -} // toString -#endif /* CONFIG_BT_ENABLED */ diff --git a/ESP32_BLE_Arduino/src/BLEDescriptor.h b/ESP32_BLE_Arduino/src/BLEDescriptor.h deleted file mode 100644 index 1d32d50..0000000 --- a/ESP32_BLE_Arduino/src/BLEDescriptor.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * BLEDescriptor.h - * - * Created on: Jun 22, 2017 - * Author: kolban - */ - -#ifndef COMPONENTS_CPP_UTILS_BLEDESCRIPTOR_H_ -#define COMPONENTS_CPP_UTILS_BLEDESCRIPTOR_H_ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) -#include -#include "BLEUUID.h" -#include "BLECharacteristic.h" -#include -#include "FreeRTOS.h" - -class BLEService; -class BLECharacteristic; - -/** - * @brief A model of a %BLE descriptor. - */ -class BLEDescriptor { -public: - BLEDescriptor(const char* uuid); - BLEDescriptor(BLEUUID uuid); - virtual ~BLEDescriptor(); - - size_t getLength(); - BLEUUID getUUID(); - uint8_t* getValue(); - void handleGATTServerEvent( - esp_gatts_cb_event_t event, - esp_gatt_if_t gatts_if, - esp_ble_gatts_cb_param_t* param); - void setValue(uint8_t* data, size_t size); - void setValue(std::string value); - std::string toString(); - -private: - friend class BLEDescriptorMap; - friend class BLECharacteristic; - BLEUUID m_bleUUID; - esp_attr_value_t m_value; - uint16_t m_handle; - BLECharacteristic* m_pCharacteristic; - void executeCreate(BLECharacteristic* pCharacteristic); - uint16_t getHandle(); - void setHandle(uint16_t handle); - FreeRTOS::Semaphore m_semaphoreCreateEvt = FreeRTOS::Semaphore("CreateEvt"); -}; -#endif /* CONFIG_BT_ENABLED */ -#endif /* COMPONENTS_CPP_UTILS_BLEDESCRIPTOR_H_ */ diff --git a/ESP32_BLE_Arduino/src/BLEDescriptorMap.cpp b/ESP32_BLE_Arduino/src/BLEDescriptorMap.cpp deleted file mode 100644 index b211652..0000000 --- a/ESP32_BLE_Arduino/src/BLEDescriptorMap.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/* - * BLEDescriptorMap.cpp - * - * Created on: Jun 22, 2017 - * Author: kolban - */ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) -#include -#include -#include "BLECharacteristic.h" -#include "BLEDescriptor.h" -#include // ESP32 BLE - -/** - * @brief Return the descriptor by UUID. - * @param [in] UUID The UUID to look up the descriptor. - * @return The descriptor. If not present, then nullptr is returned. - */ -BLEDescriptor* BLEDescriptorMap::getByUUID(const char* uuid) { - return getByUUID(BLEUUID(uuid)); -} - - -/** - * @brief Return the descriptor by UUID. - * @param [in] UUID The UUID to look up the descriptor. - * @return The descriptor. If not present, then nullptr is returned. - */ -BLEDescriptor* BLEDescriptorMap::getByUUID(BLEUUID uuid) { - for (auto &myPair : m_uuidMap) { - if (myPair.second->getUUID().equals(uuid)) { - return myPair.second; - } - } - //return m_uuidMap.at(uuid.toString()); - return nullptr; -} // getByUUID - - -/** - * @brief Return the descriptor by handle. - * @param [in] handle The handle to look up the descriptor. - * @return The descriptor. - */ -BLEDescriptor* BLEDescriptorMap::getByHandle(uint16_t handle) { - return m_handleMap.at(handle); -} // getByHandle - - -/** - * @brief Set the descriptor by UUID. - * @param [in] uuid The uuid of the descriptor. - * @param [in] characteristic The descriptor to cache. - * @return N/A. - */ -void BLEDescriptorMap::setByUUID(const char* uuid, BLEDescriptor *pDescriptor){ - m_uuidMap.insert(std::pair(uuid, pDescriptor)); -} // setByUUID - - - -/** - * @brief Set the descriptor by UUID. - * @param [in] uuid The uuid of the descriptor. - * @param [in] characteristic The descriptor to cache. - * @return N/A. - */ -void BLEDescriptorMap::setByUUID(BLEUUID uuid, BLEDescriptor *pDescriptor) { - m_uuidMap.insert(std::pair(uuid.toString(), pDescriptor)); -} // setByUUID - - -/** - * @brief Set the descriptor by handle. - * @param [in] handle The handle of the descriptor. - * @param [in] descriptor The descriptor to cache. - * @return N/A. - */ -void BLEDescriptorMap::setByHandle(uint16_t handle, - BLEDescriptor *pDescriptor) { - m_handleMap.insert(std::pair(handle, pDescriptor)); -} // setByHandle - - -/** - * @brief Return a string representation of the descriptor map. - * @return A string representation of the descriptor map. - */ -std::string BLEDescriptorMap::toString() { - std::stringstream stringStream; - stringStream << std::hex << std::setfill('0'); - int count=0; - for (auto &myPair: m_uuidMap) { - if (count > 0) { - stringStream << "\n"; - } - count++; - stringStream << "handle: 0x" << std::setw(2) << myPair.second->getHandle() << ", uuid: " + myPair.second->getUUID().toString(); - } - return stringStream.str(); -} // toString - - -/** - * @breif Pass the GATT server event onwards to each of the descriptors found in the mapping - * @param [in] event - * @param [in] gatts_if - * @param [in] param - */ -void BLEDescriptorMap::handleGATTServerEvent( - esp_gatts_cb_event_t event, - esp_gatt_if_t gatts_if, - esp_ble_gatts_cb_param_t *param) { - // Invoke the handler for every descriptor we have. - for (auto &myPair : m_uuidMap) { - myPair.second->handleGATTServerEvent(event, gatts_if, param); - } -} // handleGATTServerEvent - - -/** - * @brief Get the first descriptor in the map. - * @return The first descriptor in the map. - */ -BLEDescriptor* BLEDescriptorMap::getFirst() { - m_iterator = m_uuidMap.begin(); - if (m_iterator == m_uuidMap.end()) { - return nullptr; - } - BLEDescriptor *pRet = m_iterator->second; - m_iterator++; - return pRet; -} // getFirst - - -/** - * @brief Get the next descriptor in the map. - * @return The next descriptor in the map. - */ -BLEDescriptor* BLEDescriptorMap::getNext() { - if (m_iterator == m_uuidMap.end()) { - return nullptr; - } - BLEDescriptor *pRet = m_iterator->second; - m_iterator++; - return pRet; -} // getNext -#endif /* CONFIG_BT_ENABLED */ diff --git a/ESP32_BLE_Arduino/src/BLEDevice.cpp b/ESP32_BLE_Arduino/src/BLEDevice.cpp deleted file mode 100644 index 04cae14..0000000 --- a/ESP32_BLE_Arduino/src/BLEDevice.cpp +++ /dev/null @@ -1,222 +0,0 @@ -/* - * BLE.cpp - * - * Created on: Mar 16, 2017 - * Author: kolban - */ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) -#include -#include -#include -#include -#include -#include -#include // ESP32 BLE -#include // ESP32 BLE -#include // ESP32 BLE -// ESP32 BLE -#include // ESP32 BLE -#include // ESP32 ESP-IDF -#include // ESP32 ESP-IDF -#include // Part of C++ STL -#include -#include - -#include "BLEDevice.h" -#include "BLEClient.h" -#include "BLEUtils.h" -#include "GeneralUtils.h" - -static const char* LOG_TAG = "BLEDevice"; - -BLEServer *BLEDevice::m_bleServer = nullptr; -BLEScan *BLEDevice::m_pScan = nullptr; -BLEClient *BLEDevice::m_pClient = nullptr; - -#include - - -BLEClient* BLEDevice::createClient() { - m_pClient = new BLEClient(); - return m_pClient; -} // createClient - - -/** - * @brief Handle GATT server events. - * - * @param [in] event - * @param [in] gatts_if - * @param [in] param - */ -void BLEDevice::gattServerEventHandler( - esp_gatts_cb_event_t event, - esp_gatt_if_t gatts_if, - esp_ble_gatts_cb_param_t *param -) { - ESP_LOGD(LOG_TAG, "gattServerEventHandler [esp_gatt_if: %d] ... %s", - gatts_if, - BLEUtils::gattServerEventTypeToString(event).c_str()); - BLEUtils::dumpGattServerEvent(event, gatts_if, param); - if (BLEDevice::m_bleServer != nullptr) { - BLEDevice::m_bleServer->handleGATTServerEvent(event, gatts_if, param); - } -} // gattServerEventHandler - - -/** - * @brief Handle GATT client events. - * - * Handler for the GATT client events. - * * `ESP_GATTC_OPEN_EVT` – Invoked when a connection is opened. - * * `ESP_GATTC_PREP_WRITE_EVT` – Response to write a characteristic. - * * `ESP_GATTC_READ_CHAR_EVT` – Response to read a characteristic. - * * `ESP_GATTC_REG_EVT` – Invoked when a GATT client has been registered. - * - * @param [in] event - * @param [in] gattc_if - * @param [in] param - */ -void BLEDevice::gattClientEventHandler( - esp_gattc_cb_event_t event, - esp_gatt_if_t gattc_if, - esp_ble_gattc_cb_param_t *param) { - - ESP_LOGD(LOG_TAG, "gattClientEventHandler [esp_gatt_if: %d] ... %s", - gattc_if, BLEUtils::gattClientEventTypeToString(event).c_str()); - BLEUtils::dumpGattClientEvent(event, gattc_if, param); - - switch(event) { - default: { - break; - } - } // switch - - // If we have a client registered, call it. - if (BLEDevice::m_pClient != nullptr) { - BLEDevice::m_pClient->gattClientEventHandler(event, gattc_if, param); - } - -} // gattClientEventHandler - - -/** - * @brief Handle GAP events. - */ -void BLEDevice::gapEventHandler( - esp_gap_ble_cb_event_t event, - esp_ble_gap_cb_param_t *param) { - - BLEUtils::dumpGapEvent(event, param); - - switch(event) { - case ESP_GAP_BLE_SEC_REQ_EVT: { - esp_err_t errRc = ::esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, true); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_ble_gap_security_rsp: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - } - break; - } - - default: { - break; - } - } // switch - - if (BLEDevice::m_bleServer != nullptr) { - BLEDevice::m_bleServer->handleGAPEvent(event, param); - } - - if (BLEDevice::m_pScan != nullptr) { - BLEDevice::getScan()->gapEventHandler(event, param); - } -} // gapEventHandler - - -/** - * @brief Initialize the %BLE environment. - * @param deviceName The device name of the device. - */ -void BLEDevice::init(std::string deviceName) { - esp_err_t errRc = ::nvs_flash_init(); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "nvs_flash_init: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return; - } - - esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); - errRc = esp_bt_controller_init(&bt_cfg); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_bt_controller_init: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return; - } - - errRc = esp_bt_controller_enable(ESP_BT_MODE_BTDM); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_bt_controller_enable: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return; - } - - errRc = esp_bluedroid_init(); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_bluedroid_init: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return; - } - - errRc = esp_bluedroid_enable(); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_bluedroid_enable: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return; - } - - errRc = esp_ble_gap_register_callback(BLEDevice::gapEventHandler); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_ble_gap_register_callback: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return; - } - - errRc = esp_ble_gattc_register_callback(BLEDevice::gattClientEventHandler); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_ble_gattc_register_callback: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return; - } - - errRc = esp_ble_gatts_register_callback(BLEDevice::gattServerEventHandler); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_ble_gatts_register_callback: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return; - } - - errRc = ::esp_ble_gap_set_device_name(deviceName.c_str()); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_ble_gap_set_device_name: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return; - }; - - esp_ble_io_cap_t iocap = ESP_IO_CAP_NONE; - errRc = ::esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(uint8_t)); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_ble_gap_set_security_param: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return; - }; - - vTaskDelay(200/portTICK_PERIOD_MS); // Delay for 200 msecs as a workaround to an apparent Arduino environment issue. -} // init - - - -/** - * @brief Retrieve the Scan object that we use for scanning. - * @return The scanning object reference. - */ -BLEScan* BLEDevice::getScan() { - if (m_pScan == nullptr) { - m_pScan = new BLEScan(); - } - return m_pScan; -} // getScan - - - -#endif // CONFIG_BT_ENABLED diff --git a/ESP32_BLE_Arduino/src/BLEDevice.h b/ESP32_BLE_Arduino/src/BLEDevice.h deleted file mode 100644 index 9d767c1..0000000 --- a/ESP32_BLE_Arduino/src/BLEDevice.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * BLEDevice.h - * - * Created on: Mar 16, 2017 - * Author: kolban - */ - -#ifndef MAIN_BLEDevice_H_ -#define MAIN_BLEDevice_H_ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) -#include // ESP32 BLE -#include // ESP32 BLE -#include // Part of C++ STL -#include - -#include "BLEServer.h" -#include "BLEClient.h" -#include "BLEUtils.h" -#include "BLEScan.h" -#include "BLEAddress.h" -/** - * @brief %BLE functions. - */ -class BLEDevice { -public: - static void dumpDevices(); - static BLEClient *createClient(); - - static void init(std::string deviceName); - //static void scan(int duration, esp_ble_scan_type_t scan_type = BLE_SCAN_TYPE_PASSIVE); - static BLEScan *getScan(); - static BLEServer *m_bleServer; - static BLEScan *m_pScan; - static BLEClient *m_pClient; - -private: - static esp_gatt_if_t getGattcIF(); - - static void gattClientEventHandler( - esp_gattc_cb_event_t event, - esp_gatt_if_t gattc_if, - esp_ble_gattc_cb_param_t *param); - static void gattServerEventHandler( - esp_gatts_cb_event_t event, - esp_gatt_if_t gatts_if, - esp_ble_gatts_cb_param_t *param); - static void gapEventHandler( - esp_gap_ble_cb_event_t event, - esp_ble_gap_cb_param_t *param); -}; // class BLE - -#endif // CONFIG_BT_ENABLED -#endif /* MAIN_BLEDevice_H_ */ diff --git a/ESP32_BLE_Arduino/src/BLERemoteCharacteristic.cpp b/ESP32_BLE_Arduino/src/BLERemoteCharacteristic.cpp deleted file mode 100644 index 5227bf6..0000000 --- a/ESP32_BLE_Arduino/src/BLERemoteCharacteristic.cpp +++ /dev/null @@ -1,336 +0,0 @@ -/* - * BLERemoteCharacteristic.cpp - * - * Created on: Jul 8, 2017 - * Author: kolban - */ - -#include "BLERemoteCharacteristic.h" - -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) - -#include -#include -#include - -#include -#include "BLEUtils.h" -#include "GeneralUtils.h" - - -static const char* LOG_TAG = "BLERemoteCharacteristic"; - -BLERemoteCharacteristic::BLERemoteCharacteristic( - esp_gatt_id_t charId, - esp_gatt_char_prop_t charProp, - BLERemoteService* pRemoteService) { - m_charId = charId; - m_charProp = charProp; - m_pRemoteService = pRemoteService; - m_notifyCallback = nullptr; -} // BLERemoteCharacteristic - - -static bool compareSrvcId(esp_gatt_srvc_id_t id1, esp_gatt_srvc_id_t id2) { - if (id1.id.inst_id != id2.id.inst_id) { - return false; - } - if (!BLEUUID(id1.id.uuid).equals(BLEUUID(id2.id.uuid))) { - return false; - } - return true; -} // compareSrvcId - - -static bool compareGattId(esp_gatt_id_t id1, esp_gatt_id_t id2) { - if (id1.inst_id != id2.inst_id) { - return false; - } - if (!BLEUUID(id1.uuid).equals(BLEUUID(id2.uuid))) { - return false; - } - return true; -} // compareCharId - - -/** - * @brief Handle GATT Client events. - * When an event arrives for a GATT client we give this characteristic the opportunity to - * take a look at it to see if there is interest in it. - * @param [in] event The type of event. - * @param [in] gattc_if The interface on which the event was received. - * @param [in] evtParam Payload data for the event. - * @returns N/A - */ -void BLERemoteCharacteristic::gattClientEventHandler( - esp_gattc_cb_event_t event, - esp_gatt_if_t gattc_if, - esp_ble_gattc_cb_param_t* evtParam) { - switch(event) { - // - // ESP_GATTC_READ_CHAR_EVT - // This event indicates that the server has responded to the read request. - // - // read: - // esp_gatt_status_t status - // uint16_t conn_id - // esp_gatt_srvc_id_t srvc_id - // esp_gatt_id_t char_id - // esp_gatt_id_t descr_id - // uint8_t* value - // uint16_t value_type - // uint16_t value_len - case ESP_GATTC_READ_CHAR_EVT: { - if (compareSrvcId(evtParam->read.srvc_id, *m_pRemoteService->getSrvcId()) == false) { - break; - } - - if (evtParam->read.conn_id != m_pRemoteService->getClient()->getConnId()) { - break; - } - - if (compareGattId(evtParam->read.char_id, m_charId) == false) { - break; - } - - if (evtParam->read.status == ESP_GATT_OK) { - m_value = std::string((char*)evtParam->read.value, evtParam->read.value_len); - } else { - m_value = ""; - } - - m_semaphoreReadCharEvt.give(); - break; - } // ESP_GATTC_READ_CHAR_EVT - - - // - // ESP_GATTC_REG_FOR_NOTIFY_EVT - // - // reg_for_notify: - // - esp_gatt_status_t status - // - esp_gatt_srvc_id_t srvc_id - // - esp_gatt_id_t char_id - case ESP_GATTC_REG_FOR_NOTIFY_EVT: { - if (compareSrvcId(evtParam->reg_for_notify.srvc_id, *m_pRemoteService->getSrvcId()) == false) { - break; - } - if (compareGattId(evtParam->reg_for_notify.char_id, m_charId) == false) { - break; - } - m_semaphoreRegForNotifyEvt.give(); - break; - } // ESP_GATTC_REG_FOR_NOTIFY_EVT - - - // - // ESP_GATTC_WRITE_CHAR_EVT - // - // write: - // esp_gatt_status_t status - // uint16_t conn_id - // esp_gatt_srvc_id_t srvc_id - // esp_gatt_id_t char_id - // esp_gatt_id_t descr_id - case ESP_GATTC_WRITE_CHAR_EVT: { - if (compareSrvcId(evtParam->write.srvc_id, *m_pRemoteService->getSrvcId()) == false) { - break; - } - if (evtParam->write.conn_id != m_pRemoteService->getClient()->getConnId()) { - break; - } - if (compareGattId(evtParam->write.char_id, m_charId) == false) { - break; - } - m_semaphoreWriteCharEvt.give(); - break; - } // ESP_GATTC_WRITE_CHAR_EVT - - - default: { - break; - } - } -}; // gattClientEventHandler - - -BLEUUID BLERemoteCharacteristic::getUUID() { - return BLEUUID(m_charId.uuid); -} - -/** - * @brief Read an unsigned 16 bit value - * @return The unsigned 16 bit value. - */ -uint16_t BLERemoteCharacteristic::readUInt16(void) { - std::string value = readValue(); - if (value.length() >= 2) { - return *(uint16_t*)(value.data()); - } - return 0; -} // readUInt16 - - -/** - * @brief Read an unsigned 32 bit value. - * @return the unsigned 32 bit value. - */ -uint32_t BLERemoteCharacteristic::readUInt32(void) { - std::string value = readValue(); - if (value.length() >= 4) { - return *(uint32_t*)(value.data()); - } - return 0; -} // readUInt32 - - -/** - * @brief Read a byte value - * @return The value as a byte - */ -uint8_t BLERemoteCharacteristic::readUInt8(void) { - std::string value = readValue(); - if (value.length() >= 1) { - return (uint8_t)value[0]; - } - return 0; -} // readUInt8 - - -/** - * @brief Read the value of the remote characteristic. - * @return The value of the remote characteristic. - */ -std::string BLERemoteCharacteristic::readValue() { - ESP_LOGD(LOG_TAG, ">> readValue()"); - - m_semaphoreReadCharEvt.take("readValue"); - - // Ask the BLE subsystem to retrieve the value for the remote hosted characteristic. - esp_err_t errRc = ::esp_ble_gattc_read_char( - m_pRemoteService->getClient()->getGattcIf(), - m_pRemoteService->getClient()->getConnId(), - m_pRemoteService->getSrvcId(), - &m_charId, - ESP_GATT_AUTH_REQ_NONE); - - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_ble_gattc_read_char: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return ""; - } - - // Block waiting for the event that indicates that the read has completed. When it has, the std::string found - // in m_value will contain our data. - m_semaphoreReadCharEvt.wait("readValue"); - - ESP_LOGD(LOG_TAG, "<< readValue()"); - return m_value; -} // readValue - - -/** - * @brief Register for notifications. - * @param [in] notifyCallback A callback to be invoked for a notification. - * @return N/A. - */ -void BLERemoteCharacteristic::registerForNotify( - void (*notifyCallback)( - BLERemoteCharacteristic* pBLERemoteCharacteristic, - uint8_t* pData, - size_t length, - bool isNotify)) { - ESP_LOGD(LOG_TAG, ">> registerForNotify()"); - - m_notifyCallback = notifyCallback; // Save the notification callback. - - m_semaphoreRegForNotifyEvt.take("registerForNotify"); - - esp_err_t errRc = ::esp_ble_gattc_register_for_notify( - m_pRemoteService->getClient()->getGattcIf(), - *m_pRemoteService->getClient()->getPeerAddress().getNative(), - m_pRemoteService->getSrvcId(), - &m_charId); - - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_ble_gattc_register_for_notify: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return; - } - - m_semaphoreRegForNotifyEvt.wait("registerForNotify"); - - ESP_LOGD(LOG_TAG, "<< registerForNotify()"); -} // registerForNotify - - -/** - * @brief Convert a BLERemoteCharacteristic to a string representation; - * @return a String representation. - */ -std::string BLERemoteCharacteristic::toString() { - std::ostringstream ss; - ss << "Characteristic: uuid: " << BLEUUID(m_charId.uuid).toString() << - ", props: " << BLEUtils::characteristicPropertiesToString(m_charProp) << - ", inst_id: " << (int)m_charId.inst_id; - return ss.str(); -} // toString - - -/** - * @brief Write the new value for the characteristic. - * @param [in] newValue The new value to write. - * @param [in] response Do we expect a response? - * @return N/A. - */ -void BLERemoteCharacteristic::writeValue(std::string newValue, bool response) { - ESP_LOGD(LOG_TAG, ">> writeValue(), length: %d", newValue.length()); - - m_semaphoreWriteCharEvt.take("writeValue"); - - esp_err_t errRc = ::esp_ble_gattc_write_char( - m_pRemoteService->getClient()->getGattcIf(), - m_pRemoteService->getClient()->getConnId(), - m_pRemoteService->getSrvcId(), - &m_charId, - newValue.length(), - (uint8_t*)newValue.data(), - response?ESP_GATT_WRITE_TYPE_RSP:ESP_GATT_WRITE_TYPE_NO_RSP, - ESP_GATT_AUTH_REQ_NONE - ); - - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_ble_gattc_write_char: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return; - } - - m_semaphoreWriteCharEvt.wait("writeValue"); - - ESP_LOGD(LOG_TAG, "<< writeValue"); -} // writeValue - - -/** - * @brief Write the new value for the characteristic. - * - * This is a convenience function. Many BLE characteristics are a single byte of data. - * @param [in] newValue The new byte value to write. - * @param [in] response Whether we require a response from the write. - * @return N/A. - */ -void BLERemoteCharacteristic::writeValue(uint8_t newValue, bool response) { - writeValue(std::string(reinterpret_cast(&newValue), 1), response); -} // writeValue - - -/** - * @brief Write the new value for the characteristic from a data buffer. - * @param [in] data A pointer to a data buffer. - * @param [in] length The length of the data in the data buffer. - * @param [in] response Whether we require a response from the write. - */ -void BLERemoteCharacteristic::writeValue(uint8_t* data, size_t length, bool response) { - writeValue(std::string((char *)data, length), response); -} // writeValue - - -#endif /* CONFIG_BT_ENABLED */ diff --git a/ESP32_BLE_Arduino/src/BLERemoteCharacteristic.h b/ESP32_BLE_Arduino/src/BLERemoteCharacteristic.h deleted file mode 100644 index b5b22b6..0000000 --- a/ESP32_BLE_Arduino/src/BLERemoteCharacteristic.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * BLERemoteCharacteristic.h - * - * Created on: Jul 8, 2017 - * Author: kolban - */ - -#ifndef COMPONENTS_CPP_UTILS_BLEREMOTECHARACTERISTIC_H_ -#define COMPONENTS_CPP_UTILS_BLEREMOTECHARACTERISTIC_H_ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) - -#include - -#include - -#include "BLERemoteService.h" -#include "BLEUUID.h" -#include "FreeRTOS.h" - -class BLERemoteService; - -/** - * @brief A model of a remote %BLE characteristic. - */ -class BLERemoteCharacteristic { -public: - BLERemoteCharacteristic(esp_gatt_id_t charId, esp_gatt_char_prop_t charProp, BLERemoteService* pRemoteService); - - // Public member functions - BLEUUID getUUID(); - std::string readValue(void); - uint8_t readUInt8(void); - uint16_t readUInt16(void); - uint32_t readUInt32(void); - void registerForNotify(void (*notifyCallback)(BLERemoteCharacteristic *pBLERemoteCharacteristic, uint8_t *pData, size_t length, bool isNotify)); - void writeValue(uint8_t* data, size_t length, bool response = false); - void writeValue(std::string newValue, bool response = false); - void writeValue(uint8_t newValue, bool response = false); - std::string toString(void); - -private: - friend class BLEClient; - friend class BLERemoteService; - - // Private member functions - void gattClientEventHandler( - esp_gattc_cb_event_t event, - esp_gatt_if_t gattc_if, - esp_ble_gattc_cb_param_t *evtParam); - - // Private properties - esp_gatt_id_t m_charId; - esp_gatt_char_prop_t m_charProp; - BLERemoteService* m_pRemoteService; - FreeRTOS::Semaphore m_semaphoreReadCharEvt = FreeRTOS::Semaphore("ReadCharEvt"); - FreeRTOS::Semaphore m_semaphoreRegForNotifyEvt = FreeRTOS::Semaphore("RegForNotifyEvt"); - FreeRTOS::Semaphore m_semaphoreWriteCharEvt = FreeRTOS::Semaphore("WriteCharEvt"); - std::string m_value; - void (*m_notifyCallback)(BLERemoteCharacteristic *pBLERemoteCharacteristic, uint8_t *pData, size_t length, bool isNotify); -}; // BLERemoteCharacteristic -#endif /* CONFIG_BT_ENABLED */ -#endif /* COMPONENTS_CPP_UTILS_BLEREMOTECHARACTERISTIC_H_ */ diff --git a/ESP32_BLE_Arduino/src/BLERemoteDescriptor.cpp b/ESP32_BLE_Arduino/src/BLERemoteDescriptor.cpp deleted file mode 100644 index 2be312a..0000000 --- a/ESP32_BLE_Arduino/src/BLERemoteDescriptor.cpp +++ /dev/null @@ -1,11 +0,0 @@ -/* - * BLERemoteDescriptor.cpp - * - * Created on: Jul 8, 2017 - * Author: kolban - */ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) -#include "BLERemoteDescriptor.h" - -#endif /* CONFIG_BT_ENABLED */ diff --git a/ESP32_BLE_Arduino/src/BLERemoteDescriptor.h b/ESP32_BLE_Arduino/src/BLERemoteDescriptor.h deleted file mode 100644 index a8d944d..0000000 --- a/ESP32_BLE_Arduino/src/BLERemoteDescriptor.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * BLERemoteDescriptor.h - * - * Created on: Jul 8, 2017 - * Author: kolban - */ - -#ifndef COMPONENTS_CPP_UTILS_BLEREMOTEDESCRIPTOR_H_ -#define COMPONENTS_CPP_UTILS_BLEREMOTEDESCRIPTOR_H_ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) - -/** - * @brief A model of remote %BLE descriptor. - */ -class BLERemoteDescriptor { -public: -}; -#endif /* CONFIG_BT_ENABLED */ -#endif /* COMPONENTS_CPP_UTILS_BLEREMOTEDESCRIPTOR_H_ */ diff --git a/ESP32_BLE_Arduino/src/BLERemoteService.cpp b/ESP32_BLE_Arduino/src/BLERemoteService.cpp deleted file mode 100644 index a29a758..0000000 --- a/ESP32_BLE_Arduino/src/BLERemoteService.cpp +++ /dev/null @@ -1,220 +0,0 @@ -/* - * BLERemoteService.cpp - * - * Created on: Jul 8, 2017 - * Author: kolban - */ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) - -#include -#include "BLERemoteService.h" -#include "BLEUtils.h" -#include "GeneralUtils.h" -#include -#include - -static const char* LOG_TAG = "BLERemoteService"; - -BLERemoteService::BLERemoteService( - esp_gatt_srvc_id_t srvcId, - BLEClient *pClient) { - - m_srvcId = srvcId; - m_pClient = pClient; - m_uuid = BLEUUID(m_srvcId); - m_haveCharacteristics = false; -} - - -BLERemoteService::~BLERemoteService() { - removeCharacteristics(); -} - -static bool compareSrvcId(esp_gatt_srvc_id_t id1, esp_gatt_srvc_id_t id2) { - if (id1.id.inst_id != id2.id.inst_id) { - return false; - } - if (!BLEUUID(id1.id.uuid).equals(BLEUUID(id2.id.uuid))) { - return false; - } - return true; -} // compareSrvcId - - -/** - * @brief Handle GATT Client events - */ -void BLERemoteService::gattClientEventHandler( - esp_gattc_cb_event_t event, - esp_gatt_if_t gattc_if, - esp_ble_gattc_cb_param_t *evtParam) { - switch(event) { - // - // ESP_GATTC_GET_CHAR_EVT - // - // get_char: - // - esp_gatt_status_t status - // - uin1t6_t conn_id - // - esp_gatt_srvc_id_t srvc_id - // - esp_gatt_id_t char_id - // - esp_gatt_char_prop_t char_prop - // - case ESP_GATTC_GET_CHAR_EVT: { - // Is this event for this service? If yes, then the local srvc_id and the event srvc_id will be - // the same. - if (compareSrvcId(m_srvcId, evtParam->get_char.srvc_id) == false) { - break; - } - - // If the status is NOT OK then we have a problem and continue. - if (evtParam->get_char.status != ESP_GATT_OK) { - m_semaphoreGetCharEvt.give(); - break; - } - - // This is an indication that we now have the characteristic details for a characteristic owned - // by this service so remember it. - m_characteristicMap.insert(std::pair( - BLEUUID(evtParam->get_char.char_id.uuid).toString(), - new BLERemoteCharacteristic(evtParam->get_char.char_id, evtParam->get_char.char_prop, this) )); - - - // Now that we have received a characteristic, lets ask for the next one. - esp_err_t errRc = ::esp_ble_gattc_get_characteristic( - m_pClient->getGattcIf(), - m_pClient->getConnId(), - &m_srvcId, - &evtParam->get_char.char_id); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_ble_gattc_get_characteristic: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - break; - } - - //m_semaphoreGetCharEvt.give(); - break; - } // ESP_GATTC_GET_CHAR_EVT - - default: { - break; - } - } // switch - - // Send the event to each of the characteristics owned by this service. - for (auto &myPair : m_characteristicMap) { - myPair.second->gattClientEventHandler(event, gattc_if, evtParam); - } -} // gattClientEventHandler - - -/** - * @brief Get the characteristic object for the UUID. - * @param [in] uuid Characteristic uuid. - * @return Reference to the characteristic object. - */ -BLERemoteCharacteristic* BLERemoteService::getCharacteristic(const char* uuid) { - return getCharacteristic(BLEUUID(uuid)); -} - - -/** - * @brief Get the characteristic object for the UUID. - * @param [in] uuid Characteristic uuid. - * @return Reference to the characteristic object. - */ -BLERemoteCharacteristic* BLERemoteService::getCharacteristic(BLEUUID uuid) { -// Design -// ------ -// We wish to retrieve the characteristic given its UUID. It is possible that we have not yet asked the -// device what characteristics it has in which case we have nothing to match against. If we have not -// asked the device about its characteristics, then we do that now. Once we get the results we can then -// examine the characteristics map to see if it has the characteristic we are looking for. - if (!m_haveCharacteristics) { - getCharacteristics(); - } - std::string v = uuid.toString(); - for (auto &myPair : m_characteristicMap) { - if (myPair.first == v) { - return myPair.second; - } - } - return nullptr; -} // getCharacteristic - - -/** - * @brief Retrieve all the characteristics for this service. - * @return N/A - */ -void BLERemoteService::getCharacteristics() { - - ESP_LOGD(LOG_TAG, ">> getCharacteristics() for service: %s", getUUID().toString().c_str()); - - removeCharacteristics(); // Forget any previous characteristics. - - m_semaphoreGetCharEvt.take("getCharacteristics"); - - esp_err_t errRc = ::esp_ble_gattc_get_characteristic( - m_pClient->getGattcIf(), - m_pClient->getConnId(), - &m_srvcId, - nullptr); - - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_ble_gattc_get_characteristic: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return; - } - - m_semaphoreGetCharEvt.wait("getCharacteristics"); // Wait for the characteristics to become available. - - m_haveCharacteristics = true; // Remember that we have received the characteristics. - ESP_LOGD(LOG_TAG, "<< getCharacteristics()"); -} // getCharacteristics - - -BLEClient* BLERemoteService::getClient() { - return m_pClient; -} - -esp_gatt_srvc_id_t* BLERemoteService::getSrvcId() { - return &m_srvcId; -} - -BLEUUID BLERemoteService::getUUID() { - return m_uuid; -} - - -/** - * @brief Delete the characteristics in the characteristics map. - * We maintain a map called m_characteristicsMap that contains pointers to BLERemoteCharacteristic - * object references. Since we allocated these in this class, we are also responsible for deleteing - * them. This method does just that. - * @return N/A. - */ -void BLERemoteService::removeCharacteristics() { - for (auto &myPair : m_characteristicMap) { - delete myPair.second; - } - m_characteristicMap.empty(); -} // removeCharacteristics - - - -/** - * @brief Create a string representation of this remote service. - * @return A string representation of this remote service. - */ -std::string BLERemoteService::toString() { - std::ostringstream ss; - ss << "Service: uuid: " + m_uuid.toString(); - for (auto &myPair : m_characteristicMap) { - ss << "\n" << myPair.second->toString(); - // myPair.second is the value - } - return ss.str(); -} // toString - - - -#endif /* CONFIG_BT_ENABLED */ diff --git a/ESP32_BLE_Arduino/src/BLERemoteService.h b/ESP32_BLE_Arduino/src/BLERemoteService.h deleted file mode 100644 index 4393fbc..0000000 --- a/ESP32_BLE_Arduino/src/BLERemoteService.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * BLERemoteService.h - * - * Created on: Jul 8, 2017 - * Author: kolban - */ - -#ifndef COMPONENTS_CPP_UTILS_BLEREMOTESERVICE_H_ -#define COMPONENTS_CPP_UTILS_BLEREMOTESERVICE_H_ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) - -#include - -#include "BLEClient.h" -#include "BLERemoteCharacteristic.h" -#include "BLEUUID.h" -#include "FreeRTOS.h" - -class BLEClient; -class BLERemoteCharacteristic; - - -/** - * @brief A model of a remote %BLE service. - */ -class BLERemoteService { -public: - BLERemoteService(esp_gatt_srvc_id_t srvcId, BLEClient* pClient); - virtual ~BLERemoteService(); - - // Public methods - BLERemoteCharacteristic* getCharacteristic(const char* uuid); - BLERemoteCharacteristic* getCharacteristic(BLEUUID uuid); - void getCharacteristics(void); - BLEClient* getClient(void); - BLEUUID getUUID(void); - std::string toString(void); - -private: - // Friends - friend class BLEClient; - friend class BLERemoteCharacteristic; - - // Private methods - esp_gatt_srvc_id_t* getSrvcId(void); - void gattClientEventHandler( - esp_gattc_cb_event_t event, - esp_gatt_if_t gattc_if, - esp_ble_gattc_cb_param_t* evtParam); - void removeCharacteristics(); - - // Properties - std::map m_characteristicMap; - bool m_haveCharacteristics; // Have we previously obtained the characteristics. - BLEClient* m_pClient; - FreeRTOS::Semaphore m_semaphoreGetCharEvt = FreeRTOS::Semaphore("GetCharEvt"); - esp_gatt_srvc_id_t m_srvcId; - BLEUUID m_uuid; -}; // BLERemoteService - -#endif /* CONFIG_BT_ENABLED */ -#endif /* COMPONENTS_CPP_UTILS_BLEREMOTESERVICE_H_ */ diff --git a/ESP32_BLE_Arduino/src/BLEScan.cpp b/ESP32_BLE_Arduino/src/BLEScan.cpp deleted file mode 100644 index 9fdcffd..0000000 --- a/ESP32_BLE_Arduino/src/BLEScan.cpp +++ /dev/null @@ -1,276 +0,0 @@ -/* - * BLEScan.cpp - * - * Created on: Jul 1, 2017 - * Author: kolban - */ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) - - -#include -#include - -#include - -#include "BLEAdvertisedDevice.h" -#include "BLEScan.h" -#include "BLEUtils.h" -#include "GeneralUtils.h" - -static const char* LOG_TAG = "BLEScan"; - - -BLEScan::BLEScan() { - m_scan_params.scan_type = BLE_SCAN_TYPE_PASSIVE; // Default is a passive scan. - m_scan_params.own_addr_type = BLE_ADDR_TYPE_PUBLIC; - m_scan_params.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL; - setInterval(100); - setWindow(100); - m_pAdvertisedDeviceCallbacks = nullptr; - m_stopped = true; -} // BLEScan - - - -/** - * @brief Clear the history of previously detected advertised devices. - * @return N/A - */ -/* -void BLEScan::clearAdvertisedDevices() { - for (int i=0; iscan_rst.search_evt) { - case ESP_GAP_SEARCH_INQ_CMPL_EVT: { - m_stopped = true; - m_semaphoreScanEnd.give(); - break; - } // ESP_GAP_SEARCH_INQ_CMPL_EVT - - case ESP_GAP_SEARCH_INQ_RES_EVT: { - if (m_stopped) { // If we are not scanning, nothing to do with the extra results. - break; - } - -// Examine our list of previously scanned addresses and, if we found this one already, -// ignore it. - BLEAddress advertisedAddress(param->scan_rst.bda); - bool found = false; - /* - for (int i=0; igetAddress().equals(advertisedAddress)) { - found = true; - break; - } - } - */ - for (int i=0; iscan_rst.rssi); - advertisedDevice.setAdFlag(param->scan_rst.flag); - advertisedDevice.parseAdvertisement((uint8_t*)param->scan_rst.ble_adv); - advertisedDevice.setScan(this); - - //m_vectorAvdertisedDevices.push_back(pAdvertisedDevice); - if (m_pAdvertisedDeviceCallbacks) { - m_pAdvertisedDeviceCallbacks->onResult(advertisedDevice); - } - - m_scanResults.m_vectorAdvertisedDevices.push_back(advertisedDevice); - - break; - } // ESP_GAP_SEARCH_INQ_RES_EVT - - default: { - break; - } - } // switch - search_evt - - - break; - } // ESP_GAP_BLE_SCAN_RESULT_EVT - - default: { - break; - } // default - } // End switch -} // gapEventHandler - - -/* -void BLEScan::onResults() { - ESP_LOGD(LOG_TAG, ">> onResults: default"); - ESP_LOGD(LOG_TAG, "<< onResults"); -} // onResults -*/ - - -/** - * @brief Should we perform an active or passive scan? - * The default is a passive scan. An active scan means that we will wish a scan response. - * @param [in] active If true, we perform an active scan otherwise a passive scan. - * @return N/A. - */ -void BLEScan::setActiveScan(bool active) { - if (active) { - m_scan_params.scan_type = BLE_SCAN_TYPE_ACTIVE; - } else { - m_scan_params.scan_type = BLE_SCAN_TYPE_PASSIVE; - } -} // setActiveScan - - -/** - * @brief Set the call backs to be invoked. - * @param [in] pAdvertisedDeviceCallbacks Call backs to be invoked. - */ -void BLEScan::setAdvertisedDeviceCallbacks(BLEAdvertisedDeviceCallbacks* pAdvertisedDeviceCallbacks) { - m_pAdvertisedDeviceCallbacks = pAdvertisedDeviceCallbacks; -} // setAdvertisedDeviceCallbacks - - -/** - * @brief Set the interval to scan. - * @param [in] The interval in msecs. - */ -void BLEScan::setInterval(uint16_t intervalMSecs) { - m_scan_params.scan_interval = intervalMSecs / 0.625; -} // setInterval - - -/** - * @brief Set the window to actively scan. - * @param [in] windowMSecs How long to actively scan. - */ -void BLEScan::setWindow(uint16_t windowMSecs) { - m_scan_params.scan_window = windowMSecs / 0.625; -} // setWindow - - -/** - * @brief Start scanning. - * @param [in] duration The duration in seconds for which to scan. - * @return N/A. - */ -BLEScanResults BLEScan::start(uint32_t duration) { - ESP_LOGD(LOG_TAG, ">> start(%d)", duration); - - m_semaphoreScanEnd.take("start"); - - m_scanResults.m_vectorAdvertisedDevices.empty(); - - esp_err_t errRc = ::esp_ble_gap_set_scan_params(&m_scan_params); - - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_ble_gap_set_scan_params: err: %d, text: %s", errRc, GeneralUtils::errorToString(errRc)); - m_semaphoreScanEnd.give(); - return m_scanResults; - } - - errRc = ::esp_ble_gap_start_scanning(duration); - - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_ble_gap_start_scanning: err: %d, text: %s", errRc, GeneralUtils::errorToString(errRc)); - m_semaphoreScanEnd.give(); - return m_scanResults; - } - - m_stopped = false; - - m_semaphoreScanEnd.take("start"); - m_semaphoreScanEnd.give(); - - ESP_LOGD(LOG_TAG, "<< start()"); - return m_scanResults; -} // start - - -/** - * @brief Stop an in progress scan. - * @return N/A. - */ -void BLEScan::stop() { - ESP_LOGD(LOG_TAG, ">> stop()"); - - esp_err_t errRc = ::esp_ble_gap_stop_scanning(); - - m_stopped = true; - - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_ble_gap_stop_scanning: err: %d, text: %s", errRc, GeneralUtils::errorToString(errRc)); - return; - } - - m_semaphoreScanEnd.give(); - - ESP_LOGD(LOG_TAG, "<< stop()"); -} // stop - - -/** - * @brief Return the count of devices found in the last scan. - * @return The number of devices found in the last scan. - */ -int BLEScanResults::getCount() { - return m_vectorAdvertisedDevices.size(); -} // getCount - - -/** - * @brief Return the specified device at the given index. - * The index should be between 0 and getCount()-1. - * @param [in] i The index of the device. - * @return The device at the specified index. - */ -BLEAdvertisedDevice BLEScanResults::getDevice(uint32_t i) { - return m_vectorAdvertisedDevices.at(i); -} - -#endif /* CONFIG_BT_ENABLED */ diff --git a/ESP32_BLE_Arduino/src/BLEScan.h b/ESP32_BLE_Arduino/src/BLEScan.h deleted file mode 100644 index f9575ea..0000000 --- a/ESP32_BLE_Arduino/src/BLEScan.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * BLEScan.h - * - * Created on: Jul 1, 2017 - * Author: kolban - */ - -#ifndef COMPONENTS_CPP_UTILS_BLESCAN_H_ -#define COMPONENTS_CPP_UTILS_BLESCAN_H_ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) -#include - -#include -#include "BLEAdvertisedDevice.h" -#include "BLEClient.h" -#include "FreeRTOS.h" - -class BLEAdvertisedDevice; -class BLEAdvertisedDeviceCallbacks; -class BLEClient; -class BLEScan; - -class BLEScanResults { -public: - int getCount(); - BLEAdvertisedDevice getDevice(uint32_t i); -private: - friend BLEScan; - std::vector m_vectorAdvertisedDevices; -}; - -/** - * @brief Perform and manage %BLE scans. - * - * Scanning is associated with a %BLE client that is attempting to locate BLE servers. - */ -class BLEScan { -public: - BLEScan(); - - //virtual void onResults(); - void setActiveScan(bool active); - void setAdvertisedDeviceCallbacks(BLEAdvertisedDeviceCallbacks* pAdvertisedDeviceCallbacks); - void setInterval(uint16_t intervalMSecs); - void setWindow(uint16_t windowMSecs); - BLEScanResults start(uint32_t duration); - void stop(); - -private: - friend class BLEDevice; - void gapEventHandler( - esp_gap_ble_cb_event_t event, - esp_ble_gap_cb_param_t* param); - void parseAdvertisement(BLEClient* pRemoteDevice, uint8_t *payload); - - - esp_ble_scan_params_t m_scan_params; - BLEAdvertisedDeviceCallbacks* m_pAdvertisedDeviceCallbacks; - bool m_stopped; - FreeRTOS::Semaphore m_semaphoreScanEnd = FreeRTOS::Semaphore("ScanEnd"); - //std::vector m_vectorAvdertisedDevices; - BLEScanResults m_scanResults; -}; // BLEScan - -#endif /* CONFIG_BT_ENABLED */ -#endif /* COMPONENTS_CPP_UTILS_BLESCAN_H_ */ diff --git a/ESP32_BLE_Arduino/src/BLEServer.cpp b/ESP32_BLE_Arduino/src/BLEServer.cpp deleted file mode 100644 index be9773d..0000000 --- a/ESP32_BLE_Arduino/src/BLEServer.cpp +++ /dev/null @@ -1,353 +0,0 @@ -/* - * BLEServer.cpp - * - * Created on: Apr 16, 2017 - * Author: kolban - */ - -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) -#include -#include -#include -#include -#include -#include "BLEDevice.h" -#include "BLEServer.h" -#include "BLEService.h" -#include "BLEUtils.h" -#include -#include -#include -#include - -static const char* LOG_TAG = "BLEServer"; - - -/** - * @brief Construct a %BLE Server - * - * This class is not designed to be individually instantiated. Instead one should create a server by asking - * the BLEDevice class. - */ -BLEServer::BLEServer() { - m_appId = -1; - m_gatts_if = -1; - m_connectedCount = 0; - m_connId = -1; - BLEDevice::m_bleServer = this; - m_pServerCallbacks = nullptr; - - createApp(0); -} // BLEServer - - -void BLEServer::createApp(uint16_t appId) { - m_appId = appId; - registerApp(); -} - - -/** - * @brief Create a %BLE Service. - * - * With a %BLE server, we can host one or more services. Invoking this function causes the creation of a definition - * of a new service. Every service must have a unique UUID. - * @param [in] uuid The UUID of the new service. - * @return A reference to the new service object. - */ -BLEService* BLEServer::createService(const char* uuid) { - return createService(BLEUUID(uuid)); -} - - -/** - * @brief Create a %BLE Service. - * - * With a %BLE server, we can host one or more services. Invoking this function causes the creation of a definition - * of a new service. Every service must have a unique UUID. - * @param [in] uuid The UUID of the new service. - * @return A reference to the new service object. - */ -BLEService* BLEServer::createService(BLEUUID uuid) { - ESP_LOGD(LOG_TAG, ">> createService - %s", uuid.toString().c_str()); - m_semaphoreCreateEvt.take("createService"); - - // Check that a service with the supplied UUID does not already exist. - if (m_serviceMap.getByUUID(uuid) != nullptr) { - ESP_LOGE(LOG_TAG, "<< Attempt to create a new service with uuid %s but a service with that UUID already exists.", - uuid.toString().c_str()); - m_semaphoreCreateEvt.give(); - return nullptr; - } - - BLEService* pService = new BLEService(uuid); - m_serviceMap.setByUUID(uuid, pService); // Save a reference to this service being on this server. - pService->executeCreate(this); // Perform the API calls to actually create the service. - - m_semaphoreCreateEvt.wait("createService"); - - ESP_LOGD(LOG_TAG, "<< createService"); - return pService; -} // createService - - -/** - * @brief Retrieve the advertising object that can be used to advertise the existence of the server. - * - * @return An advertising object. - */ -BLEAdvertising* BLEServer::getAdvertising() { - return &m_bleAdvertising; -} - -uint16_t BLEServer::getConnId() { - return m_connId; -} - - -/** - * @brief Return the number of connected clients. - * @return The number of connected clients. - */ -uint32_t BLEServer::getConnectedCount() { - return m_connectedCount; -} // getConnectedCount - - -uint16_t BLEServer::getGattsIf() { - return m_gatts_if; -} - -/** - * @brief Handle a receiver GAP event. - * - * @param [in] event - * @param [in] param - */ -void BLEServer::handleGAPEvent( - esp_gap_ble_cb_event_t event, - esp_ble_gap_cb_param_t* param) { - ESP_LOGD(LOG_TAG, "BLEServer ... handling GAP event!"); - switch(event) { - case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: { - /* - esp_ble_adv_params_t adv_params; - adv_params.adv_int_min = 0x20; - adv_params.adv_int_max = 0x40; - adv_params.adv_type = ADV_TYPE_IND; - adv_params.own_addr_type = BLE_ADDR_TYPE_PUBLIC; - adv_params.channel_map = ADV_CHNL_ALL; - adv_params.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY; - ESP_LOGD(tag, "Starting advertising"); - esp_err_t errRc = ::esp_ble_gap_start_advertising(&adv_params); - if (errRc != ESP_OK) { - ESP_LOGE(tag, "esp_ble_gap_start_advertising: rc=%d %s", errRc, espToString(errRc)); - return; - } - */ - break; - } - default: - break; - } -} // handleGAPEvent - - - -/** - * @brief Handle a GATT Server Event. - * - * @param [in] event - * @param [in] gatts_if - * @param [in] param - * - */ -void BLEServer::handleGATTServerEvent( - esp_gatts_cb_event_t event, - esp_gatt_if_t gatts_if, - esp_ble_gatts_cb_param_t* param) { - - ESP_LOGD(LOG_TAG, ">> handleGATTServerEvent: %s", - BLEUtils::gattServerEventTypeToString(event).c_str()); - - // Invoke the handler for every Service we have. - m_serviceMap.handleGATTServerEvent(event, gatts_if, param); - - switch(event) { - - - // ESP_GATTS_CONNECT_EVT - // connect: - // - uint16_t conn_id - // - esp_bd_addr_t remote_bda - // - bool is_connected - case ESP_GATTS_CONNECT_EVT: { - m_connId = param->connect.conn_id; // Save the connection id. - if (m_pServerCallbacks != nullptr) { - m_pServerCallbacks->onConnect(this); - } - m_connectedCount++; - break; - } // ESP_GATTS_CONNECT_EVT - - - // ESP_GATTS_REG_EVT - // reg: - // - esp_gatt_status_t status - // - uint16_t app_id - case ESP_GATTS_REG_EVT: { - m_gatts_if = gatts_if; - - m_semaphoreRegisterAppEvt.give(); - break; - } // ESP_GATTS_REG_EVT - - - // ESP_GATTS_CREATE_EVT - // Called when a new service is registered as having been created. - // - // create: - // * esp_gatt_status_t status - // * uint16_t service_handle - // * esp_gatt_srvc_id_t service_id - // - case ESP_GATTS_CREATE_EVT: { - BLEService* pService = m_serviceMap.getByUUID(param->create.service_id.id.uuid); - m_serviceMap.setByHandle(param->create.service_handle, pService); - //pService->setHandle(param->create.service_handle); - m_semaphoreCreateEvt.give(); - break; - } // ESP_GATTS_CREATE_EVT - - - // ESP_GATTS_READ_EVT - A request to read the value of a characteristic has arrived. - // - // read: - // - uint16_t conn_id - // - uint32_t trans_id - // - esp_bd_addr_t bda - // - uint16_t handle - // - uint16_t offset - // - bool is_long - // - bool need_rsp - // - case ESP_GATTS_READ_EVT: { - break; - } // ESP_GATTS_READ_EVT - - - // ESP_GATTS_WRITE_EVT - A request to write the value of a characteristic has arrived. - // - // write: - // - uint16_t conn_id - // - uint16_t trans_id - // - esp_bd_addr_t bda - // - uint16_t handle - // - uint16_t offset - // - bool need_rsp - // - bool is_prep - // - uint16_t len - // - uint8_t *value - - case ESP_GATTS_WRITE_EVT: { - break; - } - - // ESP_GATTS_DISCONNECT_EVT - // If we receive a disconnect event then invoke the callback for disconnects (if one is present). - // we also want to start advertising again. - case ESP_GATTS_DISCONNECT_EVT: { - m_connectedCount--; - if (m_pServerCallbacks != nullptr) { - m_pServerCallbacks->onDisconnect(this); - } - startAdvertising(); - break; - } // ESP_GATTS_DISCONNECT_EVT - - - // ESP_GATTS_ADD_CHAR_EVT - Indicate that a characteristic was added to the service. - // add_char: - // - esp_gatt_status_t status - // - uint16_t attr_handle - // - uint16_t service_handle - // - esp_bt_uuid_t char_uuid - case ESP_GATTS_ADD_CHAR_EVT: { - break; - } // ESP_GATTS_ADD_CHAR_EVT - - - default: { - break; - } - } - ESP_LOGD(LOG_TAG, "<< handleGATTServerEvent"); -} // handleGATTServerEvent - - -/** - * @brief Register the app. - * - * @return N/A - */ -void BLEServer::registerApp() { - ESP_LOGD(LOG_TAG, ">> registerApp - %d", m_appId); - m_semaphoreRegisterAppEvt.take("registerApp"); // Take the mutex, will be released by ESP_GATTS_REG_EVT event. - ::esp_ble_gatts_app_register(m_appId); - m_semaphoreRegisterAppEvt.wait("registerApp"); - ESP_LOGD(LOG_TAG, "<< registerApp"); -} // registerApp - - -/** - * @brief Set the callbacks. - * - * As a %BLE server operates, it will generate server level events such as a new client connecting or a previous client - * disconnecting. This function can be called to register a callback handler that will be invoked when these - * events are detected. - * - * @param [in] pCallbacks The callbacks to be invoked. - */ -void BLEServer::setCallbacks(BLEServerCallbacks* pCallbacks) { - m_pServerCallbacks = pCallbacks; -} // setCallbacks - - -/** - * @brief Start advertising. - * - * Start the server advertising its existence. This is a convenience function and is equivalent to - * retrieving the advertising object and invoking start upon it. - */ -void BLEServer::startAdvertising() { - ESP_LOGD(LOG_TAG, ">> startAdvertising"); - m_bleAdvertising.start(); - ESP_LOGD(LOG_TAG, "<< startAdvertising"); -} // startAdvertising - - -/* -void BLEServer::addCharacteristic(BLECharacteristic *characteristic, BLEService *pService) { - ESP_LOGD(tag, "Adding characteristic (esp_ble_gatts_add_char): uuid=%s, serviceHandle=0x%.2x", - characteristic->m_bleUUID.toString().c_str(), - pService->getHandle()); - - m_characteristicMap.setByUUID(characteristic->m_bleUUID, characteristic); - - esp_err_t errRc = ::esp_ble_gatts_add_char( - pService->getHandle(), - characteristic->getUUID().getNative(), - (esp_gatt_perm_t)(ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE), - characteristic->getProperties(), - &characteristic->m_value, - NULL); - - if (errRc != ESP_OK) { - ESP_LOGE(tag, "esp_ble_gatts_add_char: rc=%d %s", errRc, espToString(errRc)); - return; - } -} -*/ - -#endif // CONFIG_BT_ENABLED diff --git a/ESP32_BLE_Arduino/src/BLEServer.h b/ESP32_BLE_Arduino/src/BLEServer.h deleted file mode 100644 index c6307bc..0000000 --- a/ESP32_BLE_Arduino/src/BLEServer.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * BLEServer.h - * - * Created on: Apr 16, 2017 - * Author: kolban - */ - -#ifndef COMPONENTS_CPP_UTILS_BLESERVER_H_ -#define COMPONENTS_CPP_UTILS_BLESERVER_H_ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) -#include - -#include -#include - -#include "BLEUUID.h" -#include "BLEAdvertising.h" -#include "BLECharacteristic.h" -#include "BLEService.h" -#include "FreeRTOS.h" - -class BLEServerCallbacks; - - -/** - * @brief A data structure that manages the %BLE servers owned by a BLE server. - */ -class BLEServiceMap { -public: - BLEService* getByHandle(uint16_t handle); - BLEService* getByUUID(const char* uuid); - BLEService* getByUUID(BLEUUID uuid); - void handleGATTServerEvent( - esp_gatts_cb_event_t event, - esp_gatt_if_t gatts_if, - esp_ble_gatts_cb_param_t* param); - void setByHandle(uint16_t handle, BLEService* service); - void setByUUID(const char* uuid, BLEService* service); - void setByUUID(BLEUUID uuid, BLEService* service); - std::string toString(); - -private: - std::map m_uuidMap; - std::map m_handleMap; -}; - - -/** - * @brief The model of a %BLE server. - */ -class BLEServer { -public: - BLEServer(); - - - uint32_t getConnectedCount(); - BLEService* createService(const char* uuid); - BLEService* createService(BLEUUID uuid); - BLEAdvertising* getAdvertising(); - void setCallbacks(BLEServerCallbacks *pCallbacks); - void startAdvertising(); - - -private: - friend class BLEService; - friend class BLECharacteristic; - friend class BLEDevice; - esp_ble_adv_data_t m_adv_data; - uint16_t m_appId; - BLEAdvertising m_bleAdvertising; - uint16_t m_connId; - uint32_t m_connectedCount; - uint16_t m_gatts_if; - FreeRTOS::Semaphore m_semaphoreRegisterAppEvt = FreeRTOS::Semaphore("RegisterAppEvt"); - FreeRTOS::Semaphore m_semaphoreCreateEvt = FreeRTOS::Semaphore("CreateEvt"); - BLEServiceMap m_serviceMap; - BLEServerCallbacks* m_pServerCallbacks; - - void createApp(uint16_t appId); - uint16_t getConnId(); - uint16_t getGattsIf(); - void handleGAPEvent(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param); - void handleGATTServerEvent(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param); - void registerApp(); -}; // BLEServer - - -/** - * @brief Callbacks associated with the operation of a %BLE server. - */ -class BLEServerCallbacks { -public: - virtual ~BLEServerCallbacks() {}; - /** - * @brief Handle a new client connection. - * - * When a new client connects, we are invoked. - * - * @param [in] pServer A reference to the %BLE server that received the client connection. - */ - virtual void onConnect(BLEServer* pServer); - - /** - * @brief Handle an existing client disconnection. - * - * When an existing client disconnects, we are invoked. - * - * @param [in] pServer A reference to the %BLE server that received the existing client disconnection. - */ - virtual void onDisconnect(BLEServer* pServer); -}; // BLEServerCallbacks - - - -#endif /* CONFIG_BT_ENABLED */ -#endif /* COMPONENTS_CPP_UTILS_BLESERVER_H_ */ diff --git a/ESP32_BLE_Arduino/src/BLEServerCallbacks.cpp b/ESP32_BLE_Arduino/src/BLEServerCallbacks.cpp deleted file mode 100644 index 8808720..0000000 --- a/ESP32_BLE_Arduino/src/BLEServerCallbacks.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* - * BLEServerCallbacks.cpp - * - * Created on: Jul 4, 2017 - * Author: kolban - */ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) -#include "BLEServer.h" -#include -static const char* LOG_TAG = "BLEServerCallbacks"; - -void BLEServerCallbacks::onConnect(BLEServer* pServer) { - ESP_LOGD(LOG_TAG, ">> onConnect(): Default"); - ESP_LOGD(LOG_TAG, "<< onConnect()"); -} - -void BLEServerCallbacks::onDisconnect(BLEServer* pServer) { - ESP_LOGD(LOG_TAG, ">> onDisconnect(): Default"); - ESP_LOGD(LOG_TAG, "<< onDisconnect()"); -} -#endif /* CONFIG_BT_ENABLED */ diff --git a/ESP32_BLE_Arduino/src/BLEService.cpp b/ESP32_BLE_Arduino/src/BLEService.cpp deleted file mode 100644 index ec16db8..0000000 --- a/ESP32_BLE_Arduino/src/BLEService.cpp +++ /dev/null @@ -1,353 +0,0 @@ -/* - * BLEService.cpp - * - * Created on: Mar 25, 2017 - * Author: kolban - */ - -// A service is identified by a UUID. A service is also the container for one or more characteristics. - -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) -#include -#include -#include - -#include -#include -#include - -#include "BLEServer.h" -#include "BLEService.h" -#include "BLEUtils.h" -#include "GeneralUtils.h" - -#define NULL_HANDLE (0xffff) - -static const char* LOG_TAG = "BLEService"; // Tag for logging. - -/** - * @brief Construct an instance of the BLEService - * @param [in] uuid The UUID of the service. - */ -BLEService::BLEService(const char* uuid) : BLEService(BLEUUID(uuid)) { -} - - -/** - * @brief Construct an instance of the BLEService - * @param [in] uuid The UUID of the service. - */ -BLEService::BLEService(BLEUUID uuid) { - m_uuid = uuid; - m_handle = NULL_HANDLE; - m_pServer = nullptr; - //m_serializeMutex.setName("BLEService"); - m_lastCreatedCharacteristic = nullptr; -} // BLEService - - -/** - * @brief Create the service. - * Create the service. - * @param [in] gatts_if The handle of the GATT server interface. - * @return N/A. - */ -void BLEService::executeCreate(BLEServer *pServer) { - ESP_LOGD(LOG_TAG, ">> executeCreate() - Creating service (esp_ble_gatts_create_service) service uuid: %s", getUUID().toString().c_str()); - - m_pServer = pServer; - esp_gatt_srvc_id_t srvc_id; - srvc_id.id.inst_id = 0; - srvc_id.id.uuid = *m_uuid.getNative(); - - m_semaphoreCreateEvt.take("executeCreate"); // Take the mutex and release at event ESP_GATTS_CREATE_EVT - - esp_err_t errRc = ::esp_ble_gatts_create_service(getServer()->getGattsIf(), &srvc_id, 10); - - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_ble_gatts_create_service: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return; - } - - m_semaphoreCreateEvt.wait("executeCreate"); - - ESP_LOGD(LOG_TAG, "<< executeCreate"); -} // executeCreate - - -/** - * @brief Dump details of this BLE GATT service. - * @return N/A. - */ -void BLEService::dump() { - ESP_LOGD(LOG_TAG, "Service: uuid:%s, handle: 0x%.2x", - m_uuid.toString().c_str(), - m_handle); - ESP_LOGD(LOG_TAG, "Characteristics:\n%s", m_characteristicMap.toString().c_str()); -} // dump - -/* -void BLEService::setService(esp_gatt_srvc_id_t srvc_id) { - m_srvc_id = srvc_id; -} -*/ - -/* -esp_gatt_srvc_id_t BLEService::getService() { - return m_srvc_id; -} -*/ - - -/** - * @brief Get the UUID of the service. - * @return the UUID of the service. - */ -BLEUUID BLEService::getUUID() { - return m_uuid; -} // getUUID - - -/** - * @brief Start the service. - * Here we wish to start the service which means that we will respond to partner requests about it. - * Starting a service also means that we can create the corresponding characteristics. - * @return Start the service. - */ -void BLEService::start() { -// We ask the BLE runtime to start the service and then create each of the characteristics. -// We start the service through its local handle which was returned in the ESP_GATTS_CREATE_EVT event -// obtained as a result of calling esp_ble_gatts_create_service(). -// - ESP_LOGD(LOG_TAG, ">> start(): Starting service (esp_ble_gatts_start_service): %s", toString().c_str()); - if (m_handle == NULL_HANDLE) { - ESP_LOGE(LOG_TAG, "<< !!! We attempted to start a service but don't know its handle!"); - return; - } - - - BLECharacteristic *pCharacteristic = m_characteristicMap.getFirst(); - - while(pCharacteristic != nullptr) { - m_lastCreatedCharacteristic = pCharacteristic; - pCharacteristic->executeCreate(this); - - pCharacteristic = m_characteristicMap.getNext(); - } - // Start each of the characteristics ... these are found in the m_characteristicMap. - - m_semaphoreStartEvt.take("start"); - esp_err_t errRc = ::esp_ble_gatts_start_service(m_handle); - - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "<< esp_ble_gatts_start_service: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return; - } - m_semaphoreStartEvt.wait("start"); - - ESP_LOGD(LOG_TAG, "<< start()"); -} // start - - -/** - * @brief Set the handle associated with this service. - * @param [in] handle The handle associated with the service. - */ -void BLEService::setHandle(uint16_t handle) { - ESP_LOGD(LOG_TAG, ">> setHandle - Handle=0x%.2x, service UUID=%s)", handle, getUUID().toString().c_str()); - if (m_handle != NULL_HANDLE) { - ESP_LOGE(LOG_TAG, "!!! Handle is already set %.2x", m_handle); - return; - } - m_handle = handle; - ESP_LOGD(LOG_TAG, "<< setHandle"); -} // setHandle - - -/** - * @brief Get the handle associated with this service. - * @return The handle associated with this service. - */ -uint16_t BLEService::getHandle() { - return m_handle; -} // getHandle - - -/** - * @brief Add a characteristic to the service. - * @param [in] pCharacteristic A pointer to the characteristic to be added. - */ -void BLEService::addCharacteristic(BLECharacteristic* pCharacteristic) { -// We maintain a mapping of characteristics owned by this service. These are managed by the -// BLECharacteristicMap class instance found in m_characteristicMap. We add the characteristic -// to the map and then ask the service to add the characteristic at the BLE level (ESP-IDF). -// - ESP_LOGD(LOG_TAG, ">> addCharacteristic()"); - ESP_LOGD(LOG_TAG, "Adding characteristic (esp_ble_gatts_add_char): uuid=%s to service: %s", - pCharacteristic->getUUID().toString().c_str(), - toString().c_str()); - - // Check that we don't add the same characteristic twice. - if (m_characteristicMap.getByUUID(pCharacteristic->getUUID()) != nullptr) { - ESP_LOGE(LOG_TAG, "<< Attempt to add a characteristic but we already have one with this UUID"); - return; - } - - // Remember this characteristic in our map of characteristics. At this point, we can lookup by UUID - // but not by handle. The handle is allocated to us on the ESP_GATTS_ADD_CHAR_EVT. - m_characteristicMap.setByUUID(pCharacteristic->getUUID(), pCharacteristic); - - ESP_LOGD(LOG_TAG, "<< addCharacteristic()"); -} // addCharacteristic - - -/** - * @brief Create a new BLE Characteristic associated with this service. - * @param [in] uuid - The UUID of the characteristic. - * @param [in] properties - The properties of the characteristic. - * @return The new BLE characteristic. - */ -BLECharacteristic* BLEService::createCharacteristic(const char* uuid, uint32_t properties) { - return createCharacteristic(BLEUUID(uuid), properties); -} - -/** - * @brief Create a new BLE Characteristic associated with this service. - * @param [in] uuid - The UUID of the characteristic. - * @param [in] properties - The properties of the characteristic. - * @return The new BLE characteristic. - */ -BLECharacteristic* BLEService::createCharacteristic(BLEUUID uuid, uint32_t properties) { - BLECharacteristic *pCharacteristic = new BLECharacteristic(uuid, properties); - addCharacteristic(pCharacteristic); - return pCharacteristic; -} // createCharacteristic - - -/** - * @brief Handle a GATTS server event. - */ -void BLEService::handleGATTServerEvent( - esp_gatts_cb_event_t event, - esp_gatt_if_t gatts_if, - esp_ble_gatts_cb_param_t *param) { - - - switch(event) { - // ESP_GATTS_ADD_CHAR_EVT - Indicate that a characteristic was added to the service. - // add_char: - // - esp_gatt_status_t status - // - uint16_t attr_handle - // - uint16_t service_handle - // - esp_bt_uuid_t char_uuid - - // If we have reached the correct service, then locate the characteristic and remember the handle - // for that characteristic. - case ESP_GATTS_ADD_CHAR_EVT: { - if (m_handle == param->add_char.service_handle) { - BLECharacteristic *pCharacteristic = getCharacteristic(BLEUUID(param->add_char.char_uuid)); - if (pCharacteristic == nullptr) { - ESP_LOGE(LOG_TAG, "Expected to find characteristic with UUID: %s, but didnt!", - BLEUUID(param->add_char.char_uuid).toString().c_str()); - dump(); - m_semaphoreAddCharEvt.give(); - break; - } - pCharacteristic->setHandle(param->add_char.attr_handle); - m_characteristicMap.setByHandle(param->add_char.attr_handle, pCharacteristic); - //ESP_LOGD(tag, "Characteristic map: %s", m_characteristicMap.toString().c_str()); - m_semaphoreAddCharEvt.give(); - break; - } // Reached the correct service. - break; - } // ESP_GATTS_ADD_CHAR_EVT - - // ESP_GATTS_START_EVT - // - // start: - // esp_gatt_status_t status - // uint16_t service_handle - case ESP_GATTS_START_EVT: { - if (param->start.service_handle == getHandle()) { - m_semaphoreStartEvt.give(); - } - break; - } // ESP_GATTS_START_EVT - - - // ESP_GATTS_CREATE_EVT - // Called when a new service is registered as having been created. - // - // create: - // * esp_gatt_status_t status - // * uint16_t service_handle - // * esp_gatt_srvc_id_t service_id - // * - esp_gatt_id id - // * - esp_bt_uuid uuid - // * - uint8_t inst_id - // * - bool is_primary - // - case ESP_GATTS_CREATE_EVT: { - if (getUUID().equals(BLEUUID(param->create.service_id.id.uuid))) { - setHandle(param->create.service_handle); - m_semaphoreCreateEvt.give(); - } - break; - } // ESP_GATTS_CREATE_EVT - - default: { - break; - } // Default - } // Switch - - m_characteristicMap.handleGATTServerEvent(event, gatts_if, param); -} // handleGATTServerEvent - - -BLECharacteristic* BLEService::getCharacteristic(const char* uuid) { - return getCharacteristic(BLEUUID(uuid)); -} - - -BLECharacteristic* BLEService::getCharacteristic(BLEUUID uuid) { - return m_characteristicMap.getByUUID(uuid); -} - - -/** - * @brief Return a string representation of this service. - * A service is defined by: - * * Its UUID - * * Its handle - * @return A string representation of this service. - */ -std::string BLEService::toString() { - std::stringstream stringStream; - stringStream << "UUID: " << getUUID().toString() << - ", handle: 0x" << std::hex << std::setfill('0') << std::setw(2) << getHandle(); - return stringStream.str(); -} // toString - - -/** - * @brief Get the last created characteristic. - * It is lamentable that this function has to exist. It returns the last created characteristic. - * We need this because the descriptor API is built around the notion that a new descriptor, when created, - * is associated with the last characteristics created and we need that information. - * @return The last created characteristic. - */ -BLECharacteristic* BLEService::getLastCreatedCharacteristic() { - return m_lastCreatedCharacteristic; -} // getLastCreatedCharacteristic - - -/** - * @brief Get the BLE server associated with this service. - * @return The BLEServer associated with this service. - */ -BLEServer* BLEService::getServer() { - return m_pServer; -} // getServer - -#endif // CONFIG_BT_ENABLED diff --git a/ESP32_BLE_Arduino/src/BLEService.h b/ESP32_BLE_Arduino/src/BLEService.h deleted file mode 100644 index 86d0776..0000000 --- a/ESP32_BLE_Arduino/src/BLEService.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * BLEService.h - * - * Created on: Mar 25, 2017 - * Author: kolban - */ - -#ifndef COMPONENTS_CPP_UTILS_BLESERVICE_H_ -#define COMPONENTS_CPP_UTILS_BLESERVICE_H_ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) - -#include - -#include "BLECharacteristic.h" -#include "BLEServer.h" -#include "BLEUUID.h" -#include "FreeRTOS.h" - -class BLEServer; - -/** - * @brief A data mapping used to manage the set of %BLE characteristics known to the server. - */ -class BLECharacteristicMap { -public: - void setByUUID(const char* uuid, BLECharacteristic* pCharacteristic); - void setByUUID(BLEUUID uuid, BLECharacteristic* pCharacteristic); - void setByHandle(uint16_t handle, BLECharacteristic* pCharacteristic); - BLECharacteristic* getByUUID(const char* uuid); - BLECharacteristic* getByUUID(BLEUUID uuid); - BLECharacteristic* getByHandle(uint16_t handle); - BLECharacteristic* getFirst(); - BLECharacteristic* getNext(); - std::string toString(); - void handleGATTServerEvent( - esp_gatts_cb_event_t event, - esp_gatt_if_t gatts_if, - esp_ble_gatts_cb_param_t* param); - - -private: - std::map m_uuidMap; - std::map m_handleMap; - std::map::iterator m_iterator; -}; - - -/** - * @brief The model of a %BLE service. - * - */ -class BLEService { -public: - BLEService(const char* uuid); - BLEService(BLEUUID uuid); - - void addCharacteristic(BLECharacteristic* pCharacteristic); - BLECharacteristic* createCharacteristic(const char* uuid, uint32_t properties); - BLECharacteristic* createCharacteristic(BLEUUID uuid, uint32_t properties); - void dump(); - void executeCreate(BLEServer* pServer); - BLECharacteristic* getCharacteristic(const char* uuid); - BLECharacteristic* getCharacteristic(BLEUUID uuid); - BLEUUID getUUID(); - BLEServer* getServer(); - void start(); - std::string toString(); - -private: - friend class BLEServer; - friend class BLEServiceMap; - friend class BLEDescriptor; - friend class BLECharacteristic; - friend class BLEDevice; - - BLECharacteristicMap m_characteristicMap; - uint16_t m_handle; - BLECharacteristic* m_lastCreatedCharacteristic; - BLEServer* m_pServer; - //FreeRTOS::Semaphore m_serializeMutex; - FreeRTOS::Semaphore m_semaphoreAddCharEvt = FreeRTOS::Semaphore("AddCharEvt"); - FreeRTOS::Semaphore m_semaphoreCreateEvt = FreeRTOS::Semaphore("CreateEvt"); - FreeRTOS::Semaphore m_semaphoreStartEvt = FreeRTOS::Semaphore("StartEvt"); - BLEUUID m_uuid; - - uint16_t getHandle(); - BLECharacteristic* getLastCreatedCharacteristic(); - void handleGATTServerEvent( - esp_gatts_cb_event_t event, - esp_gatt_if_t gatts_if, - esp_ble_gatts_cb_param_t* param); - void setHandle(uint16_t handle); - //void setService(esp_gatt_srvc_id_t srvc_id); -}; // BLEService - - -#endif // CONFIG_BT_ENABLED -#endif /* COMPONENTS_CPP_UTILS_BLESERVICE_H_ */ diff --git a/ESP32_BLE_Arduino/src/BLEServiceMap.cpp b/ESP32_BLE_Arduino/src/BLEServiceMap.cpp deleted file mode 100644 index 8fdbd5a..0000000 --- a/ESP32_BLE_Arduino/src/BLEServiceMap.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - * BLEServiceMap.cpp - * - * Created on: Jun 22, 2017 - * Author: kolban - */ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) -#include -#include -#include "BLEService.h" - - -/** - * @brief Return the service by UUID. - * @param [in] UUID The UUID to look up the service. - * @return The characteristic. - */ -BLEService* BLEServiceMap::getByUUID(const char* uuid) { - return getByUUID(BLEUUID(uuid)); -} - -/** - * @brief Return the service by UUID. - * @param [in] UUID The UUID to look up the service. - * @return The characteristic. - */ -BLEService* BLEServiceMap::getByUUID(BLEUUID uuid) { - for (auto &myPair : m_uuidMap) { - if (myPair.second->getUUID().equals(uuid)) { - return myPair.second; - } - } - //return m_uuidMap.at(uuid.toString()); - return nullptr; -} // getByUUID - - -/** - * @brief Return the service by handle. - * @param [in] handle The handle to look up the service. - * @return The service. - */ -BLEService* BLEServiceMap::getByHandle(uint16_t handle) { - return m_handleMap.at(handle); -} // getByHandle - - -/** - * @brief Set the service by UUID. - * @param [in] uuid The uuid of the service. - * @param [in] characteristic The service to cache. - * @return N/A. - */ -void BLEServiceMap::setByUUID(BLEUUID uuid, - BLEService *service) { - m_uuidMap.insert(std::pair(uuid.toString(), service)); -} // setByUUID - - -/** - * @brief Set the service by handle. - * @param [in] handle The handle of the service. - * @param [in] service The service to cache. - * @return N/A. - */ -void BLEServiceMap::setByHandle(uint16_t handle, - BLEService* service) { - m_handleMap.insert(std::pair(handle, service)); -} // setByHandle - - -/** - * @brief Return a string representation of the service map. - * @return A string representation of the service map. - */ -std::string BLEServiceMap::toString() { - std::stringstream stringStream; - stringStream << std::hex << std::setfill('0'); - for (auto &myPair: m_handleMap) { - stringStream << "handle: 0x" << std::setw(2) << myPair.first << ", uuid: " + myPair.second->getUUID().toString() << "\n"; - } - return stringStream.str(); -} // toString - -void BLEServiceMap::handleGATTServerEvent( - esp_gatts_cb_event_t event, - esp_gatt_if_t gatts_if, - esp_ble_gatts_cb_param_t *param) { - // Invoke the handler for every Service we have. - for (auto &myPair : m_uuidMap) { - myPair.second->handleGATTServerEvent(event, gatts_if, param); - } -} -#endif /* CONFIG_BT_ENABLED */ diff --git a/ESP32_BLE_Arduino/src/BLEUUID.cpp b/ESP32_BLE_Arduino/src/BLEUUID.cpp deleted file mode 100644 index 9a4fe45..0000000 --- a/ESP32_BLE_Arduino/src/BLEUUID.cpp +++ /dev/null @@ -1,326 +0,0 @@ -/* - * BLEUUID.cpp - * - * Created on: Jun 21, 2017 - * Author: kolban - */ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) -#include -#include -#include -#include -#include -#include "BLEUUID.h" -static const char* LOG_TAG = "BLEUUID"; - - -/** - * @brief Copy memory from source to target but in reverse order. - * - * When we move memory from one location it is normally: - * - * ``` - * [0][1][2]...[n] -> [0][1][2]...[n] - * ``` - * - * with this function, it is: - * - * ``` - * [0][1][2]...[n] -> [n][n-1][n-2]...[0] - * ``` - * - * @param [in] target The target of the copy - * @param [in] source The source of the copy - * @param [in] size The number of bytes to copy - */ -static void memrcpy(uint8_t* target, uint8_t* source, uint32_t size) { - target+=(size-1); // Point target to the last byte of the target data - while (size > 0) { - *target = *source; - target--; - source++; - size--; - } -} // memrcpy - - -/** - * @brief Create a UUID from a string. - * - * Create a UUID from a string. There will be two possible stories here. Either the string represents - * a binary data field or the string represents a hex encoding of a UUID. - * For the hex encoding, here is an example: - * - * ``` - * "beb5483e-36e1-4688-b7f5-ea07361b26a8" - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - * 12345678-90ab-cdef-1234-567890abcdef - * ``` - * - * This has a length of 36 characters. We need to parse this into 16 bytes. - * - * @param [in] value The string to build a UUID from. - */ -BLEUUID::BLEUUID(std::string value) { - m_valueSet = true; - if (value.length() == 2) { - m_uuid.len = ESP_UUID_LEN_16; - m_uuid.uuid.uuid16 = value[0] | (value[1] << 8); - } else if (value.length() == 4) { - m_uuid.len = ESP_UUID_LEN_32; - m_uuid.uuid.uuid32 = value[0] | (value[1] << 8) | (value[2] << 16) | (value[3] << 24); - } else if (value.length() == 16) { - m_uuid.len = ESP_UUID_LEN_128; - memrcpy(m_uuid.uuid.uuid128, (uint8_t*)value.data(), 16); - } else if (value.length() == 36) { -// If the length of the string is 36 bytes then we will assume it is a long hex string in -// UUID format. - m_uuid.len = ESP_UUID_LEN_128; - int vals[16]; - sscanf(value.c_str(), "%2x%2x%2x%2x-%2x%2x-%2x%2x-%2x%2x-%2x%2x%2x%2x%2x%2x", - &vals[15], - &vals[14], - &vals[13], - &vals[12], - &vals[11], - &vals[10], - &vals[9], - &vals[8], - &vals[7], - &vals[6], - &vals[5], - &vals[4], - &vals[3], - &vals[2], - &vals[1], - &vals[0] - ); - - int i; - for (i=0; i<16; i++) { - m_uuid.uuid.uuid128[i] = vals[i]; - } - } - else { - ESP_LOGE(LOG_TAG, "ERROR: UUID value not 2, 4, 16 or 36 bytes"); - m_valueSet = false; - } -} //BLEUUID(std::string) - - -/** - * @brief Create a UUID from 16 bytes of memory. - * - * @param [in] pData The pointer to the start of the UUID. - * @param [in] size The size of the data. - * @param [in] msbFirst Is the MSB first in pData memory? - */ -BLEUUID::BLEUUID(uint8_t* pData, size_t size, bool msbFirst) { - if (size != 16) { - ESP_LOGE(LOG_TAG, "ERROR: UUID length not 16 bytes"); - return; - } - m_uuid.len = ESP_UUID_LEN_128; - if (msbFirst) { - memrcpy(m_uuid.uuid.uuid128, pData, 16); - } else { - memcpy(m_uuid.uuid.uuid128, pData, 16); - } - m_valueSet = true; -} // BLEUUID - -/** - * @brief Create a UUID from the 16bit value. - * - * @param [in] uuid The 16bit short form UUID. - */ -BLEUUID::BLEUUID(uint16_t uuid) { - m_uuid.len = ESP_UUID_LEN_16; - m_uuid.uuid.uuid16 = uuid; - m_valueSet = true; -} // BLEUUID - - -/** - * @brief Create a UUID from the 32bit value. - * - * @param [in] uuid The 32bit short form UUID. - */ -BLEUUID::BLEUUID(uint32_t uuid) { - m_uuid.len = ESP_UUID_LEN_32; - m_uuid.uuid.uuid32 = uuid; - m_valueSet = true; -} // BLEUUID - - -/** - * @brief Create a UUID from the native UUID. - * - * @param [in] uuid The native UUID. - */ -BLEUUID::BLEUUID(esp_bt_uuid_t uuid) { - m_uuid = uuid; - m_valueSet = true; -} // BLEUUID - - -/** - * @brief Create a UUID from the ESP32 esp_gatt_srvc_id_t. - * - * @param [in] srvcId The data to create the UUID from. - */ -BLEUUID::BLEUUID(esp_gatt_srvc_id_t srcvId) : BLEUUID(srcvId.id.uuid) { -} // BLEUUID - - -BLEUUID::BLEUUID() { - m_valueSet = false; -} // BLEUUID - - -/** - * @brief Compare a UUID against this UUID. - * - * @param [in] uuid The UUID to compare against. - * @return True if the UUIDs are equal and false otherwise. - */ -bool BLEUUID::equals(BLEUUID uuid) { - //ESP_LOGD(TAG, "Comparing: %s to %s", toString().c_str(), uuid.toString().c_str()); - if (m_valueSet == false || uuid.m_valueSet == false) { - return false; - } - - if (uuid.m_uuid.len != m_uuid.len) { - return uuid.toString() == toString(); - } - - if (uuid.m_uuid.len == ESP_UUID_LEN_16) { - return uuid.m_uuid.uuid.uuid16 == m_uuid.uuid.uuid16; - } - - if (uuid.m_uuid.len == ESP_UUID_LEN_32) { - return uuid.m_uuid.uuid.uuid32 == m_uuid.uuid.uuid32; - } - - return memcmp(uuid.m_uuid.uuid.uuid128, m_uuid.uuid.uuid128, 16) == 0; -} // equals - - -/** - * @brief Get the native UUID value. - * - * @return The native UUID value or NULL if not set. - */ -esp_bt_uuid_t* BLEUUID::getNative() { - //ESP_LOGD(TAG, ">> getNative()") - if (m_valueSet == false) { - ESP_LOGD(LOG_TAG, "<< Return of un-initialized UUID!"); - return nullptr; - } - //ESP_LOGD(TAG, "<< getNative()"); - return &m_uuid; -} // getNative - - -/** - * @brief Convert a UUID to its 128 bit representation. - * - * A UUID can be internally represented as 16bit, 32bit or the full 128bit. This method - * will convert 16 or 32 bit representations to the full 128bit. - */ -BLEUUID BLEUUID::to128() { - //ESP_LOGD(LOG_TAG, ">> toFull() - %s", toString().c_str()); - - // If we either don't have a value or are already a 128 bit UUID, nothing further to do. - if (m_valueSet == false || m_uuid.len == ESP_UUID_LEN_128) { - return *this; - } - - // If we are 16 bit or 32 bit, then set the 4 bytes of the variable part of the UUID. - if (m_uuid.len == ESP_UUID_LEN_16) { - uint16_t temp = m_uuid.uuid.uuid16; - m_uuid.uuid.uuid128[15] = 0; - m_uuid.uuid.uuid128[14] = 0; - m_uuid.uuid.uuid128[13] = (temp >> 8) & 0xff; - m_uuid.uuid.uuid128[12] = temp & 0xff; - - } - else if (m_uuid.len == ESP_UUID_LEN_32) { - uint32_t temp = m_uuid.uuid.uuid32; - m_uuid.uuid.uuid128[15] = (temp >> 24) & 0xff; - m_uuid.uuid.uuid128[14] = (temp >> 16) & 0xff; - m_uuid.uuid.uuid128[13] = (temp >> 8) & 0xff; - m_uuid.uuid.uuid128[12] = temp & 0xff; - } - - // Set the fixed parts of the UUID. - m_uuid.uuid.uuid128[11] = 0x00; - m_uuid.uuid.uuid128[10] = 0x00; - - m_uuid.uuid.uuid128[9] = 0x10; - m_uuid.uuid.uuid128[8] = 0x00; - - m_uuid.uuid.uuid128[7] = 0x80; - m_uuid.uuid.uuid128[6] = 0x00; - - m_uuid.uuid.uuid128[5] = 0x00; - m_uuid.uuid.uuid128[4] = 0x80; - m_uuid.uuid.uuid128[3] = 0x5f; - m_uuid.uuid.uuid128[2] = 0x9b; - m_uuid.uuid.uuid128[1] = 0x34; - m_uuid.uuid.uuid128[0] = 0xfb; - - m_uuid.len = ESP_UUID_LEN_128; - //ESP_LOGD(TAG, "<< toFull <- %s", toString().c_str()); - return *this; -} // to128 - - -//01234567 8901 2345 6789 012345678901 -//0000180d-0000-1000-8000-00805f9b34fb -//0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - -/** - * @brief Get a string representation of the UUID. - * - * @return A string representation of the UUID. - */ -std::string BLEUUID::toString() { - if (m_valueSet == false) { - return ""; - } - - if (m_uuid.len == ESP_UUID_LEN_16) { - std::stringstream ss; - ss << "0000" << std::hex << std::setfill('0') << std::setw(4) << m_uuid.uuid.uuid16 << "-0000-1000-8000-00805f9b34fb"; - return ss.str(); - } - - if (m_uuid.len == ESP_UUID_LEN_32) { - std::stringstream ss; - ss << std::hex << std::setfill('0') << std::setw(8) << m_uuid.uuid.uuid32 << "-0000-1000-8000-00805f9b34fb"; - return ss.str(); - } - - std::stringstream ss; - ss << std::hex << std::setfill('0') << - std::setw(2) << (int)m_uuid.uuid.uuid128[15] << - std::setw(2) << (int)m_uuid.uuid.uuid128[14] << - std::setw(2) << (int)m_uuid.uuid.uuid128[13] << - std::setw(2) << (int)m_uuid.uuid.uuid128[12] << "-" << - std::setw(2) << (int)m_uuid.uuid.uuid128[11] << - std::setw(2) << (int)m_uuid.uuid.uuid128[10] << "-" << - std::setw(2) << (int)m_uuid.uuid.uuid128[9] << - std::setw(2) << (int)m_uuid.uuid.uuid128[8] << "-" << - std::setw(2) << (int)m_uuid.uuid.uuid128[7] << - std::setw(2) << (int)m_uuid.uuid.uuid128[6] << "-" << - std::setw(2) << (int)m_uuid.uuid.uuid128[5] << - std::setw(2) << (int)m_uuid.uuid.uuid128[4] << - std::setw(2) << (int)m_uuid.uuid.uuid128[3] << - std::setw(2) << (int)m_uuid.uuid.uuid128[2] << - std::setw(2) << (int)m_uuid.uuid.uuid128[1] << - std::setw(2) << (int)m_uuid.uuid.uuid128[0]; - return ss.str(); -} // toString -#endif /* CONFIG_BT_ENABLED */ diff --git a/ESP32_BLE_Arduino/src/BLEUUID.h b/ESP32_BLE_Arduino/src/BLEUUID.h deleted file mode 100644 index c364796..0000000 --- a/ESP32_BLE_Arduino/src/BLEUUID.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * BLEUUID.h - * - * Created on: Jun 21, 2017 - * Author: kolban - */ - -#ifndef COMPONENTS_CPP_UTILS_BLEUUID_H_ -#define COMPONENTS_CPP_UTILS_BLEUUID_H_ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) -#include -#include - -/** - * @brief A model of a %BLE UUID. - */ -class BLEUUID { -public: - BLEUUID(std::string uuid); - BLEUUID(uint16_t uuid); - BLEUUID(uint32_t uuid); - BLEUUID(esp_bt_uuid_t uuid); - BLEUUID(uint8_t* pData, size_t size, bool msbFirst); - BLEUUID(esp_gatt_srvc_id_t srcvId); - BLEUUID(); - bool equals(BLEUUID uuid); - esp_bt_uuid_t* getNative(); - BLEUUID to128(); - std::string toString(); - -private: - esp_bt_uuid_t m_uuid; - bool m_valueSet; -}; // BLEUUID -#endif /* CONFIG_BT_ENABLED */ -#endif /* COMPONENTS_CPP_UTILS_BLEUUID_H_ */ diff --git a/ESP32_BLE_Arduino/src/BLEUtils.cpp b/ESP32_BLE_Arduino/src/BLEUtils.cpp deleted file mode 100644 index 468a7e1..0000000 --- a/ESP32_BLE_Arduino/src/BLEUtils.cpp +++ /dev/null @@ -1,1352 +0,0 @@ -/* - * BLEUtils.cpp - * - * Created on: Mar 25, 2017 - * Author: kolban - */ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) -#include "BLEUtils.h" -#include "BLEUUID.h" -#include "BLEClient.h" -#include "BLEAddress.h" -#include "GeneralUtils.h" - -#include -#include -#include // ESP32 BLE -#include // ESP32 BLE -#include // ESP32 BLE -#include // ESP32 BLE -#include // ESP32 ESP-IDF -#include // ESP32 ESP-IDF -#include // Part of C++ STL -#include -#include - -static const char* LOG_TAG = "BLEUtils"; - -/* -static std::map g_addressMap; -static std::map g_connIdMap; -*/ - -typedef struct { - uint32_t assignedNumber; - std::string name; -} characteristicMap_t; - -static characteristicMap_t g_characteristicsMappings[] = { - {0x2a00, "Device Name"}, - {0x2a01, "Appearance"}, - {0, ""} -}; - -/** - * @brief Mapping from service ids to names - */ -typedef struct { - std::string name; - std::string type; - uint32_t assignedNumber; -} gattService_t; - - -/** - * Definition of the service ids to names that we know about. - */ -static const gattService_t g_gattServices[] = { - {"Alert Notification Service", "org.bluetooth.service.alert_notification", 0x1811}, - {"Automation IO", "org.bluetooth.service.automation_io", 0x1815 }, - {"Battery Service","org.bluetooth.service.battery_service", 0x180F}, - {"Blood Pressure", "org.bluetooth.service.blood_pressure", 0x1810}, - {"Body Composition", "org.bluetooth.service.body_composition", 0x181B}, - {"Bond Management", "org.bluetooth.service.bond_management", 0x181E}, - {"Continuous Glucose Monitoring", "org.bluetooth.service.continuous_glucose_monitoring", 0x181F}, - {"Current Time Service", "org.bluetooth.service.current_time", 0x1805}, - {"Cycling Power", "org.bluetooth.service.cycling_power", 0x1818}, - {"Cycling Speed and Cadence", "org.bluetooth.service.cycling_speed_and_cadence", 0x1816}, - {"Device Information", "org.bluetooth.service.device_information", 0x180A}, - {"Environmental Sensing", "org.bluetooth.service.environmental_sensing", 0x181A}, - {"Generic Access", "org.bluetooth.service.generic_access", 0x1800}, - {"Generic Attribute", "org.bluetooth.service.generic_attribute", 0x1801}, - {"Glucose", "org.bluetooth.service.glucose", 0x1808}, - {"Health Thermometer", "org.bluetooth.service.health_thermometer", 0x1809}, - {"Heart Rate", "org.bluetooth.service.heart_rate", 0x180D}, - {"HTTP Proxy", "org.bluetooth.service.http_proxy", 0x1823}, - {"Human Interface Device", "org.bluetooth.service.human_interface_device", 0x1812}, - {"Immediate Alert", "org.bluetooth.service.immediate_alert", 0x1802}, - {"Indoor Positioning", "org.bluetooth.service.indoor_positioning", 0x1821}, - {"Internet Protocol Support", "org.bluetooth.service.internet_protocol_support", 0x1820}, - {"Link Loss", "org.bluetooth.service.link_loss", 0x1803}, - {"Location and Navigation", "org.bluetooth.service.location_and_navigation", 0x1819}, - {"Next DST Change Service", "org.bluetooth.service.next_dst_change", 0x1807}, - {"Object Transfer", "org.bluetooth.service.object_transfer", 0x1825}, - {"Phone Alert Status Service", "org.bluetooth.service.phone_alert_status", 0x180E}, - {"Pulse Oximeter", "org.bluetooth.service.pulse_oximeter", 0x1822}, - {"Reference Time Update Service", "org.bluetooth.service.reference_time_update", 0x1806}, - {"Running Speed and Cadence", "org.bluetooth.service.running_speed_and_cadence", 0x1814}, - {"Scan Parameters", "org.bluetooth.service.scan_parameters", 0x1813}, - {"Transport Discovery", "org.bluetooth.service.transport_discovery", 0x1824}, - {"Tx Power", "org.bluetooth.service.tx_power", 0x1804}, - {"User Data", "org.bluetooth.service.user_data", 0x181C}, - {"Weight Scale", "org.bluetooth.service.weight_scale", 0x181D}, - {"", "", 0 } -}; - -/** - * @brief Convert characteristic properties into a string representation. - * @param [in] prop Characteristic properties. - * @return A string representation of characteristic properties. - */ -std::string BLEUtils::characteristicPropertiesToString(esp_gatt_char_prop_t prop) { - std::stringstream stream; - stream << - "broadcast: " << ((prop & ESP_GATT_CHAR_PROP_BIT_BROADCAST)?"1":"0") << - ", read: " << ((prop & ESP_GATT_CHAR_PROP_BIT_READ)?"1":"0") << - ", write_nr: " << ((prop & ESP_GATT_CHAR_PROP_BIT_WRITE_NR)?"1":"0") << - ", write: " << ((prop & ESP_GATT_CHAR_PROP_BIT_WRITE)?"1":"0") << - ", notify: " << ((prop & ESP_GATT_CHAR_PROP_BIT_NOTIFY)?"1":"0") << - ", indicate: " << ((prop & ESP_GATT_CHAR_PROP_BIT_INDICATE)?"1":"0") << - ", auth: " << ((prop & ESP_GATT_CHAR_PROP_BIT_AUTH)?"1":"0"); - return stream.str(); -} // characteristicPropertiesToString - -/** - * @brief Convert an esp_gatt_id_t to a string. - */ -static std::string gattIdToString(esp_gatt_id_t gattId) { - std::stringstream stream; - stream << "uuid: " << BLEUUID(gattId.uuid).toString() << ", inst_id: " << (int)gattId.inst_id; - //sprintf(buffer, "uuid: %s, inst_id: %d", uuidToString(gattId.uuid).c_str(), gattId.inst_id); - return stream.str(); -} // gattIdToString - - -/** - * @brief Convert an esp_ble_addr_type_t to a string representation. - */ -const char* BLEUtils::addressTypeToString(esp_ble_addr_type_t type) { - switch(type) { - case BLE_ADDR_TYPE_PUBLIC: - return "BLE_ADDR_TYPE_PUBLIC"; - case BLE_ADDR_TYPE_RANDOM: - return "BLE_ADDR_TYPE_RANDOM"; - case BLE_ADDR_TYPE_RPA_PUBLIC: - return "BLE_ADDR_TYPE_RPA_PUBLIC"; - case BLE_ADDR_TYPE_RPA_RANDOM: - return "BLE_ADDR_TYPE_RPA_RANDOM"; - default: - return "Unknown addr_t"; - } -} // addressTypeToString - - -/** - * @brief Given an advertising type, return a string representation of the type. - * - * For details see ... - * https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile - * - * @return A string representation of the type. - */ -const char* BLEUtils::advTypeToString(uint8_t advType) { - switch(advType) { - case ESP_BLE_AD_TYPE_FLAG: - return "ESP_BLE_AD_TYPE_FLAG"; - case ESP_BLE_AD_TYPE_16SRV_PART: - return "ESP_BLE_AD_TYPE_16SRV_PART"; - case ESP_BLE_AD_TYPE_16SRV_CMPL: - return "ESP_BLE_AD_TYPE_16SRV_CMPL"; - case ESP_BLE_AD_TYPE_32SRV_PART: - return "ESP_BLE_AD_TYPE_32SRV_PART"; - case ESP_BLE_AD_TYPE_32SRV_CMPL: - return "ESP_BLE_AD_TYPE_32SRV_CMPL"; - case ESP_BLE_AD_TYPE_128SRV_PART: - return "ESP_BLE_AD_TYPE_128SRV_PART"; - case ESP_BLE_AD_TYPE_128SRV_CMPL: - return "ESP_BLE_AD_TYPE_128SRV_CMPL"; - case ESP_BLE_AD_TYPE_NAME_SHORT: - return "ESP_BLE_AD_TYPE_NAME_SHORT"; - case ESP_BLE_AD_TYPE_NAME_CMPL: - return "ESP_BLE_AD_TYPE_NAME_CMPL"; - case ESP_BLE_AD_TYPE_TX_PWR: - return "ESP_BLE_AD_TYPE_TX_PWR"; - case ESP_BLE_AD_TYPE_DEV_CLASS: - return "ESP_BLE_AD_TYPE_DEV_CLASS"; - case ESP_BLE_AD_TYPE_SM_TK: - return "ESP_BLE_AD_TYPE_SM_TK"; - case ESP_BLE_AD_TYPE_SM_OOB_FLAG: - return "ESP_BLE_AD_TYPE_SM_OOB_FLAG"; - case ESP_BLE_AD_TYPE_INT_RANGE: - return "ESP_BLE_AD_TYPE_INT_RANGE"; - case ESP_BLE_AD_TYPE_SOL_SRV_UUID: - return "ESP_BLE_AD_TYPE_SOL_SRV_UUID"; - case ESP_BLE_AD_TYPE_128SOL_SRV_UUID: - return "ESP_BLE_AD_TYPE_128SOL_SRV_UUID"; - case ESP_BLE_AD_TYPE_SERVICE_DATA: - return "ESP_BLE_AD_TYPE_SERVICE_DATA"; - case ESP_BLE_AD_TYPE_PUBLIC_TARGET: - return "ESP_BLE_AD_TYPE_PUBLIC_TARGET"; - case ESP_BLE_AD_TYPE_RANDOM_TARGET: - return "ESP_BLE_Amap1D_TYPE_RANDOM_TARGET"; - case ESP_BLE_AD_TYPE_APPEARANCE: - return "ESP_BLE_AD_TYPE_APPEARANCE"; - case ESP_BLE_AD_TYPE_ADV_INT: - return "ESP_BLE_AD_TYPE_ADV_INT"; - case ESP_BLE_AD_TYPE_32SOL_SRV_UUID: - return "ESP_BLE_AD_TYPE_32SOL_SRV_UUID"; - case ESP_BLE_AD_TYPE_32SERVICE_DATA: - return "ESP_BLE_AD_TYPE_32SERVICE_DATA"; - case ESP_BLE_AD_TYPE_128SERVICE_DATA: - return "ESP_BLE_AD_TYPE_128SERVICE_DATA"; - case ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE: - return "ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE"; - default: - ESP_LOGD(LOG_TAG, "Unknown adv data type: 0x%x", advType); - return "Unknown"; - } // End switch -} // advTypeToString - - -esp_gatt_id_t BLEUtils::buildGattId(esp_bt_uuid_t uuid, uint8_t inst_id) { - esp_gatt_id_t retGattId; - retGattId.uuid = uuid; - retGattId.inst_id = inst_id; - return retGattId; -} - -esp_gatt_srvc_id_t BLEUtils::buildGattSrvcId(esp_gatt_id_t gattId, - bool is_primary) { - esp_gatt_srvc_id_t retSrvcId; - retSrvcId.id = gattId; - retSrvcId.is_primary = is_primary; - return retSrvcId; -} - -/** - * @brief Create a hex representation of data. - * - * @param [in] target Where to write the hex string. If this is null, we malloc storage. - * @param [in] source The start of the binary data. - * @param [in] length The length of the data to convert. - * @return A pointer to the formatted buffer. - */ -char *BLEUtils::buildHexData(uint8_t *target, uint8_t *source, uint8_t length) { -// Guard against too much data. - if (length > 100) { - length = 100; - } - - - if (target == nullptr) { - target = (uint8_t *)malloc(length * 2 + 1); - if (target == nullptr) { - ESP_LOGE(LOG_TAG, "buildHexData: malloc failed"); - return nullptr; - } - } - char *startOfData = (char *)target; - - int i; - for (i=0; iscan_rsp_data_cmpl.status); - break; - } // ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT - - - // - // ESP_GAP_BLE_ADV_START_COMPLETE_EVT - // - case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: { - ESP_LOGD(LOG_TAG, "[status: %d]", param->scan_start_cmpl.status); - break; - } // ESP_GAP_BLE_ADV_START_COMPLETE_EVT - - - // - // ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT - // - case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT: { - ESP_LOGD(LOG_TAG, "[status: %d]", param->scan_stop_cmpl.status); - break; - } // ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT - - - // - // ESP_GAP_BLE_AUTH_CMPL_EVT - // - case ESP_GAP_BLE_AUTH_CMPL_EVT: { - ESP_LOGD(LOG_TAG, "[bd_addr: %s, key_present: %d, key: ***, key_type: %d, success: %d, fail_reason: %d, addr_type: ***, dev_type: %s]", - BLEAddress(param->ble_security.auth_cmpl.bd_addr).toString().c_str(), - param->ble_security.auth_cmpl.key_present, - param->ble_security.auth_cmpl.key_type, - param->ble_security.auth_cmpl.success, - param->ble_security.auth_cmpl.fail_reason, - BLEUtils::devTypeToString(param->ble_security.auth_cmpl.dev_type) - ); - break; - } // ESP_GAP_BLE_AUTH_CMPL_EVT - - - // - // ESP_GAP_BLE_LOCAL_IR_EVT - // - case ESP_GAP_BLE_LOCAL_IR_EVT: { - break; - } // ESP_GAP_BLE_LOCAL_IR_EVT - - - // - // ESP_GAP_BLE_LOCAL_ER_EVT - // - case ESP_GAP_BLE_LOCAL_ER_EVT: { - break; - } // ESP_GAP_BLE_LOCAL_ER_EVT - - - // - // ESP_GAP_BLE_NC_REQ_EVT - // - case ESP_GAP_BLE_NC_REQ_EVT: { - ESP_LOGD(LOG_TAG, "[bd_addr: %s, passkey: %d]", - BLEAddress(param->ble_security.key_notif.bd_addr).toString().c_str(), - param->ble_security.key_notif.passkey); - break; - } // ESP_GAP_BLE_NC_REQ_EVT - - - // - // ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT - // - case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT: { - ESP_LOGD(LOG_TAG, "[status: %d]", param->scan_param_cmpl.status); - break; - } // ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT - - // - // ESP_GAP_BLE_SCAN_RESULT_EVT - // - // scan_rst: - // - search_evt - // - bda - // - dev_type - // - ble_addr_type - // - ble_evt_type - // - rssi - // - ble_adv - // - flag - // - num_resps - case ESP_GAP_BLE_SCAN_RESULT_EVT: { - switch(param->scan_rst.search_evt) { - case ESP_GAP_SEARCH_INQ_RES_EVT: { - ESP_LOGD(LOG_TAG, "search_evt: %s, bda: %s, dev_type: %s, ble_addr_type: %s, ble_evt_type: %s, rssi: %d, ble_adv: ??, flag: %d, num_resps: %d, adv_data_len: %d, scan_rsp_len: %d", - searchEventTypeToString(param->scan_rst.search_evt), - BLEAddress(param->scan_rst.bda).toString().c_str(), - devTypeToString(param->scan_rst.dev_type), - addressTypeToString(param->scan_rst.ble_addr_type), - eventTypeToString(param->scan_rst.ble_evt_type), - param->scan_rst.rssi, - param->scan_rst.flag, - param->scan_rst.num_resps, - param->scan_rst.adv_data_len, - param->scan_rst.scan_rsp_len - ); - break; - } // ESP_GAP_SEARCH_INQ_RES_EVT - - default: { - ESP_LOGD(LOG_TAG, "search_evt: %s",searchEventTypeToString(param->scan_rst.search_evt)); - break; - } - } - break; - } // ESP_GAP_BLE_SCAN_RESULT_EVT - - - // - // ESP_GAP_BLE_SCAN_START_COMPLETE_EVT - // - case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT: { - ESP_LOGD(LOG_TAG, "[status: %d]", param->scan_start_cmpl.status); - break; - } // ESP_GAP_BLE_SCAN_START_COMPLETE_EVT - - - // - // ESP_GAP_BLE_SEC_REQ_EVT - // - case ESP_GAP_BLE_SEC_REQ_EVT: { - ESP_LOGD(LOG_TAG, "[bd_addr: %s]", BLEAddress(param->ble_security.ble_req.bd_addr).toString().c_str()); - break; - } // ESP_GAP_BLE_SEC_REQ_EVT - - - // - // ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT - // - case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT: { - ESP_LOGD(LOG_TAG, "[status: %d]", param->scan_stop_cmpl.status); - break; - } // ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT - - default: { - ESP_LOGD(LOG_TAG, "*** dumpGapEvent: Logger not coded ***"); - break; - } // default - } // switch -} // dumpGapEvent - - -/** - * @brief Decode and dump a GATT client event - * - * @param [in] event The type of event received. - * @param [in] evtParam The data associated with the event. - */ -void BLEUtils::dumpGattClientEvent( - esp_gattc_cb_event_t event, - esp_gatt_if_t gattc_if, - esp_ble_gattc_cb_param_t *evtParam) { - - //esp_ble_gattc_cb_param_t *evtParam = (esp_ble_gattc_cb_param_t *)param; - ESP_LOGD(LOG_TAG, "GATT Event: %s", BLEUtils::gattClientEventTypeToString(event).c_str()); - switch(event) { - // - // ESP_GATTC_CLOSE_EVT - // - // close: - // - esp_gatt_status_t status - // - uint16_t conn_id - // - esp_bd_addr_t remote_bda - // - esp_gatt_conn_reason_t reason - // - case ESP_GATTC_CLOSE_EVT: { - ESP_LOGD(LOG_TAG, "[status: %s, reason:%s, conn_id: %d]", - BLEUtils::gattStatusToString(evtParam->close.status).c_str(), - BLEUtils::gattCloseReasonToString(evtParam->close.reason).c_str(), - evtParam->close.conn_id); - break; - } - - // - // ESP_GATTC_CONNECT_EVT - // - // connect: - // - esp_gatt_status_t status - // - uint16_t conn_id - // - esp_bd_addr_t remote_bda - case ESP_GATTC_CONNECT_EVT: { - ESP_LOGD(LOG_TAG, "[staus: %s, conn_id: %d, remote_bda: %s]", - BLEUtils::gattStatusToString(evtParam->connect.status).c_str(), - evtParam->connect.conn_id, - BLEAddress(evtParam->connect.remote_bda).toString().c_str() - ); - break; - } - - // - // ESP_GATTC_DISCONNECT_EVT - // - // disconnect: - // - esp_gatt_status_t status - // - uint16_t conn_id - // - esp_bd_addr_t remote_bda - case ESP_GATTC_DISCONNECT_EVT: { - ESP_LOGD(LOG_TAG, "[staus: %s, conn_id: %d, remote_bda: %s]", - BLEUtils::gattStatusToString(evtParam->disconnect.status).c_str(), - evtParam->disconnect.conn_id, - BLEAddress(evtParam->disconnect.remote_bda).toString().c_str() - ); - break; - } // ESP_GATTC_DISCONNECT_EVT - - // - // ESP_GATTC_GET_CHAR_EVT - // - // get_char: - // - esp_gatt_status_t status - // - uin1t6_t conn_id - // - esp_gatt_srvc_id_t srvc_id - // - esp_gatt_id_t char_id - // - esp_gatt_char_prop_t char_prop - // - case ESP_GATTC_GET_CHAR_EVT: { - - // If the status of the event shows that we have a value other than ESP_GATT_OK then the - // characteristic fields are not set to a usable value .. so don't try and log them. - if (evtParam->get_char.status == ESP_GATT_OK) { - std::string description = "Unknown"; - if (evtParam->get_char.char_id.uuid.len == ESP_UUID_LEN_16) { - description = BLEUtils::gattCharacteristicUUIDToString(evtParam->get_char.char_id.uuid.uuid.uuid16); - } - ESP_LOGD(LOG_TAG, "[status: %s, conn_id: %d, srvc_id: %s, char_id: %s [description: %s]\nchar_prop: %s]", - BLEUtils::gattStatusToString(evtParam->get_char.status).c_str(), - evtParam->get_char.conn_id, - BLEUtils::gattServiceIdToString(evtParam->get_char.srvc_id).c_str(), - gattIdToString(evtParam->get_char.char_id).c_str(), - description.c_str(), - BLEUtils::characteristicPropertiesToString(evtParam->get_char.char_prop).c_str() - ); - } else { - ESP_LOGD(LOG_TAG, "[status: %s, conn_id: %d, srvc_id: %s]", - BLEUtils::gattStatusToString(evtParam->get_char.status).c_str(), - evtParam->get_char.conn_id, - BLEUtils::gattServiceIdToString(evtParam->get_char.srvc_id).c_str() - ); - } - break; - } // ESP_GATTC_GET_CHAR_EVT - - // - // ESP_GATTC_NOTIFY_EVT - // - // notify - // uint16_t conn_id - // esp_bd_addr_t remote_bda - // esp_gatt_srvc_id_t srvc_id - // esp_gatt_id_t char_id - // esp_gatt_id_t descr_id - // uint16_t value_len - // uint8_t* value - // bool is_notify - // - case ESP_GATTC_NOTIFY_EVT: { - ESP_LOGD(LOG_TAG, "[conn_id: %d, remote_bda: %s, srvc_id: <%s>, char_id: <%s>, descr_id: <%s>, value_len: %d, is_notify: %d]", - evtParam->notify.conn_id, - BLEAddress(evtParam->notify.remote_bda).toString().c_str(), - BLEUtils::gattServiceIdToString(evtParam->notify.srvc_id).c_str(), - gattIdToString(evtParam->notify.char_id).c_str(), - gattIdToString(evtParam->notify.descr_id).c_str(), - evtParam->notify.value_len, - evtParam->notify.is_notify - ); - break; - } - - // - // ESP_GATTC_OPEN_EVT - // - // open: - // - esp_gatt_status_t status - // - uint16_t conn_id - // - esp_bd_addr_t remote_bda - // - uint16_t mtu - // - case ESP_GATTC_OPEN_EVT: { - ESP_LOGD(LOG_TAG, "[status: %s, conn_id: %d, remote_bda: %s, mtu: %d]", - BLEUtils::gattStatusToString(evtParam->open.status).c_str(), - evtParam->open.conn_id, - BLEAddress(evtParam->open.remote_bda).toString().c_str(), - evtParam->open.mtu); - break; - } // ESP_GATTC_OPEN_EVT - - - // - // ESP_GATTC_READ_CHAR_EVT - // - // Callback to indicate that requested data that we wanted to read is now available. - // - // read: - // esp_gatt_status_t status - // uint16_t conn_id - // esp_gatt_srvc_id_t srvc_id - // esp_gatt_id_t char_id - // esp_gatt_id_t descr_id - // uint8_t* value - // uint16_t value_type - // uint16_t value_len - case ESP_GATTC_READ_CHAR_EVT: { - ESP_LOGD(LOG_TAG, "[status: %s, conn_id: %d, srvc_id: <%s>, char_id: <%s>, descr_id: <%s>, value_type: 0x%x, value_len: %d]", - BLEUtils::gattStatusToString(evtParam->read.status).c_str(), - evtParam->read.conn_id, - BLEUtils::gattServiceIdToString(evtParam->read.srvc_id).c_str(), - gattIdToString(evtParam->read.char_id).c_str(), - gattIdToString(evtParam->read.descr_id).c_str(), - evtParam->read.value_type, - evtParam->read.value_len - ); - if (evtParam->read.status == ESP_GATT_OK) { - GeneralUtils::hexDump(evtParam->read.value, evtParam->read.value_len); - /* - char *pHexData = BLEUtils::buildHexData(nullptr, evtParam->read.value, evtParam->read.value_len); - ESP_LOGD(LOG_TAG, "value: %s \"%s\"", pHexData, BLEUtils::buildPrintData(evtParam->read.value, evtParam->read.value_len).c_str()); - free(pHexData); - */ - } - break; - } // ESP_GATTC_READ_CHAR_EVT - - - // - // ESP_GATTC_REG_EVT - // - // reg: - // - esp_gatt_status_t status - // - uint16_t app_id - // - case ESP_GATTC_REG_EVT: { - ESP_LOGD(LOG_TAG, "[status: %s, app_id: 0x%x]", - BLEUtils::gattStatusToString(evtParam->reg.status).c_str(), - evtParam->reg.app_id); - break; - } // ESP_GATTC_REG_EVT - - - // - // ESP_GATTC_REG_FOR_NOTIFY_EVT - // - // reg_for_notify: - // - esp_gatt_status_t status - // - esp_gatt_srvc_id_t srvc_id - // - esp_gatt_id_t char_id - case ESP_GATTC_REG_FOR_NOTIFY_EVT: { - ESP_LOGD(LOG_TAG, "[status: %s, srvc_id: <%s>, char_id: <%s>]", - BLEUtils::gattStatusToString(evtParam->reg_for_notify.status).c_str(), - BLEUtils::gattServiceIdToString(evtParam->reg_for_notify.srvc_id).c_str(), - gattIdToString(evtParam->reg_for_notify.char_id).c_str()); - break; - } // ESP_GATTC_REG_FOR_NOTIFY_EVT - - - // - // ESP_GATTC_SEARCH_CMPL_EVT - // - // search_cmpl: - // - esp_gatt_status_t status - // - uint16_t conn_id - // - case ESP_GATTC_SEARCH_CMPL_EVT: { - ESP_LOGD(LOG_TAG, "[status: %s, conn_id: %d]", - BLEUtils::gattStatusToString(evtParam->search_cmpl.status).c_str(), - evtParam->search_cmpl.conn_id); - break; - } // ESP_GATTC_SEARCH_CMPL_EVT - - - // - // ESP_GATTC_SEARCH_RES_EVT - // - // search_res: - // - uint16_t conn_id - // - esp_gatt_srvc_id_t srvc_id - // - case ESP_GATTC_SEARCH_RES_EVT: { - std::string name = ""; - if (evtParam->search_res.srvc_id.id.uuid.len == ESP_UUID_LEN_16) { - name = BLEUtils::gattServiceToString(evtParam->search_res.srvc_id.id.uuid.uuid.uuid16); - } - if (name.length() == 0) { - name = ""; - } - - ESP_LOGD(LOG_TAG, "[srvc_id: %s [%s], instanceId: 0x%.2x conn_id: %d]", - BLEUtils::gattServiceIdToString(evtParam->search_res.srvc_id).c_str(), - name.c_str(), - evtParam->search_res.srvc_id.id.inst_id, - evtParam->search_res.conn_id); - break; - } // ESP_GATTC_SEARCH_RES_EVT - - - // - // ESP_GATTC_WRITE_CHAR_EVT - // - // write: - // esp_gatt_status_t status - // uint16_t conn_id - // esp_gatt_srvc_id_t srvc_id - // esp_gatt_id_t char_id - // esp_gatt_id_t descr_id - case ESP_GATTC_WRITE_CHAR_EVT: { - ESP_LOGD(LOG_TAG, "[status: %s, conn_id: %d, srvc_id: <%s>, char_id: <%s>, descr_id: <%s>]", - BLEUtils::gattStatusToString(evtParam->write.status).c_str(), - evtParam->write.conn_id, - BLEUtils::gattServiceIdToString(evtParam->write.srvc_id).c_str(), - gattIdToString(evtParam->write.char_id).c_str(), - gattIdToString(evtParam->write.descr_id).c_str() - ); - break; - } - - default: - break; - } -} // dumpGattClientEvent - - -/** - * @brief Dump the details of a GATT server event. - * A GATT Server event is a callback received from the BLE subsystem when we are acting as a BLE - * server. The callback indicates the type of event in the `event` field. The `evtParam` is a - * union of structures where we can use the `event` to indicate which of the structures has been - * populated and hence is valid. - * - * @param [in] event The event type that was posted. - * @param [in] evtParam A union of structures only one of which is populated. - */ -void BLEUtils::dumpGattServerEvent( - esp_gatts_cb_event_t event, - esp_gatt_if_t gatts_if, - esp_ble_gatts_cb_param_t *evtParam) { - ESP_LOGD(LOG_TAG, "GATT ServerEvent: %s", BLEUtils::gattServerEventTypeToString(event).c_str()); - switch(event) { - - case ESP_GATTS_ADD_CHAR_DESCR_EVT: { - ESP_LOGD(LOG_TAG, "[status: %s, attr_handle: 0x%.2x, service_handle: 0x%.2x, char_uuid: %s]", - gattStatusToString(evtParam->add_char_descr.status).c_str(), - evtParam->add_char_descr.attr_handle, - evtParam->add_char_descr.service_handle, - BLEUUID(evtParam->add_char_descr.char_uuid).toString().c_str()); - break; - } // ESP_GATTS_ADD_CHAR_DESCR_EVT - - case ESP_GATTS_ADD_CHAR_EVT: { - ESP_LOGD(LOG_TAG, "[status: %s, attr_handle: 0x%.2x, service_handle: 0x%.2x, char_uuid: %s]", - gattStatusToString(evtParam->add_char.status).c_str(), - evtParam->add_char.attr_handle, - evtParam->add_char.service_handle, - BLEUUID(evtParam->add_char.char_uuid).toString().c_str()); - break; - } // ESP_GATTS_ADD_CHAR_EVT - - - // ESP_GATTS_CONF_EVT - // - // conf: - // - esp_gatt_status_t status – The status code. - // - uint16_t conn_id – The connection used. - // - case ESP_GATTS_CONF_EVT: { - ESP_LOGD(LOG_TAG, "[status: %s, conn_id: 0x%.2x]", - gattStatusToString(evtParam->conf.status).c_str(), - evtParam->conf.conn_id); - break; - } // ESP_GATTS_CONF_EVT - - - case ESP_GATTS_CONGEST_EVT: { - ESP_LOGD(LOG_TAG, "[conn_id: %d, congested: %d]", - evtParam->congest.conn_id, - evtParam->congest.congested); - break; - } // ESP_GATTS_CONGEST_EVT - - case ESP_GATTS_CONNECT_EVT: { - ESP_LOGD(LOG_TAG, "[conn_id: %d, remote_bda: %s, is_connected: %d]", - evtParam->connect.conn_id, - BLEAddress(evtParam->connect.remote_bda).toString().c_str(), - evtParam->connect.is_connected); - break; - } // ESP_GATTS_CONNECT_EVT - - case ESP_GATTS_CREATE_EVT: { - ESP_LOGD(LOG_TAG, "[status: %s, service_handle: 0x%.2x, service_id: [%s]]", - gattStatusToString(evtParam->create.status).c_str(), - evtParam->create.service_handle, - gattServiceIdToString(evtParam->create.service_id).c_str()); - break; - } // ESP_GATTS_CREATE_EVT - - case ESP_GATTS_DISCONNECT_EVT: { - ESP_LOGD(LOG_TAG, "[conn_id: %d, remote_bda: %s, is_connected: %d]", - evtParam->connect.conn_id, - BLEAddress(evtParam->connect.remote_bda).toString().c_str(), - evtParam->connect.is_connected); - break; - } // ESP_GATTS_DISCONNECT_EVT - - - // ESP_GATTS_EXEC_WRITE_EVT - // exec_write: - // - uint16_t conn_id - // - uint32_t trans_id - // - esp_bd_addr_t bda - // - uint8_t exec_write_flag - // - case ESP_GATTS_EXEC_WRITE_EVT: { - char* pWriteFlagText; - switch(evtParam->exec_write.exec_write_flag) { - case ESP_GATT_PREP_WRITE_EXEC: { - pWriteFlagText = (char*)"WRITE"; - break; - } - - case ESP_GATT_PREP_WRITE_CANCEL: { - pWriteFlagText = (char*)"CANCEL"; - break; - } - - default: - pWriteFlagText = (char*)""; - break; - } - - ESP_LOGD(LOG_TAG, "[conn_id: %d, trans_id: %d, bda: %s, exec_write_flag: 0x%.2x=%s]", - evtParam->exec_write.conn_id, - evtParam->exec_write.trans_id, - BLEAddress(evtParam->exec_write.bda).toString().c_str(), - evtParam->exec_write.exec_write_flag, - pWriteFlagText); - break; - } // ESP_GATTS_DISCONNECT_EVT - - - case ESP_GATTS_MTU_EVT: { - ESP_LOGD(LOG_TAG, "[conn_id: %d, mtu: %d]", - evtParam->mtu.conn_id, - evtParam->mtu.mtu); - break; - } // ESP_GATTS_MTU_EVT - - case ESP_GATTS_READ_EVT: { - ESP_LOGD(LOG_TAG, "[conn_id: %d, trans_id: %d, bda: %s, handle: 0x%.2x, is_long: %d, need_rsp:%d]", - evtParam->read.conn_id, - evtParam->read.trans_id, - BLEAddress(evtParam->read.bda).toString().c_str(), - evtParam->read.handle, - evtParam->read.is_long, - evtParam->read.need_rsp); - break; - } // ESP_GATTS_READ_EVT - - case ESP_GATTS_RESPONSE_EVT: { - ESP_LOGD(LOG_TAG, "[status: %s, handle: 0x%.2x]", - gattStatusToString(evtParam->rsp.status).c_str(), - evtParam->rsp.handle); - break; - } // ESP_GATTS_RESPONSE_EVT - - case ESP_GATTS_REG_EVT: { - ESP_LOGD(LOG_TAG, "[status: %s, app_id: %d]", - gattStatusToString(evtParam->reg.status).c_str(), - evtParam->reg.app_id); - break; - } // ESP_GATTS_REG_EVT - - - // ESP_GATTS_START_EVT - // - // start: - // - esp_gatt_status_t status - // - uint16_t service_handle - // - case ESP_GATTS_START_EVT: { - ESP_LOGD(LOG_TAG, "[status: %s, service_handle: 0x%.2x]", - gattStatusToString(evtParam->start.status).c_str(), - evtParam->start.service_handle); - break; - } // ESP_GATTS_START_EVT - - - // ESP_GATTS_WRITE_EVT - // - // write: - // - uint16_t conn_id – The connection id. - // - uint16_t trans_id – The transfer id. - // - esp_bd_addr_t bda – The address of the partner. - // - uint16_t handle – The attribute handle. - // - uint16_t offset – The offset of the currently received within the whole value. - // - bool need_rsp – Do we need a response? - // - bool is_prep – Is this a write prepare? If set, then this is to be considered part of the received value and not the whole value. A subsequent ESP_GATTS_EXEC_WRITE will mark the total. - // - uint16_t len – The length of the incoming value part. - // - uint8_t* value – The data for this value part. - // - case ESP_GATTS_WRITE_EVT: { - ESP_LOGD(LOG_TAG, "[conn_id: %d, trans_id: %d, bda: %s, handle: 0x%.2x, offset: %d, need_rsp: %d, is_prep: %d, len: %d]", - evtParam->write.conn_id, - evtParam->write.trans_id, - BLEAddress(evtParam->write.bda).toString().c_str(), - evtParam->write.handle, - evtParam->write.offset, - evtParam->write.need_rsp, - evtParam->write.is_prep, - evtParam->write.len); - char *pHex = buildHexData(nullptr, evtParam->write.value, evtParam->write.len); - ESP_LOGD(LOG_TAG, "[Data: %s]", pHex); - free(pHex); - break; - } // ESP_GATTS_WRITE_EVT - - default: - ESP_LOGD(LOG_TAG, "dumpGattServerEvent: *** NOT CODED ***"); - break; - } -} // dumpGattServerEvent - - -/** - * @brief Convert a BLE event type to a string. - * @param [in] eventType The event type. - * @return The event type as a string. - */ -const char* BLEUtils::eventTypeToString(esp_ble_evt_type_t eventType) { - switch(eventType) { - case ESP_BLE_EVT_CONN_ADV: - return "ESP_BLE_EVT_CONN_ADV"; - case ESP_BLE_EVT_CONN_DIR_ADV: - return "ESP_BLE_EVT_CONN_DIR_ADV"; - case ESP_BLE_EVT_DISC_ADV: - return "ESP_BLE_EVT_DISC_ADV"; - case ESP_BLE_EVT_NON_CONN_ADV: - return "ESP_BLE_EVT_NON_CONN_ADV"; - case ESP_BLE_EVT_SCAN_RSP: - return "ESP_BLE_EVT_SCAN_RSP"; - default: - ESP_LOGD(LOG_TAG, "Unknown esp_ble_evt_type_t: %d", eventType); - return "*** Unknown ***"; - } -} // eventTypeToString - - - -/** - * @brief Convert a BT GAP event type to a string representation. - * @param [in] eventType The type of event. - * @return A string representation of the event type. - */ -const char* BLEUtils::gapEventToString(uint32_t eventType) { - switch(eventType) { - case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT: - return "ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT"; - case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: - return "ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT"; - case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: - return "ESP_GAP_BLE_ADV_START_COMPLETE_EVT"; - case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT: - return "ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT"; - case ESP_GAP_BLE_SCAN_RESULT_EVT: - return "ESP_GAP_BLE_SCAN_RESULT_EVT"; - case ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT: - return "ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT"; - case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT: - return "ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT"; - case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT: - return "ESP_GAP_BLE_SCAN_START_COMPLETE_EVT"; - case ESP_GAP_BLE_AUTH_CMPL_EVT: /* Authentication complete indication. */ - return "ESP_GAP_BLE_AUTH_CMPL_EVT"; - case ESP_GAP_BLE_KEY_EVT: /* BLE key event for peer device keys */ - return "ESP_GAP_BLE_KEY_EVT"; - case ESP_GAP_BLE_SEC_REQ_EVT: /* BLE security request */ - return "ESP_GAP_BLE_SEC_REQ_EVT"; - case ESP_GAP_BLE_PASSKEY_NOTIF_EVT: /* passkey notification event */ - return "ESP_GAP_BLE_PASSKEY_NOTIF_EVT"; - case ESP_GAP_BLE_PASSKEY_REQ_EVT: /* passkey request event */ - return "ESP_GAP_BLE_PASSKEY_REQ_EVT"; - case ESP_GAP_BLE_OOB_REQ_EVT: /* OOB request event */ - return "ESP_GAP_BLE_OOB_REQ_EVT"; - case ESP_GAP_BLE_LOCAL_IR_EVT: /* BLE local IR event */ - return "ESP_GAP_BLE_LOCAL_IR_EVT"; - case ESP_GAP_BLE_LOCAL_ER_EVT: /* BLE local ER event */ - return "ESP_GAP_BLE_LOCAL_ER_EVT"; - case ESP_GAP_BLE_NC_REQ_EVT: /* Numeric Comparison request event */ - return "ESP_GAP_BLE_NC_REQ_EVT"; - case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT: /*!< When stop adv complete, the event comes */ - return "ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT"; - case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT: - return "ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT"; - default: - ESP_LOGD(LOG_TAG, "gapEventToString: Unknown event type 0x%x", eventType); - return "Unknown event type"; - } -} // gapEventToString - - -std::string BLEUtils::gattCharacteristicUUIDToString(uint32_t characteristicUUID) { - characteristicMap_t *p = g_characteristicsMappings; - while (p->name.length() > 0) { - if (p->assignedNumber == characteristicUUID) { - return p->name; - } - p++; - } - return "Unknown"; -} // gattCharacteristicUUIDToString - - -/** - * @brief Convert an esp_gatt_srvc_id_t to a string. - */ -std::string BLEUtils::gattServiceIdToString(esp_gatt_srvc_id_t srvcId) { - return gattIdToString(srvcId.id); -} // gattServiceIdToString - - -std::string BLEUtils::gattServiceToString(uint32_t serviceId) { - gattService_t* p = (gattService_t *)g_gattServices; - while (p->name.length() > 0) { - if (p->assignedNumber == serviceId) { - return p->name; - } - p++; - } - return "Unknown"; -} // gattServiceToString - - -/** - * @brief Convert a GATT status to a string. - * - * @param [in] status The status to convert. - * @return A string representation of the status. - */ -std::string BLEUtils::gattStatusToString(esp_gatt_status_t status) { - switch(status) { - case ESP_GATT_OK: - return "ESP_GATT_OK"; - case ESP_GATT_INVALID_HANDLE: - return "ESP_GATT_INVALID_HANDLE"; - case ESP_GATT_READ_NOT_PERMIT: - return "ESP_GATT_READ_NOT_PERMIT"; - case ESP_GATT_WRITE_NOT_PERMIT: - return "ESP_GATT_WRITE_NOT_PERMIT"; - case ESP_GATT_INVALID_PDU: - return "ESP_GATT_INVALID_PDU"; - case ESP_GATT_INSUF_AUTHENTICATION: - return "ESP_GATT_INSUF_AUTHENTICATION"; - case ESP_GATT_REQ_NOT_SUPPORTED: - return "ESP_GATT_REQ_NOT_SUPPORTED"; - case ESP_GATT_INVALID_OFFSET: - return "ESP_GATT_INVALID_OFFSET"; - case ESP_GATT_INSUF_AUTHORIZATION: - return "ESP_GATT_INSUF_AUTHORIZATION"; - case ESP_GATT_PREPARE_Q_FULL: - return "ESP_GATT_PREPARE_Q_FULL"; - case ESP_GATT_NOT_FOUND: - return "ESP_GATT_NOT_FOUND"; - case ESP_GATT_NOT_LONG: - return "ESP_GATT_NOT_LONG"; - case ESP_GATT_INSUF_KEY_SIZE: - return "ESP_GATT_INSUF_KEY_SIZE"; - case ESP_GATT_INVALID_ATTR_LEN: - return "ESP_GATT_INVALID_ATTR_LEN"; - case ESP_GATT_ERR_UNLIKELY: - return "ESP_GATT_ERR_UNLIKELY"; - case ESP_GATT_INSUF_ENCRYPTION: - return "ESP_GATT_INSUF_ENCRYPTION"; - case ESP_GATT_UNSUPPORT_GRP_TYPE: - return "ESP_GATT_UNSUPPORT_GRP_TYPE"; - case ESP_GATT_INSUF_RESOURCE: - return "ESP_GATT_INSUF_RESOURCE"; - case ESP_GATT_NO_RESOURCES: - return "ESP_GATT_NO_RESOURCES"; - case ESP_GATT_INTERNAL_ERROR: - return "ESP_GATT_INTERNAL_ERROR"; - case ESP_GATT_WRONG_STATE: - return "ESP_GATT_WRONG_STATE"; - case ESP_GATT_DB_FULL: - return "ESP_GATT_DB_FULL"; - case ESP_GATT_BUSY: - return "ESP_GATT_BUSY"; - case ESP_GATT_ERROR: - return "ESP_GATT_ERROR"; - case ESP_GATT_CMD_STARTED: - return "ESP_GATT_CMD_STARTED"; - case ESP_GATT_ILLEGAL_PARAMETER: - return "ESP_GATT_ILLEGAL_PARAMETER"; - case ESP_GATT_PENDING: - return "ESP_GATT_PENDING"; - case ESP_GATT_AUTH_FAIL: - return "ESP_GATT_AUTH_FAIL"; - case ESP_GATT_MORE: - return "ESP_GATT_MORE"; - case ESP_GATT_INVALID_CFG: - return "ESP_GATT_INVALID_CFG"; - case ESP_GATT_SERVICE_STARTED: - return "ESP_GATT_SERVICE_STARTED"; - case ESP_GATT_ENCRYPED_NO_MITM: - return "ESP_GATT_ENCRYPED_NO_MITM"; - case ESP_GATT_NOT_ENCRYPTED: - return "ESP_GATT_NOT_ENCRYPTED"; - case ESP_GATT_CONGESTED: - return "ESP_GATT_CONGESTED"; - case ESP_GATT_DUP_REG: - return "ESP_GATT_DUP_REG"; - case ESP_GATT_ALREADY_OPEN: - return "ESP_GATT_ALREADY_OPEN"; - case ESP_GATT_CANCEL: - return "ESP_GATT_CANCEL"; - case ESP_GATT_CCC_CFG_ERR: - return "ESP_GATT_CCC_CFG_ERR"; - case ESP_GATT_PRC_IN_PROGRESS: - return "ESP_GATT_PRC_IN_PROGRESS"; - default: - return "Unknown"; - } -} // gattStatusToString - - -/** - * @brief convert a GAP search event to a string. - * @param [in] searchEvt - * @return The search event type as a string. - */ -const char* BLEUtils::searchEventTypeToString(esp_gap_search_evt_t searchEvt) { - switch(searchEvt) { - case ESP_GAP_SEARCH_INQ_RES_EVT: - return "ESP_GAP_SEARCH_INQ_RES_EVT"; - case ESP_GAP_SEARCH_INQ_CMPL_EVT: - return "ESP_GAP_SEARCH_INQ_CMPL_EVT"; - case ESP_GAP_SEARCH_DISC_RES_EVT: - return "ESP_GAP_SEARCH_DISC_RES_EVT"; - case ESP_GAP_SEARCH_DISC_BLE_RES_EVT: - return "ESP_GAP_SEARCH_DISC_BLE_RES_EVT"; - case ESP_GAP_SEARCH_DISC_CMPL_EVT: - return "ESP_GAP_SEARCH_DISC_CMPL_EVT"; - case ESP_GAP_SEARCH_DI_DISC_CMPL_EVT: - return "ESP_GAP_SEARCH_DI_DISC_CMPL_EVT"; - case ESP_GAP_SEARCH_SEARCH_CANCEL_CMPL_EVT: - return "ESP_GAP_SEARCH_SEARCH_CANCEL_CMPL_EVT"; - default: - ESP_LOGD(LOG_TAG, "Unknown event type: 0x%x", searchEvt); - return "Unknown event type"; - } -} // searchEventTypeToString - -#endif // CONFIG_BT_ENABLED diff --git a/ESP32_BLE_Arduino/src/BLEUtils.h b/ESP32_BLE_Arduino/src/BLEUtils.h deleted file mode 100644 index 28c7a7e..0000000 --- a/ESP32_BLE_Arduino/src/BLEUtils.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * BLEUtils.h - * - * Created on: Mar 25, 2017 - * Author: kolban - */ - -#ifndef COMPONENTS_CPP_UTILS_BLEUTILS_H_ -#define COMPONENTS_CPP_UTILS_BLEUTILS_H_ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) -#include // ESP32 BLE -#include // ESP32 BLE -#include // ESP32 BLE -#include -#include "BLEClient.h" - -/** - * @brief A set of general %BLE utilities. - */ -class BLEUtils { -public: - static const char* advTypeToString(uint8_t advType); - static esp_gatt_id_t buildGattId(esp_bt_uuid_t uuid, uint8_t inst_id=0); - - static esp_gatt_srvc_id_t buildGattSrvcId(esp_gatt_id_t gattId, bool is_primary=true); - static std::string characteristicPropertiesToString(esp_gatt_char_prop_t prop); - static char* buildHexData(uint8_t *target, uint8_t *source, uint8_t length); - static BLEClient* findByConnId(uint16_t conn_id); - static BLEClient* findByAddress(BLEAddress address); - static std::string gattClientEventTypeToString(esp_gattc_cb_event_t eventType); - static std::string gattServerEventTypeToString(esp_gatts_cb_event_t eventType); - static std::string gattServiceIdToString(esp_gatt_srvc_id_t srvcId); - static std::string gattStatusToString(esp_gatt_status_t status); - static std::string gattServiceToString(uint32_t serviceId); - static std::string gattCloseReasonToString(esp_gatt_conn_reason_t reason); - static void registerByAddress(BLEAddress address, BLEClient* pDevice); - static void registerByConnId(uint16_t conn_id, BLEClient* pDevice); - static std::string gattCharacteristicUUIDToString(uint32_t characteristicUUID); - static std::string buildPrintData(uint8_t* source, size_t length); - static void dumpGattClientEvent( - esp_gattc_cb_event_t event, - esp_gatt_if_t gattc_if, - esp_ble_gattc_cb_param_t* evtParam); - static void dumpGattServerEvent( - esp_gatts_cb_event_t event, - esp_gatt_if_t gatts_if, - esp_ble_gatts_cb_param_t* evtParam); - static const char* devTypeToString(esp_bt_dev_type_t type); - static void dumpGapEvent( - esp_gap_ble_cb_event_t event, - esp_ble_gap_cb_param_t* param); - static const char* gapEventToString(uint32_t eventType); - static const char* searchEventTypeToString(esp_gap_search_evt_t searchEvt); - static const char* addressTypeToString(esp_ble_addr_type_t type); - static const char *eventTypeToString(esp_ble_evt_type_t eventType); -}; - -#endif // CONFIG_BT_ENABLED -#endif /* COMPONENTS_CPP_UTILS_BLEUTILS_H_ */ diff --git a/ESP32_BLE_Arduino/src/BLEValue.cpp b/ESP32_BLE_Arduino/src/BLEValue.cpp deleted file mode 100644 index 1989993..0000000 --- a/ESP32_BLE_Arduino/src/BLEValue.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/* - * BLEValue.cpp - * - * Created on: Jul 17, 2017 - * Author: kolban - */ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) - -#include - -#include "BLEValue.h" - -static const char* LOG_TAG="BLEValue"; - -BLEValue::BLEValue() { - m_accumulation = ""; - m_value = ""; - m_readOffset = 0; -} // BLEValue - - -/** - * @brief Add a message part to the accumulation. - * The accumulation is a growing set of data that is added to until a commit or cancel. - * @param [in] part A message part being added. - */ -void BLEValue::addPart(std::string part) { - ESP_LOGD(LOG_TAG, ">> addPart: length=%d", part.length()); - m_accumulation += part; -} // addPart - - -/** - * @brief Add a message part to the accumulation. - * The accumulation is a growing set of data that is added to until a commit or cancel. - * @param [in] pData A message part being added. - * @param [in] length The number of bytes being added. - */ -void BLEValue::addPart(uint8_t* pData, size_t length) { - ESP_LOGD(LOG_TAG, ">> addPart: length=%d", length); - m_accumulation += std::string((char *)pData, length); -} // addPart - - -/** - * @brief Cancel the current accumulation. - */ -void BLEValue::cancel() { - ESP_LOGD(LOG_TAG, ">> cancel"); - m_accumulation = ""; - m_readOffset = 0; -} // cancel - - -/** - * @brief Commit the current accumulation. - * When writing a value, we may find that we write it in "parts" meaning that the writes come in in pieces - * of the overall message. After the last part has been received, we may perform a commit which means that - * we now have the complete message and commit the change as a unit. - */ -void BLEValue::commit() { - ESP_LOGD(LOG_TAG, ">> commit"); - // If there is nothing to commit, do nothing. - if (m_accumulation.length() == 0) { - return; - } - setValue(m_accumulation); - m_accumulation = ""; - m_readOffset = 0; -} // commit - - -/** - * @brief Get the read offset. - * @return The read offset into the read. - */ -uint16_t BLEValue::getReadOffset() { - return m_readOffset; -} // getReadOffset - - -/** - * @brief Get the current value. - */ -std::string BLEValue::getValue() { - return m_value; -} // getValue - - -/** - * @brief Set the read offset - * @param [in] readOffset The offset into the read. - */ -void BLEValue::setReadOffset(uint16_t readOffset) { - m_readOffset = readOffset; -} // setReadOffset - - -/** - * @brief Set the current value. - */ -void BLEValue::setValue(std::string value) { - m_value = value; -} // setValue - - -/** - * @brief Set the current value. - * @param [in] pData The data for the current value. - * @param [in] The length of the new current value. - */ -void BLEValue::setValue(uint8_t* pData, size_t length) { - m_value = std::string((char*)pData, length); -} // setValue -#endif // CONFIG_BT_ENABLED diff --git a/ESP32_BLE_Arduino/src/BLEValue.h b/ESP32_BLE_Arduino/src/BLEValue.h deleted file mode 100644 index a292c6e..0000000 --- a/ESP32_BLE_Arduino/src/BLEValue.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * BLEValue.h - * - * Created on: Jul 17, 2017 - * Author: kolban - */ - -#ifndef COMPONENTS_CPP_UTILS_BLEVALUE_H_ -#define COMPONENTS_CPP_UTILS_BLEVALUE_H_ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) -#include - -/** - * @brief The model of a %BLE value. - */ -class BLEValue { -public: - BLEValue(); - void addPart(std::string part); - void addPart(uint8_t* pData, size_t length); - void cancel(); - void commit(); - uint16_t getReadOffset(); - std::string getValue(); - void setReadOffset(uint16_t readOffset); - void setValue(std::string value); - void setValue(uint8_t* pData, size_t length); - -private: - std::string m_accumulation; - uint16_t m_readOffset; - std::string m_value; -}; -#endif // CONFIG_BT_ENABLED -#endif /* COMPONENTS_CPP_UTILS_BLEVALUE_H_ */ diff --git a/ESP32_BLE_Arduino/src/FreeRTOS.cpp b/ESP32_BLE_Arduino/src/FreeRTOS.cpp deleted file mode 100644 index 663128d..0000000 --- a/ESP32_BLE_Arduino/src/FreeRTOS.cpp +++ /dev/null @@ -1,165 +0,0 @@ -/* - * FreeRTOS.cpp - * - * Created on: Feb 24, 2017 - * Author: kolban - */ -#include -#include -#include -#include -#include -#include "FreeRTOS.h" -#include -#include "sdkconfig.h" - -static const char* LOG_TAG = "FreeRTOS"; - -/** - * Sleep for the specified number of milliseconds. - * @param[in] ms The period in milliseconds for which to sleep. - */ -void FreeRTOS::sleep(uint32_t ms) { - ::vTaskDelay(ms/portTICK_PERIOD_MS); -} // sleep - - -/** - * Start a new task. - * @param[in] task The function pointer to the function to be run in the task. - * @param[in] taskName A string identifier for the task. - * @param[in] param An optional parameter to be passed to the started task. - * @param[in] stackSize An optional paremeter supplying the size of the stack in which to run the task. - */ -void FreeRTOS::startTask(void task(void*), std::string taskName, void *param, int stackSize) { - ::xTaskCreate(task, taskName.data(), stackSize, param, 5, NULL); -} // startTask - - -/** - * Delete the task. - * @param[in] pTask An optional handle to the task to be deleted. If not supplied the calling task will be deleted. - */ -void FreeRTOS::deleteTask(TaskHandle_t pTask) { - ::vTaskDelete(pTask); -} // deleteTask - - -/** - * Get the time in milliseconds since the %FreeRTOS scheduler started. - * @return The time in milliseconds since the %FreeRTOS scheduler started. - */ -uint32_t FreeRTOS::getTimeSinceStart() { - return (uint32_t)(xTaskGetTickCount()*portTICK_PERIOD_MS); -} // getTimeSinceStart - -/* - * public: - Semaphore(std::string = ""); - ~Semaphore(); - void give(); - void take(std::string owner=""); - void take(uint32_t timeoutMs, std::string owner=""); - private: - SemaphoreHandle_t m_semaphore; - std::string m_name; - std::string m_owner; - }; - * - */ - -/** - * @brief Wait for a semaphore to be released by trying to take it and - * then releasing it again. - * @param [in] owner A debug tag. - * @return The value associated with the semaphore. - */ -uint32_t FreeRTOS::Semaphore::wait(std::string owner) { - ESP_LOGV(LOG_TAG, "Semaphore waiting: %s for %s", toString().c_str(), owner.c_str()); - xSemaphoreTake(m_semaphore, portMAX_DELAY); - m_owner = owner; - xSemaphoreGive(m_semaphore); - ESP_LOGV(LOG_TAG, "Semaphore released: %s", toString().c_str()); - m_owner = ""; - return m_value; -} // wait - -FreeRTOS::Semaphore::Semaphore(std::string name) { - m_semaphore = xSemaphoreCreateMutex(); - m_name = name; - m_owner = ""; - m_value = 0; -} - -FreeRTOS::Semaphore::~Semaphore() { - vSemaphoreDelete(m_semaphore); -} - - -/** - * @brief Give a semaphore. - * The Semaphore is given. - */ -void FreeRTOS::Semaphore::give() { - xSemaphoreGive(m_semaphore); - ESP_LOGV(LOG_TAG, "Semaphore giving: %s", toString().c_str()); - m_owner = ""; -} // Semaphore::give - - -/** - * @brief Give a semaphore. - * The Semaphore is given with an associated value. - * @param [in] value The value to associate with the semaphore. - */ -void FreeRTOS::Semaphore::give(uint32_t value) { - m_value = value; - give(); -} - - -/** - * @brief Give a semaphore from an ISR. - */ -void FreeRTOS::Semaphore::giveFromISR() { - BaseType_t higherPriorityTaskWoken; - xSemaphoreGiveFromISR(m_semaphore, &higherPriorityTaskWoken); -} // giveFromISR - - -/** - * @brief Take a semaphore. - * Take a semaphore and wait indefinitely. - */ -void FreeRTOS::Semaphore::take(std::string owner) -{ - - ESP_LOGV(LOG_TAG, "Semaphore taking: %s for %s", toString().c_str(), owner.c_str()); - xSemaphoreTake(m_semaphore, portMAX_DELAY); - m_owner = owner; - ESP_LOGV(LOG_TAG, "Semaphore taken: %s", toString().c_str()); -} // Semaphore::take - - -/** - * @brief Take a semaphore. - * Take a semaphore but return if we haven't obtained it in the given period of milliseconds. - * @param [in] timeoutMs Timeout in milliseconds. - */ -void FreeRTOS::Semaphore::take(uint32_t timeoutMs, std::string owner) { - ESP_LOGV(LOG_TAG, "Semaphore taking: %s for %s", toString().c_str(), owner.c_str()); - m_owner = owner; - xSemaphoreTake(m_semaphore, timeoutMs/portTICK_PERIOD_MS); - ESP_LOGV(LOG_TAG, "Semaphore taken: %s", toString().c_str()); -} // Semaphore::take - -std::string FreeRTOS::Semaphore::toString() { - std::stringstream stringStream; - stringStream << "name: "<< m_name << " (0x" << std::hex << std::setfill('0') << (uint32_t)m_semaphore << "), owner: " << m_owner; - return stringStream.str(); -} - -void FreeRTOS::Semaphore::setName(std::string name) { - m_name = name; -} - diff --git a/ESP32_BLE_Arduino/src/FreeRTOS.h b/ESP32_BLE_Arduino/src/FreeRTOS.h deleted file mode 100644 index 320f4cc..0000000 --- a/ESP32_BLE_Arduino/src/FreeRTOS.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * FreeRTOS.h - * - * Created on: Feb 24, 2017 - * Author: kolban - */ - -#ifndef MAIN_FREERTOS_H_ -#define MAIN_FREERTOS_H_ -#include -#include - -#include -#include -#include - - -/** - * @brief Interface to %FreeRTOS functions. - */ -class FreeRTOS { -public: - static void sleep(uint32_t ms); - static void startTask(void task(void *), std::string taskName, void *param=nullptr, int stackSize = 2048); - static void deleteTask(TaskHandle_t pTask = nullptr); - - static uint32_t getTimeSinceStart(); - - class Semaphore { - public: - Semaphore(std::string owner = ""); - ~Semaphore(); - void give(); - void giveFromISR(); - void give(uint32_t value); - void setName(std::string name); - void take(std::string owner=""); - void take(uint32_t timeoutMs, std::string owner=""); - uint32_t wait(std::string owner=""); - std::string toString(); - private: - SemaphoreHandle_t m_semaphore; - std::string m_name; - std::string m_owner; - uint32_t m_value; - }; -}; - -#endif /* MAIN_FREERTOS_H_ */ diff --git a/ESP32_BLE_Arduino/src/GeneralUtils.cpp b/ESP32_BLE_Arduino/src/GeneralUtils.cpp deleted file mode 100644 index 4237b14..0000000 --- a/ESP32_BLE_Arduino/src/GeneralUtils.cpp +++ /dev/null @@ -1,388 +0,0 @@ -/* - * GeneralUtils.cpp - * - * Created on: May 20, 2017 - * Author: kolban - */ - -#include "GeneralUtils.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static const char* LOG_TAG = "GeneralUtils"; - -static const char kBase64Alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/"; - -GeneralUtils::GeneralUtils() { - // TODO Auto-generated constructor stub - -} - -GeneralUtils::~GeneralUtils() { - // TODO Auto-generated destructor stub -} - -static int base64EncodedLength(size_t length) { - return (length + 2 - ((length + 2) % 3)) / 3 * 4; -} // base64EncodedLength - - -static int base64EncodedLength(const std::string &in) { - return base64EncodedLength(in.length()); -} // base64EncodedLength - - -static void a3_to_a4(unsigned char * a4, unsigned char * a3) { - a4[0] = (a3[0] & 0xfc) >> 2; - a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4); - a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6); - a4[3] = (a3[2] & 0x3f); -} // a3_to_a4 - - -static void a4_to_a3(unsigned char * a3, unsigned char * a4) { - a3[0] = (a4[0] << 2) + ((a4[1] & 0x30) >> 4); - a3[1] = ((a4[1] & 0xf) << 4) + ((a4[2] & 0x3c) >> 2); - a3[2] = ((a4[2] & 0x3) << 6) + a4[3]; -} // a4_to_a3 - - -/** - * @brief Encode a string into base 64. - * @param [in] in - * @param [out] out - */ -bool GeneralUtils::base64Encode(const std::string &in, std::string *out) { - int i = 0, j = 0; - size_t enc_len = 0; - unsigned char a3[3]; - unsigned char a4[4]; - - out->resize(base64EncodedLength(in)); - - int input_len = in.size(); - std::string::const_iterator input = in.begin(); - - while (input_len--) { - a3[i++] = *(input++); - if (i == 3) { - a3_to_a4(a4, a3); - - for (i = 0; i < 4; i++) { - (*out)[enc_len++] = kBase64Alphabet[a4[i]]; - } - - i = 0; - } - } - - if (i) { - for (j = i; j < 3; j++) { - a3[j] = '\0'; - } - - a3_to_a4(a4, a3); - - for (j = 0; j < i + 1; j++) { - (*out)[enc_len++] = kBase64Alphabet[a4[j]]; - } - - while ((i++ < 3)) { - (*out)[enc_len++] = '='; - } - } - - return (enc_len == out->size()); -} // base64Encode - - -static int DecodedLength(const std::string &in) { - int numEq = 0; - int n = in.size(); - - for (std::string::const_reverse_iterator it = in.rbegin(); *it == '='; ++it) { - ++numEq; - } - return ((6 * n) / 8) - numEq; -} // DecodedLength - - -static unsigned char b64_lookup(unsigned char c) { - if(c >='A' && c <='Z') return c - 'A'; - if(c >='a' && c <='z') return c - 71; - if(c >='0' && c <='9') return c + 4; - if(c == '+') return 62; - if(c == '/') return 63; - return 255; -}; // b64_lookup - - -/** - * @brief Decode a chunk of data that is base64 encoded. - * @param [in] in The string to be decoded. - * @param [out] out The resulting data. - */ -bool GeneralUtils::base64Decode(const std::string &in, std::string *out) { - int i = 0, j = 0; - size_t dec_len = 0; - unsigned char a3[3]; - unsigned char a4[4]; - - int input_len = in.size(); - std::string::const_iterator input = in.begin(); - - out->resize(DecodedLength(in)); - - while (input_len--) { - if (*input == '=') { - break; - } - - a4[i++] = *(input++); - if (i == 4) { - for (i = 0; i <4; i++) { - a4[i] = b64_lookup(a4[i]); - } - - a4_to_a3(a3,a4); - - for (i = 0; i < 3; i++) { - (*out)[dec_len++] = a3[i]; - } - - i = 0; - } - } - - if (i) { - for (j = i; j < 4; j++) { - a4[j] = '\0'; - } - - for (j = 0; j < 4; j++) { - a4[j] = b64_lookup(a4[j]); - } - - a4_to_a3(a3,a4); - - for (j = 0; j < i - 1; j++) { - (*out)[dec_len++] = a3[j]; - } - } - - return (dec_len == out->size()); - } // base64Decode - -/* -void GeneralUtils::hexDump(uint8_t* pData, uint32_t length) { - uint32_t index=0; - std::stringstream ascii; - std::stringstream hex; - char asciiBuf[80]; - char hexBuf[80]; - hex.str(""); - ascii.str(""); - while(index < length) { - hex << std::setfill('0') << std::setw(2) << std::hex << (int)pData[index] << ' '; - if (std::isprint(pData[index])) { - ascii << pData[index]; - } else { - ascii << '.'; - } - index++; - if (index % 16 == 0) { - strcpy(hexBuf, hex.str().c_str()); - strcpy(asciiBuf, ascii.str().c_str()); - ESP_LOGD(tag, "%s %s", hexBuf, asciiBuf); - hex.str(""); - ascii.str(""); - } - } - if (index %16 != 0) { - while(index % 16 != 0) { - hex << " "; - index++; - } - strcpy(hexBuf, hex.str().c_str()); - strcpy(asciiBuf, ascii.str().c_str()); - ESP_LOGD(tag, "%s %s", hexBuf, asciiBuf); - //ESP_LOGD(tag, "%s %s", hex.str().c_str(), ascii.str().c_str()); - } - FreeRTOS::sleep(1000); -} -*/ - -/* -void GeneralUtils::hexDump(uint8_t* pData, uint32_t length) { - uint32_t index=0; - static std::stringstream ascii; - static std::stringstream hex; - hex.str(""); - ascii.str(""); - while(index < length) { - hex << std::setfill('0') << std::setw(2) << std::hex << (int)pData[index] << ' '; - if (std::isprint(pData[index])) { - ascii << pData[index]; - } else { - ascii << '.'; - } - index++; - if (index % 16 == 0) { - ESP_LOGD(tag, "%s %s", hex.str().c_str(), ascii.str().c_str()); - hex.str(""); - ascii.str(""); - } - } - if (index %16 != 0) { - while(index % 16 != 0) { - hex << " "; - index++; - } - ESP_LOGD(tag, "%s %s", hex.str().c_str(), ascii.str().c_str()); - } - FreeRTOS::sleep(1000); -} -*/ - -/** - * @brief Dump a representation of binary data to the console. - * - * @param [in] pData Pointer to the start of data to be logged. - * @param [in] length Length of the data (in bytes) to be logged. - * @return N/A. - */ -void GeneralUtils::hexDump(uint8_t* pData, uint32_t length) { - char ascii[80]; - char hex[80]; - char tempBuf[80]; - uint32_t lineNumber = 0; - - ESP_LOGD(LOG_TAG, " 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f ----------------"); - strcpy(ascii, ""); - strcpy(hex, ""); - uint32_t index=0; - while(index < length) { - sprintf(tempBuf, "%.2x ", pData[index]); - strcat(hex, tempBuf); - if (isprint(pData[index])) { - sprintf(tempBuf, "%c", pData[index]); - } else { - sprintf(tempBuf, "."); - } - strcat(ascii, tempBuf); - index++; - if (index % 16 == 0) { - ESP_LOGD(LOG_TAG, "%.4x %s %s", lineNumber*16, hex, ascii); - strcpy(ascii, ""); - strcpy(hex, ""); - lineNumber++; - } - } - if (index %16 != 0) { - while(index % 16 != 0) { - strcat(hex, " "); - index++; - } - ESP_LOGD(LOG_TAG, "%.4x %s %s", lineNumber*16, hex, ascii); - } -} // hexDump - -/** - * @brief Convert an IP address to string. - * @param ip The 4 byte IP address. - * @return A string representation of the IP address. - */ -std::string GeneralUtils::ipToString(uint8_t *ip) { - std::stringstream s; - s << (int)ip[0] << '.' << (int)ip[1] << '.' << (int)ip[2] << '.' << (int)ip[3]; - return s.str(); -} // ipToString - - -/** - * @brief Convert an ESP error code to a string. - * @param [in] errCode The errCode to be converted. - * @return A string representation of the error code. - */ -const char* GeneralUtils::errorToString(esp_err_t errCode) { - switch(errCode) { - case ESP_OK: - return "OK"; - case ESP_FAIL: - return "Fail"; - case ESP_ERR_NO_MEM: - return "No memory"; - case ESP_ERR_INVALID_ARG: - return "Invalid argument"; - case ESP_ERR_INVALID_SIZE: - return "Invalid state"; - case ESP_ERR_INVALID_STATE: - return "Invalid state"; - case ESP_ERR_NOT_FOUND: - return "Not found"; - case ESP_ERR_NOT_SUPPORTED: - return "Not supported"; - case ESP_ERR_TIMEOUT: - return "Timeout"; - case ESP_ERR_NVS_NOT_INITIALIZED: - return "ESP_ERR_NVS_NOT_INITIALIZED"; - case ESP_ERR_NVS_NOT_FOUND: - return "ESP_ERR_NVS_NOT_FOUND"; - case ESP_ERR_NVS_TYPE_MISMATCH: - return "ESP_ERR_NVS_TYPE_MISMATCH"; - case ESP_ERR_NVS_READ_ONLY: - return "ESP_ERR_NVS_READ_ONLY"; - case ESP_ERR_NVS_NOT_ENOUGH_SPACE: - return "ESP_ERR_NVS_NOT_ENOUGH_SPACE"; - case ESP_ERR_NVS_INVALID_NAME: - return "ESP_ERR_NVS_INVALID_NAME"; - case ESP_ERR_NVS_INVALID_HANDLE: - return "ESP_ERR_NVS_INVALID_HANDLE"; - case ESP_ERR_NVS_REMOVE_FAILED: - return "ESP_ERR_NVS_REMOVE_FAILED"; - case ESP_ERR_NVS_KEY_TOO_LONG: - return "ESP_ERR_NVS_KEY_TOO_LONG"; - case ESP_ERR_NVS_PAGE_FULL: - return "ESP_ERR_NVS_PAGE_FULL"; - case ESP_ERR_NVS_INVALID_STATE: - return "ESP_ERR_NVS_INVALID_STATE"; - case ESP_ERR_NVS_INVALID_LENGTH: - return "ESP_ERR_NVS_INVALID_LENGTH"; - case ESP_ERR_WIFI_NOT_INIT: - return "ESP_ERR_WIFI_NOT_INIT"; - //case ESP_ERR_WIFI_NOT_START: - // return "ESP_ERR_WIFI_NOT_START"; - case ESP_ERR_WIFI_IF: - return "ESP_ERR_WIFI_IF"; - case ESP_ERR_WIFI_MODE: - return "ESP_ERR_WIFI_MODE"; - case ESP_ERR_WIFI_STATE: - return "ESP_ERR_WIFI_STATE"; - case ESP_ERR_WIFI_CONN: - return "ESP_ERR_WIFI_CONN"; - case ESP_ERR_WIFI_NVS: - return "ESP_ERR_WIFI_NVS"; - case ESP_ERR_WIFI_MAC: - return "ESP_ERR_WIFI_MAC"; - case ESP_ERR_WIFI_SSID: - return "ESP_ERR_WIFI_SSID"; - case ESP_ERR_WIFI_PASSWORD: - return "ESP_ERR_WIFI_PASSWORD"; - case ESP_ERR_WIFI_TIMEOUT: - return "ESP_ERR_WIFI_TIMEOUT"; - case ESP_ERR_WIFI_WAKE_FAIL: - return "ESP_ERR_WIFI_WAKE_FAIL"; - } - return "Unknown ESP_ERR error"; -} // errorToString - diff --git a/ESP32_BLE_Arduino/src/GeneralUtils.h b/ESP32_BLE_Arduino/src/GeneralUtils.h deleted file mode 100644 index 152abca..0000000 --- a/ESP32_BLE_Arduino/src/GeneralUtils.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * GeneralUtils.h - * - * Created on: May 20, 2017 - * Author: kolban - */ - -#ifndef COMPONENTS_CPP_UTILS_GENERALUTILS_H_ -#define COMPONENTS_CPP_UTILS_GENERALUTILS_H_ -#include -#include -#include - -/** - * @brief General utilities. - */ -class GeneralUtils { -public: - GeneralUtils(); - virtual ~GeneralUtils(); - static void hexDump(uint8_t *pData, uint32_t length); - static std::string ipToString(uint8_t *ip); - static bool base64Encode(const std::string &in, std::string *out); - static bool base64Decode(const std::string &in, std::string *out); - static const char *errorToString(esp_err_t errCode); -}; - -#endif /* COMPONENTS_CPP_UTILS_GENERALUTILS_H_ */ diff --git a/examples/Arduino/BLE_client/BLE_client.ino b/examples/Arduino/BLE_client/BLE_client.ino new file mode 100644 index 0000000..3fc5efa --- /dev/null +++ b/examples/Arduino/BLE_client/BLE_client.ino @@ -0,0 +1,128 @@ +/** + * A BLE client example that is rich in capabilities. + */ + +#include "BLEDevice.h" +//#include "BLEScan.h" + +// The remote service we wish to connect to. +static BLEUUID serviceUUID("91bad492-b950-4226-aa2b-4ede9fa42f59"); +// The characteristic of the remote service we are interested in. +static BLEUUID charUUID("0d563a58-196a-48ce-ace2-dfec78acc814"); + +static BLEAddress *pServerAddress; +static boolean doConnect = false; +static boolean connected = false; +static BLERemoteCharacteristic* pRemoteCharacteristic; + +static void notifyCallback( + BLERemoteCharacteristic* pBLERemoteCharacteristic, + uint8_t* pData, + size_t length, + bool isNotify) { + Serial.print("Notify callback for characteristic "); + Serial.print(pBLERemoteCharacteristic->getUUID().toString().c_str()); + Serial.print(" of data length "); + Serial.println(length); +} + +void connectToServer(BLEAddress pAddress) { + Serial.print("Forming a connection to "); + Serial.println(pAddress.toString().c_str()); + + BLEClient* pClient = BLEDevice::createClient(); + Serial.println(" - Created client"); + + // Connect to the remove BLE Server. + pClient->connect(pAddress); + Serial.println(" - Connected to server"); + + // Obtain a reference to the service we are after in the remote BLE server. + BLERemoteService* pRemoteService = pClient->getService(serviceUUID); + if (pRemoteService == nullptr) { + Serial.print("Failed to find our service UUID: "); + Serial.println(serviceUUID.toString().c_str()); + return; + } + + + // Obtain a reference to the characteristic in the service of the remote BLE server. + pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID); + if (pRemoteCharacteristic == nullptr) { + Serial.print("Failed to find our characteristic UUID: "); + Serial.println(charUUID.toString().c_str()); + return; + } + + // Read the value of the characteristic. + std::string value = pRemoteCharacteristic->readValue(); + Serial.print("The characteristic value was: "); + Serial.println(value.c_str()); + + pRemoteCharacteristic->registerForNotify(notifyCallback); +} +/** + * Scan for BLE servers and find the first one that advertises the service we are looking for. + */ +class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks { + /** + * Called for each advertising BLE server. + */ + void onResult(BLEAdvertisedDevice advertisedDevice) { + Serial.print("BLE Advertised Device found: "); + Serial.println(advertisedDevice.toString().c_str()); + + // We have found a device, let us now see if it contains the service we are looking for. + if (advertisedDevice.haveServiceUUID() && advertisedDevice.getServiceUUID().equals(serviceUUID)) { + + // + Serial.print("Found our device! address: "); + advertisedDevice.getScan()->stop(); + + pServerAddress = new BLEAddress(advertisedDevice.getAddress()); + doConnect = true; + + } // Found our server + } // onResult +}; // MyAdvertisedDeviceCallbacks + + +void setup() { + Serial.begin(115200); + Serial.println("Starting Arduino BLE Client application..."); + BLEDevice::init(""); + + // Retrieve a Scanner and set the callback we want to use to be informed when we + // have detected a new device. Specify that we want active scanning and start the + // scan to run for 30 seconds. + BLEScan* pBLEScan = BLEDevice::getScan(); + pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks()); + pBLEScan->setActiveScan(true); + pBLEScan->start(30); +} // End of setup. + + +// This is the Arduino main loop function. +void loop() { + + // If the flag "doConnect" is true then we have scanned for and found the desired + // BLE Server with which we wish to connect. Now we connect to it. Once we are + // connected we set the connected flag to be true. + if (doConnect == true) { + connectToServer(*pServerAddress); + doConnect = false; + connected = true; + } + + // If we are connected to a peer BLE Server, update the characteristic each time we are reached + // with the current time since boot. + if (connected) { + String newValue = "Time since boot: " + String(millis()/1000); + Serial.println("Setting new characteristic value to \"" + newValue + "\""); + + // Set the characteristic's value to be the array of bytes that is actually a string. + pRemoteCharacteristic->writeValue(newValue.c_str(), newValue.length()); + } + + delay(1000); // Delay a second between loops. +} // End of loop diff --git a/examples/Arduino/BLE_notify/BLE_notify.ino b/examples/Arduino/BLE_notify/BLE_notify.ino new file mode 100644 index 0000000..44506c2 --- /dev/null +++ b/examples/Arduino/BLE_notify/BLE_notify.ino @@ -0,0 +1,93 @@ +/* + Video: https://www.youtube.com/watch?v=oCMOYS71NIU + Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp + Ported to Arduino ESP32 by Evandro Copercini + + Create a BLE server that, once we receive a connection, will send periodic notifications. + The service advertises itself as: 4fafc201-1fb5-459e-8fcc-c5c9c331914b + And has a characteristic of: beb5483e-36e1-4688-b7f5-ea07361b26a8 + + The design of creating the BLE server is: + 1. Create a BLE Server + 2. Create a BLE Service + 3. Create a BLE Characteristic on the Service + 4. Create a BLE Descriptor on the characteristic + 5. Start the service. + 6. Start advertising. + + A connect hander associated with the server starts a background task that performs notification + every couple of seconds. +*/ +#include +#include +#include +#include + +BLECharacteristic *pCharacteristic; +bool deviceConnected = false; +uint8_t value = 0; + +// See the following for generating UUIDs: +// https://www.uuidgenerator.net/ + +#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" +#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" + + +class MyServerCallbacks: public BLEServerCallbacks { + void onConnect(BLEServer* pServer) { + deviceConnected = true; + }; + + void onDisconnect(BLEServer* pServer) { + deviceConnected = false; + } +}; + + + +void setup() { + Serial.begin(115200); + + // Create the BLE Device + BLEDevice::init("MyESP32"); + + // Create the BLE Server + BLEServer *pServer = new BLEServer(); + pServer->setCallbacks(new MyServerCallbacks()); + + // Create the BLE Service + BLEService *pService = pServer->createService(SERVICE_UUID); + + // Create a BLE Characteristic + pCharacteristic = pService->createCharacteristic( + CHARACTERISTIC_UUID, + BLECharacteristic::PROPERTY_READ | + BLECharacteristic::PROPERTY_WRITE | + BLECharacteristic::PROPERTY_NOTIFY | + BLECharacteristic::PROPERTY_INDICATE + ); + + // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml + // Create a BLE Descriptor + pCharacteristic->addDescriptor(new BLE2902()); + + // Start the service + pService->start(); + + // Start advertising + pServer->getAdvertising()->start(); + Serial.println("Waiting a client connection to notify..."); +} + +void loop() { + + if (deviceConnected) { + Serial.printf("*** NOTIFY: %d ***\n", value); + pCharacteristic->setValue(&value, 1); + pCharacteristic->notify(); + //pCharacteristic->indicate(); + value++; + } + delay(2000); +} \ No newline at end of file diff --git a/examples/Arduino/BLE_scan/BLE_scan.ino b/examples/Arduino/BLE_scan/BLE_scan.ino new file mode 100644 index 0000000..ef7d892 --- /dev/null +++ b/examples/Arduino/BLE_scan/BLE_scan.ino @@ -0,0 +1,36 @@ +/* + Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleScan.cpp + Ported to Arduino ESP32 by Evandro Copercini +*/ + +#include +#include +#include +#include + +int scanTime = 30; //In seconds + +class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks { + void onResult(BLEAdvertisedDevice advertisedDevice) { + Serial.printf("Advertised Device: %s \n", advertisedDevice.toString().c_str()); + } +}; + +void setup() { + Serial.begin(115200); + Serial.println("Scanning..."); + + BLEDevice::init(""); + BLEScan* pBLEScan = BLEDevice::getScan(); //create new scan + pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks()); + pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster + BLEScanResults foundDevices = pBLEScan->start(scanTime); + Serial.print("Devices found: "); + Serial.println(foundDevices.getCount()); + Serial.println("Scan done!"); +} + +void loop() { + // put your main code here, to run repeatedly: + delay(2000); +} \ No newline at end of file diff --git a/examples/Arduino/BLE_server/BLE_server.ino b/examples/Arduino/BLE_server/BLE_server.ino new file mode 100644 index 0000000..45ebf99 --- /dev/null +++ b/examples/Arduino/BLE_server/BLE_server.ino @@ -0,0 +1,41 @@ +/* + Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleServer.cpp + Ported to Arduino ESP32 by Evandro Copercini +*/ + +#include +#include +#include + +BLEDevice ble; + +// See the following for generating UUIDs: +// https://www.uuidgenerator.net/ + +#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" +#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" + +void setup() { + Serial.begin(115200); + Serial.println("Starting BLE work!"); + + ble.init("MyESP32"); + BLEServer *pServer = new BLEServer(); + BLEService *pService = pServer->createService(SERVICE_UUID); + BLECharacteristic *pCharacteristic = pService->createCharacteristic( + CHARACTERISTIC_UUID, + BLECharacteristic::PROPERTY_READ | + BLECharacteristic::PROPERTY_WRITE + ); + + pCharacteristic->setValue("Hello World says Neil"); + pService->start(); + BLEAdvertising *pAdvertising = pServer->getAdvertising(); + pAdvertising->start(); + Serial.println("Characteristic defined! Now you can read it in your phone!"); +} + +void loop() { + // put your main code here, to run repeatedly: + delay(2000); +} \ No newline at end of file diff --git a/examples/Arduino/BLE_uart/BLE_uart.ino b/examples/Arduino/BLE_uart/BLE_uart.ino new file mode 100644 index 0000000..a8ab2d7 --- /dev/null +++ b/examples/Arduino/BLE_uart/BLE_uart.ino @@ -0,0 +1,111 @@ +/* + Video: https://www.youtube.com/watch?v=oCMOYS71NIU + Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp + Ported to Arduino ESP32 by Evandro Copercini + + Create a BLE server that, once we receive a connection, will send periodic notifications. + The service advertises itself as: 6E400001-B5A3-F393-E0A9-E50E24DCCA9E + Has a characteristic of: 6E400002-B5A3-F393-E0A9-E50E24DCCA9E - used for receiving data with "WRITE" + Has a characteristic of: 6E400003-B5A3-F393-E0A9-E50E24DCCA9E - used to send data with "NOTIFY" + + The design of creating the BLE server is: + 1. Create a BLE Server + 2. Create a BLE Service + 3. Create a BLE Characteristic on the Service + 4. Create a BLE Descriptor on the characteristic + 5. Start the service. + 6. Start advertising. + + In this example rxValue is the data received (only accessible inside that function). + And txValue is the data to be sent, in this example just a byte incremented every second. +*/ +#include +#include +#include +#include + +BLECharacteristic *pCharacteristic; +bool deviceConnected = false; +uint8_t txValue = 0; + +// See the following for generating UUIDs: +// https://www.uuidgenerator.net/ + +#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID +#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E" +#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E" + + +class MyServerCallbacks: public BLEServerCallbacks { + void onConnect(BLEServer* pServer) { + deviceConnected = true; + }; + + void onDisconnect(BLEServer* pServer) { + deviceConnected = false; + } +}; + +class MyCallbacks: public BLECharacteristicCallbacks { + void onWrite(BLECharacteristic *pCharacteristic) { + std::string rxValue = pCharacteristic->getValue(); + + if (rxValue.length() > 0) { + Serial.println("*********"); + Serial.print("Received Value: "); + for (int i = 0; i < rxValue.length(); i++) + Serial.print(rxValue[i]); + + Serial.println(); + Serial.println("*********"); + } + } +}; + + +void setup() { + Serial.begin(115200); + + // Create the BLE Device + BLEDevice::init("UART Service"); + + // Create the BLE Server + BLEServer *pServer = new BLEServer(); + pServer->setCallbacks(new MyServerCallbacks()); + + // Create the BLE Service + BLEService *pService = pServer->createService(SERVICE_UUID); + + // Create a BLE Characteristic + pCharacteristic = pService->createCharacteristic( + CHARACTERISTIC_UUID_TX, + BLECharacteristic::PROPERTY_NOTIFY + ); + + pCharacteristic->addDescriptor(new BLE2902()); + + BLECharacteristic *pCharacteristic = pService->createCharacteristic( + CHARACTERISTIC_UUID_RX, + BLECharacteristic::PROPERTY_WRITE + ); + + pCharacteristic->setCallbacks(new MyCallbacks()); + + // Start the service + pService->start(); + + // Start advertising + pServer->getAdvertising()->start(); + Serial.println("Waiting a client connection to notify..."); +} + +void loop() { + + if (deviceConnected) { + Serial.printf("*** Sent Value: %d ***\n", txValue); + pCharacteristic->setValue(&txValue, 1); + pCharacteristic->notify(); + txValue++; + } + delay(1000); +} diff --git a/examples/Arduino/BLE_write/BLE_write.ino b/examples/Arduino/BLE_write/BLE_write.ino new file mode 100644 index 0000000..ed5ebc6 --- /dev/null +++ b/examples/Arduino/BLE_write/BLE_write.ino @@ -0,0 +1,68 @@ +/* + Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleWrite.cpp + Ported to Arduino ESP32 by Evandro Copercini +*/ + +#include +#include +#include + +BLEDevice ble; + +// See the following for generating UUIDs: +// https://www.uuidgenerator.net/ + +#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" +#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" + + +class MyCallbacks: public BLECharacteristicCallbacks { + void onWrite(BLECharacteristic *pCharacteristic) { + std::string value = pCharacteristic->getValue(); + + if (value.length() > 0) { + Serial.println("*********"); + Serial.print("New value: "); + for (int i = 0; i < value.length(); i++) + Serial.print(value[i]); + + Serial.println(); + Serial.println("*********"); + } + } +}; + +void setup() { + Serial.begin(115200); + + Serial.println("1- Download and install an BLE scanner app in your phone"); + Serial.println("2- Scan for BLE devices in the app"); + Serial.println("3- Connect to MyESP32"); + Serial.println("4- Go to CUSTOM CHARACTERISTIC in CUSTOM SERVICE and write something"); + Serial.println("5- See the magic =)"); + + //ble.begin("MyESP32"); + ble.init("MyESP32"); + BLEServer *pServer = new BLEServer(); + + BLEService *pService = pServer->createService(SERVICE_UUID); + + BLECharacteristic *pCharacteristic = pService->createCharacteristic( + CHARACTERISTIC_UUID, + BLECharacteristic::PROPERTY_READ | + BLECharacteristic::PROPERTY_WRITE + ); + + pCharacteristic->setCallbacks(new MyCallbacks()); + + pCharacteristic->setValue("Hello World"); + pService->start(); + + BLEAdvertising *pAdvertising = pServer->getAdvertising(); + pAdvertising->start(); +} + +void loop() { + // put your main code here, to run repeatedly: + delay(2000); +} \ No newline at end of file diff --git a/library.properties b/library.properties new file mode 100644 index 0000000..09a02ba --- /dev/null +++ b/library.properties @@ -0,0 +1,11 @@ +name=ESP32 BLE Arduino +version=0.1.0 +author=Neil Kolban +maintainer=Neil Kolban +sentence=BLE functions for ESP32 +paragraph=BLE functions for ESP32 +category=Communication +url=https://github.com/nkolban/ESP32_BLE_Arduino +architectures=esp32 +includes=BLE.h BLEUtils.h BLEScan.h BLEAdvertisedDevice.h +dot_a_linkage=true \ No newline at end of file diff --git a/src/BLE2902.cpp b/src/BLE2902.cpp new file mode 100644 index 0000000..8984da8 --- /dev/null +++ b/src/BLE2902.cpp @@ -0,0 +1,69 @@ +/* + * BLE2902.cpp + * + * Created on: Jun 25, 2017 + * Author: kolban + */ + +/* + * See also: + * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml + */ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) + +#include "BLE2902.h" + +BLE2902::BLE2902() : BLEDescriptor(BLEUUID((uint16_t) 0x2902)) { + uint8_t data[2] = {0,0}; + setValue(data, 2); +} // BLE2902 + + +/** + * @brief Get the notifications value. + * @return The notifications value. True if notifications are enabled and false if not. + */ +bool BLE2902::getNotifications() { + return (getValue()[0] & (1 << 0)) != 0; +} // getNotifications + + +/** + * @brief Get the indications value. + * @return The indications value. True if indications are enabled and false if not. + */ +bool BLE2902::getIndications() { + return (getValue()[0] & (1 << 1)) != 0; +} // getIndications + + +/** + * @brief Set the indications flag. + * @param [in] flag The indications flag. + */ +void BLE2902::setIndications(bool flag) { + uint8_t *pValue = getValue(); + if (flag) { + pValue[0] |= 1<<1; + } else { + pValue[0] &= ~(1<<1); + } +} // setIndications + + +/** + * @brief Set the notifications flag. + * @param [in] flag The notifications flag. + */ +void BLE2902::setNotifications(bool flag) { + uint8_t *pValue = getValue(); + if (flag) { + pValue[0] |= 1<<0; + } else { + pValue[0] &= ~(1<<0); + } +} // setNotifications + + +#endif diff --git a/src/BLE2902.h b/src/BLE2902.h new file mode 100644 index 0000000..397360a --- /dev/null +++ b/src/BLE2902.h @@ -0,0 +1,34 @@ +/* + * BLE2902.h + * + * Created on: Jun 25, 2017 + * Author: kolban + */ + +#ifndef COMPONENTS_CPP_UTILS_BLE2902_H_ +#define COMPONENTS_CPP_UTILS_BLE2902_H_ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) + +#include "BLEDescriptor.h" + +/** + * @brief Descriptor for Client Characteristic Configuration. + * + * This is a convenience descriptor for the Client Characteristic Configuration which has a UUID of 0x2902. + * + * See also: + * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml + */ +class BLE2902: public BLEDescriptor { +public: + BLE2902(); + bool getNotifications(); + bool getIndications(); + void setNotifications(bool flag); + void setIndications(bool flag); + +}; // BLE2902 + +#endif /* CONFIG_BT_ENABLED */ +#endif /* COMPONENTS_CPP_UTILS_BLE2902_H_ */ diff --git a/src/BLEAddress.cpp b/src/BLEAddress.cpp new file mode 100644 index 0000000..d2f7f8b --- /dev/null +++ b/src/BLEAddress.cpp @@ -0,0 +1,93 @@ +/* + * BLEAddress.cpp + * + * Created on: Jul 2, 2017 + * Author: kolban + */ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) + +#include "BLEAddress.h" +#include +#include +#include +#include +#include + + +/** + * @brief Create an address from the native ESP32 representation. + * @param [in] address The native representation. + */ +BLEAddress::BLEAddress(esp_bd_addr_t address) { + memcpy(m_address, address, ESP_BD_ADDR_LEN); +} // BLEAddress + + +/** + * @brief Create an address from a hex string + * + * A hex string is of the format: + * ``` + * 00:00:00:00:00:00 + * ``` + * which is 17 characters in length. + * + * @param [in] stringAddress The hex representation of the address. + */ +BLEAddress::BLEAddress(std::string stringAddress) { + if (stringAddress.length() != 17) { + return; + } + int data[6]; + sscanf(stringAddress.c_str(), "%x:%x:%x:%x:%x:%x", &data[0], &data[1], &data[2], &data[3], &data[4], &data[5]); + m_address[0] = (uint8_t)data[0]; + m_address[1] = (uint8_t)data[1]; + m_address[2] = (uint8_t)data[2]; + m_address[3] = (uint8_t)data[3]; + m_address[4] = (uint8_t)data[4]; + m_address[5] = (uint8_t)data[5]; +} // BLEAddress + + +/** + * @brief Determine if this address equals another. + * @param [in] otherAddress The other address to compare against. + * @return True if the addresses are equal. + */ +bool BLEAddress::equals(BLEAddress otherAddress) { + return memcmp(otherAddress.getNative(), m_address, 6) == 0; +} // equals + + +/** + * @brief Return the native representation of the address. + * @return The native representation of the address. + */ +esp_bd_addr_t *BLEAddress::getNative() { + return &m_address; +} // getNative + + +/** + * @brief Convert a BLE address to a string. + * + * A string representation of an address is in the format: + * + * ``` + * xx:xx:xx:xx:xx:xx + * ``` + * + * @return The string representation of the address. + */ +std::string BLEAddress::toString() { + std::stringstream stream; + stream << std::setfill('0') << std::setw(2) << std::hex << (int)((uint8_t *)(m_address))[0] << ':'; + stream << std::setfill('0') << std::setw(2) << std::hex << (int)((uint8_t *)(m_address))[1] << ':'; + stream << std::setfill('0') << std::setw(2) << std::hex << (int)((uint8_t *)(m_address))[2] << ':'; + stream << std::setfill('0') << std::setw(2) << std::hex << (int)((uint8_t *)(m_address))[3] << ':'; + stream << std::setfill('0') << std::setw(2) << std::hex << (int)((uint8_t *)(m_address))[4] << ':'; + stream << std::setfill('0') << std::setw(2) << std::hex << (int)((uint8_t *)(m_address))[5]; + return stream.str(); +} // toString +#endif diff --git a/src/BLEAddress.h b/src/BLEAddress.h new file mode 100644 index 0000000..7eff4da --- /dev/null +++ b/src/BLEAddress.h @@ -0,0 +1,34 @@ +/* + * BLEAddress.h + * + * Created on: Jul 2, 2017 + * Author: kolban + */ + +#ifndef COMPONENTS_CPP_UTILS_BLEADDRESS_H_ +#define COMPONENTS_CPP_UTILS_BLEADDRESS_H_ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) +#include // ESP32 BLE +#include + + +/** + * @brief A %BLE device address. + * + * Every %BLE device has a unique address which can be used to identify it and form connections. + */ +class BLEAddress { +public: + BLEAddress(esp_bd_addr_t address); + BLEAddress(std::string stringAddress); + bool equals(BLEAddress otherAddress); + esp_bd_addr_t* getNative(); + std::string toString(); + +private: + esp_bd_addr_t m_address; +}; + +#endif /* CONFIG_BT_ENABLED */ +#endif /* COMPONENTS_CPP_UTILS_BLEADDRESS_H_ */ diff --git a/src/BLEAdvertisedDevice.cpp b/src/BLEAdvertisedDevice.cpp new file mode 100644 index 0000000..97ec1e3 --- /dev/null +++ b/src/BLEAdvertisedDevice.cpp @@ -0,0 +1,410 @@ +/* + * BLEAdvertisedDevice.cpp + * + * During the scanning procedure, we will be finding advertised BLE devices. This class + * models a found device. + * + * + * See also: + * https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile + * + * Created on: Jul 3, 2017 + * Author: kolban + */ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) +#include +#include +#include "BLEAdvertisedDevice.h" +#include "BLEUtils.h" +static const char* LOG_TAG="BLEAdvertisedDevice"; + +BLEAdvertisedDevice::BLEAdvertisedDevice() { + m_adFlag = 0; + m_appearance = 0; + m_deviceType = 0; + m_manufacturerData = ""; + m_name = ""; + m_rssi = -9999; + m_txPower = 0; + m_pScan = nullptr; + + m_haveAppearance = false; + m_haveManufacturerData = false; + m_haveName = false; + m_haveRSSI = false; + m_haveServiceUUID = false; + m_haveTXPower = false; + +} // BLEAdvertisedDevice + + +/** + * @brief Get the address. + * + * Every %BLE device exposes an address that is used to identify it and subsequently connect to it. + * Call this function to obtain the address of the advertised device. + * + * @return The address of the advertised device. + */ +BLEAddress BLEAdvertisedDevice::getAddress() { + return m_address; +} // getAddress + + +/** + * @brief Get the appearance. + * + * A %BLE device can declare its own appearance. The appearance is how it would like to be shown to an end user + * typcially in the form of an icon. + * + * @return The appearance of the advertised device. + */ +uint16_t BLEAdvertisedDevice::getApperance() { + return m_appearance; +} + + +/** + * @brief Get the manufacturer data. + * @return The manufacturer data of the advertised device. + */ +std::string BLEAdvertisedDevice::getManufacturerData() { + return m_manufacturerData; +} + + +/** + * @brief Get the name. + * @return The name of the advertised device. + */ +std::string BLEAdvertisedDevice::getName() { + return m_name; +} // getName + + +/** + * @brief Get the RSSI. + * @return The RSSI of the advertised device. + */ +int BLEAdvertisedDevice::getRSSI() { + return m_rssi; +} // getRSSI + + +/** + * @brief Get the scan object that created this advertisement. + * @return The scan object. + */ +BLEScan* BLEAdvertisedDevice::getScan() { + return m_pScan; +} // getScan + + +/** + * @brief Get the Service UUID. + * @return The Service UUID of the advertised device. + */ +BLEUUID BLEAdvertisedDevice::getServiceUUID() { + return m_serviceUUID; +} // getServiceUUID + + +/** + * @brief Get the TX Power. + * @return The TX Power of the advertised device. + */ +int8_t BLEAdvertisedDevice::getTXPower() { + return m_txPower; +} // getTXPower + +/** + * @brief Does this advertisement have an appearance value? + * @return True if there is an appearance value present. + */ +bool BLEAdvertisedDevice::haveAppearance() { + return m_haveAppearance; +} // haveAppearance + + +/** + * @brief Does this advertisement have manufacturer data? + * @return True if there is manufacturer data present. + */ +bool BLEAdvertisedDevice::haveManufacturerData() { + return m_haveManufacturerData; +} // haveManufacturerData + + +/** + * @brief Does this advertisement have a name value? + * @return True if there is a name value present. + */ +bool BLEAdvertisedDevice::haveName() { + return m_haveName; +} // haveName + + +/** + * @brief Does this advertisement have a signal strength value? + * @return True if there is a signal strength value present. + */ +bool BLEAdvertisedDevice::haveRSSI() { + return m_haveRSSI; +} // haveRSSI + + +/** + * @brief Does this advertisement have a service UUID value? + * @return True if there is a service UUID value present. + */ +bool BLEAdvertisedDevice::haveServiceUUID() { + return m_haveServiceUUID; +} // haveServiceUUID + + +/** + * @brief Does this advertisement have a transmission power value? + * @return True if there is a transmission power value present. + */ +bool BLEAdvertisedDevice::haveTXPower() { + return m_haveTXPower; +} // haveTXPower + + +/** + * @brief Parse the advertising pay load. + * + * The pay load is a buffer of bytes that is either 31 bytes long or terminated by + * a 0 length value. Each entry in the buffer has the format: + * [length][type][data...] + * + * The length does not include itself but does include everything after it until the next record. A record + * with a length value of 0 indicates a terminator. + * + * https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile + */ +void BLEAdvertisedDevice::parseAdvertisement(uint8_t* payload) { + uint8_t length; + uint8_t ad_type; + uint8_t sizeConsumed = 0; + bool finished = false; + + while(!finished) { + length = *payload; // Retrieve the length of the record. + payload++; // Skip to type + sizeConsumed += 1 + length; // increase the size consumed. + + if (length != 0) { // A length of 0 indicate that we have reached the end. + ad_type = *payload; + payload++; + length--; + + char* pHex = BLEUtils::buildHexData(nullptr, payload, length); + ESP_LOGD(LOG_TAG, "Type: 0x%.2x (%s), length: %d, data: %s", + ad_type, BLEUtils::advTypeToString(ad_type), length, pHex); + free(pHex); + + + + switch(ad_type) { + case ESP_BLE_AD_TYPE_NAME_CMPL: { // Adv Data Type: 0x09 + setName(std::string(reinterpret_cast(payload), length)); + break; + } // ESP_BLE_AD_TYPE_NAME_CMPL + + case ESP_BLE_AD_TYPE_TX_PWR: { // Adv Data Type: 0x0A + setTXPower(*payload); + break; + } // ESP_BLE_AD_TYPE_TX_PWR + + case ESP_BLE_AD_TYPE_APPEARANCE: { // Adv Data Type: 0x19 + setAppearance(*reinterpret_cast(payload)); + break; + } // ESP_BLE_AD_TYPE_APPEARANCE + + case ESP_BLE_AD_TYPE_FLAG: { // Adv Data Type: 0x01 + setAdFlag(*payload); + break; + } // ESP_BLE_AD_TYPE_FLAG + + case ESP_BLE_AD_TYPE_16SRV_CMPL: { // Adv Data Type: 0x03 + setServiceUUID(BLEUUID(*reinterpret_cast(payload))); + break; + } // ESP_BLE_AD_TYPE_16SRV_CMPL + + case ESP_BLE_AD_TYPE_16SRV_PART: { // Adv Data Type: 0x02 + setServiceUUID(BLEUUID(*reinterpret_cast(payload))); + break; + } // ESP_BLE_AD_TYPE_16SRV_PART + + case ESP_BLE_AD_TYPE_32SRV_CMPL: { // Adv Data Type: 0x05 + setServiceUUID(BLEUUID(*reinterpret_cast(payload))); + break; + } // ESP_BLE_AD_TYPE_32SRV_CMPL + + case ESP_BLE_AD_TYPE_32SRV_PART: { // Adv Data Type: 0x04 + setServiceUUID(BLEUUID(*reinterpret_cast(payload))); + break; + } // ESP_BLE_AD_TYPE_32SRV_PART + + case ESP_BLE_AD_TYPE_128SRV_CMPL: { // Adv Data Type: 0x07 + setServiceUUID(BLEUUID(payload, 16, false)); + break; + } // ESP_BLE_AD_TYPE_128SRV_CMPL + + case ESP_BLE_AD_TYPE_128SRV_PART: { // Adv Data Type: 0x06 + setServiceUUID(BLEUUID(payload, 16, false)); + break; + } // ESP_BLE_AD_TYPE_128SRV_PART + + // See CSS Part A 1.4 Manufacturer Specific Data + case ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE: { + setManufacturerData(std::string(reinterpret_cast(payload), length)); + break; + } // ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE + + default: { + ESP_LOGD(LOG_TAG, "Unhandled type"); + break; + } + } // switch + payload += length; + } // Length <> 0 + + + if (sizeConsumed >=31 || length == 0) { + finished = true; + } + } // !finished +} // parseAdvertisement + + +/** + * @brief Set the address of the advertised device. + * @param [in] address The address of the advertised device. + */ +void BLEAdvertisedDevice::setAddress(BLEAddress address) { + m_address = address; +} // setAddress + + +/** + * @brief Set the adFlag for this device. + * @param [in] The discovered adFlag. + */ +void BLEAdvertisedDevice::setAdFlag(uint8_t adFlag) { + m_adFlag = adFlag; +} // setAdFlag + + +/** + * @brief Set the appearance for this device. + * @param [in] The discovered appearance. + */ +void BLEAdvertisedDevice::setAppearance(uint16_t appearance) { + m_appearance = appearance; + m_haveAppearance = true; + ESP_LOGD(LOG_TAG, "- appearance: %d", m_appearance); +} // setAppearance + + +/** + * @brief Set the manufacturer data for this device. + * @param [in] The discovered manufacturer data. + */ +void BLEAdvertisedDevice::setManufacturerData(std::string manufacturerData) { + m_manufacturerData = manufacturerData; + m_haveManufacturerData = true; + char* pHex = BLEUtils::buildHexData(nullptr, (uint8_t*)m_manufacturerData.data(), (uint8_t)m_manufacturerData.length()); + ESP_LOGD(LOG_TAG, "- manufacturer data: %s", pHex); + free(pHex); +} // setManufacturerData + + +/** + * @brief Set the name for this device. + * @param [in] name The discovered name. + */ +void BLEAdvertisedDevice::setName(std::string name) { + m_name = name; + m_haveName = true; + ESP_LOGD(LOG_TAG, "- name: %s", m_name.c_str()); +} // setName + + +/** + * @brief Set the RSSI for this device. + * @param [in] rssi The discovered RSSI. + */ +void BLEAdvertisedDevice::setRSSI(int rssi) { + m_rssi = rssi; + m_haveRSSI = true; + ESP_LOGD(LOG_TAG, "- rssi: %d", m_rssi); +} // setRSSI + + +/** + * @brief Set the Scan that created this advertised device. + * @param pScan The Scan that created this advertised device. + */ +void BLEAdvertisedDevice::setScan(BLEScan* pScan) { + m_pScan = pScan; +} // setScan + +/** + * @brief Set the Service UUID for this device. + * @param [in] serviceUUID The discovered serviceUUID + */ +void BLEAdvertisedDevice::setServiceUUID(const char* serviceUUID) { + return setServiceUUID(BLEUUID(serviceUUID)); +} // setRSSI + +/** + * @brief Set the Service UUID for this device. + * @param [in] serviceUUID The discovered serviceUUID + */ +void BLEAdvertisedDevice::setServiceUUID(BLEUUID serviceUUID) { + m_serviceUUID = serviceUUID; + m_haveServiceUUID = true; + ESP_LOGD(LOG_TAG, "- serviceUUID: %s", serviceUUID.toString().c_str()); +} // setRSSI + + +/** + * @brief Set the power level for this device. + * @param [in] txPower The discovered power level. + */ +void BLEAdvertisedDevice::setTXPower(int8_t txPower) { + m_txPower = txPower; + m_haveTXPower = true; + ESP_LOGD(LOG_TAG, "- txPower: %d", m_txPower); +} // setTXPower + + +/** + * @brief Create a string representation of this device. + * @return A string representation of this device. + */ +std::string BLEAdvertisedDevice::toString() { + std::stringstream ss; + ss << "Name: " << getName() << ", Address: " << getAddress().toString(); + if (haveAppearance()) { + ss << ", appearance: " << getApperance(); + } + if (haveManufacturerData()) { + char *pHex = BLEUtils::buildHexData(nullptr, (uint8_t*)getManufacturerData().data(), getManufacturerData().length()); + ss << ", manufacturer data: " << pHex; + free(pHex); + } + if (haveServiceUUID()) { + ss << ", serviceUUID: " << getServiceUUID().toString(); + } + if (haveTXPower()) { + ss << ", txPower: " << (int)getTXPower(); + } + return ss.str(); +} // toString + +#endif /* CONFIG_BT_ENABLED */ + diff --git a/src/BLEAdvertisedDevice.h b/src/BLEAdvertisedDevice.h new file mode 100644 index 0000000..2fb2652 --- /dev/null +++ b/src/BLEAdvertisedDevice.h @@ -0,0 +1,106 @@ +/* + * BLEAdvertisedDevice.h + * + * Created on: Jul 3, 2017 + * Author: kolban + */ + +#ifndef COMPONENTS_CPP_UTILS_BLEADVERTISEDDEVICE_H_ +#define COMPONENTS_CPP_UTILS_BLEADVERTISEDDEVICE_H_ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) +#include + +#include + +#include "BLEAddress.h" +#include "BLEScan.h" +#include "BLEUUID.h" + + +class BLEScan; +/** + * @brief A representation of a %BLE advertised device found by a scan. + * + * When we perform a %BLE scan, the result will be a set of devices that are advertising. This + * class provides a model of a detected device. + */ +class BLEAdvertisedDevice { +public: + BLEAdvertisedDevice(); + + BLEAddress getAddress(); + uint16_t getApperance(); + std::string getManufacturerData(); + std::string getName(); + int getRSSI(); + BLEScan* getScan(); + BLEUUID getServiceUUID(); + int8_t getTXPower(); + + bool haveAppearance(); + bool haveManufacturerData(); + bool haveName(); + bool haveRSSI(); + bool haveServiceUUID(); + bool haveTXPower(); + + std::string toString(); + +private: + friend class BLEScan; + + void parseAdvertisement(uint8_t* payload); + void setAddress(BLEAddress address); + void setAdFlag(uint8_t adFlag); + void setAdvertizementResult(uint8_t* payload); + void setAppearance(uint16_t appearance); + void setManufacturerData(std::string manufacturerData); + void setName(std::string name); + void setRSSI(int rssi); + void setScan(BLEScan* pScan); + void setServiceUUID(const char* serviceUUID); + void setServiceUUID(BLEUUID serviceUUID); + void setTXPower(int8_t txPower); + + bool m_haveAppearance; + bool m_haveManufacturerData; + bool m_haveName; + bool m_haveRSSI; + bool m_haveServiceUUID; + bool m_haveTXPower; + + + BLEAddress m_address = BLEAddress((uint8_t*)"\0\0\0\0\0\0"); + uint8_t m_adFlag; + uint16_t m_appearance; + int m_deviceType; + std::string m_manufacturerData; + std::string m_name; + BLEScan* m_pScan; + int m_rssi; + BLEUUID m_serviceUUID; + int8_t m_txPower; +}; + +/** + * @brief A callback handler for callbacks associated device scanning. + * + * When we are performing a scan as a %BLE client, we may wish to know when a new device that is advertising + * has been found. This class can be sub-classed and registered such that when a scan is performed and + * a new advertised device has been found, we will be called back to be notified. + */ +class BLEAdvertisedDeviceCallbacks { +public: + virtual ~BLEAdvertisedDeviceCallbacks() {} + /** + * @brief Called when a new scan result is detected. + * + * As we are scanning, we will find new devices. When found, this call back is invoked with a reference to the + * device that was found. During any individual scan, a device will only be detected one time. + */ + virtual void onResult(BLEAdvertisedDevice advertisedDevice) = 0; +}; + +#endif /* CONFIG_BT_ENABLED */ +#endif /* COMPONENTS_CPP_UTILS_BLEADVERTISEDDEVICE_H_ */ diff --git a/src/BLEAdvertising.cpp b/src/BLEAdvertising.cpp new file mode 100644 index 0000000..ad076dd --- /dev/null +++ b/src/BLEAdvertising.cpp @@ -0,0 +1,155 @@ +/* + * BLEAdvertising.cpp + * + * This class encapsulates advertising a BLE Server. + * Created on: Jun 21, 2017 + * Author: kolban + */ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) +#include "BLEAdvertising.h" +#include +#include +#include "BLEUtils.h" +#include "GeneralUtils.h" + +static const char* LOG_TAG = "BLEAdvertising"; + + +/** + * @brief Construct a default advertising object. + * + */ +BLEAdvertising::BLEAdvertising() { + m_advData.set_scan_rsp = false; + m_advData.include_name = true; + m_advData.include_txpower = true; + m_advData.min_interval = 0x20; + m_advData.max_interval = 0x40; + m_advData.appearance = 0x00; + m_advData.manufacturer_len = 0; + m_advData.p_manufacturer_data = nullptr; + m_advData.service_data_len = 0; + m_advData.p_service_data = nullptr; + m_advData.service_uuid_len = 0; + m_advData.p_service_uuid = nullptr; + m_advData.flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT); + + m_advParams.adv_int_min = 0x20; + m_advParams.adv_int_max = 0x40; + m_advParams.adv_type = ADV_TYPE_IND; + m_advParams.own_addr_type = BLE_ADDR_TYPE_PUBLIC; + m_advParams.channel_map = ADV_CHNL_ALL; + m_advParams.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY; +} // BLEAdvertising + + +/** + * @brief Set the device appearance in the advertising data. + * The appearance attribute is of type 0x19. The codes for distinct appearances can be found here: + * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.gap.appearance.xml. + * @param [in] appearance The appearance of the device in the advertising data. + * @return N/A. + */ +void BLEAdvertising::setAppearance(uint16_t appearance) { + m_advData.appearance = appearance; +} // setAppearance + + +/** + * @brief Set the service UUID. + * We maintain a class member called m_advData (esp_ble_adv_data_t) that is passed to the + * ESP-IDF advertising functions. In this method, we see two fields within that structure + * namely service_uuid_len and p_service_uuid to be the information supplied in the passed + * in service uuid. + * @param [in] uuid The UUID of the service. + * @return N/A. + */ +void BLEAdvertising::setServiceUUID(const char* serviceUUID) { + return setServiceUUID(BLEUUID(serviceUUID)); +} +/** + * @brief Set the service UUID. + * We maintain a class member called m_advData (esp_ble_adv_data_t) that is passed to the + * ESP-IDF advertising functions. In this method, we see two fields within that structure + * namely service_uuid_len and p_service_uuid to be the information supplied in the passed + * in service uuid. + * @param [in] uuid The UUID of the service. + * @return N/A. + */ +void BLEAdvertising::setServiceUUID(BLEUUID serviceUUID) { + ESP_LOGD(LOG_TAG, ">> setServiceUUID - %s", serviceUUID.toString().c_str()); + m_serviceUUID = serviceUUID; // Save the new service UUID + esp_bt_uuid_t* espUUID = m_serviceUUID.getNative(); + switch(espUUID->len) { + case ESP_UUID_LEN_16: { + m_advData.service_uuid_len = 2; + m_advData.p_service_uuid = reinterpret_cast(&espUUID->uuid.uuid16); + break; + } + case ESP_UUID_LEN_32: { + m_advData.service_uuid_len = 4; + m_advData.p_service_uuid = reinterpret_cast(&espUUID->uuid.uuid32); + break; + } + case ESP_UUID_LEN_128: { + m_advData.service_uuid_len = 16; + m_advData.p_service_uuid = reinterpret_cast(&espUUID->uuid.uuid128); + break; + } + } // switch + ESP_LOGD(LOG_TAG, "<< setServiceUUID"); +} // setServiceUUID + + +/** + * @brief Start advertising. + * Start advertising. + * @return N/A. + */ +void BLEAdvertising::start() { + ESP_LOGD(LOG_TAG, ">> start"); + + if (m_advData.service_uuid_len > 0) { + uint8_t hexData[16*2+1]; + BLEUtils::buildHexData(hexData, m_advData.p_service_uuid, m_advData.service_uuid_len); + ESP_LOGD(LOG_TAG, " - Service: service_uuid_len=%d, p_service_uuid=0x%x (data=%s)", + m_advData.service_uuid_len, + (uint32_t)m_advData.p_service_uuid, + (m_advData.service_uuid_len > 0?(char *)hexData:"N/A") + ); + } // We have a service to advertise + + + // Set the configuration for advertising. + esp_err_t errRc = ::esp_ble_gap_config_adv_data(&m_advData); + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "<< esp_ble_gap_config_adv_data: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + + // Start advertising. + errRc = ::esp_ble_gap_start_advertising(&m_advParams); + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "<< esp_ble_gap_start_advertising: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + ESP_LOGD(LOG_TAG, "<< start"); +} // start + + +/** + * @brief Stop advertising. + * Stop advertising. + * @return N/A. + */ +void BLEAdvertising::stop() { + ESP_LOGD(LOG_TAG, ">> stop"); + esp_err_t errRc = ::esp_ble_gap_stop_advertising(); + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "esp_ble_gap_stop_advertising: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + ESP_LOGD(LOG_TAG, "<< stop"); +} // stop +#endif /* CONFIG_BT_ENABLED */ diff --git a/src/BLEAdvertising.h b/src/BLEAdvertising.h new file mode 100644 index 0000000..2d0b51c --- /dev/null +++ b/src/BLEAdvertising.h @@ -0,0 +1,34 @@ +/* + * BLEAdvertising.h + * + * Created on: Jun 21, 2017 + * Author: kolban + */ + +#ifndef COMPONENTS_CPP_UTILS_BLEADVERTISING_H_ +#define COMPONENTS_CPP_UTILS_BLEADVERTISING_H_ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) +#include +#include "BLEUUID.h" + +/** + * @brief Perform and manage %BLE advertising. + * + * A %BLE server will want to perform advertising in order to make itself known to %BLE clients. + */ +class BLEAdvertising { +public: + BLEAdvertising(); + void start(); + void stop(); + void setAppearance(uint16_t appearance); + void setServiceUUID(const char* serviceUUID); + void setServiceUUID(BLEUUID serviceUUID); +private: + esp_ble_adv_data_t m_advData; + esp_ble_adv_params_t m_advParams; + BLEUUID m_serviceUUID; +}; +#endif /* CONFIG_BT_ENABLED */ +#endif /* COMPONENTS_CPP_UTILS_BLEADVERTISING_H_ */ diff --git a/src/BLECharacteristic.cpp b/src/BLECharacteristic.cpp new file mode 100644 index 0000000..f5b8200 --- /dev/null +++ b/src/BLECharacteristic.cpp @@ -0,0 +1,693 @@ +/* + * BLECharacteristic.cpp + * + * Created on: Jun 22, 2017 + * Author: kolban + */ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) +#include +#include +#include +#include +#include "sdkconfig.h" +#include +#include +#include "BLECharacteristic.h" +#include "BLEService.h" +#include "BLEUtils.h" +#include "BLE2902.h" +#include "GeneralUtils.h" + +static const char* LOG_TAG = "BLECharacteristic"; + +#define NULL_HANDLE (0xffff) + + +/** + * @brief Construct a characteristic + * @param [in] uuid - UUID (const char*) for the characteristic. + * @param [in] properties - Properties for the characteristic. + */ +BLECharacteristic::BLECharacteristic(const char* uuid, uint32_t properties) : BLECharacteristic(BLEUUID(uuid), properties) { +} + +/** + * @brief Construct a characteristic + * @param [in] uuid - UUID for the characteristic. + * @param [in] properties - Properties for the characteristic. + */ +BLECharacteristic::BLECharacteristic(BLEUUID uuid, uint32_t properties) { + m_bleUUID = uuid; + m_handle = NULL_HANDLE; + m_properties = (esp_gatt_char_prop_t)0; + m_pCallbacks = nullptr; + + setBroadcastProperty((properties & PROPERTY_BROADCAST) !=0); + setReadProperty((properties & PROPERTY_READ) !=0); + setWriteProperty((properties & PROPERTY_WRITE) !=0); + setNotifyProperty((properties & PROPERTY_NOTIFY) !=0); + setIndicateProperty((properties & PROPERTY_INDICATE) !=0); + setWriteNoResponseProperty((properties & PROPERTY_WRITE_NR) !=0); +} // BLECharacteristic + +/** + * @brief Destructor. + */ +BLECharacteristic::~BLECharacteristic() { + //free(m_value.attr_value); // Release the storage for the value. +} // ~BLECharacteristic + + +/** + * @brief Associate a descriptor with this characteristic. + * @param [in] pDescriptor + * @return N/A. + */ +void BLECharacteristic::addDescriptor(BLEDescriptor* pDescriptor) { + ESP_LOGD(LOG_TAG, ">> addDescriptor(): Adding %s to %s", pDescriptor->toString().c_str(), toString().c_str()); + m_descriptorMap.setByUUID(pDescriptor->getUUID(), pDescriptor); + ESP_LOGD(LOG_TAG, "<< addDescriptor()"); +} // addDescriptor + + +/** + * @brief Register a new characteristic with the ESP runtime. + * @param [in] pService The service with which to associate this characteristic. + */ +void BLECharacteristic::executeCreate(BLEService* pService) { + ESP_LOGD(LOG_TAG, ">> executeCreate()"); + + if (m_handle != NULL_HANDLE) { + ESP_LOGE(LOG_TAG, "Characteristic already has a handle."); + return; + } + + m_pService = pService; // Save the service for to which this characteristic belongs. + + ESP_LOGD(LOG_TAG, "Registering characteristic (esp_ble_gatts_add_char): uuid: %s, service: %s", + getUUID().toString().c_str(), + m_pService->toString().c_str()); + + esp_attr_control_t control; + control.auto_rsp = ESP_GATT_RSP_BY_APP; + + m_semaphoreCreateEvt.take("executeCreate"); + + std::string strValue = m_value.getValue(); + + esp_attr_value_t value; + value.attr_len = strValue.length(); + value.attr_max_len = ESP_GATT_MAX_ATTR_LEN; + value.attr_value = (uint8_t*)strValue.data(); + + esp_err_t errRc = ::esp_ble_gatts_add_char( + m_pService->getHandle(), + getUUID().getNative(), + static_cast(ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE), + getProperties(), + &value, + &control); // Whether to auto respond or not. + + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "<< esp_ble_gatts_add_char: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + + m_semaphoreCreateEvt.wait("executeCreate"); + + // Now that we have registered the characteristic, we must also register all the descriptors associated with this + // characteristic. We iterate through each of those and invoke the registration call to register them with the + // ESP environment. + + BLEDescriptor* pDescriptor = m_descriptorMap.getFirst(); + + while (pDescriptor != nullptr) { + pDescriptor->executeCreate(this); + pDescriptor = m_descriptorMap.getNext(); + } // End while + + ESP_LOGD(LOG_TAG, "<< executeCreate"); +} // executeCreate + + + +/** + * @brief Return the BLE Descriptor for the given UUID if associated with this characteristic. + * @param [in] descriptorUUID The UUID of the descriptor that we wish to retrieve. + * @return The BLE Descriptor. If no such descriptor is associated with the characteristic, nullptr is returned. + */ +BLEDescriptor* BLECharacteristic::getDescriptorByUUID(const char* descriptorUUID) { + return m_descriptorMap.getByUUID(BLEUUID(descriptorUUID)); +} // getDescriptorByUUID + +/** + * @brief Return the BLE Descriptor for the given UUID if associated with this characteristic. + * @param [in] descriptorUUID The UUID of the descriptor that we wish to retrieve. + * @return The BLE Descriptor. If no such descriptor is associated with the characteristic, nullptr is returned. + */ +BLEDescriptor* BLECharacteristic::getDescriptorByUUID(BLEUUID descriptorUUID) { + return m_descriptorMap.getByUUID(descriptorUUID); +} // getDescriptorByUUID + + +/** + * @brief Get the handle of the characteristic. + * @return The handle of the characteristic. + */ +uint16_t BLECharacteristic::getHandle() { + return m_handle; +} // getHandle + + +esp_gatt_char_prop_t BLECharacteristic::getProperties() { + return m_properties; +} // getProperties + + +/** + * @brief Get the service associated with this characteristic. + */ +BLEService* BLECharacteristic::getService() { + return m_pService; +} // getService + + +/** + * @brief Get the UUID of the characteristic. + * @return The UUID of the characteristic. + */ +BLEUUID BLECharacteristic::getUUID() { + return m_bleUUID; +} // getUUID + + +/** + * @brief Retrieve the current value of the characteristic. + * @return A pointer to storage containing the current characteristic value. + */ +std::string BLECharacteristic::getValue() { + return m_value.getValue(); +} // getValue + + +void BLECharacteristic::handleGATTServerEvent( + esp_gatts_cb_event_t event, + esp_gatt_if_t gatts_if, + esp_ble_gatts_cb_param_t* param) { + switch(event) { + // Events handled: + // ESP_GATTS_ADD_CHAR_EVT + // ESP_GATTS_WRITE_EVT + // ESP_GATTS_READ_EVT + // + + // ESP_GATTS_EXEC_WRITE_EVT + // When we receive this event it is an indication that a previous write long needs to be committed. + // + // exec_write: + // - uint16_t conn_id + // - uint32_t trans_id + // - esp_bd_addr_t bda + // - uint8_t exec_write_flag + // + case ESP_GATTS_EXEC_WRITE_EVT: { + if (param->exec_write.exec_write_flag == ESP_GATT_PREP_WRITE_EXEC) { + m_value.commit(); + if (m_pCallbacks != nullptr) { + m_pCallbacks->onWrite(this); // Invoke the onWrite callback handler. + } + } else { + m_value.cancel(); + } + + esp_err_t errRc = ::esp_ble_gatts_send_response( + gatts_if, + param->write.conn_id, + param->write.trans_id, ESP_GATT_OK, nullptr); + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "esp_ble_gatts_send_response: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + } + break; + } // ESP_GATTS_EXEC_WRITE_EVT + + + // ESP_GATTS_ADD_CHAR_EVT - Indicate that a characteristic was added to the service. + // add_char: + // - esp_gatt_status_t status + // - uint16_t attr_handle + // - uint16_t service_handle + // - esp_bt_uuid_t char_uuid + case ESP_GATTS_ADD_CHAR_EVT: { + if (getUUID().equals(BLEUUID(param->add_char.char_uuid)) && + getService()->getHandle()==param->add_char.service_handle) { + m_semaphoreCreateEvt.give(); + } + break; + } // ESP_GATTS_ADD_CHAR_EVT + + + // ESP_GATTS_WRITE_EVT - A request to write the value of a characteristic has arrived. + // + // write: + // - uint16_t conn_id + // - uint16_t trans_id + // - esp_bd_addr_t bda + // - uint16_t handle + // - uint16_t offset + // - bool need_rsp + // - bool is_prep + // - uint16_t len + // - uint8_t *value + // + case ESP_GATTS_WRITE_EVT: { +// We check if this write request is for us by comparing the handles in the event. If it is for us +// we save the new value. Next we look at the need_rsp flag which indicates whether or not we need +// to send a response. If we do, then we formulate a response and send it. + if (param->write.handle == m_handle) { + if (param->write.is_prep) { + m_value.addPart(param->write.value, param->write.len); + } else { + setValue(param->write.value, param->write.len); + } + + ESP_LOGD(LOG_TAG, " - Response to write event: New value: handle: %.2x, uuid: %s", + getHandle(), getUUID().toString().c_str()); + + char *pHexData = BLEUtils::buildHexData(nullptr, param->write.value, param->write.len); + ESP_LOGD(LOG_TAG, " - Data: length: %d, data: %s", param->write.len, pHexData); + free(pHexData); + + if (param->write.need_rsp) { + esp_gatt_rsp_t rsp; + + rsp.attr_value.len = param->write.len; + rsp.attr_value.handle = m_handle; + rsp.attr_value.offset = param->write.offset; + rsp.attr_value.auth_req = ESP_GATT_AUTH_REQ_NONE; + memcpy(rsp.attr_value.value, param->write.value, param->write.len); + + esp_err_t errRc = ::esp_ble_gatts_send_response( + gatts_if, + param->write.conn_id, + param->write.trans_id, ESP_GATT_OK, &rsp); + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "esp_ble_gatts_send_response: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + } + } // Response needed + + if (m_pCallbacks != nullptr && param->write.is_prep != true) { + m_pCallbacks->onWrite(this); // Invoke the onWrite callback handler. + } + } // Match on handles. + break; + } // ESP_GATTS_WRITE_EVT + + + // ESP_GATTS_READ_EVT - A request to read the value of a characteristic has arrived. + // + // read: + // - uint16_t conn_id + // - uint32_t trans_id + // - esp_bd_addr_t bda + // - uint16_t handle + // - uint16_t offset + // - bool is_long + // - bool need_rsp + // + case ESP_GATTS_READ_EVT: { + ESP_LOGD(LOG_TAG, "- Testing: 0x%.2x == 0x%.2x", param->read.handle, m_handle); + if (param->read.handle == m_handle) { + + if (m_pCallbacks != nullptr) { + m_pCallbacks->onRead(this); // Invoke the read callback. + } + +// Here's an interesting thing. The read request has the option of saying whether we need a response +// or not. What would it "mean" to receive a read request and NOT send a response back? That feels like +// a very strange read. +// +// We have to handle the case where the data we wish to send back to the client is greater than the maximum +// packet size of 22 bytes. In this case, we become responsible for chunking the data into uints of 22 bytes. +// The apparent algorithm is as follows. +// If the is_long flag is set then this is a follow on from an original read and we will already have sent at least 22 bytes. +// If the is_long flag is not set then we need to check how much data we are going to send. If we are sending LESS than +// 22 bytes, then we "just" send it and thats the end of the story. +// If we are sending 22 bytes exactly, we just send it BUT we will get a follow on request. +// If we are sending more than 22 bytes, we send the first 22 bytes and we will get a follow on request. +// Because of follow on request processing, we need to maintain an offset of how much data we have already sent +// so that when a follow on request arrives, we know where to start in the data to send the next sequence. +// Note that the indication that the client will send a follow on request is that we sent exactly 22 bytes as a response. +// If our payload is divisible by 22 then the last response will be a response of 0 bytes in length. +// +// The following code has deliberately not been factored to make it fewer statements because this would cloud the +// the logic flow comprehension. +// + if (param->read.need_rsp) { + ESP_LOGD(LOG_TAG, "Sending a response (esp_ble_gatts_send_response)"); + esp_gatt_rsp_t rsp; + std::string value = m_value.getValue(); + if (param->read.is_long) { + if (value.length() - m_value.getReadOffset() < 22) { + // This is the last in the chain + rsp.attr_value.len = value.length() - m_value.getReadOffset(); + rsp.attr_value.offset = m_value.getReadOffset(); + memcpy(rsp.attr_value.value, value.data() + rsp.attr_value.offset, rsp.attr_value.len); + m_value.setReadOffset(0); + } else { + // There will be more to come. + rsp.attr_value.len = 22; + rsp.attr_value.offset = m_value.getReadOffset(); + memcpy(rsp.attr_value.value, value.data() + rsp.attr_value.offset, rsp.attr_value.len); + m_value.setReadOffset(rsp.attr_value.offset + 22); + } + } else { + if (value.length() > 21) { + // Too big for a single shot entry. + m_value.setReadOffset(22); + rsp.attr_value.len = 22; + rsp.attr_value.offset = 0; + memcpy(rsp.attr_value.value, value.data(), rsp.attr_value.len); + } else { + // Will fit in a single packet with no callbacks required. + rsp.attr_value.len = value.length(); + rsp.attr_value.offset = 0; + memcpy(rsp.attr_value.value, value.data(), rsp.attr_value.len); + } + } + rsp.attr_value.handle = param->read.handle; + rsp.attr_value.auth_req = ESP_GATT_AUTH_REQ_NONE; + + char *pHexData = BLEUtils::buildHexData(nullptr, rsp.attr_value.value, rsp.attr_value.len); + ESP_LOGD(LOG_TAG, " - Data: length=%d, data=%s, offset=%d", rsp.attr_value.len, pHexData, rsp.attr_value.offset); + free(pHexData); + + esp_err_t errRc = ::esp_ble_gatts_send_response( + gatts_if, param->read.conn_id, + param->read.trans_id, + ESP_GATT_OK, + &rsp); + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "esp_ble_gatts_send_response: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + } + } // Response needed + } // Handle matches this characteristic. + break; + } // ESP_GATTS_READ_EVT + + // ESP_GATTS_CONF_EVT + // + // conf: + // - esp_gatt_status_t status – The status code. + // - uint16_t conn_id – The connection used. + // + case ESP_GATTS_CONF_EVT: { + m_semaphoreConfEvt.give(); + break; + } + + default: { + break; + } // default + + } // switch event + + // Give each of the descriptors associated with this characteristic the opportunity to handle the + // event. + BLEDescriptor *pDescriptor = m_descriptorMap.getFirst(); + while(pDescriptor != nullptr) { + pDescriptor->handleGATTServerEvent(event, gatts_if, param); + pDescriptor = m_descriptorMap.getNext(); + } + +} // handleGATTServerEvent + +/** + * @brief Send an indication. + * An indication is a transmission of up to the first 20 bytes of the characteristic value. An indication + * will block waiting a positive confirmation from the client. + * @return N/A + */ +void BLECharacteristic::indicate() { + + ESP_LOGD(LOG_TAG, ">> indicate: length: %d", m_value.getValue().length()); + + assert(getService() != nullptr); + assert(getService()->getServer() != nullptr); + + GeneralUtils::hexDump((uint8_t*)m_value.getValue().data(), m_value.getValue().length()); + + if (getService()->getServer()->getConnectedCount() == 0) { + ESP_LOGD(LOG_TAG, "<< indicate: No connected clients."); + return; + } + + // Test to see if we have a 0x2902 descriptor. If we do, then check to see if indications are enabled + // and, if not, prevent the indication. + + BLE2902 *p2902 = (BLE2902*)getDescriptorByUUID((uint16_t)0x2902); + if (p2902 != nullptr && !p2902->getIndications()) { + ESP_LOGD(LOG_TAG, "<< indications disabled; ignoring"); + return; + } + + if (m_value.getValue().length() > 20) { + ESP_LOGD(LOG_TAG, "- Truncating to 20 bytes (maximum notify size)"); + } + + size_t length = m_value.getValue().length(); + if (length > 20) { + length = 20; + } + + m_semaphoreConfEvt.take("indicate"); + + esp_err_t errRc = ::esp_ble_gatts_send_indicate( + getService()->getServer()->getGattsIf(), + getService()->getServer()->getConnId(), + getHandle(), length, (uint8_t*)m_value.getValue().data(), true); // The need_confirm = true makes this an indication. + + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "<< esp_ble_gatts_send_indicate: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + + m_semaphoreConfEvt.wait("indicate"); + ESP_LOGD(LOG_TAG, "<< indicate"); +} // indicate + + +/** + * @brief Send a notify. + * A notification is a transmission of up to the first 20 bytes of the characteristic value. An notification + * will not block; it is a fire and forget. + * @return N/A. + */ +void BLECharacteristic::notify() { + ESP_LOGD(LOG_TAG, ">> notify: length: %d", m_value.getValue().length()); + + + assert(getService() != nullptr); + assert(getService()->getServer() != nullptr); + + + GeneralUtils::hexDump((uint8_t*)m_value.getValue().data(), m_value.getValue().length()); + + if (getService()->getServer()->getConnectedCount() == 0) { + ESP_LOGD(LOG_TAG, "<< notify: No connected clients."); + return; + } + + // Test to see if we have a 0x2902 descriptor. If we do, then check to see if notification is enabled + // and, if not, prevent the notification. + + BLE2902 *p2902 = (BLE2902*)getDescriptorByUUID((uint16_t)0x2902); + if (p2902 != nullptr && !p2902->getNotifications()) { + ESP_LOGD(LOG_TAG, "<< notifications disabled; ignoring"); + return; + } + + if (m_value.getValue().length() > 20) { + ESP_LOGD(LOG_TAG, "- Truncating to 20 bytes (maximum notify size)"); + } + + size_t length = m_value.getValue().length(); + if (length > 20) { + length = 20; + } + + esp_err_t errRc = ::esp_ble_gatts_send_indicate( + getService()->getServer()->getGattsIf(), + getService()->getServer()->getConnId(), + getHandle(), length, (uint8_t*)m_value.getValue().data(), false); // The need_confirm = false makes this a notify. + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "<< esp_ble_gatts_send_indicate: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + + ESP_LOGD(LOG_TAG, "<< notify"); +} // Notify + + +/** + * @brief Set the permission to broadcast. + * A characteristics has properties associated with it which define what it is capable of doing. + * One of these is the broadcast flag. + * @param [in] value The flag value of the property. + * @return N/A + */ +void BLECharacteristic::setBroadcastProperty(bool value) { + //ESP_LOGD(LOG_TAG, "setBroadcastProperty(%d)", value); + if (value) { + m_properties = (esp_gatt_char_prop_t)(m_properties | ESP_GATT_CHAR_PROP_BIT_BROADCAST); + } else { + m_properties = (esp_gatt_char_prop_t)(m_properties & ~ESP_GATT_CHAR_PROP_BIT_BROADCAST); + } +} // setBroadcastProperty + + +/** + * @brief Set the callback handlers for this characteristic. + * @param [in] pCallbacks An instance of a callbacks structure used to define any callbacks for the characteristic. + */ +void BLECharacteristic::setCallbacks(BLECharacteristicCallbacks* pCallbacks) { + m_pCallbacks = pCallbacks; +} // setCallbacks + + +/** + * @brief Set the BLE handle associated with this characteristic. + * A user program will request that a characteristic be created against a service. When the characteristic has been + * registered, the service will be given a "handle" that it knows the characteristic as. This handle is unique to the + * server/service but it is told to the service, not the characteristic associated with the service. This internally + * exposed function can be invoked by the service against this model of the characteristic to allow the characteristic + * to learn its own handle. Once the characteristic knows its own handle, it will be able to see incoming GATT events + * that will be propagated down to it which contain a handle value and now know that the event is destined for it. + * @param [in] handle The handle associated with this characteristic. + */ +void BLECharacteristic::setHandle(uint16_t handle) { + ESP_LOGD(LOG_TAG, ">> setHandle: handle=0x%.2x, characteristic uuid=%s", handle, getUUID().toString().c_str()); + m_handle = handle; + ESP_LOGD(LOG_TAG, "<< setHandle"); +} // setHandle + + +/** + * @brief Set the Indicate property value. + * @param [in] value Set to true if we are to allow indicate messages. + */ +void BLECharacteristic::setIndicateProperty(bool value) { + //ESP_LOGD(LOG_TAG, "setIndicateProperty(%d)", value); + if (value) { + m_properties = (esp_gatt_char_prop_t)(m_properties | ESP_GATT_CHAR_PROP_BIT_INDICATE); + } else { + m_properties = (esp_gatt_char_prop_t)(m_properties & ~ESP_GATT_CHAR_PROP_BIT_INDICATE); + } +} // setIndicateProperty + + +/** + * @brief Set the Notify property value. + * @param [in] value Set to true if we are to allow notification messages. + */ +void BLECharacteristic::setNotifyProperty(bool value) { + //ESP_LOGD(LOG_TAG, "setNotifyProperty(%d)", value); + if (value) { + m_properties = (esp_gatt_char_prop_t)(m_properties | ESP_GATT_CHAR_PROP_BIT_NOTIFY); + } else { + m_properties = (esp_gatt_char_prop_t)(m_properties & ~ESP_GATT_CHAR_PROP_BIT_NOTIFY); + } +} // setNotifyProperty + + +/** + * @brief Set the Read property value. + * @param [in] value Set to true if we are to allow reads. + */ +void BLECharacteristic::setReadProperty(bool value) { + //ESP_LOGD(LOG_TAG, "setReadProperty(%d)", value); + if (value) { + m_properties = (esp_gatt_char_prop_t)(m_properties | ESP_GATT_CHAR_PROP_BIT_READ); + } else { + m_properties = (esp_gatt_char_prop_t)(m_properties & ~ESP_GATT_CHAR_PROP_BIT_READ); + } +} // setReadProperty + + +/** + * @brief Set the value of the characteristic. + * @param [in] data The data to set for the characteristic. + * @param [in] length The length of the data in bytes. + */ +void BLECharacteristic::setValue(uint8_t* data, size_t length) { + char *pHex = BLEUtils::buildHexData(nullptr, data, length); + ESP_LOGD(LOG_TAG, ">> setValue: length=%d, data=%s, characteristic UUID=%s", length, pHex, getUUID().toString().c_str()); + free(pHex); + if (length > ESP_GATT_MAX_ATTR_LEN) { + ESP_LOGE(LOG_TAG, "Size %d too large, must be no bigger than %d", length, ESP_GATT_MAX_ATTR_LEN); + return; + } + m_value.setValue(data, length); + ESP_LOGD(LOG_TAG, "<< setValue"); +} // setValue + + +/** + * @brief Set the value of the characteristic from string data. + * We set the value of the characteristic from the bytes contained in the + * string. + * @param [in] Set the value of the characteristic. + * @return N/A. + */ +void BLECharacteristic::setValue(std::string value) { + setValue((uint8_t*)(value.data()), value.length()); +} // setValue + + +/** + * @brief Set the Write No Response property value. + * @param [in] value Set to true if we are to allow writes with no response. + */ +void BLECharacteristic::setWriteNoResponseProperty(bool value) { + //ESP_LOGD(LOG_TAG, "setWriteNoResponseProperty(%d)", value); + if (value) { + m_properties = (esp_gatt_char_prop_t)(m_properties | ESP_GATT_CHAR_PROP_BIT_WRITE_NR); + } else { + m_properties = (esp_gatt_char_prop_t)(m_properties & ~ESP_GATT_CHAR_PROP_BIT_WRITE_NR); + } +} // setWriteNoResponseProperty + + +/** + * @brief Set the Write property value. + * @param [in] value Set to true if we are to allow writes. + */ +void BLECharacteristic::setWriteProperty(bool value) { + //ESP_LOGD(LOG_TAG, "setWriteProperty(%d)", value); + if (value) { + m_properties = (esp_gatt_char_prop_t)(m_properties | ESP_GATT_CHAR_PROP_BIT_WRITE); + } else { + m_properties = (esp_gatt_char_prop_t)(m_properties & ~ESP_GATT_CHAR_PROP_BIT_WRITE); + } +} // setWriteProperty + + +/** + * @brief Return a string representation of the characteristic. + * @return A string representation of the characteristic. + */ +std::string BLECharacteristic::toString() { + std::stringstream stringstream; + stringstream << std::hex << std::setfill('0'); + stringstream << "UUID: " << m_bleUUID.toString() + ", handle: 0x" << std::setw(2) << m_handle; + stringstream << " " << + ((m_properties & ESP_GATT_CHAR_PROP_BIT_READ)?"Read ":"") << + ((m_properties & ESP_GATT_CHAR_PROP_BIT_WRITE)?"Write ":"") << + ((m_properties & ESP_GATT_CHAR_PROP_BIT_WRITE_NR)?"WriteNoResponse ":"") << + ((m_properties & ESP_GATT_CHAR_PROP_BIT_BROADCAST)?"Broadcast ":"") << + ((m_properties & ESP_GATT_CHAR_PROP_BIT_NOTIFY)?"Notify ":"") << + ((m_properties & ESP_GATT_CHAR_PROP_BIT_INDICATE)?"Indicate ":""); + return stringstream.str(); +} // toString + +#endif /* CONFIG_BT_ENABLED */ diff --git a/src/BLECharacteristic.h b/src/BLECharacteristic.h new file mode 100644 index 0000000..b39c022 --- /dev/null +++ b/src/BLECharacteristic.h @@ -0,0 +1,132 @@ +/* + * BLECharacteristic.h + * + * Created on: Jun 22, 2017 + * Author: kolban + */ + +#ifndef COMPONENTS_CPP_UTILS_BLECHARACTERISTIC_H_ +#define COMPONENTS_CPP_UTILS_BLECHARACTERISTIC_H_ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) +#include +#include +#include "BLEUUID.h" +#include +#include "BLEDescriptor.h" +#include "BLEValue.h" +#include "FreeRTOS.h" + +class BLEService; +class BLEDescriptor; +class BLECharacteristicCallbacks; + +/** + * @brief A management structure for %BLE descriptors. + */ +class BLEDescriptorMap { +public: + void setByUUID(const char* uuid, BLEDescriptor *pDescriptor); + void setByUUID(BLEUUID uuid, BLEDescriptor *pDescriptor); + void setByHandle(uint16_t handle, BLEDescriptor *pDescriptor); + BLEDescriptor *getByUUID(const char* uuid); + BLEDescriptor *getByUUID(BLEUUID uuid); + BLEDescriptor *getByHandle(uint16_t handle); + std::string toString(); + void handleGATTServerEvent( + esp_gatts_cb_event_t event, + esp_gatt_if_t gatts_if, + esp_ble_gatts_cb_param_t *param); + BLEDescriptor *getFirst(); + BLEDescriptor *getNext(); +private: + std::map m_uuidMap; + std::map m_handleMap; + std::map::iterator m_iterator; +}; + + +/** + * @brief The model of a %BLE Characteristic. + * + * A %BLE Characteristic is an identified value container that manages a value. It is exposed by a %BLE server and + * can be read and written to by a %BLE client. + */ +class BLECharacteristic { +public: + BLECharacteristic(const char* uuid, uint32_t properties = 0); + BLECharacteristic(BLEUUID uuid, uint32_t properties = 0); + virtual ~BLECharacteristic(); + + void addDescriptor(BLEDescriptor* pDescriptor); + BLEDescriptor* getDescriptorByUUID(const char* descriptorUUID); + BLEDescriptor* getDescriptorByUUID(BLEUUID descriptorUUID); + //size_t getLength(); + BLEUUID getUUID(); + std::string getValue(); + + void indicate(); + void notify(); + void setBroadcastProperty(bool value); + void setCallbacks(BLECharacteristicCallbacks* pCallbacks); + void setIndicateProperty(bool value); + void setNotifyProperty(bool value); + void setReadProperty(bool value); + void setValue(uint8_t* data, size_t size); + void setValue(std::string value); + void setWriteProperty(bool value); + void setWriteNoResponseProperty(bool value); + std::string toString(); + + + static const uint32_t PROPERTY_READ = 1<<0; + static const uint32_t PROPERTY_WRITE = 1<<1; + static const uint32_t PROPERTY_NOTIFY = 1<<2; + static const uint32_t PROPERTY_BROADCAST = 1<<3; + static const uint32_t PROPERTY_INDICATE = 1<<4; + static const uint32_t PROPERTY_WRITE_NR = 1<<5; + +private: + friend class BLEServer; + friend class BLEService; + friend class BLEDescriptor; + friend class BLECharacteristicMap; + + BLEUUID m_bleUUID; + BLEDescriptorMap m_descriptorMap; + uint16_t m_handle; + esp_gatt_char_prop_t m_properties; + BLECharacteristicCallbacks* m_pCallbacks; + BLEService* m_pService; + BLEValue m_value; + + void handleGATTServerEvent( + esp_gatts_cb_event_t event, + esp_gatt_if_t gatts_if, + esp_ble_gatts_cb_param_t* param); + + void executeCreate(BLEService* pService); + uint16_t getHandle(); + esp_gatt_char_prop_t getProperties(); + BLEService* getService(); + void setHandle(uint16_t handle); + FreeRTOS::Semaphore m_semaphoreCreateEvt = FreeRTOS::Semaphore("CreateEvt"); + FreeRTOS::Semaphore m_semaphoreConfEvt = FreeRTOS::Semaphore("ConfEvt"); +}; // BLECharacteristic + + +/** + * @brief Callbacks that can be associated with a %BLE characteristic to inform of events. + * + * When a server application creates a %BLE characteristic, we may wish to be informed when there is either + * a read or write request to the characteristic's value. An application can register a + * sub-classed instance of this class and will be notified when such an event happens. + */ +class BLECharacteristicCallbacks { +public: + virtual ~BLECharacteristicCallbacks(); + virtual void onRead(BLECharacteristic* pCharacteristic); + virtual void onWrite(BLECharacteristic* pCharacteristic); +}; +#endif /* CONFIG_BT_ENABLED */ +#endif /* COMPONENTS_CPP_UTILS_BLECHARACTERISTIC_H_ */ diff --git a/src/BLECharacteristicCallbacks.cpp b/src/BLECharacteristicCallbacks.cpp new file mode 100644 index 0000000..b733865 --- /dev/null +++ b/src/BLECharacteristicCallbacks.cpp @@ -0,0 +1,34 @@ +/* + * BLECharacteristicCallbacks.cpp + * + * Created on: Jul 2, 2017 + * Author: kolban + */ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) +#include "BLECharacteristic.h" +#include +static const char* LOG_TAG = "BLECharacteristicCallbacks"; + + +BLECharacteristicCallbacks::~BLECharacteristicCallbacks() {} + +/** + * @brief Callback function to support a read request. + * @param [in] pCharacteristic The characteristic that is the source of the event. + */ +void BLECharacteristicCallbacks::onRead(BLECharacteristic *pCharacteristic) { + ESP_LOGD(LOG_TAG, ">> onRead: default"); + ESP_LOGD(LOG_TAG, "<< onRead"); +} // onRead + + +/** + * @brief Callback function to support a write request. + * @param [in] pCharacteristic The characteristic that is the source of the event. + */ +void BLECharacteristicCallbacks::onWrite(BLECharacteristic *pCharacteristic) { + ESP_LOGD(LOG_TAG, ">> onWrite: default"); + ESP_LOGD(LOG_TAG, "<< onWrite"); +} // onWrite +#endif /* CONFIG_BT_ENABLED */ diff --git a/src/BLECharacteristicMap.cpp b/src/BLECharacteristicMap.cpp new file mode 100644 index 0000000..f475e83 --- /dev/null +++ b/src/BLECharacteristicMap.cpp @@ -0,0 +1,136 @@ +/* + * BLECharacteristicMap.cpp + * + * Created on: Jun 22, 2017 + * Author: kolban + */ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) +#include +#include +#include "BLEService.h" + +/** + * @brief Return the characteristic by UUID. + * @param [in] UUID The UUID to look up the characteristic. + * @return The characteristic. + */ +BLECharacteristic* BLECharacteristicMap::getByUUID(const char* uuid) { + return getByUUID(BLEUUID(uuid)); +} + +/** + * @brief Return the characteristic by UUID. + * @param [in] UUID The UUID to look up the characteristic. + * @return The characteristic. + */ +BLECharacteristic* BLECharacteristicMap::getByUUID(BLEUUID uuid) { + for (auto &myPair : m_uuidMap) { + if (myPair.second->getUUID().equals(uuid)) { + return myPair.second; + } + } + //return m_uuidMap.at(uuid.toString()); + return nullptr; +} // getByUUID + + +/** + * @brief Return the characteristic by handle. + * @param [in] handle The handle to look up the characteristic. + * @return The characteristic. + */ +BLECharacteristic* BLECharacteristicMap::getByHandle(uint16_t handle) { + return m_handleMap.at(handle); +} // getByHandle + + +/** + * @brief Set the characteristic by UUID. + * @param [in] uuid The uuid of the characteristic. + * @param [in] characteristic The characteristic to cache. + * @return N/A. + */ +void BLECharacteristicMap::setByUUID( + BLEUUID uuid, + BLECharacteristic *pCharacteristic) { + m_uuidMap.insert(std::pair(uuid.toString(), pCharacteristic)); +} // setByUUID + + +/** + * @brief Set the characteristic by handle. + * @param [in] handle The handle of the characteristic. + * @param [in] characteristic The characteristic to cache. + * @return N/A. + */ +void BLECharacteristicMap::setByHandle(uint16_t handle, + BLECharacteristic *characteristic) { + m_handleMap.insert(std::pair(handle, characteristic)); +} // setByHandle + + +/** + * @brief Return a string representation of the characteristic map. + * @return A string representation of the characteristic map. + */ +std::string BLECharacteristicMap::toString() { + std::stringstream stringStream; + stringStream << std::hex << std::setfill('0'); + int count=0; + for (auto &myPair: m_uuidMap) { + if (count > 0) { + stringStream << "\n"; + } + count++; + stringStream << "handle: 0x" << std::setw(2) << myPair.second->getHandle() << ", uuid: " + myPair.second->getUUID().toString(); + } + return stringStream.str(); +} // toString + + +/** + * @breif Pass the GATT server event onwards to each of the characteristics found in the mapping + * @param [in] event + * @param [in] gatts_if + * @param [in] param + */ +void BLECharacteristicMap::handleGATTServerEvent( + esp_gatts_cb_event_t event, + esp_gatt_if_t gatts_if, + esp_ble_gatts_cb_param_t *param) { + // Invoke the handler for every Service we have. + for (auto &myPair : m_uuidMap) { + myPair.second->handleGATTServerEvent(event, gatts_if, param); + } +} // handleGATTServerEvent + + +/** + * @brief Get the first characteristic in the map. + * @return The first characteristic in the map. + */ +BLECharacteristic* BLECharacteristicMap::getFirst() { + m_iterator = m_uuidMap.begin(); + if (m_iterator == m_uuidMap.end()) { + return nullptr; + } + BLECharacteristic *pRet = m_iterator->second; + m_iterator++; + return pRet; +} // getFirst + + +/** + * @brief Get the next characteristic in the map. + * @return The next characteristic in the map. + */ +BLECharacteristic* BLECharacteristicMap::getNext() { + if (m_iterator == m_uuidMap.end()) { + return nullptr; + } + BLECharacteristic *pRet = m_iterator->second; + m_iterator++; + return pRet; +} // getNext +#endif /* CONFIG_BT_ENABLED */ diff --git a/src/BLEClient.cpp b/src/BLEClient.cpp new file mode 100644 index 0000000..a5d60cf --- /dev/null +++ b/src/BLEClient.cpp @@ -0,0 +1,327 @@ +/* + * BLEDevice.cpp + * + * Created on: Mar 22, 2017 + * Author: kolban + */ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) +#include +#include +#include +#include +#include +#include "BLEClient.h" +#include "BLEUtils.h" +#include "BLEService.h" +#include "GeneralUtils.h" +#include +#include +#include + +/* + * Design + * ------ + * When we perform a searchService() requests, we are asking the BLE server to return each of the services + * that it exposes. For each service, we received an ESP_GATTC_SEARCH_RES_EVT event which contains details + * of the exposed service including its UUID. + * + * The objects we will invent for a BLEClient will be as follows: + * * BLERemoteService - A model of a remote service. + * * BLERemoteCharacteristic - A model of a remote characteristic + * * BLERemoteDescriptor - A model of a remote descriptor. + * + * Since there is a hierarchical relationship here, we will have the idea that from a BLERemoteService will own + * zero or more remote characteristics and a BLERemoteCharacteristic will own zero or more remote BLEDescriptors. + * + * We will assume that a BLERemoteService contains a map that maps BLEUUIDs to the set of owned characteristics + * and that a BLECharacteristic contains a map that maps BLEUUIDs to the set of owned descriptors. + * + * + */ +static const char* LOG_TAG = "BLEClient"; + +BLEClient::BLEClient() { + m_pClientCallbacks = nullptr; + m_conn_id = 0; + m_gattc_if = 0; + m_haveServices = false; +} // BLEClient + +/** + * @brief Connect to the partner. + * @param [in] address The address of the partner. + */ +bool BLEClient::connect(BLEAddress address) { + ESP_LOGD(LOG_TAG, ">> connect(%s)", address.toString().c_str()); +// We need the connection handle that we get from registering the application. We register the app +// and then block on its completion. When the event has arrived, we will have the handle. + m_semaphoreRegEvt.take("connect"); + esp_err_t errRc = esp_ble_gattc_app_register(0); + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "esp_ble_gattc_app_register: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return false; + } + m_semaphoreRegEvt.wait("connect"); + + m_peerAddress = address; + + m_semaphoreOpenEvt.take("connect"); + errRc = ::esp_ble_gattc_open( + getGattcIf(), + *getPeerAddress().getNative(), // address + 1 // direct connection + ); + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "esp_ble_gattc_open: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return false; + } + + uint32_t rc = m_semaphoreOpenEvt.wait("connect"); + ESP_LOGD(LOG_TAG, "<< connect(), rc=%d", rc==ESP_GATT_OK); + return rc == ESP_GATT_OK; +} // connect + + +/** + * @brief Disconnect from the peer. + * @return N/A. + */ +void BLEClient::disconnect() { + ESP_LOGD(LOG_TAG, ">> disconnect()"); + esp_err_t errRc = ::esp_ble_gattc_close(getGattcIf(), getConnId()); + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "esp_ble_gattc_close: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + m_peerAddress = BLEAddress("00:00:00:00:00:00"); + ESP_LOGD(LOG_TAG, "<< disconnect()"); +} // disconnect + + +/** + * @brief Handle GATT Client events + */ +void BLEClient::gattClientEventHandler( + esp_gattc_cb_event_t event, + esp_gatt_if_t gattc_if, + esp_ble_gattc_cb_param_t* evtParam) { + + // Execute handler code based on the type of event received. + switch(event) { + // + // ESP_GATTC_NOTIFY_EVT + // + // notify + // uint16_t conn_id + // esp_bd_addr_t remote_bda + // esp_gatt_srvc_id_t srvc_id + // esp_gatt_id_t char_id + // esp_gatt_id_t descr_id + // uint16_t value_len + // uint8_t* value + // bool is_notify + // + case ESP_GATTC_NOTIFY_EVT: { + BLERemoteService *pBLERemoteService = getService(BLEUUID(evtParam->notify.srvc_id.id.uuid)); + if (pBLERemoteService == nullptr) { + ESP_LOGE(LOG_TAG, "Could not find service with UUID %s for notification", BLEUUID(evtParam->notify.srvc_id.id.uuid).toString().c_str()); + break; + } + BLERemoteCharacteristic* pBLERemoteCharacteristic = pBLERemoteService->getCharacteristic(BLEUUID(evtParam->notify.char_id.uuid)); + if (pBLERemoteCharacteristic == nullptr) { + ESP_LOGE(LOG_TAG, "Could not find characteristic with UUID %s for notification", BLEUUID(evtParam->notify.char_id.uuid).toString().c_str()); + break; + } + if (pBLERemoteCharacteristic->m_notifyCallback != nullptr) { + pBLERemoteCharacteristic->m_notifyCallback(pBLERemoteCharacteristic, evtParam->notify.value, evtParam->notify.value_len, evtParam->notify.is_notify); + } + break; + } // ESP_GATTC_NOTIFY_EVT + + // + // ESP_GATTC_OPEN_EVT + // + // open: + // - esp_gatt_status_t status + // - uint16_t conn_id + // - esp_bd_addr_t remote_bda + // - uint16_t mtu + // + case ESP_GATTC_OPEN_EVT: { + m_conn_id = evtParam->open.conn_id; + if (m_pClientCallbacks != nullptr) { + m_pClientCallbacks->onConnect(this); + } + m_semaphoreOpenEvt.give(); + break; + } // ESP_GATTC_OPEN_EVT + + + // + // ESP_GATTC_REG_EVT + // + // reg: + // esp_gatt_status_t status + // uint16_t app_id + // + case ESP_GATTC_REG_EVT: { + m_gattc_if = gattc_if; + m_semaphoreRegEvt.give(); + break; + } // ESP_GATTC_REG_EVT + + + // + // ESP_GATTC_SEARCH_CMPL_EVT + // + // search_cmpl: + // - esp_gatt_status_t status + // - uint16_t conn_id + // + case ESP_GATTC_SEARCH_CMPL_EVT: { + m_semaphoreSearchCmplEvt.give(); + break; + } // ESP_GATTC_SEARCH_CMPL_EVT + + + // + // ESP_GATTC_SEARCH_RES_EVT + // + // search_res: + // - uint16_t conn_id + // - esp_gatt_srvc_id_t srvc_id + // + case ESP_GATTC_SEARCH_RES_EVT: { + BLEUUID uuid = BLEUUID(evtParam->search_res.srvc_id); + BLERemoteService* pRemoteService = new BLERemoteService(evtParam->search_res.srvc_id, this); + m_servicesMap.insert(std::pair(uuid.toString(), pRemoteService)); + break; + } // ESP_GATTC_SEARCH_RES_EVT + + + default: { + break; + } + } // Switch + + for (auto &myPair : m_servicesMap) { + myPair.second->gattClientEventHandler(event, gattc_if, evtParam); + } + +} // gattClientEventHandler + + +/** + * @brief Retrieve the address of the peer. + * + * Returns the address of the %BLE peer to which this client is connected. + */ +BLEAddress BLEClient::getPeerAddress() { + return m_peerAddress; +} // getAddress + + +uint16_t BLEClient::getConnId() { + return m_conn_id; +} // getConnId + + +esp_gatt_if_t BLEClient::getGattcIf() { + return m_gattc_if; +} // getGattcIf + + + +/** + * @brief Get the service object corresponding to the uuid. + * @param [in] uuid The UUID of the service being sought. + * @return A reference to the Service or nullptr if don't know about it. + */ +BLERemoteService* BLEClient::getService(const char* uuid) { + return getService(BLEUUID(uuid)); +} + + +/** + * @brief Get the service object corresponding to the uuid. + * @param [in] uuid The UUID of the service being sought. + * @return A reference to the Service or nullptr if don't know about it. + */ +BLERemoteService* BLEClient::getService(BLEUUID uuid) { +// Design +// ------ +// We wish to retrieve the service given its UUID. It is possible that we have not yet asked the +// device what services it has in which case we have nothing to match against. If we have not +// asked the device about its services, then we do that now. Once we get the results we can then +// examine the services map to see if it has the service we are looking for. + if (!m_haveServices) { + getServices(); + } + std::string v = uuid.toString(); + for (auto &myPair : m_servicesMap) { + if (myPair.first == v) { + return myPair.second; + } + } + return nullptr; +} // getService + + +/** + * @brief Ask the remote %BLE server for its services. + * A %BLE Server exposes a set of services for its partners. Here we ask the server for its set of + * services and wait until we have received them all. + * @return N/A + */ +std::map* BLEClient::getServices() { +/* + * Design + * ------ + * We invoke esp_ble_gattc_search_service. This will request a list of the service exposed by the + * peer BLE partner to be returned as events. Each event will be an an instance of ESP_GATTC_SEARCH_RES_EVT + * and will culminate with an ESP_GATTC_SEARCH_CMPL_EVT when all have been received. + */ + ESP_LOGD(LOG_TAG, ">> getServices"); + m_servicesMap.empty(); + esp_err_t errRc = esp_ble_gattc_search_service( + getGattcIf(), + getConnId(), + NULL // Filter UUID + ); + m_semaphoreSearchCmplEvt.take("getServices"); + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "esp_ble_gattc_search_service: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return &m_servicesMap; + } + m_semaphoreSearchCmplEvt.wait("getServices"); + m_haveServices = true; // Remember that we now have services. + ESP_LOGD(LOG_TAG, "<< getServices"); + return &m_servicesMap; +} // getServices + + +/** + * @brief Set the callbacks that will be invoked. + */ +void BLEClient::setClientCallbacks(BLEClientCallbacks* pClientCallbacks) { + m_pClientCallbacks = pClientCallbacks; +} // setClientCallbacks + + +/** + * @brief Return a string representation of this client. + * @return A string representation of this client. + */ +std::string BLEClient::toString() { + std::ostringstream ss; + ss << "peer address: " << m_peerAddress.toString(); + ss << "\nServices:\n"; + for (auto &myPair : m_servicesMap) { + ss << myPair.second->toString() << "\n"; + // myPair.second is the value + } + return ss.str(); +} // toString + +#endif // CONFIG_BT_ENABLED diff --git a/src/BLEClient.h b/src/BLEClient.h new file mode 100644 index 0000000..898f98c --- /dev/null +++ b/src/BLEClient.h @@ -0,0 +1,76 @@ +/* + * BLEDevice.h + * + * Created on: Mar 22, 2017 + * Author: kolban + */ + +#ifndef MAIN_BLEDEVICE_H_ +#define MAIN_BLEDEVICE_H_ + +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) + +#include +#include +#include +#include +#include +#include "BLEService.h" +#include "BLEAddress.h" + +class BLERemoteService; +class BLEClientCallbacks; + +/** + * @brief A model of a %BLE client. + */ +class BLEClient { +public: + BLEClient(); + bool connect(BLEAddress address); + void disconnect(); + BLEAddress getPeerAddress(); + std::map* getServices(); + BLERemoteService* getService(const char* uuid); + BLERemoteService* getService(BLEUUID uuid); + void setClientCallbacks(BLEClientCallbacks *pClientCallbacks); + std::string toString(); + +private: + friend class BLEDevice; + friend class BLERemoteCharacteristic; + friend class BLERemoteService; + + void gattClientEventHandler( + esp_gattc_cb_event_t event, + esp_gatt_if_t gattc_if, + esp_ble_gattc_cb_param_t* param); + + uint16_t getConnId(); + esp_gatt_if_t getGattcIf(); + BLEAddress m_peerAddress = BLEAddress((uint8_t*)"\0\0\0\0\0\0"); + uint16_t m_conn_id; +// int m_deviceType; + esp_gatt_if_t m_gattc_if; + + BLEClientCallbacks* m_pClientCallbacks; + FreeRTOS::Semaphore m_semaphoreRegEvt = FreeRTOS::Semaphore("RegEvt"); + FreeRTOS::Semaphore m_semaphoreOpenEvt = FreeRTOS::Semaphore("OpenEvt"); + FreeRTOS::Semaphore m_semaphoreSearchCmplEvt = FreeRTOS::Semaphore("SearchCmplEvt"); + std::map m_servicesMap; + bool m_haveServices; // Have we previously obtain the set of services. +}; // class BLEDevice + + +/** + * @brief Callbacks associated with a %BLE client. + */ +class BLEClientCallbacks { +public: + virtual ~BLEClientCallbacks() {}; + virtual void onConnect(BLEClient *pClient) = 0; +}; + +#endif // CONFIG_BT_ENABLED +#endif /* MAIN_BLEDEVICE_H_ */ diff --git a/src/BLEDescriptor.cpp b/src/BLEDescriptor.cpp new file mode 100644 index 0000000..4a7fda6 --- /dev/null +++ b/src/BLEDescriptor.cpp @@ -0,0 +1,278 @@ +/* + * BLEDescriptor.cpp + * + * Created on: Jun 22, 2017 + * Author: kolban + */ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) +#include +#include +#include +#include +#include "sdkconfig.h" +#include +#include +#include "BLEService.h" +#include "BLEDescriptor.h" +#include "GeneralUtils.h" + +static const char* LOG_TAG = "BLEDescriptor"; + + +#define NULL_HANDLE (0xffff) + + +/** + * @brief BLEDescriptor constructor. + */ +BLEDescriptor::BLEDescriptor(const char* uuid) : BLEDescriptor(BLEUUID(uuid)) { +} + +/** + * @brief BLEDescriptor constructor. + */ +BLEDescriptor::BLEDescriptor(BLEUUID uuid) { + m_bleUUID = uuid; + m_value.attr_value = (uint8_t *)malloc(ESP_GATT_MAX_ATTR_LEN); // Allocate storage for the value. + m_value.attr_len = 0; + m_value.attr_max_len = ESP_GATT_MAX_ATTR_LEN; + m_handle = NULL_HANDLE; + m_pCharacteristic = nullptr; // No initial characteristic. + +} // BLEDescriptor + + +/** + * @brief BLEDescriptor destructor. + */ +BLEDescriptor::~BLEDescriptor() { + free(m_value.attr_value); +} // ~BLEDescriptor + + +/** + * @brief Execute the creation of the descriptor with the BLE runtime in ESP. + * @param [in] pCharacteristic The characteristic to which to register this descriptor. + */ +void BLEDescriptor::executeCreate(BLECharacteristic* pCharacteristic) { + ESP_LOGD(LOG_TAG, ">> executeCreate(): %s", toString().c_str()); + + if (m_handle != NULL_HANDLE) { + ESP_LOGE(LOG_TAG, "Descriptor already has a handle."); + return; + } + + m_pCharacteristic = pCharacteristic; // Save the characteristic associated with this service. + + esp_attr_control_t control; + control.auto_rsp = ESP_GATT_RSP_BY_APP; + m_semaphoreCreateEvt.take("executeCreate"); + esp_err_t errRc = ::esp_ble_gatts_add_char_descr( + pCharacteristic->getService()->getHandle(), + getUUID().getNative(), + (esp_gatt_perm_t)(ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE), + &m_value, + &control); + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "<< esp_ble_gatts_add_char_descr: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + + m_semaphoreCreateEvt.wait("executeCreate"); + ESP_LOGD(LOG_TAG, "<< executeCreate"); +} // executeCreate + + +/** + * @brief Get the BLE handle for this descriptor. + * @return The handle for this descriptor. + */ +uint16_t BLEDescriptor::getHandle() { + return m_handle; +} // getHandle + + +/** + * @brief Get the length of the value of this descriptor. + * @return The length (in bytes) of the value of this descriptor. + */ +size_t BLEDescriptor::getLength() { + return m_value.attr_len; +} // getLength + + +/** + * @brief Get the UUID of the descriptor. + */ +BLEUUID BLEDescriptor::getUUID() { + return m_bleUUID; +} // getUUID + + + +/** + * @brief Get the value of this descriptor. + * @return A pointer to the value of this descriptor. + */ +uint8_t* BLEDescriptor::getValue() { + return m_value.attr_value; +} // getValue + + +/** + * @brief Handle GATT server events for the descripttor. + * @param [in] event + * @param [in] gatts_if + * @param [in] param + */ +void BLEDescriptor::handleGATTServerEvent( + esp_gatts_cb_event_t event, + esp_gatt_if_t gatts_if, + esp_ble_gatts_cb_param_t *param) { + switch(event) { + // ESP_GATTS_ADD_CHAR_DESCR_EVT + // + // add_char_descr: + // - esp_gatt_status_t status + // - uint16_t attr_handle + // - uint16_t service_handle + // - esp_bt_uuid_t char_uuid + case ESP_GATTS_ADD_CHAR_DESCR_EVT: { + /* + ESP_LOGD(LOG_TAG, "DEBUG: m_pCharacteristic: %x", (uint32_t)m_pCharacteristic); + ESP_LOGD(LOG_TAG, "DEBUG: m_bleUUID: %s, add_char_descr.char_uuid: %s, equals: %d", + m_bleUUID.toString().c_str(), + BLEUUID(param->add_char_descr.char_uuid).toString().c_str(), + m_bleUUID.equals(BLEUUID(param->add_char_descr.char_uuid))); + ESP_LOGD(LOG_TAG, "DEBUG: service->getHandle: %x, add_char_descr.service_handle: %x", + m_pCharacteristic->getService()->getHandle(), param->add_char_descr.service_handle); + ESP_LOGD(LOG_TAG, "DEBUG: service->lastCharacteristic: %x", + (uint32_t)m_pCharacteristic->getService()->getLastCreatedCharacteristic()); + */ + if (m_pCharacteristic != nullptr && + m_bleUUID.equals(BLEUUID(param->add_char_descr.char_uuid)) && + m_pCharacteristic->getService()->getHandle() == param->add_char_descr.service_handle && + m_pCharacteristic == m_pCharacteristic->getService()->getLastCreatedCharacteristic()) { + setHandle(param->add_char_descr.attr_handle); + m_semaphoreCreateEvt.give(); + } + break; + } // ESP_GATTS_ADD_CHAR_DESCR_EVT + + // ESP_GATTS_WRITE_EVT - A request to write the value of a descriptor has arrived. + // + // write: + // - uint16_t conn_id + // - uint16_t trans_id + // - esp_bd_addr_t bda + // - uint16_t handle + // - uint16_t offset + // - bool need_rsp + // - bool is_prep + // - uint16_t len + // - uint8_t *value + case ESP_GATTS_WRITE_EVT: { + if (param->write.handle == m_handle) { + setValue(param->write.value, param->write.len); + esp_gatt_rsp_t rsp; + rsp.attr_value.len = getLength(); + rsp.attr_value.handle = m_handle; + rsp.attr_value.offset = 0; + rsp.attr_value.auth_req = ESP_GATT_AUTH_REQ_NONE; + memcpy(rsp.attr_value.value, getValue(), rsp.attr_value.len); + esp_err_t errRc = ::esp_ble_gatts_send_response( + gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, &rsp); + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "esp_ble_gatts_send_response: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + } + } + break; + } // ESP_GATTS_WRITE_EVT + + // ESP_GATTS_READ_EVT - A request to read the value of a descriptor has arrived. + // + // read: + // - uint16_t conn_id + // - uint32_t trans_id + // - esp_bd_addr_t bda + // - uint16_t handle + // - uint16_t offset + // - bool is_long + // - bool need_rsp + // + case ESP_GATTS_READ_EVT: { + ESP_LOGD(LOG_TAG, "- Testing: Sought handle: 0x%.2x == descriptor handle: 0x%.2x ?", param->read.handle, m_handle); + if (param->read.handle == m_handle) { + ESP_LOGD(LOG_TAG, "Sending a response (esp_ble_gatts_send_response)"); + if (param->read.need_rsp) { + esp_gatt_rsp_t rsp; + rsp.attr_value.len = getLength(); + rsp.attr_value.handle = param->read.handle; + rsp.attr_value.offset = 0; + rsp.attr_value.auth_req = ESP_GATT_AUTH_REQ_NONE; + memcpy(rsp.attr_value.value, getValue(), rsp.attr_value.len); + esp_err_t errRc = ::esp_ble_gatts_send_response( + gatts_if, param->read.conn_id, param->read.trans_id, ESP_GATT_OK, &rsp); + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "esp_ble_gatts_send_response: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + } + } + } // ESP_GATTS_READ_EVT + break; + } // ESP_GATTS_READ_EVT + default: { + break; + } + }// switch event +} // handleGATTServerEvent + + +/** + * @brief Set the handle of this descriptor. + * Set the handle of this descriptor to be the supplied value. + * @param [in] handle The handle to be associated with this descriptor. + * @return N/A. + */ +void BLEDescriptor::setHandle(uint16_t handle) { + ESP_LOGD(LOG_TAG, ">> setHandle(0x%.2x): Setting descriptor handle to be 0x%.2x", handle, handle); + m_handle = handle; + ESP_LOGD(LOG_TAG, "<< setHandle()"); +} // setHandle + + +/** + * @brief Set the value of the descriptor. + * @param [in] data The data to set for the descriptor. + * @param [in] length The length of the data in bytes. + */ +void BLEDescriptor::setValue(uint8_t* data, size_t length) { + if (length > ESP_GATT_MAX_ATTR_LEN) { + ESP_LOGE(LOG_TAG, "Size %d too large, must be no bigger than %d", length, ESP_GATT_MAX_ATTR_LEN); + return; + } + m_value.attr_len = length; + memcpy(m_value.attr_value, data, length); +} // setValue + + +/** + * @brief Set the value of the descriptor. + * @param [in] value The value of the descriptor in string form. + */ +void BLEDescriptor::setValue(std::string value) { + setValue((uint8_t *)value.data(), value.length()); +} // setValue + + +/** + * @brief Return a string representation of the descriptor. + * @return A string representation of the descriptor. + */ +std::string BLEDescriptor::toString() { + std::stringstream stringstream; + stringstream << std::hex << std::setfill('0'); + stringstream << "UUID: " << m_bleUUID.toString() + ", handle: 0x" << std::setw(2) << m_handle; + return stringstream.str(); +} // toString +#endif /* CONFIG_BT_ENABLED */ diff --git a/src/BLEDescriptor.h b/src/BLEDescriptor.h new file mode 100644 index 0000000..1d32d50 --- /dev/null +++ b/src/BLEDescriptor.h @@ -0,0 +1,54 @@ +/* + * BLEDescriptor.h + * + * Created on: Jun 22, 2017 + * Author: kolban + */ + +#ifndef COMPONENTS_CPP_UTILS_BLEDESCRIPTOR_H_ +#define COMPONENTS_CPP_UTILS_BLEDESCRIPTOR_H_ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) +#include +#include "BLEUUID.h" +#include "BLECharacteristic.h" +#include +#include "FreeRTOS.h" + +class BLEService; +class BLECharacteristic; + +/** + * @brief A model of a %BLE descriptor. + */ +class BLEDescriptor { +public: + BLEDescriptor(const char* uuid); + BLEDescriptor(BLEUUID uuid); + virtual ~BLEDescriptor(); + + size_t getLength(); + BLEUUID getUUID(); + uint8_t* getValue(); + void handleGATTServerEvent( + esp_gatts_cb_event_t event, + esp_gatt_if_t gatts_if, + esp_ble_gatts_cb_param_t* param); + void setValue(uint8_t* data, size_t size); + void setValue(std::string value); + std::string toString(); + +private: + friend class BLEDescriptorMap; + friend class BLECharacteristic; + BLEUUID m_bleUUID; + esp_attr_value_t m_value; + uint16_t m_handle; + BLECharacteristic* m_pCharacteristic; + void executeCreate(BLECharacteristic* pCharacteristic); + uint16_t getHandle(); + void setHandle(uint16_t handle); + FreeRTOS::Semaphore m_semaphoreCreateEvt = FreeRTOS::Semaphore("CreateEvt"); +}; +#endif /* CONFIG_BT_ENABLED */ +#endif /* COMPONENTS_CPP_UTILS_BLEDESCRIPTOR_H_ */ diff --git a/src/BLEDescriptorMap.cpp b/src/BLEDescriptorMap.cpp new file mode 100644 index 0000000..b211652 --- /dev/null +++ b/src/BLEDescriptorMap.cpp @@ -0,0 +1,149 @@ +/* + * BLEDescriptorMap.cpp + * + * Created on: Jun 22, 2017 + * Author: kolban + */ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) +#include +#include +#include "BLECharacteristic.h" +#include "BLEDescriptor.h" +#include // ESP32 BLE + +/** + * @brief Return the descriptor by UUID. + * @param [in] UUID The UUID to look up the descriptor. + * @return The descriptor. If not present, then nullptr is returned. + */ +BLEDescriptor* BLEDescriptorMap::getByUUID(const char* uuid) { + return getByUUID(BLEUUID(uuid)); +} + + +/** + * @brief Return the descriptor by UUID. + * @param [in] UUID The UUID to look up the descriptor. + * @return The descriptor. If not present, then nullptr is returned. + */ +BLEDescriptor* BLEDescriptorMap::getByUUID(BLEUUID uuid) { + for (auto &myPair : m_uuidMap) { + if (myPair.second->getUUID().equals(uuid)) { + return myPair.second; + } + } + //return m_uuidMap.at(uuid.toString()); + return nullptr; +} // getByUUID + + +/** + * @brief Return the descriptor by handle. + * @param [in] handle The handle to look up the descriptor. + * @return The descriptor. + */ +BLEDescriptor* BLEDescriptorMap::getByHandle(uint16_t handle) { + return m_handleMap.at(handle); +} // getByHandle + + +/** + * @brief Set the descriptor by UUID. + * @param [in] uuid The uuid of the descriptor. + * @param [in] characteristic The descriptor to cache. + * @return N/A. + */ +void BLEDescriptorMap::setByUUID(const char* uuid, BLEDescriptor *pDescriptor){ + m_uuidMap.insert(std::pair(uuid, pDescriptor)); +} // setByUUID + + + +/** + * @brief Set the descriptor by UUID. + * @param [in] uuid The uuid of the descriptor. + * @param [in] characteristic The descriptor to cache. + * @return N/A. + */ +void BLEDescriptorMap::setByUUID(BLEUUID uuid, BLEDescriptor *pDescriptor) { + m_uuidMap.insert(std::pair(uuid.toString(), pDescriptor)); +} // setByUUID + + +/** + * @brief Set the descriptor by handle. + * @param [in] handle The handle of the descriptor. + * @param [in] descriptor The descriptor to cache. + * @return N/A. + */ +void BLEDescriptorMap::setByHandle(uint16_t handle, + BLEDescriptor *pDescriptor) { + m_handleMap.insert(std::pair(handle, pDescriptor)); +} // setByHandle + + +/** + * @brief Return a string representation of the descriptor map. + * @return A string representation of the descriptor map. + */ +std::string BLEDescriptorMap::toString() { + std::stringstream stringStream; + stringStream << std::hex << std::setfill('0'); + int count=0; + for (auto &myPair: m_uuidMap) { + if (count > 0) { + stringStream << "\n"; + } + count++; + stringStream << "handle: 0x" << std::setw(2) << myPair.second->getHandle() << ", uuid: " + myPair.second->getUUID().toString(); + } + return stringStream.str(); +} // toString + + +/** + * @breif Pass the GATT server event onwards to each of the descriptors found in the mapping + * @param [in] event + * @param [in] gatts_if + * @param [in] param + */ +void BLEDescriptorMap::handleGATTServerEvent( + esp_gatts_cb_event_t event, + esp_gatt_if_t gatts_if, + esp_ble_gatts_cb_param_t *param) { + // Invoke the handler for every descriptor we have. + for (auto &myPair : m_uuidMap) { + myPair.second->handleGATTServerEvent(event, gatts_if, param); + } +} // handleGATTServerEvent + + +/** + * @brief Get the first descriptor in the map. + * @return The first descriptor in the map. + */ +BLEDescriptor* BLEDescriptorMap::getFirst() { + m_iterator = m_uuidMap.begin(); + if (m_iterator == m_uuidMap.end()) { + return nullptr; + } + BLEDescriptor *pRet = m_iterator->second; + m_iterator++; + return pRet; +} // getFirst + + +/** + * @brief Get the next descriptor in the map. + * @return The next descriptor in the map. + */ +BLEDescriptor* BLEDescriptorMap::getNext() { + if (m_iterator == m_uuidMap.end()) { + return nullptr; + } + BLEDescriptor *pRet = m_iterator->second; + m_iterator++; + return pRet; +} // getNext +#endif /* CONFIG_BT_ENABLED */ diff --git a/src/BLEDevice.cpp b/src/BLEDevice.cpp new file mode 100644 index 0000000..04cae14 --- /dev/null +++ b/src/BLEDevice.cpp @@ -0,0 +1,222 @@ +/* + * BLE.cpp + * + * Created on: Mar 16, 2017 + * Author: kolban + */ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) +#include +#include +#include +#include +#include +#include +#include // ESP32 BLE +#include // ESP32 BLE +#include // ESP32 BLE +// ESP32 BLE +#include // ESP32 BLE +#include // ESP32 ESP-IDF +#include // ESP32 ESP-IDF +#include // Part of C++ STL +#include +#include + +#include "BLEDevice.h" +#include "BLEClient.h" +#include "BLEUtils.h" +#include "GeneralUtils.h" + +static const char* LOG_TAG = "BLEDevice"; + +BLEServer *BLEDevice::m_bleServer = nullptr; +BLEScan *BLEDevice::m_pScan = nullptr; +BLEClient *BLEDevice::m_pClient = nullptr; + +#include + + +BLEClient* BLEDevice::createClient() { + m_pClient = new BLEClient(); + return m_pClient; +} // createClient + + +/** + * @brief Handle GATT server events. + * + * @param [in] event + * @param [in] gatts_if + * @param [in] param + */ +void BLEDevice::gattServerEventHandler( + esp_gatts_cb_event_t event, + esp_gatt_if_t gatts_if, + esp_ble_gatts_cb_param_t *param +) { + ESP_LOGD(LOG_TAG, "gattServerEventHandler [esp_gatt_if: %d] ... %s", + gatts_if, + BLEUtils::gattServerEventTypeToString(event).c_str()); + BLEUtils::dumpGattServerEvent(event, gatts_if, param); + if (BLEDevice::m_bleServer != nullptr) { + BLEDevice::m_bleServer->handleGATTServerEvent(event, gatts_if, param); + } +} // gattServerEventHandler + + +/** + * @brief Handle GATT client events. + * + * Handler for the GATT client events. + * * `ESP_GATTC_OPEN_EVT` – Invoked when a connection is opened. + * * `ESP_GATTC_PREP_WRITE_EVT` – Response to write a characteristic. + * * `ESP_GATTC_READ_CHAR_EVT` – Response to read a characteristic. + * * `ESP_GATTC_REG_EVT` – Invoked when a GATT client has been registered. + * + * @param [in] event + * @param [in] gattc_if + * @param [in] param + */ +void BLEDevice::gattClientEventHandler( + esp_gattc_cb_event_t event, + esp_gatt_if_t gattc_if, + esp_ble_gattc_cb_param_t *param) { + + ESP_LOGD(LOG_TAG, "gattClientEventHandler [esp_gatt_if: %d] ... %s", + gattc_if, BLEUtils::gattClientEventTypeToString(event).c_str()); + BLEUtils::dumpGattClientEvent(event, gattc_if, param); + + switch(event) { + default: { + break; + } + } // switch + + // If we have a client registered, call it. + if (BLEDevice::m_pClient != nullptr) { + BLEDevice::m_pClient->gattClientEventHandler(event, gattc_if, param); + } + +} // gattClientEventHandler + + +/** + * @brief Handle GAP events. + */ +void BLEDevice::gapEventHandler( + esp_gap_ble_cb_event_t event, + esp_ble_gap_cb_param_t *param) { + + BLEUtils::dumpGapEvent(event, param); + + switch(event) { + case ESP_GAP_BLE_SEC_REQ_EVT: { + esp_err_t errRc = ::esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, true); + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "esp_ble_gap_security_rsp: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + } + break; + } + + default: { + break; + } + } // switch + + if (BLEDevice::m_bleServer != nullptr) { + BLEDevice::m_bleServer->handleGAPEvent(event, param); + } + + if (BLEDevice::m_pScan != nullptr) { + BLEDevice::getScan()->gapEventHandler(event, param); + } +} // gapEventHandler + + +/** + * @brief Initialize the %BLE environment. + * @param deviceName The device name of the device. + */ +void BLEDevice::init(std::string deviceName) { + esp_err_t errRc = ::nvs_flash_init(); + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "nvs_flash_init: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + + esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); + errRc = esp_bt_controller_init(&bt_cfg); + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "esp_bt_controller_init: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + + errRc = esp_bt_controller_enable(ESP_BT_MODE_BTDM); + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "esp_bt_controller_enable: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + + errRc = esp_bluedroid_init(); + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "esp_bluedroid_init: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + + errRc = esp_bluedroid_enable(); + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "esp_bluedroid_enable: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + + errRc = esp_ble_gap_register_callback(BLEDevice::gapEventHandler); + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "esp_ble_gap_register_callback: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + + errRc = esp_ble_gattc_register_callback(BLEDevice::gattClientEventHandler); + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "esp_ble_gattc_register_callback: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + + errRc = esp_ble_gatts_register_callback(BLEDevice::gattServerEventHandler); + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "esp_ble_gatts_register_callback: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + + errRc = ::esp_ble_gap_set_device_name(deviceName.c_str()); + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "esp_ble_gap_set_device_name: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + }; + + esp_ble_io_cap_t iocap = ESP_IO_CAP_NONE; + errRc = ::esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(uint8_t)); + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "esp_ble_gap_set_security_param: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + }; + + vTaskDelay(200/portTICK_PERIOD_MS); // Delay for 200 msecs as a workaround to an apparent Arduino environment issue. +} // init + + + +/** + * @brief Retrieve the Scan object that we use for scanning. + * @return The scanning object reference. + */ +BLEScan* BLEDevice::getScan() { + if (m_pScan == nullptr) { + m_pScan = new BLEScan(); + } + return m_pScan; +} // getScan + + + +#endif // CONFIG_BT_ENABLED diff --git a/src/BLEDevice.h b/src/BLEDevice.h new file mode 100644 index 0000000..9d767c1 --- /dev/null +++ b/src/BLEDevice.h @@ -0,0 +1,54 @@ +/* + * BLEDevice.h + * + * Created on: Mar 16, 2017 + * Author: kolban + */ + +#ifndef MAIN_BLEDevice_H_ +#define MAIN_BLEDevice_H_ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) +#include // ESP32 BLE +#include // ESP32 BLE +#include // Part of C++ STL +#include + +#include "BLEServer.h" +#include "BLEClient.h" +#include "BLEUtils.h" +#include "BLEScan.h" +#include "BLEAddress.h" +/** + * @brief %BLE functions. + */ +class BLEDevice { +public: + static void dumpDevices(); + static BLEClient *createClient(); + + static void init(std::string deviceName); + //static void scan(int duration, esp_ble_scan_type_t scan_type = BLE_SCAN_TYPE_PASSIVE); + static BLEScan *getScan(); + static BLEServer *m_bleServer; + static BLEScan *m_pScan; + static BLEClient *m_pClient; + +private: + static esp_gatt_if_t getGattcIF(); + + static void gattClientEventHandler( + esp_gattc_cb_event_t event, + esp_gatt_if_t gattc_if, + esp_ble_gattc_cb_param_t *param); + static void gattServerEventHandler( + esp_gatts_cb_event_t event, + esp_gatt_if_t gatts_if, + esp_ble_gatts_cb_param_t *param); + static void gapEventHandler( + esp_gap_ble_cb_event_t event, + esp_ble_gap_cb_param_t *param); +}; // class BLE + +#endif // CONFIG_BT_ENABLED +#endif /* MAIN_BLEDevice_H_ */ diff --git a/src/BLERemoteCharacteristic.cpp b/src/BLERemoteCharacteristic.cpp new file mode 100644 index 0000000..5227bf6 --- /dev/null +++ b/src/BLERemoteCharacteristic.cpp @@ -0,0 +1,336 @@ +/* + * BLERemoteCharacteristic.cpp + * + * Created on: Jul 8, 2017 + * Author: kolban + */ + +#include "BLERemoteCharacteristic.h" + +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) + +#include +#include +#include + +#include +#include "BLEUtils.h" +#include "GeneralUtils.h" + + +static const char* LOG_TAG = "BLERemoteCharacteristic"; + +BLERemoteCharacteristic::BLERemoteCharacteristic( + esp_gatt_id_t charId, + esp_gatt_char_prop_t charProp, + BLERemoteService* pRemoteService) { + m_charId = charId; + m_charProp = charProp; + m_pRemoteService = pRemoteService; + m_notifyCallback = nullptr; +} // BLERemoteCharacteristic + + +static bool compareSrvcId(esp_gatt_srvc_id_t id1, esp_gatt_srvc_id_t id2) { + if (id1.id.inst_id != id2.id.inst_id) { + return false; + } + if (!BLEUUID(id1.id.uuid).equals(BLEUUID(id2.id.uuid))) { + return false; + } + return true; +} // compareSrvcId + + +static bool compareGattId(esp_gatt_id_t id1, esp_gatt_id_t id2) { + if (id1.inst_id != id2.inst_id) { + return false; + } + if (!BLEUUID(id1.uuid).equals(BLEUUID(id2.uuid))) { + return false; + } + return true; +} // compareCharId + + +/** + * @brief Handle GATT Client events. + * When an event arrives for a GATT client we give this characteristic the opportunity to + * take a look at it to see if there is interest in it. + * @param [in] event The type of event. + * @param [in] gattc_if The interface on which the event was received. + * @param [in] evtParam Payload data for the event. + * @returns N/A + */ +void BLERemoteCharacteristic::gattClientEventHandler( + esp_gattc_cb_event_t event, + esp_gatt_if_t gattc_if, + esp_ble_gattc_cb_param_t* evtParam) { + switch(event) { + // + // ESP_GATTC_READ_CHAR_EVT + // This event indicates that the server has responded to the read request. + // + // read: + // esp_gatt_status_t status + // uint16_t conn_id + // esp_gatt_srvc_id_t srvc_id + // esp_gatt_id_t char_id + // esp_gatt_id_t descr_id + // uint8_t* value + // uint16_t value_type + // uint16_t value_len + case ESP_GATTC_READ_CHAR_EVT: { + if (compareSrvcId(evtParam->read.srvc_id, *m_pRemoteService->getSrvcId()) == false) { + break; + } + + if (evtParam->read.conn_id != m_pRemoteService->getClient()->getConnId()) { + break; + } + + if (compareGattId(evtParam->read.char_id, m_charId) == false) { + break; + } + + if (evtParam->read.status == ESP_GATT_OK) { + m_value = std::string((char*)evtParam->read.value, evtParam->read.value_len); + } else { + m_value = ""; + } + + m_semaphoreReadCharEvt.give(); + break; + } // ESP_GATTC_READ_CHAR_EVT + + + // + // ESP_GATTC_REG_FOR_NOTIFY_EVT + // + // reg_for_notify: + // - esp_gatt_status_t status + // - esp_gatt_srvc_id_t srvc_id + // - esp_gatt_id_t char_id + case ESP_GATTC_REG_FOR_NOTIFY_EVT: { + if (compareSrvcId(evtParam->reg_for_notify.srvc_id, *m_pRemoteService->getSrvcId()) == false) { + break; + } + if (compareGattId(evtParam->reg_for_notify.char_id, m_charId) == false) { + break; + } + m_semaphoreRegForNotifyEvt.give(); + break; + } // ESP_GATTC_REG_FOR_NOTIFY_EVT + + + // + // ESP_GATTC_WRITE_CHAR_EVT + // + // write: + // esp_gatt_status_t status + // uint16_t conn_id + // esp_gatt_srvc_id_t srvc_id + // esp_gatt_id_t char_id + // esp_gatt_id_t descr_id + case ESP_GATTC_WRITE_CHAR_EVT: { + if (compareSrvcId(evtParam->write.srvc_id, *m_pRemoteService->getSrvcId()) == false) { + break; + } + if (evtParam->write.conn_id != m_pRemoteService->getClient()->getConnId()) { + break; + } + if (compareGattId(evtParam->write.char_id, m_charId) == false) { + break; + } + m_semaphoreWriteCharEvt.give(); + break; + } // ESP_GATTC_WRITE_CHAR_EVT + + + default: { + break; + } + } +}; // gattClientEventHandler + + +BLEUUID BLERemoteCharacteristic::getUUID() { + return BLEUUID(m_charId.uuid); +} + +/** + * @brief Read an unsigned 16 bit value + * @return The unsigned 16 bit value. + */ +uint16_t BLERemoteCharacteristic::readUInt16(void) { + std::string value = readValue(); + if (value.length() >= 2) { + return *(uint16_t*)(value.data()); + } + return 0; +} // readUInt16 + + +/** + * @brief Read an unsigned 32 bit value. + * @return the unsigned 32 bit value. + */ +uint32_t BLERemoteCharacteristic::readUInt32(void) { + std::string value = readValue(); + if (value.length() >= 4) { + return *(uint32_t*)(value.data()); + } + return 0; +} // readUInt32 + + +/** + * @brief Read a byte value + * @return The value as a byte + */ +uint8_t BLERemoteCharacteristic::readUInt8(void) { + std::string value = readValue(); + if (value.length() >= 1) { + return (uint8_t)value[0]; + } + return 0; +} // readUInt8 + + +/** + * @brief Read the value of the remote characteristic. + * @return The value of the remote characteristic. + */ +std::string BLERemoteCharacteristic::readValue() { + ESP_LOGD(LOG_TAG, ">> readValue()"); + + m_semaphoreReadCharEvt.take("readValue"); + + // Ask the BLE subsystem to retrieve the value for the remote hosted characteristic. + esp_err_t errRc = ::esp_ble_gattc_read_char( + m_pRemoteService->getClient()->getGattcIf(), + m_pRemoteService->getClient()->getConnId(), + m_pRemoteService->getSrvcId(), + &m_charId, + ESP_GATT_AUTH_REQ_NONE); + + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "esp_ble_gattc_read_char: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return ""; + } + + // Block waiting for the event that indicates that the read has completed. When it has, the std::string found + // in m_value will contain our data. + m_semaphoreReadCharEvt.wait("readValue"); + + ESP_LOGD(LOG_TAG, "<< readValue()"); + return m_value; +} // readValue + + +/** + * @brief Register for notifications. + * @param [in] notifyCallback A callback to be invoked for a notification. + * @return N/A. + */ +void BLERemoteCharacteristic::registerForNotify( + void (*notifyCallback)( + BLERemoteCharacteristic* pBLERemoteCharacteristic, + uint8_t* pData, + size_t length, + bool isNotify)) { + ESP_LOGD(LOG_TAG, ">> registerForNotify()"); + + m_notifyCallback = notifyCallback; // Save the notification callback. + + m_semaphoreRegForNotifyEvt.take("registerForNotify"); + + esp_err_t errRc = ::esp_ble_gattc_register_for_notify( + m_pRemoteService->getClient()->getGattcIf(), + *m_pRemoteService->getClient()->getPeerAddress().getNative(), + m_pRemoteService->getSrvcId(), + &m_charId); + + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "esp_ble_gattc_register_for_notify: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + + m_semaphoreRegForNotifyEvt.wait("registerForNotify"); + + ESP_LOGD(LOG_TAG, "<< registerForNotify()"); +} // registerForNotify + + +/** + * @brief Convert a BLERemoteCharacteristic to a string representation; + * @return a String representation. + */ +std::string BLERemoteCharacteristic::toString() { + std::ostringstream ss; + ss << "Characteristic: uuid: " << BLEUUID(m_charId.uuid).toString() << + ", props: " << BLEUtils::characteristicPropertiesToString(m_charProp) << + ", inst_id: " << (int)m_charId.inst_id; + return ss.str(); +} // toString + + +/** + * @brief Write the new value for the characteristic. + * @param [in] newValue The new value to write. + * @param [in] response Do we expect a response? + * @return N/A. + */ +void BLERemoteCharacteristic::writeValue(std::string newValue, bool response) { + ESP_LOGD(LOG_TAG, ">> writeValue(), length: %d", newValue.length()); + + m_semaphoreWriteCharEvt.take("writeValue"); + + esp_err_t errRc = ::esp_ble_gattc_write_char( + m_pRemoteService->getClient()->getGattcIf(), + m_pRemoteService->getClient()->getConnId(), + m_pRemoteService->getSrvcId(), + &m_charId, + newValue.length(), + (uint8_t*)newValue.data(), + response?ESP_GATT_WRITE_TYPE_RSP:ESP_GATT_WRITE_TYPE_NO_RSP, + ESP_GATT_AUTH_REQ_NONE + ); + + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "esp_ble_gattc_write_char: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + + m_semaphoreWriteCharEvt.wait("writeValue"); + + ESP_LOGD(LOG_TAG, "<< writeValue"); +} // writeValue + + +/** + * @brief Write the new value for the characteristic. + * + * This is a convenience function. Many BLE characteristics are a single byte of data. + * @param [in] newValue The new byte value to write. + * @param [in] response Whether we require a response from the write. + * @return N/A. + */ +void BLERemoteCharacteristic::writeValue(uint8_t newValue, bool response) { + writeValue(std::string(reinterpret_cast(&newValue), 1), response); +} // writeValue + + +/** + * @brief Write the new value for the characteristic from a data buffer. + * @param [in] data A pointer to a data buffer. + * @param [in] length The length of the data in the data buffer. + * @param [in] response Whether we require a response from the write. + */ +void BLERemoteCharacteristic::writeValue(uint8_t* data, size_t length, bool response) { + writeValue(std::string((char *)data, length), response); +} // writeValue + + +#endif /* CONFIG_BT_ENABLED */ diff --git a/src/BLERemoteCharacteristic.h b/src/BLERemoteCharacteristic.h new file mode 100644 index 0000000..b5b22b6 --- /dev/null +++ b/src/BLERemoteCharacteristic.h @@ -0,0 +1,63 @@ +/* + * BLERemoteCharacteristic.h + * + * Created on: Jul 8, 2017 + * Author: kolban + */ + +#ifndef COMPONENTS_CPP_UTILS_BLEREMOTECHARACTERISTIC_H_ +#define COMPONENTS_CPP_UTILS_BLEREMOTECHARACTERISTIC_H_ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) + +#include + +#include + +#include "BLERemoteService.h" +#include "BLEUUID.h" +#include "FreeRTOS.h" + +class BLERemoteService; + +/** + * @brief A model of a remote %BLE characteristic. + */ +class BLERemoteCharacteristic { +public: + BLERemoteCharacteristic(esp_gatt_id_t charId, esp_gatt_char_prop_t charProp, BLERemoteService* pRemoteService); + + // Public member functions + BLEUUID getUUID(); + std::string readValue(void); + uint8_t readUInt8(void); + uint16_t readUInt16(void); + uint32_t readUInt32(void); + void registerForNotify(void (*notifyCallback)(BLERemoteCharacteristic *pBLERemoteCharacteristic, uint8_t *pData, size_t length, bool isNotify)); + void writeValue(uint8_t* data, size_t length, bool response = false); + void writeValue(std::string newValue, bool response = false); + void writeValue(uint8_t newValue, bool response = false); + std::string toString(void); + +private: + friend class BLEClient; + friend class BLERemoteService; + + // Private member functions + void gattClientEventHandler( + esp_gattc_cb_event_t event, + esp_gatt_if_t gattc_if, + esp_ble_gattc_cb_param_t *evtParam); + + // Private properties + esp_gatt_id_t m_charId; + esp_gatt_char_prop_t m_charProp; + BLERemoteService* m_pRemoteService; + FreeRTOS::Semaphore m_semaphoreReadCharEvt = FreeRTOS::Semaphore("ReadCharEvt"); + FreeRTOS::Semaphore m_semaphoreRegForNotifyEvt = FreeRTOS::Semaphore("RegForNotifyEvt"); + FreeRTOS::Semaphore m_semaphoreWriteCharEvt = FreeRTOS::Semaphore("WriteCharEvt"); + std::string m_value; + void (*m_notifyCallback)(BLERemoteCharacteristic *pBLERemoteCharacteristic, uint8_t *pData, size_t length, bool isNotify); +}; // BLERemoteCharacteristic +#endif /* CONFIG_BT_ENABLED */ +#endif /* COMPONENTS_CPP_UTILS_BLEREMOTECHARACTERISTIC_H_ */ diff --git a/src/BLERemoteDescriptor.cpp b/src/BLERemoteDescriptor.cpp new file mode 100644 index 0000000..2be312a --- /dev/null +++ b/src/BLERemoteDescriptor.cpp @@ -0,0 +1,11 @@ +/* + * BLERemoteDescriptor.cpp + * + * Created on: Jul 8, 2017 + * Author: kolban + */ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) +#include "BLERemoteDescriptor.h" + +#endif /* CONFIG_BT_ENABLED */ diff --git a/src/BLERemoteDescriptor.h b/src/BLERemoteDescriptor.h new file mode 100644 index 0000000..a8d944d --- /dev/null +++ b/src/BLERemoteDescriptor.h @@ -0,0 +1,20 @@ +/* + * BLERemoteDescriptor.h + * + * Created on: Jul 8, 2017 + * Author: kolban + */ + +#ifndef COMPONENTS_CPP_UTILS_BLEREMOTEDESCRIPTOR_H_ +#define COMPONENTS_CPP_UTILS_BLEREMOTEDESCRIPTOR_H_ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) + +/** + * @brief A model of remote %BLE descriptor. + */ +class BLERemoteDescriptor { +public: +}; +#endif /* CONFIG_BT_ENABLED */ +#endif /* COMPONENTS_CPP_UTILS_BLEREMOTEDESCRIPTOR_H_ */ diff --git a/src/BLERemoteService.cpp b/src/BLERemoteService.cpp new file mode 100644 index 0000000..a29a758 --- /dev/null +++ b/src/BLERemoteService.cpp @@ -0,0 +1,220 @@ +/* + * BLERemoteService.cpp + * + * Created on: Jul 8, 2017 + * Author: kolban + */ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) + +#include +#include "BLERemoteService.h" +#include "BLEUtils.h" +#include "GeneralUtils.h" +#include +#include + +static const char* LOG_TAG = "BLERemoteService"; + +BLERemoteService::BLERemoteService( + esp_gatt_srvc_id_t srvcId, + BLEClient *pClient) { + + m_srvcId = srvcId; + m_pClient = pClient; + m_uuid = BLEUUID(m_srvcId); + m_haveCharacteristics = false; +} + + +BLERemoteService::~BLERemoteService() { + removeCharacteristics(); +} + +static bool compareSrvcId(esp_gatt_srvc_id_t id1, esp_gatt_srvc_id_t id2) { + if (id1.id.inst_id != id2.id.inst_id) { + return false; + } + if (!BLEUUID(id1.id.uuid).equals(BLEUUID(id2.id.uuid))) { + return false; + } + return true; +} // compareSrvcId + + +/** + * @brief Handle GATT Client events + */ +void BLERemoteService::gattClientEventHandler( + esp_gattc_cb_event_t event, + esp_gatt_if_t gattc_if, + esp_ble_gattc_cb_param_t *evtParam) { + switch(event) { + // + // ESP_GATTC_GET_CHAR_EVT + // + // get_char: + // - esp_gatt_status_t status + // - uin1t6_t conn_id + // - esp_gatt_srvc_id_t srvc_id + // - esp_gatt_id_t char_id + // - esp_gatt_char_prop_t char_prop + // + case ESP_GATTC_GET_CHAR_EVT: { + // Is this event for this service? If yes, then the local srvc_id and the event srvc_id will be + // the same. + if (compareSrvcId(m_srvcId, evtParam->get_char.srvc_id) == false) { + break; + } + + // If the status is NOT OK then we have a problem and continue. + if (evtParam->get_char.status != ESP_GATT_OK) { + m_semaphoreGetCharEvt.give(); + break; + } + + // This is an indication that we now have the characteristic details for a characteristic owned + // by this service so remember it. + m_characteristicMap.insert(std::pair( + BLEUUID(evtParam->get_char.char_id.uuid).toString(), + new BLERemoteCharacteristic(evtParam->get_char.char_id, evtParam->get_char.char_prop, this) )); + + + // Now that we have received a characteristic, lets ask for the next one. + esp_err_t errRc = ::esp_ble_gattc_get_characteristic( + m_pClient->getGattcIf(), + m_pClient->getConnId(), + &m_srvcId, + &evtParam->get_char.char_id); + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "esp_ble_gattc_get_characteristic: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + break; + } + + //m_semaphoreGetCharEvt.give(); + break; + } // ESP_GATTC_GET_CHAR_EVT + + default: { + break; + } + } // switch + + // Send the event to each of the characteristics owned by this service. + for (auto &myPair : m_characteristicMap) { + myPair.second->gattClientEventHandler(event, gattc_if, evtParam); + } +} // gattClientEventHandler + + +/** + * @brief Get the characteristic object for the UUID. + * @param [in] uuid Characteristic uuid. + * @return Reference to the characteristic object. + */ +BLERemoteCharacteristic* BLERemoteService::getCharacteristic(const char* uuid) { + return getCharacteristic(BLEUUID(uuid)); +} + + +/** + * @brief Get the characteristic object for the UUID. + * @param [in] uuid Characteristic uuid. + * @return Reference to the characteristic object. + */ +BLERemoteCharacteristic* BLERemoteService::getCharacteristic(BLEUUID uuid) { +// Design +// ------ +// We wish to retrieve the characteristic given its UUID. It is possible that we have not yet asked the +// device what characteristics it has in which case we have nothing to match against. If we have not +// asked the device about its characteristics, then we do that now. Once we get the results we can then +// examine the characteristics map to see if it has the characteristic we are looking for. + if (!m_haveCharacteristics) { + getCharacteristics(); + } + std::string v = uuid.toString(); + for (auto &myPair : m_characteristicMap) { + if (myPair.first == v) { + return myPair.second; + } + } + return nullptr; +} // getCharacteristic + + +/** + * @brief Retrieve all the characteristics for this service. + * @return N/A + */ +void BLERemoteService::getCharacteristics() { + + ESP_LOGD(LOG_TAG, ">> getCharacteristics() for service: %s", getUUID().toString().c_str()); + + removeCharacteristics(); // Forget any previous characteristics. + + m_semaphoreGetCharEvt.take("getCharacteristics"); + + esp_err_t errRc = ::esp_ble_gattc_get_characteristic( + m_pClient->getGattcIf(), + m_pClient->getConnId(), + &m_srvcId, + nullptr); + + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "esp_ble_gattc_get_characteristic: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + + m_semaphoreGetCharEvt.wait("getCharacteristics"); // Wait for the characteristics to become available. + + m_haveCharacteristics = true; // Remember that we have received the characteristics. + ESP_LOGD(LOG_TAG, "<< getCharacteristics()"); +} // getCharacteristics + + +BLEClient* BLERemoteService::getClient() { + return m_pClient; +} + +esp_gatt_srvc_id_t* BLERemoteService::getSrvcId() { + return &m_srvcId; +} + +BLEUUID BLERemoteService::getUUID() { + return m_uuid; +} + + +/** + * @brief Delete the characteristics in the characteristics map. + * We maintain a map called m_characteristicsMap that contains pointers to BLERemoteCharacteristic + * object references. Since we allocated these in this class, we are also responsible for deleteing + * them. This method does just that. + * @return N/A. + */ +void BLERemoteService::removeCharacteristics() { + for (auto &myPair : m_characteristicMap) { + delete myPair.second; + } + m_characteristicMap.empty(); +} // removeCharacteristics + + + +/** + * @brief Create a string representation of this remote service. + * @return A string representation of this remote service. + */ +std::string BLERemoteService::toString() { + std::ostringstream ss; + ss << "Service: uuid: " + m_uuid.toString(); + for (auto &myPair : m_characteristicMap) { + ss << "\n" << myPair.second->toString(); + // myPair.second is the value + } + return ss.str(); +} // toString + + + +#endif /* CONFIG_BT_ENABLED */ diff --git a/src/BLERemoteService.h b/src/BLERemoteService.h new file mode 100644 index 0000000..4393fbc --- /dev/null +++ b/src/BLERemoteService.h @@ -0,0 +1,63 @@ +/* + * BLERemoteService.h + * + * Created on: Jul 8, 2017 + * Author: kolban + */ + +#ifndef COMPONENTS_CPP_UTILS_BLEREMOTESERVICE_H_ +#define COMPONENTS_CPP_UTILS_BLEREMOTESERVICE_H_ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) + +#include + +#include "BLEClient.h" +#include "BLERemoteCharacteristic.h" +#include "BLEUUID.h" +#include "FreeRTOS.h" + +class BLEClient; +class BLERemoteCharacteristic; + + +/** + * @brief A model of a remote %BLE service. + */ +class BLERemoteService { +public: + BLERemoteService(esp_gatt_srvc_id_t srvcId, BLEClient* pClient); + virtual ~BLERemoteService(); + + // Public methods + BLERemoteCharacteristic* getCharacteristic(const char* uuid); + BLERemoteCharacteristic* getCharacteristic(BLEUUID uuid); + void getCharacteristics(void); + BLEClient* getClient(void); + BLEUUID getUUID(void); + std::string toString(void); + +private: + // Friends + friend class BLEClient; + friend class BLERemoteCharacteristic; + + // Private methods + esp_gatt_srvc_id_t* getSrvcId(void); + void gattClientEventHandler( + esp_gattc_cb_event_t event, + esp_gatt_if_t gattc_if, + esp_ble_gattc_cb_param_t* evtParam); + void removeCharacteristics(); + + // Properties + std::map m_characteristicMap; + bool m_haveCharacteristics; // Have we previously obtained the characteristics. + BLEClient* m_pClient; + FreeRTOS::Semaphore m_semaphoreGetCharEvt = FreeRTOS::Semaphore("GetCharEvt"); + esp_gatt_srvc_id_t m_srvcId; + BLEUUID m_uuid; +}; // BLERemoteService + +#endif /* CONFIG_BT_ENABLED */ +#endif /* COMPONENTS_CPP_UTILS_BLEREMOTESERVICE_H_ */ diff --git a/src/BLEScan.cpp b/src/BLEScan.cpp new file mode 100644 index 0000000..9fdcffd --- /dev/null +++ b/src/BLEScan.cpp @@ -0,0 +1,276 @@ +/* + * BLEScan.cpp + * + * Created on: Jul 1, 2017 + * Author: kolban + */ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) + + +#include +#include + +#include + +#include "BLEAdvertisedDevice.h" +#include "BLEScan.h" +#include "BLEUtils.h" +#include "GeneralUtils.h" + +static const char* LOG_TAG = "BLEScan"; + + +BLEScan::BLEScan() { + m_scan_params.scan_type = BLE_SCAN_TYPE_PASSIVE; // Default is a passive scan. + m_scan_params.own_addr_type = BLE_ADDR_TYPE_PUBLIC; + m_scan_params.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL; + setInterval(100); + setWindow(100); + m_pAdvertisedDeviceCallbacks = nullptr; + m_stopped = true; +} // BLEScan + + + +/** + * @brief Clear the history of previously detected advertised devices. + * @return N/A + */ +/* +void BLEScan::clearAdvertisedDevices() { + for (int i=0; iscan_rst.search_evt) { + case ESP_GAP_SEARCH_INQ_CMPL_EVT: { + m_stopped = true; + m_semaphoreScanEnd.give(); + break; + } // ESP_GAP_SEARCH_INQ_CMPL_EVT + + case ESP_GAP_SEARCH_INQ_RES_EVT: { + if (m_stopped) { // If we are not scanning, nothing to do with the extra results. + break; + } + +// Examine our list of previously scanned addresses and, if we found this one already, +// ignore it. + BLEAddress advertisedAddress(param->scan_rst.bda); + bool found = false; + /* + for (int i=0; igetAddress().equals(advertisedAddress)) { + found = true; + break; + } + } + */ + for (int i=0; iscan_rst.rssi); + advertisedDevice.setAdFlag(param->scan_rst.flag); + advertisedDevice.parseAdvertisement((uint8_t*)param->scan_rst.ble_adv); + advertisedDevice.setScan(this); + + //m_vectorAvdertisedDevices.push_back(pAdvertisedDevice); + if (m_pAdvertisedDeviceCallbacks) { + m_pAdvertisedDeviceCallbacks->onResult(advertisedDevice); + } + + m_scanResults.m_vectorAdvertisedDevices.push_back(advertisedDevice); + + break; + } // ESP_GAP_SEARCH_INQ_RES_EVT + + default: { + break; + } + } // switch - search_evt + + + break; + } // ESP_GAP_BLE_SCAN_RESULT_EVT + + default: { + break; + } // default + } // End switch +} // gapEventHandler + + +/* +void BLEScan::onResults() { + ESP_LOGD(LOG_TAG, ">> onResults: default"); + ESP_LOGD(LOG_TAG, "<< onResults"); +} // onResults +*/ + + +/** + * @brief Should we perform an active or passive scan? + * The default is a passive scan. An active scan means that we will wish a scan response. + * @param [in] active If true, we perform an active scan otherwise a passive scan. + * @return N/A. + */ +void BLEScan::setActiveScan(bool active) { + if (active) { + m_scan_params.scan_type = BLE_SCAN_TYPE_ACTIVE; + } else { + m_scan_params.scan_type = BLE_SCAN_TYPE_PASSIVE; + } +} // setActiveScan + + +/** + * @brief Set the call backs to be invoked. + * @param [in] pAdvertisedDeviceCallbacks Call backs to be invoked. + */ +void BLEScan::setAdvertisedDeviceCallbacks(BLEAdvertisedDeviceCallbacks* pAdvertisedDeviceCallbacks) { + m_pAdvertisedDeviceCallbacks = pAdvertisedDeviceCallbacks; +} // setAdvertisedDeviceCallbacks + + +/** + * @brief Set the interval to scan. + * @param [in] The interval in msecs. + */ +void BLEScan::setInterval(uint16_t intervalMSecs) { + m_scan_params.scan_interval = intervalMSecs / 0.625; +} // setInterval + + +/** + * @brief Set the window to actively scan. + * @param [in] windowMSecs How long to actively scan. + */ +void BLEScan::setWindow(uint16_t windowMSecs) { + m_scan_params.scan_window = windowMSecs / 0.625; +} // setWindow + + +/** + * @brief Start scanning. + * @param [in] duration The duration in seconds for which to scan. + * @return N/A. + */ +BLEScanResults BLEScan::start(uint32_t duration) { + ESP_LOGD(LOG_TAG, ">> start(%d)", duration); + + m_semaphoreScanEnd.take("start"); + + m_scanResults.m_vectorAdvertisedDevices.empty(); + + esp_err_t errRc = ::esp_ble_gap_set_scan_params(&m_scan_params); + + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "esp_ble_gap_set_scan_params: err: %d, text: %s", errRc, GeneralUtils::errorToString(errRc)); + m_semaphoreScanEnd.give(); + return m_scanResults; + } + + errRc = ::esp_ble_gap_start_scanning(duration); + + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "esp_ble_gap_start_scanning: err: %d, text: %s", errRc, GeneralUtils::errorToString(errRc)); + m_semaphoreScanEnd.give(); + return m_scanResults; + } + + m_stopped = false; + + m_semaphoreScanEnd.take("start"); + m_semaphoreScanEnd.give(); + + ESP_LOGD(LOG_TAG, "<< start()"); + return m_scanResults; +} // start + + +/** + * @brief Stop an in progress scan. + * @return N/A. + */ +void BLEScan::stop() { + ESP_LOGD(LOG_TAG, ">> stop()"); + + esp_err_t errRc = ::esp_ble_gap_stop_scanning(); + + m_stopped = true; + + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "esp_ble_gap_stop_scanning: err: %d, text: %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + + m_semaphoreScanEnd.give(); + + ESP_LOGD(LOG_TAG, "<< stop()"); +} // stop + + +/** + * @brief Return the count of devices found in the last scan. + * @return The number of devices found in the last scan. + */ +int BLEScanResults::getCount() { + return m_vectorAdvertisedDevices.size(); +} // getCount + + +/** + * @brief Return the specified device at the given index. + * The index should be between 0 and getCount()-1. + * @param [in] i The index of the device. + * @return The device at the specified index. + */ +BLEAdvertisedDevice BLEScanResults::getDevice(uint32_t i) { + return m_vectorAdvertisedDevices.at(i); +} + +#endif /* CONFIG_BT_ENABLED */ diff --git a/src/BLEScan.h b/src/BLEScan.h new file mode 100644 index 0000000..f9575ea --- /dev/null +++ b/src/BLEScan.h @@ -0,0 +1,67 @@ +/* + * BLEScan.h + * + * Created on: Jul 1, 2017 + * Author: kolban + */ + +#ifndef COMPONENTS_CPP_UTILS_BLESCAN_H_ +#define COMPONENTS_CPP_UTILS_BLESCAN_H_ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) +#include + +#include +#include "BLEAdvertisedDevice.h" +#include "BLEClient.h" +#include "FreeRTOS.h" + +class BLEAdvertisedDevice; +class BLEAdvertisedDeviceCallbacks; +class BLEClient; +class BLEScan; + +class BLEScanResults { +public: + int getCount(); + BLEAdvertisedDevice getDevice(uint32_t i); +private: + friend BLEScan; + std::vector m_vectorAdvertisedDevices; +}; + +/** + * @brief Perform and manage %BLE scans. + * + * Scanning is associated with a %BLE client that is attempting to locate BLE servers. + */ +class BLEScan { +public: + BLEScan(); + + //virtual void onResults(); + void setActiveScan(bool active); + void setAdvertisedDeviceCallbacks(BLEAdvertisedDeviceCallbacks* pAdvertisedDeviceCallbacks); + void setInterval(uint16_t intervalMSecs); + void setWindow(uint16_t windowMSecs); + BLEScanResults start(uint32_t duration); + void stop(); + +private: + friend class BLEDevice; + void gapEventHandler( + esp_gap_ble_cb_event_t event, + esp_ble_gap_cb_param_t* param); + void parseAdvertisement(BLEClient* pRemoteDevice, uint8_t *payload); + + + esp_ble_scan_params_t m_scan_params; + BLEAdvertisedDeviceCallbacks* m_pAdvertisedDeviceCallbacks; + bool m_stopped; + FreeRTOS::Semaphore m_semaphoreScanEnd = FreeRTOS::Semaphore("ScanEnd"); + //std::vector m_vectorAvdertisedDevices; + BLEScanResults m_scanResults; +}; // BLEScan + +#endif /* CONFIG_BT_ENABLED */ +#endif /* COMPONENTS_CPP_UTILS_BLESCAN_H_ */ diff --git a/src/BLEServer.cpp b/src/BLEServer.cpp new file mode 100644 index 0000000..be9773d --- /dev/null +++ b/src/BLEServer.cpp @@ -0,0 +1,353 @@ +/* + * BLEServer.cpp + * + * Created on: Apr 16, 2017 + * Author: kolban + */ + +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) +#include +#include +#include +#include +#include +#include "BLEDevice.h" +#include "BLEServer.h" +#include "BLEService.h" +#include "BLEUtils.h" +#include +#include +#include +#include + +static const char* LOG_TAG = "BLEServer"; + + +/** + * @brief Construct a %BLE Server + * + * This class is not designed to be individually instantiated. Instead one should create a server by asking + * the BLEDevice class. + */ +BLEServer::BLEServer() { + m_appId = -1; + m_gatts_if = -1; + m_connectedCount = 0; + m_connId = -1; + BLEDevice::m_bleServer = this; + m_pServerCallbacks = nullptr; + + createApp(0); +} // BLEServer + + +void BLEServer::createApp(uint16_t appId) { + m_appId = appId; + registerApp(); +} + + +/** + * @brief Create a %BLE Service. + * + * With a %BLE server, we can host one or more services. Invoking this function causes the creation of a definition + * of a new service. Every service must have a unique UUID. + * @param [in] uuid The UUID of the new service. + * @return A reference to the new service object. + */ +BLEService* BLEServer::createService(const char* uuid) { + return createService(BLEUUID(uuid)); +} + + +/** + * @brief Create a %BLE Service. + * + * With a %BLE server, we can host one or more services. Invoking this function causes the creation of a definition + * of a new service. Every service must have a unique UUID. + * @param [in] uuid The UUID of the new service. + * @return A reference to the new service object. + */ +BLEService* BLEServer::createService(BLEUUID uuid) { + ESP_LOGD(LOG_TAG, ">> createService - %s", uuid.toString().c_str()); + m_semaphoreCreateEvt.take("createService"); + + // Check that a service with the supplied UUID does not already exist. + if (m_serviceMap.getByUUID(uuid) != nullptr) { + ESP_LOGE(LOG_TAG, "<< Attempt to create a new service with uuid %s but a service with that UUID already exists.", + uuid.toString().c_str()); + m_semaphoreCreateEvt.give(); + return nullptr; + } + + BLEService* pService = new BLEService(uuid); + m_serviceMap.setByUUID(uuid, pService); // Save a reference to this service being on this server. + pService->executeCreate(this); // Perform the API calls to actually create the service. + + m_semaphoreCreateEvt.wait("createService"); + + ESP_LOGD(LOG_TAG, "<< createService"); + return pService; +} // createService + + +/** + * @brief Retrieve the advertising object that can be used to advertise the existence of the server. + * + * @return An advertising object. + */ +BLEAdvertising* BLEServer::getAdvertising() { + return &m_bleAdvertising; +} + +uint16_t BLEServer::getConnId() { + return m_connId; +} + + +/** + * @brief Return the number of connected clients. + * @return The number of connected clients. + */ +uint32_t BLEServer::getConnectedCount() { + return m_connectedCount; +} // getConnectedCount + + +uint16_t BLEServer::getGattsIf() { + return m_gatts_if; +} + +/** + * @brief Handle a receiver GAP event. + * + * @param [in] event + * @param [in] param + */ +void BLEServer::handleGAPEvent( + esp_gap_ble_cb_event_t event, + esp_ble_gap_cb_param_t* param) { + ESP_LOGD(LOG_TAG, "BLEServer ... handling GAP event!"); + switch(event) { + case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: { + /* + esp_ble_adv_params_t adv_params; + adv_params.adv_int_min = 0x20; + adv_params.adv_int_max = 0x40; + adv_params.adv_type = ADV_TYPE_IND; + adv_params.own_addr_type = BLE_ADDR_TYPE_PUBLIC; + adv_params.channel_map = ADV_CHNL_ALL; + adv_params.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY; + ESP_LOGD(tag, "Starting advertising"); + esp_err_t errRc = ::esp_ble_gap_start_advertising(&adv_params); + if (errRc != ESP_OK) { + ESP_LOGE(tag, "esp_ble_gap_start_advertising: rc=%d %s", errRc, espToString(errRc)); + return; + } + */ + break; + } + default: + break; + } +} // handleGAPEvent + + + +/** + * @brief Handle a GATT Server Event. + * + * @param [in] event + * @param [in] gatts_if + * @param [in] param + * + */ +void BLEServer::handleGATTServerEvent( + esp_gatts_cb_event_t event, + esp_gatt_if_t gatts_if, + esp_ble_gatts_cb_param_t* param) { + + ESP_LOGD(LOG_TAG, ">> handleGATTServerEvent: %s", + BLEUtils::gattServerEventTypeToString(event).c_str()); + + // Invoke the handler for every Service we have. + m_serviceMap.handleGATTServerEvent(event, gatts_if, param); + + switch(event) { + + + // ESP_GATTS_CONNECT_EVT + // connect: + // - uint16_t conn_id + // - esp_bd_addr_t remote_bda + // - bool is_connected + case ESP_GATTS_CONNECT_EVT: { + m_connId = param->connect.conn_id; // Save the connection id. + if (m_pServerCallbacks != nullptr) { + m_pServerCallbacks->onConnect(this); + } + m_connectedCount++; + break; + } // ESP_GATTS_CONNECT_EVT + + + // ESP_GATTS_REG_EVT + // reg: + // - esp_gatt_status_t status + // - uint16_t app_id + case ESP_GATTS_REG_EVT: { + m_gatts_if = gatts_if; + + m_semaphoreRegisterAppEvt.give(); + break; + } // ESP_GATTS_REG_EVT + + + // ESP_GATTS_CREATE_EVT + // Called when a new service is registered as having been created. + // + // create: + // * esp_gatt_status_t status + // * uint16_t service_handle + // * esp_gatt_srvc_id_t service_id + // + case ESP_GATTS_CREATE_EVT: { + BLEService* pService = m_serviceMap.getByUUID(param->create.service_id.id.uuid); + m_serviceMap.setByHandle(param->create.service_handle, pService); + //pService->setHandle(param->create.service_handle); + m_semaphoreCreateEvt.give(); + break; + } // ESP_GATTS_CREATE_EVT + + + // ESP_GATTS_READ_EVT - A request to read the value of a characteristic has arrived. + // + // read: + // - uint16_t conn_id + // - uint32_t trans_id + // - esp_bd_addr_t bda + // - uint16_t handle + // - uint16_t offset + // - bool is_long + // - bool need_rsp + // + case ESP_GATTS_READ_EVT: { + break; + } // ESP_GATTS_READ_EVT + + + // ESP_GATTS_WRITE_EVT - A request to write the value of a characteristic has arrived. + // + // write: + // - uint16_t conn_id + // - uint16_t trans_id + // - esp_bd_addr_t bda + // - uint16_t handle + // - uint16_t offset + // - bool need_rsp + // - bool is_prep + // - uint16_t len + // - uint8_t *value + + case ESP_GATTS_WRITE_EVT: { + break; + } + + // ESP_GATTS_DISCONNECT_EVT + // If we receive a disconnect event then invoke the callback for disconnects (if one is present). + // we also want to start advertising again. + case ESP_GATTS_DISCONNECT_EVT: { + m_connectedCount--; + if (m_pServerCallbacks != nullptr) { + m_pServerCallbacks->onDisconnect(this); + } + startAdvertising(); + break; + } // ESP_GATTS_DISCONNECT_EVT + + + // ESP_GATTS_ADD_CHAR_EVT - Indicate that a characteristic was added to the service. + // add_char: + // - esp_gatt_status_t status + // - uint16_t attr_handle + // - uint16_t service_handle + // - esp_bt_uuid_t char_uuid + case ESP_GATTS_ADD_CHAR_EVT: { + break; + } // ESP_GATTS_ADD_CHAR_EVT + + + default: { + break; + } + } + ESP_LOGD(LOG_TAG, "<< handleGATTServerEvent"); +} // handleGATTServerEvent + + +/** + * @brief Register the app. + * + * @return N/A + */ +void BLEServer::registerApp() { + ESP_LOGD(LOG_TAG, ">> registerApp - %d", m_appId); + m_semaphoreRegisterAppEvt.take("registerApp"); // Take the mutex, will be released by ESP_GATTS_REG_EVT event. + ::esp_ble_gatts_app_register(m_appId); + m_semaphoreRegisterAppEvt.wait("registerApp"); + ESP_LOGD(LOG_TAG, "<< registerApp"); +} // registerApp + + +/** + * @brief Set the callbacks. + * + * As a %BLE server operates, it will generate server level events such as a new client connecting or a previous client + * disconnecting. This function can be called to register a callback handler that will be invoked when these + * events are detected. + * + * @param [in] pCallbacks The callbacks to be invoked. + */ +void BLEServer::setCallbacks(BLEServerCallbacks* pCallbacks) { + m_pServerCallbacks = pCallbacks; +} // setCallbacks + + +/** + * @brief Start advertising. + * + * Start the server advertising its existence. This is a convenience function and is equivalent to + * retrieving the advertising object and invoking start upon it. + */ +void BLEServer::startAdvertising() { + ESP_LOGD(LOG_TAG, ">> startAdvertising"); + m_bleAdvertising.start(); + ESP_LOGD(LOG_TAG, "<< startAdvertising"); +} // startAdvertising + + +/* +void BLEServer::addCharacteristic(BLECharacteristic *characteristic, BLEService *pService) { + ESP_LOGD(tag, "Adding characteristic (esp_ble_gatts_add_char): uuid=%s, serviceHandle=0x%.2x", + characteristic->m_bleUUID.toString().c_str(), + pService->getHandle()); + + m_characteristicMap.setByUUID(characteristic->m_bleUUID, characteristic); + + esp_err_t errRc = ::esp_ble_gatts_add_char( + pService->getHandle(), + characteristic->getUUID().getNative(), + (esp_gatt_perm_t)(ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE), + characteristic->getProperties(), + &characteristic->m_value, + NULL); + + if (errRc != ESP_OK) { + ESP_LOGE(tag, "esp_ble_gatts_add_char: rc=%d %s", errRc, espToString(errRc)); + return; + } +} +*/ + +#endif // CONFIG_BT_ENABLED diff --git a/src/BLEServer.h b/src/BLEServer.h new file mode 100644 index 0000000..c6307bc --- /dev/null +++ b/src/BLEServer.h @@ -0,0 +1,117 @@ +/* + * BLEServer.h + * + * Created on: Apr 16, 2017 + * Author: kolban + */ + +#ifndef COMPONENTS_CPP_UTILS_BLESERVER_H_ +#define COMPONENTS_CPP_UTILS_BLESERVER_H_ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) +#include + +#include +#include + +#include "BLEUUID.h" +#include "BLEAdvertising.h" +#include "BLECharacteristic.h" +#include "BLEService.h" +#include "FreeRTOS.h" + +class BLEServerCallbacks; + + +/** + * @brief A data structure that manages the %BLE servers owned by a BLE server. + */ +class BLEServiceMap { +public: + BLEService* getByHandle(uint16_t handle); + BLEService* getByUUID(const char* uuid); + BLEService* getByUUID(BLEUUID uuid); + void handleGATTServerEvent( + esp_gatts_cb_event_t event, + esp_gatt_if_t gatts_if, + esp_ble_gatts_cb_param_t* param); + void setByHandle(uint16_t handle, BLEService* service); + void setByUUID(const char* uuid, BLEService* service); + void setByUUID(BLEUUID uuid, BLEService* service); + std::string toString(); + +private: + std::map m_uuidMap; + std::map m_handleMap; +}; + + +/** + * @brief The model of a %BLE server. + */ +class BLEServer { +public: + BLEServer(); + + + uint32_t getConnectedCount(); + BLEService* createService(const char* uuid); + BLEService* createService(BLEUUID uuid); + BLEAdvertising* getAdvertising(); + void setCallbacks(BLEServerCallbacks *pCallbacks); + void startAdvertising(); + + +private: + friend class BLEService; + friend class BLECharacteristic; + friend class BLEDevice; + esp_ble_adv_data_t m_adv_data; + uint16_t m_appId; + BLEAdvertising m_bleAdvertising; + uint16_t m_connId; + uint32_t m_connectedCount; + uint16_t m_gatts_if; + FreeRTOS::Semaphore m_semaphoreRegisterAppEvt = FreeRTOS::Semaphore("RegisterAppEvt"); + FreeRTOS::Semaphore m_semaphoreCreateEvt = FreeRTOS::Semaphore("CreateEvt"); + BLEServiceMap m_serviceMap; + BLEServerCallbacks* m_pServerCallbacks; + + void createApp(uint16_t appId); + uint16_t getConnId(); + uint16_t getGattsIf(); + void handleGAPEvent(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param); + void handleGATTServerEvent(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param); + void registerApp(); +}; // BLEServer + + +/** + * @brief Callbacks associated with the operation of a %BLE server. + */ +class BLEServerCallbacks { +public: + virtual ~BLEServerCallbacks() {}; + /** + * @brief Handle a new client connection. + * + * When a new client connects, we are invoked. + * + * @param [in] pServer A reference to the %BLE server that received the client connection. + */ + virtual void onConnect(BLEServer* pServer); + + /** + * @brief Handle an existing client disconnection. + * + * When an existing client disconnects, we are invoked. + * + * @param [in] pServer A reference to the %BLE server that received the existing client disconnection. + */ + virtual void onDisconnect(BLEServer* pServer); +}; // BLEServerCallbacks + + + +#endif /* CONFIG_BT_ENABLED */ +#endif /* COMPONENTS_CPP_UTILS_BLESERVER_H_ */ diff --git a/src/BLEServerCallbacks.cpp b/src/BLEServerCallbacks.cpp new file mode 100644 index 0000000..8808720 --- /dev/null +++ b/src/BLEServerCallbacks.cpp @@ -0,0 +1,22 @@ +/* + * BLEServerCallbacks.cpp + * + * Created on: Jul 4, 2017 + * Author: kolban + */ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) +#include "BLEServer.h" +#include +static const char* LOG_TAG = "BLEServerCallbacks"; + +void BLEServerCallbacks::onConnect(BLEServer* pServer) { + ESP_LOGD(LOG_TAG, ">> onConnect(): Default"); + ESP_LOGD(LOG_TAG, "<< onConnect()"); +} + +void BLEServerCallbacks::onDisconnect(BLEServer* pServer) { + ESP_LOGD(LOG_TAG, ">> onDisconnect(): Default"); + ESP_LOGD(LOG_TAG, "<< onDisconnect()"); +} +#endif /* CONFIG_BT_ENABLED */ diff --git a/src/BLEService.cpp b/src/BLEService.cpp new file mode 100644 index 0000000..ec16db8 --- /dev/null +++ b/src/BLEService.cpp @@ -0,0 +1,353 @@ +/* + * BLEService.cpp + * + * Created on: Mar 25, 2017 + * Author: kolban + */ + +// A service is identified by a UUID. A service is also the container for one or more characteristics. + +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) +#include +#include +#include + +#include +#include +#include + +#include "BLEServer.h" +#include "BLEService.h" +#include "BLEUtils.h" +#include "GeneralUtils.h" + +#define NULL_HANDLE (0xffff) + +static const char* LOG_TAG = "BLEService"; // Tag for logging. + +/** + * @brief Construct an instance of the BLEService + * @param [in] uuid The UUID of the service. + */ +BLEService::BLEService(const char* uuid) : BLEService(BLEUUID(uuid)) { +} + + +/** + * @brief Construct an instance of the BLEService + * @param [in] uuid The UUID of the service. + */ +BLEService::BLEService(BLEUUID uuid) { + m_uuid = uuid; + m_handle = NULL_HANDLE; + m_pServer = nullptr; + //m_serializeMutex.setName("BLEService"); + m_lastCreatedCharacteristic = nullptr; +} // BLEService + + +/** + * @brief Create the service. + * Create the service. + * @param [in] gatts_if The handle of the GATT server interface. + * @return N/A. + */ +void BLEService::executeCreate(BLEServer *pServer) { + ESP_LOGD(LOG_TAG, ">> executeCreate() - Creating service (esp_ble_gatts_create_service) service uuid: %s", getUUID().toString().c_str()); + + m_pServer = pServer; + esp_gatt_srvc_id_t srvc_id; + srvc_id.id.inst_id = 0; + srvc_id.id.uuid = *m_uuid.getNative(); + + m_semaphoreCreateEvt.take("executeCreate"); // Take the mutex and release at event ESP_GATTS_CREATE_EVT + + esp_err_t errRc = ::esp_ble_gatts_create_service(getServer()->getGattsIf(), &srvc_id, 10); + + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "esp_ble_gatts_create_service: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + + m_semaphoreCreateEvt.wait("executeCreate"); + + ESP_LOGD(LOG_TAG, "<< executeCreate"); +} // executeCreate + + +/** + * @brief Dump details of this BLE GATT service. + * @return N/A. + */ +void BLEService::dump() { + ESP_LOGD(LOG_TAG, "Service: uuid:%s, handle: 0x%.2x", + m_uuid.toString().c_str(), + m_handle); + ESP_LOGD(LOG_TAG, "Characteristics:\n%s", m_characteristicMap.toString().c_str()); +} // dump + +/* +void BLEService::setService(esp_gatt_srvc_id_t srvc_id) { + m_srvc_id = srvc_id; +} +*/ + +/* +esp_gatt_srvc_id_t BLEService::getService() { + return m_srvc_id; +} +*/ + + +/** + * @brief Get the UUID of the service. + * @return the UUID of the service. + */ +BLEUUID BLEService::getUUID() { + return m_uuid; +} // getUUID + + +/** + * @brief Start the service. + * Here we wish to start the service which means that we will respond to partner requests about it. + * Starting a service also means that we can create the corresponding characteristics. + * @return Start the service. + */ +void BLEService::start() { +// We ask the BLE runtime to start the service and then create each of the characteristics. +// We start the service through its local handle which was returned in the ESP_GATTS_CREATE_EVT event +// obtained as a result of calling esp_ble_gatts_create_service(). +// + ESP_LOGD(LOG_TAG, ">> start(): Starting service (esp_ble_gatts_start_service): %s", toString().c_str()); + if (m_handle == NULL_HANDLE) { + ESP_LOGE(LOG_TAG, "<< !!! We attempted to start a service but don't know its handle!"); + return; + } + + + BLECharacteristic *pCharacteristic = m_characteristicMap.getFirst(); + + while(pCharacteristic != nullptr) { + m_lastCreatedCharacteristic = pCharacteristic; + pCharacteristic->executeCreate(this); + + pCharacteristic = m_characteristicMap.getNext(); + } + // Start each of the characteristics ... these are found in the m_characteristicMap. + + m_semaphoreStartEvt.take("start"); + esp_err_t errRc = ::esp_ble_gatts_start_service(m_handle); + + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "<< esp_ble_gatts_start_service: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + m_semaphoreStartEvt.wait("start"); + + ESP_LOGD(LOG_TAG, "<< start()"); +} // start + + +/** + * @brief Set the handle associated with this service. + * @param [in] handle The handle associated with the service. + */ +void BLEService::setHandle(uint16_t handle) { + ESP_LOGD(LOG_TAG, ">> setHandle - Handle=0x%.2x, service UUID=%s)", handle, getUUID().toString().c_str()); + if (m_handle != NULL_HANDLE) { + ESP_LOGE(LOG_TAG, "!!! Handle is already set %.2x", m_handle); + return; + } + m_handle = handle; + ESP_LOGD(LOG_TAG, "<< setHandle"); +} // setHandle + + +/** + * @brief Get the handle associated with this service. + * @return The handle associated with this service. + */ +uint16_t BLEService::getHandle() { + return m_handle; +} // getHandle + + +/** + * @brief Add a characteristic to the service. + * @param [in] pCharacteristic A pointer to the characteristic to be added. + */ +void BLEService::addCharacteristic(BLECharacteristic* pCharacteristic) { +// We maintain a mapping of characteristics owned by this service. These are managed by the +// BLECharacteristicMap class instance found in m_characteristicMap. We add the characteristic +// to the map and then ask the service to add the characteristic at the BLE level (ESP-IDF). +// + ESP_LOGD(LOG_TAG, ">> addCharacteristic()"); + ESP_LOGD(LOG_TAG, "Adding characteristic (esp_ble_gatts_add_char): uuid=%s to service: %s", + pCharacteristic->getUUID().toString().c_str(), + toString().c_str()); + + // Check that we don't add the same characteristic twice. + if (m_characteristicMap.getByUUID(pCharacteristic->getUUID()) != nullptr) { + ESP_LOGE(LOG_TAG, "<< Attempt to add a characteristic but we already have one with this UUID"); + return; + } + + // Remember this characteristic in our map of characteristics. At this point, we can lookup by UUID + // but not by handle. The handle is allocated to us on the ESP_GATTS_ADD_CHAR_EVT. + m_characteristicMap.setByUUID(pCharacteristic->getUUID(), pCharacteristic); + + ESP_LOGD(LOG_TAG, "<< addCharacteristic()"); +} // addCharacteristic + + +/** + * @brief Create a new BLE Characteristic associated with this service. + * @param [in] uuid - The UUID of the characteristic. + * @param [in] properties - The properties of the characteristic. + * @return The new BLE characteristic. + */ +BLECharacteristic* BLEService::createCharacteristic(const char* uuid, uint32_t properties) { + return createCharacteristic(BLEUUID(uuid), properties); +} + +/** + * @brief Create a new BLE Characteristic associated with this service. + * @param [in] uuid - The UUID of the characteristic. + * @param [in] properties - The properties of the characteristic. + * @return The new BLE characteristic. + */ +BLECharacteristic* BLEService::createCharacteristic(BLEUUID uuid, uint32_t properties) { + BLECharacteristic *pCharacteristic = new BLECharacteristic(uuid, properties); + addCharacteristic(pCharacteristic); + return pCharacteristic; +} // createCharacteristic + + +/** + * @brief Handle a GATTS server event. + */ +void BLEService::handleGATTServerEvent( + esp_gatts_cb_event_t event, + esp_gatt_if_t gatts_if, + esp_ble_gatts_cb_param_t *param) { + + + switch(event) { + // ESP_GATTS_ADD_CHAR_EVT - Indicate that a characteristic was added to the service. + // add_char: + // - esp_gatt_status_t status + // - uint16_t attr_handle + // - uint16_t service_handle + // - esp_bt_uuid_t char_uuid + + // If we have reached the correct service, then locate the characteristic and remember the handle + // for that characteristic. + case ESP_GATTS_ADD_CHAR_EVT: { + if (m_handle == param->add_char.service_handle) { + BLECharacteristic *pCharacteristic = getCharacteristic(BLEUUID(param->add_char.char_uuid)); + if (pCharacteristic == nullptr) { + ESP_LOGE(LOG_TAG, "Expected to find characteristic with UUID: %s, but didnt!", + BLEUUID(param->add_char.char_uuid).toString().c_str()); + dump(); + m_semaphoreAddCharEvt.give(); + break; + } + pCharacteristic->setHandle(param->add_char.attr_handle); + m_characteristicMap.setByHandle(param->add_char.attr_handle, pCharacteristic); + //ESP_LOGD(tag, "Characteristic map: %s", m_characteristicMap.toString().c_str()); + m_semaphoreAddCharEvt.give(); + break; + } // Reached the correct service. + break; + } // ESP_GATTS_ADD_CHAR_EVT + + // ESP_GATTS_START_EVT + // + // start: + // esp_gatt_status_t status + // uint16_t service_handle + case ESP_GATTS_START_EVT: { + if (param->start.service_handle == getHandle()) { + m_semaphoreStartEvt.give(); + } + break; + } // ESP_GATTS_START_EVT + + + // ESP_GATTS_CREATE_EVT + // Called when a new service is registered as having been created. + // + // create: + // * esp_gatt_status_t status + // * uint16_t service_handle + // * esp_gatt_srvc_id_t service_id + // * - esp_gatt_id id + // * - esp_bt_uuid uuid + // * - uint8_t inst_id + // * - bool is_primary + // + case ESP_GATTS_CREATE_EVT: { + if (getUUID().equals(BLEUUID(param->create.service_id.id.uuid))) { + setHandle(param->create.service_handle); + m_semaphoreCreateEvt.give(); + } + break; + } // ESP_GATTS_CREATE_EVT + + default: { + break; + } // Default + } // Switch + + m_characteristicMap.handleGATTServerEvent(event, gatts_if, param); +} // handleGATTServerEvent + + +BLECharacteristic* BLEService::getCharacteristic(const char* uuid) { + return getCharacteristic(BLEUUID(uuid)); +} + + +BLECharacteristic* BLEService::getCharacteristic(BLEUUID uuid) { + return m_characteristicMap.getByUUID(uuid); +} + + +/** + * @brief Return a string representation of this service. + * A service is defined by: + * * Its UUID + * * Its handle + * @return A string representation of this service. + */ +std::string BLEService::toString() { + std::stringstream stringStream; + stringStream << "UUID: " << getUUID().toString() << + ", handle: 0x" << std::hex << std::setfill('0') << std::setw(2) << getHandle(); + return stringStream.str(); +} // toString + + +/** + * @brief Get the last created characteristic. + * It is lamentable that this function has to exist. It returns the last created characteristic. + * We need this because the descriptor API is built around the notion that a new descriptor, when created, + * is associated with the last characteristics created and we need that information. + * @return The last created characteristic. + */ +BLECharacteristic* BLEService::getLastCreatedCharacteristic() { + return m_lastCreatedCharacteristic; +} // getLastCreatedCharacteristic + + +/** + * @brief Get the BLE server associated with this service. + * @return The BLEServer associated with this service. + */ +BLEServer* BLEService::getServer() { + return m_pServer; +} // getServer + +#endif // CONFIG_BT_ENABLED diff --git a/src/BLEService.h b/src/BLEService.h new file mode 100644 index 0000000..86d0776 --- /dev/null +++ b/src/BLEService.h @@ -0,0 +1,99 @@ +/* + * BLEService.h + * + * Created on: Mar 25, 2017 + * Author: kolban + */ + +#ifndef COMPONENTS_CPP_UTILS_BLESERVICE_H_ +#define COMPONENTS_CPP_UTILS_BLESERVICE_H_ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) + +#include + +#include "BLECharacteristic.h" +#include "BLEServer.h" +#include "BLEUUID.h" +#include "FreeRTOS.h" + +class BLEServer; + +/** + * @brief A data mapping used to manage the set of %BLE characteristics known to the server. + */ +class BLECharacteristicMap { +public: + void setByUUID(const char* uuid, BLECharacteristic* pCharacteristic); + void setByUUID(BLEUUID uuid, BLECharacteristic* pCharacteristic); + void setByHandle(uint16_t handle, BLECharacteristic* pCharacteristic); + BLECharacteristic* getByUUID(const char* uuid); + BLECharacteristic* getByUUID(BLEUUID uuid); + BLECharacteristic* getByHandle(uint16_t handle); + BLECharacteristic* getFirst(); + BLECharacteristic* getNext(); + std::string toString(); + void handleGATTServerEvent( + esp_gatts_cb_event_t event, + esp_gatt_if_t gatts_if, + esp_ble_gatts_cb_param_t* param); + + +private: + std::map m_uuidMap; + std::map m_handleMap; + std::map::iterator m_iterator; +}; + + +/** + * @brief The model of a %BLE service. + * + */ +class BLEService { +public: + BLEService(const char* uuid); + BLEService(BLEUUID uuid); + + void addCharacteristic(BLECharacteristic* pCharacteristic); + BLECharacteristic* createCharacteristic(const char* uuid, uint32_t properties); + BLECharacteristic* createCharacteristic(BLEUUID uuid, uint32_t properties); + void dump(); + void executeCreate(BLEServer* pServer); + BLECharacteristic* getCharacteristic(const char* uuid); + BLECharacteristic* getCharacteristic(BLEUUID uuid); + BLEUUID getUUID(); + BLEServer* getServer(); + void start(); + std::string toString(); + +private: + friend class BLEServer; + friend class BLEServiceMap; + friend class BLEDescriptor; + friend class BLECharacteristic; + friend class BLEDevice; + + BLECharacteristicMap m_characteristicMap; + uint16_t m_handle; + BLECharacteristic* m_lastCreatedCharacteristic; + BLEServer* m_pServer; + //FreeRTOS::Semaphore m_serializeMutex; + FreeRTOS::Semaphore m_semaphoreAddCharEvt = FreeRTOS::Semaphore("AddCharEvt"); + FreeRTOS::Semaphore m_semaphoreCreateEvt = FreeRTOS::Semaphore("CreateEvt"); + FreeRTOS::Semaphore m_semaphoreStartEvt = FreeRTOS::Semaphore("StartEvt"); + BLEUUID m_uuid; + + uint16_t getHandle(); + BLECharacteristic* getLastCreatedCharacteristic(); + void handleGATTServerEvent( + esp_gatts_cb_event_t event, + esp_gatt_if_t gatts_if, + esp_ble_gatts_cb_param_t* param); + void setHandle(uint16_t handle); + //void setService(esp_gatt_srvc_id_t srvc_id); +}; // BLEService + + +#endif // CONFIG_BT_ENABLED +#endif /* COMPONENTS_CPP_UTILS_BLESERVICE_H_ */ diff --git a/src/BLEServiceMap.cpp b/src/BLEServiceMap.cpp new file mode 100644 index 0000000..8fdbd5a --- /dev/null +++ b/src/BLEServiceMap.cpp @@ -0,0 +1,95 @@ +/* + * BLEServiceMap.cpp + * + * Created on: Jun 22, 2017 + * Author: kolban + */ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) +#include +#include +#include "BLEService.h" + + +/** + * @brief Return the service by UUID. + * @param [in] UUID The UUID to look up the service. + * @return The characteristic. + */ +BLEService* BLEServiceMap::getByUUID(const char* uuid) { + return getByUUID(BLEUUID(uuid)); +} + +/** + * @brief Return the service by UUID. + * @param [in] UUID The UUID to look up the service. + * @return The characteristic. + */ +BLEService* BLEServiceMap::getByUUID(BLEUUID uuid) { + for (auto &myPair : m_uuidMap) { + if (myPair.second->getUUID().equals(uuid)) { + return myPair.second; + } + } + //return m_uuidMap.at(uuid.toString()); + return nullptr; +} // getByUUID + + +/** + * @brief Return the service by handle. + * @param [in] handle The handle to look up the service. + * @return The service. + */ +BLEService* BLEServiceMap::getByHandle(uint16_t handle) { + return m_handleMap.at(handle); +} // getByHandle + + +/** + * @brief Set the service by UUID. + * @param [in] uuid The uuid of the service. + * @param [in] characteristic The service to cache. + * @return N/A. + */ +void BLEServiceMap::setByUUID(BLEUUID uuid, + BLEService *service) { + m_uuidMap.insert(std::pair(uuid.toString(), service)); +} // setByUUID + + +/** + * @brief Set the service by handle. + * @param [in] handle The handle of the service. + * @param [in] service The service to cache. + * @return N/A. + */ +void BLEServiceMap::setByHandle(uint16_t handle, + BLEService* service) { + m_handleMap.insert(std::pair(handle, service)); +} // setByHandle + + +/** + * @brief Return a string representation of the service map. + * @return A string representation of the service map. + */ +std::string BLEServiceMap::toString() { + std::stringstream stringStream; + stringStream << std::hex << std::setfill('0'); + for (auto &myPair: m_handleMap) { + stringStream << "handle: 0x" << std::setw(2) << myPair.first << ", uuid: " + myPair.second->getUUID().toString() << "\n"; + } + return stringStream.str(); +} // toString + +void BLEServiceMap::handleGATTServerEvent( + esp_gatts_cb_event_t event, + esp_gatt_if_t gatts_if, + esp_ble_gatts_cb_param_t *param) { + // Invoke the handler for every Service we have. + for (auto &myPair : m_uuidMap) { + myPair.second->handleGATTServerEvent(event, gatts_if, param); + } +} +#endif /* CONFIG_BT_ENABLED */ diff --git a/src/BLEUUID.cpp b/src/BLEUUID.cpp new file mode 100644 index 0000000..9a4fe45 --- /dev/null +++ b/src/BLEUUID.cpp @@ -0,0 +1,326 @@ +/* + * BLEUUID.cpp + * + * Created on: Jun 21, 2017 + * Author: kolban + */ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) +#include +#include +#include +#include +#include +#include "BLEUUID.h" +static const char* LOG_TAG = "BLEUUID"; + + +/** + * @brief Copy memory from source to target but in reverse order. + * + * When we move memory from one location it is normally: + * + * ``` + * [0][1][2]...[n] -> [0][1][2]...[n] + * ``` + * + * with this function, it is: + * + * ``` + * [0][1][2]...[n] -> [n][n-1][n-2]...[0] + * ``` + * + * @param [in] target The target of the copy + * @param [in] source The source of the copy + * @param [in] size The number of bytes to copy + */ +static void memrcpy(uint8_t* target, uint8_t* source, uint32_t size) { + target+=(size-1); // Point target to the last byte of the target data + while (size > 0) { + *target = *source; + target--; + source++; + size--; + } +} // memrcpy + + +/** + * @brief Create a UUID from a string. + * + * Create a UUID from a string. There will be two possible stories here. Either the string represents + * a binary data field or the string represents a hex encoding of a UUID. + * For the hex encoding, here is an example: + * + * ``` + * "beb5483e-36e1-4688-b7f5-ea07361b26a8" + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + * 12345678-90ab-cdef-1234-567890abcdef + * ``` + * + * This has a length of 36 characters. We need to parse this into 16 bytes. + * + * @param [in] value The string to build a UUID from. + */ +BLEUUID::BLEUUID(std::string value) { + m_valueSet = true; + if (value.length() == 2) { + m_uuid.len = ESP_UUID_LEN_16; + m_uuid.uuid.uuid16 = value[0] | (value[1] << 8); + } else if (value.length() == 4) { + m_uuid.len = ESP_UUID_LEN_32; + m_uuid.uuid.uuid32 = value[0] | (value[1] << 8) | (value[2] << 16) | (value[3] << 24); + } else if (value.length() == 16) { + m_uuid.len = ESP_UUID_LEN_128; + memrcpy(m_uuid.uuid.uuid128, (uint8_t*)value.data(), 16); + } else if (value.length() == 36) { +// If the length of the string is 36 bytes then we will assume it is a long hex string in +// UUID format. + m_uuid.len = ESP_UUID_LEN_128; + int vals[16]; + sscanf(value.c_str(), "%2x%2x%2x%2x-%2x%2x-%2x%2x-%2x%2x-%2x%2x%2x%2x%2x%2x", + &vals[15], + &vals[14], + &vals[13], + &vals[12], + &vals[11], + &vals[10], + &vals[9], + &vals[8], + &vals[7], + &vals[6], + &vals[5], + &vals[4], + &vals[3], + &vals[2], + &vals[1], + &vals[0] + ); + + int i; + for (i=0; i<16; i++) { + m_uuid.uuid.uuid128[i] = vals[i]; + } + } + else { + ESP_LOGE(LOG_TAG, "ERROR: UUID value not 2, 4, 16 or 36 bytes"); + m_valueSet = false; + } +} //BLEUUID(std::string) + + +/** + * @brief Create a UUID from 16 bytes of memory. + * + * @param [in] pData The pointer to the start of the UUID. + * @param [in] size The size of the data. + * @param [in] msbFirst Is the MSB first in pData memory? + */ +BLEUUID::BLEUUID(uint8_t* pData, size_t size, bool msbFirst) { + if (size != 16) { + ESP_LOGE(LOG_TAG, "ERROR: UUID length not 16 bytes"); + return; + } + m_uuid.len = ESP_UUID_LEN_128; + if (msbFirst) { + memrcpy(m_uuid.uuid.uuid128, pData, 16); + } else { + memcpy(m_uuid.uuid.uuid128, pData, 16); + } + m_valueSet = true; +} // BLEUUID + +/** + * @brief Create a UUID from the 16bit value. + * + * @param [in] uuid The 16bit short form UUID. + */ +BLEUUID::BLEUUID(uint16_t uuid) { + m_uuid.len = ESP_UUID_LEN_16; + m_uuid.uuid.uuid16 = uuid; + m_valueSet = true; +} // BLEUUID + + +/** + * @brief Create a UUID from the 32bit value. + * + * @param [in] uuid The 32bit short form UUID. + */ +BLEUUID::BLEUUID(uint32_t uuid) { + m_uuid.len = ESP_UUID_LEN_32; + m_uuid.uuid.uuid32 = uuid; + m_valueSet = true; +} // BLEUUID + + +/** + * @brief Create a UUID from the native UUID. + * + * @param [in] uuid The native UUID. + */ +BLEUUID::BLEUUID(esp_bt_uuid_t uuid) { + m_uuid = uuid; + m_valueSet = true; +} // BLEUUID + + +/** + * @brief Create a UUID from the ESP32 esp_gatt_srvc_id_t. + * + * @param [in] srvcId The data to create the UUID from. + */ +BLEUUID::BLEUUID(esp_gatt_srvc_id_t srcvId) : BLEUUID(srcvId.id.uuid) { +} // BLEUUID + + +BLEUUID::BLEUUID() { + m_valueSet = false; +} // BLEUUID + + +/** + * @brief Compare a UUID against this UUID. + * + * @param [in] uuid The UUID to compare against. + * @return True if the UUIDs are equal and false otherwise. + */ +bool BLEUUID::equals(BLEUUID uuid) { + //ESP_LOGD(TAG, "Comparing: %s to %s", toString().c_str(), uuid.toString().c_str()); + if (m_valueSet == false || uuid.m_valueSet == false) { + return false; + } + + if (uuid.m_uuid.len != m_uuid.len) { + return uuid.toString() == toString(); + } + + if (uuid.m_uuid.len == ESP_UUID_LEN_16) { + return uuid.m_uuid.uuid.uuid16 == m_uuid.uuid.uuid16; + } + + if (uuid.m_uuid.len == ESP_UUID_LEN_32) { + return uuid.m_uuid.uuid.uuid32 == m_uuid.uuid.uuid32; + } + + return memcmp(uuid.m_uuid.uuid.uuid128, m_uuid.uuid.uuid128, 16) == 0; +} // equals + + +/** + * @brief Get the native UUID value. + * + * @return The native UUID value or NULL if not set. + */ +esp_bt_uuid_t* BLEUUID::getNative() { + //ESP_LOGD(TAG, ">> getNative()") + if (m_valueSet == false) { + ESP_LOGD(LOG_TAG, "<< Return of un-initialized UUID!"); + return nullptr; + } + //ESP_LOGD(TAG, "<< getNative()"); + return &m_uuid; +} // getNative + + +/** + * @brief Convert a UUID to its 128 bit representation. + * + * A UUID can be internally represented as 16bit, 32bit or the full 128bit. This method + * will convert 16 or 32 bit representations to the full 128bit. + */ +BLEUUID BLEUUID::to128() { + //ESP_LOGD(LOG_TAG, ">> toFull() - %s", toString().c_str()); + + // If we either don't have a value or are already a 128 bit UUID, nothing further to do. + if (m_valueSet == false || m_uuid.len == ESP_UUID_LEN_128) { + return *this; + } + + // If we are 16 bit or 32 bit, then set the 4 bytes of the variable part of the UUID. + if (m_uuid.len == ESP_UUID_LEN_16) { + uint16_t temp = m_uuid.uuid.uuid16; + m_uuid.uuid.uuid128[15] = 0; + m_uuid.uuid.uuid128[14] = 0; + m_uuid.uuid.uuid128[13] = (temp >> 8) & 0xff; + m_uuid.uuid.uuid128[12] = temp & 0xff; + + } + else if (m_uuid.len == ESP_UUID_LEN_32) { + uint32_t temp = m_uuid.uuid.uuid32; + m_uuid.uuid.uuid128[15] = (temp >> 24) & 0xff; + m_uuid.uuid.uuid128[14] = (temp >> 16) & 0xff; + m_uuid.uuid.uuid128[13] = (temp >> 8) & 0xff; + m_uuid.uuid.uuid128[12] = temp & 0xff; + } + + // Set the fixed parts of the UUID. + m_uuid.uuid.uuid128[11] = 0x00; + m_uuid.uuid.uuid128[10] = 0x00; + + m_uuid.uuid.uuid128[9] = 0x10; + m_uuid.uuid.uuid128[8] = 0x00; + + m_uuid.uuid.uuid128[7] = 0x80; + m_uuid.uuid.uuid128[6] = 0x00; + + m_uuid.uuid.uuid128[5] = 0x00; + m_uuid.uuid.uuid128[4] = 0x80; + m_uuid.uuid.uuid128[3] = 0x5f; + m_uuid.uuid.uuid128[2] = 0x9b; + m_uuid.uuid.uuid128[1] = 0x34; + m_uuid.uuid.uuid128[0] = 0xfb; + + m_uuid.len = ESP_UUID_LEN_128; + //ESP_LOGD(TAG, "<< toFull <- %s", toString().c_str()); + return *this; +} // to128 + + +//01234567 8901 2345 6789 012345678901 +//0000180d-0000-1000-8000-00805f9b34fb +//0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + +/** + * @brief Get a string representation of the UUID. + * + * @return A string representation of the UUID. + */ +std::string BLEUUID::toString() { + if (m_valueSet == false) { + return ""; + } + + if (m_uuid.len == ESP_UUID_LEN_16) { + std::stringstream ss; + ss << "0000" << std::hex << std::setfill('0') << std::setw(4) << m_uuid.uuid.uuid16 << "-0000-1000-8000-00805f9b34fb"; + return ss.str(); + } + + if (m_uuid.len == ESP_UUID_LEN_32) { + std::stringstream ss; + ss << std::hex << std::setfill('0') << std::setw(8) << m_uuid.uuid.uuid32 << "-0000-1000-8000-00805f9b34fb"; + return ss.str(); + } + + std::stringstream ss; + ss << std::hex << std::setfill('0') << + std::setw(2) << (int)m_uuid.uuid.uuid128[15] << + std::setw(2) << (int)m_uuid.uuid.uuid128[14] << + std::setw(2) << (int)m_uuid.uuid.uuid128[13] << + std::setw(2) << (int)m_uuid.uuid.uuid128[12] << "-" << + std::setw(2) << (int)m_uuid.uuid.uuid128[11] << + std::setw(2) << (int)m_uuid.uuid.uuid128[10] << "-" << + std::setw(2) << (int)m_uuid.uuid.uuid128[9] << + std::setw(2) << (int)m_uuid.uuid.uuid128[8] << "-" << + std::setw(2) << (int)m_uuid.uuid.uuid128[7] << + std::setw(2) << (int)m_uuid.uuid.uuid128[6] << "-" << + std::setw(2) << (int)m_uuid.uuid.uuid128[5] << + std::setw(2) << (int)m_uuid.uuid.uuid128[4] << + std::setw(2) << (int)m_uuid.uuid.uuid128[3] << + std::setw(2) << (int)m_uuid.uuid.uuid128[2] << + std::setw(2) << (int)m_uuid.uuid.uuid128[1] << + std::setw(2) << (int)m_uuid.uuid.uuid128[0]; + return ss.str(); +} // toString +#endif /* CONFIG_BT_ENABLED */ diff --git a/src/BLEUUID.h b/src/BLEUUID.h new file mode 100644 index 0000000..c364796 --- /dev/null +++ b/src/BLEUUID.h @@ -0,0 +1,37 @@ +/* + * BLEUUID.h + * + * Created on: Jun 21, 2017 + * Author: kolban + */ + +#ifndef COMPONENTS_CPP_UTILS_BLEUUID_H_ +#define COMPONENTS_CPP_UTILS_BLEUUID_H_ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) +#include +#include + +/** + * @brief A model of a %BLE UUID. + */ +class BLEUUID { +public: + BLEUUID(std::string uuid); + BLEUUID(uint16_t uuid); + BLEUUID(uint32_t uuid); + BLEUUID(esp_bt_uuid_t uuid); + BLEUUID(uint8_t* pData, size_t size, bool msbFirst); + BLEUUID(esp_gatt_srvc_id_t srcvId); + BLEUUID(); + bool equals(BLEUUID uuid); + esp_bt_uuid_t* getNative(); + BLEUUID to128(); + std::string toString(); + +private: + esp_bt_uuid_t m_uuid; + bool m_valueSet; +}; // BLEUUID +#endif /* CONFIG_BT_ENABLED */ +#endif /* COMPONENTS_CPP_UTILS_BLEUUID_H_ */ diff --git a/src/BLEUtils.cpp b/src/BLEUtils.cpp new file mode 100644 index 0000000..468a7e1 --- /dev/null +++ b/src/BLEUtils.cpp @@ -0,0 +1,1352 @@ +/* + * BLEUtils.cpp + * + * Created on: Mar 25, 2017 + * Author: kolban + */ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) +#include "BLEUtils.h" +#include "BLEUUID.h" +#include "BLEClient.h" +#include "BLEAddress.h" +#include "GeneralUtils.h" + +#include +#include +#include // ESP32 BLE +#include // ESP32 BLE +#include // ESP32 BLE +#include // ESP32 BLE +#include // ESP32 ESP-IDF +#include // ESP32 ESP-IDF +#include // Part of C++ STL +#include +#include + +static const char* LOG_TAG = "BLEUtils"; + +/* +static std::map g_addressMap; +static std::map g_connIdMap; +*/ + +typedef struct { + uint32_t assignedNumber; + std::string name; +} characteristicMap_t; + +static characteristicMap_t g_characteristicsMappings[] = { + {0x2a00, "Device Name"}, + {0x2a01, "Appearance"}, + {0, ""} +}; + +/** + * @brief Mapping from service ids to names + */ +typedef struct { + std::string name; + std::string type; + uint32_t assignedNumber; +} gattService_t; + + +/** + * Definition of the service ids to names that we know about. + */ +static const gattService_t g_gattServices[] = { + {"Alert Notification Service", "org.bluetooth.service.alert_notification", 0x1811}, + {"Automation IO", "org.bluetooth.service.automation_io", 0x1815 }, + {"Battery Service","org.bluetooth.service.battery_service", 0x180F}, + {"Blood Pressure", "org.bluetooth.service.blood_pressure", 0x1810}, + {"Body Composition", "org.bluetooth.service.body_composition", 0x181B}, + {"Bond Management", "org.bluetooth.service.bond_management", 0x181E}, + {"Continuous Glucose Monitoring", "org.bluetooth.service.continuous_glucose_monitoring", 0x181F}, + {"Current Time Service", "org.bluetooth.service.current_time", 0x1805}, + {"Cycling Power", "org.bluetooth.service.cycling_power", 0x1818}, + {"Cycling Speed and Cadence", "org.bluetooth.service.cycling_speed_and_cadence", 0x1816}, + {"Device Information", "org.bluetooth.service.device_information", 0x180A}, + {"Environmental Sensing", "org.bluetooth.service.environmental_sensing", 0x181A}, + {"Generic Access", "org.bluetooth.service.generic_access", 0x1800}, + {"Generic Attribute", "org.bluetooth.service.generic_attribute", 0x1801}, + {"Glucose", "org.bluetooth.service.glucose", 0x1808}, + {"Health Thermometer", "org.bluetooth.service.health_thermometer", 0x1809}, + {"Heart Rate", "org.bluetooth.service.heart_rate", 0x180D}, + {"HTTP Proxy", "org.bluetooth.service.http_proxy", 0x1823}, + {"Human Interface Device", "org.bluetooth.service.human_interface_device", 0x1812}, + {"Immediate Alert", "org.bluetooth.service.immediate_alert", 0x1802}, + {"Indoor Positioning", "org.bluetooth.service.indoor_positioning", 0x1821}, + {"Internet Protocol Support", "org.bluetooth.service.internet_protocol_support", 0x1820}, + {"Link Loss", "org.bluetooth.service.link_loss", 0x1803}, + {"Location and Navigation", "org.bluetooth.service.location_and_navigation", 0x1819}, + {"Next DST Change Service", "org.bluetooth.service.next_dst_change", 0x1807}, + {"Object Transfer", "org.bluetooth.service.object_transfer", 0x1825}, + {"Phone Alert Status Service", "org.bluetooth.service.phone_alert_status", 0x180E}, + {"Pulse Oximeter", "org.bluetooth.service.pulse_oximeter", 0x1822}, + {"Reference Time Update Service", "org.bluetooth.service.reference_time_update", 0x1806}, + {"Running Speed and Cadence", "org.bluetooth.service.running_speed_and_cadence", 0x1814}, + {"Scan Parameters", "org.bluetooth.service.scan_parameters", 0x1813}, + {"Transport Discovery", "org.bluetooth.service.transport_discovery", 0x1824}, + {"Tx Power", "org.bluetooth.service.tx_power", 0x1804}, + {"User Data", "org.bluetooth.service.user_data", 0x181C}, + {"Weight Scale", "org.bluetooth.service.weight_scale", 0x181D}, + {"", "", 0 } +}; + +/** + * @brief Convert characteristic properties into a string representation. + * @param [in] prop Characteristic properties. + * @return A string representation of characteristic properties. + */ +std::string BLEUtils::characteristicPropertiesToString(esp_gatt_char_prop_t prop) { + std::stringstream stream; + stream << + "broadcast: " << ((prop & ESP_GATT_CHAR_PROP_BIT_BROADCAST)?"1":"0") << + ", read: " << ((prop & ESP_GATT_CHAR_PROP_BIT_READ)?"1":"0") << + ", write_nr: " << ((prop & ESP_GATT_CHAR_PROP_BIT_WRITE_NR)?"1":"0") << + ", write: " << ((prop & ESP_GATT_CHAR_PROP_BIT_WRITE)?"1":"0") << + ", notify: " << ((prop & ESP_GATT_CHAR_PROP_BIT_NOTIFY)?"1":"0") << + ", indicate: " << ((prop & ESP_GATT_CHAR_PROP_BIT_INDICATE)?"1":"0") << + ", auth: " << ((prop & ESP_GATT_CHAR_PROP_BIT_AUTH)?"1":"0"); + return stream.str(); +} // characteristicPropertiesToString + +/** + * @brief Convert an esp_gatt_id_t to a string. + */ +static std::string gattIdToString(esp_gatt_id_t gattId) { + std::stringstream stream; + stream << "uuid: " << BLEUUID(gattId.uuid).toString() << ", inst_id: " << (int)gattId.inst_id; + //sprintf(buffer, "uuid: %s, inst_id: %d", uuidToString(gattId.uuid).c_str(), gattId.inst_id); + return stream.str(); +} // gattIdToString + + +/** + * @brief Convert an esp_ble_addr_type_t to a string representation. + */ +const char* BLEUtils::addressTypeToString(esp_ble_addr_type_t type) { + switch(type) { + case BLE_ADDR_TYPE_PUBLIC: + return "BLE_ADDR_TYPE_PUBLIC"; + case BLE_ADDR_TYPE_RANDOM: + return "BLE_ADDR_TYPE_RANDOM"; + case BLE_ADDR_TYPE_RPA_PUBLIC: + return "BLE_ADDR_TYPE_RPA_PUBLIC"; + case BLE_ADDR_TYPE_RPA_RANDOM: + return "BLE_ADDR_TYPE_RPA_RANDOM"; + default: + return "Unknown addr_t"; + } +} // addressTypeToString + + +/** + * @brief Given an advertising type, return a string representation of the type. + * + * For details see ... + * https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile + * + * @return A string representation of the type. + */ +const char* BLEUtils::advTypeToString(uint8_t advType) { + switch(advType) { + case ESP_BLE_AD_TYPE_FLAG: + return "ESP_BLE_AD_TYPE_FLAG"; + case ESP_BLE_AD_TYPE_16SRV_PART: + return "ESP_BLE_AD_TYPE_16SRV_PART"; + case ESP_BLE_AD_TYPE_16SRV_CMPL: + return "ESP_BLE_AD_TYPE_16SRV_CMPL"; + case ESP_BLE_AD_TYPE_32SRV_PART: + return "ESP_BLE_AD_TYPE_32SRV_PART"; + case ESP_BLE_AD_TYPE_32SRV_CMPL: + return "ESP_BLE_AD_TYPE_32SRV_CMPL"; + case ESP_BLE_AD_TYPE_128SRV_PART: + return "ESP_BLE_AD_TYPE_128SRV_PART"; + case ESP_BLE_AD_TYPE_128SRV_CMPL: + return "ESP_BLE_AD_TYPE_128SRV_CMPL"; + case ESP_BLE_AD_TYPE_NAME_SHORT: + return "ESP_BLE_AD_TYPE_NAME_SHORT"; + case ESP_BLE_AD_TYPE_NAME_CMPL: + return "ESP_BLE_AD_TYPE_NAME_CMPL"; + case ESP_BLE_AD_TYPE_TX_PWR: + return "ESP_BLE_AD_TYPE_TX_PWR"; + case ESP_BLE_AD_TYPE_DEV_CLASS: + return "ESP_BLE_AD_TYPE_DEV_CLASS"; + case ESP_BLE_AD_TYPE_SM_TK: + return "ESP_BLE_AD_TYPE_SM_TK"; + case ESP_BLE_AD_TYPE_SM_OOB_FLAG: + return "ESP_BLE_AD_TYPE_SM_OOB_FLAG"; + case ESP_BLE_AD_TYPE_INT_RANGE: + return "ESP_BLE_AD_TYPE_INT_RANGE"; + case ESP_BLE_AD_TYPE_SOL_SRV_UUID: + return "ESP_BLE_AD_TYPE_SOL_SRV_UUID"; + case ESP_BLE_AD_TYPE_128SOL_SRV_UUID: + return "ESP_BLE_AD_TYPE_128SOL_SRV_UUID"; + case ESP_BLE_AD_TYPE_SERVICE_DATA: + return "ESP_BLE_AD_TYPE_SERVICE_DATA"; + case ESP_BLE_AD_TYPE_PUBLIC_TARGET: + return "ESP_BLE_AD_TYPE_PUBLIC_TARGET"; + case ESP_BLE_AD_TYPE_RANDOM_TARGET: + return "ESP_BLE_Amap1D_TYPE_RANDOM_TARGET"; + case ESP_BLE_AD_TYPE_APPEARANCE: + return "ESP_BLE_AD_TYPE_APPEARANCE"; + case ESP_BLE_AD_TYPE_ADV_INT: + return "ESP_BLE_AD_TYPE_ADV_INT"; + case ESP_BLE_AD_TYPE_32SOL_SRV_UUID: + return "ESP_BLE_AD_TYPE_32SOL_SRV_UUID"; + case ESP_BLE_AD_TYPE_32SERVICE_DATA: + return "ESP_BLE_AD_TYPE_32SERVICE_DATA"; + case ESP_BLE_AD_TYPE_128SERVICE_DATA: + return "ESP_BLE_AD_TYPE_128SERVICE_DATA"; + case ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE: + return "ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE"; + default: + ESP_LOGD(LOG_TAG, "Unknown adv data type: 0x%x", advType); + return "Unknown"; + } // End switch +} // advTypeToString + + +esp_gatt_id_t BLEUtils::buildGattId(esp_bt_uuid_t uuid, uint8_t inst_id) { + esp_gatt_id_t retGattId; + retGattId.uuid = uuid; + retGattId.inst_id = inst_id; + return retGattId; +} + +esp_gatt_srvc_id_t BLEUtils::buildGattSrvcId(esp_gatt_id_t gattId, + bool is_primary) { + esp_gatt_srvc_id_t retSrvcId; + retSrvcId.id = gattId; + retSrvcId.is_primary = is_primary; + return retSrvcId; +} + +/** + * @brief Create a hex representation of data. + * + * @param [in] target Where to write the hex string. If this is null, we malloc storage. + * @param [in] source The start of the binary data. + * @param [in] length The length of the data to convert. + * @return A pointer to the formatted buffer. + */ +char *BLEUtils::buildHexData(uint8_t *target, uint8_t *source, uint8_t length) { +// Guard against too much data. + if (length > 100) { + length = 100; + } + + + if (target == nullptr) { + target = (uint8_t *)malloc(length * 2 + 1); + if (target == nullptr) { + ESP_LOGE(LOG_TAG, "buildHexData: malloc failed"); + return nullptr; + } + } + char *startOfData = (char *)target; + + int i; + for (i=0; iscan_rsp_data_cmpl.status); + break; + } // ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT + + + // + // ESP_GAP_BLE_ADV_START_COMPLETE_EVT + // + case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: { + ESP_LOGD(LOG_TAG, "[status: %d]", param->scan_start_cmpl.status); + break; + } // ESP_GAP_BLE_ADV_START_COMPLETE_EVT + + + // + // ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT + // + case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT: { + ESP_LOGD(LOG_TAG, "[status: %d]", param->scan_stop_cmpl.status); + break; + } // ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT + + + // + // ESP_GAP_BLE_AUTH_CMPL_EVT + // + case ESP_GAP_BLE_AUTH_CMPL_EVT: { + ESP_LOGD(LOG_TAG, "[bd_addr: %s, key_present: %d, key: ***, key_type: %d, success: %d, fail_reason: %d, addr_type: ***, dev_type: %s]", + BLEAddress(param->ble_security.auth_cmpl.bd_addr).toString().c_str(), + param->ble_security.auth_cmpl.key_present, + param->ble_security.auth_cmpl.key_type, + param->ble_security.auth_cmpl.success, + param->ble_security.auth_cmpl.fail_reason, + BLEUtils::devTypeToString(param->ble_security.auth_cmpl.dev_type) + ); + break; + } // ESP_GAP_BLE_AUTH_CMPL_EVT + + + // + // ESP_GAP_BLE_LOCAL_IR_EVT + // + case ESP_GAP_BLE_LOCAL_IR_EVT: { + break; + } // ESP_GAP_BLE_LOCAL_IR_EVT + + + // + // ESP_GAP_BLE_LOCAL_ER_EVT + // + case ESP_GAP_BLE_LOCAL_ER_EVT: { + break; + } // ESP_GAP_BLE_LOCAL_ER_EVT + + + // + // ESP_GAP_BLE_NC_REQ_EVT + // + case ESP_GAP_BLE_NC_REQ_EVT: { + ESP_LOGD(LOG_TAG, "[bd_addr: %s, passkey: %d]", + BLEAddress(param->ble_security.key_notif.bd_addr).toString().c_str(), + param->ble_security.key_notif.passkey); + break; + } // ESP_GAP_BLE_NC_REQ_EVT + + + // + // ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT + // + case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT: { + ESP_LOGD(LOG_TAG, "[status: %d]", param->scan_param_cmpl.status); + break; + } // ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT + + // + // ESP_GAP_BLE_SCAN_RESULT_EVT + // + // scan_rst: + // - search_evt + // - bda + // - dev_type + // - ble_addr_type + // - ble_evt_type + // - rssi + // - ble_adv + // - flag + // - num_resps + case ESP_GAP_BLE_SCAN_RESULT_EVT: { + switch(param->scan_rst.search_evt) { + case ESP_GAP_SEARCH_INQ_RES_EVT: { + ESP_LOGD(LOG_TAG, "search_evt: %s, bda: %s, dev_type: %s, ble_addr_type: %s, ble_evt_type: %s, rssi: %d, ble_adv: ??, flag: %d, num_resps: %d, adv_data_len: %d, scan_rsp_len: %d", + searchEventTypeToString(param->scan_rst.search_evt), + BLEAddress(param->scan_rst.bda).toString().c_str(), + devTypeToString(param->scan_rst.dev_type), + addressTypeToString(param->scan_rst.ble_addr_type), + eventTypeToString(param->scan_rst.ble_evt_type), + param->scan_rst.rssi, + param->scan_rst.flag, + param->scan_rst.num_resps, + param->scan_rst.adv_data_len, + param->scan_rst.scan_rsp_len + ); + break; + } // ESP_GAP_SEARCH_INQ_RES_EVT + + default: { + ESP_LOGD(LOG_TAG, "search_evt: %s",searchEventTypeToString(param->scan_rst.search_evt)); + break; + } + } + break; + } // ESP_GAP_BLE_SCAN_RESULT_EVT + + + // + // ESP_GAP_BLE_SCAN_START_COMPLETE_EVT + // + case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT: { + ESP_LOGD(LOG_TAG, "[status: %d]", param->scan_start_cmpl.status); + break; + } // ESP_GAP_BLE_SCAN_START_COMPLETE_EVT + + + // + // ESP_GAP_BLE_SEC_REQ_EVT + // + case ESP_GAP_BLE_SEC_REQ_EVT: { + ESP_LOGD(LOG_TAG, "[bd_addr: %s]", BLEAddress(param->ble_security.ble_req.bd_addr).toString().c_str()); + break; + } // ESP_GAP_BLE_SEC_REQ_EVT + + + // + // ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT + // + case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT: { + ESP_LOGD(LOG_TAG, "[status: %d]", param->scan_stop_cmpl.status); + break; + } // ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT + + default: { + ESP_LOGD(LOG_TAG, "*** dumpGapEvent: Logger not coded ***"); + break; + } // default + } // switch +} // dumpGapEvent + + +/** + * @brief Decode and dump a GATT client event + * + * @param [in] event The type of event received. + * @param [in] evtParam The data associated with the event. + */ +void BLEUtils::dumpGattClientEvent( + esp_gattc_cb_event_t event, + esp_gatt_if_t gattc_if, + esp_ble_gattc_cb_param_t *evtParam) { + + //esp_ble_gattc_cb_param_t *evtParam = (esp_ble_gattc_cb_param_t *)param; + ESP_LOGD(LOG_TAG, "GATT Event: %s", BLEUtils::gattClientEventTypeToString(event).c_str()); + switch(event) { + // + // ESP_GATTC_CLOSE_EVT + // + // close: + // - esp_gatt_status_t status + // - uint16_t conn_id + // - esp_bd_addr_t remote_bda + // - esp_gatt_conn_reason_t reason + // + case ESP_GATTC_CLOSE_EVT: { + ESP_LOGD(LOG_TAG, "[status: %s, reason:%s, conn_id: %d]", + BLEUtils::gattStatusToString(evtParam->close.status).c_str(), + BLEUtils::gattCloseReasonToString(evtParam->close.reason).c_str(), + evtParam->close.conn_id); + break; + } + + // + // ESP_GATTC_CONNECT_EVT + // + // connect: + // - esp_gatt_status_t status + // - uint16_t conn_id + // - esp_bd_addr_t remote_bda + case ESP_GATTC_CONNECT_EVT: { + ESP_LOGD(LOG_TAG, "[staus: %s, conn_id: %d, remote_bda: %s]", + BLEUtils::gattStatusToString(evtParam->connect.status).c_str(), + evtParam->connect.conn_id, + BLEAddress(evtParam->connect.remote_bda).toString().c_str() + ); + break; + } + + // + // ESP_GATTC_DISCONNECT_EVT + // + // disconnect: + // - esp_gatt_status_t status + // - uint16_t conn_id + // - esp_bd_addr_t remote_bda + case ESP_GATTC_DISCONNECT_EVT: { + ESP_LOGD(LOG_TAG, "[staus: %s, conn_id: %d, remote_bda: %s]", + BLEUtils::gattStatusToString(evtParam->disconnect.status).c_str(), + evtParam->disconnect.conn_id, + BLEAddress(evtParam->disconnect.remote_bda).toString().c_str() + ); + break; + } // ESP_GATTC_DISCONNECT_EVT + + // + // ESP_GATTC_GET_CHAR_EVT + // + // get_char: + // - esp_gatt_status_t status + // - uin1t6_t conn_id + // - esp_gatt_srvc_id_t srvc_id + // - esp_gatt_id_t char_id + // - esp_gatt_char_prop_t char_prop + // + case ESP_GATTC_GET_CHAR_EVT: { + + // If the status of the event shows that we have a value other than ESP_GATT_OK then the + // characteristic fields are not set to a usable value .. so don't try and log them. + if (evtParam->get_char.status == ESP_GATT_OK) { + std::string description = "Unknown"; + if (evtParam->get_char.char_id.uuid.len == ESP_UUID_LEN_16) { + description = BLEUtils::gattCharacteristicUUIDToString(evtParam->get_char.char_id.uuid.uuid.uuid16); + } + ESP_LOGD(LOG_TAG, "[status: %s, conn_id: %d, srvc_id: %s, char_id: %s [description: %s]\nchar_prop: %s]", + BLEUtils::gattStatusToString(evtParam->get_char.status).c_str(), + evtParam->get_char.conn_id, + BLEUtils::gattServiceIdToString(evtParam->get_char.srvc_id).c_str(), + gattIdToString(evtParam->get_char.char_id).c_str(), + description.c_str(), + BLEUtils::characteristicPropertiesToString(evtParam->get_char.char_prop).c_str() + ); + } else { + ESP_LOGD(LOG_TAG, "[status: %s, conn_id: %d, srvc_id: %s]", + BLEUtils::gattStatusToString(evtParam->get_char.status).c_str(), + evtParam->get_char.conn_id, + BLEUtils::gattServiceIdToString(evtParam->get_char.srvc_id).c_str() + ); + } + break; + } // ESP_GATTC_GET_CHAR_EVT + + // + // ESP_GATTC_NOTIFY_EVT + // + // notify + // uint16_t conn_id + // esp_bd_addr_t remote_bda + // esp_gatt_srvc_id_t srvc_id + // esp_gatt_id_t char_id + // esp_gatt_id_t descr_id + // uint16_t value_len + // uint8_t* value + // bool is_notify + // + case ESP_GATTC_NOTIFY_EVT: { + ESP_LOGD(LOG_TAG, "[conn_id: %d, remote_bda: %s, srvc_id: <%s>, char_id: <%s>, descr_id: <%s>, value_len: %d, is_notify: %d]", + evtParam->notify.conn_id, + BLEAddress(evtParam->notify.remote_bda).toString().c_str(), + BLEUtils::gattServiceIdToString(evtParam->notify.srvc_id).c_str(), + gattIdToString(evtParam->notify.char_id).c_str(), + gattIdToString(evtParam->notify.descr_id).c_str(), + evtParam->notify.value_len, + evtParam->notify.is_notify + ); + break; + } + + // + // ESP_GATTC_OPEN_EVT + // + // open: + // - esp_gatt_status_t status + // - uint16_t conn_id + // - esp_bd_addr_t remote_bda + // - uint16_t mtu + // + case ESP_GATTC_OPEN_EVT: { + ESP_LOGD(LOG_TAG, "[status: %s, conn_id: %d, remote_bda: %s, mtu: %d]", + BLEUtils::gattStatusToString(evtParam->open.status).c_str(), + evtParam->open.conn_id, + BLEAddress(evtParam->open.remote_bda).toString().c_str(), + evtParam->open.mtu); + break; + } // ESP_GATTC_OPEN_EVT + + + // + // ESP_GATTC_READ_CHAR_EVT + // + // Callback to indicate that requested data that we wanted to read is now available. + // + // read: + // esp_gatt_status_t status + // uint16_t conn_id + // esp_gatt_srvc_id_t srvc_id + // esp_gatt_id_t char_id + // esp_gatt_id_t descr_id + // uint8_t* value + // uint16_t value_type + // uint16_t value_len + case ESP_GATTC_READ_CHAR_EVT: { + ESP_LOGD(LOG_TAG, "[status: %s, conn_id: %d, srvc_id: <%s>, char_id: <%s>, descr_id: <%s>, value_type: 0x%x, value_len: %d]", + BLEUtils::gattStatusToString(evtParam->read.status).c_str(), + evtParam->read.conn_id, + BLEUtils::gattServiceIdToString(evtParam->read.srvc_id).c_str(), + gattIdToString(evtParam->read.char_id).c_str(), + gattIdToString(evtParam->read.descr_id).c_str(), + evtParam->read.value_type, + evtParam->read.value_len + ); + if (evtParam->read.status == ESP_GATT_OK) { + GeneralUtils::hexDump(evtParam->read.value, evtParam->read.value_len); + /* + char *pHexData = BLEUtils::buildHexData(nullptr, evtParam->read.value, evtParam->read.value_len); + ESP_LOGD(LOG_TAG, "value: %s \"%s\"", pHexData, BLEUtils::buildPrintData(evtParam->read.value, evtParam->read.value_len).c_str()); + free(pHexData); + */ + } + break; + } // ESP_GATTC_READ_CHAR_EVT + + + // + // ESP_GATTC_REG_EVT + // + // reg: + // - esp_gatt_status_t status + // - uint16_t app_id + // + case ESP_GATTC_REG_EVT: { + ESP_LOGD(LOG_TAG, "[status: %s, app_id: 0x%x]", + BLEUtils::gattStatusToString(evtParam->reg.status).c_str(), + evtParam->reg.app_id); + break; + } // ESP_GATTC_REG_EVT + + + // + // ESP_GATTC_REG_FOR_NOTIFY_EVT + // + // reg_for_notify: + // - esp_gatt_status_t status + // - esp_gatt_srvc_id_t srvc_id + // - esp_gatt_id_t char_id + case ESP_GATTC_REG_FOR_NOTIFY_EVT: { + ESP_LOGD(LOG_TAG, "[status: %s, srvc_id: <%s>, char_id: <%s>]", + BLEUtils::gattStatusToString(evtParam->reg_for_notify.status).c_str(), + BLEUtils::gattServiceIdToString(evtParam->reg_for_notify.srvc_id).c_str(), + gattIdToString(evtParam->reg_for_notify.char_id).c_str()); + break; + } // ESP_GATTC_REG_FOR_NOTIFY_EVT + + + // + // ESP_GATTC_SEARCH_CMPL_EVT + // + // search_cmpl: + // - esp_gatt_status_t status + // - uint16_t conn_id + // + case ESP_GATTC_SEARCH_CMPL_EVT: { + ESP_LOGD(LOG_TAG, "[status: %s, conn_id: %d]", + BLEUtils::gattStatusToString(evtParam->search_cmpl.status).c_str(), + evtParam->search_cmpl.conn_id); + break; + } // ESP_GATTC_SEARCH_CMPL_EVT + + + // + // ESP_GATTC_SEARCH_RES_EVT + // + // search_res: + // - uint16_t conn_id + // - esp_gatt_srvc_id_t srvc_id + // + case ESP_GATTC_SEARCH_RES_EVT: { + std::string name = ""; + if (evtParam->search_res.srvc_id.id.uuid.len == ESP_UUID_LEN_16) { + name = BLEUtils::gattServiceToString(evtParam->search_res.srvc_id.id.uuid.uuid.uuid16); + } + if (name.length() == 0) { + name = ""; + } + + ESP_LOGD(LOG_TAG, "[srvc_id: %s [%s], instanceId: 0x%.2x conn_id: %d]", + BLEUtils::gattServiceIdToString(evtParam->search_res.srvc_id).c_str(), + name.c_str(), + evtParam->search_res.srvc_id.id.inst_id, + evtParam->search_res.conn_id); + break; + } // ESP_GATTC_SEARCH_RES_EVT + + + // + // ESP_GATTC_WRITE_CHAR_EVT + // + // write: + // esp_gatt_status_t status + // uint16_t conn_id + // esp_gatt_srvc_id_t srvc_id + // esp_gatt_id_t char_id + // esp_gatt_id_t descr_id + case ESP_GATTC_WRITE_CHAR_EVT: { + ESP_LOGD(LOG_TAG, "[status: %s, conn_id: %d, srvc_id: <%s>, char_id: <%s>, descr_id: <%s>]", + BLEUtils::gattStatusToString(evtParam->write.status).c_str(), + evtParam->write.conn_id, + BLEUtils::gattServiceIdToString(evtParam->write.srvc_id).c_str(), + gattIdToString(evtParam->write.char_id).c_str(), + gattIdToString(evtParam->write.descr_id).c_str() + ); + break; + } + + default: + break; + } +} // dumpGattClientEvent + + +/** + * @brief Dump the details of a GATT server event. + * A GATT Server event is a callback received from the BLE subsystem when we are acting as a BLE + * server. The callback indicates the type of event in the `event` field. The `evtParam` is a + * union of structures where we can use the `event` to indicate which of the structures has been + * populated and hence is valid. + * + * @param [in] event The event type that was posted. + * @param [in] evtParam A union of structures only one of which is populated. + */ +void BLEUtils::dumpGattServerEvent( + esp_gatts_cb_event_t event, + esp_gatt_if_t gatts_if, + esp_ble_gatts_cb_param_t *evtParam) { + ESP_LOGD(LOG_TAG, "GATT ServerEvent: %s", BLEUtils::gattServerEventTypeToString(event).c_str()); + switch(event) { + + case ESP_GATTS_ADD_CHAR_DESCR_EVT: { + ESP_LOGD(LOG_TAG, "[status: %s, attr_handle: 0x%.2x, service_handle: 0x%.2x, char_uuid: %s]", + gattStatusToString(evtParam->add_char_descr.status).c_str(), + evtParam->add_char_descr.attr_handle, + evtParam->add_char_descr.service_handle, + BLEUUID(evtParam->add_char_descr.char_uuid).toString().c_str()); + break; + } // ESP_GATTS_ADD_CHAR_DESCR_EVT + + case ESP_GATTS_ADD_CHAR_EVT: { + ESP_LOGD(LOG_TAG, "[status: %s, attr_handle: 0x%.2x, service_handle: 0x%.2x, char_uuid: %s]", + gattStatusToString(evtParam->add_char.status).c_str(), + evtParam->add_char.attr_handle, + evtParam->add_char.service_handle, + BLEUUID(evtParam->add_char.char_uuid).toString().c_str()); + break; + } // ESP_GATTS_ADD_CHAR_EVT + + + // ESP_GATTS_CONF_EVT + // + // conf: + // - esp_gatt_status_t status – The status code. + // - uint16_t conn_id – The connection used. + // + case ESP_GATTS_CONF_EVT: { + ESP_LOGD(LOG_TAG, "[status: %s, conn_id: 0x%.2x]", + gattStatusToString(evtParam->conf.status).c_str(), + evtParam->conf.conn_id); + break; + } // ESP_GATTS_CONF_EVT + + + case ESP_GATTS_CONGEST_EVT: { + ESP_LOGD(LOG_TAG, "[conn_id: %d, congested: %d]", + evtParam->congest.conn_id, + evtParam->congest.congested); + break; + } // ESP_GATTS_CONGEST_EVT + + case ESP_GATTS_CONNECT_EVT: { + ESP_LOGD(LOG_TAG, "[conn_id: %d, remote_bda: %s, is_connected: %d]", + evtParam->connect.conn_id, + BLEAddress(evtParam->connect.remote_bda).toString().c_str(), + evtParam->connect.is_connected); + break; + } // ESP_GATTS_CONNECT_EVT + + case ESP_GATTS_CREATE_EVT: { + ESP_LOGD(LOG_TAG, "[status: %s, service_handle: 0x%.2x, service_id: [%s]]", + gattStatusToString(evtParam->create.status).c_str(), + evtParam->create.service_handle, + gattServiceIdToString(evtParam->create.service_id).c_str()); + break; + } // ESP_GATTS_CREATE_EVT + + case ESP_GATTS_DISCONNECT_EVT: { + ESP_LOGD(LOG_TAG, "[conn_id: %d, remote_bda: %s, is_connected: %d]", + evtParam->connect.conn_id, + BLEAddress(evtParam->connect.remote_bda).toString().c_str(), + evtParam->connect.is_connected); + break; + } // ESP_GATTS_DISCONNECT_EVT + + + // ESP_GATTS_EXEC_WRITE_EVT + // exec_write: + // - uint16_t conn_id + // - uint32_t trans_id + // - esp_bd_addr_t bda + // - uint8_t exec_write_flag + // + case ESP_GATTS_EXEC_WRITE_EVT: { + char* pWriteFlagText; + switch(evtParam->exec_write.exec_write_flag) { + case ESP_GATT_PREP_WRITE_EXEC: { + pWriteFlagText = (char*)"WRITE"; + break; + } + + case ESP_GATT_PREP_WRITE_CANCEL: { + pWriteFlagText = (char*)"CANCEL"; + break; + } + + default: + pWriteFlagText = (char*)""; + break; + } + + ESP_LOGD(LOG_TAG, "[conn_id: %d, trans_id: %d, bda: %s, exec_write_flag: 0x%.2x=%s]", + evtParam->exec_write.conn_id, + evtParam->exec_write.trans_id, + BLEAddress(evtParam->exec_write.bda).toString().c_str(), + evtParam->exec_write.exec_write_flag, + pWriteFlagText); + break; + } // ESP_GATTS_DISCONNECT_EVT + + + case ESP_GATTS_MTU_EVT: { + ESP_LOGD(LOG_TAG, "[conn_id: %d, mtu: %d]", + evtParam->mtu.conn_id, + evtParam->mtu.mtu); + break; + } // ESP_GATTS_MTU_EVT + + case ESP_GATTS_READ_EVT: { + ESP_LOGD(LOG_TAG, "[conn_id: %d, trans_id: %d, bda: %s, handle: 0x%.2x, is_long: %d, need_rsp:%d]", + evtParam->read.conn_id, + evtParam->read.trans_id, + BLEAddress(evtParam->read.bda).toString().c_str(), + evtParam->read.handle, + evtParam->read.is_long, + evtParam->read.need_rsp); + break; + } // ESP_GATTS_READ_EVT + + case ESP_GATTS_RESPONSE_EVT: { + ESP_LOGD(LOG_TAG, "[status: %s, handle: 0x%.2x]", + gattStatusToString(evtParam->rsp.status).c_str(), + evtParam->rsp.handle); + break; + } // ESP_GATTS_RESPONSE_EVT + + case ESP_GATTS_REG_EVT: { + ESP_LOGD(LOG_TAG, "[status: %s, app_id: %d]", + gattStatusToString(evtParam->reg.status).c_str(), + evtParam->reg.app_id); + break; + } // ESP_GATTS_REG_EVT + + + // ESP_GATTS_START_EVT + // + // start: + // - esp_gatt_status_t status + // - uint16_t service_handle + // + case ESP_GATTS_START_EVT: { + ESP_LOGD(LOG_TAG, "[status: %s, service_handle: 0x%.2x]", + gattStatusToString(evtParam->start.status).c_str(), + evtParam->start.service_handle); + break; + } // ESP_GATTS_START_EVT + + + // ESP_GATTS_WRITE_EVT + // + // write: + // - uint16_t conn_id – The connection id. + // - uint16_t trans_id – The transfer id. + // - esp_bd_addr_t bda – The address of the partner. + // - uint16_t handle – The attribute handle. + // - uint16_t offset – The offset of the currently received within the whole value. + // - bool need_rsp – Do we need a response? + // - bool is_prep – Is this a write prepare? If set, then this is to be considered part of the received value and not the whole value. A subsequent ESP_GATTS_EXEC_WRITE will mark the total. + // - uint16_t len – The length of the incoming value part. + // - uint8_t* value – The data for this value part. + // + case ESP_GATTS_WRITE_EVT: { + ESP_LOGD(LOG_TAG, "[conn_id: %d, trans_id: %d, bda: %s, handle: 0x%.2x, offset: %d, need_rsp: %d, is_prep: %d, len: %d]", + evtParam->write.conn_id, + evtParam->write.trans_id, + BLEAddress(evtParam->write.bda).toString().c_str(), + evtParam->write.handle, + evtParam->write.offset, + evtParam->write.need_rsp, + evtParam->write.is_prep, + evtParam->write.len); + char *pHex = buildHexData(nullptr, evtParam->write.value, evtParam->write.len); + ESP_LOGD(LOG_TAG, "[Data: %s]", pHex); + free(pHex); + break; + } // ESP_GATTS_WRITE_EVT + + default: + ESP_LOGD(LOG_TAG, "dumpGattServerEvent: *** NOT CODED ***"); + break; + } +} // dumpGattServerEvent + + +/** + * @brief Convert a BLE event type to a string. + * @param [in] eventType The event type. + * @return The event type as a string. + */ +const char* BLEUtils::eventTypeToString(esp_ble_evt_type_t eventType) { + switch(eventType) { + case ESP_BLE_EVT_CONN_ADV: + return "ESP_BLE_EVT_CONN_ADV"; + case ESP_BLE_EVT_CONN_DIR_ADV: + return "ESP_BLE_EVT_CONN_DIR_ADV"; + case ESP_BLE_EVT_DISC_ADV: + return "ESP_BLE_EVT_DISC_ADV"; + case ESP_BLE_EVT_NON_CONN_ADV: + return "ESP_BLE_EVT_NON_CONN_ADV"; + case ESP_BLE_EVT_SCAN_RSP: + return "ESP_BLE_EVT_SCAN_RSP"; + default: + ESP_LOGD(LOG_TAG, "Unknown esp_ble_evt_type_t: %d", eventType); + return "*** Unknown ***"; + } +} // eventTypeToString + + + +/** + * @brief Convert a BT GAP event type to a string representation. + * @param [in] eventType The type of event. + * @return A string representation of the event type. + */ +const char* BLEUtils::gapEventToString(uint32_t eventType) { + switch(eventType) { + case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT: + return "ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT"; + case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: + return "ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT"; + case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: + return "ESP_GAP_BLE_ADV_START_COMPLETE_EVT"; + case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT: + return "ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT"; + case ESP_GAP_BLE_SCAN_RESULT_EVT: + return "ESP_GAP_BLE_SCAN_RESULT_EVT"; + case ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT: + return "ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT"; + case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT: + return "ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT"; + case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT: + return "ESP_GAP_BLE_SCAN_START_COMPLETE_EVT"; + case ESP_GAP_BLE_AUTH_CMPL_EVT: /* Authentication complete indication. */ + return "ESP_GAP_BLE_AUTH_CMPL_EVT"; + case ESP_GAP_BLE_KEY_EVT: /* BLE key event for peer device keys */ + return "ESP_GAP_BLE_KEY_EVT"; + case ESP_GAP_BLE_SEC_REQ_EVT: /* BLE security request */ + return "ESP_GAP_BLE_SEC_REQ_EVT"; + case ESP_GAP_BLE_PASSKEY_NOTIF_EVT: /* passkey notification event */ + return "ESP_GAP_BLE_PASSKEY_NOTIF_EVT"; + case ESP_GAP_BLE_PASSKEY_REQ_EVT: /* passkey request event */ + return "ESP_GAP_BLE_PASSKEY_REQ_EVT"; + case ESP_GAP_BLE_OOB_REQ_EVT: /* OOB request event */ + return "ESP_GAP_BLE_OOB_REQ_EVT"; + case ESP_GAP_BLE_LOCAL_IR_EVT: /* BLE local IR event */ + return "ESP_GAP_BLE_LOCAL_IR_EVT"; + case ESP_GAP_BLE_LOCAL_ER_EVT: /* BLE local ER event */ + return "ESP_GAP_BLE_LOCAL_ER_EVT"; + case ESP_GAP_BLE_NC_REQ_EVT: /* Numeric Comparison request event */ + return "ESP_GAP_BLE_NC_REQ_EVT"; + case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT: /*!< When stop adv complete, the event comes */ + return "ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT"; + case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT: + return "ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT"; + default: + ESP_LOGD(LOG_TAG, "gapEventToString: Unknown event type 0x%x", eventType); + return "Unknown event type"; + } +} // gapEventToString + + +std::string BLEUtils::gattCharacteristicUUIDToString(uint32_t characteristicUUID) { + characteristicMap_t *p = g_characteristicsMappings; + while (p->name.length() > 0) { + if (p->assignedNumber == characteristicUUID) { + return p->name; + } + p++; + } + return "Unknown"; +} // gattCharacteristicUUIDToString + + +/** + * @brief Convert an esp_gatt_srvc_id_t to a string. + */ +std::string BLEUtils::gattServiceIdToString(esp_gatt_srvc_id_t srvcId) { + return gattIdToString(srvcId.id); +} // gattServiceIdToString + + +std::string BLEUtils::gattServiceToString(uint32_t serviceId) { + gattService_t* p = (gattService_t *)g_gattServices; + while (p->name.length() > 0) { + if (p->assignedNumber == serviceId) { + return p->name; + } + p++; + } + return "Unknown"; +} // gattServiceToString + + +/** + * @brief Convert a GATT status to a string. + * + * @param [in] status The status to convert. + * @return A string representation of the status. + */ +std::string BLEUtils::gattStatusToString(esp_gatt_status_t status) { + switch(status) { + case ESP_GATT_OK: + return "ESP_GATT_OK"; + case ESP_GATT_INVALID_HANDLE: + return "ESP_GATT_INVALID_HANDLE"; + case ESP_GATT_READ_NOT_PERMIT: + return "ESP_GATT_READ_NOT_PERMIT"; + case ESP_GATT_WRITE_NOT_PERMIT: + return "ESP_GATT_WRITE_NOT_PERMIT"; + case ESP_GATT_INVALID_PDU: + return "ESP_GATT_INVALID_PDU"; + case ESP_GATT_INSUF_AUTHENTICATION: + return "ESP_GATT_INSUF_AUTHENTICATION"; + case ESP_GATT_REQ_NOT_SUPPORTED: + return "ESP_GATT_REQ_NOT_SUPPORTED"; + case ESP_GATT_INVALID_OFFSET: + return "ESP_GATT_INVALID_OFFSET"; + case ESP_GATT_INSUF_AUTHORIZATION: + return "ESP_GATT_INSUF_AUTHORIZATION"; + case ESP_GATT_PREPARE_Q_FULL: + return "ESP_GATT_PREPARE_Q_FULL"; + case ESP_GATT_NOT_FOUND: + return "ESP_GATT_NOT_FOUND"; + case ESP_GATT_NOT_LONG: + return "ESP_GATT_NOT_LONG"; + case ESP_GATT_INSUF_KEY_SIZE: + return "ESP_GATT_INSUF_KEY_SIZE"; + case ESP_GATT_INVALID_ATTR_LEN: + return "ESP_GATT_INVALID_ATTR_LEN"; + case ESP_GATT_ERR_UNLIKELY: + return "ESP_GATT_ERR_UNLIKELY"; + case ESP_GATT_INSUF_ENCRYPTION: + return "ESP_GATT_INSUF_ENCRYPTION"; + case ESP_GATT_UNSUPPORT_GRP_TYPE: + return "ESP_GATT_UNSUPPORT_GRP_TYPE"; + case ESP_GATT_INSUF_RESOURCE: + return "ESP_GATT_INSUF_RESOURCE"; + case ESP_GATT_NO_RESOURCES: + return "ESP_GATT_NO_RESOURCES"; + case ESP_GATT_INTERNAL_ERROR: + return "ESP_GATT_INTERNAL_ERROR"; + case ESP_GATT_WRONG_STATE: + return "ESP_GATT_WRONG_STATE"; + case ESP_GATT_DB_FULL: + return "ESP_GATT_DB_FULL"; + case ESP_GATT_BUSY: + return "ESP_GATT_BUSY"; + case ESP_GATT_ERROR: + return "ESP_GATT_ERROR"; + case ESP_GATT_CMD_STARTED: + return "ESP_GATT_CMD_STARTED"; + case ESP_GATT_ILLEGAL_PARAMETER: + return "ESP_GATT_ILLEGAL_PARAMETER"; + case ESP_GATT_PENDING: + return "ESP_GATT_PENDING"; + case ESP_GATT_AUTH_FAIL: + return "ESP_GATT_AUTH_FAIL"; + case ESP_GATT_MORE: + return "ESP_GATT_MORE"; + case ESP_GATT_INVALID_CFG: + return "ESP_GATT_INVALID_CFG"; + case ESP_GATT_SERVICE_STARTED: + return "ESP_GATT_SERVICE_STARTED"; + case ESP_GATT_ENCRYPED_NO_MITM: + return "ESP_GATT_ENCRYPED_NO_MITM"; + case ESP_GATT_NOT_ENCRYPTED: + return "ESP_GATT_NOT_ENCRYPTED"; + case ESP_GATT_CONGESTED: + return "ESP_GATT_CONGESTED"; + case ESP_GATT_DUP_REG: + return "ESP_GATT_DUP_REG"; + case ESP_GATT_ALREADY_OPEN: + return "ESP_GATT_ALREADY_OPEN"; + case ESP_GATT_CANCEL: + return "ESP_GATT_CANCEL"; + case ESP_GATT_CCC_CFG_ERR: + return "ESP_GATT_CCC_CFG_ERR"; + case ESP_GATT_PRC_IN_PROGRESS: + return "ESP_GATT_PRC_IN_PROGRESS"; + default: + return "Unknown"; + } +} // gattStatusToString + + +/** + * @brief convert a GAP search event to a string. + * @param [in] searchEvt + * @return The search event type as a string. + */ +const char* BLEUtils::searchEventTypeToString(esp_gap_search_evt_t searchEvt) { + switch(searchEvt) { + case ESP_GAP_SEARCH_INQ_RES_EVT: + return "ESP_GAP_SEARCH_INQ_RES_EVT"; + case ESP_GAP_SEARCH_INQ_CMPL_EVT: + return "ESP_GAP_SEARCH_INQ_CMPL_EVT"; + case ESP_GAP_SEARCH_DISC_RES_EVT: + return "ESP_GAP_SEARCH_DISC_RES_EVT"; + case ESP_GAP_SEARCH_DISC_BLE_RES_EVT: + return "ESP_GAP_SEARCH_DISC_BLE_RES_EVT"; + case ESP_GAP_SEARCH_DISC_CMPL_EVT: + return "ESP_GAP_SEARCH_DISC_CMPL_EVT"; + case ESP_GAP_SEARCH_DI_DISC_CMPL_EVT: + return "ESP_GAP_SEARCH_DI_DISC_CMPL_EVT"; + case ESP_GAP_SEARCH_SEARCH_CANCEL_CMPL_EVT: + return "ESP_GAP_SEARCH_SEARCH_CANCEL_CMPL_EVT"; + default: + ESP_LOGD(LOG_TAG, "Unknown event type: 0x%x", searchEvt); + return "Unknown event type"; + } +} // searchEventTypeToString + +#endif // CONFIG_BT_ENABLED diff --git a/src/BLEUtils.h b/src/BLEUtils.h new file mode 100644 index 0000000..28c7a7e --- /dev/null +++ b/src/BLEUtils.h @@ -0,0 +1,60 @@ +/* + * BLEUtils.h + * + * Created on: Mar 25, 2017 + * Author: kolban + */ + +#ifndef COMPONENTS_CPP_UTILS_BLEUTILS_H_ +#define COMPONENTS_CPP_UTILS_BLEUTILS_H_ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) +#include // ESP32 BLE +#include // ESP32 BLE +#include // ESP32 BLE +#include +#include "BLEClient.h" + +/** + * @brief A set of general %BLE utilities. + */ +class BLEUtils { +public: + static const char* advTypeToString(uint8_t advType); + static esp_gatt_id_t buildGattId(esp_bt_uuid_t uuid, uint8_t inst_id=0); + + static esp_gatt_srvc_id_t buildGattSrvcId(esp_gatt_id_t gattId, bool is_primary=true); + static std::string characteristicPropertiesToString(esp_gatt_char_prop_t prop); + static char* buildHexData(uint8_t *target, uint8_t *source, uint8_t length); + static BLEClient* findByConnId(uint16_t conn_id); + static BLEClient* findByAddress(BLEAddress address); + static std::string gattClientEventTypeToString(esp_gattc_cb_event_t eventType); + static std::string gattServerEventTypeToString(esp_gatts_cb_event_t eventType); + static std::string gattServiceIdToString(esp_gatt_srvc_id_t srvcId); + static std::string gattStatusToString(esp_gatt_status_t status); + static std::string gattServiceToString(uint32_t serviceId); + static std::string gattCloseReasonToString(esp_gatt_conn_reason_t reason); + static void registerByAddress(BLEAddress address, BLEClient* pDevice); + static void registerByConnId(uint16_t conn_id, BLEClient* pDevice); + static std::string gattCharacteristicUUIDToString(uint32_t characteristicUUID); + static std::string buildPrintData(uint8_t* source, size_t length); + static void dumpGattClientEvent( + esp_gattc_cb_event_t event, + esp_gatt_if_t gattc_if, + esp_ble_gattc_cb_param_t* evtParam); + static void dumpGattServerEvent( + esp_gatts_cb_event_t event, + esp_gatt_if_t gatts_if, + esp_ble_gatts_cb_param_t* evtParam); + static const char* devTypeToString(esp_bt_dev_type_t type); + static void dumpGapEvent( + esp_gap_ble_cb_event_t event, + esp_ble_gap_cb_param_t* param); + static const char* gapEventToString(uint32_t eventType); + static const char* searchEventTypeToString(esp_gap_search_evt_t searchEvt); + static const char* addressTypeToString(esp_ble_addr_type_t type); + static const char *eventTypeToString(esp_ble_evt_type_t eventType); +}; + +#endif // CONFIG_BT_ENABLED +#endif /* COMPONENTS_CPP_UTILS_BLEUTILS_H_ */ diff --git a/src/BLEValue.cpp b/src/BLEValue.cpp new file mode 100644 index 0000000..1989993 --- /dev/null +++ b/src/BLEValue.cpp @@ -0,0 +1,116 @@ +/* + * BLEValue.cpp + * + * Created on: Jul 17, 2017 + * Author: kolban + */ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) + +#include + +#include "BLEValue.h" + +static const char* LOG_TAG="BLEValue"; + +BLEValue::BLEValue() { + m_accumulation = ""; + m_value = ""; + m_readOffset = 0; +} // BLEValue + + +/** + * @brief Add a message part to the accumulation. + * The accumulation is a growing set of data that is added to until a commit or cancel. + * @param [in] part A message part being added. + */ +void BLEValue::addPart(std::string part) { + ESP_LOGD(LOG_TAG, ">> addPart: length=%d", part.length()); + m_accumulation += part; +} // addPart + + +/** + * @brief Add a message part to the accumulation. + * The accumulation is a growing set of data that is added to until a commit or cancel. + * @param [in] pData A message part being added. + * @param [in] length The number of bytes being added. + */ +void BLEValue::addPart(uint8_t* pData, size_t length) { + ESP_LOGD(LOG_TAG, ">> addPart: length=%d", length); + m_accumulation += std::string((char *)pData, length); +} // addPart + + +/** + * @brief Cancel the current accumulation. + */ +void BLEValue::cancel() { + ESP_LOGD(LOG_TAG, ">> cancel"); + m_accumulation = ""; + m_readOffset = 0; +} // cancel + + +/** + * @brief Commit the current accumulation. + * When writing a value, we may find that we write it in "parts" meaning that the writes come in in pieces + * of the overall message. After the last part has been received, we may perform a commit which means that + * we now have the complete message and commit the change as a unit. + */ +void BLEValue::commit() { + ESP_LOGD(LOG_TAG, ">> commit"); + // If there is nothing to commit, do nothing. + if (m_accumulation.length() == 0) { + return; + } + setValue(m_accumulation); + m_accumulation = ""; + m_readOffset = 0; +} // commit + + +/** + * @brief Get the read offset. + * @return The read offset into the read. + */ +uint16_t BLEValue::getReadOffset() { + return m_readOffset; +} // getReadOffset + + +/** + * @brief Get the current value. + */ +std::string BLEValue::getValue() { + return m_value; +} // getValue + + +/** + * @brief Set the read offset + * @param [in] readOffset The offset into the read. + */ +void BLEValue::setReadOffset(uint16_t readOffset) { + m_readOffset = readOffset; +} // setReadOffset + + +/** + * @brief Set the current value. + */ +void BLEValue::setValue(std::string value) { + m_value = value; +} // setValue + + +/** + * @brief Set the current value. + * @param [in] pData The data for the current value. + * @param [in] The length of the new current value. + */ +void BLEValue::setValue(uint8_t* pData, size_t length) { + m_value = std::string((char*)pData, length); +} // setValue +#endif // CONFIG_BT_ENABLED diff --git a/src/BLEValue.h b/src/BLEValue.h new file mode 100644 index 0000000..a292c6e --- /dev/null +++ b/src/BLEValue.h @@ -0,0 +1,36 @@ +/* + * BLEValue.h + * + * Created on: Jul 17, 2017 + * Author: kolban + */ + +#ifndef COMPONENTS_CPP_UTILS_BLEVALUE_H_ +#define COMPONENTS_CPP_UTILS_BLEVALUE_H_ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) +#include + +/** + * @brief The model of a %BLE value. + */ +class BLEValue { +public: + BLEValue(); + void addPart(std::string part); + void addPart(uint8_t* pData, size_t length); + void cancel(); + void commit(); + uint16_t getReadOffset(); + std::string getValue(); + void setReadOffset(uint16_t readOffset); + void setValue(std::string value); + void setValue(uint8_t* pData, size_t length); + +private: + std::string m_accumulation; + uint16_t m_readOffset; + std::string m_value; +}; +#endif // CONFIG_BT_ENABLED +#endif /* COMPONENTS_CPP_UTILS_BLEVALUE_H_ */ diff --git a/src/FreeRTOS.cpp b/src/FreeRTOS.cpp new file mode 100644 index 0000000..663128d --- /dev/null +++ b/src/FreeRTOS.cpp @@ -0,0 +1,165 @@ +/* + * FreeRTOS.cpp + * + * Created on: Feb 24, 2017 + * Author: kolban + */ +#include +#include +#include +#include +#include +#include "FreeRTOS.h" +#include +#include "sdkconfig.h" + +static const char* LOG_TAG = "FreeRTOS"; + +/** + * Sleep for the specified number of milliseconds. + * @param[in] ms The period in milliseconds for which to sleep. + */ +void FreeRTOS::sleep(uint32_t ms) { + ::vTaskDelay(ms/portTICK_PERIOD_MS); +} // sleep + + +/** + * Start a new task. + * @param[in] task The function pointer to the function to be run in the task. + * @param[in] taskName A string identifier for the task. + * @param[in] param An optional parameter to be passed to the started task. + * @param[in] stackSize An optional paremeter supplying the size of the stack in which to run the task. + */ +void FreeRTOS::startTask(void task(void*), std::string taskName, void *param, int stackSize) { + ::xTaskCreate(task, taskName.data(), stackSize, param, 5, NULL); +} // startTask + + +/** + * Delete the task. + * @param[in] pTask An optional handle to the task to be deleted. If not supplied the calling task will be deleted. + */ +void FreeRTOS::deleteTask(TaskHandle_t pTask) { + ::vTaskDelete(pTask); +} // deleteTask + + +/** + * Get the time in milliseconds since the %FreeRTOS scheduler started. + * @return The time in milliseconds since the %FreeRTOS scheduler started. + */ +uint32_t FreeRTOS::getTimeSinceStart() { + return (uint32_t)(xTaskGetTickCount()*portTICK_PERIOD_MS); +} // getTimeSinceStart + +/* + * public: + Semaphore(std::string = ""); + ~Semaphore(); + void give(); + void take(std::string owner=""); + void take(uint32_t timeoutMs, std::string owner=""); + private: + SemaphoreHandle_t m_semaphore; + std::string m_name; + std::string m_owner; + }; + * + */ + +/** + * @brief Wait for a semaphore to be released by trying to take it and + * then releasing it again. + * @param [in] owner A debug tag. + * @return The value associated with the semaphore. + */ +uint32_t FreeRTOS::Semaphore::wait(std::string owner) { + ESP_LOGV(LOG_TAG, "Semaphore waiting: %s for %s", toString().c_str(), owner.c_str()); + xSemaphoreTake(m_semaphore, portMAX_DELAY); + m_owner = owner; + xSemaphoreGive(m_semaphore); + ESP_LOGV(LOG_TAG, "Semaphore released: %s", toString().c_str()); + m_owner = ""; + return m_value; +} // wait + +FreeRTOS::Semaphore::Semaphore(std::string name) { + m_semaphore = xSemaphoreCreateMutex(); + m_name = name; + m_owner = ""; + m_value = 0; +} + +FreeRTOS::Semaphore::~Semaphore() { + vSemaphoreDelete(m_semaphore); +} + + +/** + * @brief Give a semaphore. + * The Semaphore is given. + */ +void FreeRTOS::Semaphore::give() { + xSemaphoreGive(m_semaphore); + ESP_LOGV(LOG_TAG, "Semaphore giving: %s", toString().c_str()); + m_owner = ""; +} // Semaphore::give + + +/** + * @brief Give a semaphore. + * The Semaphore is given with an associated value. + * @param [in] value The value to associate with the semaphore. + */ +void FreeRTOS::Semaphore::give(uint32_t value) { + m_value = value; + give(); +} + + +/** + * @brief Give a semaphore from an ISR. + */ +void FreeRTOS::Semaphore::giveFromISR() { + BaseType_t higherPriorityTaskWoken; + xSemaphoreGiveFromISR(m_semaphore, &higherPriorityTaskWoken); +} // giveFromISR + + +/** + * @brief Take a semaphore. + * Take a semaphore and wait indefinitely. + */ +void FreeRTOS::Semaphore::take(std::string owner) +{ + + ESP_LOGV(LOG_TAG, "Semaphore taking: %s for %s", toString().c_str(), owner.c_str()); + xSemaphoreTake(m_semaphore, portMAX_DELAY); + m_owner = owner; + ESP_LOGV(LOG_TAG, "Semaphore taken: %s", toString().c_str()); +} // Semaphore::take + + +/** + * @brief Take a semaphore. + * Take a semaphore but return if we haven't obtained it in the given period of milliseconds. + * @param [in] timeoutMs Timeout in milliseconds. + */ +void FreeRTOS::Semaphore::take(uint32_t timeoutMs, std::string owner) { + ESP_LOGV(LOG_TAG, "Semaphore taking: %s for %s", toString().c_str(), owner.c_str()); + m_owner = owner; + xSemaphoreTake(m_semaphore, timeoutMs/portTICK_PERIOD_MS); + ESP_LOGV(LOG_TAG, "Semaphore taken: %s", toString().c_str()); +} // Semaphore::take + +std::string FreeRTOS::Semaphore::toString() { + std::stringstream stringStream; + stringStream << "name: "<< m_name << " (0x" << std::hex << std::setfill('0') << (uint32_t)m_semaphore << "), owner: " << m_owner; + return stringStream.str(); +} + +void FreeRTOS::Semaphore::setName(std::string name) { + m_name = name; +} + diff --git a/src/FreeRTOS.h b/src/FreeRTOS.h new file mode 100644 index 0000000..320f4cc --- /dev/null +++ b/src/FreeRTOS.h @@ -0,0 +1,49 @@ +/* + * FreeRTOS.h + * + * Created on: Feb 24, 2017 + * Author: kolban + */ + +#ifndef MAIN_FREERTOS_H_ +#define MAIN_FREERTOS_H_ +#include +#include + +#include +#include +#include + + +/** + * @brief Interface to %FreeRTOS functions. + */ +class FreeRTOS { +public: + static void sleep(uint32_t ms); + static void startTask(void task(void *), std::string taskName, void *param=nullptr, int stackSize = 2048); + static void deleteTask(TaskHandle_t pTask = nullptr); + + static uint32_t getTimeSinceStart(); + + class Semaphore { + public: + Semaphore(std::string owner = ""); + ~Semaphore(); + void give(); + void giveFromISR(); + void give(uint32_t value); + void setName(std::string name); + void take(std::string owner=""); + void take(uint32_t timeoutMs, std::string owner=""); + uint32_t wait(std::string owner=""); + std::string toString(); + private: + SemaphoreHandle_t m_semaphore; + std::string m_name; + std::string m_owner; + uint32_t m_value; + }; +}; + +#endif /* MAIN_FREERTOS_H_ */ diff --git a/src/GeneralUtils.cpp b/src/GeneralUtils.cpp new file mode 100644 index 0000000..4237b14 --- /dev/null +++ b/src/GeneralUtils.cpp @@ -0,0 +1,388 @@ +/* + * GeneralUtils.cpp + * + * Created on: May 20, 2017 + * Author: kolban + */ + +#include "GeneralUtils.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const char* LOG_TAG = "GeneralUtils"; + +static const char kBase64Alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + +GeneralUtils::GeneralUtils() { + // TODO Auto-generated constructor stub + +} + +GeneralUtils::~GeneralUtils() { + // TODO Auto-generated destructor stub +} + +static int base64EncodedLength(size_t length) { + return (length + 2 - ((length + 2) % 3)) / 3 * 4; +} // base64EncodedLength + + +static int base64EncodedLength(const std::string &in) { + return base64EncodedLength(in.length()); +} // base64EncodedLength + + +static void a3_to_a4(unsigned char * a4, unsigned char * a3) { + a4[0] = (a3[0] & 0xfc) >> 2; + a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4); + a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6); + a4[3] = (a3[2] & 0x3f); +} // a3_to_a4 + + +static void a4_to_a3(unsigned char * a3, unsigned char * a4) { + a3[0] = (a4[0] << 2) + ((a4[1] & 0x30) >> 4); + a3[1] = ((a4[1] & 0xf) << 4) + ((a4[2] & 0x3c) >> 2); + a3[2] = ((a4[2] & 0x3) << 6) + a4[3]; +} // a4_to_a3 + + +/** + * @brief Encode a string into base 64. + * @param [in] in + * @param [out] out + */ +bool GeneralUtils::base64Encode(const std::string &in, std::string *out) { + int i = 0, j = 0; + size_t enc_len = 0; + unsigned char a3[3]; + unsigned char a4[4]; + + out->resize(base64EncodedLength(in)); + + int input_len = in.size(); + std::string::const_iterator input = in.begin(); + + while (input_len--) { + a3[i++] = *(input++); + if (i == 3) { + a3_to_a4(a4, a3); + + for (i = 0; i < 4; i++) { + (*out)[enc_len++] = kBase64Alphabet[a4[i]]; + } + + i = 0; + } + } + + if (i) { + for (j = i; j < 3; j++) { + a3[j] = '\0'; + } + + a3_to_a4(a4, a3); + + for (j = 0; j < i + 1; j++) { + (*out)[enc_len++] = kBase64Alphabet[a4[j]]; + } + + while ((i++ < 3)) { + (*out)[enc_len++] = '='; + } + } + + return (enc_len == out->size()); +} // base64Encode + + +static int DecodedLength(const std::string &in) { + int numEq = 0; + int n = in.size(); + + for (std::string::const_reverse_iterator it = in.rbegin(); *it == '='; ++it) { + ++numEq; + } + return ((6 * n) / 8) - numEq; +} // DecodedLength + + +static unsigned char b64_lookup(unsigned char c) { + if(c >='A' && c <='Z') return c - 'A'; + if(c >='a' && c <='z') return c - 71; + if(c >='0' && c <='9') return c + 4; + if(c == '+') return 62; + if(c == '/') return 63; + return 255; +}; // b64_lookup + + +/** + * @brief Decode a chunk of data that is base64 encoded. + * @param [in] in The string to be decoded. + * @param [out] out The resulting data. + */ +bool GeneralUtils::base64Decode(const std::string &in, std::string *out) { + int i = 0, j = 0; + size_t dec_len = 0; + unsigned char a3[3]; + unsigned char a4[4]; + + int input_len = in.size(); + std::string::const_iterator input = in.begin(); + + out->resize(DecodedLength(in)); + + while (input_len--) { + if (*input == '=') { + break; + } + + a4[i++] = *(input++); + if (i == 4) { + for (i = 0; i <4; i++) { + a4[i] = b64_lookup(a4[i]); + } + + a4_to_a3(a3,a4); + + for (i = 0; i < 3; i++) { + (*out)[dec_len++] = a3[i]; + } + + i = 0; + } + } + + if (i) { + for (j = i; j < 4; j++) { + a4[j] = '\0'; + } + + for (j = 0; j < 4; j++) { + a4[j] = b64_lookup(a4[j]); + } + + a4_to_a3(a3,a4); + + for (j = 0; j < i - 1; j++) { + (*out)[dec_len++] = a3[j]; + } + } + + return (dec_len == out->size()); + } // base64Decode + +/* +void GeneralUtils::hexDump(uint8_t* pData, uint32_t length) { + uint32_t index=0; + std::stringstream ascii; + std::stringstream hex; + char asciiBuf[80]; + char hexBuf[80]; + hex.str(""); + ascii.str(""); + while(index < length) { + hex << std::setfill('0') << std::setw(2) << std::hex << (int)pData[index] << ' '; + if (std::isprint(pData[index])) { + ascii << pData[index]; + } else { + ascii << '.'; + } + index++; + if (index % 16 == 0) { + strcpy(hexBuf, hex.str().c_str()); + strcpy(asciiBuf, ascii.str().c_str()); + ESP_LOGD(tag, "%s %s", hexBuf, asciiBuf); + hex.str(""); + ascii.str(""); + } + } + if (index %16 != 0) { + while(index % 16 != 0) { + hex << " "; + index++; + } + strcpy(hexBuf, hex.str().c_str()); + strcpy(asciiBuf, ascii.str().c_str()); + ESP_LOGD(tag, "%s %s", hexBuf, asciiBuf); + //ESP_LOGD(tag, "%s %s", hex.str().c_str(), ascii.str().c_str()); + } + FreeRTOS::sleep(1000); +} +*/ + +/* +void GeneralUtils::hexDump(uint8_t* pData, uint32_t length) { + uint32_t index=0; + static std::stringstream ascii; + static std::stringstream hex; + hex.str(""); + ascii.str(""); + while(index < length) { + hex << std::setfill('0') << std::setw(2) << std::hex << (int)pData[index] << ' '; + if (std::isprint(pData[index])) { + ascii << pData[index]; + } else { + ascii << '.'; + } + index++; + if (index % 16 == 0) { + ESP_LOGD(tag, "%s %s", hex.str().c_str(), ascii.str().c_str()); + hex.str(""); + ascii.str(""); + } + } + if (index %16 != 0) { + while(index % 16 != 0) { + hex << " "; + index++; + } + ESP_LOGD(tag, "%s %s", hex.str().c_str(), ascii.str().c_str()); + } + FreeRTOS::sleep(1000); +} +*/ + +/** + * @brief Dump a representation of binary data to the console. + * + * @param [in] pData Pointer to the start of data to be logged. + * @param [in] length Length of the data (in bytes) to be logged. + * @return N/A. + */ +void GeneralUtils::hexDump(uint8_t* pData, uint32_t length) { + char ascii[80]; + char hex[80]; + char tempBuf[80]; + uint32_t lineNumber = 0; + + ESP_LOGD(LOG_TAG, " 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f ----------------"); + strcpy(ascii, ""); + strcpy(hex, ""); + uint32_t index=0; + while(index < length) { + sprintf(tempBuf, "%.2x ", pData[index]); + strcat(hex, tempBuf); + if (isprint(pData[index])) { + sprintf(tempBuf, "%c", pData[index]); + } else { + sprintf(tempBuf, "."); + } + strcat(ascii, tempBuf); + index++; + if (index % 16 == 0) { + ESP_LOGD(LOG_TAG, "%.4x %s %s", lineNumber*16, hex, ascii); + strcpy(ascii, ""); + strcpy(hex, ""); + lineNumber++; + } + } + if (index %16 != 0) { + while(index % 16 != 0) { + strcat(hex, " "); + index++; + } + ESP_LOGD(LOG_TAG, "%.4x %s %s", lineNumber*16, hex, ascii); + } +} // hexDump + +/** + * @brief Convert an IP address to string. + * @param ip The 4 byte IP address. + * @return A string representation of the IP address. + */ +std::string GeneralUtils::ipToString(uint8_t *ip) { + std::stringstream s; + s << (int)ip[0] << '.' << (int)ip[1] << '.' << (int)ip[2] << '.' << (int)ip[3]; + return s.str(); +} // ipToString + + +/** + * @brief Convert an ESP error code to a string. + * @param [in] errCode The errCode to be converted. + * @return A string representation of the error code. + */ +const char* GeneralUtils::errorToString(esp_err_t errCode) { + switch(errCode) { + case ESP_OK: + return "OK"; + case ESP_FAIL: + return "Fail"; + case ESP_ERR_NO_MEM: + return "No memory"; + case ESP_ERR_INVALID_ARG: + return "Invalid argument"; + case ESP_ERR_INVALID_SIZE: + return "Invalid state"; + case ESP_ERR_INVALID_STATE: + return "Invalid state"; + case ESP_ERR_NOT_FOUND: + return "Not found"; + case ESP_ERR_NOT_SUPPORTED: + return "Not supported"; + case ESP_ERR_TIMEOUT: + return "Timeout"; + case ESP_ERR_NVS_NOT_INITIALIZED: + return "ESP_ERR_NVS_NOT_INITIALIZED"; + case ESP_ERR_NVS_NOT_FOUND: + return "ESP_ERR_NVS_NOT_FOUND"; + case ESP_ERR_NVS_TYPE_MISMATCH: + return "ESP_ERR_NVS_TYPE_MISMATCH"; + case ESP_ERR_NVS_READ_ONLY: + return "ESP_ERR_NVS_READ_ONLY"; + case ESP_ERR_NVS_NOT_ENOUGH_SPACE: + return "ESP_ERR_NVS_NOT_ENOUGH_SPACE"; + case ESP_ERR_NVS_INVALID_NAME: + return "ESP_ERR_NVS_INVALID_NAME"; + case ESP_ERR_NVS_INVALID_HANDLE: + return "ESP_ERR_NVS_INVALID_HANDLE"; + case ESP_ERR_NVS_REMOVE_FAILED: + return "ESP_ERR_NVS_REMOVE_FAILED"; + case ESP_ERR_NVS_KEY_TOO_LONG: + return "ESP_ERR_NVS_KEY_TOO_LONG"; + case ESP_ERR_NVS_PAGE_FULL: + return "ESP_ERR_NVS_PAGE_FULL"; + case ESP_ERR_NVS_INVALID_STATE: + return "ESP_ERR_NVS_INVALID_STATE"; + case ESP_ERR_NVS_INVALID_LENGTH: + return "ESP_ERR_NVS_INVALID_LENGTH"; + case ESP_ERR_WIFI_NOT_INIT: + return "ESP_ERR_WIFI_NOT_INIT"; + //case ESP_ERR_WIFI_NOT_START: + // return "ESP_ERR_WIFI_NOT_START"; + case ESP_ERR_WIFI_IF: + return "ESP_ERR_WIFI_IF"; + case ESP_ERR_WIFI_MODE: + return "ESP_ERR_WIFI_MODE"; + case ESP_ERR_WIFI_STATE: + return "ESP_ERR_WIFI_STATE"; + case ESP_ERR_WIFI_CONN: + return "ESP_ERR_WIFI_CONN"; + case ESP_ERR_WIFI_NVS: + return "ESP_ERR_WIFI_NVS"; + case ESP_ERR_WIFI_MAC: + return "ESP_ERR_WIFI_MAC"; + case ESP_ERR_WIFI_SSID: + return "ESP_ERR_WIFI_SSID"; + case ESP_ERR_WIFI_PASSWORD: + return "ESP_ERR_WIFI_PASSWORD"; + case ESP_ERR_WIFI_TIMEOUT: + return "ESP_ERR_WIFI_TIMEOUT"; + case ESP_ERR_WIFI_WAKE_FAIL: + return "ESP_ERR_WIFI_WAKE_FAIL"; + } + return "Unknown ESP_ERR error"; +} // errorToString + diff --git a/src/GeneralUtils.h b/src/GeneralUtils.h new file mode 100644 index 0000000..152abca --- /dev/null +++ b/src/GeneralUtils.h @@ -0,0 +1,28 @@ +/* + * GeneralUtils.h + * + * Created on: May 20, 2017 + * Author: kolban + */ + +#ifndef COMPONENTS_CPP_UTILS_GENERALUTILS_H_ +#define COMPONENTS_CPP_UTILS_GENERALUTILS_H_ +#include +#include +#include + +/** + * @brief General utilities. + */ +class GeneralUtils { +public: + GeneralUtils(); + virtual ~GeneralUtils(); + static void hexDump(uint8_t *pData, uint32_t length); + static std::string ipToString(uint8_t *ip); + static bool base64Encode(const std::string &in, std::string *out); + static bool base64Decode(const std::string &in, std::string *out); + static const char *errorToString(esp_err_t errCode); +}; + +#endif /* COMPONENTS_CPP_UTILS_GENERALUTILS_H_ */ -- cgit v1.2.3