#include #include #include #include "esp_log.h" #include "esp_bt.h" #include "esp_gap_ble_api.h" #include "esp_gatts_api.h" #include "esp_bt_main.h" #include "esp_bt_device.h" #include "esp_gatt_common_api.h" #include "esp_mac.h" #include "fatfs.h" #include "pages.h" #define APP_ID_PLACEHOLDER 0 #define IMAGE_SERVICE_INSTID 0x0B #define IMAGE_SERVICE_UUID 0x0B00 #define IMAGE_WRITE_UUID 0x0B01 #define IMAGE_EDIT_UUID 0x0B02 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_write[512] = {0}; static uint8_t attr_value_edit[20] = {0}; 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_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_image = { .id.uuid.len = ESP_UUID_LEN_16, .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, 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) { 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 | ESP_GATT_CHAR_PROP_BIT_WRITE_NR, &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 | ESP_GATT_CHAR_PROP_BIT_WRITE_NR, &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) { 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); } } else { ESP_LOGE(CONN_TAG, "特征创建失败,状态: %d", param->add_char.status); } 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,"wb"); ESP_LOGI(CONN_TAG,"传输通道建立成功,数据指针:%p,文件名称:%s,文件大小:%d",img_data,firstMeg.filename,(int)firstMeg.len); } }else if(SendStatus.isSend){ ESP_LOGI(CONN_TAG, "获取到数据:第:%d包,长度:%d,是否结束:%d",*value+1,(int)param->write.len,*(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){ ESP_LOGI(CONN_TAG,"数据接收完毕,累计:%d字节,预期:%d字节,首字节:%02X %02X", (int)SendStatus.port,(int)firstMeg.len,img_data[0],img_data[1]); 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); // 导航到ScreenImg显示新图片(内部刷新列表+设置索引+切换界面) ble_image_navigate(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); ble_image_navigate(imgName); }else if(type == 0xF1){ remove(filepath); SendStatus.isSend = false; SendStatus.port = 0; free(img_data); free(filepath); } } 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; } }