425 lines
16 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "esp_log.h"
#include "esp_bt.h"
#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 "esp_gatt_common_api.h"
#include "esp_mac.h"
#include "temp.h"
#include "fatfs.h"
#include "pages.h"
#define APP_ID_PLACEHOLDER 0
#define SENSOR_SERVICE_INSTID 0x0A
#define SENSOR_SERVICE_UUID 0x0A00
#define SENSOR_TEMP_UUID 0x0A01
#define SENSOR_HUMI_UUID 0x0A02
#define IMAGE_SERVICE_INSTID 0x0B
#define IMAGE_SERVICE_UUID 0x0B00
#define IMAGE_WRITE_UUID 0x0B01
#define IMAGE_EDIT_UUID 0x0B02
static uint16_t sensor_service_handle = 0;
static uint16_t temp_attr_handle = 0;
static uint16_t humi_attr_handle = 0;
static uint16_t image_service_handle = 0;
static uint16_t image_write_handle = 0;
static uint16_t image_edit_handle = 0;
static void esp_gap_cb(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param);
static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param);
static const char *CONN_TAG = "CONN_BLE";
static const char device_name[] = "MY-BLE";
static uint16_t conn_id;
static char *filepath;
typedef struct
{
uint8_t type;
char filename[23];
uint32_t len;
} Megtype;
typedef struct{
bool isSend;
uint32_t port;
} MegStatus;
Megtype firstMeg;
MegStatus SendStatus = {false,0};
uint8_t *img_data = 0;
FILE *file_img;
static uint8_t attr_value_temp[22] = {0};
static uint8_t attr_value_humi[22] = {0};
static uint8_t attr_value_write[512] = {0};
static uint8_t attr_value_edit[20] = {0};
static esp_attr_value_t char_val_temp = {
.attr_max_len = 4,
.attr_len = 4,
.attr_value = attr_value_temp
} ;
static esp_attr_value_t char_val_humi = {
.attr_max_len = 4,
.attr_len = 4,
.attr_value = attr_value_humi
} ;
static esp_attr_value_t char_val_image_write = {
.attr_max_len = 512,
.attr_len = 512,
.attr_value = attr_value_write
} ;
static esp_attr_value_t char_val_image_edit = {
.attr_max_len = 20,
.attr_len = 20,
.attr_value = attr_value_edit
} ;
static esp_attr_control_t control_temp = {
.auto_rsp = ESP_GATT_AUTO_RSP
};
static esp_attr_control_t control_humi = {
.auto_rsp = ESP_GATT_AUTO_RSP
};
static esp_attr_control_t control_image_write = {
.auto_rsp = ESP_GATT_AUTO_RSP
};
static esp_attr_control_t control_image_edit = {
.auto_rsp = ESP_GATT_AUTO_RSP
};
//传感器服务
static esp_gatt_srvc_id_t server_id_sensor = {
.id = {
.uuid.uuid.uuid16 = SENSOR_SERVICE_UUID,
.inst_id = SENSOR_SERVICE_INSTID,
},
.is_primary = true,
};
static esp_bt_uuid_t sensor_temp_uuid = {
.len = ESP_UUID_LEN_16,
.uuid.uuid16 = SENSOR_TEMP_UUID,
};
static esp_bt_uuid_t sensor_humi_uuid = {
.len = ESP_UUID_LEN_16,
.uuid.uuid16 = SENSOR_HUMI_UUID,
};
//图片传输服务
static esp_gatt_srvc_id_t server_id_image = {
.id.uuid.uuid.uuid16 = IMAGE_SERVICE_UUID,
.id.inst_id = IMAGE_SERVICE_INSTID,
.is_primary = true,
};
static esp_bt_uuid_t image_write_uuid = {
.len = ESP_UUID_LEN_16,
.uuid.uuid16 = IMAGE_WRITE_UUID,
};
static esp_bt_uuid_t image_edit_uuid = {
.len = ESP_UUID_LEN_16,
.uuid.uuid16 = IMAGE_EDIT_UUID,
};
static esp_ble_adv_params_t adv_params = {
.adv_int_min = 0x20,
.adv_int_max = 0x20,
.adv_type = ADV_TYPE_IND,
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
.channel_map = ADV_CHNL_ALL,
.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
};
static uint8_t adv_raw_data[] = {
0x02, ESP_BLE_AD_TYPE_FLAG, 0x06,
0x07, ESP_BLE_AD_TYPE_NAME_CMPL, 'M','Y','-','B','L','E',
0x02, ESP_BLE_AD_TYPE_TX_PWR, 0x09,
0x03, ESP_BLE_AD_TYPE_16SRV_CMPL, 0xB0, 0x00,
0x03, ESP_BLE_AD_TYPE_16SRV_CMPL, 0xA0, 0x00,
0x07, ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE,0x4C,0x44,0x64,0x7A,0x62,0x6A
};
void ble_init(void)
{
esp_err_t ret;
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
ret = esp_bt_controller_init(&bt_cfg);
if (ret) {
ESP_LOGE(CONN_TAG, "%s initialize controller failed: %s", __func__, esp_err_to_name(ret));
return;
}
ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
if (ret) {
ESP_LOGE(CONN_TAG, "%s enable controller failed: %s", __func__, esp_err_to_name(ret));
return;
}
ret = esp_bluedroid_init();
if (ret) {
ESP_LOGE(CONN_TAG, "%s init bluetooth failed: %s", __func__, esp_err_to_name(ret));
return;
}
ret = esp_bluedroid_enable();
if (ret) {
ESP_LOGE(CONN_TAG, "%s enable bluetooth failed: %s", __func__, esp_err_to_name(ret));
return;
}
ret = esp_ble_gap_register_callback(esp_gap_cb);
if (ret) {
ESP_LOGE(CONN_TAG, "%s gap register failed, error code = %x", __func__, ret);
return;
}
ret = esp_ble_gatts_register_callback(gatts_event_handler);
if (ret) {
ESP_LOGE(CONN_TAG, "%s gatts register failed, error code = %x", __func__, ret);
return;
}
ret = esp_ble_gatts_app_register(APP_ID_PLACEHOLDER);
if (ret) {
ESP_LOGE(CONN_TAG, "%s gatts app register failed, error code = %x", __func__, ret);
return;
}
ret = esp_ble_gatt_set_local_mtu(512);
if (ret) {
ESP_LOGE(CONN_TAG, "set local MTU failed, error code = %x", ret);
return;
}
ret = esp_ble_gap_set_device_name(device_name);
if (ret) {
ESP_LOGE(CONN_TAG, "set device name failed, error code = %x", ret);
return;
}
ret = esp_ble_gap_config_adv_data_raw(adv_raw_data, sizeof(adv_raw_data));
if (ret) {
ESP_LOGE(CONN_TAG, "config adv data failed, error code = %x", ret);
}
}
static void esp_gap_cb(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_LOGI(CONN_TAG, "Advertising data set, status %d", param->adv_data_raw_cmpl.status);
esp_ble_gap_start_advertising(&adv_params);
break;
case ESP_GAP_BLE_ADV_START_COMPLETE_EVT:
if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) {
ESP_LOGE(CONN_TAG, "Advertising start failed, status %d", param->adv_start_cmpl.status);
break;
}
ESP_LOGI(CONN_TAG, "Advertising start successfully");
break;
case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT:
if (param->adv_stop_cmpl.status != ESP_BT_STATUS_SUCCESS) {
ESP_LOGE(CONN_TAG, "Advertising stop failed, status %d", param->adv_stop_cmpl.status);
}
ESP_LOGI(CONN_TAG, "Advertising stop successfully");
break;
case ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT:
ESP_LOGI(CONN_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;
}
}
// GATT服务器事件处理函数
static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
{
switch (event) {
case ESP_GATTS_REG_EVT:
ESP_LOGI(CONN_TAG, "GATT server register, status %d, app_id %d",param->reg.status, param->reg.app_id);
// 创建图片传输服务
esp_ble_gatts_create_service(gatts_if,&server_id_image,10);
break;
case ESP_GATTS_CREATE_EVT:
if (param->create.status == ESP_GATT_OK) {
// ESP_LOGI(CONN_TAG, "服务创建成功,句柄:0x%x,instid:0x%02x",param->create.service_handle,param->create.service_id.id.inst_id);
if (param->create.service_id.id.inst_id == (uint16_t)SENSOR_SERVICE_INSTID) {
sensor_service_handle = param->create.service_handle;
esp_ble_gatts_add_char(
sensor_service_handle,
&sensor_temp_uuid,
ESP_GATT_PERM_READ,
ESP_GATT_CHAR_PROP_BIT_READ,
&char_val_temp,
&control_temp
);
esp_ble_gatts_add_char(
sensor_service_handle,
&sensor_humi_uuid,
ESP_GATT_PERM_READ,
ESP_GATT_CHAR_PROP_BIT_READ,
&char_val_humi,
&control_humi
);
ESP_LOGI(CONN_TAG, "温湿度服务创建成功,句柄: %x", sensor_service_handle);
} else if (param->create.service_id.id.inst_id == (uint16_t)IMAGE_SERVICE_INSTID) {
image_service_handle = param->create.service_handle;
esp_ble_gatts_add_char(
image_service_handle,
&image_write_uuid,
ESP_GATT_PERM_WRITE,
ESP_GATT_CHAR_PROP_BIT_WRITE,
&char_val_image_write,
&control_image_write
);
esp_ble_gatts_add_char(
image_service_handle,
&image_edit_uuid,
ESP_GATT_PERM_WRITE,
ESP_GATT_CHAR_PROP_BIT_WRITE,
&char_val_image_edit,
&control_image_edit
);
ESP_LOGI(CONN_TAG, "图片传输服务创建成功,句柄: %x", image_service_handle);
}
} else {
ESP_LOGE(CONN_TAG, "服务创建失败,状态: %d", param->create.status);
}
break;
case ESP_GATTS_ADD_CHAR_EVT:
if (param->add_char.status == ESP_GATT_OK) {
// ESP_LOGI(CONN_TAG, "特征创建成功,句柄:0x%x,UUID:0x%04x",param->add_char.attr_handle,param->add_char.char_uuid.uuid.uuid16);
if (param->add_char.char_uuid.uuid.uuid16 == (uint16_t)SENSOR_TEMP_UUID) {
temp_attr_handle = param->add_char.attr_handle;
ESP_LOGI(CONN_TAG, "TEMP特征创建成功,句柄: %d", temp_attr_handle);
} else if (param->add_char.char_uuid.uuid.uuid16 == (uint16_t)SENSOR_HUMI_UUID) {
humi_attr_handle = param->add_char.attr_handle;
ESP_LOGI(CONN_TAG, "HUMI特征创建成功,句柄: %d", humi_attr_handle);
esp_ble_gatts_start_service(sensor_service_handle);
} else if (param->add_char.char_uuid.uuid.uuid16 == (uint16_t)IMAGE_WRITE_UUID) {
image_write_handle = param->add_char.attr_handle;
ESP_LOGI(CONN_TAG, "图片写入特征创建成功,句柄: %d", image_write_handle);
}else if (param->add_char.char_uuid.uuid.uuid16 == (uint16_t)IMAGE_EDIT_UUID) {
image_edit_handle = param->add_char.attr_handle;
ESP_LOGI(CONN_TAG, "图片编辑特征创建成功,句柄: %d", image_edit_handle);
esp_ble_gatts_start_service(image_service_handle);
esp_ble_gatts_create_service(gatts_if,&server_id_sensor,10);
}
} else {
ESP_LOGE(CONN_TAG, "特征创建失败,状态: %d", param->add_char.status);
}
break;
case ESP_GATTS_READ_EVT:
uint16_t char_handle = param->read.handle;
if(char_handle == temp_attr_handle){
float *temp = malloc(4);
uint8_t *buffer = malloc(4);
get_temp(temp);
memcpy(buffer, temp, 4);;
esp_ble_gatts_set_attr_value(char_handle,4,buffer);
ESP_LOGI(CONN_TAG, "获取到温度读取事件,温度:%.2f,句柄: %d",*temp, char_handle);
free(temp);
}
break;
case ESP_GATTS_WRITE_EVT:
if(param->write.handle == image_write_handle){
uint8_t *value = param->write.value;
if(!SendStatus.isSend){
ESP_LOGI(CONN_TAG, "处理前序数据");
firstMeg.type = value[0];
memcpy(firstMeg.filename, value + 1, 22);
firstMeg.filename[22] = '\0';
firstMeg.len = (value[23] << 16) | (value[24] << 8) | value[25];
ESP_LOGI(CONN_TAG, "图片数据长度:%d",(int)firstMeg.len);
if(firstMeg.type == 0xfd){
SendStatus.isSend = true;
img_data = malloc((int)firstMeg.len);
filepath = malloc(sizeof(char) * 33);
sprintf(filepath,"/spiflash/%s",firstMeg.filename);
file_img = fopen(filepath,"w");
ESP_LOGI(CONN_TAG,"传输通道建立成功,数据指针:%p,文件名称:%s,文件大小:%d",img_data,firstMeg.filename,(int)firstMeg.len);
}
}else if(SendStatus.isSend){
ESP_LOGI(CONN_TAG, "获取到数据:第:%d包,是否结束:%d",*value+1,*(value+1));
uint8_t isEnd = *(value + 1);
uint8_t port = *(value);
uint8_t *data = value + 2;
memcpy(img_data + SendStatus.port,data,(int)param->write.len-2);
SendStatus.port += param->write.len-2;
if(isEnd){
fwrite(img_data,sizeof(uint8_t),firstMeg.len,file_img);
fclose(file_img);
SendStatus.isSend = false;
SendStatus.port = 0;
ESP_LOGI(CONN_TAG,"图片接收成功");
nvs_change_img(firstMeg.filename);
app_img_change(firstMeg.filename);
free(img_data);
free(filepath);
}
}
}// 图片编辑特征写入事件
else if(param->write.handle == image_edit_handle){
uint8_t *value = param->write.value;
char imgName[23];
uint8_t type = *(value + param->write.len - 1);
memcpy(imgName, value, 23);
if(type == 0xff){
nvs_change_img(imgName);
app_img_change(imgName);
}else if(type == 0xF1){
remove(filepath);
SendStatus.isSend = false;
SendStatus.port = 0;
free(img_data);
free(filepath);
}
// printf("%s\n %x",imgName,type);
// printf("接收到数据:");
// for (size_t i = 0; i < param->write.len; i++)
// {
// printf("%x ",*(value+i));
// }
// printf("\n");
}
break;
case ESP_GATTS_CONNECT_EVT:
esp_ble_conn_update_params_t conn_params = {0};
memcpy(conn_params.bda, param->connect.remote_bda, sizeof(esp_bd_addr_t));
conn_params.latency = 0;
conn_params.max_int = 32;
conn_params.min_int = 16;
conn_params.timeout = 400;
conn_id = param->connect.conn_id;
ESP_LOGI(CONN_TAG, "Connected, conn_id %u, remote "ESP_BD_ADDR_STR"",
param->connect.conn_id, ESP_BD_ADDR_HEX(param->connect.remote_bda));
esp_ble_gap_update_conn_params(&conn_params);
break;
case ESP_GATTS_DISCONNECT_EVT:
ESP_LOGI(CONN_TAG, "Disconnected, remote "ESP_BD_ADDR_STR", reason 0x%02x",
ESP_BD_ADDR_HEX(param->disconnect.remote_bda), param->disconnect.reason);
esp_ble_gap_start_advertising(&adv_params);
break;
default:
break;
}
}