纳入固件源码、屏幕组件、nand_xfer 工具和文档。忽略本机构建产物、sdkconfig,以及含本机路径的依赖锁。 Co-authored-by: Cursor <cursoragent@cursor.com>
1569 lines
56 KiB
C
1569 lines
56 KiB
C
#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 = ¬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 <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, "删除定时器");
|
||
}
|
||
}
|
||
}
|
||
|
||
|