advanced_https_ota: Added BLE GATTS code.

`advanced_https_ota` can run a minimal BLE GATT server while
downloading OTA update. Both NimBLE and Bluedroid stack can be used
here by configuring relevant options in menuconfig.

Signed-off-by: Chinmay Chhajed <chinmay.chhajed@espressif.com>
This commit is contained in:
Chinmay Chhajed 2021-03-02 16:00:49 +05:30
parent b05ac11456
commit 3eaf78d462
13 changed files with 1218 additions and 2 deletions

View File

@ -555,6 +555,92 @@ def test_examples_protocol_advanced_https_ota_example_partial_request(env, extra
dut1.reset()
@ttfw_idf.idf_example_test(env_tag='Example_WIFI_OTA')
def test_examples_protocol_advanced_https_ota_example_nimble_gatts(env, extra_data):
"""
Run an OTA image update while a BLE GATT Server is running in background. This GATT server will be using NimBLE Host stack.
steps: |
1. join AP
2. Run BLE advertise and then GATT server.
3. Fetch OTA image over HTTPS
4. Reboot with the new OTA image
"""
dut1 = env.get_dut('advanced_https_ota_example', 'examples/system/ota/advanced_https_ota', dut_class=ttfw_idf.ESP32DUT, app_config_name='nimble')
server_port = 8001
# File to be downloaded. This file is generated after compilation
bin_name = 'advanced_https_ota.bin'
# check and log bin size
binary_file = os.path.join(dut1.app.binary_path, bin_name)
bin_size = os.path.getsize(binary_file)
ttfw_idf.log_performance('advanced_https_ota_bin_size', '{}KB'.format(bin_size // 1024))
# start test
host_ip = get_my_ip()
if (get_server_status(host_ip, server_port) is False):
thread1 = Thread(target=start_https_server, args=(dut1.app.binary_path, host_ip, server_port))
thread1.daemon = True
thread1.start()
dut1.start_app()
dut1.expect('Loaded app from partition at offset', timeout=30)
try:
ip_address = dut1.expect(re.compile(r' sta ip: ([^,]+),'), timeout=30)
print('Connected to AP with IP: {}'.format(ip_address))
except DUT.ExpectTimeout:
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP')
dut1.expect('Starting Advanced OTA example', timeout=30)
print('writing to device: {}'.format('https://' + host_ip + ':' + str(server_port) + '/' + bin_name))
dut1.expect('GAP procedure initiated: advertise', timeout=30)
print('Started GAP advertising.')
dut1.write('https://' + host_ip + ':' + str(server_port) + '/' + bin_name)
dut1.expect('Loaded app from partition at offset', timeout=60)
dut1.expect('Starting Advanced OTA example', timeout=30)
dut1.reset()
@ttfw_idf.idf_example_test(env_tag='Example_WIFI_OTA')
def test_examples_protocol_advanced_https_ota_example_bluedroid_gatts(env, extra_data):
"""
Run an OTA image update while a BLE GATT Server is running in background. This GATT server will be using Bluedroid Host stack.
steps: |
1. join AP
2. Run BLE advertise and then GATT server.
3. Fetch OTA image over HTTPS
4. Reboot with the new OTA image
"""
dut1 = env.get_dut('advanced_https_ota_example', 'examples/system/ota/advanced_https_ota', dut_class=ttfw_idf.ESP32DUT, app_config_name='bluedroid')
server_port = 8001
# File to be downloaded. This file is generated after compilation
bin_name = 'advanced_https_ota.bin'
# check and log bin size
binary_file = os.path.join(dut1.app.binary_path, bin_name)
bin_size = os.path.getsize(binary_file)
ttfw_idf.log_performance('advanced_https_ota_bin_size', '{}KB'.format(bin_size // 1024))
# start test
host_ip = get_my_ip()
if (get_server_status(host_ip, server_port) is False):
thread1 = Thread(target=start_https_server, args=(dut1.app.binary_path, host_ip, server_port))
thread1.daemon = True
thread1.start()
dut1.start_app()
dut1.expect('Loaded app from partition at offset', timeout=30)
try:
ip_address = dut1.expect(re.compile(r' sta ip: ([^,]+),'), timeout=30)
print('Connected to AP with IP: {}'.format(ip_address))
except DUT.ExpectTimeout:
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP')
dut1.expect('Starting Advanced OTA example', timeout=30)
print('writing to device: {}'.format('https://' + host_ip + ':' + str(server_port) + '/' + bin_name))
dut1.expect('Started advertising.', timeout=30)
print('Started GAP advertising.')
dut1.write('https://' + host_ip + ':' + str(server_port) + '/' + bin_name)
dut1.expect('Loaded app from partition at offset', timeout=60)
dut1.expect('Starting Advanced OTA example', timeout=30)
dut1.reset()
if __name__ == '__main__':
test_examples_protocol_advanced_https_ota_example()
test_examples_protocol_advanced_https_ota_example_chunked()
@ -564,3 +650,5 @@ if __name__ == '__main__':
test_examples_protocol_advanced_https_ota_example_random()
test_examples_protocol_advanced_https_ota_example_anti_rollback()
test_examples_protocol_advanced_https_ota_example_partial_request()
test_examples_protocol_advanced_https_ota_example_nimble_gatts()
test_examples_protocol_advanced_https_ota_example_bluedroid_gatts()

View File

@ -1,4 +1,5 @@
idf_component_register(SRCS "advanced_https_ota_example.c"
INCLUDE_DIRS "."
idf_component_register(SRCS "advanced_https_ota_example.c" "ble_helper/bluedroid_gatts.c" "ble_helper/nimble_gatts.c"
"ble_helper/ble_api.c"
INCLUDE_DIRS "." "./ble_helper/include/"
# Embed the server root certificate into the final binary
EMBED_TXTFILES ${project_dir}/server_certs/ca_cert.pem)

View File

@ -28,6 +28,10 @@
#include "esp_wifi.h"
#endif
#if CONFIG_BT_BLE_ENABLED || CONFIG_BT_NIMBLE_ENABLED
#include "ble_api.h"
#endif
static const char *TAG = "advanced_https_ota_example";
extern const uint8_t server_cert_pem_start[] asm("_binary_ca_cert_pem_start");
extern const uint8_t server_cert_pem_end[] asm("_binary_ca_cert_pem_end");
@ -213,11 +217,24 @@ void app_main(void)
#endif
#if CONFIG_EXAMPLE_CONNECT_WIFI
#if !CONFIG_BT_ENABLED
/* Ensure to disable any WiFi power save mode, this allows best throughput
* and hence timings for overall OTA operation.
*/
esp_wifi_set_ps(WIFI_PS_NONE);
#else
/* WIFI_PS_MIN_MODEM is the default mode for WiFi Power saving. When both
* WiFi and Bluetooth are running, WiFI modem has to go down, hence we
* need WIFI_PS_MIN_MODEM. And as WiFi modem goes down, OTA download time
* increases.
*/
esp_wifi_set_ps(WIFI_PS_MIN_MODEM);
#endif // CONFIG_BT_ENABLED
#endif // CONFIG_EXAMPLE_CONNECT_WIFI
#if CONFIG_BT_BLE_ENABLED || CONFIG_BT_NIMBLE_ENABLED
esp_ble_helper_init();
#endif
xTaskCreate(&advanced_ota_example_task, "advanced_ota_example_task", 1024 * 8, NULL, 5, NULL);
}

View File

@ -0,0 +1,105 @@
// Copyright 2021 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 "sdkconfig.h"
#if CONFIG_BT_BLE_ENABLED || CONFIG_BT_NIMBLE_ENABLED
#include "ble_api.h"
#include "esp_log.h"
#ifdef CONFIG_BT_NIMBLE_ENABLED
#include "nimble_gatts.h"
#elif CONFIG_BT_BLE_ENABLED
#include "bluedroid_gatts.h"
#endif
#if CONFIG_BT_BLE_ENABLED
static const char *TAG = "BLE_API";
#endif
void esp_ble_helper_init(void)
{
esp_err_t err;
#if CONFIG_BT_BLE_ENABLED
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
err = esp_bt_controller_init(&bt_cfg);
if (err) {
ESP_LOGE(TAG, "%s initialize controller failed: %s\n", __func__, esp_err_to_name(err));
return;
}
err = esp_bt_controller_enable(ESP_BT_MODE_BLE);
if (err) {
ESP_LOGE(TAG, "%s enable controller failed: %s\n", __func__, esp_err_to_name(err));
return;
}
err = esp_bluedroid_init();
if (err) {
ESP_LOGE(TAG, "%s init bluetooth failed: %s\n", __func__, esp_err_to_name(err));
return;
}
err = esp_bluedroid_enable();
if (err) {
ESP_LOGE(TAG, "%s enable bluetooth failed: %s\n", __func__, esp_err_to_name(err));
return;
}
err = esp_ble_gatts_register_callback(gatts_event_handler);
if (err) {
ESP_LOGE(TAG, "gatts register error, error code = %x", err);
return;
}
err = esp_ble_gap_register_callback(gap_event_handler);
if (err) {
ESP_LOGE(TAG, "gap register error, error code = %x", err);
return;
}
err = esp_ble_gatts_app_register(PROFILE_A_APP_ID);
if (err) {
ESP_LOGE(TAG, "gatts app register error, error code = %x", err);
return;
}
esp_err_t local_mtu_err = esp_ble_gatt_set_local_mtu(500);
if (local_mtu_err) {
ESP_LOGE(TAG, "set local MTU failed, error code = %x", local_mtu_err);
}
#elif CONFIG_BT_NIMBLE_ENABLED
ESP_ERROR_CHECK(esp_nimble_hci_and_controller_init());
nimble_port_init();
/* Initialize the NimBLE host configuration. */
ble_hs_cfg.reset_cb = bleprph_on_reset;
ble_hs_cfg.sync_cb = bleprph_on_sync;
ble_hs_cfg.gatts_register_cb = gatt_svr_register_cb;
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
err = nimble_gatt_svr_init();
assert(err == 0);
/* Set the default device name. */
err = ble_svc_gap_device_name_set("ESP_OTA_GATTS");
assert(err == 0);
ble_store_config_init();
nimble_port_freertos_init(bleprph_host_task);
#endif
}
#endif

View File

@ -0,0 +1,411 @@
// Copyright 2021 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 "bluedroid_gatts.h"
#include "esp_log.h"
#include "string.h"
#if CONFIG_BT_BLE_ENABLED
static const char *TAG = "bluedroid_gatts";
uint8_t adv_service_uuid128[32] = {
/* LSB <--------------------------------------------------------------------------------> MSB */
//first uuid, 16bit, [12],[13] is the value
0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xEE, 0x00, 0x00, 0x00,
//second uuid, 32bit, [12], [13], [14], [15] is the value
0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
};
// The length of adv data must be less than 31 bytes
//adv data
esp_ble_adv_data_t adv_data = {
.set_scan_rsp = false,
.include_name = true,
.include_txpower = false,
.min_interval = 0x0006, //slave connection min interval, Time = min_interval * 1.25 msec
.max_interval = 0x0010, //slave connection max interval, Time = max_interval * 1.25 msec
.appearance = 0x00,
.manufacturer_len = 0, //TEST_MANUFACTURER_DATA_LEN,
.p_manufacturer_data = NULL, //&test_manufacturer[0],
.service_data_len = 0,
.p_service_data = NULL,
.service_uuid_len = sizeof(adv_service_uuid128),
.p_service_uuid = adv_service_uuid128,
.flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT),
};
// scan response data
esp_ble_adv_data_t scan_rsp_data = {
.set_scan_rsp = true,
.include_name = true,
.include_txpower = true,
.appearance = 0x00,
.manufacturer_len = 0, //TEST_MANUFACTURER_DATA_LEN,
.p_manufacturer_data = NULL, //&test_manufacturer[0],
.service_data_len = 0,
.p_service_data = NULL,
.service_uuid_len = sizeof(adv_service_uuid128),
.p_service_uuid = adv_service_uuid128,
.flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT),
};
esp_ble_adv_params_t adv_params = {
.adv_int_min = 0x20,
.adv_int_max = 0x40,
.adv_type = ADV_TYPE_IND,
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
.channel_map = ADV_CHNL_ALL,
.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
};
uint8_t char1_str[] = {0x11, 0x22, 0x33};
esp_attr_value_t gatts_demo_char1_val = {
.attr_max_len = GATTS_DEMO_CHAR_VAL_LEN_MAX,
.attr_len = sizeof(char1_str),
.attr_value = char1_str,
};
uint8_t adv_config_done = 0;
esp_gatt_char_prop_t a_property = 0;
static struct gatts_profile_inst gl_profile_tab[PROFILE_NUM] = {
[PROFILE_A_APP_ID] = {
.gatts_cb = gatts_profile_a_event_handler,
.gatts_if = ESP_GATT_IF_NONE, /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */
},
};
void example_exec_write_event_env(prepare_type_env_t *prepare_write_env, esp_ble_gatts_cb_param_t *param)
{
if (param->exec_write.exec_write_flag == ESP_GATT_PREP_WRITE_EXEC) {
esp_log_buffer_hex(TAG, prepare_write_env->prepare_buf, prepare_write_env->prepare_len);
} else {
ESP_LOGI(TAG, "ESP_GATT_PREP_WRITE_CANCEL");
}
if (prepare_write_env->prepare_buf) {
free(prepare_write_env->prepare_buf);
prepare_write_env->prepare_buf = NULL;
}
prepare_write_env->prepare_len = 0;
}
void example_write_event_env(esp_gatt_if_t gatts_if, prepare_type_env_t *prepare_write_env, esp_ble_gatts_cb_param_t *param)
{
esp_gatt_status_t status = ESP_GATT_OK;
if (param->write.need_rsp) {
if (param->write.is_prep) {
if (prepare_write_env->prepare_buf == NULL) {
prepare_write_env->prepare_buf = (uint8_t *)malloc(PREPARE_BUF_MAX_SIZE * sizeof(uint8_t));
prepare_write_env->prepare_len = 0;
if (prepare_write_env->prepare_buf == NULL) {
ESP_LOGE(TAG, "Gatt_server prep no mem\n");
status = ESP_GATT_NO_RESOURCES;
}
} else {
if (param->write.offset > PREPARE_BUF_MAX_SIZE) {
status = ESP_GATT_INVALID_OFFSET;
} else if ((param->write.offset + param->write.len) > PREPARE_BUF_MAX_SIZE) {
status = ESP_GATT_INVALID_ATTR_LEN;
}
}
esp_gatt_rsp_t *gatt_rsp = (esp_gatt_rsp_t *)malloc(sizeof(esp_gatt_rsp_t));
gatt_rsp->attr_value.len = param->write.len;
gatt_rsp->attr_value.handle = param->write.handle;
gatt_rsp->attr_value.offset = param->write.offset;
gatt_rsp->attr_value.auth_req = ESP_GATT_AUTH_REQ_NONE;
memcpy(gatt_rsp->attr_value.value, param->write.value, param->write.len);
esp_err_t response_err = esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, status, gatt_rsp);
if (response_err != ESP_OK) {
ESP_LOGE(TAG, "Send response error\n");
}
free(gatt_rsp);
if (status != ESP_GATT_OK) {
return;
}
memcpy(prepare_write_env->prepare_buf + param->write.offset,
param->write.value,
param->write.len);
prepare_write_env->prepare_len += param->write.len;
} else {
esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, status, NULL);
}
}
}
void gatts_profile_a_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
{
switch (event) {
case ESP_GATTS_REG_EVT:
ESP_LOGI(TAG, "REGISTER_APP_EVT, status %d, app_id %d\n", param->reg.status, param->reg.app_id);
gl_profile_tab[PROFILE_A_APP_ID].service_id.is_primary = true;
gl_profile_tab[PROFILE_A_APP_ID].service_id.id.inst_id = 0x00;
gl_profile_tab[PROFILE_A_APP_ID].service_id.id.uuid.len = ESP_UUID_LEN_16;
gl_profile_tab[PROFILE_A_APP_ID].service_id.id.uuid.uuid.uuid16 = GATTS_SERVICE_UUID_TEST_A;
esp_err_t set_dev_name_ret = esp_ble_gap_set_device_name(TEST_DEVICE_NAME);
if (set_dev_name_ret) {
ESP_LOGE(TAG, "set device name failed, error code = %x", set_dev_name_ret);
}
//config adv data
esp_err_t ret = esp_ble_gap_config_adv_data(&adv_data);
if (ret) {
ESP_LOGE(TAG, "config adv data failed, error code = %x", ret);
}
adv_config_done |= adv_config_flag;
//config scan response data
ret = esp_ble_gap_config_adv_data(&scan_rsp_data);
if (ret) {
ESP_LOGE(TAG, "config scan response data failed, error code = %x", ret);
}
adv_config_done |= scan_rsp_config_flag;
esp_ble_gatts_create_service(gatts_if, &gl_profile_tab[PROFILE_A_APP_ID].service_id, GATTS_NUM_HANDLE_TEST_A);
break;
case ESP_GATTS_READ_EVT: {
ESP_LOGI(TAG, "GATT_READ_EVT, conn_id %d, trans_id %d, handle %d\n", param->read.conn_id, param->read.trans_id, param->read.handle);
esp_gatt_rsp_t rsp;
memset(&rsp, 0, sizeof(esp_gatt_rsp_t));
rsp.attr_value.handle = param->read.handle;
rsp.attr_value.len = 4;
rsp.attr_value.value[0] = 0xde;
rsp.attr_value.value[1] = 0xed;
rsp.attr_value.value[2] = 0xbe;
rsp.attr_value.value[3] = 0xef;
esp_ble_gatts_send_response(gatts_if, param->read.conn_id, param->read.trans_id,
ESP_GATT_OK, &rsp);
break;
}
case ESP_GATTS_WRITE_EVT: {
ESP_LOGI(TAG, "GATT_WRITE_EVT, conn_id %d, trans_id %d, handle %d", param->write.conn_id, param->write.trans_id, param->write.handle);
if (!param->write.is_prep) {
ESP_LOGI(TAG, "GATT_WRITE_EVT, value len %d, value :", param->write.len);
esp_log_buffer_hex(TAG, param->write.value, param->write.len);
if (gl_profile_tab[PROFILE_A_APP_ID].descr_handle == param->write.handle && param->write.len == 2) {
uint16_t descr_value = param->write.value[1] << 8 | param->write.value[0];
if (descr_value == 0x0001) {
if (a_property & ESP_GATT_CHAR_PROP_BIT_NOTIFY) {
ESP_LOGI(TAG, "notify enable");
uint8_t notify_data[15];
for (int i = 0; i < sizeof(notify_data); ++i) {
notify_data[i] = i % 0xff;
}
//the size of notify_data[] need less than MTU size
esp_ble_gatts_send_indicate(gatts_if, param->write.conn_id, gl_profile_tab[PROFILE_A_APP_ID].char_handle,
sizeof(notify_data), notify_data, false);
}
} else if (descr_value == 0x0002) {
if (a_property & ESP_GATT_CHAR_PROP_BIT_INDICATE) {
ESP_LOGI(TAG, "indicate enable");
uint8_t indicate_data[15];
for (int i = 0; i < sizeof(indicate_data); ++i) {
indicate_data[i] = i % 0xff;
}
//the size of indicate_data[] need less than MTU size
esp_ble_gatts_send_indicate(gatts_if, param->write.conn_id, gl_profile_tab[PROFILE_A_APP_ID].char_handle,
sizeof(indicate_data), indicate_data, true);
}
} else if (descr_value == 0x0000) {
ESP_LOGI(TAG, "notify/indicate disable ");
} else {
ESP_LOGE(TAG, "unknown descr value");
esp_log_buffer_hex(TAG, param->write.value, param->write.len);
}
}
}
example_write_event_env(gatts_if, &a_prepare_write_env, param);
break;
}
case ESP_GATTS_EXEC_WRITE_EVT:
ESP_LOGI(TAG, "ESP_GATTS_EXEC_WRITE_EVT");
esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, NULL);
example_exec_write_event_env(&a_prepare_write_env, param);
break;
case ESP_GATTS_MTU_EVT:
ESP_LOGI(TAG, "ESP_GATTS_MTU_EVT, MTU %d", param->mtu.mtu);
break;
case ESP_GATTS_UNREG_EVT:
break;
case ESP_GATTS_CREATE_EVT:
ESP_LOGI(TAG, "CREATE_SERVICE_EVT, status %d, service_handle %d\n", param->create.status, param->create.service_handle);
gl_profile_tab[PROFILE_A_APP_ID].service_handle = param->create.service_handle;
gl_profile_tab[PROFILE_A_APP_ID].char_uuid.len = ESP_UUID_LEN_16;
gl_profile_tab[PROFILE_A_APP_ID].char_uuid.uuid.uuid16 = GATTS_CHAR_UUID_TEST_A;
esp_ble_gatts_start_service(gl_profile_tab[PROFILE_A_APP_ID].service_handle);
a_property = ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_WRITE | ESP_GATT_CHAR_PROP_BIT_NOTIFY;
esp_err_t add_char_ret = esp_ble_gatts_add_char(gl_profile_tab[PROFILE_A_APP_ID].service_handle, &gl_profile_tab[PROFILE_A_APP_ID].char_uuid,
ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
a_property,
&gatts_demo_char1_val, NULL);
if (add_char_ret) {
ESP_LOGE(TAG, "add char failed, error code =%x", add_char_ret);
}
break;
case ESP_GATTS_ADD_INCL_SRVC_EVT:
break;
case ESP_GATTS_ADD_CHAR_EVT: {
uint16_t length = 0;
const uint8_t *prf_char;
ESP_LOGI(TAG, "ADD_CHAR_EVT, status %d, attr_handle %d, service_handle %d\n",
param->add_char.status, param->add_char.attr_handle, param->add_char.service_handle);
gl_profile_tab[PROFILE_A_APP_ID].char_handle = param->add_char.attr_handle;
gl_profile_tab[PROFILE_A_APP_ID].descr_uuid.len = ESP_UUID_LEN_16;
gl_profile_tab[PROFILE_A_APP_ID].descr_uuid.uuid.uuid16 = ESP_GATT_UUID_CHAR_CLIENT_CONFIG;
esp_err_t get_attr_ret = esp_ble_gatts_get_attr_value(param->add_char.attr_handle, &length, &prf_char);
if (get_attr_ret == ESP_FAIL) {
ESP_LOGE(TAG, "ILLEGAL HANDLE");
}
ESP_LOGI(TAG, "the gatts demo char length = %x\n", length);
for (int i = 0; i < length; i++) {
ESP_LOGI(TAG, "prf_char[%x] =%x\n", i, prf_char[i]);
}
esp_err_t add_descr_ret = esp_ble_gatts_add_char_descr(gl_profile_tab[PROFILE_A_APP_ID].service_handle, &gl_profile_tab[PROFILE_A_APP_ID].descr_uuid,
ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, NULL, NULL);
if (add_descr_ret) {
ESP_LOGE(TAG, "add char descr failed, error code =%x", add_descr_ret);
}
break;
}
case ESP_GATTS_ADD_CHAR_DESCR_EVT:
gl_profile_tab[PROFILE_A_APP_ID].descr_handle = param->add_char_descr.attr_handle;
ESP_LOGI(TAG, "ADD_DESCR_EVT, status %d, attr_handle %d, service_handle %d\n",
param->add_char_descr.status, param->add_char_descr.attr_handle, param->add_char_descr.service_handle);
break;
case ESP_GATTS_DELETE_EVT:
break;
case ESP_GATTS_START_EVT:
ESP_LOGI(TAG, "SERVICE_START_EVT, status %d, service_handle %d\n",
param->start.status, param->start.service_handle);
break;
case ESP_GATTS_STOP_EVT:
break;
case ESP_GATTS_CONNECT_EVT: {
esp_ble_conn_update_params_t conn_params = {0};
memcpy(conn_params.bda, param->connect.remote_bda, sizeof(esp_bd_addr_t));
/* For the IOS system, please reference the apple official documents about the ble connection parameters restrictions. */
conn_params.latency = 0;
conn_params.max_int = 0x20; // max_int = 0x20*1.25ms = 40ms
conn_params.min_int = 0x10; // min_int = 0x10*1.25ms = 20ms
conn_params.timeout = 400; // timeout = 400*10ms = 4000ms
ESP_LOGI(TAG, "ESP_GATTS_CONNECT_EVT, conn_id %d, remote %02x:%02x:%02x:%02x:%02x:%02x:",
param->connect.conn_id,
param->connect.remote_bda[0], param->connect.remote_bda[1], param->connect.remote_bda[2],
param->connect.remote_bda[3], param->connect.remote_bda[4], param->connect.remote_bda[5]);
gl_profile_tab[PROFILE_A_APP_ID].conn_id = param->connect.conn_id;
//start sent the update connection parameters to the peer device.
esp_ble_gap_update_conn_params(&conn_params);
break;
}
case ESP_GATTS_DISCONNECT_EVT:
ESP_LOGI(TAG, "ESP_GATTS_DISCONNECT_EVT, disconnect reason 0x%x", param->disconnect.reason);
esp_ble_gap_start_advertising(&adv_params);
break;
case ESP_GATTS_CONF_EVT:
ESP_LOGI(TAG, "ESP_GATTS_CONF_EVT, status %d attr_handle %d", param->conf.status, param->conf.handle);
if (param->conf.status != ESP_GATT_OK) {
esp_log_buffer_hex(TAG, param->conf.value, param->conf.len);
}
break;
case ESP_GATTS_OPEN_EVT:
case ESP_GATTS_CANCEL_OPEN_EVT:
case ESP_GATTS_CLOSE_EVT:
case ESP_GATTS_LISTEN_EVT:
case ESP_GATTS_CONGEST_EVT:
default:
break;
}
}
void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
{
switch (event) {
case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT:
adv_config_done &= (~adv_config_flag);
if (adv_config_done == 0) {
if (esp_ble_gap_start_advertising(&adv_params) == ESP_OK) {
ESP_LOGI(TAG, "Started advertising.");
}
}
break;
case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT:
adv_config_done &= (~scan_rsp_config_flag);
if (adv_config_done == 0) {
if (esp_ble_gap_start_advertising(&adv_params) == ESP_OK) {
ESP_LOGI(TAG, "Started advertising.");
}
}
break;
case ESP_GAP_BLE_ADV_START_COMPLETE_EVT:
//advertising start complete event to indicate advertising start successfully or failed
if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) {
ESP_LOGE(TAG, "Advertising start failed\n");
}
break;
case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT:
if (param->adv_stop_cmpl.status != ESP_BT_STATUS_SUCCESS) {
ESP_LOGE(TAG, "Advertising stop failed\n");
} else {
ESP_LOGI(TAG, "Stop adv successfully\n");
}
break;
case ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT:
ESP_LOGI(TAG, "update connection params status = %d, min_int = %d, max_int = %d,conn_int = %d,latency = %d, timeout = %d",
param->update_conn_params.status,
param->update_conn_params.min_int,
param->update_conn_params.max_int,
param->update_conn_params.conn_int,
param->update_conn_params.latency,
param->update_conn_params.timeout);
break;
default:
break;
}
}
void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
{
/* If event is register event, store the gatts_if for each profile */
if (event == ESP_GATTS_REG_EVT) {
if (param->reg.status == ESP_GATT_OK) {
gl_profile_tab[param->reg.app_id].gatts_if = gatts_if;
} else {
ESP_LOGI(TAG, "Reg app failed, app_id %04x, status %d\n",
param->reg.app_id,
param->reg.status);
return;
}
}
/* If the gatts_if equal to profile A, call profile A cb handler,
* so here call each profile's callback */
do {
int idx;
for (idx = 0; idx < PROFILE_NUM; idx++) {
if (gatts_if == ESP_GATT_IF_NONE || /* ESP_GATT_IF_NONE, not specify a certain gatt_if, need to call every profile cb function */
gatts_if == gl_profile_tab[idx].gatts_if) {
if (gl_profile_tab[idx].gatts_cb) {
gl_profile_tab[idx].gatts_cb(event, gatts_if, param);
}
}
}
} while (0);
}
#endif

