pile_com_stm32/main/ble_gatts_server.c
2024-03-15 13:27:37 +08:00

806 lines
33 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
/****************************************************************************
*
* This demo showcases creating a GATT database using a predefined attribute table.
* It acts as a GATT server and can send adv data, be connected by client.
* Run the gatt_client demo, the client demo will automatically connect to the gatt_server_service_table demo.
* Client demo will enable GATT server's notify after connection. The two devices will then exchange
* data.
*
****************************************************************************/
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_bt.h"
#include "esp_gap_ble_api.h"
#include "esp_gatts_api.h"
#include "esp_bt_main.h"
#include "ble_gatts_server.h"
#include "esp_gatt_common_api.h"
#include "stm32/config.h"
#include "stm32/ModbusS.h"
#define GATTS_TABLE_TAG "BLE_GATTS_SERVER"
#define PROFILE_NUM 1
#define PROFILE_APP_IDX 0
#define ESP_APP_ID 0x55
#define SAMPLE_DEVICE_NAME "ESP_GATTS_DEMO"
#define SVC_INST_ID 0
/* The max length of characteristic value. When the GATT client performs a write or prepare write operation,
* the data length must be less than GATTS_DEMO_CHAR_VAL_LEN_MAX.
*/
#define GATTS_DEMO_CHAR_VAL_LEN_MAX 500
#define PREPARE_BUF_MAX_SIZE 1024
#define CHAR_DECLARATION_SIZE (sizeof(uint8_t))
#define ADV_CONFIG_FLAG (1 << 0)
#define SCAN_RSP_CONFIG_FLAG (1 << 1)
static uint8_t adv_config_done = 0;
uint16_t ble_gatts_handle_table[IDX_NB];
typedef struct {
uint8_t *prepare_buf;
int prepare_len;
} prepare_type_env_t;
static prepare_type_env_t prepare_write_env;
#define CONFIG_SET_RAW_ADV_DATA
#ifdef CONFIG_SET_RAW_ADV_DATA
static uint8_t raw_adv_data[] = {
/* flags */
0x02, 0x01, 0x06,
/* tx power*/
0x02, 0x0a, 0xeb,
/* service uuid */
0x03, 0x03, 0xFF, 0x00,
/* device name */
0x0f, 0x09, 'E', 'S', 'P', '_', 'G', 'A', 'T', 'T', 'S', '_', 'D','E', 'M', 'O'
};
static uint8_t raw_scan_rsp_data[] = {
/* flags */
0x02, 0x01, 0x06,
/* tx power */
0x02, 0x0a, 0xeb,
/* service uuid */
0x03, 0x03, 0xFF,0x00
};
#else
static uint8_t service_uuid[16] = {
/* LSB <--------------------------------------------------------------------------------> MSB */
//first uuid, 16bit, [12],[13] 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 */
static esp_ble_adv_data_t adv_data = {
.set_scan_rsp = false,
.include_name = true,
.include_txpower = true,
.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,
.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),
};
// scan response data
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 = 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(service_uuid),
.p_service_uuid = service_uuid,
.flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT),
};
#endif /* CONFIG_SET_RAW_ADV_DATA */
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,
};
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;
};
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);
/* One gatt-based profile one app_id and one gatts_if, this array will store the gatts_if returned by ESP_GATTS_REG_EVT */
static struct gatts_profile_inst ble_gatts_profile_tab[PROFILE_NUM] = {
[PROFILE_APP_IDX] = {
.gatts_cb = gatts_profile_event_handler,
.gatts_if = ESP_GATT_IF_NONE, /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */
},
};
/* Service */
static const uint16_t GATTS_SERVICE_UUID = 0x00FF;
static const uint16_t GATTS_DATA_READ_WRITE_UUID = 0xFF01;
static const uint16_t GATTS_DATA_NOTIFY_UUID = 0xFF02;
static const uint16_t primary_service_uuid = ESP_GATT_UUID_PRI_SERVICE;
static const uint16_t character_declaration_uuid = ESP_GATT_UUID_CHAR_DECLARE;
static const uint16_t character_client_config_uuid = ESP_GATT_UUID_CHAR_CLIENT_CONFIG;
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 char_prop_read_notify = ESP_GATT_CHAR_PROP_BIT_READ|ESP_GATT_CHAR_PROP_BIT_NOTIFY;
static const uint8_t data_read_write_value[4] = {0x00};
static const uint8_t data_read_write_ccc[2] = {0x00, 0x00};
static const uint8_t data_notify_val[4] = {0x00};
static const uint8_t data_notify_ccc[2] = {0x00, 0x00};
bool data_notify_enable = false; /* 是否允许数据上报 */
bool is_connected = false; /* 蓝牙是否连接 */
static uint16_t ble_gatts_conn_id = 0xffff;
static esp_gatt_if_t ble_gatts_if = 0xff;
/* Full Database Description - Used to add attributes into the database */
static const esp_gatts_attr_db_t gatt_db[IDX_NB] =
{
// Service Declaration
[IDX_SVC] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&primary_service_uuid, ESP_GATT_PERM_READ,
sizeof(uint16_t), sizeof(GATTS_SERVICE_UUID), (uint8_t *)&GATTS_SERVICE_UUID}},
/* Characteristic Declaration */
[IDX_DATA_READ_WRITE_CHAR] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ,
CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_read_write_notify}},
/* Characteristic Value */
[IDX_DATA_READ_WRITE_VAL] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&GATTS_DATA_READ_WRITE_UUID, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
GATTS_DEMO_CHAR_VAL_LEN_MAX, sizeof(data_read_write_value), (uint8_t *)data_read_write_value}},
/* Client Characteristic Configuration Descriptor */
[IDX_DATA_READ_WRITE_CFG] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_client_config_uuid, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
sizeof(uint16_t), sizeof(data_read_write_ccc), (uint8_t *)data_read_write_ccc}},
//SPP - data notify characteristic Declaration
[IDX_DATA_NOTIFY_CHAR] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ,
CHAR_DECLARATION_SIZE,CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_read_notify}},
//SPP - data notify characteristic Value
[IDX_DATA_NOTIFY_VAL] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&GATTS_DATA_NOTIFY_UUID, ESP_GATT_PERM_READ,
GATTS_DEMO_CHAR_VAL_LEN_MAX, sizeof(data_notify_val), (uint8_t *)data_notify_val}},
//SPP - data notify characteristic - Client Characteristic Configuration Descriptor
[IDX_DATA_NOTIFY_CFG] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_client_config_uuid, ESP_GATT_PERM_READ|ESP_GATT_PERM_WRITE,
sizeof(uint16_t),sizeof(data_notify_ccc), (uint8_t *)data_notify_ccc}},
};
static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
{
switch (event) {
#ifdef CONFIG_SET_RAW_ADV_DATA
case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT:
adv_config_done &= (~ADV_CONFIG_FLAG);
if (adv_config_done == 0){
esp_ble_gap_start_advertising(&adv_params);
}
break;
case ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT:
adv_config_done &= (~SCAN_RSP_CONFIG_FLAG);
if (adv_config_done == 0){
esp_ble_gap_start_advertising(&adv_params);
}
break;
#else
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);
}
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);
}
break;
#endif
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(GATTS_TABLE_TAG, "advertising start failed");
}else{
ESP_LOGI(GATTS_TABLE_TAG, "advertising start successfully");
}
break;
case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT:
if (param->adv_stop_cmpl.status != ESP_BT_STATUS_SUCCESS) {
ESP_LOGE(GATTS_TABLE_TAG, "Advertising stop failed");
}
else {
ESP_LOGI(GATTS_TABLE_TAG, "Stop adv successfully\n");
}
break;
case ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT:
ESP_LOGI(GATTS_TABLE_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;
}
}
/*
* [0]: 标识 F0--写多个modbus内存地址
* [2:1]: 寄存器起始地址,即寄存器下标
* [3]: 写的字节数 0-255
* ... 数据内容
*/
void gatts_write_data_cb(uint8_t *data, uint32_t len, esp_ble_gatts_cb_param_t *param)
{
ESP_LOGI(GATTS_TABLE_TAG, "gatts_write_data_cb");
if (len >= 4 && data[0] == 0xF0) /* 写gWordVar寄存器 */
{
uint16_t addr = data[1] + (data[2] << 8);
uint16_t addr_ = addr;
uint8_t cnt = data[3];
if (cnt > len - 4)
{
ESP_LOGI(GATTS_TABLE_TAG, "write format is fault, cnt > len - 4");
return;
}
ESP_LOGI(GATTS_TABLE_TAG, "write addr:%d cnt:%d", addr, cnt);
uint8_t i;
for (i = 0 + 4; i < cnt + 4; i+=2) /* 发送的数据要求两字节对齐 */
{
gWordVar[addr++] = data[i] + (data[i + 1] << 8);
ESP_LOGI(GATTS_TABLE_TAG, "gwordvar[%d]:0x%x", addr-1, gWordVar[addr-1]);
}
/* 还应该调用 ModBusWordWriteHook 来处理这些写动作带来的影响 */
ModBusWordWriteHook(addr_, cnt);
}
else if (len >= 4 && data[0] == 0xF1) /* 读gWordVar通过notify上报回去 */
{
uint16_t addr = data[1] + (data[2] << 8);
uint8_t cnt = data[3];
ESP_LOGI(GATTS_TABLE_TAG, "read addr:%d cnt:%d", addr, cnt);
uint8_t buf[500];
buf[0] = data[0];
buf[1] = data[1];
buf[2] = data[2];
buf[3] = data[3];
memcpy(buf + 4, (uint8_t *)(gWordVar + addr), cnt);
notify_data_fun(IDX_DATA_READ_WRITE_VAL, buf, cnt + 4);
}
else if (len == 1 && data[0] == 0xF2) /* 开启notify */
{
ESP_LOGI(GATTS_TABLE_TAG, "enable notify");
data_notify_enable = true;
}
else ESP_LOGI(GATTS_TABLE_TAG, "format err!");
}
void example_prepare_write_event_env(esp_gatt_if_t gatts_if, prepare_type_env_t *prepare_write_env, esp_ble_gatts_cb_param_t *param)
{
ESP_LOGI(GATTS_TABLE_TAG, "prepare write, handle = %d, value len = %d", param->write.handle, param->write.len);
esp_gatt_status_t status = ESP_GATT_OK;
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(GATTS_TABLE_TAG, "%s, Gatt_server prep no mem", __func__);
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;
}
}
/*send response when param->write.need_rsp is true */
if (param->write.need_rsp){
esp_gatt_rsp_t *gatt_rsp = (esp_gatt_rsp_t *)malloc(sizeof(esp_gatt_rsp_t));
if (gatt_rsp != NULL){
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(GATTS_TABLE_TAG, "Send response error");
}
free(gatt_rsp);
}else{
ESP_LOGE(GATTS_TABLE_TAG, "%s, malloc failed", __func__);
}
}
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;
}
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 && prepare_write_env->prepare_buf){
esp_log_buffer_hex(GATTS_TABLE_TAG, prepare_write_env->prepare_buf, prepare_write_env->prepare_len);
gatts_write_data_cb(prepare_write_env->prepare_buf, prepare_write_env->prepare_len, param); /* 此处有隐患有可能不是data_write特征的数据 */
}else{
ESP_LOGI(GATTS_TABLE_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;
}
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_err_t set_dev_name_ret = esp_ble_gap_set_device_name(SAMPLE_DEVICE_NAME);
if (set_dev_name_ret){
ESP_LOGE(GATTS_TABLE_TAG, "set device name failed, error code = %x", set_dev_name_ret);
}
#ifdef CONFIG_SET_RAW_ADV_DATA
esp_err_t raw_adv_ret = esp_ble_gap_config_adv_data_raw(raw_adv_data, sizeof(raw_adv_data));
if (raw_adv_ret){
ESP_LOGE(GATTS_TABLE_TAG, "config raw adv data failed, error code = %x ", raw_adv_ret);
}
adv_config_done |= ADV_CONFIG_FLAG;
esp_err_t raw_scan_ret = esp_ble_gap_config_scan_rsp_data_raw(raw_scan_rsp_data, sizeof(raw_scan_rsp_data));
if (raw_scan_ret){
ESP_LOGE(GATTS_TABLE_TAG, "config raw scan rsp data failed, error code = %x", raw_scan_ret);
}
adv_config_done |= SCAN_RSP_CONFIG_FLAG;
#else
//config adv data
esp_err_t ret = esp_ble_gap_config_adv_data(&adv_data);
if (ret){
ESP_LOGE(GATTS_TABLE_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(GATTS_TABLE_TAG, "config scan response data failed, error code = %x", ret);
}
adv_config_done |= SCAN_RSP_CONFIG_FLAG;
#endif
esp_err_t create_attr_ret = esp_ble_gatts_create_attr_tab(gatt_db, gatts_if, IDX_NB, SVC_INST_ID);
if (create_attr_ret){
ESP_LOGE(GATTS_TABLE_TAG, "create attr table failed, error code = %x", create_attr_ret);
}
}
break;
case ESP_GATTS_READ_EVT:
ESP_LOGI(GATTS_TABLE_TAG, "ESP_GATTS_READ_EVT");
// 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, NULL);
break;
case ESP_GATTS_WRITE_EVT:
ESP_LOGI(GATTS_TABLE_TAG, "ESP_GATTS_WRITE_EVT, need_rsp=%d", param->write.need_rsp);
if (!param->write.is_prep){
// the data length of gattc write must be less than GATTS_DEMO_CHAR_VAL_LEN_MAX.
ESP_LOGI(GATTS_TABLE_TAG, "GATT_WRITE_EVT, handle = %d, value len = %d, value :", param->write.handle, param->write.len);
esp_log_buffer_hex(GATTS_TABLE_TAG, param->write.value, param->write.len);
if (ble_gatts_handle_table[IDX_DATA_READ_WRITE_VAL] == param->write.handle)
gatts_write_data_cb(param->write.value, param->write.len, param);
if (ble_gatts_handle_table[IDX_DATA_NOTIFY_CFG] == param->write.handle && param->write.len == 2){
uint16_t descr_value = param->write.value[1]<<8 | param->write.value[0];
if (descr_value == 0x0001){
ESP_LOGI(GATTS_TABLE_TAG, "notify enable");
data_notify_enable = true;
}//else if (descr_value == 0x0002){
// ESP_LOGI(GATTS_TABLE_TAG, "indicate enable");
// }
else if (descr_value == 0x0000){
ESP_LOGI(GATTS_TABLE_TAG, "notify/indicate disable ");
data_notify_enable = false;
}else{
ESP_LOGE(GATTS_TABLE_TAG, "unknown descr value");
esp_log_buffer_hex(GATTS_TABLE_TAG, param->write.value, param->write.len);
}
}
/* send response when param->write.need_rsp is true*/
if (param->write.need_rsp){
esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, NULL);
}
}else{
/* handle prepare write */
example_prepare_write_event_env(gatts_if, &prepare_write_env, param);
}
break;
case ESP_GATTS_EXEC_WRITE_EVT:
// the length of gattc prepare write data must be less than GATTS_DEMO_CHAR_VAL_LEN_MAX.
ESP_LOGI(GATTS_TABLE_TAG, "ESP_GATTS_EXEC_WRITE_EVT");
example_exec_write_event_env(&prepare_write_env, param);
break;
case ESP_GATTS_MTU_EVT:
ESP_LOGI(GATTS_TABLE_TAG, "ESP_GATTS_MTU_EVT, MTU %d", param->mtu.mtu);
break;
case ESP_GATTS_CONF_EVT:
ESP_LOGI(GATTS_TABLE_TAG, "ESP_GATTS_CONF_EVT, status = %d, attr_handle %d", param->conf.status, param->conf.handle);
break;
case ESP_GATTS_START_EVT:
ESP_LOGI(GATTS_TABLE_TAG, "SERVICE_START_EVT, status %d, service_handle %d", param->start.status, param->start.service_handle);
break;
case ESP_GATTS_CONNECT_EVT:
ESP_LOGI(GATTS_TABLE_TAG, "ESP_GATTS_CONNECT_EVT, conn_id = %d", param->connect.conn_id);
esp_log_buffer_hex(GATTS_TABLE_TAG, param->connect.remote_bda, 6);
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 refer to 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
//start sent the update connection parameters to the peer device.
esp_ble_gap_update_conn_params(&conn_params);
is_connected = true;
ble_gatts_conn_id = param->connect.conn_id;
ble_gatts_if = gatts_if;
break;
case ESP_GATTS_DISCONNECT_EVT:
ESP_LOGI(GATTS_TABLE_TAG, "ESP_GATTS_DISCONNECT_EVT, reason = 0x%x", param->disconnect.reason);
esp_ble_gap_start_advertising(&adv_params);
is_connected = false;
break;
case ESP_GATTS_CREAT_ATTR_TAB_EVT:{
if (param->add_attr_tab.status != ESP_GATT_OK){
ESP_LOGE(GATTS_TABLE_TAG, "create attribute table failed, error code=0x%x", param->add_attr_tab.status);
}
else if (param->add_attr_tab.num_handle != IDX_NB){
ESP_LOGE(GATTS_TABLE_TAG, "create attribute table abnormally, num_handle (%d) \
doesn't equal to IDX_NB(%d)", param->add_attr_tab.num_handle, IDX_NB);
}
else {
ESP_LOGI(GATTS_TABLE_TAG, "create attribute table successfully, the number handle = %d\n",param->add_attr_tab.num_handle);
memcpy(ble_gatts_handle_table, param->add_attr_tab.handles, sizeof(ble_gatts_handle_table));
esp_ble_gatts_start_service(ble_gatts_handle_table[IDX_SVC]);
}
break;
}
case ESP_GATTS_STOP_EVT:
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:
case ESP_GATTS_UNREG_EVT:
case ESP_GATTS_DELETE_EVT:
default:
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 is register event, store the gatts_if for each profile */
if (event == ESP_GATTS_REG_EVT) {
if (param->reg.status == ESP_GATT_OK) {
ble_gatts_profile_tab[PROFILE_APP_IDX].gatts_if = gatts_if;
} else {
ESP_LOGE(GATTS_TABLE_TAG, "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 == ble_gatts_profile_tab[idx].gatts_if) {
if (ble_gatts_profile_tab[idx].gatts_cb) {
ble_gatts_profile_tab[idx].gatts_cb(event, gatts_if, param);
}
}
}
} while (0);
}
/*
* 上报长度过长则分包这里限制长度最大20分包协议
* [1:0] # #’,分包标识
* [2] 总包个数
* [3] 当前包号从0开始
* ... 包数据
*/
static uint16_t gatts_mtu_size = 23;
void notify_data_fun(int id, uint8_t *data, uint32_t len)
{
// ESP_LOGI(GATTS_TABLE_TAG, "notify_data_fun:");
// esp_log_buffer_hex(GATTS_TABLE_TAG, data, len);
if (len <= gatts_mtu_size - 3) /* 包数据可以一次完整发送 */
{
esp_ble_gatts_send_indicate(ble_gatts_if, ble_gatts_conn_id, ble_gatts_handle_table[id], len, data, false);
}
else /* 需要分包发送 */
{
int total_num = 0;
uint8_t buf[gatts_mtu_size - 3];
if ((len % (gatts_mtu_size - 7)) == 0)
total_num = len / (gatts_mtu_size - 7);
else
total_num = len / (gatts_mtu_size - 7) + 1;
// ESP_LOGI(GATTS_TABLE_TAG, "notify packet has %d", total_num);
int i = 0;
buf[0] = '#';
buf[1] = '#';
buf[2] = total_num;
for (i = 0; i < total_num - 1; i++)
{
buf[3] = i;
memcpy(buf + 4, data + i * (gatts_mtu_size - 7), gatts_mtu_size - 7);
esp_ble_gatts_send_indicate(ble_gatts_if, ble_gatts_conn_id, ble_gatts_handle_table[IDX_DATA_NOTIFY_VAL],gatts_mtu_size - 3, buf, false);
}
/* 最后一个包 */
buf[3] = i;
memcpy(buf + 4, data + i * (gatts_mtu_size - 7), len % (gatts_mtu_size - 7));
esp_ble_gatts_send_indicate(ble_gatts_if, ble_gatts_conn_id, ble_gatts_handle_table[IDX_DATA_NOTIFY_VAL], (len % (gatts_mtu_size - 7)) + 4, buf, false);
// ESP_LOGI(GATTS_TABLE_TAG, "notify packet send end!");
}
}
extern flow_t *pflow;
extern depth_t *depth_data;
extern record_t *record;
gps_message_t *gpsMessageP = (gps_message_t *)&gWordVar[REG_GPS_MESSAGE];
gps_write_data_t *gpsWriteDataP = (gps_write_data_t *)&gWordVar[REG_GPS_WRITE_DATA];
void notify_all_data(void)
{
// ESP_LOGI(GATTS_TABLE_TAG, "notify_all_data");
uint8_t buf[30];
buf[0] = 1; /* tag:深度:速度 时间 深度 桩号 */
buf[1] = depth_data->speed & 0xff;
buf[2] = (depth_data->speed >> 8) & 0xff;
buf[3] = depth_data->one_pile_work_time & 0xff;
buf[4] = (depth_data->one_pile_work_time >> 8) & 0xff;
buf[5] = depth_data->depth & 0xff;
buf[6] = (depth_data->depth >> 8) & 0xff;
buf[7] = gWordVar[LAST_PILE_ID_ADDR] & 0xff;
buf[8] = (gWordVar[LAST_PILE_ID_ADDR] >> 8) & 0xff;
notify_data_fun(IDX_DATA_NOTIFY_VAL, buf, 9);
buf[0] = 2; /* tag:1号通道流量:瞬时每10cm总 */
buf[1] = pflow[0].flow & 0xff;
buf[2] = (pflow[0].flow >> 8) & 0xff;
buf[3] = depth_data->depth_flow[0] & 0xff;
buf[4] = (depth_data->depth_flow[0] >> 8) & 0xff;
buf[5] = pflow[0].total_flow & 0xff;
buf[6] = (pflow[0].total_flow >> 8) & 0xff;
notify_data_fun(IDX_DATA_NOTIFY_VAL, buf, 7);
buf[0] = 3; /* tag:2号通道流量:瞬时每10cm总 */
buf[1] = pflow[1].flow & 0xff;
buf[2] = (pflow[1].flow >> 8) & 0xff;
buf[3] = depth_data->depth_flow[1] & 0xff;
buf[4] = (depth_data->depth_flow[1] >> 8) & 0xff;
buf[5] = pflow[1].total_flow & 0xff;
buf[6] = (pflow[1].total_flow >> 8) & 0xff;
notify_data_fun(IDX_DATA_NOTIFY_VAL, buf, 7);
buf[0] = 4; /* tag:电流:三个*/
buf[1] = gWordVar[AC_CURRENT_REG_ADDR + 0] & 0xff;
buf[2] = (gWordVar[AC_CURRENT_REG_ADDR + 0] >> 8) & 0xff;
buf[3] = gWordVar[AC_CURRENT_REG_ADDR + 1] & 0xff;
buf[4] = (gWordVar[AC_CURRENT_REG_ADDR + 1] >> 8) & 0xff;
buf[5] = gWordVar[AC_CURRENT_REG_ADDR + 2] & 0xff;
buf[6] = (gWordVar[AC_CURRENT_REG_ADDR + 2] >> 8) & 0xff;
notify_data_fun(IDX_DATA_NOTIFY_VAL, buf, 7);
int64_t x = (int64_t)(gpsMessageP->x * 1000);
int64_t y = (int64_t)(gpsMessageP->y * 1000);
uint16_t dir = (uint16_t)(gpsMessageP->dir * 100);
uint16_t pitch = (uint16_t)(gpsMessageP->pitch * 100);
uint8_t gps_status = gpsMessageP->gps_status;
uint32_t utc_time = gpsMessageP->utc;
// ESP_LOGI(GATTS_TABLE_TAG, "x:%f, %f, %lld", gpsMessageP->x, gpsMessageP->x * 1000, (long long int)(gpsMessageP->x * 1000));
// ESP_LOGI(GATTS_TABLE_TAG, "gps message x:%lld, y:%lld, dir:%ud, pitch:%ud, gps_status:%d, utc_time:%ud", (long long)x, (long long)y, (unsigned int)dir, (unsigned int)pitch, (int)gps_status, (unsigned int)utc_time);
buf[0] = 5; /* tag:CPS信息1:x, y(int64)*/
buf[1] = x & 0xff;
buf[2] = (x >> 8) & 0xff;
buf[3] = (x >> 16) & 0xff;
buf[4] = (x >> 24) & 0xff;
buf[5] = (x >> 32) & 0xff;
buf[6] = (x >> 40) & 0xff;
buf[7] = (x >> 48) & 0xff;
buf[8] = (x >> 56) & 0xff;
buf[9] = y & 0xff;
buf[10] = (y >> 8) & 0xff;
buf[11] = (y >> 16) & 0xff;
buf[12] = (y >> 24) & 0xff;
buf[13] = (y >> 32) & 0xff;
buf[14] = (y >> 40) & 0xff;
buf[15] = (y >> 48) & 0xff;
buf[16] = (y >> 56) & 0xff;
notify_data_fun(IDX_DATA_NOTIFY_VAL, buf, 17);
buf[0] = 6; /* tag:CPS信息2:方向,俯仰(uint16) gps定位状态(uint8) UTC时间(uint32)*/
buf[1] = dir & 0xff;
buf[2] = (dir >> 8) & 0xff;
buf[3] = pitch & 0xff;
buf[4] = (pitch >> 8) & 0xff;
buf[5] = utc_time & 0xff;
buf[6] = (utc_time >> 8) & 0xff;
buf[7] = (utc_time >> 16) & 0xff;
buf[8] = (utc_time >> 24) & 0xff;
buf[9] = gps_status & 0xff;
notify_data_fun(IDX_DATA_NOTIFY_VAL, buf, 10);
// // 有记录时上传记录
// static int pile_id = 0;
// static int pile_id_count = 0;
// if (record->pile_id > pile_id || record->count > pile_id_count)
// {
// pile_id = record->pile_id;
// pile_id_count = record->count;
// buf[0] = 5;
// buf[1] = record->pile_id & 0xff; // pile_id
// buf[2] = (record->pile_id >> 8) & 0xff;
// buf[3] = record->item[0].flow[0] & 0xff; // 10cm喷浆量1
// buf[4] = (record->item[0].flow[0] >> 8) & 0xff;
// buf[5] = record->item[0].flow[1] & 0xff; // 10cm喷浆量2
// buf[6] = (record->item[0].flow[1] >> 8) & 0xff;
// buf[7] = record->max_depth & 0xff; // 最大深度
// buf[8] = (record->max_depth >> 8) & 0xff;
// buf[9] = record->item[0].current1 & 0xff; // 采样的电流
// buf[10] = (record->item[0].current1 >> 8) & 0xff;
// notify_data_fun(IDX_DATA_NOTIFY_VAL, buf, 11);
// }
/* 需要上报什么数据在此处添加 */
}
void notify_task(void *pvParameters)
{
ESP_LOGI(GATTS_TABLE_TAG, "notify_task");
while (1)
{
if (data_notify_enable && is_connected)
{
notify_all_data();
}
vTaskDelay(pdMS_TO_TICKS(100));
}
vTaskDelete(NULL);
}
void ble_gatts_server_init(void)
{
esp_err_t ret;
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();
ret = esp_bt_controller_init(&bt_cfg);
if (ret) {
ESP_LOGE(GATTS_TABLE_TAG, "%s enable controller failed: %s", __func__, esp_err_to_name(ret));
return;
}
ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
if (ret) {
ESP_LOGE(GATTS_TABLE_TAG, "%s enable controller failed: %s", __func__, esp_err_to_name(ret));
return;
}
ret = esp_bluedroid_init();
if (ret) {
ESP_LOGE(GATTS_TABLE_TAG, "%s init bluetooth failed: %s", __func__, esp_err_to_name(ret));
return;
}
ret = esp_bluedroid_enable();
if (ret) {
ESP_LOGE(GATTS_TABLE_TAG, "%s enable bluetooth failed: %s", __func__, esp_err_to_name(ret));
return;
}
ret = esp_ble_gatts_register_callback(gatts_event_handler);
if (ret){
ESP_LOGE(GATTS_TABLE_TAG, "gatts register error, error code = %x", ret);
return;
}
ret = esp_ble_gap_register_callback(gap_event_handler);
if (ret){
ESP_LOGE(GATTS_TABLE_TAG, "gap register error, error code = %x", ret);
return;
}
ret = esp_ble_gatts_app_register(ESP_APP_ID);
if (ret){
ESP_LOGE(GATTS_TABLE_TAG, "gatts app register error, error code = %x", ret);
return;
}
esp_err_t local_mtu_ret = esp_ble_gatt_set_local_mtu(500);
if (local_mtu_ret){
ESP_LOGE(GATTS_TABLE_TAG, "set local MTU failed, error code = %x", local_mtu_ret);
}
/* 创建任务用于定期的数据上报notify */
xTaskCreate(notify_task, "notify_Task", 4096, NULL, 8, NULL);
}