├── Insta_BLE.ino ├── README.md ├── debug.cfg ├── debug_custom.json ├── edited_esp_lib_files ├── BLEAdvertising.cpp ├── BLEAdvertising.h ├── BLEDescriptor.h ├── BLEDevice.cpp └── BLEDevice.h └── esp32.svd /Insta_BLE.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Author: Patrick Chwalek (09/22/2023) 3 | Description: Example code used to control Insta360 X3 and RS 1-inch cameras 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define SERVICE_UUID "ce80" 13 | #define CHARACTERISTIC_UUID1 "ce81" 14 | #define CHARACTERISTIC_UUID2 "ce82" 15 | #define CHARACTERISTIC_UUID3 "ce83" 16 | 17 | #define SECONDARY_SERVICE_UUID "0000D0FF-3C17-D293-8E48-14FE2E4DA212" 18 | #define SECONDARY_CHARACTERISTIC_UUID1 "ffd1" 19 | #define SECONDARY_CHARACTERISTIC_UUID2 "ffd2" 20 | #define SECONDARY_CHARACTERISTIC_UUID3 "ffd3" 21 | #define SECONDARY_CHARACTERISTIC_UUID4 "ffd4" 22 | #define SECONDARY_CHARACTERISTIC_UUID5 "ffd5" 23 | #define SECONDARY_CHARACTERISTIC_UUID8 "ffd8" 24 | #define SECONDARY_CHARACTERISTIC_UUID9 "fff1" 25 | #define SECONDARY_CHARACTERISTIC_UUID10 "fff2" 26 | #define SECONDARY_CHARACTERISTIC_UUID11 "ffe0" 27 | 28 | #define CAPTURE_DELAY 120000 29 | 30 | uint32_t data_32; 31 | uint16_t data_16; 32 | uint8_t data_8[30]; 33 | 34 | BLEServer *pServer = NULL; 35 | BLE2902 *pDescriptor2902; 36 | 37 | bool deviceConnected = false; 38 | bool oldDeviceConnected = false; 39 | 40 | BLECharacteristic *pCharacteristicRx; 41 | 42 | unsigned long myTime; 43 | 44 | uint8_t manuf_data[30]; 45 | 46 | class MyServerCallbacks : public BLEServerCallbacks { 47 | void onConnect(BLEServer *pServer) { 48 | deviceConnected = true; 49 | myTime = millis(); 50 | BLEDevice::startAdvertising(); 51 | }; 52 | 53 | void onDisconnect(BLEServer *pServer) { deviceConnected = false; } 54 | }; 55 | 56 | void setup() { 57 | Serial.begin(115200); 58 | Serial.println("Starting BLE work!"); 59 | 60 | BLEDevice::init("Insta360 GPS Remote"); 61 | pServer = BLEDevice::createServer(); 62 | pServer->setCallbacks(new MyServerCallbacks()); 63 | 64 | BLEService *pService = pServer->createService(SERVICE_UUID); 65 | BLECharacteristic *pCharacteristic1 = pService->createCharacteristic( 66 | CHARACTERISTIC_UUID1, BLECharacteristic::PROPERTY_WRITE); 67 | 68 | pCharacteristicRx = pService->createCharacteristic( 69 | CHARACTERISTIC_UUID2, BLECharacteristic::PROPERTY_NOTIFY); 70 | pDescriptor2902 = new BLE2902(); 71 | pDescriptor2902->setNotifications(true); 72 | pDescriptor2902->setIndications(true); 73 | pCharacteristicRx->addDescriptor(pDescriptor2902); 74 | data_8[0] = 0; 75 | pCharacteristicRx->setValue(data_8, 1); 76 | 77 | BLECharacteristic *pCharacteristic3 = pService->createCharacteristic( 78 | CHARACTERISTIC_UUID3, BLECharacteristic::PROPERTY_READ); 79 | data_16 = 0x0201; 80 | pCharacteristic3->setValue(data_16); 81 | 82 | BLEService *pService2 = pServer->createService(SECONDARY_SERVICE_UUID); 83 | BLECharacteristic *secondary_pCharacteristic1 = 84 | pService2->createCharacteristic(SECONDARY_CHARACTERISTIC_UUID1, 85 | BLECharacteristic::PROPERTY_WRITE); 86 | 87 | BLECharacteristic *secondary_pCharacteristic2 = 88 | pService2->createCharacteristic(SECONDARY_CHARACTERISTIC_UUID2, 89 | BLECharacteristic::PROPERTY_READ); 90 | 91 | BLECharacteristic *secondary_pCharacteristic3 = 92 | pService2->createCharacteristic(SECONDARY_CHARACTERISTIC_UUID3, 93 | BLECharacteristic::PROPERTY_READ); 94 | data_32 = 0x301e9001; 95 | secondary_pCharacteristic3->setValue(data_32); 96 | 97 | BLECharacteristic *secondary_pCharacteristic4 = 98 | pService2->createCharacteristic(SECONDARY_CHARACTERISTIC_UUID4, 99 | BLECharacteristic::PROPERTY_READ); 100 | 101 | data_32 = 0x18002001; 102 | secondary_pCharacteristic4->setValue(data_32); 103 | 104 | BLECharacteristic *secondary_pCharacteristic5 = 105 | pService2->createCharacteristic(SECONDARY_CHARACTERISTIC_UUID5, 106 | BLECharacteristic::PROPERTY_READ); 107 | 108 | BLECharacteristic *secondary_pCharacteristic8 = 109 | pService2->createCharacteristic(SECONDARY_CHARACTERISTIC_UUID8, 110 | BLECharacteristic::PROPERTY_WRITE); 111 | 112 | BLECharacteristic *secondary_pCharacteristic9 = 113 | pService2->createCharacteristic(SECONDARY_CHARACTERISTIC_UUID9, 114 | BLECharacteristic::PROPERTY_READ); 115 | 116 | BLECharacteristic *secondary_pCharacteristic10 = 117 | pService2->createCharacteristic(SECONDARY_CHARACTERISTIC_UUID10, 118 | BLECharacteristic::PROPERTY_WRITE); 119 | 120 | BLECharacteristic *secondary_pCharacteristic11 = 121 | pService2->createCharacteristic(SECONDARY_CHARACTERISTIC_UUID11, 122 | BLECharacteristic::PROPERTY_READ); 123 | 124 | pService->start(); 125 | pService2->start(); 126 | // BLEAdvertising *pAdvertising = pServer->getAdvertising(); // this still 127 | // is working for backward compatibility 128 | BLEAdvertising *pAdvertising = BLEDevice::getAdvertising(); 129 | pAdvertising->addServiceUUID(SERVICE_UUID); 130 | pAdvertising->addServiceUUID(SECONDARY_SERVICE_UUID); 131 | 132 | pAdvertising->setScanResponse(true); 133 | pAdvertising->setMinPreferred( 134 | 0x06); // functions that help with iPhone connections issue 135 | pAdvertising->setMinPreferred(0x12); 136 | 137 | BLEDevice::startAdvertising(); 138 | Serial.println( 139 | "Characteristic defined! Now you can read it in your phone!"); 140 | 141 | /* set the manufacturing data for wakeon packet */ 142 | manuf_data[0] = 0x4c; 143 | manuf_data[1] = 0x00; 144 | manuf_data[2] = 0x02; 145 | manuf_data[3] = 0x15; 146 | manuf_data[4] = 0x09; 147 | manuf_data[5] = 0x4f; 148 | manuf_data[6] = 0x52; 149 | manuf_data[7] = 0x42; 150 | manuf_data[8] = 0x49; 151 | manuf_data[9] = 0x54; 152 | manuf_data[10] = 0x09; 153 | manuf_data[11] = 0xff; 154 | manuf_data[12] = 0x0f; 155 | manuf_data[13] = 0x00; 156 | /* note: see powerOnPrevConnectedCameras() for bytes 14-19 */ 157 | manuf_data[20] = 0x00; 158 | manuf_data[21] = 0x00; 159 | manuf_data[22] = 0x00; 160 | manuf_data[23] = 0x00; 161 | manuf_data[24] = 0xe4; 162 | manuf_data[25] = 0x01; 163 | } 164 | 165 | void loop() { 166 | // notify changed value 167 | if (deviceConnected) { 168 | delay(10); // bluetooth stack will go into congestion, if too many packets 169 | } 170 | 171 | // disconnecting 172 | if (!deviceConnected && oldDeviceConnected) { 173 | delay(500); // give the bluetooth stack the chance to get things ready 174 | pServer->startAdvertising(); // restart advertising 175 | Serial.println("start advertising"); 176 | oldDeviceConnected = deviceConnected; 177 | } 178 | // connecting 179 | if (deviceConnected && !oldDeviceConnected) { 180 | // do stuff here on connecting 181 | Serial.println("connecting"); 182 | oldDeviceConnected = deviceConnected; 183 | } 184 | 185 | /* this loop just goes through all the features */ 186 | if (((millis() - myTime) > CAPTURE_DELAY)) { 187 | Serial.println("capture"); 188 | myTime = millis(); 189 | shutterButton(pCharacteristicRx); 190 | delay(30000); 191 | 192 | Serial.println("screen off"); 193 | screenToggle(pCharacteristicRx); 194 | delay(5000); 195 | 196 | Serial.println("screen on"); 197 | screenToggle(pCharacteristicRx); 198 | delay(5000); 199 | 200 | Serial.println("power off"); 201 | powerOff(pCharacteristicRx); 202 | delay(30000); 203 | 204 | Serial.println("power on"); 205 | BLEDevice::stopAdvertising(); 206 | powerOnPrevConnectedCameras(); 207 | } 208 | } 209 | 210 | void screenToggle(BLECharacteristic *characteristic) { 211 | data_8[0] = 0xfc; 212 | data_8[1] = 0xef; 213 | data_8[2] = 0xfe; 214 | data_8[3] = 0x86; 215 | data_8[4] = 0x00; 216 | data_8[5] = 0x03; 217 | data_8[6] = 0x01; 218 | data_8[7] = 0x00; 219 | data_8[8] = 0x00; 220 | characteristic->setValue(data_8, 9); 221 | characteristic->notify(); 222 | } 223 | 224 | void powerOff(BLECharacteristic *characteristic) { 225 | data_8[0] = 0xfc; 226 | data_8[1] = 0xef; 227 | data_8[2] = 0xfe; 228 | data_8[3] = 0x86; 229 | data_8[4] = 0x00; 230 | data_8[5] = 0x03; 231 | data_8[6] = 0x01; 232 | data_8[7] = 0x00; 233 | data_8[8] = 0x03; 234 | characteristic->setValue(data_8, 9); 235 | characteristic->notify(); 236 | } 237 | 238 | void powerOnPrevConnectedCameras() { 239 | /* the below might be camera specific and you may need to sniff them yourself for your camera */ 240 | 241 | /* used for Insta360 X3 */ 242 | // manuf_data[14] = 0x37; 243 | // manuf_data[15] = 0x4b; 244 | // manuf_data[16] = 0x43; 245 | // manuf_data[17] = 0x4d; 246 | // manuf_data[18] = 0x54; 247 | // manuf_data[19] = 0x4b; 248 | 249 | /* used for Insta360 RS 1-inch */ 250 | manuf_data[14] = 0x38; 251 | manuf_data[15] = 0x51; 252 | manuf_data[16] = 0x53; 253 | manuf_data[17] = 0x4a; 254 | manuf_data[18] = 0x38; 255 | manuf_data[19] = 0x52; 256 | 257 | // BLEAdvertisementData advertisementData; 258 | // advertisementData.setName("Insta360 GPS Remote"); 259 | // advertisementData.setFlags(ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_DMT_CONTROLLER_SPT | ESP_BLE_ADV_FLAG_DMT_HOST_SPT); 260 | // advertisementData.setManufacturerData((char *) manuf_data); 261 | 262 | // BLEAdvertising* advertisement = new BLEAdvertising(); 263 | // advertisement->setAdvertisementData(advertisementData); 264 | // advertisement->start(); 265 | 266 | // custom function that adds manufacturing data and modifies flags of advertisement 267 | BLEDevice::startAdvertisingWithManufData(manuf_data); 268 | } 269 | 270 | void modeButton(BLECharacteristic *characteristic) { 271 | data_8[0] = 0xfc; 272 | data_8[1] = 0xef; 273 | data_8[2] = 0xfe; 274 | data_8[3] = 0x86; 275 | data_8[4] = 0x00; 276 | data_8[5] = 0x03; 277 | data_8[6] = 0x01; 278 | data_8[7] = 0x01; 279 | data_8[8] = 0x00; 280 | characteristic->setValue(data_8, 9); 281 | characteristic->notify(); 282 | } 283 | 284 | void shutterButton(BLECharacteristic *characteristic) { 285 | data_8[0] = 0xfc; 286 | data_8[1] = 0xef; 287 | data_8[2] = 0xfe; 288 | data_8[3] = 0x86; 289 | data_8[4] = 0x00; 290 | data_8[5] = 0x03; 291 | data_8[6] = 0x01; 292 | data_8[7] = 0x02; 293 | data_8[8] = 0x00; 294 | characteristic->setValue(data_8, 9); 295 | characteristic->notify(); 296 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Insta360 BLE ESP32 2 | 3 | ## General Information 4 | Repository that demonstrates how Insta360 X3 and RS 1-inch can be controlled via an ESP32. 5 | 6 | ## Edited ESP32 Library Files 7 | The repository also included the edited BLEDevice source and header files that include the modified manufacturing data advertisement. 8 | 9 | ## Camera-specific Information 10 | 11 | manuf_data[14]-manuf_data[19] found in powerOnPrevConnectedCameras() are specific to cameras and can be found on any specific Insta360 camera by going to settings->Camera Info. 12 | -------------------------------------------------------------------------------- /debug.cfg: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0-or-later 2 | # 3 | # Example OpenOCD configuration file for ESP32-WROVER-KIT board. 4 | # 5 | # For example, OpenOCD can be started for ESP32 debugging on 6 | # 7 | # openocd -f board/esp32-wrover-kit-3.3v.cfg 8 | # 9 | 10 | # Source the JTAG interface configuration file 11 | source [find interface/ftdi/esp32_devkitj_v1.cfg] 12 | set ESP32_FLASH_VOLTAGE 3.3 13 | # Source the ESP32 configuration file 14 | source [find target/esp32.cfg] 15 | -------------------------------------------------------------------------------- /debug_custom.json: -------------------------------------------------------------------------------- 1 | { 2 | "name":"Arduino on ESP32", 3 | "toolchainPrefix":"xtensa-esp32-elf", 4 | "svdFile":"esp32.svd", 5 | "request":"attach", 6 | "postAttachCommands":[ 7 | "set remote hardware-watchpoint-limit 2", 8 | "monitor reset halt", 9 | "monitor gdb_sync", 10 | "thb setup", 11 | "c" 12 | ], 13 | "overrideRestartCommands":[ 14 | "monitor reset halt", 15 | "monitor gdb_sync", 16 | "thb setup", 17 | "c" 18 | ] 19 | } -------------------------------------------------------------------------------- /edited_esp_lib_files/BLEAdvertising.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * BLEAdvertising.cpp 3 | * 4 | * This class encapsulates advertising a BLE Server. 5 | * Created on: Jun 21, 2017 6 | * Author: kolban 7 | * 8 | * The ESP-IDF provides a framework for BLE advertising. It has determined that there are a common set 9 | * of properties that are advertised and has built a data structure that can be populated by the programmer. 10 | * This means that the programmer doesn't have to "mess with" the low level construction of a low level 11 | * BLE advertising frame. Many of the fields are determined for us while others we can set before starting 12 | * to advertise. 13 | * 14 | * Should we wish to construct our own payload, we can use the BLEAdvertisementData class and call the setters 15 | * upon it. Once it is populated, we can then associate it with the advertising and what ever the programmer 16 | * set in the data will be advertised. 17 | * 18 | */ 19 | #include "sdkconfig.h" 20 | #if defined(CONFIG_BLUEDROID_ENABLED) 21 | #include "BLEAdvertising.h" 22 | #include 23 | #include "BLEUtils.h" 24 | #include "GeneralUtils.h" 25 | #include "esp32-hal-log.h" 26 | 27 | /** 28 | * @brief Construct a default advertising object. 29 | * 30 | */ 31 | BLEAdvertising::BLEAdvertising() 32 | : m_scanRespData{} 33 | { 34 | m_advData.set_scan_rsp = false; 35 | m_advData.include_name = true; 36 | m_advData.include_txpower = true; 37 | m_advData.min_interval = 0x20; 38 | m_advData.max_interval = 0x40; 39 | m_advData.appearance = 0x00; 40 | m_advData.manufacturer_len = 0; 41 | m_advData.p_manufacturer_data = nullptr; 42 | m_advData.service_data_len = 0; 43 | m_advData.p_service_data = nullptr; 44 | m_advData.service_uuid_len = 0; 45 | m_advData.p_service_uuid = nullptr; 46 | m_advData.flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT); 47 | 48 | m_advParams.adv_int_min = 0x20; 49 | m_advParams.adv_int_max = 0x40; 50 | m_advParams.adv_type = ADV_TYPE_IND; 51 | m_advParams.own_addr_type = BLE_ADDR_TYPE_PUBLIC; 52 | m_advParams.channel_map = ADV_CHNL_ALL; 53 | m_advParams.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY; 54 | m_advParams.peer_addr_type = BLE_ADDR_TYPE_PUBLIC; 55 | 56 | m_customAdvData = false; // No custom advertising data 57 | m_customScanResponseData = false; // No custom scan response data 58 | } // BLEAdvertising 59 | 60 | void BLEAdvertising::directed_advertisement(std::string stringAddress){ 61 | // m_advParams.adv_type = ADV_TYPE_DIRECT_IND_HIGH; 62 | // m_advParams.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY; 63 | // m_advParams.peer_addr = BLEAddress(stringAddress); 64 | // m_advParams.peer_addr_type = BLE_ADDR_TYPE_PUBLIC; 65 | } // BLEAdvertising 66 | 67 | void BLEAdvertising::wake_advertisement(uint8_t *manuf_data){ 68 | 69 | m_advData.flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_DMT_CONTROLLER_SPT | ESP_BLE_ADV_FLAG_DMT_HOST_SPT); 70 | m_advData.manufacturer_len = 31; 71 | m_advData.p_manufacturer_data = manuf_data; 72 | // m_advData.appearance = 0x004c; 73 | 74 | // m_advParams.adv_type = ADV_TYPE_DIRECT_IND_HIGH; 75 | // m_advParams.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY; 76 | // m_advParams.peer_addr = BLEAddress(stringAddress); 77 | // m_advParams.peer_addr_type = BLE_ADDR_TYPE_PUBLIC; 78 | } // BLEAdvertising 79 | 80 | /** 81 | * @brief Add a service uuid to exposed list of services. 82 | * @param [in] serviceUUID The UUID of the service to expose. 83 | */ 84 | void BLEAdvertising::addServiceUUID(BLEUUID serviceUUID) { 85 | m_serviceUUIDs.push_back(serviceUUID); 86 | } // addServiceUUID 87 | 88 | 89 | /** 90 | * @brief Add a service uuid to exposed list of services. 91 | * @param [in] serviceUUID The string representation of the service to expose. 92 | */ 93 | void BLEAdvertising::addServiceUUID(const char* serviceUUID) { 94 | addServiceUUID(BLEUUID(serviceUUID)); 95 | } // addServiceUUID 96 | 97 | 98 | /** 99 | * @brief Set the device appearance in the advertising data. 100 | * The appearance attribute is of type 0x19. The codes for distinct appearances can be found here: 101 | * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.gap.appearance.xml. 102 | * @param [in] appearance The appearance of the device in the advertising data. 103 | * @return N/A. 104 | */ 105 | void BLEAdvertising::setAppearance(uint16_t appearance) { 106 | m_advData.appearance = appearance; 107 | } // setAppearance 108 | 109 | void BLEAdvertising::setAdvertisementType(esp_ble_adv_type_t adv_type){ 110 | m_advParams.adv_type = adv_type; 111 | } // setAdvertisementType 112 | 113 | void BLEAdvertising::setAdvertisementChannelMap(esp_ble_adv_channel_t channel_map) { 114 | m_advParams.channel_map = channel_map; 115 | } // setAdvertisementChannelMap 116 | 117 | void BLEAdvertising::setMinInterval(uint16_t mininterval) { 118 | m_advParams.adv_int_min = mininterval; 119 | } // setMinInterval 120 | 121 | void BLEAdvertising::setMaxInterval(uint16_t maxinterval) { 122 | m_advParams.adv_int_max = maxinterval; 123 | } // setMaxInterval 124 | 125 | void BLEAdvertising::setMinPreferred(uint16_t mininterval) { 126 | m_advData.min_interval = mininterval; 127 | } // 128 | 129 | void BLEAdvertising::setMaxPreferred(uint16_t maxinterval) { 130 | m_advData.max_interval = maxinterval; 131 | } // 132 | 133 | void BLEAdvertising::setScanResponse(bool set) { 134 | m_scanResp = set; 135 | } 136 | 137 | /** 138 | * @brief Set the filtering for the scan filter. 139 | * @param [in] scanRequestWhitelistOnly If true, only allow scan requests from those on the white list. 140 | * @param [in] connectWhitelistOnly If true, only allow connections from those on the white list. 141 | */ 142 | void BLEAdvertising::setScanFilter(bool scanRequestWhitelistOnly, bool connectWhitelistOnly) { 143 | log_v(">> setScanFilter: scanRequestWhitelistOnly: %d, connectWhitelistOnly: %d", scanRequestWhitelistOnly, connectWhitelistOnly); 144 | if (!scanRequestWhitelistOnly && !connectWhitelistOnly) { 145 | m_advParams.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY; 146 | log_v("<< setScanFilter"); 147 | return; 148 | } 149 | if (scanRequestWhitelistOnly && !connectWhitelistOnly) { 150 | m_advParams.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_WLST_CON_ANY; 151 | log_v("<< setScanFilter"); 152 | return; 153 | } 154 | if (!scanRequestWhitelistOnly && connectWhitelistOnly) { 155 | m_advParams.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_WLST; 156 | log_v("<< setScanFilter"); 157 | return; 158 | } 159 | if (scanRequestWhitelistOnly && connectWhitelistOnly) { 160 | m_advParams.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_WLST_CON_WLST; 161 | log_v("<< setScanFilter"); 162 | return; 163 | } 164 | } // setScanFilter 165 | 166 | 167 | /** 168 | * @brief Set the advertisement data that is to be published in a regular advertisement. 169 | * @param [in] advertisementData The data to be advertised. 170 | */ 171 | void BLEAdvertising::setAdvertisementData(BLEAdvertisementData& advertisementData) { 172 | log_v(">> setAdvertisementData"); 173 | esp_err_t errRc = ::esp_ble_gap_config_adv_data_raw( 174 | (uint8_t*)advertisementData.getPayload().data(), 175 | advertisementData.getPayload().length()); 176 | if (errRc != ESP_OK) { 177 | log_e("esp_ble_gap_config_adv_data_raw: %d %s", errRc, GeneralUtils::errorToString(errRc)); 178 | } 179 | m_customAdvData = true; // Set the flag that indicates we are using custom advertising data. 180 | log_v("<< setAdvertisementData"); 181 | } // setAdvertisementData 182 | 183 | 184 | /** 185 | * @brief Set the advertisement data that is to be published in a scan response. 186 | * @param [in] advertisementData The data to be advertised. 187 | */ 188 | void BLEAdvertising::setScanResponseData(BLEAdvertisementData& advertisementData) { 189 | log_v(">> setScanResponseData"); 190 | esp_err_t errRc = ::esp_ble_gap_config_scan_rsp_data_raw( 191 | (uint8_t*)advertisementData.getPayload().data(), 192 | advertisementData.getPayload().length()); 193 | if (errRc != ESP_OK) { 194 | log_e("esp_ble_gap_config_scan_rsp_data_raw: %d %s", errRc, GeneralUtils::errorToString(errRc)); 195 | } 196 | m_customScanResponseData = true; // Set the flag that indicates we are using custom scan response data. 197 | log_v("<< setScanResponseData"); 198 | } // setScanResponseData 199 | 200 | /** 201 | * @brief Start advertising. 202 | * Start advertising. 203 | * @return N/A. 204 | */ 205 | void BLEAdvertising::start() { 206 | log_v(">> start: customAdvData: %d, customScanResponseData: %d", m_customAdvData, m_customScanResponseData); 207 | 208 | // We have a vector of service UUIDs that we wish to advertise. In order to use the 209 | // ESP-IDF framework, these must be supplied in a contiguous array of their 128bit (16 byte) 210 | // representations. If we have 1 or more services to advertise then we allocate enough 211 | // storage to host them and then copy them in one at a time into the contiguous storage. 212 | int numServices = m_serviceUUIDs.size(); 213 | if (numServices > 0) { 214 | m_advData.service_uuid_len = 16 * numServices; 215 | m_advData.p_service_uuid = new uint8_t[m_advData.service_uuid_len]; 216 | uint8_t* p = m_advData.p_service_uuid; 217 | for (int i = 0; i < numServices; i++) { 218 | log_d("- advertising service: %s", m_serviceUUIDs[i].toString().c_str()); 219 | BLEUUID serviceUUID128 = m_serviceUUIDs[i].to128(); 220 | memcpy(p, serviceUUID128.getNative()->uuid.uuid128, 16); 221 | p += 16; 222 | } 223 | } else { 224 | m_advData.service_uuid_len = 0; 225 | log_d("- no services advertised"); 226 | } 227 | 228 | esp_err_t errRc; 229 | 230 | if (!m_customAdvData) { 231 | // Set the configuration for advertising. 232 | m_advData.set_scan_rsp = false; 233 | m_advData.include_name = !m_scanResp; 234 | m_advData.include_txpower = !m_scanResp; 235 | errRc = ::esp_ble_gap_config_adv_data(&m_advData); 236 | if (errRc != ESP_OK) { 237 | log_e("<< esp_ble_gap_config_adv_data: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); 238 | return; 239 | } 240 | } 241 | 242 | if (!m_customScanResponseData && m_scanResp) { 243 | // Set the configuration for scan response. 244 | memcpy(&m_scanRespData, &m_advData, sizeof(esp_ble_adv_data_t)); // Copy the content of m_advData. 245 | m_scanRespData.set_scan_rsp = true; // Define this struct as scan response data 246 | m_scanRespData.include_name = true; // Caution: This may lead to a crash if the device name has more than 29 characters 247 | m_scanRespData.include_txpower = true; 248 | m_scanRespData.appearance = 0; // If defined the 'Appearance' attribute is already included in the advertising data 249 | m_scanRespData.flag = 0; // 'Flags' attribute should no be included in the scan response 250 | 251 | errRc = ::esp_ble_gap_config_adv_data(&m_scanRespData); 252 | if (errRc != ESP_OK) { 253 | log_e("<< esp_ble_gap_config_adv_data (Scan response): rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); 254 | return; 255 | } 256 | } 257 | 258 | // If we had services to advertise then we previously allocated some storage for them. 259 | // Here we release that storage. 260 | if (m_advData.service_uuid_len > 0) { 261 | delete[] m_advData.p_service_uuid; 262 | m_advData.p_service_uuid = nullptr; 263 | } 264 | 265 | // Start advertising. 266 | errRc = ::esp_ble_gap_start_advertising(&m_advParams); 267 | if (errRc != ESP_OK) { 268 | log_e("<< esp_ble_gap_start_advertising: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); 269 | return; 270 | } 271 | log_v("<< start"); 272 | } // start 273 | 274 | 275 | /** 276 | * @brief Stop advertising. 277 | * Stop advertising. 278 | * @return N/A. 279 | */ 280 | void BLEAdvertising::stop() { 281 | log_v(">> stop"); 282 | esp_err_t errRc = ::esp_ble_gap_stop_advertising(); 283 | if (errRc != ESP_OK) { 284 | log_e("esp_ble_gap_stop_advertising: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); 285 | return; 286 | } 287 | log_v("<< stop"); 288 | } // stop 289 | 290 | /** 291 | * @brief Set BLE address. 292 | * @param [in] Bluetooth address. 293 | * @param [in] Bluetooth address type. 294 | * Set BLE address. 295 | */ 296 | 297 | void BLEAdvertising::setDeviceAddress(esp_bd_addr_t addr, esp_ble_addr_type_t type) 298 | { 299 | log_v(">> setPrivateAddress"); 300 | 301 | m_advParams.own_addr_type = type; 302 | esp_err_t errRc = esp_ble_gap_set_rand_addr((uint8_t*)addr); 303 | if (errRc != ESP_OK) 304 | { 305 | log_e("esp_ble_gap_set_rand_addr: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); 306 | return; 307 | } 308 | log_v("<< setPrivateAddress"); 309 | } // setPrivateAddress 310 | 311 | /** 312 | * @brief Add data to the payload to be advertised. 313 | * @param [in] data The data to be added to the payload. 314 | */ 315 | void BLEAdvertisementData::addData(std::string data) { 316 | if ((m_payload.length() + data.length()) > ESP_BLE_ADV_DATA_LEN_MAX) { 317 | return; 318 | } 319 | m_payload.append(data); 320 | } // addData 321 | 322 | 323 | /** 324 | * @brief Set the appearance. 325 | * @param [in] appearance The appearance code value. 326 | * 327 | * See also: 328 | * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.gap.appearance.xml 329 | */ 330 | void BLEAdvertisementData::setAppearance(uint16_t appearance) { 331 | char cdata[2]; 332 | cdata[0] = 3; 333 | cdata[1] = ESP_BLE_AD_TYPE_APPEARANCE; // 0x19 334 | addData(std::string(cdata, 2) + std::string((char*) &appearance, 2)); 335 | } // setAppearance 336 | 337 | 338 | /** 339 | * @brief Set the complete services. 340 | * @param [in] uuid The single service to advertise. 341 | */ 342 | void BLEAdvertisementData::setCompleteServices(BLEUUID uuid) { 343 | char cdata[2]; 344 | switch (uuid.bitSize()) { 345 | case 16: { 346 | // [Len] [0x02] [LL] [HH] 347 | cdata[0] = 3; 348 | cdata[1] = ESP_BLE_AD_TYPE_16SRV_CMPL; // 0x03 349 | addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->uuid.uuid16, 2)); 350 | break; 351 | } 352 | 353 | case 32: { 354 | // [Len] [0x04] [LL] [LL] [HH] [HH] 355 | cdata[0] = 5; 356 | cdata[1] = ESP_BLE_AD_TYPE_32SRV_CMPL; // 0x05 357 | addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->uuid.uuid32, 4)); 358 | break; 359 | } 360 | 361 | case 128: { 362 | // [Len] [0x04] [0] [1] ... [15] 363 | cdata[0] = 17; 364 | cdata[1] = ESP_BLE_AD_TYPE_128SRV_CMPL; // 0x07 365 | addData(std::string(cdata, 2) + std::string((char*) uuid.getNative()->uuid.uuid128, 16)); 366 | break; 367 | } 368 | 369 | default: 370 | return; 371 | } 372 | } // setCompleteServices 373 | 374 | 375 | /** 376 | * @brief Set the advertisement flags. 377 | * @param [in] The flags to be set in the advertisement. 378 | * 379 | * * ESP_BLE_ADV_FLAG_LIMIT_DISC 380 | * * ESP_BLE_ADV_FLAG_GEN_DISC 381 | * * ESP_BLE_ADV_FLAG_BREDR_NOT_SPT 382 | * * ESP_BLE_ADV_FLAG_DMT_CONTROLLER_SPT 383 | * * ESP_BLE_ADV_FLAG_DMT_HOST_SPT 384 | * * ESP_BLE_ADV_FLAG_NON_LIMIT_DISC 385 | */ 386 | void BLEAdvertisementData::setFlags(uint8_t flag) { 387 | char cdata[3]; 388 | cdata[0] = 2; 389 | cdata[1] = ESP_BLE_AD_TYPE_FLAG; // 0x01 390 | cdata[2] = flag; 391 | addData(std::string(cdata, 3)); 392 | } // setFlag 393 | 394 | 395 | 396 | /** 397 | * @brief Set manufacturer specific data. 398 | * @param [in] data Manufacturer data. 399 | */ 400 | void BLEAdvertisementData::setManufacturerData(std::string data) { 401 | log_d("BLEAdvertisementData", ">> setManufacturerData"); 402 | char cdata[2]; 403 | cdata[0] = data.length() + 1; 404 | cdata[1] = ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE; // 0xff 405 | addData(std::string(cdata, 2) + data); 406 | log_d("BLEAdvertisementData", "<< setManufacturerData"); 407 | } // setManufacturerData 408 | 409 | 410 | /** 411 | * @brief Set the name. 412 | * @param [in] The complete name of the device. 413 | */ 414 | void BLEAdvertisementData::setName(std::string name) { 415 | log_d("BLEAdvertisementData", ">> setName: %s", name.c_str()); 416 | char cdata[2]; 417 | cdata[0] = name.length() + 1; 418 | cdata[1] = ESP_BLE_AD_TYPE_NAME_CMPL; // 0x09 419 | addData(std::string(cdata, 2) + name); 420 | log_d("BLEAdvertisementData", "<< setName"); 421 | } // setName 422 | 423 | 424 | /** 425 | * @brief Set the partial services. 426 | * @param [in] uuid The single service to advertise. 427 | */ 428 | void BLEAdvertisementData::setPartialServices(BLEUUID uuid) { 429 | char cdata[2]; 430 | switch (uuid.bitSize()) { 431 | case 16: { 432 | // [Len] [0x02] [LL] [HH] 433 | cdata[0] = 3; 434 | cdata[1] = ESP_BLE_AD_TYPE_16SRV_PART; // 0x02 435 | addData(std::string(cdata, 2) + std::string((char *) &uuid.getNative()->uuid.uuid16, 2)); 436 | break; 437 | } 438 | 439 | case 32: { 440 | // [Len] [0x04] [LL] [LL] [HH] [HH] 441 | cdata[0] = 5; 442 | cdata[1] = ESP_BLE_AD_TYPE_32SRV_PART; // 0x04 443 | addData(std::string(cdata, 2) + std::string((char *) &uuid.getNative()->uuid.uuid32, 4)); 444 | break; 445 | } 446 | 447 | case 128: { 448 | // [Len] [0x04] [0] [1] ... [15] 449 | cdata[0] = 17; 450 | cdata[1] = ESP_BLE_AD_TYPE_128SRV_PART; // 0x06 451 | addData(std::string(cdata, 2) + std::string((char *) &uuid.getNative()->uuid.uuid128, 16)); 452 | break; 453 | } 454 | 455 | default: 456 | return; 457 | } 458 | } // setPartialServices 459 | 460 | 461 | /** 462 | * @brief Set the service data (UUID + data) 463 | * @param [in] uuid The UUID to set with the service data. Size of UUID will be used. 464 | * @param [in] data The data to be associated with the service data advert. 465 | */ 466 | void BLEAdvertisementData::setServiceData(BLEUUID uuid, std::string data) { 467 | char cdata[2]; 468 | switch (uuid.bitSize()) { 469 | case 16: { 470 | // [Len] [0x16] [UUID16] data 471 | cdata[0] = data.length() + 3; 472 | cdata[1] = ESP_BLE_AD_TYPE_SERVICE_DATA; // 0x16 473 | addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->uuid.uuid16, 2) + data); 474 | break; 475 | } 476 | 477 | case 32: { 478 | // [Len] [0x20] [UUID32] data 479 | cdata[0] = data.length() + 5; 480 | cdata[1] = ESP_BLE_AD_TYPE_32SERVICE_DATA; // 0x20 481 | addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->uuid.uuid32, 4) + data); 482 | break; 483 | } 484 | 485 | case 128: { 486 | // [Len] [0x21] [UUID128] data 487 | cdata[0] = data.length() + 17; 488 | cdata[1] = ESP_BLE_AD_TYPE_128SERVICE_DATA; // 0x21 489 | addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->uuid.uuid128, 16) + data); 490 | break; 491 | } 492 | 493 | default: 494 | return; 495 | } 496 | } // setServiceData 497 | 498 | 499 | /** 500 | * @brief Set the short name. 501 | * @param [in] The short name of the device. 502 | */ 503 | void BLEAdvertisementData::setShortName(std::string name) { 504 | log_d("BLEAdvertisementData", ">> setShortName: %s", name.c_str()); 505 | char cdata[2]; 506 | cdata[0] = name.length() + 1; 507 | cdata[1] = ESP_BLE_AD_TYPE_NAME_SHORT; // 0x08 508 | addData(std::string(cdata, 2) + name); 509 | log_d("BLEAdvertisementData", "<< setShortName"); 510 | } // setShortName 511 | 512 | 513 | /** 514 | * @brief Retrieve the payload that is to be advertised. 515 | * @return The payload that is to be advertised. 516 | */ 517 | std::string BLEAdvertisementData::getPayload() { 518 | return m_payload; 519 | } // getPayload 520 | 521 | void BLEAdvertising::handleGAPEvent( 522 | esp_gap_ble_cb_event_t event, 523 | esp_ble_gap_cb_param_t* param) { 524 | 525 | log_d("handleGAPEvent [event no: %d]", (int)event); 526 | 527 | switch(event) { 528 | case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: { 529 | // m_semaphoreSetAdv.give(); 530 | break; 531 | } 532 | case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT: { 533 | // m_semaphoreSetAdv.give(); 534 | break; 535 | } 536 | case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: { 537 | // m_semaphoreSetAdv.give(); 538 | break; 539 | } 540 | case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT: { 541 | log_i("STOP advertising"); 542 | //start(); 543 | break; 544 | } 545 | default: 546 | break; 547 | } 548 | } 549 | 550 | #ifdef CONFIG_BT_BLE_50_FEATURES_SUPPORTED 551 | 552 | /** 553 | * @brief Creator 554 | * 555 | * @param[in] instance : number of multi advertising instances 556 | * 557 | * 558 | */ 559 | BLEMultiAdvertising::BLEMultiAdvertising(uint8_t num) 560 | { 561 | params_arrays = (esp_ble_gap_ext_adv_params_t*)calloc(num, sizeof(esp_ble_gap_ext_adv_params_t)); 562 | ext_adv = (esp_ble_gap_ext_adv_t*)calloc(num, sizeof(esp_ble_gap_ext_adv_t)); 563 | count = num; 564 | } 565 | 566 | /** 567 | * @brief This function is used by the Host to set the advertising parameters. 568 | * 569 | * @param[in] instance : identifies the advertising set whose parameters are being configured. 570 | * @param[in] params : advertising parameters 571 | * 572 | * @return - true : success 573 | * - false : failed 574 | * 575 | */ 576 | bool BLEMultiAdvertising::setAdvertisingParams(uint8_t instance, const esp_ble_gap_ext_adv_params_t* params) 577 | { 578 | if (params->type == ESP_BLE_GAP_SET_EXT_ADV_PROP_LEGACY_IND && params->primary_phy == ESP_BLE_GAP_PHY_2M) return false; 579 | esp_err_t rc; 580 | rc = esp_ble_gap_ext_adv_set_params(instance, params); 581 | 582 | return ESP_OK == rc; 583 | } 584 | 585 | /** 586 | * @brief This function is used to set the data used in advertising PDUs that have a data field 587 | * 588 | * @param[in] instance : identifies the advertising set whose data are being configured 589 | * @param[in] length : data length 590 | * @param[in] data : data information 591 | * 592 | * @return - true : success 593 | * - false : failed 594 | * 595 | */ 596 | bool BLEMultiAdvertising::setAdvertisingData(uint8_t instance, uint16_t length, const uint8_t* data) 597 | { 598 | esp_err_t rc; 599 | rc = esp_ble_gap_config_ext_adv_data_raw(instance, length, data); 600 | if (rc) log_e("set advertising data err: %d", rc); 601 | 602 | return ESP_OK == rc; 603 | } 604 | 605 | bool BLEMultiAdvertising::setScanRspData(uint8_t instance, uint16_t length, const uint8_t* data) 606 | { 607 | esp_err_t rc; 608 | rc = esp_ble_gap_config_ext_scan_rsp_data_raw(instance, length, data); 609 | if (rc) log_e("set scan resp data err: %d", rc); 610 | 611 | return ESP_OK == rc; 612 | } 613 | 614 | /** 615 | * @brief This function is used to request the Controller to enable one or more 616 | * advertising sets using the advertising sets identified by the instance parameter. 617 | * 618 | * @return - true : success 619 | * - false : failed 620 | * 621 | */ 622 | bool BLEMultiAdvertising::start() 623 | { 624 | return start(count, 0); 625 | } 626 | 627 | /** 628 | * @brief This function is used to request the Controller to enable one or more 629 | * advertising sets using the advertising sets identified by the instance parameter. 630 | * 631 | * @param[in] num : Number of advertising sets to enable or disable 632 | * @param[in] from : first sxt adv set to use 633 | * 634 | * @return - true : success 635 | * - false : failed 636 | * 637 | */ 638 | bool BLEMultiAdvertising::start(uint8_t num, uint8_t from) 639 | { 640 | if (num > count || from >= count) return false; 641 | 642 | esp_err_t rc; 643 | rc = esp_ble_gap_ext_adv_start(num, &ext_adv[from]); 644 | if (rc) log_e("start extended advertising err: %d", rc); 645 | 646 | return ESP_OK == rc; 647 | } 648 | 649 | /** 650 | * @brief This function is used to request the Controller to disable one or more 651 | * advertising sets using the advertising sets identified by the instance parameter. 652 | * 653 | * @param[in] num_adv : Number of advertising sets to enable or disable 654 | * @param[in] ext_adv_inst : ext adv instance 655 | * 656 | * @return - ESP_OK : success 657 | * - other : failed 658 | * 659 | */ 660 | bool BLEMultiAdvertising::stop(uint8_t num_adv, const uint8_t* ext_adv_inst) 661 | { 662 | esp_err_t rc; 663 | rc = esp_ble_gap_ext_adv_stop(num_adv, ext_adv_inst); 664 | if (rc) log_e("stop extended advertising err: %d", rc); 665 | 666 | return ESP_OK == rc; 667 | } 668 | 669 | /** 670 | * @brief This function is used to remove an advertising set from the Controller. 671 | * 672 | * @param[in] instance : Used to identify an advertising set 673 | * 674 | * @return - ESP_OK : success 675 | * - other : failed 676 | * 677 | */ 678 | bool BLEMultiAdvertising::remove(uint8_t instance) 679 | { 680 | esp_err_t rc; 681 | rc = esp_ble_gap_ext_adv_set_remove(instance); 682 | if (rc) log_e("remove extended advertising err: %d", rc); 683 | 684 | return ESP_OK == rc; 685 | } 686 | 687 | /** 688 | * @brief This function is used to remove all existing advertising sets from the Controller. 689 | * 690 | * 691 | * @return - ESP_OK : success 692 | * - other : failed 693 | * 694 | */ 695 | bool BLEMultiAdvertising::clear() 696 | { 697 | esp_err_t rc; 698 | rc = esp_ble_gap_ext_adv_set_clear(); 699 | if (rc) log_e("clear extended advertising err: %d", rc); 700 | 701 | return ESP_OK == rc; 702 | } 703 | 704 | /** 705 | * @brief This function is used by the Host to set the random device address specified by the Random_Address parameter. 706 | * 707 | * @param[in] instance : Used to identify an advertising set 708 | * @param[in] addr_legacy : Random Device Address 709 | * 710 | * @return - true : success 711 | * - false : failed 712 | * 713 | */ 714 | bool BLEMultiAdvertising::setInstanceAddress(uint8_t instance, uint8_t* addr_legacy) 715 | { 716 | esp_err_t rc; 717 | rc = esp_ble_gap_ext_adv_set_rand_addr(instance, addr_legacy); 718 | if (rc) log_e("set random address err: %d", rc); 719 | 720 | return ESP_OK == rc; 721 | } 722 | 723 | /** 724 | * @brief This function is used by the Host to set the parameters for periodic advertising. 725 | * 726 | * @param[in] instance : identifies the advertising set whose periodic advertising parameters are being configured. 727 | * @param[in] params : periodic adv parameters 728 | * 729 | * @return - true : success 730 | * - false : failed 731 | * 732 | */ 733 | bool BLEMultiAdvertising::setPeriodicAdvertisingParams(uint8_t instance, const esp_ble_gap_periodic_adv_params_t* params) 734 | { 735 | esp_err_t rc; 736 | rc = esp_ble_gap_periodic_adv_set_params(instance, params); 737 | if (rc) log_e("set periodic advertising params err: %d", rc); 738 | 739 | return ESP_OK == rc; 740 | } 741 | 742 | /** 743 | * @brief This function is used to set the data used in periodic advertising PDUs. 744 | * 745 | * @param[in] instance : identifies the advertising set whose periodic advertising parameters are being configured. 746 | * @param[in] length : the length of periodic data 747 | * @param[in] data : periodic data information 748 | * 749 | * @return - true : success 750 | * - false : failed 751 | * 752 | */ 753 | bool BLEMultiAdvertising::setPeriodicAdvertisingData(uint8_t instance, uint16_t length, const uint8_t* data) 754 | { 755 | esp_err_t rc; 756 | rc = esp_ble_gap_config_periodic_adv_data_raw(instance, length, data); 757 | if (rc) log_e("set periodic advertising raw data err: %d", rc); 758 | 759 | return ESP_OK == rc; 760 | } 761 | 762 | /** 763 | * @brief This function is used to request the Controller to enable the periodic advertising for the advertising set specified 764 | * 765 | * @param[in] instance : Used to identify an advertising set 766 | * 767 | * @return - true : success 768 | * - false : failed 769 | * 770 | */ 771 | bool BLEMultiAdvertising::startPeriodicAdvertising(uint8_t instance) 772 | { 773 | esp_err_t rc; 774 | rc = esp_ble_gap_periodic_adv_start(instance); 775 | if (rc) log_e("start periodic advertising err: %d", rc); 776 | 777 | return ESP_OK == rc; 778 | } 779 | 780 | void BLEMultiAdvertising::setDuration(uint8_t instance, int duration, int max_events) 781 | { 782 | ext_adv[instance] = { instance, duration, max_events }; 783 | } 784 | 785 | #endif // CONFIG_BT_BLE_50_FEATURES_SUPPORTED 786 | 787 | 788 | #endif /* CONFIG_BLUEDROID_ENABLED */ 789 | -------------------------------------------------------------------------------- /edited_esp_lib_files/BLEAdvertising.h: -------------------------------------------------------------------------------- 1 | /* 2 | * BLEAdvertising.h 3 | * 4 | * Created on: Jun 21, 2017 5 | * Author: kolban 6 | */ 7 | 8 | #ifndef COMPONENTS_CPP_UTILS_BLEADVERTISING_H_ 9 | #define COMPONENTS_CPP_UTILS_BLEADVERTISING_H_ 10 | #include "sdkconfig.h" 11 | #if defined(CONFIG_BLUEDROID_ENABLED) 12 | #include 13 | #include "BLEUUID.h" 14 | #include 15 | #include "RTOS.h" 16 | 17 | /** 18 | * @brief Advertisement data set by the programmer to be published by the %BLE server. 19 | */ 20 | class BLEAdvertisementData { 21 | // Only a subset of the possible BLE architected advertisement fields are currently exposed. Others will 22 | // be exposed on demand/request or as time permits. 23 | // 24 | public: 25 | void setAppearance(uint16_t appearance); 26 | void setCompleteServices(BLEUUID uuid); 27 | void setFlags(uint8_t); 28 | void setManufacturerData(std::string data); 29 | void setName(std::string name); 30 | void setPartialServices(BLEUUID uuid); 31 | void setServiceData(BLEUUID uuid, std::string data); 32 | void setShortName(std::string name); 33 | void addData(std::string data); // Add data to the payload. 34 | std::string getPayload(); // Retrieve the current advert payload. 35 | 36 | private: 37 | friend class BLEAdvertising; 38 | std::string m_payload; // The payload of the advertisement. 39 | }; // BLEAdvertisementData 40 | 41 | 42 | /** 43 | * @brief Perform and manage %BLE advertising. 44 | * 45 | * A %BLE server will want to perform advertising in order to make itself known to %BLE clients. 46 | */ 47 | class BLEAdvertising { 48 | public: 49 | BLEAdvertising(); 50 | void directed_advertisement(std::string stringAddress); 51 | void wake_advertisement(uint8_t *manuf_data); 52 | void addServiceUUID(BLEUUID serviceUUID); 53 | void addServiceUUID(const char* serviceUUID); 54 | void start(); 55 | void stop(); 56 | void setAppearance(uint16_t appearance); 57 | void setAdvertisementType(esp_ble_adv_type_t adv_type); 58 | void setAdvertisementChannelMap(esp_ble_adv_channel_t channel_map); 59 | void setMaxInterval(uint16_t maxinterval); 60 | void setMinInterval(uint16_t mininterval); 61 | void setAdvertisementData(BLEAdvertisementData& advertisementData); 62 | void setScanFilter(bool scanRequertWhitelistOnly, bool connectWhitelistOnly); 63 | void setScanResponseData(BLEAdvertisementData& advertisementData); 64 | void setPrivateAddress(esp_ble_addr_type_t type = BLE_ADDR_TYPE_RANDOM); 65 | void setDeviceAddress(esp_bd_addr_t addr, esp_ble_addr_type_t type = BLE_ADDR_TYPE_RANDOM); 66 | 67 | void handleGAPEvent(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t* param); 68 | void setMinPreferred(uint16_t); 69 | void setMaxPreferred(uint16_t); 70 | void setScanResponse(bool); 71 | 72 | private: 73 | esp_ble_adv_data_t m_advData; 74 | esp_ble_adv_data_t m_scanRespData; // Used for configuration of scan response data when m_scanResp is true 75 | esp_ble_adv_params_t m_advParams; 76 | std::vector m_serviceUUIDs; 77 | bool m_customAdvData = false; // Are we using custom advertising data? 78 | bool m_customScanResponseData = false; // Are we using custom scan response data? 79 | FreeRTOS::Semaphore m_semaphoreSetAdv = FreeRTOS::Semaphore("startAdvert"); 80 | bool m_scanResp = true; 81 | 82 | }; 83 | 84 | #ifdef CONFIG_BT_BLE_50_FEATURES_SUPPORTED 85 | 86 | class BLEMultiAdvertising 87 | { 88 | private: 89 | esp_ble_gap_ext_adv_params_t* params_arrays; 90 | esp_ble_gap_ext_adv_t* ext_adv; 91 | uint8_t count; 92 | 93 | public: 94 | BLEMultiAdvertising(uint8_t num = 1); 95 | ~BLEMultiAdvertising() {} 96 | 97 | bool setAdvertisingParams(uint8_t instance, const esp_ble_gap_ext_adv_params_t* params); 98 | bool setAdvertisingData(uint8_t instance, uint16_t length, const uint8_t* data); 99 | bool setScanRspData(uint8_t instance, uint16_t length, const uint8_t* data); 100 | bool start(); 101 | bool start(uint8_t num, uint8_t from); 102 | void setDuration(uint8_t instance, int duration = 0, int max_events = 0); 103 | bool setInstanceAddress(uint8_t instance, esp_bd_addr_t rand_addr); 104 | bool stop(uint8_t num_adv, const uint8_t* ext_adv_inst); 105 | bool remove(uint8_t instance); 106 | bool clear(); 107 | bool setPeriodicAdvertisingParams(uint8_t instance, const esp_ble_gap_periodic_adv_params_t* params); 108 | bool setPeriodicAdvertisingData(uint8_t instance, uint16_t length, const uint8_t* data); 109 | bool startPeriodicAdvertising(uint8_t instance); 110 | }; 111 | 112 | #endif // CONFIG_BT_BLE_50_FEATURES_SUPPORTED 113 | 114 | #endif /* CONFIG_BLUEDROID_ENABLED */ 115 | #endif /* COMPONENTS_CPP_UTILS_BLEADVERTISING_H_ */ 116 | -------------------------------------------------------------------------------- /edited_esp_lib_files/BLEDescriptor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * BLEDescriptor.h 3 | * 4 | * Created on: Jun 22, 2017 5 | * Author: kolban 6 | */ 7 | 8 | #ifndef COMPONENTS_CPP_UTILS_BLEDESCRIPTOR_H_ 9 | #define COMPONENTS_CPP_UTILS_BLEDESCRIPTOR_H_ 10 | #include "sdkconfig.h" 11 | #if defined(CONFIG_BLUEDROID_ENABLED) 12 | #include 13 | #include "BLEUUID.h" 14 | #include "BLECharacteristic.h" 15 | #include 16 | #include "RTOS.h" 17 | 18 | class BLEService; 19 | class BLECharacteristic; 20 | class BLEDescriptorCallbacks; 21 | 22 | /** 23 | * @brief A model of a %BLE descriptor. 24 | */ 25 | class BLEDescriptor { 26 | public: 27 | BLEDescriptor(const char* uuid, uint16_t max_len = 100); 28 | BLEDescriptor(BLEUUID uuid, uint16_t max_len = 100); 29 | virtual ~BLEDescriptor(); 30 | 31 | uint16_t getHandle(); // Get the handle of the descriptor. 32 | size_t getLength(); // Get the length of the value of the descriptor. 33 | BLEUUID getUUID(); // Get the UUID of the descriptor. 34 | uint8_t* getValue(); // Get a pointer to the value of the descriptor. 35 | void handleGATTServerEvent( 36 | esp_gatts_cb_event_t event, 37 | esp_gatt_if_t gatts_if, 38 | esp_ble_gatts_cb_param_t* param); 39 | 40 | void setAccessPermissions(esp_gatt_perm_t perm); // Set the permissions of the descriptor. 41 | void setCallbacks(BLEDescriptorCallbacks* pCallbacks); // Set callbacks to be invoked for the descriptor. 42 | void setValue(uint8_t* data, size_t size); // Set the value of the descriptor as a pointer to data. 43 | void setValue(std::string value); // Set the value of the descriptor as a data buffer. 44 | 45 | std::string toString(); // Convert the descriptor to a string representation. 46 | 47 | private: 48 | friend class BLEDescriptorMap; 49 | friend class BLECharacteristic; 50 | BLEUUID m_bleUUID; 51 | uint16_t m_handle; 52 | BLEDescriptorCallbacks* m_pCallback; 53 | BLECharacteristic* m_pCharacteristic; 54 | esp_gatt_perm_t m_permissions = ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE; 55 | FreeRTOS::Semaphore m_semaphoreCreateEvt = FreeRTOS::Semaphore("CreateEvt"); 56 | esp_attr_value_t m_value; 57 | 58 | void executeCreate(BLECharacteristic* pCharacteristic); 59 | void setHandle(uint16_t handle); 60 | }; // BLEDescriptor 61 | 62 | 63 | /** 64 | * @brief Callbacks that can be associated with a %BLE descriptors to inform of events. 65 | * 66 | * When a server application creates a %BLE descriptor, we may wish to be informed when there is either 67 | * a read or write request to the descriptors value. An application can register a 68 | * sub-classed instance of this class and will be notified when such an event happens. 69 | */ 70 | class BLEDescriptorCallbacks { 71 | public: 72 | virtual ~BLEDescriptorCallbacks(); 73 | virtual void onRead(BLEDescriptor* pDescriptor); 74 | virtual void onWrite(BLEDescriptor* pDescriptor); 75 | }; 76 | #endif /* CONFIG_BLUEDROID_ENABLED */ 77 | #endif /* COMPONENTS_CPP_UTILS_BLEDESCRIPTOR_H_ */ 78 | -------------------------------------------------------------------------------- /edited_esp_lib_files/BLEDevice.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * BLE.cpp 3 | * 4 | * Created on: Mar 16, 2017 5 | * Author: kolban 6 | */ 7 | #include "sdkconfig.h" 8 | #if defined(CONFIG_BLUEDROID_ENABLED) 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include // ESP32 BLE 15 | #include // ESP32 BLE 16 | #include // ESP32 BLE 17 | #include // ESP32 BLE 18 | #include // ESP32 BLE 19 | #include // ESP32 BLE 20 | #include // ESP32 BLE 21 | #include // ESP32 ESP-IDF 22 | #include // Part of C++ Standard library 23 | #include // Part of C++ Standard library 24 | #include // Part of C++ Standard library 25 | 26 | #include "BLEDevice.h" 27 | #include "BLEClient.h" 28 | #include "BLEUtils.h" 29 | #include "GeneralUtils.h" 30 | 31 | #if defined(ARDUINO_ARCH_ESP32) 32 | #include "esp32-hal-bt.h" 33 | #endif 34 | 35 | #include "esp32-hal-log.h" 36 | 37 | 38 | /** 39 | * Singletons for the BLEDevice. 40 | */ 41 | BLEServer* BLEDevice::m_pServer = nullptr; 42 | BLEScan* BLEDevice::m_pScan = nullptr; 43 | BLEClient* BLEDevice::m_pClient = nullptr; 44 | bool initialized = false; 45 | esp_ble_sec_act_t BLEDevice::m_securityLevel = (esp_ble_sec_act_t)0; 46 | BLESecurityCallbacks* BLEDevice::m_securityCallbacks = nullptr; 47 | uint16_t BLEDevice::m_localMTU = 23; // not sure if this variable is useful 48 | BLEAdvertising* BLEDevice::m_bleAdvertising = nullptr; 49 | uint16_t BLEDevice::m_appId = 0; 50 | std::map BLEDevice::m_connectedClientsMap; 51 | gap_event_handler BLEDevice::m_customGapHandler = nullptr; 52 | gattc_event_handler BLEDevice::m_customGattcHandler = nullptr; 53 | gatts_event_handler BLEDevice::m_customGattsHandler = nullptr; 54 | 55 | /** 56 | * @brief Create a new instance of a client. 57 | * @return A new instance of the client. 58 | */ 59 | /* STATIC */ BLEClient* BLEDevice::createClient() { 60 | log_v(">> createClient"); 61 | #ifndef CONFIG_GATTC_ENABLE // Check that BLE GATTC is enabled in make menuconfig 62 | log_e("BLE GATTC is not enabled - CONFIG_GATTC_ENABLE not defined"); 63 | abort(); 64 | #endif // CONFIG_GATTC_ENABLE 65 | m_pClient = new BLEClient(); 66 | log_v("<< createClient"); 67 | return m_pClient; 68 | } // createClient 69 | 70 | 71 | /** 72 | * @brief Create a new instance of a server. 73 | * @return A new instance of the server. 74 | */ 75 | /* STATIC */ BLEServer* BLEDevice::createServer() { 76 | log_v(">> createServer"); 77 | #ifndef CONFIG_GATTS_ENABLE // Check that BLE GATTS is enabled in make menuconfig 78 | log_e("BLE GATTS is not enabled - CONFIG_GATTS_ENABLE not defined"); 79 | abort(); 80 | #endif // CONFIG_GATTS_ENABLE 81 | m_pServer = new BLEServer(); 82 | m_pServer->createApp(m_appId++); 83 | log_v("<< createServer"); 84 | return m_pServer; 85 | } // createServer 86 | 87 | 88 | /** 89 | * @brief Handle GATT server events. 90 | * 91 | * @param [in] event The event that has been newly received. 92 | * @param [in] gatts_if The connection to the GATT interface. 93 | * @param [in] param Parameters for the event. 94 | */ 95 | /* STATIC */ void BLEDevice::gattServerEventHandler( 96 | esp_gatts_cb_event_t event, 97 | esp_gatt_if_t gatts_if, 98 | esp_ble_gatts_cb_param_t* param 99 | ) { 100 | log_d("gattServerEventHandler [esp_gatt_if: %d] ... %s", 101 | gatts_if, 102 | BLEUtils::gattServerEventTypeToString(event).c_str()); 103 | 104 | BLEUtils::dumpGattServerEvent(event, gatts_if, param); 105 | 106 | switch (event) { 107 | case ESP_GATTS_CONNECT_EVT: { 108 | #ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig 109 | if(BLEDevice::m_securityLevel){ 110 | esp_ble_set_encryption(param->connect.remote_bda, BLEDevice::m_securityLevel); 111 | } 112 | #endif // CONFIG_BLE_SMP_ENABLE 113 | break; 114 | } // ESP_GATTS_CONNECT_EVT 115 | 116 | default: { 117 | break; 118 | } 119 | } // switch 120 | 121 | 122 | if (BLEDevice::m_pServer != nullptr) { 123 | BLEDevice::m_pServer->handleGATTServerEvent(event, gatts_if, param); 124 | } 125 | 126 | if(m_customGattsHandler != nullptr) { 127 | m_customGattsHandler(event, gatts_if, param); 128 | } 129 | 130 | } // gattServerEventHandler 131 | 132 | 133 | /** 134 | * @brief Handle GATT client events. 135 | * 136 | * Handler for the GATT client events. 137 | * 138 | * @param [in] event 139 | * @param [in] gattc_if 140 | * @param [in] param 141 | */ 142 | /* STATIC */ void BLEDevice::gattClientEventHandler( 143 | esp_gattc_cb_event_t event, 144 | esp_gatt_if_t gattc_if, 145 | esp_ble_gattc_cb_param_t* param) { 146 | 147 | log_d("gattClientEventHandler [esp_gatt_if: %d] ... %s", 148 | gattc_if, BLEUtils::gattClientEventTypeToString(event).c_str()); 149 | BLEUtils::dumpGattClientEvent(event, gattc_if, param); 150 | 151 | switch(event) { 152 | case ESP_GATTC_CONNECT_EVT: { 153 | #ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig 154 | if(BLEDevice::m_securityLevel){ 155 | esp_ble_set_encryption(param->connect.remote_bda, BLEDevice::m_securityLevel); 156 | } 157 | #endif // CONFIG_BLE_SMP_ENABLE 158 | break; 159 | } // ESP_GATTS_CONNECT_EVT 160 | 161 | default: 162 | break; 163 | } // switch 164 | for(auto &myPair : BLEDevice::getPeerDevices(true)) { 165 | conn_status_t conn_status = (conn_status_t)myPair.second; 166 | if(((BLEClient*)conn_status.peer_device)->getGattcIf() == gattc_if || ((BLEClient*)conn_status.peer_device)->getGattcIf() == ESP_GATT_IF_NONE || gattc_if == ESP_GATT_IF_NONE){ 167 | ((BLEClient*)conn_status.peer_device)->gattClientEventHandler(event, gattc_if, param); 168 | } 169 | } 170 | 171 | if(m_customGattcHandler != nullptr) { 172 | m_customGattcHandler(event, gattc_if, param); 173 | } 174 | 175 | 176 | } // gattClientEventHandler 177 | 178 | 179 | /** 180 | * @brief Handle GAP events. 181 | */ 182 | /* STATIC */ void BLEDevice::gapEventHandler( 183 | esp_gap_ble_cb_event_t event, 184 | esp_ble_gap_cb_param_t *param) { 185 | 186 | BLEUtils::dumpGapEvent(event, param); 187 | 188 | switch(event) { 189 | 190 | case ESP_GAP_BLE_OOB_REQ_EVT: /* OOB request event */ 191 | log_i("ESP_GAP_BLE_OOB_REQ_EVT"); 192 | break; 193 | case ESP_GAP_BLE_LOCAL_IR_EVT: /* BLE local IR event */ 194 | log_i("ESP_GAP_BLE_LOCAL_IR_EVT"); 195 | break; 196 | case ESP_GAP_BLE_LOCAL_ER_EVT: /* BLE local ER event */ 197 | log_i("ESP_GAP_BLE_LOCAL_ER_EVT"); 198 | break; 199 | case ESP_GAP_BLE_NC_REQ_EVT: /* NUMERIC CONFIRMATION */ 200 | log_i("ESP_GAP_BLE_NC_REQ_EVT"); 201 | #ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig 202 | if(BLEDevice::m_securityCallbacks != nullptr){ 203 | esp_ble_confirm_reply(param->ble_security.ble_req.bd_addr, BLEDevice::m_securityCallbacks->onConfirmPIN(param->ble_security.key_notif.passkey)); 204 | } 205 | #endif // CONFIG_BLE_SMP_ENABLE 206 | break; 207 | case ESP_GAP_BLE_PASSKEY_REQ_EVT: /* passkey request event */ 208 | log_i("ESP_GAP_BLE_PASSKEY_REQ_EVT: "); 209 | // esp_log_buffer_hex(m_remote_bda, sizeof(m_remote_bda)); 210 | #ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig 211 | if(BLEDevice::m_securityCallbacks != nullptr){ 212 | esp_ble_passkey_reply(param->ble_security.ble_req.bd_addr, true, BLEDevice::m_securityCallbacks->onPassKeyRequest()); 213 | } 214 | #endif // CONFIG_BLE_SMP_ENABLE 215 | break; 216 | /* 217 | * TODO should we add white/black list comparison? 218 | */ 219 | case ESP_GAP_BLE_SEC_REQ_EVT: 220 | /* send the positive(true) security response to the peer device to accept the security request. 221 | If not accept the security request, should sent the security response with negative(false) accept value*/ 222 | log_i("ESP_GAP_BLE_SEC_REQ_EVT"); 223 | #ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig 224 | if(BLEDevice::m_securityCallbacks!=nullptr){ 225 | esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, BLEDevice::m_securityCallbacks->onSecurityRequest()); 226 | } 227 | else{ 228 | esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, true); 229 | } 230 | #endif // CONFIG_BLE_SMP_ENABLE 231 | break; 232 | /* 233 | * 234 | */ 235 | case ESP_GAP_BLE_PASSKEY_NOTIF_EVT: //the app will receive this evt when the IO has Output capability and the peer device IO has Input capability. 236 | //display the passkey number to the user to input it in the peer deivce within 30 seconds 237 | log_i("ESP_GAP_BLE_PASSKEY_NOTIF_EVT"); 238 | #ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig 239 | log_i("passKey = %d", param->ble_security.key_notif.passkey); 240 | if(BLEDevice::m_securityCallbacks!=nullptr){ 241 | BLEDevice::m_securityCallbacks->onPassKeyNotify(param->ble_security.key_notif.passkey); 242 | } 243 | #endif // CONFIG_BLE_SMP_ENABLE 244 | break; 245 | case ESP_GAP_BLE_KEY_EVT: 246 | //shows the ble key type info share with peer device to the user. 247 | log_d("ESP_GAP_BLE_KEY_EVT"); 248 | #ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig 249 | log_i("key type = %s", BLESecurity::esp_key_type_to_str(param->ble_security.ble_key.key_type)); 250 | #endif // CONFIG_BLE_SMP_ENABLE 251 | break; 252 | case ESP_GAP_BLE_AUTH_CMPL_EVT: 253 | log_i("ESP_GAP_BLE_AUTH_CMPL_EVT"); 254 | #ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig 255 | if(BLEDevice::m_securityCallbacks != nullptr){ 256 | BLEDevice::m_securityCallbacks->onAuthenticationComplete(param->ble_security.auth_cmpl); 257 | } 258 | #endif // CONFIG_BLE_SMP_ENABLE 259 | break; 260 | default: { 261 | break; 262 | } 263 | } // switch 264 | 265 | if (BLEDevice::m_pClient != nullptr) { 266 | BLEDevice::m_pClient->handleGAPEvent(event, param); 267 | } 268 | 269 | if (BLEDevice::m_pScan != nullptr) { 270 | BLEDevice::getScan()->handleGAPEvent(event, param); 271 | } 272 | 273 | if(m_bleAdvertising != nullptr) { 274 | BLEDevice::getAdvertising()->handleGAPEvent(event, param); 275 | } 276 | 277 | if(m_customGapHandler != nullptr) { 278 | BLEDevice::m_customGapHandler(event, param); 279 | } 280 | 281 | } // gapEventHandler 282 | 283 | 284 | /** 285 | * @brief Get the BLE device address. 286 | * @return The BLE device address. 287 | */ 288 | /* STATIC*/ BLEAddress BLEDevice::getAddress() { 289 | const uint8_t* bdAddr = esp_bt_dev_get_address(); 290 | esp_bd_addr_t addr; 291 | memcpy(addr, bdAddr, sizeof(addr)); 292 | return BLEAddress(addr); 293 | } // getAddress 294 | 295 | 296 | /** 297 | * @brief Retrieve the Scan object that we use for scanning. 298 | * @return The scanning object reference. This is a singleton object. The caller should not 299 | * try and release/delete it. 300 | */ 301 | /* STATIC */ BLEScan* BLEDevice::getScan() { 302 | //log_v(">> getScan"); 303 | if (m_pScan == nullptr) { 304 | m_pScan = new BLEScan(); 305 | //log_d(" - creating a new scan object"); 306 | } 307 | //log_v("<< getScan: Returning object at 0x%x", (uint32_t)m_pScan); 308 | return m_pScan; 309 | } // getScan 310 | 311 | 312 | /** 313 | * @brief Get the value of a characteristic of a service on a remote device. 314 | * @param [in] bdAddress 315 | * @param [in] serviceUUID 316 | * @param [in] characteristicUUID 317 | */ 318 | /* STATIC */ std::string BLEDevice::getValue(BLEAddress bdAddress, BLEUUID serviceUUID, BLEUUID characteristicUUID) { 319 | log_v(">> getValue: bdAddress: %s, serviceUUID: %s, characteristicUUID: %s", bdAddress.toString().c_str(), serviceUUID.toString().c_str(), characteristicUUID.toString().c_str()); 320 | BLEClient* pClient = createClient(); 321 | pClient->connect(bdAddress); 322 | std::string ret = pClient->getValue(serviceUUID, characteristicUUID); 323 | pClient->disconnect(); 324 | log_v("<< getValue"); 325 | return ret; 326 | } // getValue 327 | 328 | 329 | /** 330 | * @brief Initialize the %BLE environment. 331 | * @param deviceName The device name of the device. 332 | */ 333 | /* STATIC */ void BLEDevice::init(std::string deviceName) { 334 | if(!initialized){ 335 | initialized = true; // Set the initialization flag to ensure we are only initialized once. 336 | 337 | esp_err_t errRc = ESP_OK; 338 | #ifdef ARDUINO_ARCH_ESP32 339 | if (!btStart()) { 340 | errRc = ESP_FAIL; 341 | return; 342 | } 343 | #else 344 | errRc = ::nvs_flash_init(); 345 | if (errRc != ESP_OK) { 346 | log_e("nvs_flash_init: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); 347 | return; 348 | } 349 | 350 | #ifndef CONFIG_BT_CLASSIC_ENABLED 351 | esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT); 352 | #endif 353 | esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); 354 | errRc = esp_bt_controller_init(&bt_cfg); 355 | if (errRc != ESP_OK) { 356 | log_e("esp_bt_controller_init: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); 357 | return; 358 | } 359 | 360 | #ifndef CONFIG_BT_CLASSIC_ENABLED 361 | errRc = esp_bt_controller_enable(ESP_BT_MODE_BLE); 362 | if (errRc != ESP_OK) { 363 | log_e("esp_bt_controller_enable: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); 364 | return; 365 | } 366 | #else 367 | errRc = esp_bt_controller_enable(ESP_BT_MODE_BTDM); 368 | if (errRc != ESP_OK) { 369 | log_e("esp_bt_controller_enable: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); 370 | return; 371 | } 372 | #endif 373 | #endif 374 | 375 | esp_bluedroid_status_t bt_state = esp_bluedroid_get_status(); 376 | if (bt_state == ESP_BLUEDROID_STATUS_UNINITIALIZED) { 377 | errRc = esp_bluedroid_init(); 378 | if (errRc != ESP_OK) { 379 | log_e("esp_bluedroid_init: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); 380 | return; 381 | } 382 | } 383 | 384 | if (bt_state != ESP_BLUEDROID_STATUS_ENABLED) { 385 | errRc = esp_bluedroid_enable(); 386 | if (errRc != ESP_OK) { 387 | log_e("esp_bluedroid_enable: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); 388 | return; 389 | } 390 | } 391 | 392 | errRc = esp_ble_gap_register_callback(BLEDevice::gapEventHandler); 393 | if (errRc != ESP_OK) { 394 | log_e("esp_ble_gap_register_callback: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); 395 | return; 396 | } 397 | 398 | #ifdef CONFIG_GATTC_ENABLE // Check that BLE client is configured in make menuconfig 399 | errRc = esp_ble_gattc_register_callback(BLEDevice::gattClientEventHandler); 400 | if (errRc != ESP_OK) { 401 | log_e("esp_ble_gattc_register_callback: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); 402 | return; 403 | } 404 | #endif // CONFIG_GATTC_ENABLE 405 | 406 | #ifdef CONFIG_GATTS_ENABLE // Check that BLE server is configured in make menuconfig 407 | errRc = esp_ble_gatts_register_callback(BLEDevice::gattServerEventHandler); 408 | if (errRc != ESP_OK) { 409 | log_e("esp_ble_gatts_register_callback: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); 410 | return; 411 | } 412 | #endif // CONFIG_GATTS_ENABLE 413 | 414 | errRc = ::esp_ble_gap_set_device_name(deviceName.c_str()); 415 | if (errRc != ESP_OK) { 416 | log_e("esp_ble_gap_set_device_name: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); 417 | return; 418 | }; 419 | 420 | #ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig 421 | esp_ble_io_cap_t iocap = ESP_IO_CAP_NONE; 422 | errRc = ::esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(uint8_t)); 423 | if (errRc != ESP_OK) { 424 | log_e("esp_ble_gap_set_security_param: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); 425 | return; 426 | }; 427 | #endif // CONFIG_BLE_SMP_ENABLE 428 | } 429 | vTaskDelay(200 / portTICK_PERIOD_MS); // Delay for 200 msecs as a workaround to an apparent Arduino environment issue. 430 | } // init 431 | 432 | 433 | /** 434 | * @brief Set the transmission power. 435 | * The power level can be one of: 436 | * * ESP_PWR_LVL_N14 437 | * * ESP_PWR_LVL_N11 438 | * * ESP_PWR_LVL_N8 439 | * * ESP_PWR_LVL_N5 440 | * * ESP_PWR_LVL_N2 441 | * * ESP_PWR_LVL_P1 442 | * * ESP_PWR_LVL_P4 443 | * * ESP_PWR_LVL_P7 444 | * 445 | * The power types can be one of: 446 | * * ESP_BLE_PWR_TYPE_CONN_HDL0 447 | * * ESP_BLE_PWR_TYPE_CONN_HDL1 448 | * * ESP_BLE_PWR_TYPE_CONN_HDL2 449 | * * ESP_BLE_PWR_TYPE_CONN_HDL3 450 | * * ESP_BLE_PWR_TYPE_CONN_HDL4 451 | * * ESP_BLE_PWR_TYPE_CONN_HDL5 452 | * * ESP_BLE_PWR_TYPE_CONN_HDL6 453 | * * ESP_BLE_PWR_TYPE_CONN_HDL7 454 | * * ESP_BLE_PWR_TYPE_CONN_HDL8 455 | * * ESP_BLE_PWR_TYPE_ADV 456 | * * ESP_BLE_PWR_TYPE_SCAN 457 | * * ESP_BLE_PWR_TYPE_DEFAULT 458 | * @param [in] powerType. 459 | * @param [in] powerLevel. 460 | */ 461 | /* STATIC */ void BLEDevice::setPower(esp_power_level_t powerLevel, esp_ble_power_type_t powerType) { 462 | log_v(">> setPower: %d (type: %d)", powerLevel, powerType); 463 | esp_err_t errRc = ::esp_ble_tx_power_set(powerType, powerLevel); 464 | if (errRc != ESP_OK) { 465 | log_e("esp_ble_tx_power_set: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); 466 | }; 467 | log_v("<< setPower"); 468 | } // setPower 469 | 470 | 471 | /** 472 | * @brief Set the value of a characteristic of a service on a remote device. 473 | * @param [in] bdAddress 474 | * @param [in] serviceUUID 475 | * @param [in] characteristicUUID 476 | */ 477 | /* STATIC */ void BLEDevice::setValue(BLEAddress bdAddress, BLEUUID serviceUUID, BLEUUID characteristicUUID, std::string value) { 478 | log_v(">> setValue: bdAddress: %s, serviceUUID: %s, characteristicUUID: %s", bdAddress.toString().c_str(), serviceUUID.toString().c_str(), characteristicUUID.toString().c_str()); 479 | BLEClient* pClient = createClient(); 480 | pClient->connect(bdAddress); 481 | pClient->setValue(serviceUUID, characteristicUUID, value); 482 | pClient->disconnect(); 483 | } // setValue 484 | 485 | 486 | /** 487 | * @brief Return a string representation of the nature of this device. 488 | * @return A string representation of the nature of this device. 489 | */ 490 | /* STATIC */ std::string BLEDevice::toString() { 491 | std::string res = "BD Address: " + getAddress().toString(); 492 | return res; 493 | } // toString 494 | 495 | 496 | /** 497 | * @brief Add an entry to the BLE white list. 498 | * @param [in] address The address to add to the white list. 499 | */ 500 | void BLEDevice::whiteListAdd(BLEAddress address) { 501 | log_v(">> whiteListAdd: %s", address.toString().c_str()); 502 | #ifdef ESP_IDF_VERSION_MAJOR 503 | esp_err_t errRc = esp_ble_gap_update_whitelist(true, *address.getNative(), BLE_WL_ADDR_TYPE_PUBLIC); // HACK!!! True to add an entry. 504 | #else 505 | esp_err_t errRc = esp_ble_gap_update_whitelist(true, *address.getNative()); // True to add an entry. 506 | #endif 507 | if (errRc != ESP_OK) { 508 | log_e("esp_ble_gap_update_whitelist: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); 509 | } 510 | log_v("<< whiteListAdd"); 511 | } // whiteListAdd 512 | 513 | 514 | /** 515 | * @brief Remove an entry from the BLE white list. 516 | * @param [in] address The address to remove from the white list. 517 | */ 518 | void BLEDevice::whiteListRemove(BLEAddress address) { 519 | log_v(">> whiteListRemove: %s", address.toString().c_str()); 520 | #ifdef ESP_IDF_VERSION_MAJOR 521 | esp_err_t errRc = esp_ble_gap_update_whitelist(false, *address.getNative(), BLE_WL_ADDR_TYPE_PUBLIC); // HACK!!! False to remove an entry. 522 | #else 523 | esp_err_t errRc = esp_ble_gap_update_whitelist(false, *address.getNative()); // False to remove an entry. 524 | #endif 525 | if (errRc != ESP_OK) { 526 | log_e("esp_ble_gap_update_whitelist: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); 527 | } 528 | log_v("<< whiteListRemove"); 529 | } // whiteListRemove 530 | 531 | /* 532 | * @brief Set encryption level that will be negotiated with peer device durng connection 533 | * @param [in] level Requested encryption level 534 | */ 535 | void BLEDevice::setEncryptionLevel(esp_ble_sec_act_t level) { 536 | BLEDevice::m_securityLevel = level; 537 | } 538 | 539 | /* 540 | * @brief Set callbacks that will be used to handle encryption negotiation events and authentication events 541 | * @param [in] cllbacks Pointer to BLESecurityCallbacks class callback 542 | */ 543 | void BLEDevice::setSecurityCallbacks(BLESecurityCallbacks* callbacks) { 544 | BLEDevice::m_securityCallbacks = callbacks; 545 | } 546 | 547 | /* 548 | * @brief Setup local mtu that will be used to negotiate mtu during request from client peer 549 | * @param [in] mtu Value to set local mtu, should be larger than 23 and lower or equal to 517 550 | */ 551 | esp_err_t BLEDevice::setMTU(uint16_t mtu) { 552 | log_v(">> setLocalMTU: %d", mtu); 553 | esp_err_t err = esp_ble_gatt_set_local_mtu(mtu); 554 | if (err == ESP_OK) { 555 | m_localMTU = mtu; 556 | } else { 557 | log_e("can't set local mtu value: %d", mtu); 558 | } 559 | log_v("<< setLocalMTU"); 560 | return err; 561 | } 562 | 563 | /* 564 | * @brief Get local MTU value set during mtu request or default value 565 | */ 566 | uint16_t BLEDevice::getMTU() { 567 | return m_localMTU; 568 | } 569 | 570 | bool BLEDevice::getInitialized() { 571 | return initialized; 572 | } 573 | 574 | BLEAdvertising* BLEDevice::getAdvertising() { 575 | if(m_bleAdvertising == nullptr) { 576 | m_bleAdvertising = new BLEAdvertising(); 577 | log_i("create advertising"); 578 | } 579 | log_d("get advertising"); 580 | return m_bleAdvertising; 581 | } 582 | 583 | void BLEDevice::startAdvertising() { 584 | log_v(">> startAdvertising"); 585 | getAdvertising()->start(); 586 | log_v("<< startAdvertising"); 587 | } // startAdvertising 588 | 589 | void BLEDevice::startAdvertisingDirected(std::string stringAddress) { 590 | log_v(">> startAdvertising"); 591 | BLEAdvertising* advertisement = getAdvertising(); 592 | advertisement->directed_advertisement(stringAddress); 593 | advertisement->start(); 594 | log_v("<< startAdvertising"); 595 | } // startAdvertising 596 | 597 | void BLEDevice::startAdvertisingWithManufData(uint8_t *manuf_data) { 598 | log_v(">> startAdvertising"); 599 | BLEAdvertising* advertisement = getAdvertising(); 600 | advertisement->wake_advertisement(manuf_data); 601 | advertisement->start(); 602 | log_v("<< startAdvertising"); 603 | } // startAdvertising 604 | 605 | void BLEDevice::stopAdvertising() { 606 | log_v(">> stopAdvertising"); 607 | getAdvertising()->stop(); 608 | log_v("<< stopAdvertising"); 609 | } // stopAdvertising 610 | 611 | /* multi connect support */ 612 | /* requires a little more work */ 613 | std::map BLEDevice::getPeerDevices(bool _client) { 614 | return m_connectedClientsMap; 615 | } 616 | 617 | BLEClient* BLEDevice::getClientByGattIf(uint16_t conn_id) { 618 | return (BLEClient*)m_connectedClientsMap.find(conn_id)->second.peer_device; 619 | } 620 | 621 | void BLEDevice::updatePeerDevice(void* peer, bool _client, uint16_t conn_id) { 622 | log_d("update conn_id: %d, GATT role: %s", conn_id, _client? "client":"server"); 623 | std::map::iterator it = m_connectedClientsMap.find(ESP_GATT_IF_NONE); 624 | if (it != m_connectedClientsMap.end()) { 625 | std::swap(m_connectedClientsMap[conn_id], it->second); 626 | m_connectedClientsMap.erase(it); 627 | }else{ 628 | it = m_connectedClientsMap.find(conn_id); 629 | if (it != m_connectedClientsMap.end()) { 630 | conn_status_t _st = it->second; 631 | _st.peer_device = peer; 632 | std::swap(m_connectedClientsMap[conn_id], _st); 633 | } 634 | } 635 | } 636 | 637 | void BLEDevice::addPeerDevice(void* peer, bool _client, uint16_t conn_id) { 638 | log_i("add conn_id: %d, GATT role: %s", conn_id, _client? "client":"server"); 639 | conn_status_t status = { 640 | .peer_device = peer, 641 | .connected = true, 642 | .mtu = 23 643 | }; 644 | 645 | m_connectedClientsMap.insert(std::pair(conn_id, status)); 646 | } 647 | 648 | //there may have some situation that invoking this function simultaneously, that will cause CORRUPT HEAP 649 | //let this function serializable 650 | portMUX_TYPE BLEDevice::mux = portMUX_INITIALIZER_UNLOCKED; 651 | void BLEDevice::removePeerDevice(uint16_t conn_id, bool _client) { 652 | portENTER_CRITICAL(&mux); 653 | log_i("remove: %d, GATT role %s", conn_id, _client?"client":"server"); 654 | if(m_connectedClientsMap.find(conn_id) != m_connectedClientsMap.end()) 655 | m_connectedClientsMap.erase(conn_id); 656 | portEXIT_CRITICAL(&mux); 657 | } 658 | 659 | /* multi connect support */ 660 | 661 | /** 662 | * @brief de-Initialize the %BLE environment. 663 | * @param release_memory release the internal BT stack memory 664 | */ 665 | /* STATIC */ void BLEDevice::deinit(bool release_memory) { 666 | if (!initialized) return; 667 | 668 | esp_bluedroid_disable(); 669 | esp_bluedroid_deinit(); 670 | esp_bt_controller_disable(); 671 | esp_bt_controller_deinit(); 672 | #ifdef ARDUINO_ARCH_ESP32 673 | if (release_memory) { 674 | esp_bt_controller_mem_release(ESP_BT_MODE_BTDM); // <-- require tests because we released classic BT memory and this can cause crash (most likely not, esp-idf takes care of it) 675 | } else { 676 | initialized = false; 677 | } 678 | #endif 679 | } 680 | 681 | void BLEDevice::setCustomGapHandler(gap_event_handler handler) { 682 | m_customGapHandler = handler; 683 | } 684 | 685 | void BLEDevice::setCustomGattcHandler(gattc_event_handler handler) { 686 | m_customGattcHandler = handler; 687 | } 688 | 689 | void BLEDevice::setCustomGattsHandler(gatts_event_handler handler) { 690 | m_customGattsHandler = handler; 691 | } 692 | 693 | #endif // CONFIG_BLUEDROID_ENABLED 694 | -------------------------------------------------------------------------------- /edited_esp_lib_files/BLEDevice.h: -------------------------------------------------------------------------------- 1 | /* 2 | * BLEDevice.h 3 | * 4 | * Created on: Mar 16, 2017 5 | * Author: kolban 6 | */ 7 | 8 | #ifndef MAIN_BLEDevice_H_ 9 | #define MAIN_BLEDevice_H_ 10 | #include "sdkconfig.h" 11 | #if defined(CONFIG_BLUEDROID_ENABLED) 12 | #include // ESP32 BLE 13 | #include // ESP32 BLE 14 | #include // Part of C++ STL 15 | #include 16 | #include 17 | 18 | #include "BLEServer.h" 19 | #include "BLEClient.h" 20 | #include "BLEUtils.h" 21 | #include "BLEScan.h" 22 | #include "BLEAddress.h" 23 | 24 | /** 25 | * @brief BLE functions. 26 | */ 27 | typedef void (*gap_event_handler)(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t* param); 28 | typedef void (*gattc_event_handler)(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t* param); 29 | typedef void (*gatts_event_handler)(esp_gatts_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gatts_cb_param_t* param); 30 | 31 | class BLEDevice { 32 | public: 33 | 34 | static BLEClient* createClient(); // Create a new BLE client. 35 | static BLEServer* createServer(); // Cretae a new BLE server. 36 | static BLEAddress getAddress(); // Retrieve our own local BD address. 37 | static BLEScan* getScan(); // Get the scan object 38 | static std::string getValue(BLEAddress bdAddress, BLEUUID serviceUUID, BLEUUID characteristicUUID); // Get the value of a characteristic of a service on a server. 39 | static void init(std::string deviceName); // Initialize the local BLE environment. 40 | static void setPower(esp_power_level_t powerLevel, esp_ble_power_type_t powerType=ESP_BLE_PWR_TYPE_DEFAULT); // Set our power level. 41 | static void setValue(BLEAddress bdAddress, BLEUUID serviceUUID, BLEUUID characteristicUUID, std::string value); // Set the value of a characteristic on a service on a server. 42 | static std::string toString(); // Return a string representation of our device. 43 | static void whiteListAdd(BLEAddress address); // Add an entry to the BLE white list. 44 | static void whiteListRemove(BLEAddress address); // Remove an entry from the BLE white list. 45 | static void setEncryptionLevel(esp_ble_sec_act_t level); 46 | static void setSecurityCallbacks(BLESecurityCallbacks* pCallbacks); 47 | static esp_err_t setMTU(uint16_t mtu); 48 | static uint16_t getMTU(); 49 | static bool getInitialized(); // Returns the state of the device, is it initialized or not? 50 | /* move advertising to BLEDevice for saving ram and flash in beacons */ 51 | static BLEAdvertising* getAdvertising(); 52 | static void startAdvertising(); 53 | static void startAdvertisingDirected(std::string stringAddress); 54 | static void startAdvertisingWithManufData(uint8_t *manuf_data) ; 55 | static void stopAdvertising(); 56 | static uint16_t m_appId; 57 | /* multi connect */ 58 | static std::map getPeerDevices(bool client); 59 | static void addPeerDevice(void* peer, bool is_client, uint16_t conn_id); 60 | static void updatePeerDevice(void* peer, bool _client, uint16_t conn_id); 61 | static void removePeerDevice(uint16_t conn_id, bool client); 62 | static BLEClient* getClientByGattIf(uint16_t conn_id); 63 | static void setCustomGapHandler(gap_event_handler handler); 64 | static void setCustomGattcHandler(gattc_event_handler handler); 65 | static void setCustomGattsHandler(gatts_event_handler handler); 66 | static void deinit(bool release_memory = false); 67 | static uint16_t m_localMTU; 68 | static esp_ble_sec_act_t m_securityLevel; 69 | 70 | private: 71 | static BLEServer* m_pServer; 72 | static BLEScan* m_pScan; 73 | static BLEClient* m_pClient; 74 | static BLESecurityCallbacks* m_securityCallbacks; 75 | static BLEAdvertising* m_bleAdvertising; 76 | static esp_gatt_if_t getGattcIF(); 77 | static std::map m_connectedClientsMap; 78 | static portMUX_TYPE mux; 79 | 80 | static void gattClientEventHandler( 81 | esp_gattc_cb_event_t event, 82 | esp_gatt_if_t gattc_if, 83 | esp_ble_gattc_cb_param_t* param); 84 | 85 | static void gattServerEventHandler( 86 | esp_gatts_cb_event_t event, 87 | esp_gatt_if_t gatts_if, 88 | esp_ble_gatts_cb_param_t* param); 89 | 90 | static void gapEventHandler( 91 | esp_gap_ble_cb_event_t event, 92 | esp_ble_gap_cb_param_t* param); 93 | 94 | public: 95 | /* custom gap and gatt handlers for flexibility */ 96 | static gap_event_handler m_customGapHandler; 97 | static gattc_event_handler m_customGattcHandler; 98 | static gatts_event_handler m_customGattsHandler; 99 | 100 | }; // class BLE 101 | 102 | #endif // CONFIG_BLUEDROID_ENABLED 103 | #endif /* MAIN_BLEDevice_H_ */ 104 | --------------------------------------------------------------------------------