hid dfu
This commit is contained in:
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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~36dB,HID可见范围)
|
unsigned g_mic_volume_level = 37; // 麦克风PGA增益级别(0=mute, 1-37=0dB~36dB,HID可见范围)
|
||||||
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
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 0,begin_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 仍为 1,write_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
|
||||||
|
|
||||||
@@ -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_*/
|
||||||
@@ -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
|
||||||
@@ -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-0xAC,0xAE由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
|
||||||
@@ -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_
|
||||||
@@ -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[]) {
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -789,3 +789,133 @@
|
|||||||
4. **错误恢复**: 通信失败时需要重新建立连接并重试
|
4. **错误恢复**: 通信失败时需要重新建立连接并重试
|
||||||
5. **参数验证**: 设备端会验证参数范围,超出范围的值会被限制
|
5. **参数验证**: 设备端会验证参数范围,超出范围的值会被限制
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. 固件升级命令 (0xA7–0xAE)
|
||||||
|
|
||||||
|
本节定义通过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 — 重启加载新固件
|
||||||
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user