2022-04-14 20:47:39 +02:00

340 lines
13 KiB
C

#ifdef CONFIG_BT_BLUEDROID_ENABLED
#include <string.h>
#include "BTlib.h"
#include "esp_log.h"
#include "esp_bt.h"
#include "esp_bt_main.h"
#include "esp_gap_ble_api.h"
#include "esp_gatts_api.h"
#include "esp_gatt_common_api.h"
#include "scd4x_data.h"
#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;
static struct gatts_profile_inst env_sense_profile_tab[PROFILE_NUM] = {
[ENVIRONMENTAL_SENSING_IDX] = {
.gatts_cb = gatts_profile_event_handler,
.gatts_if = ESP_GATT_IF_NONE,
},
};
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,
ENVIRONMENTAL_SENSING_UUID & 0xFF,
ENVIRONMENTAL_SENSING_UUID & 0xFF00 >> 8,
0x00,
0x00,
};
static esp_ble_adv_data_t env_sense_adv_data = {
.set_scan_rsp = false,
.include_name = true,
.include_txpower = true,
.min_interval = 0x0006,
.max_interval = 0x0010,
.appearance = 0x054A, // Carbon Dioxide Sensor
.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(service_uuid),
.p_service_uuid = service_uuid,
.flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT),
};
static esp_ble_adv_data_t scan_rsp_data = {
.set_scan_rsp = true,
.include_name = true,
.include_txpower = true,
.min_interval = 0x0006,
.max_interval = 0x0010,
.appearance = 0x054A,
.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(service_uuid),
.p_service_uuid = service_uuid,
.flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT),
};
static 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,
};
static const uint16_t primary_service_uuid = ESP_GATT_UUID_PRI_SERVICE;
static const uint16_t env_service_uuid = ENVIRONMENTAL_SENSING_UUID;
static const uint16_t ES_measurement_uuid = 0x290C;
static const uint16_t char_dec_uuid = ESP_GATT_UUID_CHAR_DECLARE;
static const uint16_t char_co2_uuid = 0x0c39; // random
static const uint16_t char_temp_uuid = 0x2A6E;
static const uint16_t char_hum_uuid = 0x2A6F;
static const uint16_t char_prop_read = ESP_GATT_CHAR_PROP_BIT_READ;
//static const uint8_t char_prop_read_write_notify = ESP_GATT_CHAR_PROP_BIT_WRITE | ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_NOTIFY;
static const uint8_t CO2_char_descr[]={
0x00, 0x00, // Flags (RFU)
0x01, // Sampling function : Instantaneous
0x1E, 0x00, 0x00, // Measurement period : 30s TODO
0x1E, 0x00, 0x00, // Update Interval : 30s TODO
0x01, // Application : Air
0xFF, // Mesurement Uncertainty : TODO
};
static const uint8_t temp_char_descr[]={
0x00, 0x00, // Flags (RFU)
0x01, // Sampling function : Instantaneous
0x1E, 0x00, 0x00, // Measurement period : 30s TODO
0x1E, 0x00, 0x00, // Update Interval : 30s TODO
0x01, // Application : Air
0xFF, // Mesurement Uncertainty : TODO
};
static const uint8_t hum_char_descr[]={
0x00, 0x00, // Flags (RFU)
0x01, // Sampling function : Instantaneous
0x1E, 0x00, 0x00, // Measurement period : 30s TODO
0x1E, 0x00, 0x00, // Update Interval : 30s TODO
0x01, // Application : Air
0xFF, // Mesurement Uncertainty : TODO
};
static const uint16_t CO2_value = 1260;
static const int16_t temp_value = 1560;
static const uint16_t hum_value = 4200;
static const esp_gatts_attr_db_t gatt_db[ENV_IDX_NB] =
{
// Service Declaration
[ENV_IDX_SVC] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&primary_service_uuid, ESP_GATT_PERM_READ,
sizeof(uint16_t), sizeof(env_service_uuid), (uint8_t *)&env_service_uuid}},
/* Characteristic Declaration */
[CO2_IDX_MEAS_CHAR] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&char_dec_uuid, ESP_GATT_PERM_READ,
CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_read}},
/* Characteristic Value */
[CO2_IDX_MEAS_VAL] =
{{ESP_GATT_RSP_BY_APP}, {ESP_UUID_LEN_16, (uint8_t *)&char_co2_uuid, ESP_GATT_PERM_READ,
GATTS_CHAR_VAL_LEN_MAX, sizeof(CO2_value), (uint8_t *)&CO2_value}},
/* Client Characteristic Configuration Descriptor */
[CO2_IDX_MEAS_DESC] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&ES_measurement_uuid, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
sizeof(CO2_char_descr), sizeof(CO2_char_descr), (uint8_t *)CO2_char_descr}},
/* Characteristic Declaration */
[T_IDX_MEAS_CHAR] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&char_dec_uuid, ESP_GATT_PERM_READ,
CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_read}},
/* Characteristic Value */
[T_IDX_MEAS_VAL] =
{{ESP_GATT_RSP_BY_APP}, {ESP_UUID_LEN_16, (uint8_t *)&char_temp_uuid, ESP_GATT_PERM_READ,
GATTS_CHAR_VAL_LEN_MAX, sizeof(temp_value), (uint8_t *)&temp_value}},
/* Client Characteristic Configuration Descriptor */
[T_IDX_MEAS_DESC] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&ES_measurement_uuid, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
sizeof(temp_char_descr), sizeof(temp_char_descr), (uint8_t *)temp_char_descr}},
/* Characteristic Declaration */
[HUM_IDX_MEAS_CHAR] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&char_dec_uuid, ESP_GATT_PERM_READ,
CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_read}},
/* Characteristic Value */
[HUM_IDX_MEAS_VAL] =
{{ESP_GATT_RSP_BY_APP}, {ESP_UUID_LEN_16, (uint8_t *)&char_hum_uuid, ESP_GATT_PERM_READ,
GATTS_CHAR_VAL_LEN_MAX, sizeof(hum_value), (uint8_t *)&hum_value}},
/* Client Characteristic Configuration Descriptor */
[HUM_IDX_MEAS_DESC] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&ES_measurement_uuid, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
sizeof(hum_char_descr), sizeof(hum_char_descr), (uint8_t *)hum_char_descr}},
};
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);
if(adv_config_done == 0)
esp_ble_gap_start_advertising(&adv_params); // TODO : use ble 5.0
break;
case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT:
adv_config_done &= (~SCAN_RSP_CONFIG_FLAG);
if(adv_config_done == 0)
esp_ble_gap_start_advertising(&adv_params); // TODO : use ble 5.0
break;
case ESP_GAP_BLE_ADV_START_COMPLETE_EVT:
if(param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS)
ESP_LOGE("bt", "advertising start failed");
else
ESP_LOGI("bt", "started advertising");
break;
case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT:
if(param->adv_stop_cmpl.status != ESP_BT_STATUS_SUCCESS)
ESP_LOGE("bt", "advertising stop failed");
else
ESP_LOGI("bt", "stopped advertising");
break;
case ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT:
ESP_LOGI("bt", "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:
ESP_LOGI("bt", "GATTS, non implemented event");
break;
}
}
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;
else{
ESP_LOGE("bt", "reg app failed, app_id %04x, status %d",param->reg.app_id,param->reg.status);
return;
}
}
do{
int idx;
for (idx = 0; idx < PROFILE_NUM; idx++) {
/* ESP_GATT_IF_NONE, not specify a certain gatt_if, need to call every profile cb function */
if (gatts_if == ESP_GATT_IF_NONE || gatts_if == env_sense_profile_tab[idx].gatts_if) {
if (env_sense_profile_tab[idx].gatts_cb)
env_sense_profile_tab[idx].gatts_cb(event, gatts_if, param);
}
}
}
while (0);
}
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));
ESP_ERROR_CHECK(esp_ble_gap_config_adv_data(&env_sense_adv_data));
adv_config_done |= ADV_CONFIG_FLAG;
ESP_ERROR_CHECK(esp_ble_gap_config_adv_data(&scan_rsp_data));
adv_config_done |= SCAN_RSP_CONFIG_FLAG;
ESP_ERROR_CHECK(esp_ble_gatts_create_attr_tab(gatt_db, gatts_if, ENV_IDX_NB, ENVIRONMENTAL_SENSING_IDX));
break;
case ESP_GATTS_READ_EVT:
ESP_LOGI("bt", "read event");
esp_gatt_rsp_t rsp;
memset(&rsp, 0, sizeof(esp_gatt_rsp_t));
rsp.attr_value.handle = param->read.handle;
if(param->read.handle == env_handle_table[CO2_IDX_MEAS_VAL]){
uint16_t co2 = main_app_conf->measure->co2;
rsp.attr_value.len = sizeof(co2);
memcpy(rsp.attr_value.value, &co2, sizeof(co2));
}
else if(param->read.handle == env_handle_table[T_IDX_MEAS_VAL]){
int32_t raw_temp = main_app_conf->measure->temperature;
int16_t temperature = raw_temp/10;
ESP_LOGI("bt", "temp %i", temperature);
rsp.attr_value.len = sizeof(temperature);
memcpy(rsp.attr_value.value, &temperature, sizeof(temperature));
}
else if(param->read.handle == env_handle_table[HUM_IDX_MEAS_VAL]){
int32_t raw_hum = main_app_conf->measure->humidity;
int16_t hum = raw_hum/10;
rsp.attr_value.len = sizeof(hum);
memcpy(rsp.attr_value.value, &hum, sizeof(hum));
}
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("bt", "write event NI");
break;
case ESP_GATTS_EXEC_WRITE_EVT:
ESP_LOGI("bt", "write exec event NI");
break;
case ESP_GATTS_MTU_EVT:
ESP_LOGI("bt", "MTU event NI");
break;
case ESP_GATTS_CONF_EVT:
ESP_LOGI("bt", "conf event NI");
break;
case ESP_GATTS_START_EVT:
ESP_LOGI("bt", "start event NI");
break;
case ESP_GATTS_CONNECT_EVT:
ESP_LOGI("bt", "connect event");
esp_ble_conn_update_params_t conn_params = {0};
memcpy(conn_params.bda, param->connect.remote_bda, sizeof(esp_bd_addr_t));
conn_params.latency = 0;
conn_params.max_int = 0x20;
conn_params.min_int = 0x10;
conn_params.timeout = 400;
esp_ble_gap_update_conn_params(&conn_params);
break;
case ESP_GATTS_DISCONNECT_EVT:
ESP_LOGI("bt", "disconnect event");
esp_ble_gap_start_advertising(&adv_params);
break;
case ESP_GATTS_CREAT_ATTR_TAB_EVT:
if(param->add_attr_tab.status != ESP_GATT_OK){
ESP_LOGE("bt", "create attribute table failed, error code=0x%x", param->add_attr_tab.status);
}
else if(param->add_attr_tab.num_handle != ENV_IDX_NB){
ESP_LOGE("bt", "wrong num hanbdle tab");
}
else{
ESP_LOGI("bt", "creationg tab");
memcpy(env_handle_table, param->add_attr_tab.handles, sizeof(env_handle_table));
esp_ble_gatts_start_service(env_handle_table[ENV_IDX_SVC]);
}
break;
default:
ESP_LOGI("bt", "GATTS, non implemented event");
break;
}
}
void initBle(configuration_data_t* main_conf){
ESP_LOGI("initBle", "starting bluetooth");
main_app_conf = main_conf;
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_bt_controller_init(&bt_cfg));
ESP_ERROR_CHECK(esp_bt_controller_enable(ESP_BT_MODE_BLE));
ESP_ERROR_CHECK(esp_bluedroid_init());
ESP_ERROR_CHECK(esp_bluedroid_enable());
ESP_ERROR_CHECK(esp_ble_gatts_register_callback(gatts_event_handler));
ESP_ERROR_CHECK(esp_ble_gap_register_callback(gap_event_handler));
ESP_ERROR_CHECK(esp_ble_gatts_app_register(SENSOR_BLE_APP_ID));
}
#endif