View File

@ -0,0 +1,28 @@
// Copyright 2021 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.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#if CONFIG_BT_BLE_ENABLED || CONFIG_BT_NIMBLE_ENABLED
void esp_ble_helper_init(void);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,86 @@
// Copyright 2021 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 H_BLUEDROID_GATTS_
#define H_BLUEDROID_GATTS_
#include "sdkconfig.h"
#if CONFIG_BT_BLE_ENABLED
#ifdef __cplusplus
extern "C" {
#endif
#include "esp_bt.h"
#include "esp_gap_ble_api.h"
#include "esp_gatts_api.h"
#include "esp_bt_defs.h"
#include "esp_bt_main.h"
#include "esp_gatt_common_api.h"
#define PROFILE_NUM 1
#define PROFILE_A_APP_ID 0
#define GATTS_SERVICE_UUID_TEST_A 0x00FF
#define GATTS_CHAR_UUID_TEST_A 0xFF01
#define GATTS_DESCR_UUID_TEST_A 0x3333
#define GATTS_NUM_HANDLE_TEST_A 4
#define adv_config_flag (1 << 0)
#define scan_rsp_config_flag (1 << 1)
#define TEST_DEVICE_NAME "ESP_OTA_GATTS"
#define TEST_MANUFACTURER_DATA_LEN 17
#define GATTS_DEMO_CHAR_VAL_LEN_MAX 0x40
#define PREPARE_BUF_MAX_SIZE 1024
struct gatts_profile_inst {
esp_gatts_cb_t gatts_cb;
uint16_t gatts_if;
uint16_t app_id;
uint16_t conn_id;
uint16_t service_handle;
esp_gatt_srvc_id_t service_id;
uint16_t char_handle;
esp_bt_uuid_t char_uuid;
esp_gatt_perm_t perm;
esp_gatt_char_prop_t property;
uint16_t descr_handle;
esp_bt_uuid_t descr_uuid;
};
typedef struct {
uint8_t *prepare_buf;
int prepare_len;
} prepare_type_env_t;
prepare_type_env_t a_prepare_write_env;
void gatts_profile_a_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param);
void example_write_event_env(esp_gatt_if_t gatts_if, prepare_type_env_t *prepare_write_env, esp_ble_gatts_cb_param_t *param);
void example_exec_write_event_env(prepare_type_env_t *prepare_write_env, esp_ble_gatts_cb_param_t *param);
void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param);
void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param);
#ifdef __cplusplus
}
#endif
#endif
#endif

