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

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-13 21:54:50 +08:00

588 lines
18 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 "ble_send.h"
#include "ble.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "config.h"
#include "esp_log.h"
#include "ALGORITHM/crc.h"
#include "EMOJI_STORAGE/emoji_storage.h"
#include "event.h"
/* 统一亮度真源(定义在 main.c) */
extern int get_system_brightness_percent(void);
volatile uint8_t s_ota_progress_to_send = 0;
volatile bool g_emoji_upgrade_pending_finalize = false;
volatile char g_emoji_upgrade_downloaded_pack = '0';
volatile char g_emoji_upgrade_last_switch_target = '0';
static uint8_t s_wifi_state_to_send = 0;
bool g_wifi_state = 0;
static uint8_t s_ota_result_to_send = 0;
static char s_emoji_switch_target_pack = '0';
volatile uint8_t g_brightness = 85;
void notification_task(void *arg)//上报任务
{
ESP_LOGI(BLE_TAG, "通知任务启动");
uint32_t bits = 0;
BaseType_t rec;
while (1)
{
rec = xTaskNotifyWait(0, ULONG_MAX, &bits, portMAX_DELAY);//永久等待通知
ESP_LOGI("NOTIFICATION", "recv notify");
if (rec != pdPASS)
{
ESP_LOGE("NOTIFICATION", "接受任务通知失败");
continue;
}
if (bits & BLE_SEND_PROGRESS)//BLE 发送OTA 升级进度
{
ESP_LOGI("NOTIFICATION", "recv BLE_SEND_PROGRESS, 发送OTA进度(十进制)=%d%%", (int)s_ota_progress_to_send);
notify_enabled = 1;
send_ota_progress_frame(s_ota_progress_to_send);
}
else if (bits & BLE_SEND_OTA_RESULT)//返回OTA 升级结果
{
ESP_LOGI("NOTIFICATION", "recv BLE_SEND_OTA_RESULT, 发送OTA结果 %s", s_ota_result_to_send ? "成功" : "失败");
notify_enabled = 1;
send_ota_result_frame(s_ota_result_to_send);
}
else if (bits & BLE_SEND_VERSION) // 收到 get_system_info (0x0010) 请求后发送版本号、亮度和系统状态
{
ESP_LOGI("NOTIFICATION", "recv BLE_SEND_VERSION (get_system_info 请求)");
int current_brightness_percent = get_system_brightness_percent();
if (current_brightness_percent < 0)
current_brightness_percent = 0;
if (current_brightness_percent > 100)
current_brightness_percent = 100;
g_brightness = (uint8_t)current_brightness_percent; /* 保持兼容镜像 */
notify_enabled = 1;
// 发送3个协议反馈帧
// feedback2.1A: get_system_ok
send_get_system_ok_frame();
vTaskDelay(pdMS_TO_TICKS(10)); // 短暂延时,避免发送过快
// feedback2.2A: brightness
send_brightness_frame((uint8_t)current_brightness_percent);
vTaskDelay(pdMS_TO_TICKS(10));
// feedback2.3A: version
send_version_frame(DEVICE_FIRMWARE_VERSION);
vTaskDelay(pdMS_TO_TICKS(10));
// 1.10_A: 返回当前 WiFi 状态(配网成功为 0x01,未连为 0x00)
send_wifi_state_frame(s_wifi_state_to_send);
ESP_LOGI(BLE_TAG, "已发送get_system_info反馈: version=%s, 亮度=%u, WiFi状态=%s", DEVICE_FIRMWARE_VERSION, (unsigned int)g_brightness, s_wifi_state_to_send ? "已连接" : "断开");
}
else if (bits & BLE_SEND_BRIGHTNESS)
{
ESP_LOGI("NOTIFICATION", "recv BLE_SEND_BRIGHTNESS");
int current_brightness_percent = get_system_brightness_percent();
if (current_brightness_percent < 0)
current_brightness_percent = 0;
if (current_brightness_percent > 100)
current_brightness_percent = 100;
g_brightness = (uint8_t)current_brightness_percent;
notify_enabled = 1;
send_brightness_frame((uint8_t)current_brightness_percent);
}
else if (bits & BLE_SEND_DL_EMOJI_FAILED)//返回下载表情失败
{
ESP_LOGI("NOTIFICATION", "BLE_SEND_DL_EMOJI_FAILED");
notify_enabled = 1;
send_emoji_download_result_frame(0);
}
else if (bits & BLE_SEND_DL_EMOJI_SUCCESS)//返回下载表情成功
{
ESP_LOGI("NOTIFICATION", "BLE_SEND_DL_EMOJI_SUCCESS");
notify_enabled = 1;
send_emoji_download_result_frame(1);
}
else if (bits & BLE_SEND_DOWNLOADED_PACKS)//返回已下载表情包列表
{
ESP_LOGI("NOTIFICATION", "BLE_SEND_DOWNLOADED_PACKS");
notify_enabled = 1;
send_downloaded_packs_frame();
}
else if (bits & BLE_SEND_WIFI_STATE)//返回WiFi状态
{
ESP_LOGI("NOTIFICATION", "BLE_SEND_WIFI_STATE, 主动发送 1.10_A WiFi状态=%s", s_wifi_state_to_send ? "已连接(0x01)" : "断开(0x00)");
notify_enabled = 1;
send_wifi_state_frame(s_wifi_state_to_send);
}
else if (bits & BLE_SEND_EMOJI_EXCHANGE_RESULT)//返回表情包切换结果
{
ESP_LOGI("NOTIFICATION", "BLE_SEND_EMOJI_EXCHANGE_RESULT");
notify_enabled = 1;
esp_err_t err = emoji_storage_save_using_pack(s_emoji_switch_target_pack);
send_emoji_switch_result_frame(err == ESP_OK ? 1 : 0);
ESP_LOGI("NOTIFICATION", "g_emoji_upgrade_pending_finalize = %d", (int)g_emoji_upgrade_pending_finalize);
if (g_emoji_upgrade_pending_finalize)
{
/* 下载成功后第一次切换:收尾升级(不重启,不回到原来) */
g_emoji_upgrade_pending_finalize = false;
g_emoji_upgrade_last_switch_target = s_emoji_switch_target_pack;
set_system_event(EMOJI_UPGRADE_FINALIZE_BIT);
}
}
else if (bits & BLE_SEND_EMOJI_USING)//返回正在使用的表情包
{
ESP_LOGI("NOTIFICATION", "BLE_SEND_EMOJI_USING");
notify_enabled = 1;
send_emoji_using_frame(emoji_storage_get_using_pack());
}
else if (bits & BLE_SEND_EMOJI_DELETE_RESULT)//返回删除表情包结果
{
ESP_LOGI("NOTIFICATION", "BLE_SEND_EMOJI_DELETE_RESULT");
notify_enabled = 1;
emoji_storage_remove_pack_files(s_emoji_delete_target_pack);
esp_err_t err = emoji_storage_remove_downloaded_pack(s_emoji_delete_target_pack);
send_emoji_delete_result_frame(err == ESP_OK ? 1 : 0);
}
else if (bits & BLE_SEND_EMOJI_CLEAR_RESULT)
{
ESP_LOGI("NOTIFICATION", "BLE_SEND_EMOJI_CLEAR_RESULT");
notify_enabled = 1;
esp_err_t err = emoji_storage_clear_all_packs();
send_emoji_clear_result_frame(err == ESP_OK ? 1 : 0);
}
else
{
}
}
}
/* Feedback 3.4 返回删除表情包结果 0x0020 op=0x03:帧头(1)+类(2)+指令(2)+op(1)+Exchange_result(1)+CRC16(2)+帧尾(1)=10 */
void send_emoji_delete_result_frame(uint8_t success)
{
uint8_t frame[10] = {0};
uint16_t crc16;
frame[0] = 0xAA;
frame[1] = 0xFF;
frame[2] = 0xFF;
frame[3] = 0x00;
frame[4] = 0x20;
frame[5] = 0x03; /* op=0x03 删除结果 */
frame[6] = success ? 0x01 : 0x00;
crc16 = crc16_ccitt_calculate(frame, 7);
frame[7] = (crc16 >> 8) & 0xFF;
frame[8] = crc16 & 0xFF;
frame[9] = 0x55;
send_protocol_frame(frame, sizeof(frame));
ESP_LOGI(BLE_TAG, "发送Feedback3.4删除表情包结果: %s, 发送 CRC16=0x%04X", success ? "成功(0x01)" : "失败(0x00)", crc16);
}
/* Feedback clear_emojo 返回清除所有表情包结果 0x0021:帧头(1)+类(2)+指令(2)+result(1)+CRC16(2)+帧尾(1)=9 */
void send_emoji_clear_result_frame(uint8_t success)
{
uint8_t frame[9] = {0};
uint16_t crc16;
frame[0] = 0xAA;
frame[1] = 0xFF;
frame[2] = 0xFF;
frame[3] = 0x00;
frame[4] = 0x21;
frame[5] = success ? 0x01 : 0x00;
crc16 = crc16_ccitt_calculate(frame, 6);
frame[6] = (crc16 >> 8) & 0xFF;
frame[7] = crc16 & 0xFF;
frame[8] = 0x55;
send_protocol_frame(frame, sizeof(frame));
ESP_LOGI(BLE_TAG, "发送清除所有表情包结果: %s, CRC16=0x%04X", success ? "成功(0x01)" : "失败(0x00)", crc16);
}
/* Feedback 表情包查询/切换 0x0020 op=0x02 切换结果:帧头(1)+类(2)+指令(2)+op(1)+result(1)+CRC16(2)+帧尾(1)=10 */
void send_emoji_switch_result_frame(uint8_t success)
{
uint8_t frame[11] = {0};
uint16_t crc16;
frame[0] = 0xAA;
frame[1] = 0xFF;
frame[2] = 0xFF;
frame[3] = 0x00;
frame[4] = 0x20;
frame[5] = 0x02; /* op=0x02 切换结果 */
frame[6] = success ? 0x01 : 0x00;
frame[7] = s_emoji_switch_target_pack;//pack_id
crc16 = crc16_ccitt_calculate(frame, 8);
frame[8] = (crc16 >> 8) & 0xFF;
frame[9] = crc16 & 0xFF;
frame[10] = 0x55;
send_protocol_frame(frame, sizeof(frame));
ESP_LOGI(BLE_TAG, "发送Feedback3.2切换结果: %s, 发送 CRC16=0x%04X", success ? "成功(0x01)" : "失败(0x00)", crc16);
}
/* Feedback 表情包下载结果 0x0003:帧头(1)+类(2)+指令(2)+result(1)+CRC16(2)+帧尾(1)=9 */
void send_emoji_download_result_frame(uint8_t success)
{
uint8_t frame[9] = {0};
uint16_t crc16;
frame[0] = 0xAA;
frame[1] = 0xFF;
frame[2] = 0xFF;
frame[3] = 0x00;
frame[4] = 0x03; /* 表情包下载结果 */
frame[5] = success ? 0x01 : 0x00;
crc16 = crc16_ccitt_calculate(frame, 6);
frame[6] = (crc16 >> 8) & 0xFF;
frame[7] = crc16 & 0xFF;
frame[8] = 0x55;
send_protocol_frame(frame, sizeof(frame));
ESP_LOGI(BLE_TAG, "发送表情包下载结果: %s, 发送 CRC16=0x%04X", success ? "成功(0x01)" : "失败(0x00)", crc16);
}
/* Feedback 0x0020 op=0x00 返回已安装表情包列表:帧头(1)+类(2)+指令(2)+op(1)+count(1)+[id1..idN]+CRC16(2)+帧尾(1);默认系列 0 自带,无论如何都先发 */
#define EMOJI_PACK_LIST_MAX 16
void send_downloaded_packs_frame(void)
{
char list_buf[64];
int len = emoji_storage_get_downloaded_packs(list_buf, sizeof(list_buf));
uint8_t ids[EMOJI_PACK_LIST_MAX];
int count = 0;
/* 默认表情包系列 0 始终第一位 */
ids[count++] = (uint8_t)'0';
if (len > 0)
{
for (int i = 0; i < len && count < EMOJI_PACK_LIST_MAX; i++)
{
if (list_buf[i] != ',' && list_buf[i] != '0')
{
ids[count++] = (uint8_t)list_buf[i];
}
}
}
size_t frame_len = 10 + count;
uint8_t *frame = (uint8_t *)malloc(frame_len);
if (!frame)
{
ESP_LOGE(BLE_TAG, "已安装列表帧分配失败");
return;
}
frame[0] = 0xAA;
frame[1] = 0xFF;
frame[2] = 0xFF;
frame[3] = 0x00;
frame[4] = 0x20;
frame[5] = 0x00; /* op=0x00 返回已安装列表 */
frame[6] = (uint8_t)count;
for (int i = 0; i < count; i++)
{
frame[7 + i] = ids[i];
}
uint16_t crc16 = crc16_ccitt_calculate(frame, 7 + count);
frame[7 + count] = (crc16 >> 8) & 0xFF;
frame[8 + count] = crc16 & 0xFF;
frame[9 + count] = 0x55;
send_protocol_frame(frame, frame_len);
ESP_LOGI(BLE_TAG, "发送已安装表情包列表: count=%d, 发送 CRC16=0x%04X", count, crc16);
free(frame);
}
/* 发送get_system_info反馈帧2.3A: version */
void send_version_frame(const char *version_str)
{
size_t version_len = strlen(version_str);
size_t frame_len = 7 + version_len + 2 + 1; // 帧头(1) + 类(2) + 指令(2) + 长度(2) + 版本号 + CRC16(2) + 帧尾(1)
uint8_t *frame = (uint8_t *)malloc(frame_len);
if (!frame)
{
ESP_LOGE(BLE_TAG, "分配内存失败");
return;
}
uint16_t crc16;
size_t pos = 0;
// 帧头
frame[pos++] = 0xAA;
// 类 (Feedback)
frame[pos++] = 0xFF;
frame[pos++] = 0xFF;
// 指令 (version_cmd)
frame[pos++] = 0x00;
frame[pos++] = 0x06;
// 长度 (2字节,大端序)
frame[pos++] = (version_len >> 8) & 0xFF;
frame[pos++] = version_len & 0xFF;
// 版本号字符串
memcpy(&frame[pos], version_str, version_len);
pos += version_len;
// 计算CRC16 (不包括帧尾)
crc16 = crc16_ccitt_calculate(frame, pos);
frame[pos++] = (crc16 >> 8) & 0xFF;
frame[pos++] = crc16 & 0xFF;
// 帧尾
frame[pos++] = 0x55;
send_protocol_frame(frame, frame_len);
ESP_LOGI(BLE_TAG, "发送version帧: %s (长度: %d), 发送 CRC16=0x%04X", version_str, frame_len, crc16);
free(frame);
}
/* 1.11_B: 发送 OTA 升级进度 Feedback OTA_progress_cmd 0x0002,进度 0~100 */
void send_ota_progress_frame(uint8_t progress)
{
uint8_t frame[9] = {0};
uint16_t crc16;
frame[0] = 0xAA;
frame[1] = 0xFF;
frame[2] = 0xFF;
frame[3] = 0x00;
frame[4] = 0x02;
frame[5] = progress > 100 ? 100 : progress;
crc16 = crc16_ccitt_calculate(frame, 6);
frame[6] = (crc16 >> 8) & 0xFF;
frame[7] = crc16 & 0xFF;
frame[8] = 0x55;
send_protocol_frame(frame, sizeof(frame));
ESP_LOGI(BLE_TAG, "发送OTA进度帧 1.11_B: 进度(十进制)=%d%%, 发送 CRC16=0x%04X", (int)frame[5], crc16);
}
/* 1.11_A: 发送 OTA 升级结果 Feedback OTA_result_cmd 0x0001,0x01=成功 0x00=失败 */
void send_ota_result_frame(uint8_t result)
{
uint8_t frame[9] = {0};
uint16_t crc16;
frame[0] = 0xAA;
frame[1] = 0xFF;
frame[2] = 0xFF;
frame[3] = 0x00;
frame[4] = 0x01;
frame[5] = result ? 0x01 : 0x00;
crc16 = crc16_ccitt_calculate(frame, 6);
frame[6] = (crc16 >> 8) & 0xFF;
frame[7] = crc16 & 0xFF;
frame[8] = 0x55;
send_protocol_frame(frame, sizeof(frame));
ESP_LOGI(BLE_TAG, "发送OTA结果帧 1.11_A: %s, 发送 CRC16=0x%04X", result ? "成功(0x01)" : "失败(0x00)", crc16);
}
void ble_send_ota_progress(uint8_t progress)
{
s_ota_progress_to_send = progress > 100 ? 100 : progress;
if (notification_task_handle)
{
xTaskNotify(notification_task_handle, BLE_SEND_PROGRESS, eSetBits);
}
}
void ble_send_ota_result_request(uint8_t success)
{
s_ota_result_to_send = success ? 1 : 0;
if (notification_task_handle)
{
xTaskNotify(notification_task_handle, BLE_SEND_OTA_RESULT, eSetBits);
}
else
{
ESP_LOGE(BLE_TAG, "notification_task_handle 不存在");
}
}
/* 发送get_system_info反馈帧2.1A: get_system_ok */
void send_get_system_ok_frame(void)
{
uint8_t frame[9] = {0};
uint16_t crc16;
// 帧头
frame[0] = 0xAA;
// 类 (Feedback)
frame[1] = 0xFF;
frame[2] = 0xFF;
// 指令 (get_sysinfo_feedback)
frame[3] = 0x00;
frame[4] = 0x04;
// 指令返回 (get_system_ok = 0x01)
frame[5] = 0x01;
// 计算CRC16 (不包括帧尾)
crc16 = crc16_ccitt_calculate(frame, 6);
frame[6] = (crc16 >> 8) & 0xFF;
frame[7] = crc16 & 0xFF;
// 帧尾
frame[8] = 0x55;
send_protocol_frame(frame, sizeof(frame));
ESP_LOGI(BLE_TAG, "发送get_system_ok帧, 发送 CRC16=0x%04X", crc16);
}
/* 发送get_system_info反馈帧2.2A: brightness */
void send_brightness_frame(uint8_t brightness)
{
uint8_t frame[9] = {0};
uint16_t crc16;
// 帧头
frame[0] = 0xAA;
// 类 (Feedback)
frame[1] = 0xFF;
frame[2] = 0xFF;
// 指令 (Brightness_cmd)
frame[3] = 0x00;
frame[4] = 0x05;
frame[5] = brightness > 100 ? 100 : brightness;
// 计算CRC16 (不包括帧尾)
crc16 = crc16_ccitt_calculate(frame, 6);
frame[6] = (crc16 >> 8) & 0xFF;
frame[7] = crc16 & 0xFF;
// 帧尾
frame[8] = 0x55;
send_protocol_frame(frame, sizeof(frame));
ESP_LOGI(BLE_TAG, "发送brightness帧: 亮度(十进制)=%d, 发送 CRC16=0x%04X", (int)frame[5], crc16);
}
/* Feedback 3.2: 返回正在使用的表情包 帧头(1)+类(2)+指令(2)+Check_using(1)+Pack_id(1)+CRC16(2)+帧尾(1)=10 */
void send_emoji_using_frame(uint8_t pack_id)
{
uint8_t frame[10] = {0};
uint16_t crc16;
frame[0] = 0xAA;
frame[1] = 0xFF;
frame[2] = 0xFF;
frame[3] = 0x00;
frame[4] = 0x20; /* Emoji_cmd 0x0020 */
frame[5] = 0x01; /* Check_using 查询正在使用 */
frame[6] = pack_id; /* Pack_id ASCII 1 byte */
crc16 = crc16_ccitt_calculate(frame, 7);
frame[7] = (crc16 >> 8) & 0xFF;
frame[8] = crc16 & 0xFF;
frame[9] = 0x55;
send_protocol_frame(frame, sizeof(frame));
ESP_LOGI(BLE_TAG, "发送Feedback3.2正在使用表情包: Pack_id=%c (0x%02X), 发送 CRC16=0x%04X", (char)pack_id, pack_id, crc16);
}
/* 发送 WiFi 状态反馈帧 1.10_A: Feedback Wifi_state_cmd 0x0010 */
void send_wifi_state_frame(uint8_t state)
{
uint8_t frame[9] = {0};
uint16_t crc16;
frame[0] = 0xAA;
frame[1] = 0xFF;
frame[2] = 0xFF;
frame[3] = 0x00;
frame[4] = 0x10;
frame[5] = state ? 0x01 : 0x00; /* 0x01=已连接, 0x00=断开 */
crc16 = crc16_ccitt_calculate(frame, 6);
frame[6] = (crc16 >> 8) & 0xFF;
frame[7] = crc16 & 0xFF;
frame[8] = 0x55;
send_protocol_frame(frame, sizeof(frame));
ESP_LOGI(BLE_TAG, "发送WiFi状态帧: %s, 发送 CRC16=0x%04X", state ? "已连接" : "断开", crc16);
}
void ble_send_wifi_state_request(uint8_t connected)
{
s_wifi_state_to_send = connected ? 1 : 0;
if (notification_task_handle)
{
xTaskNotify(notification_task_handle, BLE_SEND_WIFI_STATE, eSetBits);
}
}
void ble_request_send_brightness(void)
{
if (notification_task_handle)
{
xTaskNotify(notification_task_handle, BLE_SEND_BRIGHTNESS, eSetBits);
}
}
/* 切换表情包指令的目标 Pack_id,由 ble_data_ansy 在收到 op=0x02 时设置 */
// static char s_emoji_switch_target_pack = '0';
void ble_set_emoji_switch_target(char pack_id)
{
s_emoji_switch_target_pack = pack_id;
}
/* 删除表情包指令的目标 Pack_id,由 ble_data_ansy 在收到 op=0x03 时设置 */
void ble_set_emoji_delete_target(char pack_id)
{
s_emoji_delete_target_pack = pack_id;
}
void robot_sleep_frame(uint8_t state)
{
(void)state;
uint8_t frame[8] = {0};
uint16_t crc16;
frame[0] = 0xAA;
frame[1] = 0xFF;
frame[2] = 0xFF;
frame[3] = 0x00;
frame[4] = 0x07;
crc16 = crc16_ccitt_calculate(frame, 5);
frame[5] = (crc16 >> 8) & 0xFF;
frame[6] = crc16 & 0xFF;
frame[7] = 0x55;
send_protocol_frame(frame, sizeof(frame));
ESP_LOGI(BLE_TAG, "发送robot睡眠状态帧: 发送 CRC16=0x%04X", crc16);
}
void robot_wake_frame(uint8_t state)
{
(void)state;
uint8_t frame[8] = {0};
uint16_t crc16;
frame[0] = 0xAA;
frame[1] = 0xFF;
frame[2] = 0xFF;
frame[3] = 0x00;
frame[4] = 0x08;
crc16 = crc16_ccitt_calculate(frame, 5);
frame[5] = (crc16 >> 8) & 0xFF;
frame[6] = crc16 & 0xFF;
frame[7] = 0x55;
send_protocol_frame(frame, sizeof(frame));
ESP_LOGI(BLE_TAG, "发送robot唤醒状态帧: 发送 CRC16=0x%04X", crc16);
}