ESP32_BLE_UART/main/ble_spp_server_demo.c

1022 lines
41 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-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#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 "driver/uart.h"
#include "string.h"
#include "stdio.h"
// SPI相关代码已注释改用UART通信
/*
// SPI头文件条件包含兼容不同ESP-IDF版本
// 如果编译错误,请尝试以下方法之一:
// 1. ESP-IDF 4.x: #include "driver/spi_master.h"
// 2. ESP-IDF 5.x: #include "driver/spi_host.h"
#ifndef SPI_VERSION_DEFINED
#define SPI_VERSION_DEFINED
// 如果没有ESP_IDF_VERSION定义假设是ESP-IDF 4.x
#ifndef ESP_IDF_VERSION_VAL
#define ESP_IDF_VERSION_VAL(major, minor, patch) (((major) << 16) | ((minor) << 8) | (patch))
#endif
// 临时包含任意一个版本测试
#include "driver/spi_master.h"
#endif
*/
#include "esp_gap_ble_api.h"
#include "esp_gatts_api.h"
#include "esp_bt_defs.h"
#include "esp_bt_main.h"
#include "esp_bt_device.h"
#include "ble_spp_server_demo.h"
#include "esp_gatt_common_api.h"
#include "esp_timer.h"
#if (CONFIG_EXAMPLE_ENABLE_RF_TESTING_CONFIGURATION_COMMAND)
#include "rf_tesing_configuration_cmd.h"
#endif // CONFIG_EXAMPLE_ENABLE_RF_TESTING_CONFIGURATION_COMMAND
#define GATTS_TABLE_TAG "GATTS_SPP_DEMO"
// UART相关全局变量已移至 uart_ens1.c
// SPI相关代码已注释
/*
// 全局SPI设备句柄和连接状态
spi_device_handle_t spi_handle;
volatile bool ens1_connected = false;
*/
#define SPP_PROFILE_NUM 1
#define SPP_PROFILE_APP_IDX 0
#define ESP_SPP_APP_ID 0x56
#define SAMPLE_DEVICE_NAME "ESP_SPP_SERVER" //The Device Name Characteristics in GAP
#define SPP_SVC_INST_ID 0
/// SPP Service
static const uint16_t spp_service_uuid = 0xABF0;
/// Characteristic UUID
#define ESP_GATT_UUID_SPP_DATA_RECEIVE 0xABF1
#define ESP_GATT_UUID_SPP_DATA_NOTIFY 0xABF2
#define ESP_GATT_UUID_SPP_COMMAND_RECEIVE 0xABF3
#define ESP_GATT_UUID_SPP_COMMAND_NOTIFY 0xABF4
#define SPP_GATT_MTU_SIZE (512)
#ifdef SUPPORT_HEARTBEAT
#define ESP_GATT_UUID_SPP_HEARTBEAT 0xABF5
#endif
#define BLUETOOTH_TASK_PINNED_TO_CORE (0)
static const uint8_t spp_adv_data[23] = {
/* Flags */
0x02,0x01,0x06,
/* Complete List of 16-bit Service Class UUIDs */
0x03,0x03,0xF0,0xAB,
/* Complete Local Name in advertising */
0x0F,0x09, 'E', 'S', 'P', '_', 'S', 'P', 'P', '_', 'S', 'E', 'R','V', 'E', 'R'
};
static uint16_t spp_mtu_size = SPP_GATT_MTU_SIZE;
static uint16_t spp_conn_id = 0xffff;
static esp_gatt_if_t spp_gatts_if = 0xff;
QueueHandle_t spp_uart_queue = NULL;
static QueueHandle_t cmd_cmd_queue = NULL;
// 心跳功能已完全删除
static bool enable_data_ntf = false;
static bool is_connected = false;
static esp_bd_addr_t spp_remote_bda = {0x0,};
static uint16_t spp_handle_table[SPP_IDX_NB];
static esp_ble_adv_params_t spp_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;
};
typedef struct spp_receive_data_node{
int32_t len;
uint8_t * node_buff;
struct spp_receive_data_node * next_node;
}spp_receive_data_node_t;
static spp_receive_data_node_t * temp_spp_recv_data_node_p1 = NULL;
static spp_receive_data_node_t * temp_spp_recv_data_node_p2 = NULL;
typedef struct spp_receive_data_buff{
int32_t node_num;
int32_t buff_size;
spp_receive_data_node_t * first_node;
}spp_receive_data_buff_t;
static spp_receive_data_buff_t SppRecvDataBuff = {
.node_num = 0,
.buff_size = 0,
.first_node = NULL
};
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 spp_profile_tab[SPP_PROFILE_NUM] = {
[SPP_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 */
},
};
/*
* SPP PROFILE ATTRIBUTES
****************************************************************************************
*/
#define CHAR_DECLARATION_SIZE (sizeof(uint8_t))
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_notify = ESP_GATT_CHAR_PROP_BIT_READ|ESP_GATT_CHAR_PROP_BIT_NOTIFY;
static const uint8_t char_prop_read_write = ESP_GATT_CHAR_PROP_BIT_WRITE_NR|ESP_GATT_CHAR_PROP_BIT_READ;
#ifdef CONFIG_EXAMPLE_SPP_THROUGHPUT
static const uint8_t spp_data_notity_char_prop = char_prop_read_notify;
#else
static const uint8_t spp_data_notity_char_prop = ESP_GATT_CHAR_PROP_BIT_READ|ESP_GATT_CHAR_PROP_BIT_INDICATE;
#endif
#ifdef SUPPORT_HEARTBEAT
static const uint8_t char_prop_read_write_notify = ESP_GATT_CHAR_PROP_BIT_READ|ESP_GATT_CHAR_PROP_BIT_WRITE_NR|ESP_GATT_CHAR_PROP_BIT_NOTIFY;
#endif
///SPP Service - data receive characteristic, read&write without response
static const uint16_t spp_data_receive_uuid = ESP_GATT_UUID_SPP_DATA_RECEIVE;
static const uint8_t spp_data_receive_val[20] = {0x00};
///SPP Service - data notify characteristic, notify&read
static const uint16_t spp_data_notify_uuid = ESP_GATT_UUID_SPP_DATA_NOTIFY;
static const uint8_t spp_data_notify_val[20] = {0x00};
static const uint8_t spp_data_notify_ccc[2] = {0x00, 0x00};
///SPP Service - command characteristic, read&write without response
static const uint16_t spp_command_uuid = ESP_GATT_UUID_SPP_COMMAND_RECEIVE;
static const uint8_t spp_command_val[10] = {0x00};
///SPP Service - status characteristic, notify&read
static const uint16_t spp_status_uuid = ESP_GATT_UUID_SPP_COMMAND_NOTIFY;
static const uint8_t spp_status_val[10] = {0x00};
static const uint8_t spp_status_ccc[2] = {0x00, 0x00};
#ifdef SUPPORT_HEARTBEAT
///SPP Server - Heart beat characteristic, notify&write&read
static const uint16_t spp_heart_beat_uuid = ESP_GATT_UUID_SPP_HEARTBEAT;
static const uint8_t spp_heart_beat_val[2] = {0x00, 0x00};
static const uint8_t spp_heart_beat_ccc[2] = {0x00, 0x00};
#endif
///Full HRS Database Description - Used to add attributes into the database
static const esp_gatts_attr_db_t spp_gatt_db[SPP_IDX_NB] =
{
//SPP - Service Declaration
[SPP_IDX_SVC] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&primary_service_uuid, ESP_GATT_PERM_READ,
sizeof(spp_service_uuid), sizeof(spp_service_uuid), (uint8_t *)&spp_service_uuid}},
//SPP - data receive characteristic Declaration
[SPP_IDX_SPP_DATA_RECV_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}},
//SPP - data receive characteristic Value
[SPP_IDX_SPP_DATA_RECV_VAL] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&spp_data_receive_uuid, ESP_GATT_PERM_READ|ESP_GATT_PERM_WRITE,
SPP_DATA_MAX_LEN, sizeof(spp_data_receive_val), (uint8_t *)spp_data_receive_val}},
//SPP - data notify characteristic Declaration
[SPP_IDX_SPP_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 *)&spp_data_notity_char_prop}},
//SPP - data notify characteristic Value
[SPP_IDX_SPP_DATA_NTY_VAL] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&spp_data_notify_uuid, ESP_GATT_PERM_READ,
SPP_DATA_MAX_LEN, sizeof(spp_data_notify_val), (uint8_t *)spp_data_notify_val}},
//SPP - data notify characteristic - Client Characteristic Configuration Descriptor
[SPP_IDX_SPP_DATA_NTF_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(spp_data_notify_ccc), (uint8_t *)spp_data_notify_ccc}},
//SPP - command characteristic Declaration
[SPP_IDX_SPP_COMMAND_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}},
//SPP - command characteristic Value
[SPP_IDX_SPP_COMMAND_VAL] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&spp_command_uuid, ESP_GATT_PERM_READ|ESP_GATT_PERM_WRITE,
SPP_CMD_MAX_LEN, sizeof(spp_command_val), (uint8_t *)spp_command_val}},
//SPP - status characteristic Declaration
[SPP_IDX_SPP_STATUS_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 - status characteristic Value
[SPP_IDX_SPP_STATUS_VAL] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&spp_status_uuid, ESP_GATT_PERM_READ,
SPP_STATUS_MAX_LEN, sizeof(spp_status_val), (uint8_t *)spp_status_val}},
//SPP - status characteristic - Client Characteristic Configuration Descriptor
[SPP_IDX_SPP_STATUS_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(spp_status_ccc), (uint8_t *)spp_status_ccc}},
#ifdef SUPPORT_HEARTBEAT
//SPP - Heart beat characteristic Declaration
[SPP_IDX_SPP_HEARTBEAT_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}},
//SPP - Heart beat characteristic Value
[SPP_IDX_SPP_HEARTBEAT_VAL] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&spp_heart_beat_uuid, ESP_GATT_PERM_READ|ESP_GATT_PERM_WRITE,
sizeof(spp_heart_beat_val), sizeof(spp_heart_beat_val), (uint8_t *)spp_heart_beat_val}},
//SPP - Heart beat characteristic - Client Characteristic Configuration Descriptor
[SPP_IDX_SPP_HEARTBEAT_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(spp_data_notify_ccc), (uint8_t *)spp_heart_beat_ccc}},
#endif
};
static uint8_t find_char_and_desr_index(uint16_t handle)
{
uint8_t error = 0xff;
for(int i = 0; i < SPP_IDX_NB ; i++){
if(handle == spp_handle_table[i]){
return i;
}
}
return error;
}
static bool store_wr_buffer(esp_ble_gatts_cb_param_t *p_data)
{
temp_spp_recv_data_node_p1 = (spp_receive_data_node_t *)malloc(sizeof(spp_receive_data_node_t));
if(temp_spp_recv_data_node_p1 == NULL){
ESP_LOGI(GATTS_TABLE_TAG, "malloc error %s %d", __func__, __LINE__);
return false;
}
if(temp_spp_recv_data_node_p2 != NULL){
temp_spp_recv_data_node_p2->next_node = temp_spp_recv_data_node_p1;
}
temp_spp_recv_data_node_p1->len = p_data->write.len;
SppRecvDataBuff.buff_size += p_data->write.len;
temp_spp_recv_data_node_p1->next_node = NULL;
temp_spp_recv_data_node_p1->node_buff = (uint8_t *)malloc(p_data->write.len);
temp_spp_recv_data_node_p2 = temp_spp_recv_data_node_p1;
if (temp_spp_recv_data_node_p1->node_buff == NULL) {
ESP_LOGI(GATTS_TABLE_TAG, "malloc error %s %d\n", __func__, __LINE__);
temp_spp_recv_data_node_p1->len = 0;
} else {
memcpy(temp_spp_recv_data_node_p1->node_buff,p_data->write.value,p_data->write.len);
}
if(SppRecvDataBuff.node_num == 0){
SppRecvDataBuff.first_node = temp_spp_recv_data_node_p1;
SppRecvDataBuff.node_num++;
}else{
SppRecvDataBuff.node_num++;
}
return true;
}
static void free_write_buffer(void)
{
temp_spp_recv_data_node_p1 = SppRecvDataBuff.first_node;
while(temp_spp_recv_data_node_p1 != NULL){
temp_spp_recv_data_node_p2 = temp_spp_recv_data_node_p1->next_node;
if (temp_spp_recv_data_node_p1->node_buff) {
free(temp_spp_recv_data_node_p1->node_buff);
}
free(temp_spp_recv_data_node_p1);
temp_spp_recv_data_node_p1 = temp_spp_recv_data_node_p2;
}
SppRecvDataBuff.node_num = 0;
SppRecvDataBuff.buff_size = 0;
SppRecvDataBuff.first_node = NULL;
}
static void print_write_buffer(void)
{
temp_spp_recv_data_node_p1 = SppRecvDataBuff.first_node;
while (temp_spp_recv_data_node_p1 != NULL) {
uart_write_bytes(UART_NUM_0, (char *)(temp_spp_recv_data_node_p1->node_buff), temp_spp_recv_data_node_p1->len);
temp_spp_recv_data_node_p1 = temp_spp_recv_data_node_p1->next_node;
}
}
void uart_task(void *pvParameters)
{
uart_event_t event;
uint8_t total_num = 0;
uint8_t current_num = 0;
for (;;) {
//Waiting for UART event.
if (xQueueReceive(spp_uart_queue, (void * )&event, (TickType_t)portMAX_DELAY)) {
switch (event.type) {
//Event of UART receiving data
case UART_DATA:
if ((event.size)&&(is_connected)) {
uint8_t * temp = NULL;
uint8_t * ntf_value_p = NULL;
if(!enable_data_ntf){
ESP_LOGE(GATTS_TABLE_TAG, "%s do not enable data Notify", __func__);
break;
}
temp = (uint8_t *)malloc(sizeof(uint8_t)*event.size);
if (temp == NULL) {
ESP_LOGE(GATTS_TABLE_TAG, "%s malloc.1 failed", __func__);
break;
}
uart_read_bytes(UART_NUM_0, temp, event.size, portMAX_DELAY);
if (event.size <= (spp_mtu_size - 3)) {
#ifdef CONFIG_EXAMPLE_ENABLE_RF_EMC_TEST_MODE
ESP_LOG_BUFFER_HEX("TX", temp, event.size);
#endif
#ifdef CONFIG_EXAMPLE_SPP_THROUGHPUT
if(esp_ble_get_cur_sendable_packets_num(spp_conn_id) > 0) {
esp_ble_gatts_send_indicate(spp_gatts_if, spp_conn_id, spp_handle_table[SPP_IDX_SPP_DATA_NTY_VAL], event.size, temp, false);
} else {
//Add the vTaskDelay to prevent this task from consuming the CPU all the time, causing low-priority tasks to not be executed at all.
vTaskDelay(10 / portTICK_PERIOD_MS);
}
#else
esp_ble_gatts_send_indicate(spp_gatts_if, spp_conn_id, spp_handle_table[SPP_IDX_SPP_DATA_NTY_VAL], event.size, temp, true);
#endif
} else if (event.size > (spp_mtu_size - 3)) {
if ((event.size % (spp_mtu_size - 7)) == 0) {
total_num = event.size / (spp_mtu_size - 7);
} else {
total_num = event.size / (spp_mtu_size - 7) + 1;
}
current_num = 1;
ntf_value_p = (uint8_t *)malloc((spp_mtu_size-3)*sizeof(uint8_t));
if (ntf_value_p == NULL) {
ESP_LOGE(GATTS_TABLE_TAG, "%s malloc.2 failed", __func__);
free(temp);
break;
}
while (current_num <= total_num) {
if (current_num < total_num) {
ntf_value_p[0] = '#';
ntf_value_p[1] = '#';
ntf_value_p[2] = total_num;
ntf_value_p[3] = current_num;
memcpy(ntf_value_p + 4, temp + (current_num - 1)*(spp_mtu_size-7), (spp_mtu_size-7));
esp_ble_gatts_send_indicate(spp_gatts_if, spp_conn_id, spp_handle_table[SPP_IDX_SPP_DATA_NTY_VAL], (spp_mtu_size-3), ntf_value_p, false);
} else if(current_num == total_num) {
ntf_value_p[0] = '#';
ntf_value_p[1] = '#';
ntf_value_p[2] = total_num;
ntf_value_p[3] = current_num;
memcpy(ntf_value_p + 4, temp + (current_num - 1)*(spp_mtu_size-7), (event.size - (current_num - 1)*(spp_mtu_size - 7)));
esp_ble_gatts_send_indicate(spp_gatts_if, spp_conn_id, spp_handle_table[SPP_IDX_SPP_DATA_NTY_VAL], (event.size - (current_num - 1)*(spp_mtu_size - 7) + 4), ntf_value_p, false);
}
vTaskDelay(20 / portTICK_PERIOD_MS);
current_num++;
}
free(ntf_value_p);
}
free(temp);
}
break;
default:
break;
}
}
}
vTaskDelete(NULL);
}
static void spp_uart_init(void)
{
uart_config_t uart_config = {
.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_RTS,
.rx_flow_ctrl_thresh = 124,
.source_clk = UART_SCLK_DEFAULT,
};
//Install UART driver, and get the queue.
uart_driver_install(UART_NUM_0, 4096, 8192, 10, &spp_uart_queue,0);
//Set UART parameters
uart_param_config(UART_NUM_0, &uart_config);
//Set UART pins
uart_set_pin(UART_NUM_0, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
xTaskCreate(uart_task, "uTask", 4096, (void*)UART_NUM_0, 8, NULL);
}
// 心跳任务已删除
void spp_cmd_task(void * arg)
{
uint8_t * cmd_id;
for (;;) {
vTaskDelay(50 / portTICK_PERIOD_MS);
if(xQueueReceive(cmd_cmd_queue, &cmd_id, portMAX_DELAY)) {
ESP_LOG_BUFFER_CHAR(GATTS_TABLE_TAG, (char *)(cmd_id), strlen((char *)cmd_id));
free(cmd_id);
}
}
vTaskDelete(NULL);
}
// SPI ENS1连接监控任务已注释UART不需要监控任务
/*
// ENS1连接监控任务
void ens1_monitor_task(void *pvParameters) {
ESP_LOGI(GATTS_TABLE_TAG, "ENS1连接监控任务启动");
for (;;) {
vTaskDelay(10000 / portTICK_PERIOD_MS); // 每10秒检查一次
if (spi_handle != NULL) {
ESP_LOGI(GATTS_TABLE_TAG, "定期检查ENS1连接状态...");
esp_err_t ret = send_ens1_ping();
if (ret != ESP_OK) {
ESP_LOGW(GATTS_TABLE_TAG, "ENS1连接异常尝试重新检测: %s", esp_err_to_name(ret));
vTaskDelay(5000 / portTICK_PERIOD_MS); // 5秒后重试
ret = check_ens1_connection();
if (ret == ESP_OK) {
ESP_LOGI(GATTS_TABLE_TAG, "✅ ENS1连接已恢复");
} else {
ESP_LOGW(GATTS_TABLE_TAG, "⚠️ ENS1连接仍异常状态: %s", ens1_connected ? "已连接" : "未连接");
}
}
} else {
ESP_LOGW(GATTS_TABLE_TAG, "SPI设备未初始化跳过连接检测");
}
}
vTaskDelete(NULL);
}
*/
static void spp_task_init(void)
{
#ifdef CONFIG_EXAMPLE_ENABLE_RF_TESTING_CONFIGURATION_COMMAND
rf_testing_configuration_command_enable();
#else
spp_uart_init();
#endif // CONFIG_EXAMPLE_ENABLE_RF_TESTING_CONFIGURATION_COMMAND
// 心跳队列和任务创建已删除
cmd_cmd_queue = xQueueCreate(10, sizeof(uint32_t));
xTaskCreate(spp_cmd_task, "spp_cmd_task", 4096, NULL, 10, NULL);
// SPI ENS1连接监控任务已注释UART不需要监控任务
/*
// 创建ENS1连接监控任务
xTaskCreate(ens1_monitor_task, "ens1_monitor_task", 4096, NULL, 5, NULL);
*/
}
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_RAW_SET_COMPLETE_EVT:
esp_ble_gap_start_advertising(&spp_adv_params);
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(GATTS_TABLE_TAG, "Advertising start failed, status %d", param->adv_start_cmpl.status);
break;
}
ESP_LOGI(GATTS_TABLE_TAG, "Advertising start successfully");
break;
case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT:
if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) {
ESP_LOGE(GATTS_TABLE_TAG, "Advertising stop failed, status %d", param->adv_stop_cmpl.status);
break;
}
ESP_LOGI(GATTS_TABLE_TAG, "Advertising stop successfully");
break;
case ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT:
ESP_LOGI(GATTS_TABLE_TAG, "Connection params update, status %d, conn_int %d, latency %d, timeout %d",
param->update_conn_params.status,
param->update_conn_params.conn_int,
param->update_conn_params.latency,
param->update_conn_params.timeout);
break;
default:
break;
}
}
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)
{
esp_ble_gatts_cb_param_t *p_data = (esp_ble_gatts_cb_param_t *) param;
uint8_t res = 0xff;
switch (event) {
case ESP_GATTS_REG_EVT:
ESP_LOGI(GATTS_TABLE_TAG, "GATT server register, status %d, app_id %d, gatts_if %d", param->reg.status, param->reg.app_id, gatts_if);
esp_ble_gap_set_device_name(SAMPLE_DEVICE_NAME);
esp_ble_gap_config_adv_data_raw((uint8_t *)spp_adv_data, sizeof(spp_adv_data));
esp_ble_gatts_create_attr_tab(spp_gatt_db, gatts_if, SPP_IDX_NB, SPP_SVC_INST_ID);
break;
case ESP_GATTS_READ_EVT:
ESP_LOGI(GATTS_TABLE_TAG, "Characteristic read");
break;
case ESP_GATTS_WRITE_EVT: {
// ESP_LOGI(GATTS_TABLE_TAG, "Characteristic write, conn_id %d, handle %d", param->write.conn_id, param->write.handle);
res = find_char_and_desr_index(p_data->write.handle);
if (p_data->write.is_prep == false) {
if (res == SPP_IDX_SPP_COMMAND_VAL) {
uint8_t * spp_cmd_buff = NULL;
spp_cmd_buff = (uint8_t *)malloc((spp_mtu_size - 3) * sizeof(uint8_t));
if(spp_cmd_buff == NULL){
ESP_LOGE(GATTS_TABLE_TAG, "%s malloc failed", __func__);
break;
}
memset(spp_cmd_buff, 0x0, (spp_mtu_size - 3));
memcpy(spp_cmd_buff, p_data->write.value, p_data->write.len);
xQueueSend(cmd_cmd_queue, &spp_cmd_buff, 10/portTICK_PERIOD_MS);
} else if (res == SPP_IDX_SPP_DATA_NTF_CFG) {
if ((p_data->write.len == 2) && (p_data->write.value[0] == 0x01) && (p_data->write.value[1] == 0x00)) {
ESP_LOGI(GATTS_TABLE_TAG, "SPP data notification enable");
enable_data_ntf = true;
} else if ((p_data->write.len == 2) && (p_data->write.value[0] == 0x02) && (p_data->write.value[1] == 0x00)) {
ESP_LOGI(GATTS_TABLE_TAG, "SPP data indication enable");
enable_data_ntf = true;
} else if ((p_data->write.len == 2) && (p_data->write.value[0] == 0x00) && (p_data->write.value[1] == 0x00)) {
ESP_LOGI(GATTS_TABLE_TAG, "SPP data notification/indication disable");
enable_data_ntf = false;
}
} else if (res == SPP_IDX_SPP_STATUS_CFG) {
if ((p_data->write.len == 2) && (p_data->write.value[0] == 0x01) && (p_data->write.value[1] == 0x00)) {
ESP_LOGI(GATTS_TABLE_TAG, "SPP status notification enable");
} else if ((p_data->write.len == 2) && (p_data->write.value[0] == 0x00) && (p_data->write.value[1] == 0x00)) {
ESP_LOGI(GATTS_TABLE_TAG, "SPP status notification disable");
}
}
// 心跳相关处理已删除
else if (res == SPP_IDX_SPP_DATA_RECV_VAL) {
// 添加接收数据的日志输出
ESP_LOGI(GATTS_TABLE_TAG, "接收到BLE数据长度: %d 字节", p_data->write.len);
ESP_LOG_BUFFER_HEX("BLE接收数据", p_data->write.value, p_data->write.len);
// 检查ENS1 UART连接状态并发送数据
if (ens1_uart_connected) {
ESP_LOGI(GATTS_TABLE_TAG, "✅ ENS1 UART已连接转发数据到ENS1芯片...");
esp_err_t uart_ret = uart_send_data_to_ens1((uint8_t*)p_data->write.value, p_data->write.len);
if (uart_ret != ESP_OK) {
ESP_LOGE(GATTS_TABLE_TAG, "UART数据发送失败连接可能异常");
ens1_uart_connected = false;
}
} else {
ESP_LOGW(GATTS_TABLE_TAG, "⚠️ ENS1 UART未连接跳过数据发送");
}
/*
// SPI发送已注释
// 检查ENS1连接状态并发送数据
if (ens1_connected) {
ESP_LOGI(GATTS_TABLE_TAG, "ENS1已连接转发数据到芯片...");
esp_err_t spi_ret = spi_send_data((uint8_t*)p_data->write.value, p_data->write.len);
if (spi_ret != ESP_OK) {
ESP_LOGE(GATTS_TABLE_TAG, "SPI数据发送失败连接可能异常");
ens1_connected = false;
}
} else {
ESP_LOGW(GATTS_TABLE_TAG, "ENS1未连接跳过SPI发送");
}
*/
#ifdef CONFIG_EXAMPLE_ENABLE_RF_EMC_TEST_MODE
ESP_LOG_BUFFER_HEX("RX", p_data->write.value, p_data->write.len);
#else
uart_write_bytes(UART_NUM_0, (char *)(p_data->write.value), p_data->write.len);
#endif
} else {
//TODO:
}
} else if ((p_data->write.is_prep == true) && (res == SPP_IDX_SPP_DATA_RECV_VAL)) {
store_wr_buffer(p_data);
}
break;
}
case ESP_GATTS_EXEC_WRITE_EVT: {
ESP_LOGI(GATTS_TABLE_TAG, "Execute write");
if (p_data->exec_write.exec_write_flag) {
print_write_buffer();
free_write_buffer();
}
break;
}
case ESP_GATTS_RESPONSE_EVT:
break;
case ESP_GATTS_MTU_EVT:
ESP_LOGI(GATTS_TABLE_TAG, "MTU exchange, MTU %d", param->mtu.mtu);
spp_mtu_size = p_data->mtu.mtu;
break;
case ESP_GATTS_CONF_EVT:
if (param->conf.status) {
ESP_LOGI(GATTS_TABLE_TAG, "Confirm received, status %d, handle %d", param->conf.status, param->conf.handle);
}
break;
case ESP_GATTS_UNREG_EVT:
break;
case ESP_GATTS_DELETE_EVT:
break;
case ESP_GATTS_START_EVT:
ESP_LOGI(GATTS_TABLE_TAG, "Service start, status %d, service_handle %d",
param->start.status, param->start.service_handle);
break;
case ESP_GATTS_STOP_EVT:
break;
case ESP_GATTS_CONNECT_EVT:
ESP_LOGI(GATTS_TABLE_TAG, "Connected, conn_id %u, remote "ESP_BD_ADDR_STR"",
param->connect.conn_id, ESP_BD_ADDR_HEX(param->connect.remote_bda));
spp_conn_id = p_data->connect.conn_id;
spp_gatts_if = gatts_if;
is_connected = true;
memcpy(&spp_remote_bda,&p_data->connect.remote_bda,sizeof(esp_bd_addr_t));
// 心跳启动已删除
break;
case ESP_GATTS_DISCONNECT_EVT:
ESP_LOGI(GATTS_TABLE_TAG, "Disconnected, remote "ESP_BD_ADDR_STR", reason 0x%02x",
ESP_BD_ADDR_HEX(param->disconnect.remote_bda), param->disconnect.reason);
spp_mtu_size = 23;
is_connected = false;
enable_data_ntf = false;
// 心跳状态重置已删除
esp_ble_gap_start_advertising(&spp_adv_params);
break;
case ESP_GATTS_OPEN_EVT:
break;
case ESP_GATTS_CANCEL_OPEN_EVT:
break;
case ESP_GATTS_CLOSE_EVT:
break;
case ESP_GATTS_LISTEN_EVT:
break;
case ESP_GATTS_CONGEST_EVT:
break;
case ESP_GATTS_CREAT_ATTR_TAB_EVT:{
ESP_LOGI(GATTS_TABLE_TAG, "The number handle %x",param->add_attr_tab.num_handle);
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 != SPP_IDX_NB) {
ESP_LOGE(GATTS_TABLE_TAG, "Create attribute table abnormally, num_handle (%d) doesn't equal to HRS_IDX_NB(%d)", param->add_attr_tab.num_handle, SPP_IDX_NB);
}
else {
memcpy(spp_handle_table, param->add_attr_tab.handles, sizeof(spp_handle_table));
esp_ble_gatts_start_service(spp_handle_table[SPP_IDX_SVC]);
}
break;
}
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) {
spp_profile_tab[SPP_PROFILE_APP_IDX].gatts_if = gatts_if;
} else {
ESP_LOGI(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 < SPP_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 == spp_profile_tab[idx].gatts_if) {
if (spp_profile_tab[idx].gatts_cb) {
spp_profile_tab[idx].gatts_cb(event, gatts_if, param);
}
}
}
} while (0);
}
void app_main(void)
{
esp_err_t ret;
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
ret = init_uart_ens1();
if (ret != ESP_OK) {
ESP_LOGE(GATTS_TABLE_TAG, "UART初始化失败继续运行但不支持ENS1通信功能");
ens1_uart_connected = false;
} else {
ESP_LOGI(GATTS_TABLE_TAG, "UART初始化完成跳过连接检测");
// 直接设置连接状态为true不发送检测命令
ens1_uart_connected = true;
// 启动UART接收任务
xTaskCreate(uart_ens1_rx_task, "uart_ens1_rx_task", 4096, NULL, 10, NULL);
}
/*
// SPI初始化已注释
// 初始化SPI (连接ENS1芯片)
ESP_LOGI(GATTS_TABLE_TAG, "初始化SPI外设...");
ret = init_spi();
if (ret != ESP_OK) {
ESP_LOGE(GATTS_TABLE_TAG, "SPI总线初始化失败继续运行但不支持SPI功能");
} else {
ret = init_spi_device();
if (ret != ESP_OK) {
ESP_LOGE(GATTS_TABLE_TAG, "SPI设备初始化失败继续运行但不支持SPI功能");
ens1_connected = false;
} else {
ESP_LOGI(GATTS_TABLE_TAG, "SPI初始化完成检测ENS1芯片连接...");
// 初始连接检测
ret = check_ens1_connection();
if (ret == ESP_OK) {
ESP_LOGI(GATTS_TABLE_TAG, "✅ ENS1芯片连接检测成功");
ens1_connected = true;
} else {
ESP_LOGW(GATTS_TABLE_TAG, "⚠️ ENS1芯片连接检测失败可能是断线或芯片未响应");
ens1_connected = false;
}
}
}
*/
spp_task_init();
// Initialize NVS
ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK( ret );
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
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;
}
ESP_LOGI(GATTS_TABLE_TAG, "%s init bluetooth", __func__);
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;
}
esp_ble_gatts_register_callback(gatts_event_handler);
esp_ble_gap_register_callback(gap_event_handler);
esp_ble_gatts_app_register(ESP_SPP_APP_ID);
esp_err_t local_mtu_ret = esp_ble_gatt_set_local_mtu(SPP_GATT_MTU_SIZE);
if (local_mtu_ret){
ESP_LOGE(GATTS_TABLE_TAG, "set local MTU failed, error code = %x", local_mtu_ret);
}
return;
}
// ========================= UART通信功能已移至 uart_ens1.c =========================
// ========================= SPI功能已注释 =========================
/*
// SPI初始化函数 (连接到ENS1芯片)
esp_err_t init_spi(void) {
spi_bus_config_t bus_config = {
.miso_io_num = GPIO_NUM_NC, // 不使用MISO只输出到ENS1
.mosi_io_num = PIN_MOSI, // MOSI引脚 (GPIO13)
.sclk_io_num = PIN_SCK, // SCK引脚 (GPIO14)
.quadhd_io_num = GPIO_NUM_NC, // 不需要
.quadwp_io_num = GPIO_NUM_NC, // 不需要
.max_transfer_sz = 4096, // 最大传输大小
};
ESP_LOGI(GATTS_TABLE_TAG, "初始化SPI总线 (SPI2_HOST)...");
esp_err_t ret;
// ESP-IDF v5.5 仍使用 spi_bus_initialize
ret = spi_bus_initialize(SPI_HOST, &bus_config, SPI_DMA_CH_AUTO);
if (ret != ESP_OK) {
ESP_LOGE(GATTS_TABLE_TAG, "SPI总线初始化失败: %s", esp_err_to_name(ret));
return ret;
}
ESP_LOGI(GATTS_TABLE_TAG, "SPI总线初始化成功");
return ESP_OK;
}
// SPI设备初始化 (ENS1芯片)
esp_err_t init_spi_device(void) {
spi_device_interface_config_t dev_config = {
.clock_speed_hz = 1500000, // 1.5 MHz SPI时钟 (适配STM32 FPCLK/32)
.mode = 0, // SPI模式0 (CPOL=0, CPHA=0) - 匹配ENS1
.spics_io_num = PIN_CS, // SPI片选引脚 (GPIO15) - 对应NSS1
.queue_size = 1, // 队列大小
.flags = SPI_DEVICE_HALFDUPLEX, // 半双工模式匹配L2_UniDirect_TandR
.input_delay_ns = 0,
.command_bits = 0, // 无命令位匹配8位CHAR_LEN
.address_bits = 0, // 无地址位
};
ESP_LOGI(GATTS_TABLE_TAG, "添加SPI设备到总线...");
esp_err_t ret = spi_bus_add_device(SPI_HOST, &dev_config, &spi_handle);
if (ret != ESP_OK) {
ESP_LOGE(GATTS_TABLE_TAG, "添加SPI设备失败: %s", esp_err_to_name(ret));
return ret;
}
// 确保设备句柄有效
if (spi_handle == NULL) {
ESP_LOGE(GATTS_TABLE_TAG, "SPI设备句柄无效");
return ESP_FAIL;
}
ESP_LOGI(GATTS_TABLE_TAG, "SPI设备初始化成功 (ENS1芯片)");
ESP_LOGI(GATTS_TABLE_TAG, "MOSI: GPIO%d, SCK: GPIO%d, CS: GPIO%d", PIN_MOSI, PIN_SCK, PIN_CS);
return ESP_OK;
}
// SPI发送数据到ENS1芯片
esp_err_t spi_send_data(uint8_t *data, size_t len) {
if (spi_handle == NULL) {
ESP_LOGE(GATTS_TABLE_TAG, "SPI设备未初始化");
return ESP_ERR_INVALID_STATE;
}
if (data == NULL || len == 0) {
ESP_LOGE(GATTS_TABLE_TAG, "无效的数据或长度");
return ESP_ERR_INVALID_ARG;
}
spi_transaction_t trans = {
.length = len * 8, // 数据长度(位数)
.tx_buffer = NULL, // 默认不使用缓冲区
.tx_data = {0},
.flags = 0, // 不设置SPI_TRANS_USE_TXDATA标志
};
// 根据数据长度选择传输方式
if (len <= 4) {
// 4字节以内的数据使用tx_data字段更高效
memset(trans.tx_data, 0, sizeof(trans.tx_data));
memcpy(trans.tx_data, data, len);
trans.length = len * 8;
trans.flags = SPI_TRANS_USE_TXDATA; // 使用发送数据标志
} else {
// 超过4字节的数据使用tx_buffer
trans.tx_buffer = data;
trans.length = len * 8;
trans.flags = 0; // 使用缓冲区模式
}
ESP_LOGI(GATTS_TABLE_TAG, "发送SPI数据到ENS1长度: %d 字节", len);
ESP_LOG_BUFFER_HEX("ENS1发送数据", data, len);
esp_err_t ret = spi_device_transmit(spi_handle, &trans);
if (ret != ESP_OK) {
ESP_LOGE(GATTS_TABLE_TAG, "SPI数据发送失败: %s", esp_err_to_name(ret));
return ret;
}
ESP_LOGI(GATTS_TABLE_TAG, "SPI数据发送成功");
return ESP_OK;
}
// 检查ENS1芯片连接状态 (Ping检测)
esp_err_t check_ens1_connection(void) {
if (spi_handle == NULL) {
ESP_LOGW(GATTS_TABLE_TAG, "SPI设备未初始化无法检测ENS1连接");
ens1_connected = false;
return ESP_ERR_INVALID_STATE;
}
// 发送Ping命令检测连接
uint8_t ping_cmd[] = {0xAA, 0x55, 0x01, 0x02}; // ENS1连接检测命令
esp_err_t ret = spi_device_transmit(spi_handle, &(spi_transaction_t){
.length = sizeof(ping_cmd) * 8, // 4字节 = 32位
.tx_data = {ping_cmd[0], ping_cmd[1], ping_cmd[2], ping_cmd[3]}, // 4字节数据
.flags = SPI_TRANS_USE_TXDATA, // 使用tx_data字段≤32位
});
if (ret == ESP_OK) {
ESP_LOGI(GATTS_TABLE_TAG, "ENS1连接检测成功 - PING响应正常");
ens1_connected = true;
return ESP_OK;
} else {
ESP_LOGW(GATTS_TABLE_TAG, "ENS1连接检测失败: %s", esp_err_to_name(ret));
ens1_connected = false;
return ret;
}
}
// 发送ENS1芯片Ping命令 (持续检测连接)
esp_err_t send_ens1_ping(void) {
if (spi_handle == NULL) {
ESP_LOGW(GATTS_TABLE_TAG, "SPI设备未初始化无法发送Ping");
ens1_connected = false;
return ESP_ERR_INVALID_STATE;
}
// ENS1心跳包格式: 命令头 + 序列号 + 校验和 (限制在4字节以内)
static uint8_t ping_sequence = 0;
ping_sequence++;
uint8_t ping_data[] = {
0xAA, // 起始同步头
0x55, // 起始同步头
0xFE, // Ping命令ID
ping_sequence // 序列号(递增)
};
ESP_LOGI(GATTS_TABLE_TAG, "发送ENS1 Ping命令序列号: %d", ping_sequence);
ESP_LOG_BUFFER_HEX("Ping数据", ping_data, sizeof(ping_data));
spi_transaction_t trans = {
.length = sizeof(ping_data) * 8, // 4字节 = 32位
.tx_data = {ping_data[0], ping_data[1], ping_data[2], ping_data[3]}, // 只使用前4字节
.flags = SPI_TRANS_USE_TXDATA, // 使用tx_data字段≤32位
};
esp_err_t ret = spi_device_transmit(spi_handle, &trans);
if (ret == ESP_OK) {
ESP_LOGI(GATTS_TABLE_TAG, "ENS1 Ping发送成功");
ens1_connected = true;
return ESP_OK;
} else {
ESP_LOGE(GATTS_TABLE_TAG, "ENS1 Ping发送失败: %s", esp_err_to_name(ret));
ens1_connected = false;
return ret;
}
}
*/
// ========================= SPI功能注释结束 =========================