View File

@ -0,0 +1,67 @@
// Copyright 2021 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 H_NIMBLE_GATTS_
#define H_NIMBLE_GATTS_
#include "sdkconfig.h"
#if CONFIG_BT_NIMBLE_ENABLED
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include "nimble/ble.h"
#include "modlog/modlog.h"
#include "esp_nimble_hci.h"
#include "nimble/nimble_port.h"
#include "nimble/nimble_port_freertos.h"
#include "host/ble_hs.h"
#include "host/util/util.h"
#include "console/console.h"
#include "services/gap/ble_svc_gap.h"
struct ble_hs_cfg;
struct ble_gatt_register_ctxt;
int bleprph_gap_event(struct ble_gap_event *event, void *arg);
uint8_t own_addr_type;
/** GATT server. */
#define GATT_SVR_SVC_ALERT_UUID 0x1811
#define GATT_SVR_CHR_SUP_NEW_ALERT_CAT_UUID 0x2A47
#define GATT_SVR_CHR_NEW_ALERT 0x2A46
#define GATT_SVR_CHR_SUP_UNR_ALERT_CAT_UUID 0x2A48
#define GATT_SVR_CHR_UNR_ALERT_STAT_UUID 0x2A45
#define GATT_SVR_CHR_ALERT_NOT_CTRL_PT 0x2A44
void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg);
int nimble_gatt_svr_init(void);
void ble_store_config_init(void);
void print_addr(const void *addr);
void bleprph_print_conn_desc(struct ble_gap_conn_desc *desc);
void bleprph_advertise(void);
int bleprph_gap_event(struct ble_gap_event *event, void *arg);
void bleprph_host_task(void *param);
void bleprph_on_reset(int reason);
void bleprph_on_sync(void);
#ifdef __cplusplus
}
#endif
#endif
#endif

