This commit is contained in:
Steven Dan
2026-03-26 23:22:40 +08:00
parent 17ad9324de
commit fcb0ddd7f5
12 changed files with 2095 additions and 172 deletions

View File

@@ -156,6 +156,7 @@ set(APP_COMPILER_FLAGS_f1_music_uac2 ${SW_USB_AUDIO_FLAGS} -DI2S_CHANS_DAC
-DOUTPUT_VOLUME_CONTROL=1 -DOUTPUT_VOLUME_CONTROL=1
#-DDEBUG_MEMORY_LOG_ENABLED=1 #-DDEBUG_MEMORY_LOG_ENABLED=1
-DXUA_DFU_EN=1 -DXUA_DFU_EN=1
-DHID_DFU_EN=1
#-DIR_SWITCHING_MODE #-DIR_SWITCHING_MODE
-DHID_CONTROLS=1) -DHID_CONTROLS=1)
@@ -181,6 +182,7 @@ set(APP_COMPILER_FLAGS_f3_f4_fps_uac2 ${SW_USB_AUDIO_FLAGS} -DI2S_CHANS_DAC=2
-DOUTPUT_VOLUME_CONTROL=1 -DOUTPUT_VOLUME_CONTROL=1
#-DDEBUG_MEMORY_LOG_ENABLED=1 #-DDEBUG_MEMORY_LOG_ENABLED=1
-DXUA_DFU_EN=1 -DXUA_DFU_EN=1
-DHID_DFU_EN=1
-DIR_SWITCHING_MODE -DIR_SWITCHING_MODE
-DHID_CONTROLS=1) -DHID_CONTROLS=1)
set(APP_COMPILER_FLAGS_f6_f7_fps_uac1 ${SW_USB_AUDIO_FLAGS} -DI2S_CHANS_DAC=2 set(APP_COMPILER_FLAGS_f6_f7_fps_uac1 ${SW_USB_AUDIO_FLAGS} -DI2S_CHANS_DAC=2
@@ -204,6 +206,7 @@ set(APP_COMPILER_FLAGS_f6_f7_fps_uac1 ${SW_USB_AUDIO_FLAGS} -DI2S_CHANS_DAC=2
-DOUTPUT_VOLUME_CONTROL=1 -DOUTPUT_VOLUME_CONTROL=1
#-DDEBUG_MEMORY_LOG_ENABLED=1 #-DDEBUG_MEMORY_LOG_ENABLED=1
-DXUA_DFU_EN=1 -DXUA_DFU_EN=1
-DHID_DFU_EN=1
-DIR_SWITCHING_MODE -DIR_SWITCHING_MODE
-DHID_CONTROLS=1) -DHID_CONTROLS=1)

View File

@@ -1,2 +1 @@
xflash --factory-version 15.3 --target-file src/core/synido.xn --upgrade 2 bin\ex3d_UAC1\app_usb_aud_phaten_gs_ex3d_UAC1.xe --upgrade 4 bin/ex3d_stereo_2k/app_usb_aud_phaten_gs_ex3d_stereo_2k.xe --upgrade 1 bin\ex3d_71_game\app_usb_aud_phaten_gs_ex3d_71_game.xe --upgrade 3 bin\ex3d_71_movie\app_usb_aud_phaten_gs_ex3d_71_movie.xe -o %1 xflash --factory-version 15.3 --target-file src/core/synido.xn --upgrade 2 bin/f5_music_uac1/app_usb_aud_sy102_f5_music_uac1.xe --upgrade 3 bin/f1_music_uac2/app_usb_aud_sy102_f1_music_uac2.xe --upgrade 1 bin/f3_f4_fps_uac2/app_usb_aud_sy102_f3_f4_fps_uac2.xe -o %1

View File

@@ -80,9 +80,6 @@ unsigned g_volume_level = 29, g_saved_volume_level = 29;
unsigned g_request_volume_set = 0; unsigned g_request_volume_set = 0;
unsigned g_init_saved_settings = 0; unsigned g_init_saved_settings = 0;
unsigned g_host_volume = 0x0; unsigned g_host_volume = 0x0;
// HID主动上报缓冲区被eq.c通过extern引用
unsigned char g_hid_status_report_data[63] = {0};
unsigned int g_hid_status_report_index = 0;
unsigned g_last_volume_level = 0xFF; // 上次已上报的音量级别0xFF表示初始化未完成 unsigned g_last_volume_level = 0xFF; // 上次已上报的音量级别0xFF表示初始化未完成
unsigned g_mic_volume_level = 37; // 麦克风PGA增益级别0=mute, 1-37=0dB~36dBHID可见范围 unsigned g_mic_volume_level = 37; // 麦克风PGA增益级别0=mute, 1-37=0dB~36dBHID可见范围
unsigned g_request_mic_volume_set = 0; unsigned g_request_mic_volume_set = 0;
@@ -103,16 +100,12 @@ unsigned g_disable_i2c = 0;
unsigned g_dac_mode = 10; unsigned g_dac_mode = 10;
unsigned g_new_dac_mode = 0; unsigned g_new_dac_mode = 0;
unsigned g_samfreq = 48000; unsigned g_samfreq = 48000;
unsigned g_dsd_mode = 0;
unsafe chanend uc_audiohw; // tile[1] end: AudioHwConfig → button_task (tile[0]) unsafe chanend uc_audiohw; // tile[1] end: AudioHwConfig → button_task (tile[0])
// 改动原因添加DSD模式全局变量用于HID命令读取采样率和格式信息已去掉DAC采样分辨率 #if HID_DFU_EN
unsigned g_dsd_mode = 0; // DSD模式0=PCM, >0=DSD unsafe streaming chanend uc_dfu; // tile[1] send end: hid_button_task → button_task (tile[0])
unsigned g_gain_mode = 0; // 0: 低阻, 1: 高阻 #endif
// 改动原因支持8种滤波器模式0-7与g_filter_map[8]数组定义一致
unsigned g_filter_mode = 0; // 0-7: 对应8种滤波器模式
// 改动原因添加增益模式和滤波器模式的请求变量用于HID命令设置模式 // 改动原因添加增益模式和滤波器模式的请求变量用于HID命令设置模式
unsigned g_request_gain_mode = -1; // -1表示无请求0=低阻1=高阻
// 改动原因支持8种滤波器模式0-7与g_filter_map[8]数组定义一致
unsigned g_request_filter_mode = -1; // -1表示无请求0-7=滤波器模式
unsigned g_request_game_mode = -1; unsigned g_request_game_mode = -1;
#if EQ_EN #if EQ_EN
@@ -294,9 +287,36 @@ enum {IR_OFF=0, IR_GAME=1, IR_MUSIC=2, IR_MOVIE=3, IR_7_1_GAME=4, IR_7_1_MUSIC=5
#ifndef HID_MAX_DATA_BYTES #ifndef HID_MAX_DATA_BYTES
#define HID_MAX_DATA_BYTES ( 64 ) #define HID_MAX_DATA_BYTES ( 64 )
#endif #endif
unsigned hidSendData_local[HID_MAX_DATA_BYTES / 4]; extern unsigned hidSendData[];
void button_task(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol, chanend c_audiohw_rx) #if HID_DFU_EN
#include "dfu_upgrade.h"
/* 将HID收到的63字节固件升级START命令打包为16个unsigned word
* 通过uc_dfu streaming channel发送到button_task (tile[0])执行。
* 从eq.c的process_send_params中对0xA7命令调用此函数。 */
void dfu_chan_forward(unsigned char data[], unsigned len)
{
unsafe
{
for (int i = 0; i < 16; i++) {
unsigned word = 0;
for (int j = 0; j < 4; j++) {
int idx = i * 4 + j;
if (idx < 63) {
word |= ((unsigned)data[idx]) << (j * 8);
}
}
uc_dfu <: word;
}
}
}
#endif
void button_task(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol, chanend c_audiohw_rx
#if HID_DFU_EN
, streaming chanend c_dfu_rx
#endif
)
{ {
//hwtimer_t timer = hwtimer_alloc(); //hwtimer_t timer = hwtimer_alloc();
unsigned time = 0; unsigned time = 0;
@@ -633,8 +653,6 @@ void button_task(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol,
{ {
case c_hidSendData :> hidData0: case c_hidSendData :> hidData0:
{ {
unsigned *reportData = hidSendData_local;
reportData[0] = hidData0;
if (hidData0 == 0xffffffff) { if (hidData0 == 0xffffffff) {
debug_printf("receive end data\n"); debug_printf("receive end data\n");
@@ -727,12 +745,20 @@ void button_task(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol,
#endif #endif
break; break;
} }
#if HID_DFU_EN
if (!g_in_fw_upgrade)
#endif
{
#if (HID_CONTROLS == 1) #if (HID_CONTROLS == 1)
unsigned *reportData = hidSendData;
reportData[0] = hidData0;
for (int i=1; i<(HID_MAX_DATA_BYTES/4); i++) { for (int i=1; i<(HID_MAX_DATA_BYTES/4); i++) {
c_hidSendData :> reportData[i]; c_hidSendData :> reportData[i];
} }
hidSetChangePending(1); hidSetChangePending(1);
#endif #endif
}
break; break;
} }
@@ -780,21 +806,46 @@ void button_task(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol,
c_audiohw_rx <: 0xff; c_audiohw_rx <: 0xff;
#if HID_CONTROLS > 0 #if HID_CONTROLS > 0
g_hid_status_report_data[0] = 0x77; #if HID_DFU_EN
g_hid_status_report_data[1] = 0x9F; if (!g_in_fw_upgrade)
g_hid_status_report_data[2] = (unsigned char)(new_samfreq & 0xFF); #endif
g_hid_status_report_data[3] = (unsigned char)((new_samfreq >> 8) & 0xFF); {
g_hid_status_report_data[4] = (unsigned char)((new_samfreq >> 16) & 0xFF); unsafe {
g_hid_status_report_data[5] = (unsigned char)((new_samfreq >> 24) & 0xFF); unsigned char * unsafe ptr = (unsigned char * unsafe)hidSendData;
g_hid_status_report_data[6] = (unsigned char)new_dsd_mode; ptr[0] = 1;
for (int i = 7; i < 63; i++) ptr[1] = 0x77;
g_hid_status_report_data[i] = 0x00; ptr[2] = 0x9F;
g_hid_status_report_index = 63; ptr[3] = (unsigned char)(new_samfreq & 0xFF);
ptr[4] = (unsigned char)((new_samfreq >> 8) & 0xFF);
ptr[5] = (unsigned char)((new_samfreq >> 16) & 0xFF);
ptr[6] = (unsigned char)((new_samfreq >> 24) & 0xFF);
ptr[7] = (unsigned char)new_dsd_mode;
for (int i = 8; i < HID_MAX_DATA_BYTES; i++)
ptr[i] = 0x00;
}
hidSetChangePending(0x1); hidSetChangePending(0x1);
}
#endif #endif
break; break;
} }
#if HID_DFU_EN
case c_dfu_rx :> unsigned dfu_first_word:
{
// 接收来自tile[1] hid_button_task转发的固件升级START命令16个word
unsigned dfu_words[16];
dfu_words[0] = dfu_first_word;
for (int i = 1; i < 16; i++)
c_dfu_rx :> dfu_words[i];
unsigned char cmd_buf[63];
for (int i = 0; i < 63; i++)
cmd_buf[i] = (dfu_words[i / 4] >> ((i % 4) * 8)) & 0xFF;
if (cmd_buf[1] == FIRMWARE_UPGRADE_START)
handle_firmware_upgrade_start(cmd_buf, 63);
break;
}
#endif
case tmr when timerafter(time) :> void : case tmr when timerafter(time) :> void :
{ {
//hwtimer_change_trigger_time(timer, hwtimer_get_time(timer) + KEY_POLLING_INTERVAL); //hwtimer_change_trigger_time(timer, hwtimer_get_time(timer) + KEY_POLLING_INTERVAL);
@@ -1512,13 +1563,19 @@ void button_task(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol,
// HID监听音量变化主动上报编码器旋转或HID命令导致的音量变化 // HID监听音量变化主动上报编码器旋转或HID命令导致的音量变化
{ {
unsigned current_volume_level = g_volume_level; unsigned current_volume_level = g_volume_level;
#if HID_DFU_EN
if (!g_in_fw_upgrade)
#endif
if (g_last_volume_level != current_volume_level && g_last_volume_level != 0xFF) { if (g_last_volume_level != current_volume_level && g_last_volume_level != 0xFF) {
g_hid_status_report_data[0] = 0x77; // 同步头1 unsafe {
g_hid_status_report_data[1] = 0x94; // GET_VOLUME命令码 unsigned char * unsafe ptr = (unsigned char * unsafe)hidSendData;
g_hid_status_report_data[2] = (unsigned char)current_volume_level; ptr[0] = 1;
for (int i = 3; i < 63; i++) ptr[1] = 0x77;
g_hid_status_report_data[i] = 0x00; ptr[2] = 0x94;
g_hid_status_report_index = 63; ptr[3] = (unsigned char)current_volume_level;
for (int i = 4; i < HID_MAX_DATA_BYTES; i++)
ptr[i] = 0x00;
}
hidSetChangePending(0x1); hidSetChangePending(0x1);
debug_printf("Volume changed: %d -> %d, HID report sent\n", debug_printf("Volume changed: %d -> %d, HID report sent\n",
g_last_volume_level, current_volume_level); g_last_volume_level, current_volume_level);
@@ -1529,13 +1586,19 @@ void button_task(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol,
// HID麦克风增益变化主动上报 // HID麦克风增益变化主动上报
{ {
unsigned current_mic_level = g_mic_volume_level; unsigned current_mic_level = g_mic_volume_level;
#if HID_DFU_EN
if (!g_in_fw_upgrade)
#endif
if (g_last_mic_volume_level != current_mic_level && g_last_mic_volume_level != 0xFF) { if (g_last_mic_volume_level != current_mic_level && g_last_mic_volume_level != 0xFF) {
g_hid_status_report_data[0] = 0x77; // 同步头1 unsafe {
g_hid_status_report_data[1] = 0x83; // GET_MIC_VOLUME命令码 unsigned char * unsafe ptr = (unsigned char * unsafe)hidSendData;
g_hid_status_report_data[2] = (unsigned char)current_mic_level; ptr[0] = 1;
for (int i = 3; i < 63; i++) ptr[1] = 0x77;
g_hid_status_report_data[i] = 0x00; ptr[2] = 0x83;
g_hid_status_report_index = 63; ptr[3] = (unsigned char)current_mic_level;
for (int i = 4; i < HID_MAX_DATA_BYTES; i++)
ptr[i] = 0x00;
}
hidSetChangePending(0x1); hidSetChangePending(0x1);
debug_printf("Mic volume changed: %d -> %d, HID report sent\n", debug_printf("Mic volume changed: %d -> %d, HID report sent\n",
g_last_mic_volume_level, current_mic_level); g_last_mic_volume_level, current_mic_level);
@@ -1600,7 +1663,11 @@ void button_task(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol,
} }
} }
void AudioHwRemote(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol, chanend c_audiohw_rx) void AudioHwRemote(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol, chanend c_audiohw_rx
#if HID_DFU_EN
, streaming chanend c_dfu_rx
#endif
)
{ {
i2c_master_if i2c[1]; i2c_master_if i2c[1];
board_setup(); board_setup();
@@ -1608,7 +1675,11 @@ void AudioHwRemote(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vo
i2c_master(i2c, 1, p_scl, p_sda, 300); i2c_master(i2c, 1, p_scl, p_sda, 300);
{ {
unsafe {i_i2c_client = i2c[0];} unsafe {i_i2c_client = i2c[0];}
button_task(c_hidSendData, cc_mic_level, c_uac_vol, c_audiohw_rx); button_task(c_hidSendData, cc_mic_level, c_uac_vol, c_audiohw_rx
#if HID_DFU_EN
, c_dfu_rx
#endif
);
} }
} }
} }

View File

@@ -0,0 +1,273 @@
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#define DEBUG_PRINT_ENABLE 0
#include <xs1.h>
#include <flash.h>
#include <flashlib.h>
#include <string.h>
#include <xclib.h>
#include <stdio.h>
#include "debug_print.h"
#include "xua.h"
#if HID_DFU_EN
#ifndef DFU_FLASH_MAX_UPGRADE_SIZE
#define DFU_FLASH_MAX_UPGRADE_SIZE (1600 * 1024)
#endif
#define DFU_FLASH_ERROR()
static int dfu_flash_device_open = 0;
static fl_BootImageInfo dfu_factory_image;
static fl_BootImageInfo dfu_upgrade_image;
static int dfu_upgrade_image_valid = 0;
static int dfu_current_flash_subpage_index = 0;
static unsigned char dfu_current_flash_page_data[256];
int dfu_flash_cmd_enable_ports() __attribute__ ((weak));
int dfu_flash_cmd_enable_ports() {
return 0;
}
int dfu_flash_cmd_disable_ports() __attribute__ ((weak));
int dfu_flash_cmd_disable_ports() {
return 0;
}
void DFUCustomFlashEnable() __attribute__ ((weak));
void DFUCustomFlashEnable()
{
return;
}
void DFUCustomFlashDisable() __attribute__ ((weak));
void DFUCustomFlashDisable()
{
return;
}
/* Returns non-zero for error */
int dfu_flash_cmd_init(void)
{
debug_printf("dfu_flash_cmd_init: dfu_flash_cmd_init\n");
fl_BootImageInfo image;
if (!dfu_flash_device_open)
{
if (dfu_flash_cmd_enable_ports())
dfu_flash_device_open = 1;
debug_printf("dfu_flash_cmd_init: dfu_flash_device_open = 1\n");
}
if (!dfu_flash_device_open)
{
debug_printf("dfu_flash_cmd_init: dfu_flash_device_open = 0\n");
return 1;
}
#if (!XUA_QUAD_SPI_FLASH)
// Disable flash protection
fl_setProtection(0);
#endif
if (fl_getFactoryImage(&image) != 0)
{
return 1;
}
dfu_factory_image = image;
if (fl_getNextBootImage(&image) == 0)
{
dfu_upgrade_image_valid = 1;
dfu_upgrade_image = image;
debug_printf("dfu_flash_cmd_init: dfu_upgrade_image_valid = 1\n");
}
debug_printf("dfu_flash_cmd_init: return 0\n");
return 0;
}
int dfu_flash_cmd_deinit(void)
{
if (!dfu_flash_device_open)
return 0;
dfu_flash_cmd_disable_ports();
dfu_flash_device_open = 0;
return 0;
}
int dfu_flash_cmd_read_page(unsigned char *data)
{
if (!dfu_upgrade_image_valid)
{
*(unsigned int *)data = 1;
return 4;
}
if (*(unsigned int *)data == 0)
{
fl_startImageRead(&dfu_upgrade_image);
}
dfu_current_flash_subpage_index = 0;
if (fl_readImagePage(dfu_current_flash_page_data) == 0)
{
*(unsigned int *)data = 0;
}
else
{
*(unsigned int *)data = 1;
}
return 4;
}
int dfu_flash_cmd_read_page_data(unsigned char *data)
{
unsigned char *page_data_ptr = &dfu_current_flash_page_data[dfu_current_flash_subpage_index * 64];
memcpy(data, page_data_ptr, 64);
dfu_current_flash_subpage_index++;
return 64;
}
static int begin_write()
{
int result;
// TODO this will take a long time. To minimise the amount of time spent
// paused on this operation it would be preferable to move to this to a
// seperate command, e.g. start_write.
do
{
result = fl_startImageAdd(&dfu_factory_image, DFU_FLASH_MAX_UPGRADE_SIZE, 0);
} while (result > 0);
if (result < 0)
{
DFU_FLASH_ERROR();
}
return result;
}
static int pages_written = 0;
int dfu_flash_cmd_write_page(unsigned char *data)
{
/* 改动原因:协议仅约定第一个字节为 flag(0=第一页,1=后续页,2=结束)
* 若用 *(unsigned int *)data 读取 4 字节,而调用处只设置 data[0]=0 且未清零 data[1..3]
* 则 flag 可能非 0导致不进入 case 0begin_write() 被跳过。改为仅用首字节。 */
unsigned int flag = (unsigned int)data[0];
if (flag == 0)
debug_printf("dfu_flash_cmd_write_page: flag = %d\n", flag);
if (dfu_upgrade_image_valid)
{
debug_printf("dfu_flash_cmd_write_page: dfu_upgrade_image_valid = 1\n");
return 0;
}
switch (flag)
{
case 0:
// First page.
debug_printf("dfu_flash_cmd_write_page: begin_write\n");
int result = begin_write();
if (result < 0)
return result;
pages_written = 0;
// fallthrough
case 1:
// Do nothing.
break;
case 2:
// Termination.
if (fl_endWriteImage() != 0)
DFU_FLASH_ERROR();
// Sanity check
fl_BootImageInfo image = dfu_factory_image;
if (fl_getNextBootImage(&image) != 0)
DFU_FLASH_ERROR();
break;
}
dfu_current_flash_subpage_index = 0;
return 0;
}
int dfu_flash_cmd_write_page_data(unsigned char *data)
{
unsigned char *page_data_ptr = &dfu_current_flash_page_data[dfu_current_flash_subpage_index * 64];
if (dfu_upgrade_image_valid)
{
return 0;
}
if (dfu_current_flash_subpage_index >= 4)
{
return 0;
}
memcpy(page_data_ptr, data, 64);
dfu_current_flash_subpage_index++;
if (dfu_current_flash_subpage_index == 4)
{
if (fl_writeImagePage(dfu_current_flash_page_data) != 0)
DFU_FLASH_ERROR();
pages_written++;
}
return 0;
}
int dfu_flash_cmd_erase_all(void)
{
fl_BootImageInfo tmp_image = dfu_upgrade_image;
if (dfu_upgrade_image_valid)
{
if (fl_deleteImage(&dfu_upgrade_image) != 0)
{
DFU_FLASH_ERROR();
}
// Keep deleting all upgrade images
// TODO Perhaps using replace would be nicer...
while(1)
{
if (fl_getNextBootImage(&tmp_image) == 0)
{
if (fl_deleteImage(&tmp_image) != 0)
{
DFU_FLASH_ERROR();
}
}
else
{
break;
}
}
dfu_upgrade_image_valid = 0;
}
/* 改动原因强制升级流程中erase 后必须允许后续第一页写执行 begin_write()
* 若仅在上面 if 块内清零,某些路径(如删除失败或 while 未正确退出)可能导致
* dfu_upgrade_image_valid 仍为 1write_page(flag=0) 会直接 return 0 而不调用
* begin_write(),导致 begin_write 未执行。此处无条件清零,保证 erase 后下一
* 次 write_page(0) 必定执行 begin_write。 */
dfu_upgrade_image_valid = 0;
debug_printf("dfu_flash_cmd_erase_all: set dfu_upgrade_image_valid = 0\n");
return 0;
}
#endif

View File

@@ -0,0 +1,34 @@
// Copyright 2011-2021 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#ifndef _dfu_flash_interface_h_
#define _dfu_flash_interface_h_
int dfu_flash_cmd_init(void);
/**
* Prepare to write a page of a new upgrade image.
* The first word of data should be set to 0 if it is the first page,
* 1 for all other pages and 2 to terminate the write (no further data is sent).
*/
int dfu_flash_cmd_write_page(unsigned char []);
/**
* Provide upgrade image data. flash_cmd_write_page() must be called previously.
* Once a page of data has been provided it is written to the device.
*/
int dfu_flash_cmd_write_page_data(unsigned char []);
/**
* Read a page of data from the upgrade image.
* If the first word of data is 0 the page is read from the start of the
* upgrade image, otherwise the next page in the image will be read.
* On return the first word of data is written with 1 if there is nothing to
* read and 0 otherwise.
*/
int dfu_flash_cmd_read_page(unsigned char []);
/**
* Get data previously read by flash_cmd_read_page().
*/
int dfu_flash_cmd_read_page_data(unsigned char []);
int dfu_flash_cmd_erase_all(void);
int dfu_flash_cmd_reboot(void);
int dfu_flash_cmd_init(void);
int dfu_flash_cmd_deinit(void);
#endif /*_dfu_flash_interface_h_*/

View File

@@ -0,0 +1,129 @@
// Copyright 2012-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include "xua.h"
#if (XUA_DFU_EN == 1 || UAC1 == 1)
#include "uac_hwresources.h"
#include <xs1.h>
#include <xclib.h>
#if (XUA_QUAD_SPI_FLASH)
#include <quadflashlib.h>
#else
#include <flashlib.h>
#endif
#include <print.h>
#define settw(a,b) {__asm__ __volatile__("settw res[%0], %1": : "r" (a) , "r" (b));}
#define setc(a,b) {__asm__ __volatile__("setc res[%0], %1": : "r" (a) , "r" (b));}
#define setclk(a,b) {__asm__ __volatile__("setclk res[%0], %1": : "r" (a) , "r" (b));}
#define portin(a,b) {__asm__ __volatile__("in %0, res[%1]": "=r" (b) : "r" (a));}
#define portout(a,b) {__asm__ __volatile__("out res[%0], %1": : "r" (a) , "r" (b));}
#ifdef DFU_FLASH_DEVICE
#if (XUA_QUAD_SPI_FLASH)
/* Using specified flash device rather than all supported in tools */
fl_QuadDeviceSpec dfu_flash_devices[] = {DFU_FLASH_DEVICE};
#else
/* Using specified flash device rather than all supported in tools */
fl_DeviceSpec dfu_flash_devices[] = {DFU_FLASH_DEVICE};
#endif
#endif
#if (XUA_QUAD_SPI_FLASH)
/*
typedef struct {
out port qspiCS;
out port qspiSCLK;
out buffered port:32 qspiSIO;
clock qspiClkblk;
} fl_QSPIPorts;
*/
fl_QSPIPorts dfu_p_qflash =
{
XS1_PORT_1B,
XS1_PORT_1C,
XS1_PORT_4B,
CLKBLK_FLASHLIB
};
#else
fl_PortHolderStruct p_flash =
{
XS1_PORT_1A,
XS1_PORT_1B,
XS1_PORT_1C,
XS1_PORT_1D,
CLKBLK_FLASHLIB
};
#endif
/* return 1 for opened ports successfully */
int dfu_flash_cmd_enable_ports()
{
int result = 0;
#if (XUA_QUAD_SPI_FLASH)
/* Ports not shared */
#else
setc(p_flash.spiMISO, XS1_SETC_INUSE_OFF);
setc(p_flash.spiCLK, XS1_SETC_INUSE_OFF);
setc(p_flash.spiMOSI, XS1_SETC_INUSE_OFF);
setc(p_flash.spiSS, XS1_SETC_INUSE_OFF);
setc(p_flash.spiClkblk, XS1_SETC_INUSE_OFF);
setc(p_flash.spiMISO, XS1_SETC_INUSE_ON);
setc(p_flash.spiCLK, XS1_SETC_INUSE_ON);
setc(p_flash.spiMOSI, XS1_SETC_INUSE_ON);
setc(p_flash.spiSS, XS1_SETC_INUSE_ON);
setc(p_flash.spiClkblk, XS1_SETC_INUSE_ON);
setc(p_flash.spiClkblk, XS1_SETC_INUSE_ON);
setclk(p_flash.spiMISO, XS1_CLKBLK_REF);
setclk(p_flash.spiCLK, XS1_CLKBLK_REF);
setclk(p_flash.spiMOSI, XS1_CLKBLK_REF);
setclk(p_flash.spiSS, XS1_CLKBLK_REF);
setc(p_flash.spiMISO, XS1_SETC_BUF_BUFFERS);
setc(p_flash.spiMOSI, XS1_SETC_BUF_BUFFERS);
settw(p_flash.spiMISO, 8);
settw(p_flash.spiMOSI, 8);
#endif
#ifdef DFU_FLASH_DEVICE
#if (XUA_QUAD_SPI_FLASH)
result = fl_connectToDevice(&dfu_p_qflash, dfu_flash_devices, sizeof(dfu_flash_devices) / sizeof(fl_QuadDeviceSpec));
#else
result = fl_connectToDevice(&dfu_p_flash, dfu_flash_devices, sizeof(dfu_flash_devices) / sizeof(fl_DeviceSpec));
#endif
#else
/* Use default flash list */
#if (XUA_QUAD_SPI_FLASH)
result = fl_connect(&dfu_p_qflash);
#else
result = fl_connect(&dfu_p_flash);
#endif
#endif
if (!result)
{
/* All okay.. */
return 1;
}
else
{
return 0;
}
}
int dfu_flash_cmd_disable_ports()
{
fl_disconnect();
#if (!XUA_QUAD_SPI_FLASH)
setc(p_flash.spiMISO, XS1_SETC_INUSE_OFF);
setc(p_flash.spiCLK, XS1_SETC_INUSE_OFF);
setc(p_flash.spiMOSI, XS1_SETC_INUSE_OFF);
setc(p_flash.spiSS, XS1_SETC_INUSE_OFF);
#endif
return 1;
}
#endif

View File

@@ -0,0 +1,436 @@
// Copyright 2026 Shanling.
// HID固件升级实现文件 (adapted for app_usb_aud_phaten_golden_6ch)
#define DEBUG_PRINT_ENABLE 0
#include "dfu_upgrade.h"
#include "user_func.h"
#include "dfu_flash_interface.h"
#include <string.h>
#include <stdio.h>
#include "debug_print.h"
#if HID_DFU_EN
// 外部函数声明
extern void hidSetChangePending(unsigned int id);
extern unsigned char check_sum(unsigned char *pbuf, unsigned len);
extern void device_reboot(void);
extern unsigned hidSendData[];
// 固件升级通知MCU的标志phaten无UART MCU保留为静态变量供内部使用
static unsigned g_firmware_upgrade_mcu_notify = 0;
unsigned g_in_fw_upgrade = 0; // 升级进行中标志供其他模块检查以阻止非升级HID上报
// 升级状态(静态全局变量)
static upgrade_status_t g_upgrade_status;
// 全局标志:第一页写命令是否已执行
static uint8_t g_first_page_write_executed = 0;
// 全局标志是否已执行dfu_flash_cmd_erase_all
static uint8_t g_flash_erased = 0;
// 初始化固件升级模块
void firmware_upgrade_init(void)
{
memset(&g_upgrade_status, 0, sizeof(upgrade_status_t));
g_upgrade_status.state = UPGRADE_IDLE;
g_upgrade_status.expected_block_num = 0;
debug_printf("Firmware upgrade module initialized\n");
}
// 获取当前升级状态
upgrade_state_t firmware_upgrade_get_state(void)
{
return g_upgrade_status.state;
}
// 重置升级状态
void firmware_upgrade_reset(void)
{
memset(&g_upgrade_status, 0, sizeof(upgrade_status_t));
g_upgrade_status.state = UPGRADE_IDLE;
g_upgrade_status.expected_block_num = 0;
g_upgrade_status.first_page_written = 0;
g_first_page_write_executed = 0;
g_flash_erased = 0;
}
// 发送固件升级响应(主动上报)
// 填充hidSendData通过UserHIDGetData上报给host
void send_firmware_upgrade_response(uint8_t cmd, uint8_t *response_data, uint16_t data_len)
{
unsigned char *ptr = (unsigned char *)hidSendData;
ptr[0] = 1;
ptr[1] = 0x77; // 同步头
ptr[2] = cmd; // 命令码
if (response_data != NULL && data_len > 0) {
uint16_t copy_len = (data_len < 61) ? data_len : 61;
memcpy(&ptr[3], response_data, copy_len);
}
for (int i = 3 + (int)data_len; i < 64; i++) {
ptr[i] = 0x00;
}
hidSetChangePending(0x1);
}
// 处理START命令
unsigned char handle_firmware_upgrade_start(uint8_t data[], uint16_t len)
{
uint8_t response[64] = {0};
if (g_upgrade_status.state != UPGRADE_IDLE) {
debug_printf("Firmware upgrade error: not in IDLE state (current: %d)\n", g_upgrade_status.state);
response[0] = STATUS_FAIL;
send_firmware_upgrade_response(FIRMWARE_UPGRADE_START, response, 1);
return STATUS_FAIL;
}
uint32_t firmware_size = data[2] | (data[3] << 8) | (data[4] << 16) | (data[5] << 24);
debug_printf("g_first_page_write_executed: %d\n", g_first_page_write_executed);
if (firmware_size == 0 || firmware_size > FLASH_MAX_UPGRADE_SIZE) {
debug_printf("Firmware upgrade error: invalid size %lu\n", firmware_size);
response[0] = STATUS_SIZE_INVALID;
send_firmware_upgrade_response(FIRMWARE_UPGRADE_START, response, 1);
return STATUS_SIZE_INVALID;
}
uint32_t aligned_size = ((firmware_size + FLASH_PAGE_SIZE - 1) / FLASH_PAGE_SIZE) * FLASH_PAGE_SIZE;
if (dfu_flash_cmd_init() != 0) {
debug_printf("Firmware upgrade error: flash init failed\n");
response[0] = STATUS_FAIL;
send_firmware_upgrade_response(FIRMWARE_UPGRADE_START, response, 1);
return STATUS_FAIL;
}
if (g_first_page_write_executed == 0 && g_flash_erased == 0) {
debug_printf("Force upgrade: erasing existing upgrade image\n");
dfu_flash_cmd_erase_all();
g_flash_erased = 1;
} else {
debug_printf("Force upgrade: erase skipped (already erased or begin_write started)\n");
}
g_upgrade_status.state = UPGRADE_PREPARING;
g_upgrade_status.firmware_size = aligned_size;
g_upgrade_status.total_blocks = (aligned_size + MAX_DATA_BLOCK_SIZE - 1) / MAX_DATA_BLOCK_SIZE;
g_upgrade_status.received_blocks = 0;
g_upgrade_status.expected_block_num = 0;
g_upgrade_status.error_code = 0;
memset(g_upgrade_status.page_buf.buffer, 0, FLASH_PAGE_SIZE);
g_upgrade_status.page_buf.offset = 0;
g_upgrade_status.page_buf.total_pages = aligned_size / FLASH_PAGE_SIZE;
g_upgrade_status.page_buf.written_pages = 0;
if (g_first_page_write_executed == 0) {
debug_printf("Firmware upgrade: executing first page write command (flag=0) in START...\n");
unsigned char cmd_data[16];
memset(cmd_data, 0, sizeof(cmd_data));
cmd_data[0] = 0;
if (dfu_flash_cmd_write_page(cmd_data) != 0) {
debug_printf("Firmware upgrade error: first page write command failed (begin_write error)\n");
dfu_flash_cmd_deinit();
g_upgrade_status.state = UPGRADE_IDLE;
response[0] = STATUS_FAIL;
send_firmware_upgrade_response(FIRMWARE_UPGRADE_START, response, 1);
return STATUS_FAIL;
}
g_first_page_write_executed = 1;
debug_printf("Firmware upgrade: first page write command completed\n");
} else {
debug_printf("Firmware upgrade: first page write command already executed in ERASE, skipping %d\n", g_first_page_write_executed);
}
g_upgrade_status.first_page_written = 1;
response[0] = STATUS_SUCCESS;
response[1] = (aligned_size >> 0) & 0xFF;
response[2] = (aligned_size >> 8) & 0xFF;
response[3] = (aligned_size >> 16) & 0xFF;
response[4] = (aligned_size >> 24) & 0xFF;
response[5] = (g_upgrade_status.total_blocks >> 0) & 0xFF;
response[6] = (g_upgrade_status.total_blocks >> 8) & 0xFF;
send_firmware_upgrade_response(FIRMWARE_UPGRADE_START, response, 7);
g_firmware_upgrade_mcu_notify = 1;
g_in_fw_upgrade = 1;
return STATUS_SUCCESS;
}
// 处理DATA命令
unsigned char handle_firmware_upgrade_data(uint8_t data[], uint16_t len)
{
uint8_t response[64] = {0};
if (g_upgrade_status.state != UPGRADE_PREPARING && g_upgrade_status.state != UPGRADE_TRANSFERRING) {
debug_printf("Firmware upgrade error: not in PREPARING or TRANSFERRING state (current: %d)\n", g_upgrade_status.state);
response[0] = STATUS_FAIL;
send_firmware_upgrade_response(FIRMWARE_UPGRADE_DATA, response, 1);
return STATUS_FAIL;
}
uint16_t block_num = data[2] | (data[3] << 8);
uint8_t data_len = data[4];
if (data_len != MAX_DATA_BLOCK_SIZE) {
debug_printf("Firmware upgrade error: invalid data length %d (must be %d)\n", data_len, MAX_DATA_BLOCK_SIZE);
response[0] = STATUS_SIZE_INVALID;
send_firmware_upgrade_response(FIRMWARE_UPGRADE_DATA, response, 1);
return STATUS_SIZE_INVALID;
}
if (block_num != g_upgrade_status.expected_block_num) {
debug_printf("Firmware upgrade error: block number mismatch (expected: %d, got: %d)\n",
g_upgrade_status.expected_block_num, block_num);
response[0] = STATUS_BLOCK_NUM_ERROR;
response[1] = (g_upgrade_status.expected_block_num >> 0) & 0xFF;
response[2] = (g_upgrade_status.expected_block_num >> 8) & 0xFF;
send_firmware_upgrade_response(FIRMWARE_UPGRADE_DATA, response, 3);
return STATUS_BLOCK_NUM_ERROR;
}
uint8_t received_checksum = data[5 + data_len];
uint8_t calculated_checksum = check_sum(data, 5 + data_len);
if (received_checksum != calculated_checksum) {
debug_printf("Firmware upgrade error: checksum mismatch (expected: 0x%02x, got: 0x%02x)\n",
calculated_checksum, received_checksum);
response[0] = STATUS_CHECKSUM_ERROR;
send_firmware_upgrade_response(FIRMWARE_UPGRADE_DATA, response, 1);
return STATUS_CHECKSUM_ERROR;
}
if (g_upgrade_status.state == UPGRADE_PREPARING) {
g_upgrade_status.state = UPGRADE_TRANSFERRING;
if (block_num == 0) {
if (g_first_page_write_executed == 0 && g_flash_erased == 0) {
debug_printf("Firmware upgrade: erasing existing upgrade image\n");
dfu_flash_cmd_erase_all();
g_flash_erased = 1;
}
}
}
uint16_t buf_offset = g_upgrade_status.page_buf.offset;
uint16_t remaining = FLASH_PAGE_SIZE - buf_offset;
uint16_t to_copy = (data_len < remaining) ? data_len : remaining;
memcpy(&g_upgrade_status.page_buf.buffer[buf_offset], &data[5], to_copy);
g_upgrade_status.page_buf.offset += to_copy;
if (g_upgrade_status.page_buf.offset >= FLASH_PAGE_SIZE) {
unsigned char cmd_data[16];
if (g_upgrade_status.page_buf.written_pages == 0) {
debug_printf("Firmware upgrade: writing first page data (flag=0 already executed in START)\n");
} else {
cmd_data[0] = 1;
dfu_flash_cmd_write_page(cmd_data);
}
for (int i = 0; i < 4; i++) {
dfu_flash_cmd_write_page_data(&g_upgrade_status.page_buf.buffer[i * 64]);
}
g_upgrade_status.page_buf.written_pages++;
g_upgrade_status.page_buf.offset = 0;
}
if (to_copy < data_len) {
uint16_t remaining_data = data_len - to_copy;
memcpy(&g_upgrade_status.page_buf.buffer[0], &data[5 + to_copy], remaining_data);
g_upgrade_status.page_buf.offset = remaining_data;
}
g_upgrade_status.received_blocks++;
g_upgrade_status.expected_block_num++;
response[0] = STATUS_SUCCESS;
response[1] = (block_num >> 0) & 0xFF;
response[2] = (block_num >> 8) & 0xFF;
send_firmware_upgrade_response(FIRMWARE_UPGRADE_DATA, response, 3);
return STATUS_SUCCESS;
}
// 处理END命令
unsigned char handle_firmware_upgrade_end(uint8_t data[], uint16_t len)
{
uint8_t response[64] = {0};
if (g_upgrade_status.state != UPGRADE_TRANSFERRING) {
debug_printf("Firmware upgrade error: not in TRANSFERRING state (current: %d)\n", g_upgrade_status.state);
response[0] = STATUS_FAIL;
send_firmware_upgrade_response(FIRMWARE_UPGRADE_END, response, 1);
return STATUS_FAIL;
}
g_upgrade_status.state = UPGRADE_COMPLETING;
uint32_t firmware_size = data[2] | (data[3] << 8) | (data[4] << 16) | (data[5] << 24);
debug_printf("Firmware upgrade END: firmware_size=%lu\n", firmware_size);
if (g_upgrade_status.page_buf.offset > 0) {
for (uint16_t i = g_upgrade_status.page_buf.offset; i < FLASH_PAGE_SIZE; i++) {
g_upgrade_status.page_buf.buffer[i] = 0x00;
}
unsigned char cmd_data[16];
cmd_data[0] = 1;
dfu_flash_cmd_write_page(cmd_data);
for (int i = 0; i < 4; i++) {
dfu_flash_cmd_write_page_data(&g_upgrade_status.page_buf.buffer[i * 64]);
}
g_upgrade_status.page_buf.written_pages++;
debug_printf("Firmware upgrade: last page written (total pages: %d)\n",
g_upgrade_status.page_buf.written_pages);
}
unsigned char cmd_data[16];
cmd_data[0] = 2;
int result = dfu_flash_cmd_write_page(cmd_data);
if (result != 0) {
debug_printf("Firmware upgrade error: flash write termination failed\n");
g_upgrade_status.state = UPGRADE_ERROR;
g_upgrade_status.error_code = STATUS_FAIL;
response[0] = STATUS_FAIL;
send_firmware_upgrade_response(FIRMWARE_UPGRADE_END, response, 1);
return STATUS_FAIL;
}
debug_printf("Firmware upgrade: image verification passed\n");
g_upgrade_status.state = UPGRADE_COMPLETED;
response[0] = STATUS_SUCCESS;
send_firmware_upgrade_response(FIRMWARE_UPGRADE_END, response, 1);
debug_printf("Firmware upgrade completed successfully\n");
g_firmware_upgrade_mcu_notify = 2;
g_in_fw_upgrade = 0;
g_upgrade_status.state = UPGRADE_IDLE;
return STATUS_SUCCESS;
}
// 处理STATUS命令
unsigned char handle_firmware_upgrade_status(uint8_t data[], uint16_t len)
{
uint8_t response[64] = {0};
response[0] = (uint8_t)g_upgrade_status.state;
response[1] = (g_upgrade_status.received_blocks >> 0) & 0xFF;
response[2] = (g_upgrade_status.received_blocks >> 8) & 0xFF;
response[3] = (g_upgrade_status.total_blocks >> 0) & 0xFF;
response[4] = (g_upgrade_status.total_blocks >> 8) & 0xFF;
response[5] = (g_upgrade_status.page_buf.written_pages >> 0) & 0xFF;
response[6] = (g_upgrade_status.page_buf.written_pages >> 8) & 0xFF;
response[7] = (g_upgrade_status.page_buf.total_pages >> 0) & 0xFF;
response[8] = (g_upgrade_status.page_buf.total_pages >> 8) & 0xFF;
uint32_t bytes_transferred = g_upgrade_status.received_blocks * MAX_DATA_BLOCK_SIZE;
response[9] = (bytes_transferred >> 0) & 0xFF;
response[10] = (bytes_transferred >> 8) & 0xFF;
response[11] = (bytes_transferred >> 16) & 0xFF;
response[12] = (bytes_transferred >> 24) & 0xFF;
response[13] = (g_upgrade_status.firmware_size >> 0) & 0xFF;
response[14] = (g_upgrade_status.firmware_size >> 8) & 0xFF;
response[15] = (g_upgrade_status.firmware_size >> 16) & 0xFF;
response[16] = (g_upgrade_status.firmware_size >> 24) & 0xFF;
response[17] = g_upgrade_status.error_code;
send_firmware_upgrade_response(FIRMWARE_UPGRADE_STATUS, response, 18);
return STATUS_SUCCESS;
}
// 处理ABORT命令
unsigned char handle_firmware_upgrade_abort(uint8_t data[], uint16_t len)
{
uint8_t response[64] = {0};
uint8_t erase_flag = data[2];
debug_printf("Firmware upgrade ABORT: erase_flag=0x%02x\n", erase_flag);
if (erase_flag == 0x01) {
debug_printf("Firmware upgrade: erasing written data\n");
dfu_flash_cmd_erase_all();
}
dfu_flash_cmd_deinit();
firmware_upgrade_reset();
g_upgrade_status.state = UPGRADE_ABORTED;
response[0] = STATUS_SUCCESS;
send_firmware_upgrade_response(FIRMWARE_UPGRADE_ABORT, response, 1);
g_firmware_upgrade_mcu_notify = 3;
g_in_fw_upgrade = 0;
g_upgrade_status.state = UPGRADE_IDLE;
return STATUS_SUCCESS;
}
// 处理ERASE命令
unsigned char handle_firmware_upgrade_erase(uint8_t data[], uint16_t len)
{
uint8_t response[64] = {0};
debug_printf("Firmware upgrade ERASE: erasing all upgrade images\n");
if (dfu_flash_cmd_init() != 0) {
debug_printf("Firmware upgrade error: flash init failed\n");
response[0] = STATUS_FAIL;
send_firmware_upgrade_response(FIRMWARE_UPGRADE_ERASE, response, 1);
return STATUS_FAIL;
}
if (g_first_page_write_executed == 0 && g_flash_erased == 0) {
dfu_flash_cmd_erase_all();
g_flash_erased = 1;
} else {
debug_printf("Firmware upgrade ERASE: erase skipped (already erased or begin_write started)\n");
}
dfu_flash_cmd_deinit();
response[0] = STATUS_SUCCESS;
send_firmware_upgrade_response(FIRMWARE_UPGRADE_ERASE, response, 1);
return STATUS_SUCCESS;
}
// 固件升级主处理函数分发0xA7-0xAC0xAE由eq.c直接处理
unsigned char process_firmware_upgrade_cmd(uint8_t data[], uint16_t len)
{
if (data[0] != 0x77) {
debug_printf("Firmware upgrade error: invalid sync header 0x%02x\n", data[0]);
return STATUS_FAIL;
}
uint8_t cmd = data[1];
debug_printf("Firmware upgrade command: 0x%02x\n", cmd);
switch (cmd) {
case FIRMWARE_UPGRADE_START:
return handle_firmware_upgrade_start(data, len);
case FIRMWARE_UPGRADE_DATA:
return handle_firmware_upgrade_data(data, len);
case FIRMWARE_UPGRADE_END:
return handle_firmware_upgrade_end(data, len);
case FIRMWARE_UPGRADE_STATUS:
return handle_firmware_upgrade_status(data, len);
case FIRMWARE_UPGRADE_ABORT:
return handle_firmware_upgrade_abort(data, len);
case FIRMWARE_UPGRADE_ERASE:
return handle_firmware_upgrade_erase(data, len);
default:
debug_printf("Firmware upgrade error: unknown command 0x%02x\n", cmd);
return STATUS_FAIL;
}
}
#endif // HID_DFU_EN

View File

@@ -0,0 +1,156 @@
// Copyright 2026 Shanling.
// HID固件升级头文件
// 改动原因实现通过HID协议进行固件升级的功能提供高效、稳定、安全的升级方案
#ifndef _DFU_UPGRADE_H_
#define _DFU_UPGRADE_H_
#include <stdint.h>
// 固件升级命令定义
#define FIRMWARE_UPGRADE_START 0xA7 // 开始固件升级
#define FIRMWARE_UPGRADE_DATA 0xA8 // 传输固件数据块
#define FIRMWARE_UPGRADE_END 0xA9 // 结束固件升级
#define FIRMWARE_UPGRADE_STATUS 0xAA // 获取升级状态
#define FIRMWARE_UPGRADE_ABORT 0xAB // 中止固件升级
#define FIRMWARE_UPGRADE_ERASE 0xAC // 擦除现有升级镜像
#define DEVICE_REBOOT 0xAE // 设备重启(通用命令,不仅限于固件升级)
// 升级状态定义
typedef enum {
UPGRADE_IDLE = 0x00, // 空闲状态,未开始升级
UPGRADE_PREPARING = 0x01, // 准备状态已调用START
UPGRADE_TRANSFERRING = 0x02, // 传输状态,正在接收数据
UPGRADE_COMPLETING = 0x03, // 完成中,正在写入最后一页
UPGRADE_COMPLETED = 0x04, // 已完成,升级成功
UPGRADE_ERROR = 0x05, // 错误状态,升级失败
UPGRADE_ABORTED = 0x06 // 已中止,升级被中止
} upgrade_state_t;
// 状态码定义
#define STATUS_SUCCESS 0x00 // 成功
#define STATUS_FAIL 0x01 // 失败
#define STATUS_SPACE_INSUFFICIENT 0x02 // Flash空间不足
#define STATUS_SIZE_INVALID 0x03 // 大小无效
#define STATUS_BLOCK_NUM_ERROR 0x04 // 块序号错误
#define STATUS_CHECKSUM_ERROR 0x05 // Checksum错误
#define STATUS_DATA_INCOMPLETE 0x06 // 数据不完整
#define STATUS_VERSION_INVALID 0x08 // 版本号无效
#define STATUS_SIZE_MISMATCH 0x09 // 大小不匹配
// Flash参数
#define FLASH_PAGE_SIZE 256 // Flash页大小
// 改动原因修正最大数据块大小HID数据包63字节不包括Report ID
// 数据包格式:同步头(1) + 命令码(1) + 块序号(2) + 数据长度(1) + 数据(N) + Checksum(1)
// 所以最大数据长度 = 63 - 5(头部) - 1(Checksum) = 57字节
#define MAX_DATA_BLOCK_SIZE 57 // 最大数据块大小63字节HID数据包 - 5字节头部 - 1字节Checksum
#define FLASH_MAX_UPGRADE_SIZE (2000 * 1024) // 最大固件大小1400KB
// 页缓冲区结构
typedef struct {
uint8_t buffer[FLASH_PAGE_SIZE]; // Flash页缓冲区
uint16_t offset; // 当前偏移
uint16_t total_pages; // 总页数
uint16_t written_pages; // 已写入页数
} page_buffer_t;
// 升级状态结构
typedef struct {
upgrade_state_t state; // 当前状态
uint32_t firmware_size; // 固件总大小
uint16_t total_blocks; // 总块数
uint16_t received_blocks; // 已接收块数
uint16_t expected_block_num; // 期望的块序号
// 改动原因:去掉固件版本号字段,不再存储版本号
uint8_t error_code; // 错误码
page_buffer_t page_buf; // 页缓冲区
uint8_t first_page_written; // 第一页写命令是否已执行0=未执行1=已执行)
} upgrade_status_t;
// 固件升级主处理函数
// 改动原因处理HID固件升级命令支持START、DATA、END等命令
// 参数:
// - data: HID数据包63字节不包括Report ID
// - len: 数据长度
// 返回值0=成功非0=失败
unsigned char process_firmware_upgrade_cmd(uint8_t data[], uint16_t len);
/* 改动原因:声明 DFU channel 转发函数,供 eq.c (process_send_params) 调用,
* 将 HID 固件升级命令通过 streaming channel 转发到 uart_handler 处理。
* 实现在 audiohw.xc 中。 */
void dfu_chan_forward(unsigned char data[], unsigned len);
// 各个固件升级命令的独立处理函数
// 改动原因在eq.c中为每个命令添加独立处理支持HID一条一条指令发送
// 参数:
// - data: HID数据包63字节不包括Report ID
// - len: 数据长度
// 返回值0=成功非0=失败(状态码)
unsigned char handle_firmware_upgrade_start(uint8_t data[], uint16_t len);
unsigned char handle_firmware_upgrade_data(uint8_t data[], uint16_t len);
unsigned char handle_firmware_upgrade_end(uint8_t data[], uint16_t len);
unsigned char handle_firmware_upgrade_status(uint8_t data[], uint16_t len);
unsigned char handle_firmware_upgrade_abort(uint8_t data[], uint16_t len);
unsigned char handle_firmware_upgrade_erase(uint8_t data[], uint16_t len);
// 发送固件升级响应(主动上报)
// 改动原因通过HID主动上报机制发送响应与音量上报机制一致
// 参数:
// - cmd: 命令码
// - response_data: 响应数据
// - data_len: 响应数据长度
void send_firmware_upgrade_response(uint8_t cmd, uint8_t *response_data, uint16_t data_len);
// 升级进行中标志升级期间阻止其他HID主动上报
extern unsigned g_in_fw_upgrade;
// 初始化固件升级模块
// 改动原因:初始化升级状态和缓冲区
void firmware_upgrade_init(void);
// 获取当前升级状态
// 改动原因:供外部查询当前升级状态
upgrade_state_t firmware_upgrade_get_state(void);
// 重置升级状态
// 改动原因:升级完成或中止后重置状态
void firmware_upgrade_reset(void);
// ====================== UART DFU 友好接口 ======================
// 改动原因:为 UART 串口升级提供不依赖 g_hid_pass_data 的接口,
// 内部仍然复用 HID DFU 的状态机和 Flash 写入流程。
//
// 这些函数只操作内部的 g_upgrade_status并通过参数返回需要的字段
// 方便 user_uart.xc 根据 UART 协议打包响应。
// UART 版 START输入固件原始大小返回对齐后的大小和总块数
unsigned char uart_firmware_upgrade_start(uint32_t firmware_size,
uint32_t *aligned_size_out,
uint16_t *total_blocks_out);
// UART 版 DATA输入块号和数据返回状态码和“确认的块号”成功时等于块号序号错误时为期望块号
unsigned char uart_firmware_upgrade_data(uint16_t block_num,
uint8_t data_len,
const uint8_t *data,
uint16_t *confirmed_block_out);
// UART 版 END结束升级写入最后一页并终止 Flash 写入
unsigned char uart_firmware_upgrade_end(uint32_t firmware_size);
// UART 版 STATUS直接从 g_upgrade_status 中读取当前状态和进度
unsigned char uart_firmware_upgrade_status(uint8_t *state_out,
uint16_t *received_blocks_out,
uint16_t *total_blocks_out,
uint16_t *written_pages_out,
uint16_t *total_pages_out,
uint32_t *bytes_transferred_out,
uint32_t *firmware_size_out,
uint8_t *error_code_out);
// UART 版 ABORT中止升级可选择是否擦除已写入数据
unsigned char uart_firmware_upgrade_abort(uint8_t erase_flag);
// UART 版 ERASE擦除现有 upgrade image 并执行 begin_write 初始化
unsigned char uart_firmware_upgrade_erase(void);
#endif // _DFU_UPGRADE_H_

View File

@@ -9,6 +9,10 @@
extern void device_reboot(void); extern void device_reboot(void);
#if HID_DFU_EN
#include "dfu_upgrade.h"
#endif
// 常量定义 // 常量定义
#define EQ_DISABLED_MODE 10 // 禁用EQ的模式编号 #define EQ_DISABLED_MODE 10 // 禁用EQ的模式编号
@@ -805,6 +809,39 @@ unsigned char process_send_params(uint8_t data[], uint16_t len) {
} }
#endif // #if EQ_EN (for process_send_params EQ commands section starting at line 1228) #endif // #if EQ_EN (for process_send_params EQ commands section starting at line 1228)
#if HID_DFU_EN
// 0xA7 START: 转发到button_task (tile[0])执行因为flash访问需要在tile[0]进行
if (data[1] == FIRMWARE_UPGRADE_START) {
dfu_chan_forward(data, len);
return true;
}
// 0xA8 DATA / 0xA9 END / 0xAA STATUS / 0xAB ABORT / 0xAC ERASE: 直接处理
if (data[1] >= FIRMWARE_UPGRADE_DATA && data[1] <= FIRMWARE_UPGRADE_ERASE) {
unsigned char result;
if (data[1] == FIRMWARE_UPGRADE_DATA)
result = handle_firmware_upgrade_data(data, len);
else if (data[1] == FIRMWARE_UPGRADE_END)
result = handle_firmware_upgrade_end(data, len);
else if (data[1] == FIRMWARE_UPGRADE_STATUS)
result = handle_firmware_upgrade_status(data, len);
else if (data[1] == FIRMWARE_UPGRADE_ABORT)
result = handle_firmware_upgrade_abort(data, len);
else
result = handle_firmware_upgrade_erase(data, len);
(void)result;
return true;
}
#endif
// 0xAE DEVICE_REBOOT (通用命令,不仅限于固件升级)
if (data[1] == 0xAE) {
debug_printf("Received device REBOOT command (0xAE)\n");
device_reboot();
while(1);
return true;
}
return true; return true;
} }
@@ -880,17 +917,6 @@ void init_mode_info(void) {
#endif #endif
void get_key_ret(uint8_t *buffer); void get_key_ret(uint8_t *buffer);
extern unsigned char g_hid_status_report_data[63];
extern unsigned int g_hid_status_report_index;
void user_read_hid_status(unsigned char hidPassData[])
{
if (g_hid_status_report_index > 0) {
memcpy(hidPassData, g_hid_status_report_data, 63);
g_hid_status_report_index = 0;
} else {
memset(hidPassData, 0, 63);
}
}
// process_read_params: build HID response from pending request state // process_read_params: build HID response from pending request state
unsigned char process_read_params(uint8_t response[]) { unsigned char process_read_params(uint8_t response[]) {

View File

@@ -2,7 +2,7 @@ from PySide6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout,
QHBoxLayout, QPushButton, QComboBox, QLabel, QHBoxLayout, QPushButton, QComboBox, QLabel,
QScrollArea, QSplitter, QGroupBox, QFormLayout, QScrollArea, QSplitter, QGroupBox, QFormLayout,
QDoubleSpinBox, QCheckBox, QLineEdit, QSpinBox, QDoubleSpinBox, QCheckBox, QLineEdit, QSpinBox,
QMessageBox, QMenuBar, QMenu) QMessageBox, QMenuBar, QMenu, QFileDialog, QProgressBar)
from PySide6.QtCore import Qt, QObject, Signal, Slot, QTimer from PySide6.QtCore import Qt, QObject, Signal, Slot, QTimer
import numpy as np import numpy as np
import matplotlib import matplotlib
@@ -55,6 +55,14 @@ from filter_utils import (BiquadFilterCalculator, make_biquad_bypass, make_biqua
MAX_EQ_BANDS = 8 # 最大EQ滤波器数量 (0-7) MAX_EQ_BANDS = 8 # 最大EQ滤波器数量 (0-7)
NUM_EQ_MODES = 12 # EQ模式数量10预设 + 2用户 NUM_EQ_MODES = 12 # EQ模式数量10预设 + 2用户
EQ_DISABLED_MODE = 12 # 禁用EQ的模式编号 EQ_DISABLED_MODE = 12 # 禁用EQ的模式编号
# HID 固件升级命令码(使用命令名代替裸命令码)
FIRMWARE_UPGRADE_START = 0xA7 # 开始固件升级
FIRMWARE_UPGRADE_DATA = 0xA8 # 传输固件数据块
FIRMWARE_UPGRADE_END = 0xA9 # 结束固件升级
FIRMWARE_UPGRADE_STATUS = 0xAA # 获取升级状态
FIRMWARE_UPGRADE_ABORT = 0xAB # 中止固件升级
FIRMWARE_UPGRADE_ERASE = 0xAC # 擦除现有升级镜像
DEVICE_REBOOT = 0xAE # 设备重启(通用命令)
class BandFilter(QGroupBox): class BandFilter(QGroupBox):
"""单个滤波器带控件""" """单个滤波器带控件"""
@@ -457,7 +465,7 @@ class EQDesigner(QMainWindow):
sample_rate_layout = QHBoxLayout() sample_rate_layout = QHBoxLayout()
sample_rate_layout.addWidget(QLabel("采样率:")) sample_rate_layout.addWidget(QLabel("采样率:"))
self.sample_rate = QComboBox() self.sample_rate = QComboBox()
self.sample_rate.addItems(["44100", "48000", "88200", "96000", "176400", "192000"]) self.sample_rate.addItems(["44100"]) # 只保留44100Hz其他采样率使用相同参数
self.sample_rate.currentTextChanged.connect(self.on_sample_rate_changed) self.sample_rate.currentTextChanged.connect(self.on_sample_rate_changed)
sample_rate_layout.addWidget(self.sample_rate) sample_rate_layout.addWidget(self.sample_rate)
left_content_layout.addLayout(sample_rate_layout) left_content_layout.addLayout(sample_rate_layout)
@@ -734,7 +742,68 @@ class EQDesigner(QMainWindow):
left_content_layout.addWidget(eq_enable_group) left_content_layout.addWidget(eq_enable_group)
# 添加EX3D控制组
# 添加固件升级控制组
# 改动原因添加HID固件升级功能支持通过HID协议升级设备固件
firmware_upgrade_group = QGroupBox("固件升级")
self.ui_groups['firmware'] = firmware_upgrade_group # 保存引用
firmware_upgrade_layout = QFormLayout(firmware_upgrade_group)
# 固件文件选择
firmware_file_layout = QHBoxLayout()
self.firmware_file_edit = QLineEdit()
self.firmware_file_edit.setPlaceholderText("选择固件文件...")
firmware_file_layout.addWidget(self.firmware_file_edit)
browse_btn = QPushButton("浏览")
browse_btn.clicked.connect(self.on_browse_firmware)
firmware_file_layout.addWidget(browse_btn)
firmware_upgrade_layout.addRow("固件文件:", firmware_file_layout)
# 升级进度条
self.firmware_progress = QProgressBar()
self.firmware_progress.setRange(0, 100)
self.firmware_progress.setValue(0)
firmware_upgrade_layout.addRow("升级进度:", self.firmware_progress)
# 状态标签
self.firmware_status_label = QLabel("状态: 空闲")
firmware_upgrade_layout.addRow("当前状态:", self.firmware_status_label)
# 固件升级按钮
firmware_buttons_layout = QVBoxLayout()
# 擦除upgrade image按钮
self.erase_upgrade_btn = QPushButton("擦除现有升级镜像")
self.erase_upgrade_btn.clicked.connect(self.on_erase_upgrade_image)
firmware_buttons_layout.addWidget(self.erase_upgrade_btn)
# 开始升级按钮
self.start_upgrade_btn = QPushButton("开始固件升级")
self.start_upgrade_btn.clicked.connect(self.on_start_firmware_upgrade)
firmware_buttons_layout.addWidget(self.start_upgrade_btn)
# 查询升级状态按钮
self.status_upgrade_btn = QPushButton("查询升级状态")
self.status_upgrade_btn.clicked.connect(self.on_get_firmware_upgrade_status)
firmware_buttons_layout.addWidget(self.status_upgrade_btn)
# 中止升级按钮
self.abort_upgrade_btn = QPushButton("中止固件升级")
self.abort_upgrade_btn.clicked.connect(self.on_abort_firmware_upgrade)
firmware_buttons_layout.addWidget(self.abort_upgrade_btn)
# 验证镜像按钮
# 重启设备按钮
self.reboot_device_btn = QPushButton("重启设备")
self.reboot_device_btn.clicked.connect(self.on_reboot_device)
firmware_buttons_layout.addWidget(self.reboot_device_btn)
firmware_upgrade_layout.addRow(firmware_buttons_layout)
left_content_layout.addWidget(firmware_upgrade_group)
ex3d_group = QGroupBox("EX3D控制") ex3d_group = QGroupBox("EX3D控制")
self.ui_groups['ex3d'] = ex3d_group # 保存引用 self.ui_groups['ex3d'] = ex3d_group # 保存引用
ex3d_layout = QVBoxLayout(ex3d_group) ex3d_layout = QVBoxLayout(ex3d_group)
@@ -880,7 +949,8 @@ class EQDesigner(QMainWindow):
'volume': '音量控制', 'volume': '音量控制',
'device_mode': '音效模式控制', 'device_mode': '音效模式控制',
'eq_enable': 'EQ使能控制', 'eq_enable': 'EQ使能控制',
'ex3d': 'EX3D控制' 'ex3d': 'EX3D控制',
'firmware': '固件升级'
} }
# 为每组创建切换可见性的动作 # 为每组创建切换可见性的动作
@@ -907,7 +977,8 @@ class EQDesigner(QMainWindow):
'volume': '音量控制', 'volume': '音量控制',
'device_mode': '音效模式控制', 'device_mode': '音效模式控制',
'eq_enable': 'EQ使能控制', 'eq_enable': 'EQ使能控制',
'ex3d': 'EX3D控制' 'ex3d': 'EX3D控制',
'firmware': '固件升级'
} }
name = group_names.get(group_key, group_key) name = group_names.get(group_key, group_key)
self.view_actions[group_key].setText(f"{'显示' if visible else '隐藏'} {name}") self.view_actions[group_key].setText(f"{'显示' if visible else '隐藏'} {name}")
@@ -1662,108 +1733,17 @@ eq_mode_data_t sEQ_data_{int(fs)}HZ[NUM_EQ_MODES][NUM_EQ_CHANS] = {{
band.update_coefficients() band.update_coefficients()
def apply_to_all_sample_rates(self): def apply_to_all_sample_rates(self):
"""将当前EQ参数应用到所有采样率""" """将当前EQ参数应用到所有采样率
改动原因现在所有采样率共用44100Hz参数此函数只需保存44100Hz参数即可
"""
try: try:
# 获取当前模式 # 改动原因所有采样率共用44100Hz参数直接保存当前参数即可
current_mode = self.current_mode log_message(LOG_LEVEL_INFO, "现在所有采样率共用44100Hz参数直接保存当前参数", self.log_level)
self.save_parameters() # 直接保存当前参数44100Hz
# 获取所有可用的采样率 log_message(LOG_LEVEL_INFO, "参数已保存(适用于所有采样率)", self.log_level)
sample_rates = [float(self.sample_rate.itemText(i)) for i in range(self.sample_rate.count())]
# 保存当前采样率
current_fs = float(self.sample_rate.currentText())
# 遍历所有采样率
for fs in sample_rates:
log_message(LOG_LEVEL_INFO, f"正在处理采样率: {fs}Hz", self.log_level)
# 临时切换到目标采样率
self.sample_rate.setCurrentText(str(int(fs)))
# 计算总的bshift
total_bshift = sum(band.get_bshift() for band in self.bands)
# 生成JSON文件名
json_filename = f"eq_parameters_{int(fs)}_mode{current_mode}.json"
# 读取现有的JSON文件如果存在
all_params = {}
if os.path.exists(json_filename):
with open(json_filename, "r", encoding='utf-8') as f:
all_params = json.load(f)
# 更新当前mode的参数
params = {
"sample_rate": fs,
"mode": current_mode, # 保存当前模式
"total_bshift": total_bshift,
"post_gain_db": int(self.post_gain_spin.value()),
"bands": []
}
# 计算每个band的参数
for band in self.bands:
band_params = band.get_parameters()
if band_params["enabled"]:
# 计算浮点系数
coeffs = band.calculate_coefficients(fs)
if coeffs is not None:
# 反转 b1 和 b2 的符号
coeffs = np.array([
coeffs[0], # a0
coeffs[1], # a1
coeffs[2], # a2
-coeffs[3], # b1
-coeffs[4] # b2
])
band_scale_factor = band.get_scale_factor()
# 只对 a0, a1, a2 乘以 scale_factor
coeffs_scaled = np.array([
coeffs[0] * band_scale_factor,
coeffs[1] * band_scale_factor,
coeffs[2] * band_scale_factor,
coeffs[3],
coeffs[4]
])
coeffs_q30 = (coeffs_scaled * 2**30).astype(np.int32)
band_params["coefficients"] = {
"float": coeffs.tolist(),
"q30": [f"0x{int(x):08x}" if x >= 0 else f"-0x{int(-x):08x}" for x in coeffs_q30]
}
params["bands"].append(band_params)
# 保存当前mode的参数
all_params[f"mode_{current_mode}"] = params
# 保存JSON文件
with open(json_filename, "w", encoding='utf-8') as f:
json.dump(all_params, f, indent=2, ensure_ascii=False)
# 生成头文件
self.save_parameters() # 这会自动生成头文件
log_message(LOG_LEVEL_INFO, f"已保存采样率 {fs}Hz 的参数", self.log_level)
# 恢复原始采样率
self.sample_rate.setCurrentText(str(int(current_fs)))
log_message(LOG_LEVEL_INFO, "所有采样率的参数已保存完成", self.log_level)
# 检查是否所有模式都已生成
all_modes_generated = True
for mode in range(NUM_EQ_MODES):
mode_file = f"eq_params_{int(current_fs)}_mode{mode}.h"
if not os.path.exists(mode_file):
all_modes_generated = False
break
# 如果所有模式都已生成,合并成一个完整的头文件
if all_modes_generated:
self.merge_mode_files(current_fs)
except Exception as e: except Exception as e:
log_message(LOG_LEVEL_ERROR, f"应用到所有采样率时出错: {str(e)}", self.log_level) log_message(LOG_LEVEL_ERROR, f"保存参数时出错: {str(e)}", self.log_level)
import traceback import traceback
log_message(LOG_LEVEL_ERROR, "详细错误信息:", self.log_level) log_message(LOG_LEVEL_ERROR, "详细错误信息:", self.log_level)
traceback.print_exc() traceback.print_exc()
@@ -3497,6 +3477,671 @@ eq_mode_data_t sEQ_data_{int(fs)}HZ[NUM_EQ_MODES][NUM_EQ_CHANS] = {{
except Exception as e: except Exception as e:
log_message(LOG_LEVEL_ERROR, f"读取固件版本时出错: {str(e)}", self.log_level) log_message(LOG_LEVEL_ERROR, f"读取固件版本时出错: {str(e)}", self.log_level)
def on_browse_firmware(self):
"""浏览选择固件文件"""
# 改动原因:打开文件对话框选择固件文件
filename, _ = QFileDialog.getOpenFileName(
self,
"选择固件文件",
"",
"Firmware Files (*.bin *.xe);;All Files (*.*)"
)
if filename:
self.firmware_file_edit.setText(filename)
log_message(LOG_LEVEL_INFO, f"已选择固件文件: {filename}", self.log_level)
def calculate_checksum(self, data):
"""计算checksum参考user_func.c实现"""
# 改动原因实现checksum算法与设备端check_sum函数一致
sum_value = 0
for byte in data:
sum_value += byte
return sum_value % 256
def debug_print_hex(self, data, prefix="", max_bytes=64):
"""以16进制形式打印数据包
改动原因:添加调试打印功能,方便查看发送的命令和收到的响应
参数:
data: 要打印的数据bytes或bytearray
prefix: 前缀字符串(如"发送""接收"
max_bytes: 最大打印字节数
"""
if not data:
log_message(LOG_LEVEL_DEBUG, f"{prefix}: (空数据)", self.log_level)
return
# 限制打印长度
print_data = data[:max_bytes] if len(data) > max_bytes else data
# 转换为16进制字符串
hex_str = ' '.join([f'{b:02X}' for b in print_data])
# 如果数据被截断,添加提示
if len(data) > max_bytes:
hex_str += f" ... (共{len(data)}字节,仅显示前{max_bytes}字节)"
log_message(LOG_LEVEL_DEBUG, f"{prefix}: {hex_str}", self.log_level)
def wait_for_hid_response(self, h, expected_cmd, timeout=180.0, max_retries=5000):
"""等待设备主动上报的HID响应
改动原因:实现可靠的响应等待机制,确保每个命令发送后都等待设备响应后再继续
参数:
h: HID设备对象
expected_cmd: 期望的命令码如0xA7, 0xA8等
timeout: 超时时间(秒)
max_retries: 最大重试次数
返回:
响应数据包64字节如果超时返回None
"""
import time
start_time = time.time()
retry_count = 0
while retry_count < max_retries:
# 检查超时
if time.time() - start_time > timeout:
log_message(LOG_LEVEL_ERROR, f"等待命令0x{expected_cmd:02x}响应超时({timeout}秒)", self.log_level)
return None
# 改动原因使用中断端点读取主动上报数据避免HID_GET_REPORT返回非预期数据
# 使用hid.read读取中断IN端点数据长度64单位ms超时
reply = h.read(64, 50)
if reply and len(reply) == 64:
# 改动原因添加调试打印显示所有收到的HID报告用于调试
if retry_count % 10 == 0: # 每10次重试打印一次避免输出过多
self.debug_print_hex(reply, f"[等待响应] 收到HID报告 (期望命令0x{expected_cmd:02x})", max_bytes=64)
# 检查Report ID和同步头
if reply[0] == 0x01 and reply[1] == 0x77:
# 检查命令码
if reply[2] == expected_cmd:
log_message(LOG_LEVEL_DEBUG, f"收到命令0x{expected_cmd:02x}的响应", self.log_level)
return reply
else:
# 收到其他命令的响应,继续等待
log_message(LOG_LEVEL_DEBUG, f"收到其他命令0x{reply[2]:02x}的响应继续等待0x{expected_cmd:02x}", self.log_level)
# 短暂延迟后重试
time.sleep(0.05) # 50ms延迟
retry_count += 1
log_message(LOG_LEVEL_ERROR, f"等待命令0x{expected_cmd:02x}响应失败,已重试{max_retries}", self.log_level)
return None
def on_erase_upgrade_image(self):
"""擦除现有升级镜像发送FIRMWARE_UPGRADE_ERASE命令"""
# 改动原因擦除Flash中的现有upgrade image为新固件腾出空间
if self.device_combo.currentData() is None:
log_message(LOG_LEVEL_ERROR, "请先选择设备", self.log_level)
QMessageBox.warning(self, "错误", "请先选择设备")
return
# 确认对话框
reply = QMessageBox.question(
self,
"确认擦除",
"确定要擦除现有的升级镜像吗?\n\n"
"这将删除Flash中的upgrade image\n"
"但不会影响当前运行的固件。\n\n"
"是否继续?",
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No
)
if reply != QMessageBox.Yes:
return
try:
device_info = self.device_combo.currentData()
h = hid.device()
h.open(device_info['vendor_id'], device_info['product_id'])
h.set_nonblocking(1)
# 构建FIRMWARE_UPGRADE_ERASE命令数据包
data = bytearray(63)
data[0] = 0x77 # 同步头
data[1] = FIRMWARE_UPGRADE_ERASE # 命令码
log_message(LOG_LEVEL_INFO, "正在擦除现有升级镜像...", self.log_level)
# 改动原因添加调试打印显示发送的ERASE命令
send_packet = [0x01] + list(data)
self.debug_print_hex(send_packet, f"[发送] ERASE命令 (FIRMWARE_UPGRADE_ERASE)", max_bytes=64)
h.write(send_packet)
# 改动原因等待设备主动上报ERASE命令响应
reply = self.wait_for_hid_response(h, FIRMWARE_UPGRADE_ERASE, timeout=180.0)
# 改动原因添加调试打印显示收到的ERASE响应
if reply:
self.debug_print_hex(reply, f"[接收] ERASE响应 (FIRMWARE_UPGRADE_ERASE)", max_bytes=64)
if reply:
status = reply[3]
if status == 0x00:
log_message(LOG_LEVEL_INFO, "升级镜像擦除成功", self.log_level)
QMessageBox.information(self, "成功", "升级镜像已擦除")
else:
log_message(LOG_LEVEL_ERROR, f"升级镜像擦除失败,状态码: 0x{status:02x}", self.log_level)
QMessageBox.warning(self, "失败", f"升级镜像擦除失败\n状态码: 0x{status:02x}")
else:
log_message(LOG_LEVEL_ERROR, "ERASE命令响应超时", self.log_level)
QMessageBox.warning(self, "超时", "擦除命令响应超时")
h.close()
except Exception as e:
log_message(LOG_LEVEL_ERROR, f"擦除升级镜像时出错: {str(e)}", self.log_level)
QMessageBox.critical(self, "错误", f"擦除升级镜像时出错:\n{str(e)}")
def on_start_firmware_upgrade(self):
"""开始固件升级流程"""
# 改动原因实现HID固件升级的完整流程包括START、循环DATA、END命令
if self.device_combo.currentData() is None:
log_message(LOG_LEVEL_ERROR, "请先选择设备", self.log_level)
QMessageBox.warning(self, "错误", "请先选择设备")
return
firmware_file = self.firmware_file_edit.text()
if not firmware_file or not os.path.exists(firmware_file):
log_message(LOG_LEVEL_ERROR, "请选择有效的固件文件", self.log_level)
QMessageBox.warning(self, "错误", "请选择有效的固件文件")
return
# 确认对话框
reply = QMessageBox.question(
self,
"确认升级",
f"确定要升级固件吗?\n\n"
f"固件文件: {firmware_file}\n"
f"警告:升级过程中请勿断电或拔出设备!\n\n"
f"是否继续?",
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No
)
if reply != QMessageBox.Yes:
return
try:
import time
# 读取固件文件
with open(firmware_file, 'rb') as f:
firmware_data = f.read()
file_size = len(firmware_data)
# 页对齐到256字节
page_size = 256
file_size_padded = ((file_size + page_size - 1) // page_size) * page_size
log_message(LOG_LEVEL_INFO, f"固件文件大小: {file_size} 字节", self.log_level)
log_message(LOG_LEVEL_INFO, f"页对齐后大小: {file_size_padded} 字节", self.log_level)
device_info = self.device_combo.currentData()
h = hid.device()
h.open(device_info['vendor_id'], device_info['product_id'])
h.set_nonblocking(1)
# 步骤1: 发送START命令 (FIRMWARE_UPGRADE_START)
log_message(LOG_LEVEL_INFO, "发送START命令...", self.log_level)
self.firmware_status_label.setText("状态: 初始化中...")
QApplication.processEvents()
# 改动原因:去掉固件版本号和升级标志位,所有实现都是强制升级方式
data = bytearray(63)
data[0] = 0x77 # 同步头
data[1] = FIRMWARE_UPGRADE_START # 命令码
# 固件大小4字节小端序
data[2] = (file_size_padded >> 0) & 0xFF
data[3] = (file_size_padded >> 8) & 0xFF
data[4] = (file_size_padded >> 16) & 0xFF
data[5] = (file_size_padded >> 24) & 0xFF
# 其余字节为0保留字节
# 改动原因添加调试打印显示发送的START命令
send_packet = [0x01] + list(data)
self.debug_print_hex(send_packet, f"[发送] START命令 (FIRMWARE_UPGRADE_START)", max_bytes=64)
h.write(send_packet)
# 改动原因等待设备主动上报START命令响应确保收到响应后再继续
log_message(LOG_LEVEL_DEBUG, "等待START命令响应...", self.log_level)
reply = self.wait_for_hid_response(h, FIRMWARE_UPGRADE_START, timeout=180.0)
# 改动原因添加调试打印显示收到的START响应
if reply:
self.debug_print_hex(reply, f"[接收] START响应 (0xA7)", max_bytes=64)
if not reply:
raise Exception("START命令响应超时或无效")
status = reply[3]
if status != 0x00:
error_msgs = {
0x01: "初始化失败",
0x02: "Flash空间不足",
0x03: "固件大小无效"
}
raise Exception(f"START命令失败: {error_msgs.get(status, f'状态码0x{status:02x}')}")
# 改动原因:修正总块数读取位置,根据协议响应格式:
# reply[0]=Report ID, reply[1]=0x77, reply[2]=FIRMWARE_UPGRADE_START, reply[3]=状态码
# reply[4-7]=aligned_size(4字节), reply[8-9]=total_blocks(2字节)
total_blocks = reply[8] | (reply[9] << 8)
log_message(LOG_LEVEL_INFO, f"升级初始化成功,总块数: {total_blocks}", self.log_level)
# 步骤2: 循环发送DATA命令
# 改动原因HID数据包只有63字节不包括Report ID需要为Checksum留出空间
# 数据包格式:同步头(1) + 命令码(1) + 块序号(2) + 数据长度(1) + 数据(N) + Checksum(1)
# 所以最大数据长度 = 63 - 5(头部) - 1(Checksum) = 57字节
max_data_block_size = 57 # 最大数据块大小考虑Checksum空间
block_number = 0
sent_bytes = 0
self.firmware_status_label.setText("状态: 传输中...")
QApplication.processEvents()
while sent_bytes < file_size_padded:
# 改动原因数据长度固定为57字节最后一个块可能不足57字节用0填充
remaining = file_size_padded - sent_bytes
# 数据长度固定为57字节
data_len = max_data_block_size # 固定57字节
# 读取实际数据(如果还有数据的话)
if sent_bytes < file_size:
actual_read_len = min(data_len, file_size - sent_bytes)
block_data = firmware_data[sent_bytes:sent_bytes + actual_read_len]
# 如果实际读取的数据不足57字节用0填充到57字节
if actual_read_len < data_len:
block_data += bytes(data_len - actual_read_len) # 填充0
else:
# 如果已经超过实际文件大小全部填充0
block_data = bytes(data_len) # 全部填充0
# 构建DATA命令数据包
data = bytearray(63)
data[0] = 0x77 # 同步头
data[1] = FIRMWARE_UPGRADE_DATA # 命令码
data[2] = (block_number >> 0) & 0xFF # 块序号(小端序)
data[3] = (block_number >> 8) & 0xFF
data[4] = data_len # 数据长度
data[5:5+data_len] = block_data # 固件数据
# 计算Checksum同步头+命令码+块序号+数据长度+数据)
checksum_data = data[0:5+data_len]
checksum = self.calculate_checksum(checksum_data)
data[5+data_len] = checksum # Checksum位置5 + data_len最大62不会越界
# 改动原因添加调试打印显示发送的DATA命令每10个块打印一次避免输出过多
send_packet = [0x01] + list(data)
if block_number % 10 == 0 or block_number < 3:
self.debug_print_hex(send_packet, f"[发送] DATA命令 (FIRMWARE_UPGRADE_DATA) 块{block_number}", max_bytes=64)
# 发送DATA命令
h.write(send_packet)
# 改动原因等待设备主动上报DATA命令响应确保收到响应后再发送下一个数据块
reply = self.wait_for_hid_response(h, FIRMWARE_UPGRADE_DATA, timeout=180.0)
# 改动原因添加调试打印显示收到的DATA响应每10个块打印一次
if reply and (block_number % 10 == 0 or block_number < 3):
self.debug_print_hex(reply, f"[接收] DATA响应 (FIRMWARE_UPGRADE_DATA) 块{block_number}", max_bytes=64)
if not reply:
raise Exception(f"DATA命令响应超时块序号: {block_number}")
# 改动原因:响应格式已简化,只包含状态码和已确认的块序号,删除了已写入页数和总页数
# 验证响应
status = reply[3]
confirmed_block = reply[4] | (reply[5] << 8)
if status != 0x00:
error_msgs = {
0x01: "写入Flash失败",
0x02: f"块序号错误(期望: {confirmed_block}",
0x03: "Checksum校验失败",
0x04: "数据长度错误必须为57字节"
}
raise Exception(f"DATA命令失败: {error_msgs.get(status, f'状态码0x{status:02x}')}")
if confirmed_block != block_number:
raise Exception(f"块序号不匹配(发送: {block_number}, 确认: {confirmed_block}")
log_message(LOG_LEVEL_DEBUG, f"{block_number} 传输成功", self.log_level)
# 更新进度
sent_bytes += data_len
block_number += 1
progress = int((sent_bytes / file_size_padded) * 100)
self.firmware_progress.setValue(progress)
self.firmware_status_label.setText(f"状态: 传输中 ({block_number}/{total_blocks})")
QApplication.processEvents()
if block_number % 10 == 0:
log_message(LOG_LEVEL_INFO, f"已发送 {block_number}/{total_blocks}", self.log_level)
log_message(LOG_LEVEL_INFO, "数据传输完成", self.log_level)
# 步骤3: 发送END命令
self.firmware_status_label.setText("状态: 完成中...")
QApplication.processEvents()
data = bytearray(63)
data[0] = 0x77 # 同步头
data[1] = FIRMWARE_UPGRADE_END # 命令码
# 固件总大小4字节小端序
data[2] = (file_size_padded >> 0) & 0xFF
data[3] = (file_size_padded >> 8) & 0xFF
data[4] = (file_size_padded >> 16) & 0xFF
data[5] = (file_size_padded >> 24) & 0xFF
log_message(LOG_LEVEL_INFO, "发送END命令...", self.log_level)
# 改动原因添加调试打印显示发送的END命令
send_packet = [0x01] + list(data)
self.debug_print_hex(send_packet, f"[发送] END命令 (FIRMWARE_UPGRADE_END)", max_bytes=64)
h.write(send_packet)
# 改动原因等待设备主动上报END命令响应END命令需要更长时间写入最后一页并验证
log_message(LOG_LEVEL_DEBUG, "等待END命令响应可能需要较长时间...", self.log_level)
reply = self.wait_for_hid_response(h, FIRMWARE_UPGRADE_END, timeout=180.0) # END命令需要更长时间
# 改动原因添加调试打印显示收到的END响应
if reply:
self.debug_print_hex(reply, f"[接收] END响应 (FIRMWARE_UPGRADE_END)", max_bytes=64)
if not reply:
raise Exception("END命令响应超时或无效")
# 改动原因:响应格式已简化,只包含状态码,删除了已写入总块数和总页数
status = reply[3]
if status != 0x00:
error_msgs = {
0x01: "写入失败",
0x02: "数据不完整",
0x03: "镜像验证失败",
0x04: "版本号无效"
}
raise Exception(f"END命令失败: {error_msgs.get(status, f'状态码0x{status:02x}')}")
log_message(LOG_LEVEL_INFO, "升级完成", self.log_level)
h.close()
# 更新UI
self.firmware_progress.setValue(100)
self.firmware_status_label.setText("状态: 升级完成")
QMessageBox.information(
self,
"升级成功",
f"固件升级完成!\n\n"
f"请点击\"重启设备\"按钮重启设备以加载新固件。"
)
except Exception as e:
log_message(LOG_LEVEL_ERROR, f"固件升级失败: {str(e)}", self.log_level)
self.firmware_progress.setValue(0)
self.firmware_status_label.setText("状态: 升级失败")
QMessageBox.critical(self, "升级失败", f"固件升级失败:\n{str(e)}")
def on_verify_firmware_image(self):
"""验证固件镜像发送0xAD命令"""
# 改动原因验证Flash中已写入的固件镜像完整性
if self.device_combo.currentData() is None:
log_message(LOG_LEVEL_ERROR, "请先选择设备", self.log_level)
QMessageBox.warning(self, "错误", "请先选择设备")
return
try:
device_info = self.device_combo.currentData()
h = hid.device()
h.open(device_info['vendor_id'], device_info['product_id'])
h.set_nonblocking(1)
# 构建0xAD命令数据包
data = bytearray(63)
data[0] = 0x77 # 同步头
data[1] = 0xAD # 命令码 (FIRMWARE_UPGRADE_VERIFY)
# 固件大小0表示不校验大小
data[2] = 0x00
data[3] = 0x00
data[4] = 0x00
data[5] = 0x00
log_message(LOG_LEVEL_INFO, "正在验证固件镜像...", self.log_level)
# 改动原因添加调试打印显示发送的VERIFY命令
send_packet = [0x01] + list(data)
self.debug_print_hex(send_packet, f"[发送] VERIFY命令 (0xAD)", max_bytes=64)
h.write(send_packet)
# 改动原因等待设备主动上报VERIFY命令响应
reply = self.wait_for_hid_response(h, 0xAD, timeout=180.0)
# 改动原因添加调试打印显示收到的VERIFY响应
if reply:
self.debug_print_hex(reply, f"[接收] VERIFY响应 (0xAD)", max_bytes=64)
verify_result = reply[3]
image_size = reply[4] | (reply[5] << 8) | (reply[6] << 16) | (reply[7] << 24)
ver_major = reply[13]
ver_minor = reply[14]
ver_patch = reply[15]
if verify_result == 0x00:
log_message(LOG_LEVEL_INFO, "固件镜像验证通过", self.log_level)
QMessageBox.information(
self,
"验证成功",
f"固件镜像验证通过!\n\n"
f"镜像大小: {image_size} 字节\n"
f"镜像版本: {ver_major}.{ver_minor}.{ver_patch}"
)
else:
error_msgs = {
0x01: "镜像验证失败",
0x02: "版本号无效",
0x03: "大小不匹配"
}
log_message(LOG_LEVEL_ERROR, f"固件镜像验证失败: {error_msgs.get(verify_result, f'状态码0x{verify_result:02x}')}", self.log_level)
QMessageBox.warning(
self,
"验证失败",
f"固件镜像验证失败\n\n{error_msgs.get(verify_result, f'状态码0x{verify_result:02x}')}"
)
h.close()
except Exception as e:
log_message(LOG_LEVEL_ERROR, f"验证固件镜像时出错: {str(e)}", self.log_level)
QMessageBox.critical(self, "错误", f"验证固件镜像时出错:\n{str(e)}")
def on_reboot_device(self):
"""重启设备发送DEVICE_REBOOT命令"""
# 改动原因发送重启命令设备会重启并加载新的upgrade image
if self.device_combo.currentData() is None:
log_message(LOG_LEVEL_ERROR, "请先选择设备", self.log_level)
QMessageBox.warning(self, "错误", "请先选择设备")
return
# 确认对话框
reply = QMessageBox.question(
self,
"确认重启",
"确定要重启设备吗?\n\n"
"设备将重启并加载新的固件\n"
"如果upgrade image有效\n\n"
"是否继续?",
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No
)
if reply != QMessageBox.Yes:
return
try:
device_info = self.device_combo.currentData()
h = hid.device()
h.open(device_info['vendor_id'], device_info['product_id'])
h.set_nonblocking(1)
# 改动原因将固件升级专用的REBOOT命令改为通用的设备重启命令DEVICE_REBOOT
# 构建DEVICE_REBOOT命令数据包通用设备重启命令
data = bytearray(63)
data[0] = 0x77 # 同步头
data[1] = DEVICE_REBOOT # 命令码
log_message(LOG_LEVEL_INFO, "正在重启设备...", self.log_level)
# 改动原因添加调试打印显示发送的DEVICE_REBOOT命令
send_packet = [0x01] + list(data)
self.debug_print_hex(send_packet, f"[发送] DEVICE_REBOOT命令 (DEVICE_REBOOT)", max_bytes=64)
h.write(send_packet)
# 改动原因DEVICE_REBOOT不需要返回发送后设备立即重启
# 注意:设备不会返回响应,主机不等待
h.close()
QMessageBox.information(
self,
"重启设备",
"重启命令已发送\n\n"
"设备将在几秒内重启。\n"
"请等待设备重新连接。"
)
except Exception as e:
log_message(LOG_LEVEL_ERROR, f"重启设备时出错: {str(e)}", self.log_level)
QMessageBox.critical(self, "错误", f"重启设备时出错:\n{str(e)}")
def on_get_firmware_upgrade_status(self):
"""查询固件升级状态发送FIRMWARE_UPGRADE_STATUS命令"""
# 改动原因:支持查询升级状态,便于诊断升级进度和错误
if self.device_combo.currentData() is None:
log_message(LOG_LEVEL_ERROR, "请先选择设备", self.log_level)
QMessageBox.warning(self, "错误", "请先选择设备")
return
try:
device_info = self.device_combo.currentData()
h = hid.device()
h.open(device_info['vendor_id'], device_info['product_id'])
h.set_nonblocking(1)
data = bytearray(63)
data[0] = 0x77 # 同步头
data[1] = FIRMWARE_UPGRADE_STATUS # 命令码
log_message(LOG_LEVEL_INFO, "正在查询升级状态...", self.log_level)
send_packet = [0x01] + list(data)
self.debug_print_hex(send_packet, f"[发送] STATUS命令 (FIRMWARE_UPGRADE_STATUS)", max_bytes=64)
h.write(send_packet)
reply = self.wait_for_hid_response(h, FIRMWARE_UPGRADE_STATUS, timeout=180.0)
if reply:
self.debug_print_hex(reply, f"[接收] STATUS响应 (FIRMWARE_UPGRADE_STATUS)", max_bytes=64)
if not reply:
raise Exception("STATUS命令响应超时或无效")
# 响应解析Report ID + 同步头 + 命令码 + payload
state = reply[3]
received_blocks = reply[4] | (reply[5] << 8)
total_blocks = reply[6] | (reply[7] << 8)
written_pages = reply[8] | (reply[9] << 8)
total_pages = reply[10] | (reply[11] << 8)
bytes_transferred = reply[12] | (reply[13] << 8) | (reply[14] << 16) | (reply[15] << 24)
total_bytes = reply[16] | (reply[17] << 8) | (reply[18] << 16) | (reply[19] << 24)
error_code = reply[20]
state_map = {
0x00: "IDLE",
0x01: "PREPARING",
0x02: "TRANSFERRING",
0x03: "COMPLETING",
0x04: "COMPLETED",
0x05: "ERROR",
0x06: "ABORTED"
}
msg = (
f"状态: {state_map.get(state, f'0x{state:02x}')}\n"
f"块进度: {received_blocks}/{total_blocks}\n"
f"页进度: {written_pages}/{total_pages}\n"
f"字节进度: {bytes_transferred}/{total_bytes}\n"
f"错误码: 0x{error_code:02x}"
)
log_message(LOG_LEVEL_INFO, f"升级状态: {msg}", self.log_level)
QMessageBox.information(self, "升级状态", msg)
h.close()
except Exception as e:
log_message(LOG_LEVEL_ERROR, f"查询升级状态时出错: {str(e)}", self.log_level)
QMessageBox.critical(self, "错误", f"查询升级状态时出错:\n{str(e)}")
def on_abort_firmware_upgrade(self):
"""中止固件升级发送FIRMWARE_UPGRADE_ABORT命令"""
# 改动原因:支持中止升级流程,并可选择是否擦除已写入数据
if self.device_combo.currentData() is None:
log_message(LOG_LEVEL_ERROR, "请先选择设备", self.log_level)
QMessageBox.warning(self, "错误", "请先选择设备")
return
erase_reply = QMessageBox.question(
self,
"中止升级",
"是否擦除已写入的数据?\n\n"
"选择“是”:擦除已写入数据\n"
"选择“否”:保留已写入数据",
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No
)
erase_flag = 0x01 if erase_reply == QMessageBox.Yes else 0x00
try:
device_info = self.device_combo.currentData()
h = hid.device()
h.open(device_info['vendor_id'], device_info['product_id'])
h.set_nonblocking(1)
data = bytearray(63)
data[0] = 0x77 # 同步头
data[1] = FIRMWARE_UPGRADE_ABORT # 命令码
data[2] = erase_flag # 清理标志
log_message(LOG_LEVEL_INFO, "正在中止升级...", self.log_level)
send_packet = [0x01] + list(data)
self.debug_print_hex(send_packet, f"[发送] ABORT命令 (FIRMWARE_UPGRADE_ABORT)", max_bytes=64)
h.write(send_packet)
reply = self.wait_for_hid_response(h, FIRMWARE_UPGRADE_ABORT, timeout=180.0)
if reply:
self.debug_print_hex(reply, f"[接收] ABORT响应 (FIRMWARE_UPGRADE_ABORT)", max_bytes=64)
if not reply:
raise Exception("ABORT命令响应超时或无效")
status = reply[3]
if status == 0x00:
log_message(LOG_LEVEL_INFO, "升级已中止", self.log_level)
QMessageBox.information(self, "成功", "升级已中止")
else:
log_message(LOG_LEVEL_ERROR, f"中止升级失败,状态码: 0x{status:02x}", self.log_level)
QMessageBox.warning(self, "失败", f"中止升级失败\n状态码: 0x{status:02x}")
h.close()
except Exception as e:
log_message(LOG_LEVEL_ERROR, f"中止升级时出错: {str(e)}", self.log_level)
QMessageBox.critical(self, "错误", f"中止升级时出错:\n{str(e)}")
def on_send_ex3d_cmd(self): def on_send_ex3d_cmd(self):
"""发送EX3D SET命令0xB0命令""" """发送EX3D SET命令0xB0命令"""
if self.device_combo.currentData() is None: if self.device_combo.currentData() is None:

View File

@@ -789,3 +789,133 @@
4. **错误恢复**: 通信失败时需要重新建立连接并重试 4. **错误恢复**: 通信失败时需要重新建立连接并重试
5. **参数验证**: 设备端会验证参数范围,超出范围的值会被限制 5. **参数验证**: 设备端会验证参数范围,超出范围的值会被限制
---
## 8. 固件升级命令 (0xA70xAE)
本节定义通过HID进行固件升级的命令。最大数据块57字节Flash页256字节字节序小端序。
### 8.1 固件升级命令列表
| 指令码 | 命令名称 | 功能 | 方向 |
|--------|----------|------|------|
| 0xA7 | FIRMWARE_UPGRADE_START | 开始固件升级 | 主机→设备 |
| 0xA8 | FIRMWARE_UPGRADE_DATA | 传输固件数据块固定57字节 | 主机→设备 |
| 0xA9 | FIRMWARE_UPGRADE_END | 结束固件升级,验证镜像 | 主机→设备 |
| 0xAA | FIRMWARE_UPGRADE_STATUS | 获取升级状态和进度 | 主机→设备 |
| 0xAB | FIRMWARE_UPGRADE_ABORT | 中止固件升级 | 主机→设备 |
| 0xAC | FIRMWARE_UPGRADE_ERASE | 擦除现有升级镜像 | 主机→设备 |
| 0xAE | DEVICE_REBOOT | 设备重启(通用命令) | 主机→设备 |
### 8.2 0xA7 - FIRMWARE_UPGRADE_START
**请求**:
```
字节 0: 0x77 同步头
字节 1: 0xA7 命令码
字节 2-5: uint32 固件大小(字节,小端序)
字节 6-62: 0x00 保留
```
**响应**(主动上报):
```
字节 0: 0x77
字节 1: 0xA7
字节 2: 状态码 (0x00=成功, 0x01=失败, 0x03=大小无效)
字节 3-6: uint32 页对齐后的实际大小
字节 7-8: uint16 总块数
字节 9-62: 0x00
```
### 8.3 0xA8 - FIRMWARE_UPGRADE_DATA
**请求**数据块固定57字节不足补0:
```
字节 0: 0x77
字节 1: 0xA8
字节 2-3: uint16 块序号从0开始小端序
字节 4: uint8 数据长度固定57
字节 5-61: uint8[57] 固件数据
字节 62: uint8 Checksum字节0-61累加 mod 256
```
**响应**(主动上报):
```
字节 0: 0x77
字节 1: 0xA8
字节 2: 状态码 (0x00=成功, 0x04=块号错误, 0x05=Checksum错误)
字节 3-4: uint16 已确认块序号
字节 5-62: 0x00
```
### 8.4 0xA9 - FIRMWARE_UPGRADE_END
**请求**:
```
字节 0: 0x77
字节 1: 0xA9
字节 2-5: uint32 固件总大小(用于验证)
字节 6-62: 0x00
```
**响应**(主动上报):
```
字节 0: 0x77
字节 1: 0xA9
字节 2: 状态码 (0x00=成功, 0x01=失败)
字节 3-62: 0x00
```
### 8.5 0xAA - FIRMWARE_UPGRADE_STATUS
**请求**: 字节0=0x77, 字节1=0xAA, 其余0x00
**响应**(主动上报):
```
字节 0: 0x77
字节 1: 0xAA
字节 2: 升级状态 (0=空闲, 1=准备中, 2=传输中, 3=完成中, 4=已完成, 5=错误, 6=已中止)
字节 3-4: uint16 已接收块数
字节 5-6: uint16 总块数
字节 7-8: uint16 已写页数
字节 9-10: uint16 总页数
字节 11-14: uint32 已传输字节数
字节 15-18: uint32 总字节数
字节 19: 错误码
字节 20-62: 0x00
```
### 8.6 0xAB - FIRMWARE_UPGRADE_ABORT
**请求**:
```
字节 0: 0x77
字节 1: 0xAB
字节 2: 清理标志 (0x00=保留数据, 0x01=擦除数据)
字节 3-62: 0x00
```
**响应**(主动上报): 字节0=0x77, 字节1=0xAB, 字节2=状态码(0x00=成功)
### 8.7 0xAC - FIRMWARE_UPGRADE_ERASE
**请求**: 字节0=0x77, 字节1=0xAC, 其余0x00
**响应**(主动上报): 字节0=0x77, 字节1=0xAC, 字节2=状态码(0x00=成功)
### 8.8 0xAE - DEVICE_REBOOT
**请求**: 字节0=0x77, 字节1=0xAE, 其余0x00
**响应**: 无响应,设备立即重启。
### 8.9 标准升级流程
```
1. (可选) ERASE — 擦除现有upgrade image
2. START — 设置固件大小,等待响应(SUCCESS)
3. 循环 DATA — 逐块发送,每块等待响应确认
4. END — 完成写入,等待响应(SUCCESS)
5. REBOOT — 重启加载新固件
```

View File

@@ -431,13 +431,20 @@ extern int dsp_worker_tile(chanend c_dsp_to_ex3d, int worker_id);
//extern int dsp_worker_tile_1(chanend c_dsp_to_ex3d, int worker_id); //extern int dsp_worker_tile_1(chanend c_dsp_to_ex3d, int worker_id);
extern void ex3d_task(); extern void ex3d_task();
extern void hid_button_task(chanend cc_mic_level, chanend c_hid, chanend c_hidSendData, chanend c_uac_vol, chanend c_ex3d_hid_cmd); extern void hid_button_task(chanend cc_mic_level, chanend c_hid, chanend c_hidSendData, chanend c_uac_vol, chanend c_ex3d_hid_cmd);
#if HID_DFU_EN
extern void AudioHwRemote(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol, chanend c_audiohw_rx, streaming chanend c_dfu_rx);
#else
extern void AudioHwRemote(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol, chanend c_audiohw_rx); extern void AudioHwRemote(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol, chanend c_audiohw_rx);
#endif
extern void dnr_dsp_proc_task(void); extern void dnr_dsp_proc_task(void);
extern unsafe chanend uc_dsp_to_ex3d[DSP_WORKER_COUNT]; extern unsafe chanend uc_dsp_to_ex3d[DSP_WORKER_COUNT];
extern unsafe chanend uc_dsp_to_dnr_t1; extern unsafe chanend uc_dsp_to_dnr_t1;
extern unsafe chanend uc_key_to_ubm_t0; extern unsafe chanend uc_key_to_ubm_t0;
extern unsafe chanend uc_audiohw; extern unsafe chanend uc_audiohw;
#if HID_DFU_EN
extern unsafe streaming chanend uc_dfu;
#endif
extern void key_sender(chanend c_key); extern void key_sender(chanend c_key);
extern void key_receiver(chanend c_key); extern void key_receiver(chanend c_key);
@@ -535,6 +542,9 @@ int main()
chan c_dsp_to_ex3d[DSP_WORKER_COUNT]; chan c_dsp_to_ex3d[DSP_WORKER_COUNT];
chan cc_mic_level; chan cc_mic_level;
chan c_audiohw; chan c_audiohw;
#if HID_DFU_EN
streaming chan c_dfu;
#endif
chan c_key; chan c_hidSendData; chan c_key; chan c_hidSendData;
chan c_hidRcvData; chan c_hidRcvData;
chan c_eq_data; chan c_eq_data;
@@ -572,13 +582,24 @@ int main()
#if USE_EX3D == 1 #if USE_EX3D == 1
unsafe { key_receiver(c_key); } unsafe { key_receiver(c_key); }
#endif #endif
AudioHwRemote(c_hidSendData, cc_mic_level, c_uac_vol, c_audiohw); AudioHwRemote(c_hidSendData, cc_mic_level, c_uac_vol, c_audiohw
#if HID_DFU_EN
, c_dfu
#endif
);
} }
} }
} }
#if EQ_EN == 1 #if EQ_EN == 1
on tile[0] : { on tile[0] : {
{ {
#if HID_DFU_EN
unsafe {
uc_dfu = (streaming chanend)c_dfu;
}
#endif
dsp_core0(); dsp_core0();
} }
} }