#include #include #include #include #include "freertos/FreeRTOS.h" #include "freertos/projdefs.h" #include "freertos/task.h" #include "freertos/event_groups.h" #include "esp_system.h" #include "esp_log.h" #include "nvs_flash.h" #include "esp_wifi.h" #include "esp_wifi_default.h" #include "esp_netif.h" #include "WIFI/wifi.h" /* NimBLE 相关头文件 */ #include "nimble/nimble_port.h" #include "nimble/nimble_port_freertos.h" #include "host/ble_hs.h" #include "host/ble_uuid.h" #include "services/gap/ble_svc_gap.h" #include "services/gatt/ble_svc_gatt.h" #include "LVGL/lvgl_init.h" #include "LVGL/lvgl_lottie.h" #include "event.h" #include "LVGL/lvgl_src.h" #include "ble.h" #include "ble_data_ansy.h" #include "EMOJI_STORAGE/emoji_storage.h" #include "ALGORITHM/crc.h" #include "MQTT/mqtt.h" #include "remapping.h" #include "ble_send.h" #include "MOTOR/motor_control.h" // 使用不同的名称替代TAG,避免与其他声明冲突 const char *BLE_TAG = "NimBLE_SERVER"; static uint16_t conn_handle = 0; // 当前连接句柄 static bool is_connected = false; bool notify_enabled = false; // 默认通知使能 关闭 char s_emoji_delete_target_pack = '0'; volatile bool sentinel_mode_is_active = false; // 当前是否处于哨兵激活态 const char *form = "/%s/%s.json"; const char *form1 = "/extflash/%s/%02d"; bool is_auth=false; void ble_wv_data_ansy(uint8_t *input, size_t length);//大众加密 static uint16_t is_On_handle = 0; // 事件特征句柄 static uint16_t event_char_handle = 0; static uint16_t auth_handle = 0; static uint16_t otaData_handle = 0; // 特征值存储 static uint8_t rw_char_value[256] = {0}; static uint8_t ro_char_value[] = "Hello from ESP32-S3"; static uint8_t notify_char_value[MAX_NOTIFY_LEN] = {0}; static int notify_counter = 0; // 在全局变量区域添加 static uint16_t tx_char_handle = 0; // 发送特征句柄 static uint16_t rx_char_handle = 0; // 接收特征句柄 static uint16_t notify_char_handle = 0; // 通知特征句柄 <- 这是关键! extern int g_progress; /* 声明函数 */ static int gatt_svr_chr_access(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg); void ble_app_advertise(void); static int ble_gap_event(struct ble_gap_event *event, void *arg); static void print_heap_info(void); void send_notification_to_app(const char *message); void sentinel_task(void *arg); /* 哨兵任务已禁用 */ extern char filename_emoji[64]; TaskHandle_t sentinel_task_handle = NULL; TaskHandle_t notification_task_handle = NULL; bool is_not_sentinel_mode = true; static void auth_timeout_handler(TimerHandle_t xTimer); TimerHandle_t timer=NULL; #if 1 static const struct ble_gatt_svc_def gatt_svr_svcs[] = { {/* 主服务 */ .type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid = BLE_UUID128_DECLARE(0x9f, 0x6a, 0xe8, 0x0c, 0x9f, 0x6a, 0x00, 0x01, 0x6b, 0x00, 0x2c, 0x1f, 0x42, 0x74, 0xbd, 0x08), //&gatt_svr_svc_uuid.u, .characteristics = (struct ble_gatt_chr_def[]){ { /* 可读写特征 (用于接收APP数据) */ .uuid = BLE_UUID16_DECLARE(BLE_CHAR_UUID_TX), //&gatt_svr_chr_uuid_rw.u, .access_cb = gatt_svr_chr_access, .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE, .val_handle = &tx_char_handle, // 将由系统分配 }, { /* 只读特征 (用于APP读取数据) */ .uuid = BLE_UUID16_DECLARE(BLE_CHAR_UUID_RX), //&gatt_svr_chr_uuid_ro.u,RX .access_cb = gatt_svr_chr_access, .flags = BLE_GATT_CHR_F_READ, .val_handle = &rx_char_handle, }, { /* 通知特征 (用于主动向APP推送数据) */ .uuid = BLE_UUID16_DECLARE(BLE_CHAR_UUID_NOTIFY), //&gatt_svr_chr_uuid_notify.u, .access_cb = gatt_svr_chr_access, .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_WRITE, .val_handle = ¬ify_char_handle, }, { /* IS ON 开关状态*/ .uuid = BLE_UUID128_DECLARE(0x08, 0xbd, 0x74, 0x42, 0x1f, 0x2c, 0x00, 0x6b , 0x01, 0x00, 0x6a, 0x9f, 0xf7, 0xa0, 0x8c, 0x45), .access_cb = gatt_svr_chr_access, .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_WRITE, .val_handle = &is_On_handle, }, { /*EVENT ID 场景模式*/ .uuid = BLE_UUID128_DECLARE(0x08, 0xbd, 0x74, 0x42, 0x1f, 0x2c, 0x00, 0x6b , 0x01, 0x00, 0x6a, 0x9f, 0xb5, 0x4d, 0xcc, 0x53), .access_cb = gatt_svr_chr_access, .flags = BLE_GATT_CHR_F_WRITE, .val_handle = &event_char_handle, }, { /*Auth 认证消息*/ .uuid = BLE_UUID128_DECLARE(0x08, 0xbd, 0x74, 0x42, 0x1f, 0x2c, 0x00, 0x6b , 0x01, 0x00, 0x6a, 0x9f, 0x1c, 0xb9, 0x53, 0xfa), .access_cb = gatt_svr_chr_access, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_NOTIFY, .val_handle = &auth_handle, }, { /*Auth OTA更新*/ .uuid = BLE_UUID128_DECLARE(0x08, 0xbd, 0x74, 0x42, 0x1f, 0x2c, 0x00, 0x6b , 0x01, 0x00, 0x6a, 0x9f, 0x22, 0x01, 0x15, 0x80), .access_cb = gatt_svr_chr_access, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_NOTIFY, .val_handle = &otaData_handle, }, {0} /* 结束标记 */ }}, {0} /* 结束标记 */ }; #endif /* 特征访问回调函数 */ static int gatt_svr_chr_access(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { const ble_uuid_t *uuid = ctxt->chr->uuid; int rc = 0; uint16_t cccd_value = 0; uint8_t sentinel_mode_flag = 0; /* 任何特征被访问时都打印,便于排查“发送指令无反应” */ ESP_LOGI(BLE_TAG, "GATT 访问: op=%d 句柄=%d", ctxt->op, attr_handle); /* 判断是哪个特征被访问 */ if (ble_uuid_cmp(uuid, BLE_UUID16_DECLARE(BLE_CHAR_UUID_TX)) == 0) { switch (ctxt->op) { case BLE_GATT_ACCESS_OP_READ_CHR: /* APP读取可读特征值 */ ESP_LOGI(BLE_TAG, "APP READ_CHR ,句柄: %d", attr_handle); rc = os_mbuf_append(ctxt->om, rw_char_value, strlen((char *)rw_char_value)); break; case BLE_GATT_ACCESS_OP_WRITE_CHR: /* APP写入可写特征值 */ ESP_LOGI(BLE_TAG, "APP WRITE_CHR,句柄: %d", attr_handle); if (ctxt->om->om_len < sizeof(rw_char_value)) { memcpy(rw_char_value, ctxt->om->om_data, ctxt->om->om_len); ESP_LOGI(BLE_TAG, "接收蓝牙数据帧 [长度: %d]:", ctxt->om->om_len); ble_data_ansy(rw_char_value, ctxt->om->om_len); } break; default: rc = BLE_ATT_ERR_UNLIKELY; break; } } else if (ble_uuid_cmp(uuid, BLE_UUID16_DECLARE(BLE_CHAR_UUID_RX)) == 0) { /* 只读特征 */ if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { ESP_LOGI(BLE_TAG, "APP读取只读特征"); rc = os_mbuf_append(ctxt->om, ro_char_value, strlen((char *)ro_char_value)); } else { rc = BLE_ATT_ERR_REQ_NOT_SUPPORTED; } } else if (ble_uuid_cmp(uuid, BLE_UUID16_DECLARE(BLE_CHAR_UUID_NOTIFY)) == 0) { /* 通知特征 */ switch (ctxt->op) { case BLE_GATT_ACCESS_OP_READ_CHR: ESP_LOGI(BLE_TAG, "APP读取通知特征"); rc = os_mbuf_append(ctxt->om, notify_char_value, strlen((char *)notify_char_value)); break; case BLE_GATT_ACCESS_OP_WRITE_DSC: /* APP写入CCCD描述符 */ if (ctxt->dsc && ctxt->dsc->uuid) { if (ble_uuid_cmp(ctxt->dsc->uuid, BLE_UUID16_DECLARE(0x2902)) == 0) { if (ctxt->om->om_len == 2) { memcpy(&cccd_value, ctxt->om->om_data, 2); notify_enabled = (cccd_value == 0x0001); ESP_LOGI(BLE_TAG, "CCCD写入: 0x%04X, 通知%s", cccd_value, notify_enabled ? "启用" : "禁用"); } } } break; case BLE_GATT_ACCESS_OP_READ_DSC: /* APP读取CCCD描述符 */ if (ctxt->dsc && ctxt->dsc->uuid) { if (ble_uuid_cmp(ctxt->dsc->uuid, BLE_UUID16_DECLARE(0x2902)) == 0) { uint16_t current_cccd = notify_enabled ? 0x0001 : 0x0000; ESP_LOGI(BLE_TAG, "APP读取CCCD,返回: 0x%04X", current_cccd); rc = os_mbuf_append(ctxt->om, ¤t_cccd, sizeof(current_cccd)); } } break; default: rc = BLE_ATT_ERR_UNLIKELY; break; } } else if(ble_uuid_cmp(uuid, BLE_UUID128_DECLARE(0x08, 0xbd, 0x74, 0x42, 0x1f, 0x2c, 0x00, 0x6b , 0x01, 0x00, 0x6a, 0x9f, 0xf7, 0xa0, 0x8c, 0x45)) == 0){ //IS_ON switch (ctxt->op){ case BLE_GATT_ACCESS_OP_READ_CHR: /* APP读取可读特征值 */ ESP_LOGI(BLE_TAG, "APP READ_CHR ,句柄: %d", attr_handle); rc = os_mbuf_append(ctxt->om, rw_char_value, strlen((char *)rw_char_value)); break; case BLE_GATT_ACCESS_OP_WRITE_CHR: ESP_LOGI(BLE_TAG, "EVENT ID WRITE_CHR,句柄: %d", attr_handle); if (ctxt->om->om_len < sizeof(rw_char_value)){ memcpy(rw_char_value, ctxt->om->om_data, ctxt->om->om_len); ESP_LOGI(BLE_TAG, "接收蓝牙数据帧 [长度: %d]:", ctxt->om->om_len); //ble_wv_data_ansy(rw_char_value, ctxt->om->om_len); } break; case BLE_GATT_ACCESS_OP_WRITE_DSC: /* APP写入CCCD描述符 */ if (ctxt->dsc && ctxt->dsc->uuid) { if (ble_uuid_cmp(ctxt->dsc->uuid, BLE_UUID16_DECLARE(0x2902)) == 0) { if (ctxt->om->om_len == 2) { memcpy(&cccd_value, ctxt->om->om_data, 2); notify_enabled = (cccd_value == 0x0001); ///变量需修改 ESP_LOGI(BLE_TAG, "CCCD写入: 0x%04X, 通知%s", cccd_value, notify_enabled ? "启用" : "禁用"); } } } break; case BLE_GATT_ACCESS_OP_READ_DSC: /* APP读取CCCD描述符 */ if (ctxt->dsc && ctxt->dsc->uuid) { if (ble_uuid_cmp(ctxt->dsc->uuid, BLE_UUID16_DECLARE(0x2902)) == 0) { uint16_t current_cccd = notify_enabled ? 0x0001 : 0x0000; ESP_LOGI(BLE_TAG, "APP读取CCCD,返回: 0x%04X", current_cccd); rc = os_mbuf_append(ctxt->om, ¤t_cccd, sizeof(current_cccd)); } } break; } } else if(ble_uuid_cmp(uuid, BLE_UUID128_DECLARE(0x08, 0xbd, 0x74, 0x42, 0x1f, 0x2c, 0x00, 0x6b , 0x01, 0x00, 0x6a, 0x9f, 0xb5, 0x4d, 0xcc, 0x53)) == 0){ //场景模式 switch (ctxt->op){ case BLE_GATT_ACCESS_OP_WRITE_CHR: ESP_LOGI(BLE_TAG, "EVENT ID WRITE_CHR,句柄: %d", attr_handle); if (ctxt->om->om_len < sizeof(rw_char_value)){ memcpy(rw_char_value, ctxt->om->om_data, ctxt->om->om_len); ESP_LOGI(BLE_TAG, "接收蓝牙数据帧 [长度: %d]:", ctxt->om->om_len); ble_wv_data_ansy2(rw_char_value, ctxt->om->om_len); } break; case BLE_GATT_ACCESS_OP_WRITE_DSC: /* APP写入CCCD描述符 */ if (ctxt->dsc && ctxt->dsc->uuid) { if (ble_uuid_cmp(ctxt->dsc->uuid, BLE_UUID16_DECLARE(0x2902)) == 0) { if (ctxt->om->om_len == 2) { memcpy(&cccd_value, ctxt->om->om_data, 2); notify_enabled = (cccd_value == 0x0001); ///变量需修改 ESP_LOGI(BLE_TAG, "CCCD写入: 0x%04X, 通知%s", cccd_value, notify_enabled ? "启用" : "禁用"); } } } break; case BLE_GATT_ACCESS_OP_READ_DSC: /* APP读取CCCD描述符 */ if (ctxt->dsc && ctxt->dsc->uuid) { if (ble_uuid_cmp(ctxt->dsc->uuid, BLE_UUID16_DECLARE(0x2902)) == 0) { uint16_t current_cccd = notify_enabled ? 0x0001 : 0x0000; ESP_LOGI(BLE_TAG, "APP读取CCCD,返回: 0x%04X", current_cccd); rc = os_mbuf_append(ctxt->om, ¤t_cccd, sizeof(current_cccd)); } } break; } } else if(ble_uuid_cmp(uuid, BLE_UUID128_DECLARE(0x08, 0xbd, 0x74, 0x42, 0x1f, 0x2c, 0x00, 0x6b , 0x01, 0x00, 0x6a, 0x9f, 0x1c, 0xb9, 0x53, 0xfa)) == 0){ //认证消息 switch (ctxt->op){ case BLE_GATT_ACCESS_OP_WRITE_CHR: ESP_LOGI(BLE_TAG, "EVENT ID WRITE_CHR,句柄: %d", attr_handle); if (ctxt->om->om_len < sizeof(rw_char_value)){ memcpy(rw_char_value, ctxt->om->om_data, ctxt->om->om_len); ESP_LOGI(BLE_TAG, "接收蓝牙数据帧 [长度: %d]:", ctxt->om->om_len); ble_wv_data_ansy(rw_char_value, ctxt->om->om_len); } break; case BLE_GATT_ACCESS_OP_WRITE_DSC: /* APP写入CCCD描述符 */ if (ctxt->dsc && ctxt->dsc->uuid) { if (ble_uuid_cmp(ctxt->dsc->uuid, BLE_UUID16_DECLARE(0x2902)) == 0) { if (ctxt->om->om_len == 2) { memcpy(&cccd_value, ctxt->om->om_data, 2); notify_enabled = (cccd_value == 0x0001); ///变量需修改 ESP_LOGI(BLE_TAG, "CCCD写入: 0x%04X, 通知%s", cccd_value, notify_enabled ? "启用" : "禁用"); } } } break; case BLE_GATT_ACCESS_OP_READ_DSC: /* APP读取CCCD描述符 */ if (ctxt->dsc && ctxt->dsc->uuid) { if (ble_uuid_cmp(ctxt->dsc->uuid, BLE_UUID16_DECLARE(0x2902)) == 0) { uint16_t current_cccd = notify_enabled ? 0x0001 : 0x0000; ESP_LOGI(BLE_TAG, "APP读取CCCD,返回: 0x%04X", current_cccd); rc = os_mbuf_append(ctxt->om, ¤t_cccd, sizeof(current_cccd)); } } break; } } else if(ble_uuid_cmp(uuid, BLE_UUID128_DECLARE(0x08, 0xbd, 0x74, 0x42, 0x1f, 0x2c, 0x00, 0x6b , 0x01, 0x00, 0x6a, 0x9f, 0x22, 0x0b, 0x15, 0x80)) == 0){ //OTA_DATA switch (ctxt->op){ case BLE_GATT_ACCESS_OP_WRITE_CHR: ESP_LOGI(BLE_TAG, "EVENT ID WRITE_CHR,句柄: %d", attr_handle); if (ctxt->om->om_len < sizeof(rw_char_value)){ memcpy(rw_char_value, ctxt->om->om_data, ctxt->om->om_len); ESP_LOGI(BLE_TAG, "接收蓝牙数据帧 [长度: %d]:", ctxt->om->om_len); ble_wv_data_ansy2(rw_char_value, ctxt->om->om_len); } break; case BLE_GATT_ACCESS_OP_WRITE_DSC: /* APP写入CCCD描述符 */ if (ctxt->dsc && ctxt->dsc->uuid) { if (ble_uuid_cmp(ctxt->dsc->uuid, BLE_UUID16_DECLARE(0x2902)) == 0) { if (ctxt->om->om_len == 2) { memcpy(&cccd_value, ctxt->om->om_data, 2); notify_enabled = (cccd_value == 0x0001); ///变量需修改 ESP_LOGI(BLE_TAG, "CCCD写入: 0x%04X, 通知%s", cccd_value, notify_enabled ? "启用" : "禁用"); } } } break; case BLE_GATT_ACCESS_OP_READ_DSC: /* APP读取CCCD描述符 */ if (ctxt->dsc && ctxt->dsc->uuid) { if (ble_uuid_cmp(ctxt->dsc->uuid, BLE_UUID16_DECLARE(0x2902)) == 0) { uint16_t current_cccd = notify_enabled ? 0x0001 : 0x0000; ESP_LOGI(BLE_TAG, "APP读取CCCD,返回: 0x%04X", current_cccd); rc = os_mbuf_append(ctxt->om, ¤t_cccd, sizeof(current_cccd)); } } break; } } else { rc = BLE_ATT_ERR_UNLIKELY; } return rc; } /* 向APP发送通知 */ void send_notification_to_app(const char *message) { if (!is_connected || !notify_enabled) { ESP_LOGI(BLE_TAG, "无法发送通知: 连接=%d, 通知使能=%d", is_connected, notify_enabled); return; } if (notify_char_handle == 0) { ESP_LOGE(BLE_TAG, "通知特征句柄未初始化: %d", notify_char_handle); return; } /* 准备通知数据 */ if (message) { snprintf((char *)notify_char_value, MAX_NOTIFY_LEN, "%s", message); } else { notify_counter++; snprintf((char *)notify_char_value, MAX_NOTIFY_LEN, "Notify #%d: %lld", notify_counter, esp_timer_get_time() / 1000); } int data_len = strlen((char *)notify_char_value); /* 创建消息缓冲区 */ struct os_mbuf *om = ble_hs_mbuf_from_flat(notify_char_value, data_len); if (!om) { ESP_LOGE(BLE_TAG, "无法创建消息缓冲区"); return; } /* 发送通知 */ int rc = ble_gatts_notify_custom(conn_handle, notify_char_handle, om); if (rc != 0) { ESP_LOGE(BLE_TAG, "发送通知失败: %d, 句柄: %d", rc, notify_char_handle); os_mbuf_free_chain(om); } else { ESP_LOGI(BLE_TAG, "发送通知成功: %s (长度: %d)", notify_char_value, data_len); } } /* 发送二进制协议帧 */ void send_protocol_frame(const uint8_t *data, size_t len) { if (!is_connected || !notify_enabled) { ESP_LOGI(BLE_TAG, "无法发送协议帧: 连接=%d, 通知使能=%d", is_connected, notify_enabled); return; } if (notify_char_handle == 0) { ESP_LOGE(BLE_TAG, "通知特征句柄未初始化: %d", notify_char_handle); return; } /* 打印发送的数据帧(十六进制格式) */ ESP_LOGI(BLE_TAG, "发送蓝牙数据帧 [长度: %d]:", len); char hex_str[512] = {0}; // 足够大的缓冲区 int pos = 0; for (size_t i = 0; i < len && pos < sizeof(hex_str) - 4; i++) { pos += snprintf(hex_str + pos, sizeof(hex_str) - pos, "%02X ", data[i]); } ESP_LOGI(BLE_TAG, "%s", hex_str); /* 创建消息缓冲区 */ struct os_mbuf *om = ble_hs_mbuf_from_flat(data, len); if (!om) { ESP_LOGE(BLE_TAG, "无法创建消息缓冲区"); return; } /* 发送通知 */ int rc = ble_gatts_notify_custom(conn_handle, notify_char_handle, om); if (rc != 0) { ESP_LOGE(BLE_TAG, "发送协议帧失败: %d", rc); os_mbuf_free_chain(om); } else { ESP_LOGI(BLE_TAG, "发送协议帧成功"); } } static uint16_t current_conn_handle = BLE_HS_CONN_HANDLE_NONE; /* BLE GAP事件处理 */ static int ble_gap_event(struct ble_gap_event *event, void *arg) { struct ble_gap_conn_desc desc; int rc; switch (event->type) { case BLE_GAP_EVENT_CONNECT: /* 新连接建立 */ ESP_LOGI(BLE_TAG, "连接建立,状态: %d", event->connect.status); if (event->connect.status == 0) { /* 连接成功 */ is_connected = true; conn_handle = event->connect.conn_handle; set_system_event(BLE_CONNECTED_BIT); if (current_conn_handle != BLE_HS_CONN_HANDLE_NONE) { // 已经有连接存在,拒绝新的连接 ESP_LOGW(BLE_TAG, "Only one connection allowed, rejecting new connection."); ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM); return 0; } // 接受此连接 current_conn_handle = conn_handle; /* timer = xTimerCreate("auth_tm", pdMS_TO_TICKS(15000), pdFALSE, (void*)(uintptr_t)conn_handle, auth_timeout_handler); xTimerStart(timer, 0); ESP_LOGW(BLE_TAG, "开始计时10秒认证"); */ notify_enabled = true; // 蓝牙连接成功,不再发送JSON格式的WiFi状态 // WiFi状态将通过协议帧发送 /* 获取连接信息 */ rc = ble_gap_conn_find(event->connect.conn_handle, &desc); if (rc == 0) { ESP_LOGI(BLE_TAG, "连接参数: interval=%d, latency=%d, timeout=%d", desc.conn_itvl, desc.conn_latency, desc.supervision_timeout); } } else { /* 连接失败,重新开始广告 */ ESP_LOGI(BLE_TAG, "连接失败,重新广告"); ble_app_advertise(); } break; case BLE_GAP_EVENT_DISCONNECT: /* 连接断开 */ ESP_LOGI(BLE_TAG, "连接断开,原因: 0x%02x", event->disconnect.reason); current_conn_handle = BLE_HS_CONN_HANDLE_NONE; /* 分析断开原因 */ switch (event->disconnect.reason) { case 0x05: // 认证失败 ESP_LOGE(BLE_TAG, "断开原因: 认证失败"); break; case 0x08: // 超时 ESP_LOGE(BLE_TAG, "断开原因: 连接超时"); break; case 0x13: // 远程用户终止连接 ESP_LOGE(BLE_TAG, "断开原因: 远程设备终止连接"); break; case 0x213: // 安全相关原因 ESP_LOGE(BLE_TAG, "断开原因: 安全失败 (配对/加密失败)"); break; default: ESP_LOGE(BLE_TAG, "断开原因: 0x%02x", event->disconnect.reason); break; } is_connected = false; notify_enabled = false; conn_handle = 0; set_system_event(BLE_DISCONNECTED_BIT); /* 蓝牙断开:若处于任一循环态,统一退出循环并回默认。 */ if (change_task_handle) { const bool is_in_loop_state = is_playing_music || g_is_ktv_playing || lvgl_lottie_calling_active_for_ble() || lvgl_lottie_ai_respond_loop_active_for_ble(); if (is_in_loop_state) { ESP_LOGI(BLE_TAG, "BLE 断开且处于循环态,触发 EXIT_ALL_MODES"); xTaskNotify(change_task_handle, (uint32_t)NOTIFY_EXIT_ALL_MODES, eSetValueWithOverwrite); } } /* 重新开始广告 */ ESP_LOGI(BLE_TAG, "开始广告,设备名: %s", DEVICE_NAME); ble_app_advertise(); break; case BLE_GAP_EVENT_ENC_CHANGE: /* 加密状态变化 */ ESP_LOGI(BLE_TAG, "加密状态变化: 状态=%d", event->enc_change.status); if (event->enc_change.status == 0) { ESP_LOGI(BLE_TAG, "加密已启用"); } else { ESP_LOGE(BLE_TAG, "加密失败"); } break; case BLE_GAP_EVENT_PASSKEY_ACTION: /* 密码请求 */ ESP_LOGI(BLE_TAG, "密码请求: 操作=%d", event->passkey.params.action); break; case BLE_GAP_EVENT_ADV_COMPLETE: ESP_LOGI(BLE_TAG, "广告完成"); /* 如果没有连接,重新开始广告 */ if (!is_connected) { ble_app_advertise(); } break; case BLE_GAP_EVENT_SUBSCRIBE: /* CCCD订阅状态变化 */ ESP_LOGI(BLE_TAG, "GAP订阅事件: conn=%d, attr_handle=%d, cur_notify=%d, cur_indicate=%d", event->subscribe.conn_handle, event->subscribe.attr_handle, event->subscribe.cur_notify, event->subscribe.cur_indicate); // 可以在这里也更新通知状态,与CCCD写入同步 if (event->subscribe.attr_handle == notify_char_handle) { // CCCD句柄通常是特征值句柄+1 notify_enabled = (event->subscribe.cur_notify || event->subscribe.cur_indicate); ESP_LOGI(BLE_TAG, "通知状态已更新: %s", notify_enabled ? "启用" : "禁用"); } break; case BLE_GAP_EVENT_MTU: /* MTU更新 */ ESP_LOGI(BLE_TAG, "MTU更新: conn_handle=%d, mtu=%d", event->mtu.conn_handle, event->mtu.value); break; case BLE_GAP_EVENT_CONN_UPDATE: /* 连接参数更新 */ ESP_LOGI(BLE_TAG, "连接参数更新: status=%d", event->conn_update.status); break; } return 0; } /* 开始广播吧 */ void ble_app_advertise(void) { struct ble_gap_adv_params adv_params; struct ble_hs_adv_fields fields; uint8_t own_addr_type; int rc; /* 设置广告数据 */ memset(&fields, 0, sizeof(fields)); fields.name = (uint8_t *)DEVICE_NAME; fields.name_len = strlen(DEVICE_NAME); fields.name_is_complete = 1; fields.flags = BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP; //fields.uuids16 = (ble_uuid16_t *)BLE_UUID16_DECLARE(BLE_SERVICE_UUID); //fields.num_uuids16 = 1; //fields.uuids16_is_complete = 1; fields.uuids128 = (ble_uuid128_t *)BLE_UUID128_DECLARE(0x5d, 0xf7, 0x9f, 0x6a, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb); fields.num_uuids128 = 1; // 1 个 128 位 UUID fields.uuids128_is_complete = 1; // 完整的列表 rc = ble_gap_adv_set_fields(&fields); if (rc != 0) { ESP_LOGE(BLE_TAG, "设置广告数据失败: %d", rc); return; } memset(&fields, 0, sizeof(fields)); fields.tx_pwr_lvl_is_present = 1; fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO; rc = ble_gap_adv_rsp_set_fields(&fields); if (rc != 0) { ESP_LOGE(BLE_TAG, "设置扫描响应失败: %d", rc); return; } rc = ble_hs_id_infer_auto(0, &own_addr_type); if (rc != 0) { ESP_LOGE(BLE_TAG, "获取设备地址失败: %d", rc); return; } memset(&adv_params, 0, sizeof(adv_params)); adv_params.conn_mode = BLE_GAP_CONN_MODE_UND; adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN; adv_params.itvl_min = BLE_GAP_ADV_FAST_INTERVAL1_MIN; adv_params.itvl_max = BLE_GAP_ADV_FAST_INTERVAL1_MAX; adv_params.channel_map = 0x07; rc = ble_gap_adv_start(own_addr_type, NULL, BLE_HS_FOREVER, &adv_params, ble_gap_event, NULL); if (rc != 0) { ESP_LOGE(BLE_TAG, "开始广告失败: %d", rc); return; } ESP_LOGI(BLE_TAG, "开始广告,设备名: %s", DEVICE_NAME); } /** * 整机初始化完成后由 main 调用:从非 NimBLE host 线程安全地启动广播。 * GAP 回调里请直接调用 ble_app_advertise()(勿用本函数,避免重复持锁)。 */ void ble_app_advertise_after_system_init(void) { ble_hs_lock(); ble_app_advertise(); ble_hs_unlock(); } /* NimBLE主机任务 */ static void nimble_host_task(void *param) { ESP_LOGI(BLE_TAG, "NimBLE主机任务启动"); nimble_port_run(); nimble_port_freertos_deinit(); } /* 重置事件回调 */ static void ble_app_on_reset(int reason) { ESP_LOGE(BLE_TAG, "BLE重置,原因: %d", reason); } /* 同步事件回调 */ static void ble_app_on_sync(void) { ESP_LOGI(BLE_TAG, "BLE同步完成"); /* 设置设备地址(可选) */ uint8_t addr_type; ble_hs_id_infer_auto(0, &addr_type); /* 设置设备名称 */ ble_svc_gap_device_name_set(DEVICE_NAME); /* 注册GATT服务 */ int rc = ble_gatts_count_cfg(gatt_svr_svcs); if (rc != 0) { ESP_LOGE(BLE_TAG, "GATT服务计数失败: %d", rc); return; } // rc = ble_gatts_add_svcs(gatt_svr_svcs); if (rc != 0) { ESP_LOGE(BLE_TAG, "添加GATT服务失败: %d", rc); return; } /* 初始化阶段不广播,避免整机未就绪时被连接;首次广播见 ble_app_advertise_after_system_init() */ ESP_LOGI(BLE_TAG, "BLE 已就绪,等待整机初始化完成后再开始可连接广播"); } /* NimBLE主机配置 */ static void nimble_host_config(void) { /* 设置回调 */ ble_hs_cfg.reset_cb = ble_app_on_reset; ble_hs_cfg.sync_cb = ble_app_on_sync; /* 配置安全参数 */ ble_hs_cfg.sm_bonding = 0; // 是否支持配对绑定(0=不绑定,1=绑定,断电后记住配对信息) ble_hs_cfg.sm_mitm = 0; // 是否要求MITM保护(中间人攻击保护,0=不要求,1=要求) ble_hs_cfg.sm_sc = 0; // 是否要求安全连接(Secure Connections,0=不要求,1=要求) ble_hs_cfg.sm_our_key_dist = BLE_SM_PAIR_KEY_DIST_ENC; // 我方分发哪些密钥(ENC=加密密钥) ble_hs_cfg.sm_their_key_dist = BLE_SM_PAIR_KEY_DIST_ENC; // 对方分发哪些密钥(ENC=加密密钥) } static void nimble_host_config_init(void) { /* Set host callbacks */ ble_hs_cfg.reset_cb = ble_app_on_reset; ble_hs_cfg.sync_cb = ble_app_on_sync; ble_hs_cfg.sm_bonding = 0; // 是否支持配对绑定(0=不绑定,1=绑定,断电后记住配对信息) ble_hs_cfg.sm_mitm = 0; // 是否要求MITM保护(中间人攻击保护,0=不要求,1=要求) ble_hs_cfg.sm_sc = 0; // 是否要求安全连接(Secure Connections,0=不要求,1=要求) ble_hs_cfg.sm_our_key_dist = BLE_SM_PAIR_KEY_DIST_ENC; // 我方分发哪些密钥(ENC=加密密钥) ble_hs_cfg.sm_their_key_dist = BLE_SM_PAIR_KEY_DIST_ENC; // 对方分发哪些密钥(ENC=加密密钥) } /* 通知任务 - 定期向APP发送通知 */ /* 打印堆内存信息 */ static void print_heap_info(void) { printf(" Heap info:\n"); printf(" Free heap: %" PRIu32 " bytes\n", (uint32_t)esp_get_free_heap_size()); printf(" Min free heap: %" PRIu32 " bytes\n", (uint32_t)esp_get_minimum_free_heap_size()); multi_heap_info_t info; heap_caps_get_info(&info, MALLOC_CAP_DEFAULT); printf(" Total free: %d bytes\n", info.total_free_bytes); printf(" Largest free block: %d bytes\n", info.largest_free_block); printf(" Minimum free ever: %d bytes\n", info.minimum_free_bytes); printf(" Allocated blocks: %d\n", info.allocated_blocks); printf(" Free blocks: %d\n", info.free_blocks); printf(" Total blocks: %d\n", info.total_blocks); } /* 主应用程序入口 */ void ble_main(void) { int rc; /* 初始化NVS */ esp_err_t 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); /* 加载表情包存储数据 */ ret = emoji_storage_load(); if (ret != ESP_OK) { ESP_LOGW(BLE_TAG, "加载表情包存储数据失败: %s", esp_err_to_name(ret)); } // 首先释放经典蓝牙内存 // ret = esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT); if (ret != ESP_OK) { ESP_LOGW(BLE_TAG, "Failed to release classic BT memory: %s", esp_err_to_name(ret)); } // 打印内存信息 ESP_LOGI(BLE_TAG, "Before BT controller init:"); // print_heap_info(); // /* 初始化NimBLE协议栈 */ // /* 启动NimBLE主机任务 */ rc = nimble_port_init(); if (rc != 0) { ESP_LOGE(BLE_TAG, "NimBLE任务初始化失败: %d", rc); return; } ble_svc_gap_init(); rc =ble_svc_gap_device_name_set(DEVICE_NAME); if (rc != 0) { ESP_LOGE(BLE_TAG, "设置设备名称失败: %d", rc); return; } /* 注册GATT服务 */ ble_svc_gatt_init(); rc = ble_gatts_count_cfg(gatt_svr_svcs); if (rc != 0) { ESP_LOGE(BLE_TAG, "GATT服务计数失败: %d", rc); return; } rc = ble_gatts_add_svcs(gatt_svr_svcs); if (rc != 0) { ESP_LOGE(BLE_TAG, "添加GATT服务失败: %d", rc); return; } /* 配置NimBLE主机 */ //nimble_host_config(); nimble_host_config_init(); nimble_port_freertos_init(nimble_host_task); /* 创建通知任务 */ xTaskCreate(notification_task, "notification_task", 4096, NULL, 5, ¬ification_task_handle); //xTaskCreate(sentinel_task, "sentinel_task", 4096, NULL, 5, &sentinel_task_handle); // 哨兵模式(已禁用) //ble_app_advertise(); //ESP_LOGI(BLE_TAG, "notification_task_handle %p", notification_task_handle); //ESP_LOGI(BLE_TAG, "entinel_task_handle %p", sentinel_task_handle); //ESP_LOGI(BLE_TAG, "设备名称: %s", DEVICE_NAME); //ESP_LOGI(BLE_TAG, "等待手机APP连接..."); } bool ble_is_connected(void) { return is_connected; } #if 1 /* 哨兵任务已禁用 */ void sentinel_task(void *arg) { (void)arg; uint32_t bits = 0; // 通知位 // 状态标志 bool listen_mode = false; // 监听脉冲模式 bool manual_mode = false; // 手动直接进入哨兵模式 bool was_active = false; // 记录上一轮激活状态,用于只在状态切换时触发一次 uint8_t motor_state = 0; // 0为初始状态 默认不动 1-- 0——L180 2 180 // 计时相关变量 TickType_t last_pulse_tick = xTaskGetTickCount(); // 上一次收到脉冲的时间点 TickType_t sentinel_active_tick = 0; // 进入哨兵模式的时间点 const TickType_t pulse_timeout_ticks = pdMS_TO_TICKS(SENTINEL_PULSE_TIMEOUT_MS); // 3 秒未收到脉冲自动进入 const TickType_t sentinel_duration_ticks = pdMS_TO_TICKS(SENTINEL_TOTAL_DURATION_MS); // 20 分钟自动退出 ESP_LOGI(BLE_TAG, "哨兵任务已启动"); while (1) { // 1. 等待通知;最多阻塞 100ms,避免任务空转 BaseType_t res = xTaskNotifyWait(0, ULONG_MAX, &bits, pdMS_TO_TICKS(100)); // 获取当前时间 TickType_t now_tick = xTaskGetTickCount(); // 2. 处理收到的指令 if (res == pdTRUE) { // --- 强制开启 --- if (bits & SENTINEL_TURN_ON) { manual_mode = true; // 手动直接进入哨兵模式 listen_mode = false; // 脉冲监听模式关闭 ESP_LOGI(BLE_TAG, "哨兵模式: 手动开启"); } // --- 强制关闭 --- if (bits & SENTINEL_TURN_OFF) { manual_mode = false; // 手动操作关闭 listen_mode = false; // 监听脉冲功能也关闭 ESP_LOGI(BLE_TAG, "哨兵模式: 手动关闭"); } // --- 收到脉冲 --- if (bits & SENTINEL_LISTEN_START_PULSE) { // 更新最后脉冲时间,并进入监听模式 last_pulse_tick = now_tick; if (!listen_mode) { ESP_LOGI(BLE_TAG, "哨兵模式: 激活监听脉冲模式"); } listen_mode = true; manual_mode = false; } // --- 停止监听 --- if (bits & SENTINEL_LISTEN_STOP_PULSE) { manual_mode = false; // 停止监听的时候关闭哨兵模式 listen_mode = false; ESP_LOGI(BLE_TAG, "哨兵模式: 停止监听"); } } // 3. 监听状态下,3 秒没有收到脉冲,自动进入哨兵模式 if (listen_mode && !manual_mode && (now_tick - last_pulse_tick >= pulse_timeout_ticks)) { manual_mode = true; listen_mode = false; ESP_LOGW(BLE_TAG, "哨兵模式: 3s 未收到脉冲,自动进入哨兵模式"); } // 综合状态 sentinel_mode_is_active = manual_mode; // 当前哨兵模式已激活 // 5. 哨兵模式运行 20 分钟后自动退出 if (sentinel_mode_is_active && (sentinel_active_tick != 0) && (now_tick - sentinel_active_tick >= sentinel_duration_ticks)) { manual_mode = false; listen_mode = false; sentinel_mode_is_active = false; ESP_LOGI(BLE_TAG, "哨兵模式: 运行 20min 到时,自动退出"); } // 6. 执行逻辑 (动画 + 电机) // 仅在 false -> true 的状态切换时,通知一次 change_task 和 motor_control_task if (sentinel_mode_is_active ) { is_not_sentinel_mode = false; sentinel_active_tick = now_tick; if(!was_active) { if (change_task_handle) { xTaskNotify(change_task_handle, emoji_event_sentinel_guard, eSetValueWithOverwrite); } ESP_LOGI(BLE_TAG, "哨兵模式: 进入激活态,通知播放 guard_emojo"); } if(xSemaphoreTake(motor_action_down_sem,pdMS_TO_TICKS(100)))// { switch (motor_state) { case 0 :motor_state = 1; case 1: { if (motor_control_handle) (void)motor_post_cmd(0x07u); motor_state = 2; }break; case 2: { if (motor_control_handle) (void)motor_post_cmd(0x0Au); motor_state = 3; }break; case 3: { if (motor_control_handle) (void)motor_post_cmd(0x08u); motor_state = 4; }break; case 4: { if (motor_control_handle) (void)motor_post_cmd(0x0Au); motor_state = 1; }break; } } // if (motor_control_handle) // { // xTaskNotify(motor_control_handle, (uint32_t)MOTOR_CMD_SENTINEL_START, eSetValueWithOverwrite); // } } // 7. 非激活状态 (退出处理):只在 true -> false 时执行一次 else if (!sentinel_mode_is_active && was_active) { is_not_sentinel_mode = true; sentinel_active_tick = 0; motor_state = 0; if (motor_control_handle) { (void)motor_post_cmd(0x0Au); } ESP_LOGI(BLE_TAG, "哨兵模式结束,电机回正"); back2default = true; // 切回默认表情 } was_active = sentinel_mode_is_active; } } #endif /* 哨兵任务已禁用 */ static void auth_timeout_handler(TimerHandle_t xTimer) { uint16_t conn_handle = (uint16_t)(uintptr_t)pvTimerGetTimerID(xTimer); if (is_auth==false && current_conn_handle != BLE_HS_CONN_HANDLE_NONE) { ESP_LOGW(BLE_TAG, "Auth timeout, 踢出蓝牙配对和连接..."); ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM); } // 清理定时器资源 timer = NULL; } #define AES_KEY_SIZE 16 #define HMAC_KEY_SIZE 9 static const uint8_t DEFAULT_AES_KEY[AES_KEY_SIZE] = "SharedKey1234567"; static const uint8_t DEFAULT_HMAC_KEY[HMAC_KEY_SIZE] = "SharedKey"; uint8_t uuid_bytes[16] ={ 0xa4,0x1b,0x78,0x58,0xa4,0x1b,0x00,0x01,0x6b,0x00,0x59,0xe9,0xf0,0xdc,0xed,0xad } ; /* {0xfa, 0x53, 0xb9, 0x1c, 0x9f, 0x6a, 0x00, 0x01, 0x6b, 0x00, 0x2c, 0x1f, 0x42, 0x74, 0xbd, 0x08} */ #include "mbedtls/aes.h" #include "esp_random.h" #include #include "mbedtls/md.h" #define AES_KEY_SIZE 16 // AES-128 密钥长度,16字节[reference:23][reference:24] #define AES_BLOCK_SIZE 16 // AES块大小,16字节[reference:25] #define HMAC_KEY_SIZE 9 // HMAC 密钥长度(与 Kotlin 端保持一致) #define HMAC_OUTPUT_SIZE 32 // SHA-256 输出固定 32 字节 uint8_t encrypted_output[64] = {0}; // PKCS#7 填充函数[reference:26][reference:27] // 输入: input - 待填充数据, input_len - 数据长度 // 输出: output - 填充后数据(需保证有足够空间), output_len - 填充后长度 void pkcs7_pad(const uint8_t *input, size_t input_len, uint8_t *output, size_t *output_len) { size_t pad_len = AES_BLOCK_SIZE - (input_len % AES_BLOCK_SIZE); memcpy(output, input, input_len); memset(output + input_len, pad_len, pad_len); *output_len = input_len + pad_len; } /** * AES-CBC 加密函数 (对应Kotlin的 encryptAES) * * @param data 要加密的明文数据 * @param data_len 明文数据长度 (字节) * @param key 16字节的AES密钥 * @param out 输出缓冲区 (需调用者分配) * @param out_len 输出长度 (IV 16字节 + 密文长度) * @return 0 成功, -1 失败 */ int encrypt_aes_cbc(const uint8_t *data, size_t data_len, const uint8_t key[AES_KEY_SIZE], uint8_t *out, size_t *out_len) { mbedtls_aes_context aes_ctx; uint8_t iv[AES_BLOCK_SIZE]={ 0x4f,0x58,0x50,0x53,0x7f, 0x6e ,0x42 ,0xfa ,0x3a ,0xea ,0x24 ,0x67 ,0xdf ,0xae ,0x46 ,0xab }; uint8_t padded_data[data_len + AES_BLOCK_SIZE]; // 预留填充空间 size_t padded_len; int ret = -1; // 1. 生成随机 IV (对应 Kotlin 的 SecureRandom().nextBytes(iv))[reference:28] //esp_fill_random(iv, AES_BLOCK_SIZE); ESP_LOG_BUFFER_HEX("IV随机数生成成功", iv, sizeof(iv)); // 2. PKCS#7 填充数据 (对应 Kotlin 的 Cipher 自动填充)[reference:29] pkcs7_pad(data, data_len, padded_data, &padded_len); ESP_LOG_BUFFER_HEX("DATA填充成功", padded_data, sizeof(padded_data)); // 3. 初始化 mbedTLS AES 上下文[reference:30][reference:31] mbedtls_aes_init(&aes_ctx); // 4. 设置加密密钥 (对应 Kotlin 的 SecretKeySpec)[reference:32][reference:33] if (mbedtls_aes_setkey_enc(&aes_ctx, key, AES_KEY_SIZE * 8) != 0) { goto cleanup; } memcpy(out, iv, AES_BLOCK_SIZE); // 5. 执行 CBC 模式加密 (对应 Kotlin 的 cipher.doFinal(data))[reference:34][reference:35] if (mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_ENCRYPT, padded_len, iv, padded_data, out + AES_BLOCK_SIZE) != 0) { goto cleanup; } // 6. 将 IV 复制到输出缓冲区最前面 (对应 Kotlin 的 return iv + encrypted)[reference:36] *out_len = AES_BLOCK_SIZE + padded_len; // 总长度 = IV + 密文 ESP_LOG_BUFFER_HEX("AFTER_COPY", out, *out_len); ret = 0; // 成功 cleanup: mbedtls_aes_free(&aes_ctx); // 释放上下文[reference:37] return ret; } void test_encryption() { // 1. 准备明文数据(模拟你的 seed,假设是 16 字节) uint8_t random_seed[16]; memset(random_seed, 0, sizeof(random_seed)); //循环填充(每次取4字节) for (int i = 0; i < 4; i++) { uint32_t rnd = esp_random(); memcpy(random_seed + i * 4, &rnd, 4); } size_t random_seed_len = sizeof(random_seed); ESP_LOG_BUFFER_HEX("AES随机数生成成功", random_seed, sizeof(random_seed)); // 2. 准备输出缓冲区(要足够大) size_t output_len = 0; // 3. 调用加密函数 int ret = encrypt_aes_cbc(random_seed, random_seed_len, DEFAULT_AES_KEY, encrypted_output, &output_len); if (ret == 0) { ESP_LOGI("AES", "加密成功!输出长度: %d 字节", output_len); // 此时 encrypted_output 前16字节是IV,后面是密文 // 你可以在这里继续调用 HMAC 函数进行签名 } else { ESP_LOGE("AES", "加密失败!"); } } /** * 计算 HMAC-SHA256(对应 Kotlin 的 generateHmac) * * @param encrypted_data AES 加密后的数据(IV + 密文) * @param encrypted_len encrypted_data 的长度 * @param uuid_bytes UUID 的 16 字节原始二进制 * @param key HMAC 密钥 * @param key_len 密钥长度 * @param output 输出缓冲区(至少 32 字节) * @return 0 成功,-1 失败 */ int generate_hmac(const uint8_t *encrypted_data, size_t encrypted_len, const uint8_t *uuid_bytes, const uint8_t *key, size_t key_len, uint8_t *output) { mbedtls_md_context_t ctx; const mbedtls_md_info_t *md_info; int ret = -1; // 1. 拼接数据到临时缓冲区 size_t total_len = encrypted_len + 16; // uuid_bytes 固定16字节 uint8_t *input_buffer = malloc(total_len); if (!input_buffer) { return -1; // 内存分配失败 } memcpy(input_buffer, encrypted_data, encrypted_len); memcpy(input_buffer + encrypted_len, uuid_bytes, 16); // 可选:打印拼接后的数据,方便调试 ESP_LOG_BUFFER_HEX("HMAC_INPUT", input_buffer, total_len); // 2. 初始化 HMAC 上下文 mbedtls_md_init(&ctx); md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); if (md_info == NULL) { goto cleanup; } if (mbedtls_md_setup(&ctx, md_info, 1) != 0) { goto cleanup; } if (mbedtls_md_hmac_starts(&ctx, key, key_len) != 0) { goto cleanup; } // 3. 一次性写入拼接后的数据 if (mbedtls_md_hmac_update(&ctx, input_buffer, total_len) != 0) { goto cleanup; } // 4. 完成计算 if (mbedtls_md_hmac_finish(&ctx, output) != 0) { goto cleanup; } ret = 0; cleanup: mbedtls_md_free(&ctx); free(input_buffer); // 释放临时缓冲区 return ret; } void test_hmac() { // 假设已经有加密数据(IV + 密文) size_t encrypted_len = 48; // UUID 16 字节原始数据 uint8_t hmac_output[32] = {0}; // 计算 HMAC int ret = generate_hmac(encrypted_output, encrypted_len, uuid_bytes, DEFAULT_HMAC_KEY, sizeof(DEFAULT_HMAC_KEY), hmac_output); if (ret == 0) { ESP_LOGI("HMAC", "HMAC 计算成功"); ESP_LOG_BUFFER_HEX("HMAC", hmac_output, 32); // 截取前 16 字节作为签名(对应 AuthPacket.signature) uint8_t signature[16]; memcpy(signature, hmac_output, 16); ESP_LOG_BUFFER_HEX("SIGN", signature, 16); } else { ESP_LOGE("HMAC", "HMAC 计算失败"); } } /** * PKCS#7 去填充 * @param data 解密后的数据(带填充) * @param data_len 数据长度(必须是16的倍数) * @param out_len 输出去掉填充后的实际长度 * @return 0 成功,-1 填充无效 */ int pkcs7_unpad(const uint8_t *data, size_t data_len, size_t *out_len) { if (data_len == 0 || data_len % AES_BLOCK_SIZE != 0) { return -1; } uint8_t pad_len = data[data_len - 1]; if (pad_len == 0 || pad_len > AES_BLOCK_SIZE) { return -1; } // 检查所有填充字节是否都等于 pad_len for (size_t i = data_len - pad_len; i < data_len; i++) { if (data[i] != pad_len) { return -1; } } *out_len = data_len - pad_len; return 0; } /** * AES-CBC 解密(对应 Kotlin 的 decryptAES) * * @param encrypted_with_iv 输入数据:IV(16字节) + 密文 * @param enc_len 输入数据总长度 * @param key 16字节AES密钥 * @param out 输出缓冲区(存放解密后的明文) * @param out_len 输出明文长度(去除填充后) * @return 0 成功,-1 失败 */ int decrypt_aes_cbc(const uint8_t *encrypted_with_iv, size_t enc_len, const uint8_t key[AES_KEY_SIZE], uint8_t *out, size_t *out_len) { mbedtls_aes_context aes_ctx; int ret = -1; // 1. 检查输入长度:至少 IV(16) + 一个密文块(16) if (enc_len < AES_BLOCK_SIZE + AES_BLOCK_SIZE) { return -1; } // 密文长度应为16的倍数 size_t ciphertext_len = enc_len - AES_BLOCK_SIZE; if (ciphertext_len % AES_BLOCK_SIZE != 0) { return -1; } // 2. 提取 IV 和密文 const uint8_t *iv = encrypted_with_iv; const uint8_t *ciphertext = encrypted_with_iv + AES_BLOCK_SIZE; // 3. 准备临时IV(mbedtls 会修改传入的IV,所以需要拷贝) uint8_t iv_copy[AES_BLOCK_SIZE]; memcpy(iv_copy, iv, AES_BLOCK_SIZE); // 4. 初始化 mbedTLS AES 上下文 mbedtls_aes_init(&aes_ctx); // 5. 设置解密密钥 if (mbedtls_aes_setkey_dec(&aes_ctx, key, AES_KEY_SIZE * 8) != 0) { goto cleanup; } // 6. CBC 解密(输出直接放在 out 中,长度与密文相同) if (mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_DECRYPT, ciphertext_len, iv_copy, ciphertext, out) != 0) { goto cleanup; } // 7. 去除 PKCS#7 填充 if (pkcs7_unpad(out, ciphertext_len, out_len) != 0) { goto cleanup; } ret = 0; // 成功 cleanup: mbedtls_aes_free(&aes_ctx); return ret; } void test_decrypt(void); void test_decrypt(void) { // 假设你已经有一个从蓝牙收到的数据包(IV + 密文) // 这里模拟从加密函数得到的数据 uint8_t random_seed[16]={ 0x0e, 0xd7, 0x10, 0x64, 0x26, 0xcd, 0x0b, 0x31, 0x7d, 0x01, 0xc2, 0x76, 0x57, 0x76, 0x48, 0xbd }; /* memset(random_seed, 0, sizeof(random_seed)); //循环填充(每次取4字节) for (int i = 0; i < 4; i++) { uint32_t rnd = esp_random(); memcpy(random_seed + i * 4, &rnd, 4); } size_t random_seed_len = sizeof(random_seed); ESP_LOG_BUFFER_HEX("AES随机数生成成功", random_seed, sizeof(random_seed)); */ size_t encrypted_len = 0; // 先加密(得到 IV + 密文) if (encrypt_aes_cbc(random_seed, sizeof(random_seed), DEFAULT_AES_KEY, encrypted_output, &encrypted_len) != 0) { ESP_LOGE("DECRYPT", "加密失败"); return; } ESP_LOGI("DECRYPT", "加密成功,总长度: %d 字节", encrypted_len); ESP_LOG_BUFFER_HEX("iv+密文", encrypted_output, sizeof(encrypted_output)); //模拟HMAC签名 uint8_t hmac_full[32] = {0}; int ret = generate_hmac(encrypted_output, encrypted_len, uuid_bytes, DEFAULT_HMAC_KEY, sizeof(DEFAULT_HMAC_KEY), hmac_full); if (ret == 0) { ESP_LOGI("HMAC", "HMAC 计算成功,完整 32 字节:"); ESP_LOG_BUFFER_HEX("HMAC_FULL", hmac_full, 32); // 3. 截取前 16 字节作为签名(与 AuthPacket 一致) uint8_t signature[16]; memcpy(signature, hmac_full, 16); ESP_LOGI("HMAC", "截断签名(前16字节):"); ESP_LOG_BUFFER_HEX("SIGNATURE", signature, 16); } else { ESP_LOGE("HMAC", "HMAC 计算失败,跳过验证"); return; } // 现在模拟解密(用同一个密钥) uint8_t decrypted[64] = {0}; size_t decrypted_len = 0; if (decrypt_aes_cbc(encrypted_output, encrypted_len, DEFAULT_AES_KEY, decrypted, &decrypted_len) != 0) { ESP_LOGE("DECRYPT", "解密失败"); return; } ESP_LOGI("DECRYPT", "解密成功,明文长度: %d 字节", decrypted_len); ESP_LOG_BUFFER_HEX("解密数据", decrypted, decrypted_len); // 验证是否与原始明文相同 if (decrypted_len == sizeof(random_seed) && memcmp(decrypted, random_seed, decrypted_len) == 0) { ESP_LOGI("DECRYPT", "✅ 加解密验证通过!"); } else { ESP_LOGE("DECRYPT", "❌ 加解密验证失败!"); } } #include #include #include #define SIGNATURE_SIZE 16 // 1. 数据结构定义 typedef struct { uint8_t signature[SIGNATURE_SIZE]; // HMAC 签名(前16字节) uint8_t *encrypted_data; // 指向加密数据的指针 size_t encrypted_len; // 加密数据的长度 } auth_packet_t; // 2. 打包函数(对应 toPayload) // 将结构体转换为连续的字节数组:signature + encrypted_data void auth_packet_pack(const auth_packet_t *packet, uint8_t *out, size_t *out_len) { *out_len = SIGNATURE_SIZE + packet->encrypted_len; memcpy(out, packet->signature, SIGNATURE_SIZE); memcpy(out + SIGNATURE_SIZE, packet->encrypted_data, packet->encrypted_len); } // 3. 拆包函数(对应 fromPayload)——零拷贝版本,encrypted_data 直接指向 payload 内部 bool auth_packet_unpack(const uint8_t *payload, size_t payload_len, auth_packet_t *packet) { // 最小长度检查:签名(16) + IV(16) + 最小密文块(16) = 48 if (payload_len < SIGNATURE_SIZE + 16 + 16) { return false; } memcpy(packet->signature, payload, SIGNATURE_SIZE); packet->encrypted_data = (uint8_t*)(payload + SIGNATURE_SIZE); // 指向 payload 内部(零拷贝) packet->encrypted_len = payload_len - SIGNATURE_SIZE; return true; } // 4. 比较函数(对应 equals)——检查两个包的内容是否完全一致 bool auth_packet_equals(const auth_packet_t *a, const auth_packet_t *b) { if (a->encrypted_len != b->encrypted_len) return false; if (memcmp(a->signature, b->signature, SIGNATURE_SIZE) != 0) return false; if (memcmp(a->encrypted_data, b->encrypted_data, a->encrypted_len) != 0) return false; return true; } void ble_wv_data_ansy(uint8_t *input, size_t length){ if(length==64){ ESP_LOGI(BLE_TAG, "开始加解密"); //uint8_t notify_data[10]="ABCDEFGHJ"; //send_protocol_frame(notify_data, 10); auth_packet_t receive_data={0}; auth_packet_unpack(input,length,&receive_data); uint8_t output[64] = {0}; size_t output_len = 0; decrypt_aes_cbc(receive_data.encrypted_data,receive_data.encrypted_len,DEFAULT_AES_KEY,output,&output_len); uint8_t hmac_full[32] = {0}; int ret = generate_hmac(receive_data.encrypted_data,receive_data.encrypted_len, uuid_bytes, DEFAULT_HMAC_KEY, sizeof(DEFAULT_HMAC_KEY), hmac_full); uint8_t signature[16]; if (ret == 0) { ESP_LOGI("HMAC", "HMAC 计算成功,完整 32 字节:"); ESP_LOG_BUFFER_HEX("HMAC_FULL", hmac_full, 32); // 3. 截取前 16 字节作为签名(与 AuthPacket 一致) memcpy(signature, hmac_full, 16); ESP_LOGI("HMAC", "截断签名(前16字节):"); ESP_LOG_BUFFER_HEX("SIGNATURE", signature, 16); } uint8_t send_data[64] = {0}; memcpy(send_data, signature, SIGNATURE_SIZE); memcpy(send_data + SIGNATURE_SIZE, receive_data.encrypted_data, receive_data.encrypted_len); send_protocol_frame(send_data, 64); if (timer != NULL) { xTimerStop(timer, 0); xTimerDelete(timer, 0); timer = NULL; ESP_LOGI(BLE_TAG, "删除定时器"); } } }