View File

@ -0,0 +1,366 @@
// Copyright 2021 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 "sdkconfig.h"
#if CONFIG_BT_NIMBLE_ENABLED
#include "nimble_gatts.h"
#include "esp_log.h"
#include "services/gatt/ble_svc_gatt.h"
static const char *TAG = "nimble_gatts";
static const ble_uuid128_t gatt_svr_svc_sec_test_uuid =
BLE_UUID128_INIT(0x2d, 0x71, 0xa2, 0x59, 0xb4, 0x58, 0xc8, 0x12,
0x99, 0x99, 0x43, 0x95, 0x12, 0x2f, 0x46, 0x59);
/* 5c3a659e-897e-45e1-b016-007107c96df6 */
static const ble_uuid128_t gatt_svr_chr_sec_test_rand_uuid =
BLE_UUID128_INIT(0xf6, 0x6d, 0xc9, 0x07, 0x71, 0x00, 0x16, 0xb0,
0xe1, 0x45, 0x7e, 0x89, 0x9e, 0x65, 0x3a, 0x5c);
/* 5c3a659e-897e-45e1-b016-007107c96df7 */
static const ble_uuid128_t gatt_svr_chr_sec_test_static_uuid =
BLE_UUID128_INIT(0xf7, 0x6d, 0xc9, 0x07, 0x71, 0x00, 0x16, 0xb0,
0xe1, 0x45, 0x7e, 0x89, 0x9e, 0x65, 0x3a, 0x5c);
static int
gatt_svr_chr_access_sec_test(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt,
void *arg);
static uint8_t gatt_svr_sec_test_static_val;
static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
{
/*** Service: Security test. */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = &gatt_svr_svc_sec_test_uuid.u,
.characteristics = (struct ble_gatt_chr_def[]) { {
/*** Characteristic: Random number generator. */
.uuid = &gatt_svr_chr_sec_test_rand_uuid.u,
.access_cb = gatt_svr_chr_access_sec_test,
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC,
}, {
0, /* No more characteristics in this service. */
} },
},
{
0, /* No more services. */
},
};
static int
gatt_svr_chr_write(struct os_mbuf *om, uint16_t min_len, uint16_t max_len,
void *dst, uint16_t *len)
{
uint16_t om_len;
int rc;
om_len = OS_MBUF_PKTLEN(om);
if (om_len < min_len || om_len > max_len) {
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
}
rc = ble_hs_mbuf_to_flat(om, dst, max_len, len);
if (rc != 0) {
return BLE_ATT_ERR_UNLIKELY;
}
return 0;
}
static int
gatt_svr_chr_access_sec_test(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt,
void *arg)
{
const ble_uuid_t *uuid;
int rand_num;
int rc;
uuid = ctxt->chr->uuid;
/* Determine which characteristic is being accessed by examining its
* 128-bit UUID.
*/
if (ble_uuid_cmp(uuid, &gatt_svr_chr_sec_test_rand_uuid.u) == 0) {
assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
/* Respond with a 32-bit random number. */
rand_num = rand();
rc = os_mbuf_append(ctxt->om, &rand_num, sizeof rand_num);
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
}
if (ble_uuid_cmp(uuid, &gatt_svr_chr_sec_test_static_uuid.u) == 0) {
switch (ctxt->op) {
case BLE_GATT_ACCESS_OP_READ_CHR:
rc = os_mbuf_append(ctxt->om, &gatt_svr_sec_test_static_val,
sizeof gatt_svr_sec_test_static_val);
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
case BLE_GATT_ACCESS_OP_WRITE_CHR:
rc = gatt_svr_chr_write(ctxt->om,
sizeof gatt_svr_sec_test_static_val,
sizeof gatt_svr_sec_test_static_val,
&gatt_svr_sec_test_static_val, NULL);
return rc;
default:
assert(0);
return BLE_ATT_ERR_UNLIKELY;
}
}
/* Unknown characteristic; the nimble stack should not have called this
* function.
*/
assert(0);
return BLE_ATT_ERR_UNLIKELY;
}
void
print_addr(const void *addr)
{
const uint8_t *u8p;
u8p = addr;
MODLOG_DFLT(INFO, "%02x:%02x:%02x:%02x:%02x:%02x",
u8p[5], u8p[4], u8p[3], u8p[2], u8p[1], u8p[0]);
}
/**
* Enables advertising with the following parameters:
* o General discoverable mode.
* o Undirected connectable mode.
*/
void
bleprph_advertise(void)
{
struct ble_gap_adv_params adv_params;
struct ble_hs_adv_fields fields;
const char *name;
int rc;
/**
* Set the advertisement data included in our advertisements:
* o Flags (indicates advertisement type and other general info).
* o Advertising tx power.
* o Device name.
* o 16-bit service UUIDs (alert notifications).
*/
memset(&fields, 0, sizeof fields);
/* Advertise two flags:
* o Discoverability in forthcoming advertisement (general)
* o BLE-only (BR/EDR unsupported).
*/
fields.flags = BLE_HS_ADV_F_DISC_GEN |
BLE_HS_ADV_F_BREDR_UNSUP;
/* Indicate that the TX power level field should be included; have the
* stack fill this value automatically. This is done by assigning the
* special value BLE_HS_ADV_TX_PWR_LVL_AUTO.
*/
fields.tx_pwr_lvl_is_present = 1;
fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO;
name = ble_svc_gap_device_name();
fields.name = (uint8_t *)name;
fields.name_len = strlen(name);
fields.name_is_complete = 1;
fields.uuids16 = (ble_uuid16_t[]) {
BLE_UUID16_INIT(GATT_SVR_SVC_ALERT_UUID)
};
fields.num_uuids16 = 1;
fields.uuids16_is_complete = 1;
rc = ble_gap_adv_set_fields(&fields);
if (rc != 0) {
MODLOG_DFLT(ERROR, "error setting advertisement data; rc=%d\n", rc);
return;
}
/* Begin advertising. */
memset(&adv_params, 0, sizeof adv_params);
adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
rc = ble_gap_adv_start(own_addr_type, NULL, BLE_HS_FOREVER,
&adv_params, bleprph_gap_event, NULL);
if (rc != 0) {
MODLOG_DFLT(ERROR, "error enabling advertisement; rc=%d\n", rc);
return;
}
}
int
bleprph_gap_event(struct ble_gap_event *event, void *arg)
{
struct ble_gap_conn_desc desc;
int rc;
switch (event->type) {
case BLE_GAP_EVENT_CONNECT:
/* A new connection was established or a connection attempt failed. */
MODLOG_DFLT(INFO, "connection %s; status=%d ",
event->connect.status == 0 ? "established" : "failed",
event->connect.status);
if (event->connect.status == 0) {
rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
assert(rc == 0);
bleprph_print_conn_desc(&desc);
}
MODLOG_DFLT(INFO, "\n");
if (event->connect.status != 0) {
/* Connection failed; resume advertising. */
bleprph_advertise();
}
return 0;
case BLE_GAP_EVENT_DISCONNECT:
MODLOG_DFLT(INFO, "disconnect; reason=%d ", event->disconnect.reason);
bleprph_print_conn_desc(&event->disconnect.conn);
MODLOG_DFLT(INFO, "\n");
/* Connection terminated; resume advertising. */
bleprph_advertise();
return 0;
case BLE_GAP_EVENT_CONN_UPDATE:
/* The central has updated the connection parameters. */
MODLOG_DFLT(INFO, "connection updated; status=%d ",
event->conn_update.status);
rc = ble_gap_conn_find(event->conn_update.conn_handle, &desc);
assert(rc == 0);
bleprph_print_conn_desc(&desc);
MODLOG_DFLT(INFO, "\n");
return 0;
case BLE_GAP_EVENT_ADV_COMPLETE:
MODLOG_DFLT(INFO, "advertise complete; reason=%d",
event->adv_complete.reason);
bleprph_advertise();
return 0;
case BLE_GAP_EVENT_MTU:
MODLOG_DFLT(INFO, "mtu update event; conn_handle=%d cid=%d mtu=%d\n",
event->mtu.conn_handle,
event->mtu.channel_id,
event->mtu.value);
return 0;
}
return 0;
}
/**
* Logs information about a connection to the console.
*/
void
bleprph_print_conn_desc(struct ble_gap_conn_desc *desc)
{
MODLOG_DFLT(INFO, "handle=%d our_ota_addr_type=%d our_ota_addr=",
desc->conn_handle, desc->our_ota_addr.type);
print_addr(desc->our_ota_addr.val);
MODLOG_DFLT(INFO, " our_id_addr_type=%d our_id_addr=",
desc->our_id_addr.type);
print_addr(desc->our_id_addr.val);
MODLOG_DFLT(INFO, " peer_ota_addr_type=%d peer_ota_addr=",
desc->peer_ota_addr.type);
print_addr(desc->peer_ota_addr.val);
MODLOG_DFLT(INFO, " peer_id_addr_type=%d peer_id_addr=",
desc->peer_id_addr.type);
print_addr(desc->peer_id_addr.val);
MODLOG_DFLT(INFO, " conn_itvl=%d conn_latency=%d supervision_timeout=%d "
"encrypted=%d authenticated=%d bonded=%d\n",
desc->conn_itvl, desc->conn_latency,
desc->supervision_timeout,
desc->sec_state.encrypted,
desc->sec_state.authenticated,
desc->sec_state.bonded);
}
void
bleprph_on_reset(int reason)
{
MODLOG_DFLT(ERROR, "Resetting state; reason=%d\n", reason);
}
void
bleprph_on_sync(void)
{
int rc;
rc = ble_hs_util_ensure_addr(0);
assert(rc == 0);
/* Figure out address to use while advertising (no privacy for now) */
rc = ble_hs_id_infer_auto(0, &own_addr_type);
if (rc != 0) {
MODLOG_DFLT(ERROR, "error determining address type; rc=%d\n", rc);
return;
}
/* Printing ADDR */
uint8_t addr_val[6] = {0};
rc = ble_hs_id_copy_addr(own_addr_type, addr_val, NULL);
MODLOG_DFLT(INFO, "Device Address: ");
print_addr(addr_val);
MODLOG_DFLT(INFO, "\n");
/* Begin advertising. */
bleprph_advertise();
}
void bleprph_host_task(void *param)
{
ESP_LOGI(TAG, "BLE Host Task Started");
/* This function will return only when nimble_port_stop() is executed */
nimble_port_run();
nimble_port_freertos_deinit();
}
int
nimble_gatt_svr_init(void)
{
int rc;
ble_svc_gap_init();
ble_svc_gatt_init();
rc = ble_gatts_count_cfg(gatt_svr_svcs);
if (rc != 0) {
return rc;
}
rc = ble_gatts_add_svcs(gatt_svr_svcs);
if (rc != 0) {
return rc;
}
return 0;
}
#endif

