Files
P4-USB-transfer/main/BLE/ble.c
T
zhengxinandCursor 851e347cf5 初始提交卡包 USB 工程
纳入固件源码、屏幕组件、nand_xfer 工具和文档。忽略本机构建产物、sdkconfig,以及含本机路径的依赖锁。

Co-authored-by: Cursor <[email protected]>
2026-10-13 21:54:50 +08:00

1569 lines
56 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>
#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 = &notify_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, &current_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, &current_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, &current_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, &current_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, &current_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, &notification_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 <string.h>
#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 <stdint.h>
#include <string.h>
#include <stdbool.h>
#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, "删除定时器");
}
}
}