nimBLE gatt

This commit is contained in:
leo 2022-04-14 20:47:39 +02:00
parent d435f9dc1f
commit 8324df6420
Signed by: leo
GPG Key ID: 0DD993BFB2B307DB
8 changed files with 289 additions and 76 deletions

View File

@ -1,3 +1,5 @@
#ifdef CONFIG_BT_BLUEDROID_ENABLED
#include <string.h>
#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

View File

@ -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; i<ES_CHAR_NB; i++)
if(event->subscribe.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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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);
}
}

View File

@ -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

View File

@ -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
#