This commit is contained in:
snow 2024-03-15 17:42:04 +08:00
parent d7e84e433d
commit 79a0eb73b7
11 changed files with 208 additions and 2400 deletions

View File

@ -286,7 +286,7 @@ static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param
* [3]: 0-255 * [3]: 0-255
* ... * ...
*/ */
void gatts_write_data_cb(uint8_t *data, uint32_t len, esp_ble_gatts_cb_param_t *param) void gatts_write_data_cb(uint8_t *data, uint32_t len)
{ {
ESP_LOGI(GATTS_TABLE_TAG, "gatts_write_data_cb"); ESP_LOGI(GATTS_TABLE_TAG, "gatts_write_data_cb");
@ -381,7 +381,7 @@ void example_prepare_write_event_env(esp_gatt_if_t gatts_if, prepare_type_env_t
void example_exec_write_event_env(prepare_type_env_t *prepare_write_env, esp_ble_gatts_cb_param_t *param){ 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){ 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); 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特征的数据 */ gatts_write_data_cb(prepare_write_env->prepare_buf); /* 此处有隐患有可能不是data_write特征的数据 */
}else{ }else{
ESP_LOGI(GATTS_TABLE_TAG,"ESP_GATT_PREP_WRITE_CANCEL"); ESP_LOGI(GATTS_TABLE_TAG,"ESP_GATT_PREP_WRITE_CANCEL");
} }
@ -453,7 +453,7 @@ static void gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_
ESP_LOGI(GATTS_TABLE_TAG, "GATT_WRITE_EVT, handle = %d, value len = %d, value :", param->write.handle, param->write.len); 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); 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) if (ble_gatts_handle_table[IDX_DATA_READ_WRITE_VAL] == param->write.handle)
gatts_write_data_cb(param->write.value, param->write.len, param); gatts_write_data_cb(param->write.value, param->write.len);
if (ble_gatts_handle_table[IDX_DATA_NOTIFY_CFG] == param->write.handle && param->write.len == 2){ 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]; uint16_t descr_value = param->write.value[1]<<8 | param->write.value[0];
if (descr_value == 0x0001){ if (descr_value == 0x0001){
@ -624,7 +624,7 @@ gps_write_data_t *gpsWriteDataP = (gps_write_data_t *)&gWordVar[REG_GPS_WRITE_DA
void notify_all_data(void) void notify_all_data(void)
{ {
// ESP_LOGI(GATTS_TABLE_TAG, "notify_all_data"); ESP_LOGI(GATTS_TABLE_TAG, "notify_all_data");
uint8_t buf[30]; uint8_t buf[30];
buf[0] = 1; /* tag:深度:速度 时间 深度 桩号 */ buf[0] = 1; /* tag:深度:速度 时间 深度 桩号 */
@ -704,29 +704,6 @@ void notify_all_data(void)
buf[8] = (utc_time >> 24) & 0xff; buf[8] = (utc_time >> 24) & 0xff;
buf[9] = gps_status & 0xff; buf[9] = gps_status & 0xff;
notify_data_fun(IDX_DATA_NOTIFY_VAL, buf, 10); 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);
// }
/* 需要上报什么数据在此处添加 */ /* 需要上报什么数据在此处添加 */
} }

View File

@ -1,859 +0,0 @@
/*
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#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 "esp_gap_ble_api.h"
#include "esp_gatts_api.h"
#include "esp_bt_defs.h"
#include "esp_bt_main.h"
#include "bt_server.h"
#define SPP_DEBUG_MODE 1
#define GATTS_TABLE_TAG "GATTS_SPP_DEMO"
#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
#ifdef SUPPORT_HEARTBEAT
#define ESP_GATT_UUID_SPP_HEARTBEAT 0xABF5
#endif
/*蓝牙的广播数据*/
static const uint8_t spp_adv_data[23] = {
/* Flags */
0x02,0x01,0x06, //表示设备支持LE General Discoverable Mode可被发现模式和BR/EDR Not Supported不支持传统蓝牙
/* Complete List of 16-bit Service Class UUIDs */
0x03,0x03,0xF0,0xAB,//广播数据中的16位服务UUID字段表示设备提供了一个特定的服务这里是自定义的16位UUID
/* Complete Local Name in advertising */
0x0F,0x09, 'E', 'S', 'P', '_', 'S', 'P', 'P', '_', 'S', 'E', 'R','V', 'E', 'R'
//广播数据中的16位服务UUID字段表示设备提供了一个特定的服务这里是自定义的16位UUID
};
static uint16_t spp_mtu_size = 23;
uint16_t spp_conn_id = 0xffff;
esp_gatt_if_t spp_gatts_if = 0xff;
QueueHandle_t spp_uart_queue = NULL;
static QueueHandle_t cmd_cmd_queue = NULL;
#ifdef SUPPORT_HEARTBEAT
static QueueHandle_t cmd_heartbeat_queue = NULL;
static uint8_t heartbeat_s[9] = {'E','s','p','r','e','s','s','i','f'};
static bool enable_heart_ntf = false;
static uint8_t heartbeat_count_num = 0;
#endif
static bool enable_data_ntf = false;
bool is_connected = false;
static esp_bd_addr_t spp_remote_bda = {0x0,};
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; //0x2800
static const uint16_t character_declaration_uuid = ESP_GATT_UUID_CHAR_DECLARE; //0x2803
static const uint16_t character_client_config_uuid = ESP_GATT_UUID_CHAR_CLIENT_CONFIG; //0x2902
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 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; //0xABF1
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; //0xABF2
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; //0xABF3
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; //0xABF4
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, //0x2800
ESP_GATT_PERM_READ,
sizeof(spp_service_uuid), //0xABF0
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, //0x2803
ESP_GATT_PERM_READ,
CHAR_DECLARATION_SIZE,
CHAR_DECLARATION_SIZE,
(uint8_t *)&char_prop_read_write
}
},
//SPP - data receive characteristic Value spp服务中数据接收特征值
[SPP_IDX_SPP_DATA_RECV_VAL] = {
{ESP_GATT_AUTO_RSP},
{
ESP_UUID_LEN_16,
(uint8_t *)&spp_data_receive_uuid, //0xABF1
ESP_GATT_PERM_READ|ESP_GATT_PERM_WRITE,
SPP_DATA_MAX_LEN,
sizeof(spp_data_receive_val),
(uint8_t *)spp_data_receive_val //0x00
}
},
//SPP - data notify characteristic Declaration spp协议中数据通知特征
[SPP_IDX_SPP_DATA_NOTIFY_CHAR] = {
{ESP_GATT_AUTO_RSP},
{
ESP_UUID_LEN_16,
(uint8_t *)&character_declaration_uuid, //0x2803
ESP_GATT_PERM_READ,
CHAR_DECLARATION_SIZE,
CHAR_DECLARATION_SIZE,
(uint8_t *)&char_prop_read_notify
}
},
//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, //0xABF2
ESP_GATT_PERM_READ,
SPP_DATA_MAX_LEN,
sizeof(spp_data_notify_val),
(uint8_t *)spp_data_notify_val //0x00
}
},
//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, //0x2902
ESP_GATT_PERM_READ|ESP_GATT_PERM_WRITE,
sizeof(uint16_t),
sizeof(spp_data_notify_ccc),
(uint8_t *)spp_data_notify_ccc //{0x00, 0x00}
}
},
//SPP - command characteristic Declaration 命令特征声明
[SPP_IDX_SPP_COMMAND_CHAR]= {
{ESP_GATT_AUTO_RSP},
{
ESP_UUID_LEN_16,
(uint8_t *)&character_declaration_uuid, //0x2803
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, //0xABF3
ESP_GATT_PERM_READ|ESP_GATT_PERM_WRITE,
SPP_CMD_MAX_LEN,
sizeof(spp_command_val),
(uint8_t *)spp_command_val //{0x00}
}
},
//SPP - status characteristic Declaration
[SPP_IDX_SPP_STATUS_CHAR] = {
{ESP_GATT_AUTO_RSP},
{
ESP_UUID_LEN_16,
(uint8_t *)&character_declaration_uuid, //0x2803
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, //0xABF4
ESP_GATT_PERM_READ,
SPP_STATUS_MAX_LEN,
sizeof(spp_status_val),
(uint8_t *)spp_status_val //{0x00}
}
},
//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, //0x2902
ESP_GATT_PERM_READ|ESP_GATT_PERM_WRITE,
sizeof(uint16_t),
sizeof(spp_status_ccc),
(uint8_t *)spp_status_ccc //{0x00, 0x00}
}
},
#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
};
/*在 spp_handle_table 数组中查找与给定句柄匹配的特性或描述符,返回其索引值。如果没有找到匹配的值,则返回 0xff*/
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\n", __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;
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;
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;
}
/*将缓冲区数据写入uart*/
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_2, (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;
}
}
//蓝牙设备接收到消息后将分组数据通过蓝牙的 GATT Indicate 方式发送给蓝牙连接的设备(也就是蓝牙客户端)
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, 10/portTICK_PERIOD_MS)) {
switch (event.type) {
//Event of UART receving data
case UART_DATA:
if ((event.size)&&(is_connected)) {
uint8_t * temp = NULL;
uint8_t * ntf_value_p = NULL;
#ifdef SUPPORT_HEARTBEAT
if(!enable_heart_ntf){
ESP_LOGE(GATTS_TABLE_TAG, "%s do not enable heartbeat Notify\n", __func__);
break;
}
#endif
if(!enable_data_ntf){
ESP_LOGE(GATTS_TABLE_TAG, "%s do not enable data Notify\n", __func__);
break;
}
temp = (uint8_t *)malloc(sizeof(uint8_t)*event.size);
if(temp == NULL){
ESP_LOGE(GATTS_TABLE_TAG, "%s malloc.1 failed\n", __func__);
break;
}
//将数据通过uart串口读入缓冲区
memset(temp,0x0,event.size);
uart_read_bytes(UART_NUM_2,temp,event.size,10/portTICK_PERIOD_MS);
if(event.size <= (spp_mtu_size - 3)){ //spp_mtu_size - 3是一个分组的最大容量
//向gatt发送indicate消息
//1.接口号2.连接id 3.特征句柄 4.数据长度 5.数据指针
esp_ble_gatts_send_indicate(spp_gatts_if,
spp_conn_id,
spp_handle_table[4],
event.size,
temp,
false
);
}else if(event.size > (spp_mtu_size - 3)){
if((event.size%(spp_mtu_size - 7)) == 0){
total_num = event.size/(spp_mtu_size - 7);//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\n", __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 = 122,
.source_clk = UART_SCLK_APB,
};
//Install UART driver, and get the queue.
uart_driver_install(UART_NUM_2, 4096, 8192, 10, &spp_uart_queue,0);
//Set UART parameters
uart_param_config(UART_NUM_2, &uart_config);
//Set UART pins
uart_set_pin(UART_NUM_2, 14, 21, 47, UART_PIN_NO_CHANGE);
xTaskCreate(uart_task, "uTask", 2048, (void*)UART_NUM_2, 8, NULL);
}
#ifdef SUPPORT_HEARTBEAT
void spp_heartbeat_task(void * arg)
{
uint16_t cmd_id;
for(;;) {
vTaskDelay(50 / portTICK_PERIOD_MS);
if(xQueueReceive(cmd_heartbeat_queue, &cmd_id, portMAX_DELAY)) {
while(1){
heartbeat_count_num++;
vTaskDelay(5000/ portTICK_PERIOD_MS);
if((heartbeat_count_num >3)&&(is_connected)){
esp_ble_gap_disconnect(spp_remote_bda);
}
if(is_connected && enable_heart_ntf){
esp_ble_gatts_send_indicate(spp_gatts_if, spp_conn_id, spp_handle_table[SPP_IDX_SPP_HEARTBEAT_VAL],sizeof(heartbeat_s), heartbeat_s, false);
}else if(!is_connected){
break;
}
}
}
}
vTaskDelete(NULL);
}
#endif
//通过接收队列获取蓝牙命令数据,进行相应的处理,然后打印到系统日志并释放相关内存
void spp_cmd_task(void * arg)
{
uint8_t * cmd_id;
for(;;){
vTaskDelay(50 / portTICK_PERIOD_MS);
if(xQueueReceive(cmd_cmd_queue, &cmd_id, 10 / portTICK_PERIOD_MS)) {
esp_log_buffer_char(GATTS_TABLE_TAG,(char *)(cmd_id),strlen((char *)cmd_id));
free(cmd_id);
}
}
vTaskDelete(NULL);
}
static void spp_task_init(void)
{
spp_uart_init();
#ifdef SUPPORT_HEARTBEAT
cmd_heartbeat_queue = xQueueCreate(10, sizeof(uint32_t));
xTaskCreate(spp_heartbeat_task, "spp_heartbeat_task", 2048, NULL, 10, NULL);
#endif
cmd_cmd_queue = xQueueCreate(10, sizeof(uint32_t));
xTaskCreate(spp_cmd_task, "spp_cmd_task", 2048, NULL, 10, NULL);
}
/*gap事件回调函数*/
static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
{
esp_err_t err;
ESP_LOGI(GATTS_TABLE_TAG, "GAP_EVT, event %d\n", event);
switch (event) {
/*表示原始广播数据设置完成*/
case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT:
/*启动广播,并传递蓝牙广播参数 spp_adv_params*/
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((err = param->adv_start_cmpl.status) != ESP_BT_STATUS_SUCCESS) {
ESP_LOGE(GATTS_TABLE_TAG, "Advertising start failed: %s\n", esp_err_to_name(err));
}
break;
default:
break;
}
}
/*处理gatt事件的回调函数,根据不同的请求执行不同的操作*/
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;
ESP_LOGI(GATTS_TABLE_TAG, "event = %x\n",event);
switch (event) {
//gatt服务器注册事件
case ESP_GATTS_REG_EVT:
ESP_LOGI(GATTS_TABLE_TAG, "%s %d\n", __func__, __LINE__);
//设置蓝牙设备名称
esp_ble_gap_set_device_name(SAMPLE_DEVICE_NAME);
ESP_LOGI(GATTS_TABLE_TAG, "%s %d\n", __func__, __LINE__);
//配置蓝牙广播数据的原始数据
esp_ble_gap_config_adv_data_raw((uint8_t *)spp_adv_data, sizeof(spp_adv_data));
ESP_LOGI(GATTS_TABLE_TAG, "%s %d\n", __func__, __LINE__);
//创建gatt服务的属性表
esp_ble_gatts_create_attr_tab(spp_gatt_db, gatts_if, SPP_IDX_NB, SPP_SVC_INST_ID);
break;
//收到读取数据的请求
case ESP_GATTS_READ_EVT:
//找到对应句柄,返回对应索引
res = find_char_and_desr_index(p_data->read.handle);
if(res == SPP_IDX_SPP_STATUS_VAL){
//TODO:client read the status characteristic
}
break;
//收到写数据的请求
case ESP_GATTS_WRITE_EVT: {
res = find_char_and_desr_index(p_data->write.handle);
if(p_data->write.is_prep == false){
ESP_LOGI(GATTS_TABLE_TAG, "ESP_GATTS_WRITE_EVT : handle = %d\n", res);
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\n", __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);
//SPP 数据通知配置
}else if(res == SPP_IDX_SPP_DATA_NTF_CFG){
//第一个字节为 0x01第二个字节为 0x00。如果条件满足则将 enable_data_ntf 设置为 true表示启用数据通知
if((p_data->write.len == 2)&&(p_data->write.value[0] == 0x01)&&(p_data->write.value[1] == 0x00)){
enable_data_ntf = true;
}else if((p_data->write.len == 2)&&(p_data->write.value[0] == 0x00)&&(p_data->write.value[1] == 0x00)){
enable_data_ntf = false;
}
}
#ifdef SUPPORT_HEARTBEAT
else if(res == SPP_IDX_SPP_HEARTBEAT_CFG){
if((p_data->write.len == 2)&&(p_data->write.value[0] == 0x01)&&(p_data->write.value[1] == 0x00)){
enable_heart_ntf = true;
}else if((p_data->write.len == 2)&&(p_data->write.value[0] == 0x00)&&(p_data->write.value[1] == 0x00)){
enable_heart_ntf = false;
}
}else if(res == SPP_IDX_SPP_HEARTBEAT_VAL){
if((p_data->write.len == sizeof(heartbeat_s))&&(memcmp(heartbeat_s,p_data->write.value,sizeof(heartbeat_s)) == 0)){
heartbeat_count_num = 0;
}
}
#endif
else if(res == SPP_IDX_SPP_DATA_RECV_VAL){
#ifdef SPP_DEBUG_MODE
esp_log_buffer_char(GATTS_TABLE_TAG,(char *)(p_data->write.value),p_data->write.len);
#else
uart_write_bytes(UART_NUM_2, (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)){
ESP_LOGI(GATTS_TABLE_TAG, "ESP_GATTS_PREP_WRITE_EVT : handle = %d\n", res);
store_wr_buffer(p_data);
}
break;
}
//执行写入操作
case ESP_GATTS_EXEC_WRITE_EVT:{
ESP_LOGI(GATTS_TABLE_TAG, "ESP_GATTS_EXEC_WRITE_EVT\n");
if(p_data->exec_write.exec_write_flag){
print_write_buffer();
free_write_buffer();
}
break;
}
case ESP_GATTS_MTU_EVT:
spp_mtu_size = p_data->mtu.mtu;
break;
case ESP_GATTS_CONF_EVT:
break;
case ESP_GATTS_UNREG_EVT:
break;
case ESP_GATTS_DELETE_EVT:
break;
case ESP_GATTS_START_EVT:
break;
case ESP_GATTS_STOP_EVT:
break;
case ESP_GATTS_CONNECT_EVT:
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));
#ifdef SUPPORT_HEARTBEAT
uint16_t cmd = 0;
xQueueSend(cmd_heartbeat_queue,&cmd,10/portTICK_PERIOD_MS);
#endif
break;
case ESP_GATTS_DISCONNECT_EVT:
is_connected = false;
enable_data_ntf = false;
#ifdef SUPPORT_HEARTBEAT
enable_heart_ntf = false;
heartbeat_count_num = 0;
#endif
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;
//gatt创建属性表
case ESP_GATTS_CREAT_ATTR_TAB_EVT:{
ESP_LOGI(GATTS_TABLE_TAG, "The number handle =%x\n",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));
//启动gatt服务
esp_ble_gatts_start_service(spp_handle_table[SPP_IDX_SVC]);
}
break;
}
default:
break;
}
}
/*gatt事件回调函数*/ //gatt属于ble的一个协议层
static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
{
ESP_LOGI(GATTS_TABLE_TAG, "EVT %d, gatts if %d\n", event, gatts_if);//打印接口标识符gatts_if
/* If event is register event, store the gatts_if for each profile */
//GATT 注册事件
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\n",param->reg.app_id, param->reg.status);
return;
}
}
//循环遍历 spp_profile_tab 结构体中的配置文件,根据条件判断是否需要调用回调函数处理事件
do {
int idx;
for (idx = 0; idx < SPP_PROFILE_NUM; idx++) {
/* 表示没有指定特定的 gatts_if ,需要调用每个配置文件的回调函数*/
if (gatts_if == ESP_GATT_IF_NONE || 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 bt_client_init(void)
{
esp_err_t ret;
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
/*初始化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 );
/*对 BTDM 控制器的 ROM只读存储器数据进行初始化操作*/
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\n", __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\n", __func__, esp_err_to_name(ret));
return;
}
ESP_LOGI(GATTS_TABLE_TAG, "%s init bluetooth\n", __func__);
/*初始化蓝牙协议栈r*/
ret = esp_bluedroid_init();
if (ret) {
ESP_LOGE(GATTS_TABLE_TAG, "%s init bluetooth failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
/*使能蓝牙协议栈*/
ret = esp_bluedroid_enable();
if (ret) {
ESP_LOGE(GATTS_TABLE_TAG, "%s enable bluetooth failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
/*注册ble的gap和gatt回调函数*/
esp_ble_gatts_register_callback(gatts_event_handler);
esp_ble_gap_register_callback(gap_event_handler);
/*注册gatt服务应用*/
esp_ble_gatts_app_register(ESP_SPP_APP_ID);
/*spp任务初始化*/
spp_task_init(); //初始化uart创建消息队列以及任务
return;
}

View File

@ -1,42 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
* DEFINES
****************************************************************************************
*/
//#define SUPPORT_HEARTBEAT
//#define SPP_DEBUG_MODE
#define spp_sprintf(s,...) sprintf((char*)(s), ##__VA_ARGS__)
#define SPP_DATA_MAX_LEN (512)
#define SPP_CMD_MAX_LEN (20)
#define SPP_STATUS_MAX_LEN (20)
#define SPP_DATA_BUFF_MAX_LEN (2*1024)
///Attributes State Machine
enum{
SPP_IDX_SVC,
SPP_IDX_SPP_DATA_RECV_CHAR,
SPP_IDX_SPP_DATA_RECV_VAL,
SPP_IDX_SPP_DATA_NOTIFY_CHAR,
SPP_IDX_SPP_DATA_NTY_VAL,
SPP_IDX_SPP_DATA_NTF_CFG,
SPP_IDX_SPP_COMMAND_CHAR,
SPP_IDX_SPP_COMMAND_VAL,
SPP_IDX_SPP_STATUS_CHAR,
SPP_IDX_SPP_STATUS_VAL,
SPP_IDX_SPP_STATUS_CFG,
#ifdef SUPPORT_HEARTBEAT
SPP_IDX_SPP_HEARTBEAT_CHAR,
SPP_IDX_SPP_HEARTBEAT_VAL,
SPP_IDX_SPP_HEARTBEAT_CFG,
#endif
SPP_IDX_NB,
};

192
main/communication_tcp.c Normal file
View File

@ -0,0 +1,192 @@
#include <stdint.h>
#include <string.h>
#include "lwip/ip_addr.h"
#include "lwip/tcp.h"
#include "lwip/err.h"
#include "lwip/opt.h"
#include "lwip/sockets.h"
#include "stm32/ModbusS.h"
#include "esp_log.h"
#define LOG_TAG "[communication_tcp_sr]: "
bool tcp_is_connected = false;
extern bool data_notify_enable; /* 是否允许数据上报 */
extern void gatts_write_data_cb(uint8_t *data, uint32_t len);
static err_t ModBusSlave_recv(void *arg, struct tcp_pcb *newpcb, struct pbuf *p, err_t err) {
if (p != NULL) {
uint8_t *rxbuf;
int rxlen;
tcp_recved(newpcb, p->tot_len);
rxbuf = (uint8_t *)p->payload;
rxlen = p->len;
ESP_LOGI(LOG_TAG, "recive data %d:", rxlen);
esp_log_buffer_hex(LOG_TAG, rxbuf, rxlen);
gatts_write_data_cb(rxbuf, rxlen);
pbuf_free(p);
}
else if (err == ERR_OK)
{
ESP_LOGI(LOG_TAG, "gps1 remote end is closing the connection\n");
for (uint8_t i = 0; i < 1; i++)
{ // 清空所有客户端
gps1_acce_newpacb[i] = 0;
}
tcp_err(newpcb, NULL);
tcp_recv(newpcb, NULL);
tcp_poll(newpcb, NULL, 120);
err_t err_p = tcp_close(newpcb);
tcp_is_connected = false;
if (ERR_OK != err_p)
{
ESP_LOGI(LOG_TAG, "gps1 close error. err:%d\n", err_p);
}
return err_p;
}
return ERR_OK;
}
static void ModBusSlave_conn_err(void *arg, err_t err) {
// log_printf(LERROR, LOG_TAG "connection error, err:%d\n", err);
tcp_is_connected = false;
}
static err_t ModBusSlave_poll(void *arg, struct tcp_pcb *newpcb) {
// if (newpcb) {
// // log_printf(LERROR, LOG_TAG "close pcb\n");
// tcp_close(newpcb);
// newpcb = NULL;
// }
ESP_LOGI(LOG_TAG, "poll!");
return ERR_OK;
}
static err_t ModBusSlave_accept(void *arg, struct tcp_pcb *pcb, err_t err) {
tcp_err(pcb, ModBusSlave_conn_err);
tcp_recv(pcb, ModBusSlave_recv);
tcp_poll(pcb, ModBusSlave_poll, 120); // 60 second timeout
/* Send out the first message */
// tcp_write(pcb, GREETING, strlen(GREETING), 1);
tcp_is_connected = true;
return ERR_OK;
}
static void notify_all_data(void)
{
ESP_LOGI(GATTS_TABLE_TAG, "notify_all_data");
uint8_t buf[1024];
buf[0] = 1; /* tag:深度:速度 时间 深度 桩号 */
buf[1] = 8;
buf[2] = depth_data->speed & 0xff;
buf[3] = (depth_data->speed >> 8) & 0xff;
buf[4] = depth_data->one_pile_work_time & 0xff;
buf[5] = (depth_data->one_pile_work_time >> 8) & 0xff;
buf[6] = depth_data->depth & 0xff;
buf[7] = (depth_data->depth >> 8) & 0xff;
buf[8] = gWordVar[LAST_PILE_ID_ADDR] & 0xff;
buf[9] = (gWordVar[LAST_PILE_ID_ADDR] >> 8) & 0xff;
buf[10] = 2; /* tag:1号通道流量:瞬时每10cm总 */
buf[11] = 6;
buf[12] = pflow[0].flow & 0xff;
buf[13] = (pflow[0].flow >> 8) & 0xff;
buf[14] = depth_data->depth_flow[0] & 0xff;
buf[15] = (depth_data->depth_flow[0] >> 8) & 0xff;
buf[16] = pflow[0].total_flow & 0xff;
buf[17] = (pflow[0].total_flow >> 8) & 0xff;
buf[18] = 3; /* tag:2号通道流量:瞬时每10cm总 */
buf[19] = 6;
buf[20] = pflow[1].flow & 0xff;
buf[21] = (pflow[1].flow >> 8) & 0xff;
buf[22] = depth_data->depth_flow[1] & 0xff;
buf[23] = (depth_data->depth_flow[1] >> 8) & 0xff;
buf[24] = pflow[1].total_flow & 0xff;
buf[25] = (pflow[1].total_flow >> 8) & 0xff;
buf[26] = 4; /* tag:电流:三个*/
buf[27] = 6;
buf[28] = gWordVar[AC_CURRENT_REG_ADDR + 0] & 0xff;
buf[29] = (gWordVar[AC_CURRENT_REG_ADDR + 0] >> 8) & 0xff;
buf[30] = gWordVar[AC_CURRENT_REG_ADDR + 1] & 0xff;
buf[31] = (gWordVar[AC_CURRENT_REG_ADDR + 1] >> 8) & 0xff;
buf[32] = gWordVar[AC_CURRENT_REG_ADDR + 2] & 0xff;
buf[33] = (gWordVar[AC_CURRENT_REG_ADDR + 2] >> 8) & 0xff;
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[34] = 5; /* tag:CPS信息1:x, y(int64)*/
buf[35] = 16;
buf[36] = x & 0xff;
buf[37] = (x >> 8) & 0xff;
buf[38] = (x >> 16) & 0xff;
buf[39] = (x >> 24) & 0xff;
buf[40] = (x >> 32) & 0xff;
buf[41] = (x >> 40) & 0xff;
buf[42] = (x >> 48) & 0xff;
buf[43] = (x >> 56) & 0xff;
buf[44] = y & 0xff;
buf[45] = (y >> 8) & 0xff;
buf[56] = (y >> 16) & 0xff;
buf[47] = (y >> 24) & 0xff;
buf[48] = (y >> 32) & 0xff;
buf[49] = (y >> 40) & 0xff;
buf[50] = (y >> 48) & 0xff;
buf[51] = (y >> 56) & 0xff;
buf[52] = 6; /* tag:CPS信息2:方向,俯仰(uint16) gps定位状态(uint8) UTC时间(uint32)*/
buf[53] = 9;
buf[54] = dir & 0xff;
buf[55] = (dir >> 8) & 0xff;
buf[56] = pitch & 0xff;
buf[57] = (pitch >> 8) & 0xff;
buf[58] = utc_time & 0xff;
buf[59] = (utc_time >> 8) & 0xff;
buf[60] = (utc_time >> 16) & 0xff;
buf[61] = (utc_time >> 24) & 0xff;
buf[62] = gps_status & 0xff;
/* 需要上报什么数据在此处添加 */
// tcp_write(pcb, GREETING, strlen(GREETING), 1);
}
void notify_tcp_task(void *pvParameters)
{
ESP_LOGI(GATTS_TABLE_TAG, "notify_tcp_task");
while (1)
{
if (data_notify_enable && tcp_is_connected)
{
notify_all_data();
}
vTaskDelay(pdMS_TO_TICKS(100));
}
vTaskDelete(NULL);
}
void communication_tcp_init(void) {
struct tcp_pcb *pcb;
pcb = tcp_new();
tcp_bind(pcb, IP_ADDR_ANY, 6061);
pcb = tcp_listen(pcb);
tcp_accept(pcb, ModBusSlave_accept);
xTaskCreate(notify_tcp_task, "notify_tcp_Task", 4096, NULL, 8, NULL);
}

View File

@ -121,7 +121,7 @@ void app_main(void)
wifi_init_softap();//ok wifi_init_softap();//ok
// wifi_init_sta(); // wifi_init_sta();
// can_init(); // can_init();
// PWR_4G_Init(); // PWR_4G_Init();
ModBusTCPSlave_init(); ModBusTCPSlave_init();
ads1220_task_start(); /* 两路电流AD采样获取瞬时流量计算累计流量 */ ads1220_task_start(); /* 两路电流AD采样获取瞬时流量计算累计流量 */
@ -130,7 +130,6 @@ void app_main(void)
FLOW_init(); /* 两一种计算流量的方法,计算累计流量 */ FLOW_init(); /* 两一种计算流量的方法,计算累计流量 */
uart0_modbus_slave_init(); uart0_modbus_slave_init();
// ble_server_init(); // ble_server_init();
ble_gatts_server_init(); ble_gatts_server_init();

View File

@ -9,6 +9,7 @@
#include "lwip/opt.h" #include "lwip/opt.h"
#include "lwip/sockets.h" #include "lwip/sockets.h"
#include "stm32/ModbusS.h" #include "stm32/ModbusS.h"
#include "esp_log.h"
// #include "log.h" // #include "log.h"
#define LOG_TAG "[mb_tcp_sr]: " #define LOG_TAG "[mb_tcp_sr]: "
@ -92,11 +93,12 @@ static void ModBusSlave_conn_err(void *arg, err_t err) {
// log_printf(LERROR, LOG_TAG "connection error, err:%d\n", err); // log_printf(LERROR, LOG_TAG "connection error, err:%d\n", err);
} }
static err_t ModBusSlave_poll(void *arg, struct tcp_pcb *newpcb) { static err_t ModBusSlave_poll(void *arg, struct tcp_pcb *newpcb) {
if (newpcb) { // if (newpcb) {
// log_printf(LERROR, LOG_TAG "close pcb\n"); // // log_printf(LERROR, LOG_TAG "close pcb\n");
tcp_close(newpcb); // tcp_close(newpcb);
newpcb = NULL; // newpcb = NULL;
} // }
ESP_LOGI(LOG_TAG, "HELLO!");
return ERR_OK; return ERR_OK;
} }
/** /**
@ -112,7 +114,7 @@ static err_t ModBusSlave_accept(void *arg, struct tcp_pcb *pcb, err_t err) {
/* Configure LwIP to use our call back functions. */ /* Configure LwIP to use our call back functions. */
tcp_err(pcb, ModBusSlave_conn_err); tcp_err(pcb, ModBusSlave_conn_err);
tcp_recv(pcb, ModBusSlave_recv); tcp_recv(pcb, ModBusSlave_recv);
tcp_poll(pcb, ModBusSlave_poll, 120); // 60 second timeout tcp_poll(pcb, ModBusSlave_poll, 1); // 60 second timeout
/* Send out the first message */ /* Send out the first message */
// tcp_write(pcb, GREETING, strlen(GREETING), 1); // tcp_write(pcb, GREETING, strlen(GREETING), 1);
return ERR_OK; return ERR_OK;

View File

@ -19,7 +19,8 @@
// #include "driver/mcpwm_prelude.h" // #include "driver/mcpwm_prelude.h"
#include "config.h" #include "config.h"
#include "../../../../components/bt/host/bluedroid/api/include/api/esp_gatts_api.h" #include "../../../../components/bt/host/bluedroid/api/include/api/esp_gatts_api.h"
#include "bt_server.h" // #include "bt_server.h"
#include "../ble_gatts_server.h"
#include "esp_system.h" #include "esp_system.h"
#include "driver/uart.h" #include "driver/uart.h"
@ -332,7 +333,7 @@ int abs_sub(uint32_t enc_update_time, uint32_t _enc_update_time)
send_to_bt_t1 send_to_bt1; send_to_bt_t1 send_to_bt1;
send_to_bt_t2 send_to_bt2; send_to_bt_t2 send_to_bt2;
extern bool is_connected; extern bool is_connected;
extern uint16_t spp_handle_table[SPP_IDX_NB]; extern uint16_t spp_handle_table[IDX_NB];
extern uint16_t spp_conn_id; extern uint16_t spp_conn_id;
extern esp_gatt_if_t spp_gatts_if; extern esp_gatt_if_t spp_gatts_if;
extern flow_t *pflow; extern flow_t *pflow;

View File

@ -1,502 +0,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 "esp_gap_ble_api.h"
#include "esp_gatts_api.h"
#include "esp_bt_defs.h"
#include "esp_bt_main.h"
#include "ble_server.h"
#include "stm32/config.h"
#include "stm32/ModbusS.h"
#define GATTS_TABLE_TAG "GATTS_SPP_DEMO"
#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 ESP_GATT_UUID_PILE_DATA_RECEIVE1 0XABF5
#define ESP_GATT_UUID_PILE_DATA_RECEIVE2 0XABF6
#define ESP_GATT_UUID_PILE_DATA_RECEIVE3 0XABF7
#ifdef SUPPORT_HEARTBEAT
#define ESP_GATT_UUID_SPP_HEARTBEAT 0xABF5
#endif
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 = 23;
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;
#ifdef SUPPORT_HEARTBEAT
static QueueHandle_t cmd_heartbeat_queue = NULL;
static uint8_t heartbeat_s[9] = {'E','s','p','r','e','s','s','i','f'};
static bool enable_heart_ntf = false;
static uint8_t heartbeat_count_num = 0;
#endif
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 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] = {0x02, 0x03};
///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
extern cal_4_20ma_t *cal_4_20ma;//电流数据结构体
extern flow_config_t *flow_config;//流量数据结构体
extern depth_config_t *depth_config;//深度数据结构体
static const uint16_t pile_data_receive1_uuid = ESP_GATT_UUID_PILE_DATA_RECEIVE1;
static const uint16_t pile_data_receive2_uuid = ESP_GATT_UUID_PILE_DATA_RECEIVE2;
static const uint16_t pile_data_receive3_uuid = ESP_GATT_UUID_PILE_DATA_RECEIVE3;
///Full HRS Database Description - Used to add attributes into the database
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 *)&char_prop_read_notify}},
//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}},
[PILE_IDX_DATA_RECV1_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}},
[PILE_IDX_DATA_RECV1_VAL] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&pile_data_receive1_uuid, ESP_GATT_PERM_READ|ESP_GATT_PERM_WRITE,
SPP_DATA_MAX_LEN,sizeof(cal_4_20ma_t), (uint8_t *)&gWordVar[CAL_4_20MA_ADDR]}},
[PILE_IDX_DATA_RECV2_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}},
[PILE_IDX_DATA_RECV2_VAL] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&pile_data_receive2_uuid, ESP_GATT_PERM_READ|ESP_GATT_PERM_WRITE,
SPP_DATA_MAX_LEN,sizeof(flow_config_t), (uint8_t *)&gWordVar[FLOW_CONFIG_ADDR]}},
[PILE_IDX_DATA_RECV3_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}},
[PILE_IDX_DATA_RECV3_VAL] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&pile_data_receive3_uuid, ESP_GATT_PERM_READ|ESP_GATT_PERM_WRITE,
SPP_DATA_MAX_LEN,sizeof(depth_config_t), (uint8_t *)&gWordVar[DEPTH_CONFIG_ADDR]}},
};
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 void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
{
esp_err_t err;
ESP_LOGE(GATTS_TABLE_TAG, "GAP_EVT, event %d\n", event);
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((err = param->adv_start_cmpl.status) != ESP_BT_STATUS_SUCCESS) {
ESP_LOGE(GATTS_TABLE_TAG, "Advertising start failed: %s\n", esp_err_to_name(err));
}
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;
ESP_LOGI(GATTS_TABLE_TAG, "event = %d\n",event);
switch (event) {
case ESP_GATTS_REG_EVT:
ESP_LOGI(GATTS_TABLE_TAG, "ESP_GATTS_REG_EVT");
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, "ESP_GATTS_READ_EVT");
gWordVar[CAL_4_20MA_ADDR] = 1;
// res = find_char_and_desr_index(p_data->read.handle);
// if(res == SPP_IDX_SPP_STATUS_VAL){
// //TODO:client read the status characteristic
// }
break;
case ESP_GATTS_WRITE_EVT: {
ESP_LOGI(GATTS_TABLE_TAG, "ESP_GATTS_WRITE_EVT");
res = find_char_and_desr_index(p_data->write.handle);
if(p_data->write.is_prep == false){
// ESP_LOGI(GATTS_TABLE_TAG, "ESP_GATTS_WRITE_EVT : handle = %d\n", res);
if(res == SPP_IDX_SPP_COMMAND_VAL){
ESP_LOGI(GATTS_TABLE_TAG, "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\n", __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){
ESP_LOGI(GATTS_TABLE_TAG, "SPP_IDX_SPP_DATA_NTF_CFG");
if((p_data->write.len == 2)&&(p_data->write.value[0] == 0x01)&&(p_data->write.value[1] == 0x00)){
enable_data_ntf = true;
}else if((p_data->write.len == 2)&&(p_data->write.value[0] == 0x00)&&(p_data->write.value[1] == 0x00)){
enable_data_ntf = false;
}
}
else if(res == SPP_IDX_SPP_DATA_RECV_VAL){
ESP_LOGI(GATTS_TABLE_TAG, "SPP_IDX_SPP_DATA_RECV_VAL");
ESP_LOGI(GATTS_TABLE_TAG, "0x%x 0x%x", spp_data_receive_val[0], spp_data_receive_val[1]);
// uart_write_bytes(UART_NUM_2, (char *)(p_data->write.value), p_data->write.len);
}
else if (res == PILE_IDX_DATA_RECV1_VAL){
ESP_LOGI(GATTS_TABLE_TAG, "PILE_IDX_DATA_RECV1_VAL %d:0x%x 0x%x 0x%x 0x%x", p_data->write.len, p_data->write.value[0], p_data->write.value[1], p_data->write.value[2], p_data->write.value[3]);
ESP_LOGI(GATTS_TABLE_TAG, "0x%x 0x%x", gWordVar[CAL_4_20MA_ADDR], gWordVar[CAL_4_20MA_ADDR + 1]);
ESP_LOGI(GATTS_TABLE_TAG, "cal_4_20ma->magic=%d", cal_4_20ma->magic);
}
else if (res == PILE_IDX_DATA_RECV2_VAL){
ESP_LOGI(GATTS_TABLE_TAG, "PILE_IDX_DATA_RECV2_VAL");
}
else if (res == PILE_IDX_DATA_RECV3_VAL){
ESP_LOGI(GATTS_TABLE_TAG, "PILE_IDX_DATA_RECV3_VAL");
}
else{
//TODO:
}
}else if((p_data->write.is_prep == true)&&(res == SPP_IDX_SPP_DATA_RECV_VAL)){
ESP_LOGI(GATTS_TABLE_TAG, "ESP_GATTS_PREP_WRITE_EVT : handle = %d\n", res);
// store_wr_buffer(p_data);
}
break;
}
case ESP_GATTS_EXEC_WRITE_EVT:{
ESP_LOGI(GATTS_TABLE_TAG, "ESP_GATTS_EXEC_WRITE_EVT\n");
if(p_data->exec_write.exec_write_flag){
// print_write_buffer();
// free_write_buffer();
}
break;
}
case ESP_GATTS_MTU_EVT:
spp_mtu_size = p_data->mtu.mtu;
break;
case ESP_GATTS_CONF_EVT:
break;
case ESP_GATTS_UNREG_EVT:
break;
case ESP_GATTS_DELETE_EVT:
break;
case ESP_GATTS_START_EVT:
break;
case ESP_GATTS_STOP_EVT:
break;
case ESP_GATTS_CONNECT_EVT:
ESP_LOGI(GATTS_TABLE_TAG, "ESP_GATTS_CONNECT_EVT");
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));
#ifdef SUPPORT_HEARTBEAT
uint16_t cmd = 0;
xQueueSend(cmd_heartbeat_queue,&cmd,10/portTICK_PERIOD_MS);
#endif
break;
case ESP_GATTS_DISCONNECT_EVT:
ESP_LOGI(GATTS_TABLE_TAG, "ESP_GATTS_DISCONNECT_EVT");
is_connected = false;
enable_data_ntf = false;
#ifdef SUPPORT_HEARTBEAT
enable_heart_ntf = false;
heartbeat_count_num = 0;
#endif
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\n",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)
{
ESP_LOGI(GATTS_TABLE_TAG, "EVT %d, gatts if %d\n", event, gatts_if);
/* 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\n",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 ble_server_init(void)
{
esp_err_t ret;
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
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\n", __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\n", __func__, esp_err_to_name(ret));
return;
}
ESP_LOGI(GATTS_TABLE_TAG, "%s init bluetooth\n", __func__);
ret = esp_bluedroid_init();
if (ret) {
ESP_LOGE(GATTS_TABLE_TAG, "%s init bluetooth failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
ret = esp_bluedroid_enable();
if (ret) {
ESP_LOGE(GATTS_TABLE_TAG, "%s enable bluetooth failed: %s\n", __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);
return;
}

View File

@ -1,59 +0,0 @@
#ifndef __BLE_SERCER_H
#define __BLE_SERCER_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
* DEFINES
****************************************************************************************
*/
//#define SUPPORT_HEARTBEAT
//#define SPP_DEBUG_MODE
#define spp_sprintf(s,...) sprintf((char*)(s), ##__VA_ARGS__)
#define SPP_DATA_MAX_LEN (512)
#define SPP_CMD_MAX_LEN (20)
#define SPP_STATUS_MAX_LEN (20)
#define SPP_DATA_BUFF_MAX_LEN (2*1024)
///Attributes State Machine
enum{
SPP_IDX_SVC,
SPP_IDX_SPP_DATA_RECV_CHAR,
SPP_IDX_SPP_DATA_RECV_VAL,
SPP_IDX_SPP_DATA_NOTIFY_CHAR,
SPP_IDX_SPP_DATA_NTY_VAL,
SPP_IDX_SPP_DATA_NTF_CFG,
SPP_IDX_SPP_COMMAND_CHAR,
SPP_IDX_SPP_COMMAND_VAL,
SPP_IDX_SPP_STATUS_CHAR,
SPP_IDX_SPP_STATUS_VAL,
SPP_IDX_SPP_STATUS_CFG,
#ifdef SUPPORT_HEARTBEAT
SPP_IDX_SPP_HEARTBEAT_CHAR,
SPP_IDX_SPP_HEARTBEAT_VAL,
SPP_IDX_SPP_HEARTBEAT_CFG,
#endif
PILE_IDX_DATA_RECV1_CHAR,
PILE_IDX_DATA_RECV1_VAL,
PILE_IDX_DATA_RECV2_CHAR,
PILE_IDX_DATA_RECV2_VAL,
PILE_IDX_DATA_RECV3_CHAR,
PILE_IDX_DATA_RECV3_VAL,
SPP_IDX_NB,
};
void ble_server_init(void);
#endif

View File

@ -1,859 +0,0 @@
/*
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#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 "esp_gap_ble_api.h"
#include "esp_gatts_api.h"
#include "esp_bt_defs.h"
#include "esp_bt_main.h"
#include "bt_server.h"
#define SPP_DEBUG_MODE 1
#define GATTS_TABLE_TAG "GATTS_SPP_DEMO"
#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
#ifdef SUPPORT_HEARTBEAT
#define ESP_GATT_UUID_SPP_HEARTBEAT 0xABF5
#endif
/*蓝牙的广播数据*/
static const uint8_t spp_adv_data[23] = {
/* Flags */
0x02,0x01,0x06, //表示设备支持LE General Discoverable Mode可被发现模式和BR/EDR Not Supported不支持传统蓝牙
/* Complete List of 16-bit Service Class UUIDs */
0x03,0x03,0xF0,0xAB,//广播数据中的16位服务UUID字段表示设备提供了一个特定的服务这里是自定义的16位UUID
/* Complete Local Name in advertising */
0x0F,0x09, 'E', 'S', 'P', '_', 'S', 'P', 'P', '_', 'S', 'E', 'R','V', 'E', 'R'
//广播数据中的16位服务UUID字段表示设备提供了一个特定的服务这里是自定义的16位UUID
};
static uint16_t spp_mtu_size = 23;
uint16_t spp_conn_id = 0xffff;
esp_gatt_if_t spp_gatts_if = 0xff;
QueueHandle_t spp_uart_queue = NULL;
static QueueHandle_t cmd_cmd_queue = NULL;
#ifdef SUPPORT_HEARTBEAT
static QueueHandle_t cmd_heartbeat_queue = NULL;
static uint8_t heartbeat_s[9] = {'E','s','p','r','e','s','s','i','f'};
static bool enable_heart_ntf = false;
static uint8_t heartbeat_count_num = 0;
#endif
static bool enable_data_ntf = false;
bool is_connected = false;
static esp_bd_addr_t spp_remote_bda = {0x0,};
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; //0x2800
static const uint16_t character_declaration_uuid = ESP_GATT_UUID_CHAR_DECLARE; //0x2803
static const uint16_t character_client_config_uuid = ESP_GATT_UUID_CHAR_CLIENT_CONFIG; //0x2902
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 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; //0xABF1
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; //0xABF2
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; //0xABF3
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; //0xABF4
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, //0x2800
ESP_GATT_PERM_READ,
sizeof(spp_service_uuid), //0xABF0
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, //0x2803
ESP_GATT_PERM_READ,
CHAR_DECLARATION_SIZE,
CHAR_DECLARATION_SIZE,
(uint8_t *)&char_prop_read_write
}
},
//SPP - data receive characteristic Value spp服务中数据接收特征值
[SPP_IDX_SPP_DATA_RECV_VAL] = {
{ESP_GATT_AUTO_RSP},
{
ESP_UUID_LEN_16,
(uint8_t *)&spp_data_receive_uuid, //0xABF1
ESP_GATT_PERM_READ|ESP_GATT_PERM_WRITE,
SPP_DATA_MAX_LEN,
sizeof(spp_data_receive_val),
(uint8_t *)spp_data_receive_val //0x00
}
},
//SPP - data notify characteristic Declaration spp协议中数据通知特征
[SPP_IDX_SPP_DATA_NOTIFY_CHAR] = {
{ESP_GATT_AUTO_RSP},
{
ESP_UUID_LEN_16,
(uint8_t *)&character_declaration_uuid, //0x2803
ESP_GATT_PERM_READ,
CHAR_DECLARATION_SIZE,
CHAR_DECLARATION_SIZE,
(uint8_t *)&char_prop_read_notify
}
},
//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, //0xABF2
ESP_GATT_PERM_READ,
SPP_DATA_MAX_LEN,
sizeof(spp_data_notify_val),
(uint8_t *)spp_data_notify_val //0x00
}
},
//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, //0x2902
ESP_GATT_PERM_READ|ESP_GATT_PERM_WRITE,
sizeof(uint16_t),
sizeof(spp_data_notify_ccc),
(uint8_t *)spp_data_notify_ccc //{0x00, 0x00}
}
},
//SPP - command characteristic Declaration 命令特征声明
[SPP_IDX_SPP_COMMAND_CHAR]= {
{ESP_GATT_AUTO_RSP},
{
ESP_UUID_LEN_16,
(uint8_t *)&character_declaration_uuid, //0x2803
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, //0xABF3
ESP_GATT_PERM_READ|ESP_GATT_PERM_WRITE,
SPP_CMD_MAX_LEN,
sizeof(spp_command_val),
(uint8_t *)spp_command_val //{0x00}
}
},
//SPP - status characteristic Declaration
[SPP_IDX_SPP_STATUS_CHAR] = {
{ESP_GATT_AUTO_RSP},
{
ESP_UUID_LEN_16,
(uint8_t *)&character_declaration_uuid, //0x2803
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, //0xABF4
ESP_GATT_PERM_READ,
SPP_STATUS_MAX_LEN,
sizeof(spp_status_val),
(uint8_t *)spp_status_val //{0x00}
}
},
//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, //0x2902
ESP_GATT_PERM_READ|ESP_GATT_PERM_WRITE,
sizeof(uint16_t),
sizeof(spp_status_ccc),
(uint8_t *)spp_status_ccc //{0x00, 0x00}
}
},
#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
};
/*在 spp_handle_table 数组中查找与给定句柄匹配的特性或描述符,返回其索引值。如果没有找到匹配的值,则返回 0xff*/
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\n", __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;
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;
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;
}
/*将缓冲区数据写入uart*/
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_2, (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;
}
}
//蓝牙设备接收到消息后将分组数据通过蓝牙的 GATT Indicate 方式发送给蓝牙连接的设备(也就是蓝牙客户端)
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, 10/portTICK_PERIOD_MS)) {
switch (event.type) {
//Event of UART receving data
case UART_DATA:
if ((event.size)&&(is_connected)) {
uint8_t * temp = NULL;
uint8_t * ntf_value_p = NULL;
#ifdef SUPPORT_HEARTBEAT
if(!enable_heart_ntf){
ESP_LOGE(GATTS_TABLE_TAG, "%s do not enable heartbeat Notify\n", __func__);
break;
}
#endif
if(!enable_data_ntf){
ESP_LOGE(GATTS_TABLE_TAG, "%s do not enable data Notify\n", __func__);
break;
}
temp = (uint8_t *)malloc(sizeof(uint8_t)*event.size);
if(temp == NULL){
ESP_LOGE(GATTS_TABLE_TAG, "%s malloc.1 failed\n", __func__);
break;
}
//将数据通过uart串口读入缓冲区
memset(temp,0x0,event.size);
uart_read_bytes(UART_NUM_2,temp,event.size,10/portTICK_PERIOD_MS);
if(event.size <= (spp_mtu_size - 3)){ //spp_mtu_size - 3是一个分组的最大容量
//向gatt发送indicate消息
//1.接口号2.连接id 3.特征句柄 4.数据长度 5.数据指针
esp_ble_gatts_send_indicate(spp_gatts_if,
spp_conn_id,
spp_handle_table[4],
event.size,
temp,
false
);
}else if(event.size > (spp_mtu_size - 3)){
if((event.size%(spp_mtu_size - 7)) == 0){
total_num = event.size/(spp_mtu_size - 7);//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\n", __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 = 122,
.source_clk = UART_SCLK_APB,
};
//Install UART driver, and get the queue.
uart_driver_install(UART_NUM_2, 4096, 8192, 10, &spp_uart_queue,0);
//Set UART parameters
uart_param_config(UART_NUM_2, &uart_config);
//Set UART pins
uart_set_pin(UART_NUM_2, 14, 21, 47, UART_PIN_NO_CHANGE);
xTaskCreate(uart_task, "uTask", 2048, (void*)UART_NUM_2, 8, NULL);
}
#ifdef SUPPORT_HEARTBEAT
void spp_heartbeat_task(void * arg)
{
uint16_t cmd_id;
for(;;) {
vTaskDelay(50 / portTICK_PERIOD_MS);
if(xQueueReceive(cmd_heartbeat_queue, &cmd_id, portMAX_DELAY)) {
while(1){
heartbeat_count_num++;
vTaskDelay(5000/ portTICK_PERIOD_MS);
if((heartbeat_count_num >3)&&(is_connected)){
esp_ble_gap_disconnect(spp_remote_bda);
}
if(is_connected && enable_heart_ntf){
esp_ble_gatts_send_indicate(spp_gatts_if, spp_conn_id, spp_handle_table[SPP_IDX_SPP_HEARTBEAT_VAL],sizeof(heartbeat_s), heartbeat_s, false);
}else if(!is_connected){
break;
}
}
}
}
vTaskDelete(NULL);
}
#endif
//通过接收队列获取蓝牙命令数据,进行相应的处理,然后打印到系统日志并释放相关内存
void spp_cmd_task(void * arg)
{
uint8_t * cmd_id;
for(;;){
vTaskDelay(50 / portTICK_PERIOD_MS);
if(xQueueReceive(cmd_cmd_queue, &cmd_id, 10 / portTICK_PERIOD_MS)) {
esp_log_buffer_char(GATTS_TABLE_TAG,(char *)(cmd_id),strlen((char *)cmd_id));
free(cmd_id);
}
}
vTaskDelete(NULL);
}
static void spp_task_init(void)
{
spp_uart_init();
#ifdef SUPPORT_HEARTBEAT
cmd_heartbeat_queue = xQueueCreate(10, sizeof(uint32_t));
xTaskCreate(spp_heartbeat_task, "spp_heartbeat_task", 2048, NULL, 10, NULL);
#endif
cmd_cmd_queue = xQueueCreate(10, sizeof(uint32_t));
xTaskCreate(spp_cmd_task, "spp_cmd_task", 2048, NULL, 10, NULL);
}
/*gap事件回调函数*/
static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
{
esp_err_t err;
ESP_LOGI(GATTS_TABLE_TAG, "GAP_EVT, event %d\n", event);
switch (event) {
/*表示原始广播数据设置完成*/
case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT:
/*启动广播,并传递蓝牙广播参数 spp_adv_params*/
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((err = param->adv_start_cmpl.status) != ESP_BT_STATUS_SUCCESS) {
ESP_LOGE(GATTS_TABLE_TAG, "Advertising start failed: %s\n", esp_err_to_name(err));
}
break;
default:
break;
}
}
/*处理gatt事件的回调函数,根据不同的请求执行不同的操作*/
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;
ESP_LOGI(GATTS_TABLE_TAG, "event = %x\n",event);
switch (event) {
//gatt服务器注册事件
case ESP_GATTS_REG_EVT:
ESP_LOGI(GATTS_TABLE_TAG, "%s %d\n", __func__, __LINE__);
//设置蓝牙设备名称
esp_ble_gap_set_device_name(SAMPLE_DEVICE_NAME);
ESP_LOGI(GATTS_TABLE_TAG, "%s %d\n", __func__, __LINE__);
//配置蓝牙广播数据的原始数据
esp_ble_gap_config_adv_data_raw((uint8_t *)spp_adv_data, sizeof(spp_adv_data));
ESP_LOGI(GATTS_TABLE_TAG, "%s %d\n", __func__, __LINE__);
//创建gatt服务的属性表
esp_ble_gatts_create_attr_tab(spp_gatt_db, gatts_if, SPP_IDX_NB, SPP_SVC_INST_ID);
break;
//收到读取数据的请求
case ESP_GATTS_READ_EVT:
//找到对应句柄,返回对应索引
res = find_char_and_desr_index(p_data->read.handle);
if(res == SPP_IDX_SPP_STATUS_VAL){
//TODO:client read the status characteristic
}
break;
//收到写数据的请求
case ESP_GATTS_WRITE_EVT: {
res = find_char_and_desr_index(p_data->write.handle);
if(p_data->write.is_prep == false){
ESP_LOGI(GATTS_TABLE_TAG, "ESP_GATTS_WRITE_EVT : handle = %d\n", res);
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\n", __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);
//SPP 数据通知配置
}else if(res == SPP_IDX_SPP_DATA_NTF_CFG){
//第一个字节为 0x01第二个字节为 0x00。如果条件满足则将 enable_data_ntf 设置为 true表示启用数据通知
if((p_data->write.len == 2)&&(p_data->write.value[0] == 0x01)&&(p_data->write.value[1] == 0x00)){
enable_data_ntf = true;
}else if((p_data->write.len == 2)&&(p_data->write.value[0] == 0x00)&&(p_data->write.value[1] == 0x00)){
enable_data_ntf = false;
}
}
#ifdef SUPPORT_HEARTBEAT
else if(res == SPP_IDX_SPP_HEARTBEAT_CFG){
if((p_data->write.len == 2)&&(p_data->write.value[0] == 0x01)&&(p_data->write.value[1] == 0x00)){
enable_heart_ntf = true;
}else if((p_data->write.len == 2)&&(p_data->write.value[0] == 0x00)&&(p_data->write.value[1] == 0x00)){
enable_heart_ntf = false;
}
}else if(res == SPP_IDX_SPP_HEARTBEAT_VAL){
if((p_data->write.len == sizeof(heartbeat_s))&&(memcmp(heartbeat_s,p_data->write.value,sizeof(heartbeat_s)) == 0)){
heartbeat_count_num = 0;
}
}
#endif
else if(res == SPP_IDX_SPP_DATA_RECV_VAL){
#ifdef SPP_DEBUG_MODE
esp_log_buffer_char(GATTS_TABLE_TAG,(char *)(p_data->write.value),p_data->write.len);
#else
uart_write_bytes(UART_NUM_2, (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)){
ESP_LOGI(GATTS_TABLE_TAG, "ESP_GATTS_PREP_WRITE_EVT : handle = %d\n", res);
store_wr_buffer(p_data);
}
break;
}
//执行写入操作
case ESP_GATTS_EXEC_WRITE_EVT:{
ESP_LOGI(GATTS_TABLE_TAG, "ESP_GATTS_EXEC_WRITE_EVT\n");
if(p_data->exec_write.exec_write_flag){
print_write_buffer();
free_write_buffer();
}
break;
}
case ESP_GATTS_MTU_EVT:
spp_mtu_size = p_data->mtu.mtu;
break;
case ESP_GATTS_CONF_EVT:
break;
case ESP_GATTS_UNREG_EVT:
break;
case ESP_GATTS_DELETE_EVT:
break;
case ESP_GATTS_START_EVT:
break;
case ESP_GATTS_STOP_EVT:
break;
case ESP_GATTS_CONNECT_EVT:
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));
#ifdef SUPPORT_HEARTBEAT
uint16_t cmd = 0;
xQueueSend(cmd_heartbeat_queue,&cmd,10/portTICK_PERIOD_MS);
#endif
break;
case ESP_GATTS_DISCONNECT_EVT:
is_connected = false;
enable_data_ntf = false;
#ifdef SUPPORT_HEARTBEAT
enable_heart_ntf = false;
heartbeat_count_num = 0;
#endif
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;
//gatt创建属性表
case ESP_GATTS_CREAT_ATTR_TAB_EVT:{
ESP_LOGI(GATTS_TABLE_TAG, "The number handle =%x\n",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));
//启动gatt服务
esp_ble_gatts_start_service(spp_handle_table[SPP_IDX_SVC]);
}
break;
}
default:
break;
}
}
/*gatt事件回调函数*/ //gatt属于ble的一个协议层
static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
{
ESP_LOGI(GATTS_TABLE_TAG, "EVT %d, gatts if %d\n", event, gatts_if);//打印接口标识符gatts_if
/* If event is register event, store the gatts_if for each profile */
//GATT 注册事件
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\n",param->reg.app_id, param->reg.status);
return;
}
}
//循环遍历 spp_profile_tab 结构体中的配置文件,根据条件判断是否需要调用回调函数处理事件
do {
int idx;
for (idx = 0; idx < SPP_PROFILE_NUM; idx++) {
/* 表示没有指定特定的 gatts_if ,需要调用每个配置文件的回调函数*/
if (gatts_if == ESP_GATT_IF_NONE || 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 bt_client_init(void)
{
esp_err_t ret;
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
/*初始化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 );
/*对 BTDM 控制器的 ROM只读存储器数据进行初始化操作*/
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\n", __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\n", __func__, esp_err_to_name(ret));
return;
}
ESP_LOGI(GATTS_TABLE_TAG, "%s init bluetooth\n", __func__);
/*初始化蓝牙协议栈r*/
ret = esp_bluedroid_init();
if (ret) {
ESP_LOGE(GATTS_TABLE_TAG, "%s init bluetooth failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
/*使能蓝牙协议栈*/
ret = esp_bluedroid_enable();
if (ret) {
ESP_LOGE(GATTS_TABLE_TAG, "%s enable bluetooth failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
/*注册ble的gap和gatt回调函数*/
esp_ble_gatts_register_callback(gatts_event_handler);
esp_ble_gap_register_callback(gap_event_handler);
/*注册gatt服务应用*/
esp_ble_gatts_app_register(ESP_SPP_APP_ID);
/*spp任务初始化*/
spp_task_init(); //初始化uart创建消息队列以及任务
return;
}

View File

@ -1,42 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
* DEFINES
****************************************************************************************
*/
//#define SUPPORT_HEARTBEAT
//#define SPP_DEBUG_MODE
#define spp_sprintf(s,...) sprintf((char*)(s), ##__VA_ARGS__)
#define SPP_DATA_MAX_LEN (512)
#define SPP_CMD_MAX_LEN (20)
#define SPP_STATUS_MAX_LEN (20)
#define SPP_DATA_BUFF_MAX_LEN (2*1024)
///Attributes State Machine
enum{
SPP_IDX_SVC,
SPP_IDX_SPP_DATA_RECV_CHAR,
SPP_IDX_SPP_DATA_RECV_VAL,
SPP_IDX_SPP_DATA_NOTIFY_CHAR,
SPP_IDX_SPP_DATA_NTY_VAL,
SPP_IDX_SPP_DATA_NTF_CFG,
SPP_IDX_SPP_COMMAND_CHAR,
SPP_IDX_SPP_COMMAND_VAL,
SPP_IDX_SPP_STATUS_CHAR,
SPP_IDX_SPP_STATUS_VAL,
SPP_IDX_SPP_STATUS_CFG,
#ifdef SUPPORT_HEARTBEAT
SPP_IDX_SPP_HEARTBEAT_CHAR,
SPP_IDX_SPP_HEARTBEAT_VAL,
SPP_IDX_SPP_HEARTBEAT_CFG,
#endif
SPP_IDX_NB,
};