From 8324df64202004a5ce54eada731f756e1abbd4ec Mon Sep 17 00:00:00 2001 From: leo Date: Thu, 14 Apr 2022 20:47:39 +0200 Subject: [PATCH] nimBLE gatt --- components/BTlib/BTlib.c | 16 +- components/BTlib/BTlib_nimble.c | 211 +++++++++++++++++++++++- components/BTlib/CMakeLists.txt | 2 +- components/BTlib/include/BTlib.h | 10 -- components/BTlib/include/BTlib_nimble.h | 113 ++++++++----- main/CO2_Sense.c | 1 + main/Kconfig.projbuild | 9 - sdkconfig | 3 - 8 files changed, 289 insertions(+), 76 deletions(-) diff --git a/components/BTlib/BTlib.c b/components/BTlib/BTlib.c index fe2a7f4..a3a5263 100644 --- a/components/BTlib/BTlib.c +++ b/components/BTlib/BTlib.c @@ -1,3 +1,5 @@ +#ifdef CONFIG_BT_BLUEDROID_ENABLED + #include #include "BTlib.h" #include "esp_log.h" @@ -12,6 +14,11 @@ #define ADV_CONFIG_FLAG (1 << 0) #define SCAN_RSP_CONFIG_FLAG (1 << 1) +static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t* param); +static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t* param); +static void gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t* param); + + static configuration_data_t* main_app_conf; static uint8_t adv_config_done = 0; @@ -23,7 +30,7 @@ static struct gatts_profile_inst env_sense_profile_tab[PROFILE_NUM] = { }, }; -uint16_t env_handle_table[ENV_IDX_NB]; +static uint16_t env_handle_table[ENV_IDX_NB]; static uint8_t service_uuid[16] = { 0x2f, 0x3f, 0x08, 0x63, 0x3b, 0x44, 0x40, 0xa4, 0x71, 0x4a, 0xdc, 0x0c, @@ -171,7 +178,7 @@ static const esp_gatts_attr_db_t gatt_db[ENV_IDX_NB] = }; -void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t* param){ +static 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); @@ -211,7 +218,7 @@ void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t* par } } -void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t* param){ +static 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 == ESP_GATTS_REG_EVT) { if (param->reg.status == ESP_GATT_OK) env_sense_profile_tab[ENVIRONMENTAL_SENSING_IDX].gatts_if = gatts_if; @@ -233,7 +240,7 @@ void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp while (0); } -void gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t* param){ +static void gatts_profile_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_ERROR_CHECK(esp_ble_gap_set_device_name(main_app_conf->hostname)); @@ -329,3 +336,4 @@ void initBle(configuration_data_t* main_conf){ ESP_ERROR_CHECK(esp_ble_gap_register_callback(gap_event_handler)); ESP_ERROR_CHECK(esp_ble_gatts_app_register(SENSOR_BLE_APP_ID)); } +#endif diff --git a/components/BTlib/BTlib_nimble.c b/components/BTlib/BTlib_nimble.c index ec8698f..0fed8fa 100644 --- a/components/BTlib/BTlib_nimble.c +++ b/components/BTlib/BTlib_nimble.c @@ -1,3 +1,6 @@ +#include "sdkconfig.h" +#ifdef CONFIG_BT_NIMBLE_ENABLED + #include "BTlib_nimble.h" #include "nimble/ble.h" @@ -7,7 +10,179 @@ #include "services/gatt/ble_svc_gatt.h" #include "nimble/nimble_port_freertos.h" +static configuration_data_t* main_app_conf; + static uint8_t ble_addr_type; +static uint16_t conn_handle; +static uint16_t hrm_handle[ES_CHAR_NB]; +static uint8_t notify_state[ES_CHAR_NB]; + +static int ble_gap_event(struct ble_gap_event *event, void* arg); + +static int gatt_svr_chr_access_co2(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg); +static int gatt_svr_chr_access_temp(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg); +static int gatt_svr_chr_access_hum(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg); + +static int gatt_svr_init(void); + +ES_char_descr_t CO2_char_descr = { + .flags = 0, // RFU + .sampling_function = ES_SAMPLING_FUNC_INSTANT, + .measurement_period = {30,0,0}, + .update_interval = {30,0,0}, + .application = ES_APP_AIR, + .measurement_uncertainty = 10, +}; +ES_char_descr_t temp_char_descr = { + .flags = 0, // RFU + .sampling_function = ES_SAMPLING_FUNC_INSTANT, + .measurement_period = {30,0,0}, + .update_interval = {30,0,0}, + .application = ES_APP_AIR, + .measurement_uncertainty = 5, +}; +ES_char_descr_t hum_char_descr = { + .flags = 0, // RFU + .sampling_function = ES_SAMPLING_FUNC_INSTANT, + .measurement_period = {30,0,0}, + .update_interval = {30,0,0}, + .application = ES_APP_AIR, + .measurement_uncertainty = 30, +}; + +struct ble_hs_adv_fields adv_fields = { + .flags = BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP, + .tx_pwr_lvl_is_present = 1, + .tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO, + .name = (uint8_t*)DEFAULT_NAME, + .name_len = DEFAULT_NAME_LEN, + .name_is_complete = 1, + .appearance = CO2_SENSOR_APPEARANCE, + .appearance_is_present = 1, +}; + +struct ble_gap_adv_params adv_params = { + .conn_mode = BLE_GAP_CONN_MODE_UND, + .disc_mode = BLE_GAP_DISC_MODE_GEN, +}; + + +static struct ble_gatt_svc_def gatt_svr_svcs[] = { + [ES_SVC_IDX] = { + // Environmental sensing service + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(ENVIRONMENTAL_SENSING_UUID), + .characteristics = (struct ble_gatt_chr_def[]){ + // CO2 + [ES_CHAR_CO2] = { + .uuid = BLE_UUID16_DECLARE(CHAR_CO2_UUID), + .access_cb = gatt_svr_chr_access_co2, + .val_handle = &hrm_handle[ES_CHAR_CO2], + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY, + .descriptors = (struct ble_gatt_dsc_def[]){ + { + .uuid = BLE_UUID16_DECLARE(ES_MEASUREMENT_UUID), + .att_flags = BLE_ATT_F_READ, + .access_cb = gatt_svr_chr_access_co2, + }, + { 0 }, + }, + }, + // TEMP + [ES_CHAR_TEMP] = { + .uuid = BLE_UUID16_DECLARE(CHAR_TEMP_UUID), + .access_cb = gatt_svr_chr_access_temp, + .val_handle = &hrm_handle[ES_CHAR_TEMP], + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY, + .descriptors = (struct ble_gatt_dsc_def[]){ + { + .uuid = BLE_UUID16_DECLARE(ES_MEASUREMENT_UUID), + .att_flags = BLE_ATT_F_READ, + .access_cb = gatt_svr_chr_access_temp, + }, + { 0 }, + }, + + }, + // HUMIDITY + [ES_CHAR_HUM] = { + .uuid = BLE_UUID16_DECLARE(CHAR_HUM_UUID), + .access_cb = gatt_svr_chr_access_hum, + .val_handle = &hrm_handle[ES_CHAR_HUM], + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY, + .descriptors = (struct ble_gatt_dsc_def[]){ + { + .uuid = BLE_UUID16_DECLARE(ES_MEASUREMENT_UUID), + .att_flags = BLE_ATT_F_READ, + .access_cb = gatt_svr_chr_access_hum, + }, + { 0 }, + }, + + }, + { 0 }, + }, + }, + { 0 }, +}; + +static int gatt_svr_chr_access_co2(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg){ + int rc = 0; + + ESP_LOGI(NIMBLE_LOG_TAG, "co2 access evt"); + + switch(ctxt->op){ + case BLE_GATT_ACCESS_OP_READ_CHR: + rc = os_mbuf_append(ctxt->om, &main_app_conf->measure->co2, sizeof(main_app_conf->measure->co2)); + break; + case BLE_GATT_ACCESS_OP_READ_DSC: + rc = os_mbuf_append(ctxt->om, &CO2_char_descr, 11); // hardcoded size 'cause struct gets padded to 12bytes + break; + } + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; +} +static int gatt_svr_chr_access_temp(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg){ + int rc = 0; + + ESP_LOGI(NIMBLE_LOG_TAG, "temp access evt"); + + switch(ctxt->op){ + case BLE_GATT_ACCESS_OP_READ_CHR: + { + int16_t raw_temp = main_app_conf->measure->temperature; + int16_t temp = raw_temp/10; + rc = os_mbuf_append(ctxt->om, &temp, sizeof(temp)); + } + break; + case BLE_GATT_ACCESS_OP_READ_DSC: + rc = os_mbuf_append(ctxt->om, &temp_char_descr, 11); // hardcoded size 'cause struct gets padded to 12bytes + break; + } + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; + +} +static int gatt_svr_chr_access_hum(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg){ + int rc = 0; + + ESP_LOGI(NIMBLE_LOG_TAG, "hum access evt"); + + switch(ctxt->op){ + case BLE_GATT_ACCESS_OP_READ_CHR: + { + int32_t raw_hum = main_app_conf->measure->humidity; + int16_t hum = raw_hum/10; + rc = os_mbuf_append(ctxt->om, &hum, sizeof(hum)); + } + break; + case BLE_GATT_ACCESS_OP_READ_DSC: + rc = os_mbuf_append(ctxt->om, &hum_char_descr, 11); // hardcoded size 'cause struct gets padded to 12bytes + break; + } + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; + +} + + static void ble_advertise(void){ ESP_ERROR_CHECK(ble_gap_adv_set_fields(&adv_fields)); @@ -32,9 +207,12 @@ static int ble_gap_event(struct ble_gap_event *event, void* arg){ break; case BLE_GAP_EVENT_SUBSCRIBE: - ESP_LOGI(NIMBLE_LOG_TAG, "subscribe event notify : %b", notify_state); - if(event->subscribe.attr_handle == es_hrm_handle) - notify_state = event->subscribe.cur_notify; + ESP_LOGI(NIMBLE_LOG_TAG, "subscribe event notify : %d", event->subscribe.attr_handle); + for(int i=0; isubscribe.attr_handle == hrm_handle[i]){ + ESP_LOGI(NIMBLE_LOG_TAG, "enabling notifs for %d", i); + notify_state[i] = event->subscribe.cur_notify; + } break; case BLE_GAP_EVENT_MTU: ESP_LOGI(NIMBLE_LOG_TAG, "MTU event"); @@ -73,13 +251,38 @@ static void ble_host_task(void* param){ } void initBle(configuration_data_t* main_conf){ + main_app_conf = main_conf; + adv_fields.name = (uint8_t*)&main_conf->hostname; + adv_fields.name_len = strlen(main_conf->hostname); ESP_ERROR_CHECK(esp_nimble_hci_and_controller_init()); nimble_port_init(); ble_hs_cfg.sync_cb = ble_on_sync; ble_hs_cfg.reset_cb = ble_on_reset; - ESP_ERROR_CHECK(gatt_srv_init()); + ESP_ERROR_CHECK(gatt_svr_init()); ESP_ERROR_CHECK(ble_svc_gap_device_name_set(main_conf->hostname)); nimble_port_freertos_init(ble_host_task); } + +void ble_sensor_notify(){ + if(notify_state[ES_CHAR_CO2]){ + ESP_LOGI(NIMBLE_LOG_TAG, "notify co2"); + uint16_t co2 = main_app_conf->measure->co2; + struct os_mbuf* om = ble_hs_mbuf_from_flat(&co2, sizeof(co2)); + ESP_ERROR_CHECK(ble_gattc_notify_custom(conn_handle, hrm_handle[ES_CHAR_CO2], om)); + } + if(notify_state[ES_CHAR_TEMP]){ + ESP_LOGI(NIMBLE_LOG_TAG, "notify temp"); + int16_t temp = main_app_conf->measure->temperature / 10; + struct os_mbuf* om = ble_hs_mbuf_from_flat(&temp, sizeof(temp)); + ESP_ERROR_CHECK(ble_gattc_notify_custom(conn_handle, hrm_handle[ES_CHAR_TEMP], om)); + } + if(notify_state[ES_CHAR_HUM]){ + ESP_LOGI(NIMBLE_LOG_TAG, "notify hum"); + int16_t hum = main_app_conf->measure->humidity / 10; + struct os_mbuf* om = ble_hs_mbuf_from_flat(&hum, sizeof(hum)); + ESP_ERROR_CHECK(ble_gattc_notify_custom(conn_handle, hrm_handle[ES_CHAR_HUM], om)); + } +} +#endif diff --git a/components/BTlib/CMakeLists.txt b/components/BTlib/CMakeLists.txt index 8a4cb2c..324d2e9 100644 --- a/components/BTlib/CMakeLists.txt +++ b/components/BTlib/CMakeLists.txt @@ -1,3 +1,3 @@ -idf_component_register(SRCS "BTlib.c" +idf_component_register(SRCS "BTlib.c" "BTlib_nimble.c" INCLUDE_DIRS "include" REQUIRES bt configuration sensirion_i2c_scd4x) diff --git a/components/BTlib/include/BTlib.h b/components/BTlib/include/BTlib.h index 3cb097f..cc058bb 100644 --- a/components/BTlib/include/BTlib.h +++ b/components/BTlib/include/BTlib.h @@ -1,5 +1,3 @@ -#ifdef BT_BLUEDROID_USED - #include "esp_gap_ble_api.h" #include "esp_gatts_api.h" @@ -47,12 +45,4 @@ struct gatts_profile_inst { esp_bt_uuid_t descr_uuid; }; - -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); -void gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t* param); - - void initBle(configuration_data_t* main_conf); - -#endif diff --git a/components/BTlib/include/BTlib_nimble.h b/components/BTlib/include/BTlib_nimble.h index c9efba8..846965a 100644 --- a/components/BTlib/include/BTlib_nimble.h +++ b/components/BTlib/include/BTlib_nimble.h @@ -1,3 +1,6 @@ +#ifndef BTLIB_H +#define BTLIB_H + #include "nimble/ble.h" #include "host/ble_hs.h" @@ -6,64 +9,84 @@ #define C_WL_MODE_BLE 0b100 #define ENVIRONMENTAL_SENSING_UUID 0x181A -#define ES_MEASUREMENT_UUID 0x290C; +#define ES_MEASUREMENT_UUID 0x290C #define CHAR_CO2_UUID 0x0C39 #define CHAR_TEMP_UUID 0x2A6E #define CHAR_HUM_UUID 0x2A6F +#define CO2_SENSOR_APPEARANCE 0x054A #define DEFAULT_NAME "CO2_ble" #define DEFAULT_NAME_LEN 7 #define NIMBLE_LOG_TAG "NIMBLE" -uint16_t es_hrm_handle; -uint16_t conn_handle; -uint8_t notify_state; - -struct ble_hs_adv_fields adv_fields = { - .flags = BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP, - .tx_pwr_lvl_is_present = 1, - .tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO, - .name = (uint8_t*)DEFAULT_NAME, - .name_len = DEFAULT_NAME_LEN, - .name_is_complete = 1, +enum { + ES_SAMPLING_FUNC_UNSPEC, + ES_SAMPLING_FUNC_INSTANT, + ES_SAMPLING_FUNC_MEAN, + ES_SAMPLING_FUNC_RMS, + ES_SAMPLING_FUNC_MAX, + ES_SAMPLING_FUNC_MIN, + ES_SAMPLING_FUNC_ACC, + ES_SAMPLING_FUNC_COUNT, }; -struct ble_gap_adv_params adv_params = { - .conn_mode = BLE_GAP_CONN_MODE_UND, - .disc_mode = BLE_GAP_DISC_MODE_GEN, +enum { + ES_APP_UNSPEC, + ES_APP_AIR, + ES_APP_WATER, + ES_APP_BAROMETRIC, + ES_APP_SOIL, + ES_APP_INFRARED, + ES_APP_MAP_DB, + ES_APP_BAROMETRIC_EL, + ES_APP_GPS_EL, + ES_APP_GPS_MAP_EL, + ES_APP_VERT_EL, + ES_APP_ONSHORE, + ES_APP_ONBOARD, + ES_APP_FRONT, + ES_APP_BACK, + ES_APP_UPPER, + ES_APP_LOWER, + ES_APP_PRIMARY, + ES_APP_SECONDARY, + ES_APP_OUTDOOR, + ES_APP_INDOOR, + ES_APP_TOP, + ES_APP_BOTTOM, + ES_APP_MAIN, + ES_APP_BACKUP, + ES_APP_AUXILIARY, + ES_APP_SUPPLEMENTARY, + ES_APP_INSIDE, + ES_APP_OUTSIDE, + ES_APP_LEFT, + ES_APP_RIGHT, + ES_APP_INTERNAL, + ES_APP_EXTERNAL, + ES_APP_SOLAR, }; -struct ble_gatt_svc_def gatt_svr_svcs[] = { - { - // Environmental sensing service - .type = BLE_GATT_SVC_TYPE_PRIMARY, - .uuid = BLE_UUID16_DECLARE(ENVIRONMENTAL_SENSING_UUID), - .characteristics = (struct ble_gatt_chr_def[]){ - // CO2 - { - .uuid = BLE_UUID16_DECLARE(CHAR_CO2_UUID), - .access_cb = gatt_svr_chr_access_co2, - //.val_handle = &es_hrm_handle, - .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY, - }, - // TEMP - { - .uuid = BLE_UUID16_DECLARE(CHAR_TEMP_UUID), - .access_cb = gatt_svr_chr_access_temp, - .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY, - }, - // HUMIDITY - { - .uuid = BLE_UUID16_DECLARE(CHAR_HUM_UUID), - .access_cb = gatt_svr_chr_access_hum, - .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY, - }, - { 0 }, - }, - }, - { 0 }, +enum{ + ES_SVC_IDX, +}; +enum{ + ES_CHAR_CO2, + ES_CHAR_TEMP, + ES_CHAR_HUM, + ES_CHAR_NB, }; -int ble_gap_event(struct ble_gap_event *event, void* arg); +struct ES_char_descr { + uint16_t flags; + uint8_t sampling_function; + uint8_t measurement_period[3]; + uint8_t update_interval[3]; + uint8_t application; + uint8_t measurement_uncertainty; +}; +typedef struct ES_char_descr ES_char_descr_t; void initBle(configuration_data_t* main_conf); +void ble_sensor_notify(); +#endif diff --git a/main/CO2_Sense.c b/main/CO2_Sense.c index c4a9187..84dd27e 100644 --- a/main/CO2_Sense.c +++ b/main/CO2_Sense.c @@ -98,6 +98,7 @@ void fetch_sensor_task(void* pvParameters){ if (error) ESP_LOGE("sensor fetch", "Error executing scd4x_read_measurement(): %i\n", error); update_led_status(mainConf->leds, LED_NUMBER, conf->measure->co2); + ble_sensor_notify(); ESP_LOGI("MAIN", "co2 : %u ppm, temp : %d m°C, hum : %d mRH", conf->measure->co2, conf->measure->temperature, conf->measure->humidity); } } diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index c7c7977..00165f7 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -21,13 +21,4 @@ menu "CO2Sense config" help The pin on which the 3rd LED is connected endmenu - choice BT_BACKEND - prompt "BT backend" - default BT_NIMBLE_USED - config BT_NIMBLE_USED - bool "nimBLE" - - config BT_BLUEDROID_USED - bool "bluedroid" - endchoice endmenu diff --git a/sdkconfig b/sdkconfig index 3f82895..2f8e749 100644 --- a/sdkconfig +++ b/sdkconfig @@ -310,9 +310,6 @@ CONFIG_LED_1_PIN=4 CONFIG_LED_2_PIN=5 CONFIG_LED_3_PIN=6 # end of LED pins - -CONFIG_BT_NIMBLE_USED=y -# CONFIG_BT_BLUEDROID_USED is not set # end of CO2Sense config #