diff --git a/components/bt/CMakeLists.txt b/components/bt/CMakeLists.txt index 7de6b2f90..7a5b99b11 100644 --- a/components/bt/CMakeLists.txt +++ b/components/bt/CMakeLists.txt @@ -305,6 +305,7 @@ if(CONFIG_BT_ENABLED) "esp_ble_mesh/api") list(APPEND COMPONENT_SRCS + "esp_ble_mesh/api/core/esp_ble_mesh_ble_api.c" "esp_ble_mesh/api/core/esp_ble_mesh_common_api.c" "esp_ble_mesh/api/core/esp_ble_mesh_local_data_operation_api.c" "esp_ble_mesh/api/core/esp_ble_mesh_low_power_api.c" diff --git a/components/bt/Kconfig b/components/bt/Kconfig index fd22f064b..c60dab04b 100644 --- a/components/bt/Kconfig +++ b/components/bt/Kconfig @@ -2079,6 +2079,24 @@ if BLE_MESH SDU size is 60 bytes, which leaves 56 bytes for application layer data using a 4-byte MIC, or 52 bytes using an 8-byte MIC. + config BLE_MESH_SUPPORT_BLE_ADV + bool "Support sending normal BLE advertising packets" + default n + help + When selected, users can send normal BLE advertising packets + with specific API. + + if BLE_MESH_SUPPORT_BLE_ADV + + config BLE_MESH_BLE_ADV_BUF_COUNT + int "Number of advertising buffers for BLE advertising packets" + default 3 + range 1 255 + help + Number of advertising buffers for BLE packets available. + + endif # BLE_MESH_SUPPORT_BLE_ADV + config BLE_MESH_IVU_DIVIDER int "Divider for IV Update state refresh timer" default 4 diff --git a/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_ble_api.c b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_ble_api.c new file mode 100644 index 000000000..1ba2dcd57 --- /dev/null +++ b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_ble_api.c @@ -0,0 +1,73 @@ +// Copyright 2017-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include "btc/btc_manage.h" + +#include "esp_err.h" + +#include "btc_ble_mesh_prov.h" +#include "esp_ble_mesh_defs.h" + +#if CONFIG_BLE_MESH_SUPPORT_BLE_ADV + +esp_err_t esp_ble_mesh_start_ble_advertising(const esp_ble_mesh_ble_adv_param_t *param, + const esp_ble_mesh_ble_adv_data_t *data) +{ + btc_ble_mesh_prov_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (param == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_PROV; + msg.act = BTC_BLE_MESH_ACT_START_BLE_ADVERTISING; + + memcpy(&arg.start_ble_advertising.param, param, sizeof(esp_ble_mesh_ble_adv_param_t)); + if (data) { + memcpy(&arg.start_ble_advertising.data, data, sizeof(esp_ble_mesh_ble_adv_data_t)); + } + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_stop_ble_advertising(uint8_t index) +{ + btc_ble_mesh_prov_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (index >= CONFIG_BLE_MESH_BLE_ADV_BUF_COUNT) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_PROV; + msg.act = BTC_BLE_MESH_ACT_STOP_BLE_ADVERTISING; + + arg.stop_ble_advertising.index = index; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +#endif /* CONFIG_BLE_MESH_SUPPORT_BLE_ADV */ diff --git a/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_ble_api.h b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_ble_api.h new file mode 100644 index 000000000..0bfe4ce64 --- /dev/null +++ b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_ble_api.h @@ -0,0 +1,57 @@ +// Copyright 2017-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef _ESP_BLE_MESH_BLE_API_H_ +#define _ESP_BLE_MESH_BLE_API_H_ + +#include "esp_ble_mesh_defs.h" + +/** + * @brief This function is called to start BLE advertising with the corresponding data + * and parameters while BLE Mesh is working at the same time. + * + * @note 1. When this function is called, the BLE advertising packet will be posted to + * the BLE mesh adv queue in the mesh stack and waited to be sent. + * 2. In the BLE advertising parameters, the "duration" means the time used for + * sending the BLE advertising packet each time, it shall not be smaller than the + * advertising interval. When the packet is sent successfully, it will be posted + * to the adv queue again after the "period" time if the "count" is bigger than 0. + * The "count" means how many durations the packet will be sent after it is sent + * successfully for the first time. And if the "count" is set to 0xFFFF, which + * means the packet will be sent infinitely. + * 3. The "priority" means the priority of BLE advertising packet compared with + * BLE Mesh packets. Currently two options (i.e. low/high) are provided. If the + * "priority" is high, the BLE advertising packet will be posted to the front of + * adv queue. Otherwise it will be posted to the back of adv queue. + * + * @param[in] param: Pointer to the BLE advertising parameters + * @param[in] data: Pointer to the BLE advertising data and scan response data + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_start_ble_advertising(const esp_ble_mesh_ble_adv_param_t *param, + const esp_ble_mesh_ble_adv_data_t *data); + +/** + * @brief This function is called to stop BLE advertising with the corresponding index. + * + * @param[in] index: Index of BLE advertising + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_stop_ble_advertising(uint8_t index); + +#endif /* _ESP_BLE_MESH_BLE_API_H_ */ diff --git a/components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h b/components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h index 855a4fd5a..96648c216 100644 --- a/components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h +++ b/components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h @@ -725,6 +725,36 @@ typedef enum { PROXY_FILTER_BLACKLIST, } esp_ble_mesh_proxy_filter_type_t; +/** Count for sending BLE advertising packet infinitely */ +#define ESP_BLE_MESH_BLE_ADV_INFINITE 0xFFFF + +/*!< This enum value is the priority of BLE advertising packet */ +typedef enum { + ESP_BLE_MESH_BLE_ADV_PRIO_LOW, + ESP_BLE_MESH_BLE_ADV_PRIO_HIGH, +} esp_ble_mesh_ble_adv_priority_t; + +/** Context of BLE advertising parameters. */ +typedef struct { + uint16_t interval; /*!< BLE advertising interval */ + uint8_t adv_type; /*!< BLE advertising type */ + uint8_t own_addr_type; /*!< Own address type */ + uint8_t peer_addr_type; /*!< Peer address type */ + uint8_t peer_addr[BD_ADDR_LEN]; /*!< Peer address */ + uint16_t duration; /*!< Duration is milliseconds */ + uint16_t period; /*!< Period in milliseconds */ + uint16_t count; /*!< Number of advertising duration */ + uint8_t priority:2; /*!< Priority of BLE advertising packet */ +} esp_ble_mesh_ble_adv_param_t; + +/** Context of BLE advertising data. */ +typedef struct { + uint8_t adv_data_len; /*!< Advertising data length */ + uint8_t adv_data[31]; /*!< Advertising data */ + uint8_t scan_rsp_data_len; /*!< Scan response data length */ + uint8_t scan_rsp_data[31]; /*!< Scan response data */ +} esp_ble_mesh_ble_adv_data_t; + /*!< This enum value is the event of node/provisioner/fast provisioning */ typedef enum { ESP_BLE_MESH_PROV_REGISTER_COMP_EVT, /*!< Initialize BLE Mesh provisioning capabilities and internal data information completion event */ @@ -792,6 +822,8 @@ typedef enum { ESP_BLE_MESH_PROXY_CLIENT_SET_FILTER_TYPE_COMP_EVT, /*!< Proxy Client set filter type completion event */ ESP_BLE_MESH_PROXY_CLIENT_ADD_FILTER_ADDR_COMP_EVT, /*!< Proxy Client add filter address completion event */ ESP_BLE_MESH_PROXY_CLIENT_REMOVE_FILTER_ADDR_COMP_EVT, /*!< Proxy Client remove filter address completion event */ + ESP_BLE_MESH_START_BLE_ADVERTISING_COMP_EVT, /*!< Start BLE advertising completion event */ + ESP_BLE_MESH_STOP_BLE_ADVERTISING_COMP_EVT, /*!< Stop BLE advertising completion event */ ESP_BLE_MESH_DEINIT_MESH_COMP_EVT, /*!< De-initialize BLE Mesh stack completion event */ ESP_BLE_MESH_PROV_EVT_MAX, } esp_ble_mesh_prov_cb_event_t; @@ -1260,6 +1292,20 @@ typedef union { uint8_t conn_handle; /*!< Proxy connection handle */ uint16_t net_idx; /*!< Corresponding NetKey Index */ } proxy_client_remove_filter_addr_comp; /*!< Event parameter of ESP_BLE_MESH_PROXY_CLIENT_REMOVE_FILTER_ADDR_COMP_EVT */ + /** + * @brief ESP_BLE_MESH_START_BLE_ADVERTISING_COMP_EVT + */ + struct ble_mesh_start_ble_advertising_comp_param { + int err_code; /*!< Indicate the result of starting BLE advertising */ + uint8_t index; /*!< Index of the BLE advertising */ + } start_ble_advertising_comp; /*!< Event parameter of ESP_BLE_MESH_START_BLE_ADVERTISING_COMP_EVT */ + /** + * @brief ESP_BLE_MESH_STOP_BLE_ADVERTISING_COMP_EVT + */ + struct ble_mesh_stop_ble_advertising_comp_param { + int err_code; /*!< Indicate the result of stopping BLE advertising */ + uint8_t index; /*!< Index of the BLE advertising */ + } stop_ble_advertising_comp; /*!< Event parameter of ESP_BLE_MESH_STOP_BLE_ADVERTISING_COMP_EVT */ /** * @brief ESP_BLE_MESH_DEINIT_MESH_COMP_EVT */ diff --git a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c index 2cafe026d..18c90116f 100644 --- a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c +++ b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c @@ -18,6 +18,7 @@ #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" +#include "adv.h" #include "mesh_proxy.h" #include "mesh.h" #include "access.h" @@ -1879,6 +1880,26 @@ void btc_ble_mesh_prov_call_handler(btc_msg_t *msg) break; } #endif /* CONFIG_BLE_MESH_GATT_PROXY_CLIENT */ +#if CONFIG_BLE_MESH_SUPPORT_BLE_ADV + case BTC_BLE_MESH_ACT_START_BLE_ADVERTISING: { + struct bt_mesh_ble_adv_param *set = (struct bt_mesh_ble_adv_param *)&arg->start_ble_advertising.param; + struct bt_mesh_ble_adv_data *data = NULL; + if (arg->start_ble_advertising.data.adv_data_len || + arg->start_ble_advertising.data.scan_rsp_data_len) { + data = (struct bt_mesh_ble_adv_data *)&arg->start_ble_advertising.data; + } + act = ESP_BLE_MESH_START_BLE_ADVERTISING_COMP_EVT; + param.start_ble_advertising_comp.err_code = + bt_mesh_start_ble_advertising(set, data, ¶m.start_ble_advertising_comp.index); + break; + } + case BTC_BLE_MESH_ACT_STOP_BLE_ADVERTISING: + act = ESP_BLE_MESH_STOP_BLE_ADVERTISING_COMP_EVT; + param.stop_ble_advertising_comp.index = arg->stop_ble_advertising.index; + param.stop_ble_advertising_comp.err_code = + bt_mesh_stop_ble_advertising(arg->stop_ble_advertising.index); + break; +#endif /* CONFIG_BLE_MESH_SUPPORT_BLE_ADV */ case BTC_BLE_MESH_ACT_DEINIT_MESH: act = ESP_BLE_MESH_DEINIT_MESH_COMP_EVT; param.deinit_mesh_comp.err_code = bt_mesh_deinit((struct bt_mesh_deinit_param *)&arg->mesh_deinit.param); diff --git a/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_prov.h b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_prov.h index 28a713ef1..39690f303 100644 --- a/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_prov.h +++ b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_prov.h @@ -63,6 +63,8 @@ typedef enum { BTC_BLE_MESH_ACT_PROXY_CLIENT_SET_FILTER_TYPE, BTC_BLE_MESH_ACT_PROXY_CLIENT_ADD_FILTER_ADDR, BTC_BLE_MESH_ACT_PROXY_CLIENT_REMOVE_FILTER_ADDR, + BTC_BLE_MESH_ACT_START_BLE_ADVERTISING, + BTC_BLE_MESH_ACT_STOP_BLE_ADVERTISING, BTC_BLE_MESH_ACT_DEINIT_MESH, } btc_ble_mesh_prov_act_t; @@ -235,6 +237,13 @@ typedef union { uint16_t addr_num; uint16_t *addr; } proxy_client_remove_filter_addr; + struct ble_mesh_start_ble_advertising_args { + esp_ble_mesh_ble_adv_param_t param; + esp_ble_mesh_ble_adv_data_t data; + } start_ble_advertising; + struct ble_mesh_stop_ble_advertising_args { + uint8_t index; + } stop_ble_advertising; struct ble_mesh_deinit_args { esp_ble_mesh_deinit_param_t param; } mesh_deinit; diff --git a/components/bt/esp_ble_mesh/mesh_core/adv.c b/components/bt/esp_ble_mesh/mesh_core/adv.c index da83dd656..1986f1fba 100644 --- a/components/bt/esp_ble_mesh/mesh_core/adv.c +++ b/components/bt/esp_ble_mesh/mesh_core/adv.c @@ -21,6 +21,7 @@ #include "mesh.h" #include "mesh_hci.h" +#include "mesh_common.h" #include "adv.h" #include "beacon.h" #include "prov.h" @@ -32,6 +33,8 @@ /* Convert from ms to 0.625ms units */ #define ADV_SCAN_UNIT(_ms) ((_ms) * 8 / 5) +/* Convert from 0.625ms units to interval(ms) */ +#define ADV_SCAN_INT(val) ((val) * 5 / 8) /* Window and Interval are equal for continuous scanning */ #define MESH_SCAN_INTERVAL 0x20 @@ -73,7 +76,11 @@ struct bt_mesh_queue { static struct bt_mesh_queue xBleMeshQueue; /* We reserve one queue for bt_mesh_adv_update() */ -#define BLE_MESH_QUEUE_SIZE (CONFIG_BLE_MESH_ADV_BUF_COUNT + 1) +#if CONFIG_BLE_MESH_SUPPORT_BLE_ADV +#define BLE_MESH_QUEUE_SIZE (CONFIG_BLE_MESH_ADV_BUF_COUNT + CONFIG_BLE_MESH_BLE_ADV_BUF_COUNT + 1) +#else +#define BLE_MESH_QUEUE_SIZE (CONFIG_BLE_MESH_ADV_BUF_COUNT + 1) +#endif #if defined(CONFIG_BLE_MESH_RELAY_ADV_BUF) NET_BUF_POOL_DEFINE(relay_adv_buf_pool, CONFIG_BLE_MESH_RELAY_ADV_BUF_COUNT, @@ -93,6 +100,30 @@ static QueueSetHandle_t xBleMeshQueueSet; static bool ignore_relay_packet(u32_t timestamp); #endif /* defined(CONFIG_BLE_MESH_RELAY_ADV_BUF) */ +#if CONFIG_BLE_MESH_SUPPORT_BLE_ADV +/* length + advertising data + length + scan response data */ +NET_BUF_POOL_DEFINE(ble_adv_buf_pool, CONFIG_BLE_MESH_BLE_ADV_BUF_COUNT, + ((BLE_MESH_ADV_DATA_SIZE + 3) << 1), BLE_MESH_ADV_USER_DATA_SIZE, NULL); + +static struct bt_mesh_adv ble_adv_pool[CONFIG_BLE_MESH_BLE_ADV_BUF_COUNT]; + +enum { + TIMER_INIT, /* Resend timer is initialized */ + NUM_FLAGS, +}; + +static struct ble_adv_tx { + struct bt_mesh_ble_adv_param param; + struct net_buf *buf; + struct k_delayed_work resend; + BLE_MESH_ATOMIC_DEFINE(flags, NUM_FLAGS); +} ble_adv_tx[CONFIG_BLE_MESH_BLE_ADV_BUF_COUNT]; + +#define SEND_BLE_ADV_INFINITE 0xFFFF + +static void bt_mesh_ble_adv_deinit(void); +#endif /* CONFIG_BLE_MESH_SUPPORT_BLE_ADV */ + struct bt_mesh_adv_task { TaskHandle_t handle; #if CONFIG_SPIRAM_USE_MALLOC @@ -136,28 +167,63 @@ static inline int adv_send(struct net_buf *buf) struct bt_mesh_adv_data ad = {0}; int err = 0; - adv_int = MAX(adv_int_min, - BLE_MESH_TRANSMIT_INT(BLE_MESH_ADV(buf)->xmit)); - duration = (BLE_MESH_TRANSMIT_COUNT(BLE_MESH_ADV(buf)->xmit) + 1) * - (adv_int + 10); - BT_DBG("type %u len %u: %s", BLE_MESH_ADV(buf)->type, - buf->len, bt_hex(buf->data, buf->len)); - BT_DBG("count %u interval %ums duration %ums", - BLE_MESH_TRANSMIT_COUNT(BLE_MESH_ADV(buf)->xmit) + 1, adv_int, - duration); + buf->len, bt_hex(buf->data, buf->len)); - ad.type = adv_type[BLE_MESH_ADV(buf)->type]; - ad.data_len = buf->len; - ad.data = buf->data; +#if CONFIG_BLE_MESH_SUPPORT_BLE_ADV + if (BLE_MESH_ADV(buf)->type != BLE_MESH_ADV_BLE) { +#endif + adv_int = MAX(adv_int_min, + BLE_MESH_TRANSMIT_INT(BLE_MESH_ADV(buf)->xmit)); + duration = (BLE_MESH_TRANSMIT_COUNT(BLE_MESH_ADV(buf)->xmit) + 1) * + (adv_int + 10); - param.options = 0U; - param.interval_min = ADV_SCAN_UNIT(adv_int); - param.interval_max = param.interval_min; + BT_DBG("count %u interval %ums duration %ums", + BLE_MESH_TRANSMIT_COUNT(BLE_MESH_ADV(buf)->xmit) + 1, adv_int, + duration); - bt_mesh_adv_buf_ref_debug(__func__, buf, 4U, BLE_MESH_BUF_REF_SMALL); + ad.type = adv_type[BLE_MESH_ADV(buf)->type]; + ad.data_len = buf->len; + ad.data = buf->data; + + param.options = 0U; + param.interval_min = ADV_SCAN_UNIT(adv_int); + param.interval_max = param.interval_min; + + bt_mesh_adv_buf_ref_debug(__func__, buf, 4U, BLE_MESH_BUF_REF_SMALL); + + err = bt_le_adv_start(¶m, &ad, 1, NULL, 0); +#if CONFIG_BLE_MESH_SUPPORT_BLE_ADV + } else { + struct bt_mesh_ble_adv_data data = {0}; + struct ble_adv_tx *tx = cb_data; + + if (tx == NULL) { + BT_ERR("%s, Invalid adv user data", __func__); + net_buf_unref(buf); + return -EINVAL; + } + + BT_DBG("interval %dms, duration %dms, period %dms, count %d", + ADV_SCAN_INT(tx->param.interval), tx->param.duration, + tx->param.period, tx->param.count); + + data.adv_data_len = tx->buf->data[0]; + if (data.adv_data_len) { + memcpy(data.adv_data, tx->buf->data + 1, data.adv_data_len); + } + data.scan_rsp_data_len = tx->buf->data[data.adv_data_len + 1]; + if (data.scan_rsp_data_len) { + memcpy(data.scan_rsp_data, tx->buf->data + data.adv_data_len + 2, data.scan_rsp_data_len); + } + duration = tx->param.duration; + + bt_mesh_adv_buf_ref_debug(__func__, buf, 3U, BLE_MESH_BUF_REF_SMALL); + + err = bt_mesh_ble_adv_start(&tx->param, &data); + } +#endif /* CONFIG_BLE_MESH_SUPPORT_BLE_ADV */ - err = bt_le_adv_start(¶m, &ad, 1, NULL, 0); net_buf_unref(buf); adv_send_start(duration, err, cb, cb_data); if (err) { @@ -381,7 +447,7 @@ static void bt_mesh_unref_buf(bt_mesh_msg_t *msg) return; } -static void bt_mesh_task_post(bt_mesh_msg_t *msg, uint32_t timeout) +static void bt_mesh_task_post(bt_mesh_msg_t *msg, uint32_t timeout, bool front) { BT_DBG("%s", __func__); @@ -390,9 +456,16 @@ static void bt_mesh_task_post(bt_mesh_msg_t *msg, uint32_t timeout) return; } - if (xQueueSend(xBleMeshQueue.queue, msg, timeout) != pdTRUE) { - BT_ERR("%s, Failed to send item to queue", __func__); - bt_mesh_unref_buf(msg); + if (front) { + if (xQueueSendToFront(xBleMeshQueue.queue, msg, timeout) != pdTRUE) { + BT_ERR("%s, Failed to send item to queue front", __func__); + bt_mesh_unref_buf(msg); + } + } else { + if (xQueueSend(xBleMeshQueue.queue, msg, timeout) != pdTRUE) { + BT_ERR("%s, Failed to send item to queue back", __func__); + bt_mesh_unref_buf(msg); + } } } @@ -413,7 +486,7 @@ void bt_mesh_adv_send(struct net_buf *buf, const struct bt_mesh_send_cb *cb, bt_mesh_adv_buf_ref_debug(__func__, buf, 3U, BLE_MESH_BUF_REF_SMALL); msg.arg = (void *)net_buf_ref(buf); - bt_mesh_task_post(&msg, portMAX_DELAY); + bt_mesh_task_post(&msg, portMAX_DELAY, false); } void bt_mesh_adv_update(void) @@ -425,7 +498,7 @@ void bt_mesh_adv_update(void) BT_DBG("%s", __func__); - bt_mesh_task_post(&msg, K_NO_WAIT); + bt_mesh_task_post(&msg, K_NO_WAIT, false); } #if defined(CONFIG_BLE_MESH_RELAY_ADV_BUF) @@ -823,6 +896,10 @@ void bt_mesh_adv_deinit(void) bt_mesh_unref_buf_from_pool(&adv_buf_pool); memset(adv_pool, 0, sizeof(adv_pool)); + +#if CONFIG_BLE_MESH_SUPPORT_BLE_ADV + bt_mesh_ble_adv_deinit(); +#endif } int bt_mesh_scan_enable(void) @@ -895,3 +972,248 @@ int bt_mesh_scan_with_wl_enable(void) return 0; } #endif /* CONFIG_BLE_MESH_TEST_USE_WHITE_LIST */ + +#if CONFIG_BLE_MESH_SUPPORT_BLE_ADV +static struct bt_mesh_adv *ble_adv_alloc(int id) +{ + return &ble_adv_pool[id]; +} + +static struct net_buf *bt_mesh_ble_adv_create(enum bt_mesh_adv_type type, u8_t xmit, s32_t timeout) +{ + return bt_mesh_adv_create_from_pool(&ble_adv_buf_pool, ble_adv_alloc, type, + xmit, timeout); +} + +static void bt_mesh_ble_adv_send(struct net_buf *buf, const struct bt_mesh_send_cb *cb, + void *cb_data, bool front) +{ + bt_mesh_msg_t msg = { + .relay = false, + }; + + BT_DBG("type 0x%02x len %u: %s", BLE_MESH_ADV(buf)->type, buf->len, + bt_hex(buf->data, buf->len)); + + BLE_MESH_ADV(buf)->cb = cb; + BLE_MESH_ADV(buf)->cb_data = cb_data; + BLE_MESH_ADV(buf)->busy = 1U; + + bt_mesh_adv_buf_ref_debug(__func__, buf, 3U, BLE_MESH_BUF_REF_SMALL); + + msg.arg = (void *)net_buf_ref(buf); + bt_mesh_task_post(&msg, portMAX_DELAY, front); +} + +static void ble_adv_tx_reset(struct ble_adv_tx *tx, bool unref) +{ + if (tx->buf == NULL) { + return; + } + + if (bt_mesh_atomic_test_bit(tx->flags, TIMER_INIT)) { + k_delayed_work_free(&tx->resend); + } + bt_mesh_atomic_set(tx->flags, 0); + memset(&tx->param, 0, sizeof(tx->param)); + BLE_MESH_ADV(tx->buf)->busy = 0U; + if (unref) { + net_buf_unref(tx->buf); + } + tx->buf = NULL; +} + +static void ble_adv_send_start(u16_t duration, int err, void *cb_data) +{ + struct ble_adv_tx *tx = cb_data; + + BT_DBG("%s, duration %d, err %d", __func__, duration, err); + + /* If failed to send BLE adv packet, and param->count is not 0 + * which means the timer has been initialized, here we need to + * free the timer. + */ + if (err) { + ble_adv_tx_reset(tx, true); + } +} + +static void ble_adv_send_end(int err, void *cb_data) +{ + struct ble_adv_tx *tx = cb_data; + + BT_DBG("%s, err %d", __func__, err); + + if (err) { + ble_adv_tx_reset(tx, true); + return; + } + + if (tx->param.count) { + if (tx->param.period) { + k_delayed_work_submit(&tx->resend, tx->param.period); + } else { + k_work_submit(&tx->resend.work); + } + } else { + ble_adv_tx_reset(tx, true); + } +} + +static struct bt_mesh_send_cb ble_adv_send_cb = { + .start = ble_adv_send_start, + .end = ble_adv_send_end, +}; + +static void ble_adv_resend(struct k_work *work) +{ + struct ble_adv_tx *tx = CONTAINER_OF(work, struct ble_adv_tx, resend.work); + bool front = false; + + if (tx->buf == NULL) { + /* The advertising has been cancelled */ + return; + } + + front = (tx->param.priority == BLE_MESH_BLE_ADV_PRIO_HIGH) ? true : false; + bt_mesh_ble_adv_send(tx->buf, &ble_adv_send_cb, tx, front); + + if (tx->param.count == SEND_BLE_ADV_INFINITE) { + /* Send the BLE advertising packet infinitely */ + return; + } + + if (tx->param.count > 0U) { + tx->param.count--; + } +} + +int bt_mesh_start_ble_advertising(const struct bt_mesh_ble_adv_param *param, + const struct bt_mesh_ble_adv_data *data, u8_t *index) +{ + struct ble_adv_tx *tx = NULL; + struct net_buf *buf = NULL; + bool front = false; + + if (param == NULL || index == NULL) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + if (param->adv_type != BLE_MESH_ADV_DIRECT_IND && + (param->interval < 0x20 || param->interval > 0x4000)) { + BT_ERR("%s, Invalid adv interval 0x%04x", __func__, param->interval); + return -EINVAL; + } + + if (param->adv_type > BLE_MESH_ADV_DIRECT_IND_LOW_DUTY) { + BT_ERR("%s, Invalid adv type 0x%02x", __func__, param->adv_type); + return -EINVAL; + } + + if (param->own_addr_type > BLE_MESH_ADDR_RANDOM_ID) { + BT_ERR("%s, Invalid own addr type 0x%02x", __func__, param->own_addr_type); + return -EINVAL; + } + + if ((param->own_addr_type == BLE_MESH_ADDR_PUBLIC_ID || + param->own_addr_type == BLE_MESH_ADDR_RANDOM_ID || + param->adv_type == BLE_MESH_ADV_DIRECT_IND || + param->adv_type == BLE_MESH_ADV_DIRECT_IND_LOW_DUTY) && + param->peer_addr_type > BLE_MESH_ADDR_RANDOM) { + BT_ERR("%s, Invalid peer addr type 0x%02x", __func__, param->peer_addr_type); + return -EINVAL; + } + + if (data && (data->adv_data_len > 31 || data->scan_rsp_data_len > 31)) { + BT_ERR("%s, Invalid adv data length, %d %d", __func__, + data->adv_data_len, data->scan_rsp_data_len); + return -EINVAL; + } + + if (param->priority > BLE_MESH_BLE_ADV_PRIO_HIGH) { + BT_ERR("%s, Invalid adv priority %d", __func__, param->priority); + return -EINVAL; + } + + if (param->duration < ADV_SCAN_INT(param->interval)) { + BT_ERR("%s, Too small duration %dms", __func__, param->duration); + return -EINVAL; + } + + buf = bt_mesh_ble_adv_create(BLE_MESH_ADV_BLE, 0U, K_NO_WAIT); + if (!buf) { + BT_ERR("%s, Unable to allocate buffer", __func__); + return -ENOBUFS; + } + + /* Set advertising data and scan response data */ + memset(buf->data, 0, buf->size); + if (data) { + net_buf_add_u8(buf, data->adv_data_len); + if (data->adv_data_len) { + net_buf_add_mem(buf, data->adv_data, data->adv_data_len); + } + net_buf_add_u8(buf, data->scan_rsp_data_len); + if (data->scan_rsp_data_len) { + net_buf_add_mem(buf, data->scan_rsp_data, data->scan_rsp_data_len); + } + } + + *index = net_buf_id(buf); + tx = &ble_adv_tx[*index]; + tx->buf = buf; + memcpy(&tx->param, param, sizeof(tx->param)); + + front = (tx->param.priority == BLE_MESH_BLE_ADV_PRIO_HIGH) ? true : false; + bt_mesh_ble_adv_send(buf, &ble_adv_send_cb, tx, front); + if (param->count) { + k_delayed_work_init(&tx->resend, ble_adv_resend); + bt_mesh_atomic_set_bit(tx->flags, TIMER_INIT); + } else { + /* Send the BLE advertising packet only once */ + net_buf_unref(buf); + } + + return 0; +} + +int bt_mesh_stop_ble_advertising(u8_t index) +{ + struct ble_adv_tx *tx = NULL; + bool unref = true; + + if (index >= ARRAY_SIZE(ble_adv_tx)) { + BT_ERR("%s, Invalid index %d", __func__, index); + return -EINVAL; + } + + tx = &ble_adv_tx[index]; + + if (tx->buf == NULL) { + BT_WARN("%s, Already stopped, index %d", __func__, index); + return 0; + } + + /* busy 1, ref 1; busy 1, ref 2; + * busy 0, ref 0; busy 0, ref 1; + */ + if (BLE_MESH_ADV(tx->buf)->busy == 1U && + tx->buf->ref == 1U) { + unref = false; + } + ble_adv_tx_reset(tx, unref); + + return 0; +} + +static void bt_mesh_ble_adv_deinit(void) +{ + for (int i = 0; i < ARRAY_SIZE(ble_adv_tx); i++) { + struct ble_adv_tx *tx = &ble_adv_tx[i]; + ble_adv_tx_reset(tx, false); + } + bt_mesh_unref_buf_from_pool(&ble_adv_buf_pool); + memset(ble_adv_pool, 0, sizeof(ble_adv_pool)); +} +#endif /* CONFIG_BLE_MESH_SUPPORT_BLE_ADV */ diff --git a/components/bt/esp_ble_mesh/mesh_core/adv.h b/components/bt/esp_ble_mesh/mesh_core/adv.h index 8a9b8e872..492ca2873 100644 --- a/components/bt/esp_ble_mesh/mesh_core/adv.h +++ b/components/bt/esp_ble_mesh/mesh_core/adv.h @@ -34,6 +34,7 @@ enum bt_mesh_adv_type { BLE_MESH_ADV_DATA, BLE_MESH_ADV_BEACON, BLE_MESH_ADV_URI, + BLE_MESH_ADV_BLE, }; typedef void (*bt_mesh_adv_func_t)(struct net_buf *buf, u16_t duration, @@ -43,7 +44,7 @@ struct bt_mesh_adv { const struct bt_mesh_send_cb *cb; void *cb_data; - u8_t type: 2, + u8_t type: 3, busy: 1; u8_t xmit; @@ -99,4 +100,11 @@ int bt_mesh_scan_disable(void); int bt_mesh_scan_with_wl_enable(void); +#if CONFIG_BLE_MESH_SUPPORT_BLE_ADV +int bt_mesh_start_ble_advertising(const struct bt_mesh_ble_adv_param *param, + const struct bt_mesh_ble_adv_data *data, u8_t *index); + +int bt_mesh_stop_ble_advertising(u8_t index); +#endif /* CONFIG_BLE_MESH_SUPPORT_BLE_ADV */ + #endif /* _ADV_H_ */ diff --git a/components/bt/esp_ble_mesh/mesh_core/bluedroid_host/mesh_bearer_adapt.c b/components/bt/esp_ble_mesh/mesh_core/bluedroid_host/mesh_bearer_adapt.c index 0a1f29f89..11e092eef 100644 --- a/components/bt/esp_ble_mesh/mesh_core/bluedroid_host/mesh_bearer_adapt.c +++ b/components/bt/esp_ble_mesh/mesh_core/bluedroid_host/mesh_bearer_adapt.c @@ -401,6 +401,50 @@ int bt_le_adv_start(const struct bt_mesh_adv_param *param, return 0; } +#if CONFIG_BLE_MESH_SUPPORT_BLE_ADV +int bt_mesh_ble_adv_start(const struct bt_mesh_ble_adv_param *param, + const struct bt_mesh_ble_adv_data *data) +{ + struct bt_mesh_hci_cp_set_adv_data set = {0}; + tBTM_BLE_ADV_CHNL_MAP channel_map = 0U; + tBTM_BLE_AFP adv_fil_pol = 0U; + tBLE_BD_ADDR p_dir_bda = {0}; + + if (data && param->adv_type != BLE_MESH_ADV_DIRECT_IND && + param->adv_type != BLE_MESH_ADV_DIRECT_IND_LOW_DUTY) { + if (data->adv_data_len) { + set.len = data->adv_data_len; + memcpy(set.data, data->adv_data, data->adv_data_len); + BLE_MESH_BTM_CHECK_STATUS(BTM_BleWriteAdvDataRaw(set.data, set.len)); + } + if (data->scan_rsp_data_len && param->adv_type != BLE_MESH_ADV_NONCONN_IND) { + set.len = data->scan_rsp_data_len; + memcpy(set.data, data->scan_rsp_data, data->scan_rsp_data_len); + BLE_MESH_BTM_CHECK_STATUS(BTM_BleWriteScanRspRaw(set.data, set.len)); + } + } + + channel_map = BLE_MESH_ADV_CHNL_37 | BLE_MESH_ADV_CHNL_38 | BLE_MESH_ADV_CHNL_39; + adv_fil_pol = BLE_MESH_AP_SCAN_CONN_ALL; + if (param->own_addr_type == BLE_MESH_ADDR_PUBLIC_ID || + param->own_addr_type == BLE_MESH_ADDR_RANDOM_ID || + param->adv_type == BLE_MESH_ADV_DIRECT_IND || + param->adv_type == BLE_MESH_ADV_DIRECT_IND_LOW_DUTY) { + p_dir_bda.type = param->peer_addr_type; + memcpy(p_dir_bda.bda, param->peer_addr, BLE_MESH_ADDR_LEN); + } + + /* Check if we can start adv using BTM_BleSetAdvParamsStartAdvCheck */ + BLE_MESH_BTM_CHECK_STATUS( + BTM_BleSetAdvParamsAll(param->interval, param->interval, param->adv_type, + param->own_addr_type, &p_dir_bda, + channel_map, adv_fil_pol, NULL)); + BLE_MESH_BTM_CHECK_STATUS(BTM_BleStartAdv()); + + return 0; +} +#endif /* CONFIG_BLE_MESH_SUPPORT_BLE_ADV */ + int bt_le_adv_stop(void) { #if BLE_MESH_DEV diff --git a/components/bt/esp_ble_mesh/mesh_core/include/mesh_bearer_adapt.h b/components/bt/esp_ble_mesh/mesh_core/include/mesh_bearer_adapt.h index 450452df1..6c18ae0b7 100644 --- a/components/bt/esp_ble_mesh/mesh_core/include/mesh_bearer_adapt.h +++ b/components/bt/esp_ble_mesh/mesh_core/include/mesh_bearer_adapt.h @@ -394,6 +394,32 @@ struct bt_mesh_adv_param { u16_t interval_max; }; +#if CONFIG_BLE_MESH_SUPPORT_BLE_ADV +enum bt_mesh_ble_adv_priority { + BLE_MESH_BLE_ADV_PRIO_LOW, + BLE_MESH_BLE_ADV_PRIO_HIGH, +}; + +struct bt_mesh_ble_adv_param { + u16_t interval; /* Advertising interval */ + u8_t adv_type; /* Advertising type */ + u8_t own_addr_type; /* Own address type */ + u8_t peer_addr_type; /* Peer address type */ + u8_t peer_addr[6]; /* Peer address */ + u16_t duration; /* Duration is milliseconds */ + u16_t period; /* Period in milliseconds */ + u16_t count; /* Number of advertising duration */ + u8_t priority:2; /* Priority of BLE advertising packet */ +}; + +struct bt_mesh_ble_adv_data { + u8_t adv_data_len; /* Advertising data length */ + u8_t adv_data[31]; /* Advertising data */ + u8_t scan_rsp_data_len; /* Scan response data length */ + u8_t scan_rsp_data[31]; /* Scan response data */ +}; +#endif /* CONFIG_BLE_MESH_SUPPORT_BLE_ADV */ + /* BLE Mesh scan parameters */ struct bt_mesh_scan_param { /** Scan type (BLE_MESH_SCAN_ACTIVE or BLE_MESH_SCAN_PASSIVE) */ @@ -652,6 +678,11 @@ int bt_le_adv_start(const struct bt_mesh_adv_param *param, const struct bt_mesh_adv_data *ad, size_t ad_len, const struct bt_mesh_adv_data *sd, size_t sd_len); +#if CONFIG_BLE_MESH_SUPPORT_BLE_ADV +int bt_mesh_ble_adv_start(const struct bt_mesh_ble_adv_param *param, + const struct bt_mesh_ble_adv_data *data); +#endif + int bt_le_adv_stop(void); int bt_le_scan_start(const struct bt_mesh_scan_param *param, bt_mesh_scan_cb_t cb); diff --git a/components/bt/esp_ble_mesh/mesh_core/nimble_host/mesh_bearer_adapt.c b/components/bt/esp_ble_mesh/mesh_core/nimble_host/mesh_bearer_adapt.c index 8db87d67b..e034762e6 100644 --- a/components/bt/esp_ble_mesh/mesh_core/nimble_host/mesh_bearer_adapt.c +++ b/components/bt/esp_ble_mesh/mesh_core/nimble_host/mesh_bearer_adapt.c @@ -846,6 +846,79 @@ again: return 0; } +#if CONFIG_BLE_MESH_SUPPORT_BLE_ADV +int bt_mesh_ble_adv_start(const struct bt_mesh_ble_adv_param *param, + const struct bt_mesh_ble_adv_data *data) +{ + struct ble_gap_adv_params adv_params = {0}; + ble_addr_t p_dir_bda = {0}; + int err = 0; + + if (data && param->adv_type != BLE_MESH_ADV_DIRECT_IND && + param->adv_type != BLE_MESH_ADV_DIRECT_IND_LOW_DUTY) { + if (data->adv_data_len) { + err = ble_gap_adv_set_data(data->adv_data, data->adv_data_len); + if (err) { + BT_ERR("Failed to set advertising data, err %d", err); + return err; + } + } + if (data->scan_rsp_data_len && param->adv_type != BLE_MESH_ADV_NONCONN_IND) { + err = ble_gap_adv_rsp_set_data(data->scan_rsp_data, data->scan_rsp_data_len); + if (err) { + BT_ERR("Failed to set scan rsp data, err %d", err); + return err; + } + } + } + + switch (param->adv_type) { + case BLE_MESH_ADV_IND: + adv_params.conn_mode = BLE_GAP_CONN_MODE_UND; + adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN; + break; + case BLE_MESH_ADV_DIRECT_IND: + adv_params.conn_mode = BLE_GAP_CONN_MODE_DIR; + adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN; + break; + case BLE_MESH_ADV_SCAN_IND: + adv_params.conn_mode = BLE_GAP_CONN_MODE_NON; + adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN; + break; + case BLE_MESH_ADV_NONCONN_IND: + adv_params.conn_mode = BLE_GAP_CONN_MODE_NON; + adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN; + break; + case BLE_MESH_ADV_DIRECT_IND_LOW_DUTY: + adv_params.conn_mode = BLE_GAP_CONN_MODE_DIR; + adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN; + break; + } + adv_params.itvl_min = param->interval; + adv_params.itvl_max = param->interval; + adv_params.channel_map = BLE_MESH_ADV_CHNL_37 | BLE_MESH_ADV_CHNL_38 | BLE_MESH_ADV_CHNL_39; + adv_params.filter_policy = BLE_MESH_AP_SCAN_CONN_ALL; + adv_params.high_duty_cycle = (param->adv_type == BLE_MESH_ADV_DIRECT_IND) ? true : false; + + if (param->own_addr_type == BLE_MESH_ADDR_PUBLIC_ID || + param->own_addr_type == BLE_MESH_ADDR_RANDOM_ID || + param->adv_type == BLE_MESH_ADV_DIRECT_IND || + param->adv_type == BLE_MESH_ADV_DIRECT_IND_LOW_DUTY) { + p_dir_bda.type = param->peer_addr_type; + memcpy(p_dir_bda.val, param->peer_addr, BLE_MESH_ADDR_LEN); + } + + err = ble_gap_adv_start(param->own_addr_type, &p_dir_bda, BLE_HS_FOREVER, &adv_params, + gap_event_cb, NULL); + if (err) { + BT_ERR("Failed to start advertising, err %d", err); + return err; + } + + return 0; +} +#endif /* CONFIG_BLE_MESH_SUPPORT_BLE_ADV */ + int bt_le_adv_stop(void) { #if BLE_MESH_DEV