#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); }