diff --git a/libraries/BLE/examples/BLE5_extended_scan/.skip.esp32 b/libraries/BLE/examples/BLE5_extended_scan/.skip.esp32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/BLE/examples/BLE5_extended_scan/.skip.esp32s2 b/libraries/BLE/examples/BLE5_extended_scan/.skip.esp32s2 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/BLE/examples/BLE5_extended_scan/BLE5_extended_scan.ino b/libraries/BLE/examples/BLE5_extended_scan/BLE5_extended_scan.ino new file mode 100644 index 00000000000..c2ff2ec8a52 --- /dev/null +++ b/libraries/BLE/examples/BLE5_extended_scan/BLE5_extended_scan.ino @@ -0,0 +1,69 @@ +/* + BLE5 extended scan example for esp32 C3 and S3 + with this code it is simple to scan legacy (BLE4) compatible advertising, + and BLE5 extended advertising. New coded added in BLEScan is not changing old behavior, + which can be used with old esp32, but is adding functionality to use on C3/S3. + With this new API advertised device wont be stored in API, it is now user responsibility + + author: chegewara +*/ +#ifndef CONFIG_BT_BLE_50_FEATURES_SUPPORTED +#warning "Not compatible hardware" +#else +#include +#include +#include +#include + +uint32_t scanTime = 100; //In 10ms (1000ms) +BLEScan* pBLEScan; + +/** +* @brief extend adv report parameters +*/ +//typedef struct { +// esp_ble_gap_adv_type_t event_type; /*!< extend advertising type */ +// uint8_t addr_type; /*!< extend advertising address type */ +// esp_bd_addr_t addr; /*!< extend advertising address */ +// esp_ble_gap_pri_phy_t primary_phy; /*!< extend advertising primary phy */ +// esp_ble_gap_phy_t secondly_phy; /*!< extend advertising secondary phy */ +// uint8_t sid; /*!< extend advertising sid */ +// uint8_t tx_power; /*!< extend advertising tx power */ +// int8_t rssi; /*!< extend advertising rssi */ +// uint16_t per_adv_interval; /*!< periodic advertising interval */ +// uint8_t dir_addr_type; /*!< direct address type */ +// esp_bd_addr_t dir_addr; /*!< direct address */ +// esp_ble_gap_ext_adv_data_status_t data_status; /*!< data type */ +// uint8_t adv_data_len; /*!< extend advertising data length */ +// uint8_t adv_data[251]; /*!< extend advertising data */ +//} esp_ble_gap_ext_adv_reprot_t; + +class MyBLEExtAdvertisingCallbacks: public BLEExtAdvertisingCallbacks { + void onResult(esp_ble_gap_ext_adv_reprot_t report) { + if(report.event_type & ESP_BLE_GAP_SET_EXT_ADV_PROP_LEGACY){ + // here we can receive regular advertising data from BLE4.x devices + Serial.println("BLE4.2"); + } else { + // here we will get extended advertising data that are advertised over data channel by BLE5 divices + Serial.printf("Ext advertise: data_le: %d, data_status: %d \n", report.adv_data_len, report.data_status); + } + } +}; + +void setup() { + Serial.begin(115200); + Serial.println("Scanning..."); + + BLEDevice::init(""); + pBLEScan = BLEDevice::getScan(); //create new scan + pBLEScan->setExtendedScanCallback(new MyBLEExtAdvertisingCallbacks()); + pBLEScan->setExtScanParams(); // use with pre-defined/default values, overloaded function allows to pass parameters + delay(1000); // it is just for simplicity this example, to let ble stack to set extended scan params + pBLEScan->startExtScan(scanTime, 3); // scan duration in n * 10ms, period - repeat after n seconds (period >= duration) +} + +void loop() { + // put your main code here, to run repeatedly: + delay(2000); +} +#endif // CONFIG_BT_BLE_50_FEATURES_SUPPORTED diff --git a/libraries/BLE/examples/BLE5_multi_advertising/.skip.esp32 b/libraries/BLE/examples/BLE5_multi_advertising/.skip.esp32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/BLE/examples/BLE5_multi_advertising/.skip.esp32s2 b/libraries/BLE/examples/BLE5_multi_advertising/.skip.esp32s2 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/BLE/examples/BLE5_multi_advertising/BLE5_multi_advertising.ino b/libraries/BLE/examples/BLE5_multi_advertising/BLE5_multi_advertising.ino new file mode 100644 index 00000000000..217c2ed3bc4 --- /dev/null +++ b/libraries/BLE/examples/BLE5_multi_advertising/BLE5_multi_advertising.ino @@ -0,0 +1,142 @@ +/* + Simple BLE5 multi advertising example on esp32 C3/S3 + only ESP_BLE_GAP_SET_EXT_ADV_PROP_LEGACY_IND is backward compatible + and can be scanned with BLE4.2 devices + + author: chegewara +*/ + +#include +#include + +esp_ble_gap_ext_adv_params_t ext_adv_params_1M = { + .type = ESP_BLE_GAP_SET_EXT_ADV_PROP_CONNECTABLE, + .interval_min = 0x30, + .interval_max = 0x30, + .channel_map = ADV_CHNL_ALL, + .own_addr_type = BLE_ADDR_TYPE_RANDOM, + .filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, + .primary_phy = ESP_BLE_GAP_PHY_CODED, + .max_skip = 0, + .secondary_phy = ESP_BLE_GAP_PHY_1M, + .sid = 0, + .scan_req_notif = false, +}; + +esp_ble_gap_ext_adv_params_t ext_adv_params_2M = { + .type = ESP_BLE_GAP_SET_EXT_ADV_PROP_SCANNABLE, + .interval_min = 0x40, + .interval_max = 0x40, + .channel_map = ADV_CHNL_ALL, + .own_addr_type = BLE_ADDR_TYPE_RANDOM, + .filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, + .primary_phy = ESP_BLE_GAP_PHY_1M, + .max_skip = 0, + .secondary_phy = ESP_BLE_GAP_PHY_2M, + .sid = 1, + .scan_req_notif = false, +}; + +esp_ble_gap_ext_adv_params_t legacy_adv_params = { + .type = ESP_BLE_GAP_SET_EXT_ADV_PROP_LEGACY_IND, + .interval_min = 0x45, + .interval_max = 0x45, + .channel_map = ADV_CHNL_ALL, + .own_addr_type = BLE_ADDR_TYPE_RANDOM, + .filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, + .primary_phy = ESP_BLE_GAP_PHY_1M, + .max_skip = 0, + .secondary_phy = ESP_BLE_GAP_PHY_1M, + .sid = 2, + .scan_req_notif = false, +}; + +esp_ble_gap_ext_adv_params_t ext_adv_params_coded = { + .type = ESP_BLE_GAP_SET_EXT_ADV_PROP_SCANNABLE, + .interval_min = 0x50, + .interval_max = 0x50, + .channel_map = ADV_CHNL_ALL, + .own_addr_type = BLE_ADDR_TYPE_RANDOM, + .filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, + .primary_phy = ESP_BLE_GAP_PHY_1M, + .max_skip = 0, + .secondary_phy = ESP_BLE_GAP_PHY_CODED, + .sid = 3, + .scan_req_notif = false, +}; + +static uint8_t raw_adv_data_1m[] = { + 0x02, 0x01, 0x06, + 0x02, 0x0a, 0xeb, + 0x12, 0x09, 'E', 'S', 'P', '_', 'M', 'U', 'L', 'T', 'I', '_', 'A', + 'D', 'V', '_', '1', 'M', 0X0 +}; + +static uint8_t raw_scan_rsp_data_2m[] = { + 0x02, 0x01, 0x06, + 0x02, 0x0a, 0xeb, + 0x12, 0x09, 'E', 'S', 'P', '_', 'M', 'U', 'L', 'T', 'I', '_', 'A', + 'D', 'V', '_', '2', 'M', 0X0 +}; + +static uint8_t legacy_adv_data[] = { + 0x02, 0x01, 0x06, + 0x02, 0x0a, 0xeb, + 0x15, 0x09, 'E', 'S', 'P', '_', 'M', 'U', 'L', 'T', 'I', '_', 'A', + 'D', 'V', '_', 'C', 'O', 'D', 'E', 'D', 0X0 +}; + +static uint8_t legacy_scan_rsp_data[] = { + 0x02, 0x01, 0x06, + 0x02, 0x0a, 0xeb, + 0x16, 0x09, 'E', 'S', 'P', '_', 'M', 'U', 'L', 'T', 'I', '_', 'A', + 'D', 'V', '_', 'L', 'E', 'G', 'A', 'C', 'Y', 0X0 +}; + +static uint8_t raw_scan_rsp_data_coded[] = { + 0x37, 0x09, 'V', 'E', 'R', 'Y', '_', 'L', 'O', 'N', 'G', '_', 'D', 'E', 'V', 'I', 'C', 'E', '_', 'N', 'A', 'M', 'E', '_', + 'S', 'E', 'N', 'T', '_', 'U', 'S', 'I', 'N', 'G', '_', 'E', 'X', 'T', 'E', 'N', 'D', 'E', 'D', '_', 'A', 'D', 'V', 'E', 'R', 'T', 'I', 'S', 'I', 'N', 'G', 0X0 +}; + + +uint8_t addr_1m[6] = {0xc0, 0xde, 0x52, 0x00, 0x00, 0x01}; +uint8_t addr_2m[6] = {0xc0, 0xde, 0x52, 0x00, 0x00, 0x02}; +uint8_t addr_legacy[6] = {0xc0, 0xde, 0x52, 0x00, 0x00, 0x03}; +uint8_t addr_coded[6] = {0xc0, 0xde, 0x52, 0x00, 0x00, 0x04}; + +BLEMultiAdvertising advert(4); // max number of advertisement data + +void setup() { + Serial.begin(115200); + Serial.println("Multi-Advertising..."); + + BLEDevice::init(""); + + advert.setAdvertisingParams(0, &ext_adv_params_1M); + advert.setAdvertisingData(0, sizeof(raw_adv_data_1m), &raw_adv_data_1m[0]); + advert.setInstanceAddress(0, addr_1m); + advert.setDuration(0); + + advert.setAdvertisingParams(1, &ext_adv_params_2M); + advert.setScanRspData(1, sizeof(raw_scan_rsp_data_2m), &raw_scan_rsp_data_2m[0]); + advert.setInstanceAddress(1, addr_2m); + advert.setDuration(1); + + advert.setAdvertisingParams(2, &legacy_adv_params); + advert.setAdvertisingData(2, sizeof(legacy_adv_data), &legacy_adv_data[0]); + advert.setScanRspData(2, sizeof(legacy_scan_rsp_data), &legacy_scan_rsp_data[0]); + advert.setInstanceAddress(2, addr_legacy); + advert.setDuration(2); + + advert.setAdvertisingParams(3, &ext_adv_params_coded); + advert.setDuration(3); + advert.setScanRspData(3, sizeof(raw_scan_rsp_data_coded), &raw_scan_rsp_data_coded[0]); + advert.setInstanceAddress(3, addr_coded); + + delay(1000); + advert.start(4, 0); +} + +void loop() { + delay(2000); +} diff --git a/libraries/BLE/examples/BLE5_periodic_advertising/.skip.esp32 b/libraries/BLE/examples/BLE5_periodic_advertising/.skip.esp32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/BLE/examples/BLE5_periodic_advertising/.skip.esp32s2 b/libraries/BLE/examples/BLE5_periodic_advertising/.skip.esp32s2 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/BLE/examples/BLE5_periodic_advertising/BLE5_periodic_advertising.ino b/libraries/BLE/examples/BLE5_periodic_advertising/BLE5_periodic_advertising.ino new file mode 100644 index 00000000000..1b36bbb8b54 --- /dev/null +++ b/libraries/BLE/examples/BLE5_periodic_advertising/BLE5_periodic_advertising.ino @@ -0,0 +1,72 @@ +/* + Simple BLE5 multi advertising example on esp32 C3/S3 + only ESP_BLE_GAP_SET_EXT_ADV_PROP_NONCONN_NONSCANNABLE_UNDIRECTED can be used for periodic advertising + + author: chegewara +*/ + +#include +#include + + +esp_ble_gap_ext_adv_params_t ext_adv_params_2M = { + .type = ESP_BLE_GAP_SET_EXT_ADV_PROP_NONCONN_NONSCANNABLE_UNDIRECTED, + .interval_min = 0x40, + .interval_max = 0x40, + .channel_map = ADV_CHNL_ALL, + .own_addr_type = BLE_ADDR_TYPE_RANDOM, + .filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, + .primary_phy = ESP_BLE_GAP_PHY_1M, + .max_skip = 0, + .secondary_phy = ESP_BLE_GAP_PHY_2M, + .sid = 1, + .scan_req_notif = false, +}; + +static uint8_t raw_scan_rsp_data_2m[] = { + 0x02, 0x01, 0x06, + 0x02, 0x0a, 0xeb, + 0x12, 0x09, 'E', 'S', 'P', '_', 'M', 'U', 'L', 'T', 'I', '_', 'A', + 'D', 'V', '_', '2', 'M', 0X0 +}; + +static esp_ble_gap_periodic_adv_params_t periodic_adv_params = { + .interval_min = 0x320, // 1000 ms interval + .interval_max = 0x640, + .properties = 0, // Do not include TX power +}; + +static uint8_t periodic_adv_raw_data[] = { + 0x02, 0x01, 0x06, + 0x02, 0x0a, 0xeb, + 0x03, 0x03, 0xab, 0xcd, + 0x11, 0x09, 'E', 'S', 'P', '_', 'P', 'E', 'R', 'I', 'O', 'D', 'I', + 'C', '_', 'A', 'D', 'V' +}; + + +uint8_t addr_2m[6] = {0xc0, 0xde, 0x52, 0x00, 0x00, 0x02}; + +BLEMultiAdvertising advert(1); // max number of advertisement data + +void setup() { + Serial.begin(115200); + Serial.println("Multi-Advertising..."); + + BLEDevice::init(""); + + advert.setAdvertisingParams(0, &ext_adv_params_2M); + advert.setAdvertisingData(0, sizeof(raw_scan_rsp_data_2m), &raw_scan_rsp_data_2m[0]); + advert.setInstanceAddress(0, addr_2m); + advert.setDuration(0, 0, 0); + + delay(100); + advert.start(); + advert.setPeriodicAdvertisingParams(0, &periodic_adv_params); + advert.setPeriodicAdvertisingData(0, sizeof(periodic_adv_raw_data), &periodic_adv_raw_data[0]); + advert.startPeriodicAdvertising(0); +} + +void loop() { + delay(2000); +} diff --git a/libraries/BLE/examples/BLE5_periodic_sync/.skip.esp32 b/libraries/BLE/examples/BLE5_periodic_sync/.skip.esp32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/BLE/examples/BLE5_periodic_sync/.skip.esp32s2 b/libraries/BLE/examples/BLE5_periodic_sync/.skip.esp32s2 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/BLE/examples/BLE5_periodic_sync/BLE5_periodic_sync.ino b/libraries/BLE/examples/BLE5_periodic_sync/BLE5_periodic_sync.ino new file mode 100644 index 00000000000..fdc25b394a2 --- /dev/null +++ b/libraries/BLE/examples/BLE5_periodic_sync/BLE5_periodic_sync.ino @@ -0,0 +1,127 @@ +/* + BLE5 extended scan example for esp32 C3 and S3 + with this code it is simple to scan legacy (BLE4) compatible advertising, + and BLE5 extended advertising. New coded added in BLEScan is not changing old behavior, + which can be used with old esp32, but is adding functionality to use on C3/S3. + With this new API advertised device wont be stored in API, it is now user responsibility + + author: chegewara +*/ +#ifndef CONFIG_BT_BLE_50_FEATURES_SUPPORTED +#warning "Not compatible hardware" +#else +#include +#include +#include + +BLEScan *pBLEScan; +static bool periodic_sync = false; + +static esp_ble_gap_periodic_adv_sync_params_t periodic_adv_sync_params = { + .filter_policy = 0, + .sid = 0, + .addr_type = BLE_ADDR_TYPE_RANDOM, + .skip = 10, + .sync_timeout = 1000, // timeout: 1000 * 10ms +}; + +/** +* @brief extend adv report parameters +*/ +//typedef struct { +// esp_ble_gap_adv_type_t event_type; /*!< extend advertising type */ +// uint8_t addr_type; /*!< extend advertising address type */ +// esp_bd_addr_t addr; /*!< extend advertising address */ +// esp_ble_gap_pri_phy_t primary_phy; /*!< extend advertising primary phy */ +// esp_ble_gap_phy_t secondly_phy; /*!< extend advertising secondary phy */ +// uint8_t sid; /*!< extend advertising sid */ +// uint8_t tx_power; /*!< extend advertising tx power */ +// int8_t rssi; /*!< extend advertising rssi */ +// uint16_t per_adv_interval; /*!< periodic advertising interval */ +// uint8_t dir_addr_type; /*!< direct address type */ +// esp_bd_addr_t dir_addr; /*!< direct address */ +// esp_ble_gap_ext_adv_data_status_t data_status; /*!< data type */ +// uint8_t adv_data_len; /*!< extend advertising data length */ +// uint8_t adv_data[251]; /*!< extend advertising data */ +//} esp_ble_gap_ext_adv_reprot_t; + +class MyBLEExtAdvertisingCallbacks : public BLEExtAdvertisingCallbacks +{ + void onResult(esp_ble_gap_ext_adv_reprot_t params) + { + uint8_t *adv_name = NULL; + uint8_t adv_name_len = 0; + adv_name = esp_ble_resolve_adv_data(params.adv_data, ESP_BLE_AD_TYPE_NAME_CMPL, &adv_name_len); + if ((adv_name != NULL) && (memcmp(adv_name, "ESP_MULTI_ADV_2M", adv_name_len) == 0) && !periodic_sync) + { + periodic_sync = true; + char adv_temp_name[60] = {'0'}; + memcpy(adv_temp_name, adv_name, adv_name_len); + log_i("Start create sync with the peer device %s", adv_temp_name); + periodic_adv_sync_params.sid = params.sid; + // periodic_adv_sync_params.addr_type = params.addr_type; + memcpy(periodic_adv_sync_params.addr, params.addr, sizeof(esp_bd_addr_t)); + esp_ble_gap_periodic_adv_create_sync(&periodic_adv_sync_params); + } + } +}; + +class MyPeriodicScan : public BLEPeriodicScanCallbacks +{ + // void onCreateSync(esp_bt_status_t status){} + // void onCancelSync(esp_bt_status_t status){} + // void onTerminateSync(esp_bt_status_t status){} + + void onStop(esp_bt_status_t status) + { + log_i("ESP_GAP_BLE_EXT_SCAN_STOP_COMPLETE_EVT"); + periodic_sync = false; + pBLEScan->startExtScan(0, 0); // scan duration in n * 10ms, period - repeat after n seconds (period >= duration) + } + + void onLostSync(uint16_t sync_handle) + { + log_i("ESP_GAP_BLE_PERIODIC_ADV_SYNC_LOST_EVT"); + esp_ble_gap_stop_ext_scan(); + } + + void onSync(esp_ble_periodic_adv_sync_estab_param_t params) + { + log_i("ESP_GAP_BLE_PERIODIC_ADV_SYNC_ESTAB_EVT, status %d", params.status); + // esp_log_buffer_hex("sync addr", param->periodic_adv_sync_estab.adv_addr, 6); + log_i("sync handle %d sid %d perioic adv interval %d adv phy %d", params.sync_handle, + params.sid, + params.period_adv_interval, + params.adv_phy); + } + + void onReport(esp_ble_gap_periodic_adv_report_t params) + { + log_i("periodic adv report, sync handle %d data status %d data len %d rssi %d", params.sync_handle, + params.data_status, + params.data_length, + params.rssi); + } +}; + +void setup() +{ + Serial.begin(115200); + Serial.println("Periodic scan..."); + + BLEDevice::init(""); + pBLEScan = BLEDevice::getScan(); //create new scan + pBLEScan->setExtendedScanCallback(new MyBLEExtAdvertisingCallbacks()); + pBLEScan->setExtScanParams(); // use with pre-defined/default values, overloaded function allows to pass parameters + pBLEScan->setPeriodicScanCallback(new MyPeriodicScan()); + delay(100); // it is just for simplicity this example, to let ble stack to set extended scan params + pBLEScan->startExtScan(0, 0); + +} + +void loop() +{ + delay(2000); +} + +#endif // CONFIG_BT_BLE_50_FEATURES_SUPPORTED diff --git a/libraries/BLE/src/BLEAdvertisedDevice.h b/libraries/BLE/src/BLEAdvertisedDevice.h index 5b305b6ff5e..1b00dd635a5 100644 --- a/libraries/BLE/src/BLEAdvertisedDevice.h +++ b/libraries/BLE/src/BLEAdvertisedDevice.h @@ -124,5 +124,20 @@ class BLEAdvertisedDeviceCallbacks { virtual void onResult(BLEAdvertisedDevice advertisedDevice) = 0; }; +#ifdef CONFIG_BT_BLE_50_FEATURES_SUPPORTED +class BLEExtAdvertisingCallbacks { +public: + virtual ~BLEExtAdvertisingCallbacks() {} + /** + * @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(esp_ble_gap_ext_adv_reprot_t report) = 0; +}; +#endif // CONFIG_BT_BLE_50_FEATURES_SUPPORTED + + #endif /* CONFIG_BLUEDROID_ENABLED */ #endif /* COMPONENTS_CPP_UTILS_BLEADVERTISEDDEVICE_H_ */ diff --git a/libraries/BLE/src/BLEAdvertising.cpp b/libraries/BLE/src/BLEAdvertising.cpp index d4f1045a2ed..09e829e5fa5 100644 --- a/libraries/BLE/src/BLEAdvertising.cpp +++ b/libraries/BLE/src/BLEAdvertising.cpp @@ -528,5 +528,242 @@ void BLEAdvertising::handleGAPEvent( } } +#ifdef CONFIG_BT_BLE_50_FEATURES_SUPPORTED + +/** +* @brief Creator +* +* @param[in] instance : number of multi advertising instances +* +* +*/ +BLEMultiAdvertising::BLEMultiAdvertising(uint8_t num) +{ + params_arrays = (esp_ble_gap_ext_adv_params_t*)calloc(num, sizeof(esp_ble_gap_ext_adv_params_t)); + ext_adv = (esp_ble_gap_ext_adv_t*)calloc(num, sizeof(esp_ble_gap_ext_adv_t)); + count = num; +} + +/** +* @brief This function is used by the Host to set the advertising parameters. +* +* @param[in] instance : identifies the advertising set whose parameters are being configured. +* @param[in] params : advertising parameters +* +* @return - true : success +* - false : failed +* +*/ +bool BLEMultiAdvertising::setAdvertisingParams(uint8_t instance, const esp_ble_gap_ext_adv_params_t* params) +{ + if (params->type == ESP_BLE_GAP_SET_EXT_ADV_PROP_LEGACY_IND && params->primary_phy == ESP_BLE_GAP_PHY_2M) return false; + esp_err_t rc; + rc = esp_ble_gap_ext_adv_set_params(instance, params); + + return ESP_OK == rc; +} + +/** +* @brief This function is used to set the data used in advertising PDUs that have a data field +* +* @param[in] instance : identifies the advertising set whose data are being configured +* @param[in] length : data length +* @param[in] data : data information +* +* @return - true : success +* - false : failed +* +*/ +bool BLEMultiAdvertising::setAdvertisingData(uint8_t instance, uint16_t length, const uint8_t* data) +{ + esp_err_t rc; + rc = esp_ble_gap_config_ext_adv_data_raw(instance, length, data); + if (rc) log_e("set advertising data err: %d", rc); + + return ESP_OK == rc; +} + +bool BLEMultiAdvertising::setScanRspData(uint8_t instance, uint16_t length, const uint8_t* data) +{ + esp_err_t rc; + rc = esp_ble_gap_config_ext_scan_rsp_data_raw(instance, length, data); + if (rc) log_e("set scan resp data err: %d", rc); + + return ESP_OK == rc; +} + +/** +* @brief This function is used to request the Controller to disable one or more +* advertising sets using the advertising sets identified by the instance parameter. +* +* @return - true : success +* - false : failed +* +*/ +bool BLEMultiAdvertising::start() +{ + return start(count, 0); +} + +/** +* @brief This function is used to request the Controller to disable one or more +* advertising sets using the advertising sets identified by the instance parameter. +* +* @param[in] num : Number of advertising sets to enable or disable +* @param[in] from : first sxt adv set to use +* +* @return - true : success +* - false : failed +* +*/ +bool BLEMultiAdvertising::start(uint8_t num, uint8_t from) +{ + if (num > count || from >= count) return false; + + esp_err_t rc; + rc = esp_ble_gap_ext_adv_start(num, &ext_adv[from]); + if (rc) log_e("start extended advertising err: %d", rc); + + return ESP_OK == rc; +} + +/** +* @brief This function is used to request the Controller to disable one or more +* advertising sets using the advertising sets identified by the instance parameter. +* +* @param[in] num_adv : Number of advertising sets to enable or disable +* @param[in] ext_adv_inst : ext adv instance +* +* @return - ESP_OK : success +* - other : failed +* +*/ +bool BLEMultiAdvertising::stop(uint8_t num_adv, const uint8_t* ext_adv_inst) +{ + esp_err_t rc; + rc = esp_ble_gap_ext_adv_stop(num_adv, ext_adv_inst); + if (rc) log_e("stop extended advertising err: %d", rc); + + return ESP_OK == rc; +} + +/** +* @brief This function is used to remove an advertising set from the Controller. +* +* @param[in] instance : Used to identify an advertising set +* +* @return - ESP_OK : success +* - other : failed +* +*/ +bool BLEMultiAdvertising::remove(uint8_t instance) +{ + esp_err_t rc; + rc = esp_ble_gap_ext_adv_set_remove(instance); + if (rc) log_e("remove extended advertising err: %d", rc); + + return ESP_OK == rc; +} + +/** +* @brief This function is used to remove all existing advertising sets from the Controller. +* +* +* @return - ESP_OK : success +* - other : failed +* +*/ +bool BLEMultiAdvertising::clear() +{ + esp_err_t rc; + rc = esp_ble_gap_ext_adv_set_clear(); + if (rc) log_e("clear extended advertising err: %d", rc); + + return ESP_OK == rc; +} + +/** +* @brief This function is used by the Host to set the random device address specified by the Random_Address parameter. +* +* @param[in] instance : Used to identify an advertising set +* @param[in] addr_legacy : Random Device Address +* +* @return - true : success +* - false : failed +* +*/ +bool BLEMultiAdvertising::setInstanceAddress(uint8_t instance, uint8_t* addr_legacy) +{ + esp_err_t rc; + rc = esp_ble_gap_ext_adv_set_rand_addr(instance, addr_legacy); + if (rc) log_e("set random address err: %d", rc); + + return ESP_OK == rc; +} + +/** +* @brief This function is used by the Host to set the parameters for periodic advertising. +* +* @param[in] instance : identifies the advertising set whose periodic advertising parameters are being configured. +* @param[in] params : periodic adv parameters +* +* @return - true : success +* - false : failed +* +*/ +bool BLEMultiAdvertising::setPeriodicAdvertisingParams(uint8_t instance, const esp_ble_gap_periodic_adv_params_t* params) +{ + esp_err_t rc; + rc = esp_ble_gap_periodic_adv_set_params(instance, params); + if (rc) log_e("set periodic advertising params err: %d", rc); + + return ESP_OK == rc; +} + +/** +* @brief This function is used to set the data used in periodic advertising PDUs. +* +* @param[in] instance : identifies the advertising set whose periodic advertising parameters are being configured. +* @param[in] length : the length of periodic data +* @param[in] data : periodic data information +* +* @return - true : success +* - false : failed +* +*/ +bool BLEMultiAdvertising::setPeriodicAdvertisingData(uint8_t instance, uint16_t length, const uint8_t* data) +{ + esp_err_t rc; + rc = esp_ble_gap_config_periodic_adv_data_raw(instance, length, data); + if (rc) log_e("set periodic advertising raw data err: %d", rc); + + return ESP_OK == rc; +} + +/** +* @brief This function is used to request the Controller to enable the periodic advertising for the advertising set specified +* +* @param[in] instance : Used to identify an advertising set +* +* @return - true : success +* - false : failed +* +*/ +bool BLEMultiAdvertising::startPeriodicAdvertising(uint8_t instance) +{ + esp_err_t rc; + rc = esp_ble_gap_periodic_adv_start(instance); + if (rc) log_e("start periodic advertising err: %d", rc); + + return ESP_OK == rc; +} + +void BLEMultiAdvertising::setDuration(uint8_t instance, int duration, int max_events) +{ + ext_adv[instance] = { instance, duration, max_events }; +} + +#endif // CONFIG_BT_BLE_50_FEATURES_SUPPORTED + #endif /* CONFIG_BLUEDROID_ENABLED */ diff --git a/libraries/BLE/src/BLEAdvertising.h b/libraries/BLE/src/BLEAdvertising.h index 0f929292a21..ec1d00334e9 100644 --- a/libraries/BLE/src/BLEAdvertising.h +++ b/libraries/BLE/src/BLEAdvertising.h @@ -78,5 +78,36 @@ class BLEAdvertising { bool m_scanResp = true; }; + +#ifdef CONFIG_BT_BLE_50_FEATURES_SUPPORTED + +class BLEMultiAdvertising +{ +private: + esp_ble_gap_ext_adv_params_t* params_arrays; + esp_ble_gap_ext_adv_t* ext_adv; + uint8_t count; + +public: + BLEMultiAdvertising(uint8_t num = 1); + ~BLEMultiAdvertising() {} + + bool setAdvertisingParams(uint8_t instance, const esp_ble_gap_ext_adv_params_t* params); + bool setAdvertisingData(uint8_t instance, uint16_t length, const uint8_t* data); + bool setScanRspData(uint8_t instance, uint16_t length, const uint8_t* data); + bool start(); + bool start(uint8_t num, uint8_t from); + void setDuration(uint8_t instance, int duration = 0, int max_events = 0); + bool setInstanceAddress(uint8_t instance, esp_bd_addr_t rand_addr); + bool stop(uint8_t num_adv, const uint8_t* ext_adv_inst); + bool remove(uint8_t instance); + bool clear(); + bool setPeriodicAdvertisingParams(uint8_t instance, const esp_ble_gap_periodic_adv_params_t* params); + bool setPeriodicAdvertisingData(uint8_t instance, uint16_t length, const uint8_t* data); + bool startPeriodicAdvertising(uint8_t instance); +}; + +#endif // CONFIG_BT_BLE_50_FEATURES_SUPPORTED + #endif /* CONFIG_BLUEDROID_ENABLED */ #endif /* COMPONENTS_CPP_UTILS_BLEADVERTISING_H_ */ diff --git a/libraries/BLE/src/BLEScan.cpp b/libraries/BLE/src/BLEScan.cpp index fd16c89923e..c93a30c5fa3 100644 --- a/libraries/BLE/src/BLEScan.cpp +++ b/libraries/BLE/src/BLEScan.cpp @@ -3,6 +3,9 @@ * * Created on: Jul 1, 2017 * Author: kolban + * + * Update: April, 2021 + * add BLE5 support */ #include "sdkconfig.h" #if defined(CONFIG_BLUEDROID_ENABLED) @@ -142,6 +145,98 @@ void BLEScan::handleGAPEvent( break; } // ESP_GAP_BLE_SCAN_RESULT_EVT +#ifdef CONFIG_BT_BLE_50_FEATURES_SUPPORTED + case ESP_GAP_BLE_EXT_ADV_REPORT_EVT: { + if (param->ext_adv_report.params.event_type & ESP_BLE_GAP_SET_EXT_ADV_PROP_LEGACY) { + log_v("legacy adv, adv type 0x%x data len %d", param->ext_adv_report.params.event_type, param->ext_adv_report.params.adv_data_len); + } + else { + log_v("extend adv, adv type 0x%x data len %d, data status: %d", param->ext_adv_report.params.event_type, param->ext_adv_report.params.adv_data_len, param->ext_adv_report.params.data_status); + } + + if (m_pExtendedScanCb != nullptr) + { + m_pExtendedScanCb->onResult(param->ext_adv_report.params); + } + + break; + } + + case ESP_GAP_BLE_SET_EXT_SCAN_PARAMS_COMPLETE_EVT: { + if (param->set_ext_scan_params.status != ESP_BT_STATUS_SUCCESS) { + log_e("extend scan parameters set failed, error status = %x", param->set_ext_scan_params.status); + break; + } + log_v("extend scan params set successfully"); + break; + } + + case ESP_GAP_BLE_EXT_SCAN_START_COMPLETE_EVT: + if (param->ext_scan_start.status != ESP_BT_STATUS_SUCCESS) { + log_e("scan start failed, error status = %x", param->scan_start_cmpl.status); + break; + } + log_v("Scan start success"); + break; + + case ESP_GAP_BLE_EXT_SCAN_STOP_COMPLETE_EVT: + if (m_pPeriodicScanCb != nullptr) + { + m_pPeriodicScanCb->onStop(param->ext_scan_stop.status); + } + + if (param->ext_scan_stop.status != ESP_BT_STATUS_SUCCESS){ + log_e("extend Scan stop failed, error status = %x", param->ext_scan_stop.status); + break; + } + log_v("Stop extend scan successfully"); + break; + + case ESP_GAP_BLE_PERIODIC_ADV_CREATE_SYNC_COMPLETE_EVT: + if (m_pPeriodicScanCb != nullptr) + { + m_pPeriodicScanCb->onCreateSync(param->period_adv_create_sync.status); + } + + log_v("ESP_GAP_BLE_PERIODIC_ADV_CREATE_SYNC_COMPLETE_EVT, status %d", param->period_adv_create_sync.status); + break; + case ESP_GAP_BLE_PERIODIC_ADV_SYNC_CANCEL_COMPLETE_EVT: + if (m_pPeriodicScanCb != nullptr) + { + m_pPeriodicScanCb->onCancelSync(param->period_adv_sync_cancel.status); + } + log_v("ESP_GAP_BLE_PERIODIC_ADV_SYNC_CANCEL_COMPLETE_EVT, status %d", param->period_adv_sync_cancel.status); + break; + case ESP_GAP_BLE_PERIODIC_ADV_SYNC_TERMINATE_COMPLETE_EVT: + if (m_pPeriodicScanCb != nullptr) + { + m_pPeriodicScanCb->onTerminateSync(param->period_adv_sync_term.status); + } + log_v("ESP_GAP_BLE_PERIODIC_ADV_SYNC_TERMINATE_COMPLETE_EVT, status %d", param->period_adv_sync_term.status); + break; + case ESP_GAP_BLE_PERIODIC_ADV_SYNC_LOST_EVT: + if (m_pPeriodicScanCb != nullptr) + { + m_pPeriodicScanCb->onLostSync(param->periodic_adv_sync_lost.sync_handle); + } + log_v("ESP_GAP_BLE_PERIODIC_ADV_SYNC_LOST_EVT, sync handle %d", param->periodic_adv_sync_lost.sync_handle); + break; + case ESP_GAP_BLE_PERIODIC_ADV_SYNC_ESTAB_EVT: + if (m_pPeriodicScanCb != nullptr) + { + m_pPeriodicScanCb->onSync(*(esp_ble_periodic_adv_sync_estab_param_t*)¶m->periodic_adv_sync_estab); + } + log_v("ESP_GAP_BLE_PERIODIC_ADV_SYNC_ESTAB_EVT, status %d", param->periodic_adv_sync_estab.status); + break; + + case ESP_GAP_BLE_PERIODIC_ADV_REPORT_EVT: + if (m_pPeriodicScanCb != nullptr) + { + m_pPeriodicScanCb->onReport(param->period_adv_report.params); + } + break; + +#endif // CONFIG_BT_BLE_50_FEATURES_SUPPORTED default: { break; @@ -177,6 +272,89 @@ void BLEScan::setAdvertisedDeviceCallbacks(BLEAdvertisedDeviceCallbacks* pAdvert m_shouldParse = shouldParse; } // setAdvertisedDeviceCallbacks +#ifdef CONFIG_BT_BLE_50_FEATURES_SUPPORTED + +void BLEScan::setExtendedScanCallback(BLEExtAdvertisingCallbacks* cb) +{ + m_pExtendedScanCb = cb; +} + +/** +* @brief This function is used to set the extended scan parameters to be used on the advertising channels. +* +* +* @return - ESP_OK : success +* - other : failed +* +*/ +esp_err_t BLEScan::setExtScanParams() +{ + esp_ble_ext_scan_params_t ext_scan_params = { + .own_addr_type = BLE_ADDR_TYPE_PUBLIC, + .filter_policy = BLE_SCAN_FILTER_ALLOW_ALL, + .scan_duplicate = BLE_SCAN_DUPLICATE_DISABLE, + .cfg_mask = ESP_BLE_GAP_EXT_SCAN_CFG_UNCODE_MASK | ESP_BLE_GAP_EXT_SCAN_CFG_CODE_MASK, + .uncoded_cfg = {BLE_SCAN_TYPE_ACTIVE, 40, 40}, + .coded_cfg = {BLE_SCAN_TYPE_ACTIVE, 40, 40}, + }; + + esp_err_t rc = esp_ble_gap_set_ext_scan_params(&ext_scan_params); + if (rc) { + log_e("set extend scan params error, error code = %x", rc); + } + return rc; +} + +/** +* @brief This function is used to set the extended scan parameters to be used on the advertising channels. +* +* @param[in] params : scan parameters +* +* @return - ESP_OK : success +* - other : failed +* +*/ +esp_err_t BLEScan::setExtScanParams(esp_ble_ext_scan_params_t* ext_scan_params) +{ + esp_err_t rc = esp_ble_gap_set_ext_scan_params(ext_scan_params); + if (rc) { + log_e("set extend scan params error, error code = %x", rc); + } + return rc; +} + +/** +* @brief This function is used to enable scanning. +* +* @param[in] duration : Scan duration +* @param[in] period : Time interval from when the Controller started its last Scan Duration until it begins the subsequent Scan Duration. +* +* @return - ESP_OK : success +* - other : failed +* +*/ +esp_err_t BLEScan::startExtScan(uint32_t duration, uint16_t period) +{ + esp_err_t rc = esp_ble_gap_start_ext_scan(duration, period); + if(rc) log_e("extended scan start failed: %d", rc); + return rc; +} + + +esp_err_t BLEScan::stopExtScan() +{ + esp_err_t rc; + rc = esp_ble_gap_stop_ext_scan(); + + return rc; +} + +void BLEScan::setPeriodicScanCallback(BLEPeriodicScanCallbacks* cb) +{ + m_pPeriodicScanCb = cb; +} + +#endif // CONFIG_BT_BLE_50_FEATURES_SUPPORTED /** * @brief Set the interval to scan. * @param [in] The interval in msecs. diff --git a/libraries/BLE/src/BLEScan.h b/libraries/BLE/src/BLEScan.h index 14b47153d81..3aca9e7d084 100644 --- a/libraries/BLE/src/BLEScan.h +++ b/libraries/BLE/src/BLEScan.h @@ -19,9 +19,21 @@ class BLEAdvertisedDevice; class BLEAdvertisedDeviceCallbacks; +class BLEExtAdvertisingCallbacks; class BLEClient; class BLEScan; +class BLEPeriodicScanCallbacks; +struct esp_ble_periodic_adv_sync_estab_param_t { + uint8_t status; /*!< periodic advertising sync status */ + uint16_t sync_handle; /*!< periodic advertising sync handle */ + uint8_t sid; /*!< periodic advertising sid */ + esp_ble_addr_type_t adv_addr_type; /*!< periodic advertising address type */ + esp_bd_addr_t adv_addr; /*!< periodic advertising address */ + esp_ble_gap_phy_t adv_phy; /*!< periodic advertising phy type */ + uint16_t period_adv_interval; /*!< periodic advertising interval */ + uint8_t adv_clk_accuracy; /*!< periodic advertising clock accuracy */ +}; /** * @brief The result of having performed a scan. @@ -62,13 +74,25 @@ class BLEScan { BLEScanResults getResults(); void clearResults(); +#ifdef CONFIG_BT_BLE_50_FEATURES_SUPPORTED + void setExtendedScanCallback(BLEExtAdvertisingCallbacks* cb); + void setPeriodicScanCallback(BLEPeriodicScanCallbacks* cb); + + esp_err_t stopExtScan(); + esp_err_t setExtScanParams(); + esp_err_t setExtScanParams(esp_ble_ext_scan_params_t* ext_scan_params); + esp_err_t startExtScan(uint32_t duration, uint16_t period); +private: + BLEExtAdvertisingCallbacks* m_pExtendedScanCb = nullptr; + BLEPeriodicScanCallbacks* m_pPeriodicScanCb = nullptr; +#endif // CONFIG_BT_BLE_50_FEATURES_SUPPORTED + private: BLEScan(); // One doesn't create a new instance instead one asks the BLEDevice for the singleton. friend class BLEDevice; void handleGAPEvent( 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; @@ -81,5 +105,18 @@ class BLEScan { void (*m_scanCompleteCB)(BLEScanResults scanResults); }; // BLEScan +class BLEPeriodicScanCallbacks { +public: + virtual ~BLEPeriodicScanCallbacks() {} + + virtual void onCreateSync(esp_bt_status_t status) {} + virtual void onCancelSync(esp_bt_status_t status) {} + virtual void onTerminateSync(esp_bt_status_t status) {} + virtual void onLostSync(uint16_t sync_handle) {} + virtual void onSync(esp_ble_periodic_adv_sync_estab_param_t) {} + virtual void onReport(esp_ble_gap_periodic_adv_report_t params) {} + virtual void onStop(esp_bt_status_t status) {} +}; + #endif /* CONFIG_BLUEDROID_ENABLED */ #endif /* COMPONENTS_CPP_UTILS_BLESCAN_H_ */