View File

@ -4,3 +4,6 @@
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
COMPONENT_EMBED_TXTFILES := ${PROJECT_PATH}/server_certs/ca_cert.pem
COMPONENT_ADD_INCLUDEDIRS += ./ble_helper/include
COMPONENT_SRCDIRS += ./ble_helper/

View File

@ -0,0 +1,8 @@
# Name, Type, SubType, Offset, Size, Flags
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
nvs, data, nvs, , 0x4000,
otadata, data, ota, , 0x2000,
phy_init, data, phy, , 0x1000,
ota_0, app, ota_0, , 1500K,
ota_1, app, ota_1, , 1500K,
1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
3 nvs, data, nvs, , 0x4000,
4 otadata, data, ota, , 0x2000,
5 phy_init, data, phy, , 0x1000,
6 ota_0, app, ota_0, , 1500K,
7 ota_1, app, ota_1, , 1500K,

View File

@ -0,0 +1,19 @@
# Enable Bluedroid BLE
CONFIG_BT_ENABLED=y
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
CONFIG_BTDM_CTRL_MODE_BTDM=n
CONFIG_CTRL_BTDM_MODEM_SLEEP=y
CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y
CONFIG_BT_BTU_TASK_STACK_SIZE=4512
CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y
# Partition Table
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_example_with_ble.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions_example_with_ble.csv"
CONFIG_EXAMPLE_FIRMWARE_UPGRADE_URL="FROM_STDIN"
CONFIG_EXAMPLE_SKIP_COMMON_NAME_CHECK=y
CONFIG_EXAMPLE_SKIP_VERSION_CHECK=y
CONFIG_EXAMPLE_OTA_RECV_TIMEOUT=3000

View File

@ -0,0 +1,17 @@
# Enable NimBLE
CONFIG_BT_ENABLED=y
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
CONFIG_BTDM_CTRL_MODE_BTDM=n
CONFIG_BT_BLUEDROID_ENABLED=n
CONFIG_BT_NIMBLE_ENABLED=y
# Partition Table
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_example_with_ble.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions_example_with_ble.csv"
CONFIG_EXAMPLE_FIRMWARE_UPGRADE_URL="FROM_STDIN"
CONFIG_EXAMPLE_SKIP_COMMON_NAME_CHECK=y
CONFIG_EXAMPLE_SKIP_VERSION_CHECK=y
CONFIG_EXAMPLE_OTA_RECV_TIMEOUT=3000