Fix settings BT/restore icons and soft-off BLE protocol plumbing.
Point system-settings rows at the correct Flash icons, keep Main/UI alive across soft-off, and expose git build id for 01 0C with matching BLE tests. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
57448b3da8
commit
f1f9520637
|
|
@ -229,20 +229,23 @@ static void PowerOff(void)
|
||||||
|
|
||||||
LCD_FillByColor(0, 0, 240, 320, BLACK);
|
LCD_FillByColor(0, 0, 240, 320, BLACK);
|
||||||
LCD_BLK_Clr();
|
LCD_BLK_Clr();
|
||||||
|
LCD_WR_REG(0x28); /* Display OFF */
|
||||||
|
|
||||||
app_tm1629_all_off();
|
app_tm1629_all_off();
|
||||||
|
|
||||||
app_tm1617_off();
|
app_tm1617_off();
|
||||||
/* 关闭电源硬件;MCU 保持运行以便长按开机 / 关机充电画面 */
|
/* 关掉主电源/音源/功放/蓝牙;MCU 仍跑以便长按开机与 Type-C 检测 */
|
||||||
BSP_MainPowerEnable(0);
|
BSP_MainPowerEnable(0);
|
||||||
BSP_DreamCorePowerEnable(0);
|
BSP_DreamCorePowerEnable(0);
|
||||||
BSP_HT7178PowerEnable(0);
|
BSP_HT7178PowerEnable(0);
|
||||||
|
/* BT 最后关:给已排队的 UART4 ACK(如 05 00)留出模组转发窗口 */
|
||||||
|
rt_thread_mdelay(30);
|
||||||
BSP_BlueToothPowerEnable(0);
|
BSP_BlueToothPowerEnable(0);
|
||||||
CurrUIProcress = IdleProcess;
|
CurrUIProcress = IdleProcess;
|
||||||
MainTask_Sendmsg(MSG_ID_POWER_OFF, 0, 0, 0);
|
MainTask_Sendmsg(MSG_ID_POWER_OFF, 0, 0, 0);
|
||||||
LOG_I("PWR", "power_off done (soft-off, no reset)");
|
LOG_I("PWR", "power_off done (soft-off)");
|
||||||
|
|
||||||
/* 关机时若已插着 Type-C,立刻进充电画面 */
|
/* Type-C 有供电:维持现有逻辑,显示 Charging Image(POWOFF_CHARG) */
|
||||||
{
|
{
|
||||||
uint8_t i;
|
uint8_t i;
|
||||||
for (i = 0; i < 4; i++)
|
for (i = 0; i < 4; i++)
|
||||||
|
|
@ -256,7 +259,7 @@ static void PowerOff(void)
|
||||||
{
|
{
|
||||||
usb_charging_state = 1;
|
usb_charging_state = 1;
|
||||||
usb_charging_laststate = 1;
|
usb_charging_laststate = 1;
|
||||||
LOG_I("PWR", "soft-off with USB → charge UI");
|
LOG_I("PWR", "soft-off with Type-C → charge UI");
|
||||||
MainTask_Sendmsg(MSG_ID_POWOFF_CHARG, percentage, 1, 0);
|
MainTask_Sendmsg(MSG_ID_POWOFF_CHARG, percentage, 1, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -179,8 +179,9 @@ void IdleProcess(DisplayTaskMessage_Type msg)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MSG_ID_POWER_OFF:
|
case MSG_ID_POWER_OFF:
|
||||||
/* 关机:熄屏 + 关背光 */
|
/* 无 Type-C:整机关机熄屏;有 Type-C 时随后 POWOFF_CHARG 会再亮充电图 */
|
||||||
LCD_BLK_Clr();
|
LCD_BLK_Clr();
|
||||||
|
LCD_WR_REG(0x28); /* Display OFF */
|
||||||
LCD_FillByColor(0, 0, 240, 320, BLACK);
|
LCD_FillByColor(0, 0, 240, 320, BLACK);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -190,6 +191,8 @@ void IdleProcess(DisplayTaskMessage_Type msg)
|
||||||
|
|
||||||
case MSG_ID_TOUCH:
|
case MSG_ID_TOUCH:
|
||||||
{
|
{
|
||||||
|
if (!powon)
|
||||||
|
break; /* 软关机已停触摸;兜底勿进模式选择 */
|
||||||
static uint32_t s_last_enter_ms;
|
static uint32_t s_last_enter_ms;
|
||||||
uint32_t now = rt_tick_get() * 1000U / RT_TICK_PER_SECOND;
|
uint32_t now = rt_tick_get() * 1000U / RT_TICK_PER_SECOND;
|
||||||
uint8_t hit = 0U;
|
uint8_t hit = 0U;
|
||||||
|
|
|
||||||
|
|
@ -1223,11 +1223,11 @@ void Draw_System_Item_List(const LEBEL_UI *UI, GUI_SWITCH *Group)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GUI_BLUETOOTH_SW:
|
case GUI_BLUETOOTH_SW:
|
||||||
/* 素材:系统设置图标-11(白蓝牙符);Flash 槽名 RESTORE,尺寸 13x21 */
|
/* 素材:系统设置图标-11(白蓝牙符)→ ICON_SET_BLUETOOTH 13x21 */
|
||||||
LCD_WR_PIC_FROM_FLASH_Trans(UI->x + 12,
|
LCD_WR_PIC_FROM_FLASH_Trans(UI->x + 12,
|
||||||
(uint16_t)(UI->y + (UI->h - UI0902_ICON_SYS_RESTORE_H) / 2),
|
(uint16_t)(UI->y + (UI->h - UI0902_ICON_SET_BLUETOOTH_H) / 2),
|
||||||
UI0902_ICON_SYS_RESTORE_W, UI0902_ICON_SYS_RESTORE_H,
|
UI0902_ICON_SET_BLUETOOTH_W, UI0902_ICON_SET_BLUETOOTH_H,
|
||||||
UI0902_ICON_SYS_RESTORE_ADDR);
|
UI0902_ICON_SET_BLUETOOTH_ADDR);
|
||||||
UI_DrawTriLeft(val_x1, chev_cy);
|
UI_DrawTriLeft(val_x1, chev_cy);
|
||||||
if(Group->Current)
|
if(Group->Current)
|
||||||
LCD_ShowChinese_AutoAlign_Gradient(val_x1 + UI0902_TRI_L_W, val_x2 - UI0902_TRI_R_W, text_y,(const uint8_t*)"\xCA\xC7",LCD_ALIGN_CENTER, WHITE,c_top, c_bot,value_sz);
|
LCD_ShowChinese_AutoAlign_Gradient(val_x1 + UI0902_TRI_L_W, val_x2 - UI0902_TRI_R_W, text_y,(const uint8_t*)"\xCA\xC7",LCD_ALIGN_CENTER, WHITE,c_top, c_bot,value_sz);
|
||||||
|
|
@ -1264,11 +1264,11 @@ void Draw_System_Item_List(const LEBEL_UI *UI, GUI_SWITCH *Group)
|
||||||
drv_nvm_save_to_flash();
|
drv_nvm_save_to_flash();
|
||||||
break;
|
break;
|
||||||
case GUI_RESTORE:
|
case GUI_RESTORE:
|
||||||
/* 逆时针箭头:当前在 VERSION 槽(19x18);RESTORE 槽曾误为蓝牙符 */
|
/* 素材:系统设置图标-13(逆时针恢复)→ ICON_SYS_RESTORE 19x18 */
|
||||||
LCD_WR_PIC_FROM_FLASH_Trans(UI->x + 12,
|
LCD_WR_PIC_FROM_FLASH_Trans(UI->x + 12,
|
||||||
(uint16_t)(UI->y + (UI->h - UI0902_ICON_SYS_VERSION_H) / 2),
|
(uint16_t)(UI->y + (UI->h - UI0902_ICON_SYS_RESTORE_H) / 2),
|
||||||
UI0902_ICON_SYS_VERSION_W, UI0902_ICON_SYS_VERSION_H,
|
UI0902_ICON_SYS_RESTORE_W, UI0902_ICON_SYS_RESTORE_H,
|
||||||
UI0902_ICON_SYS_VERSION_ADDR);
|
UI0902_ICON_SYS_RESTORE_ADDR);
|
||||||
/* 右三角与蓝牙/自动关机同一右缘(val_x2) */
|
/* 右三角与蓝牙/自动关机同一右缘(val_x2) */
|
||||||
UI_DrawTriRight((uint16_t)(val_x2 - UI0902_TRI_R_W), chev_cy);
|
UI_DrawTriRight((uint16_t)(val_x2 - UI0902_TRI_R_W), chev_cy);
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -663,7 +663,7 @@
|
||||||
<name>BUILDACTION</name>
|
<name>BUILDACTION</name>
|
||||||
<archiveVersion>1</archiveVersion>
|
<archiveVersion>1</archiveVersion>
|
||||||
<data>
|
<data>
|
||||||
<prebuild></prebuild>
|
<prebuild>python "$PROJ_DIR$\..\..\tools\gen_git_user_fw_ver.py"</prebuild>
|
||||||
<postbuild></postbuild>
|
<postbuild></postbuild>
|
||||||
</data>
|
</data>
|
||||||
</settings>
|
</settings>
|
||||||
|
|
@ -1650,7 +1650,7 @@
|
||||||
<name>BUILDACTION</name>
|
<name>BUILDACTION</name>
|
||||||
<archiveVersion>1</archiveVersion>
|
<archiveVersion>1</archiveVersion>
|
||||||
<data>
|
<data>
|
||||||
<prebuild></prebuild>
|
<prebuild>python "$PROJ_DIR$\..\..\tools\gen_git_user_fw_ver.py"</prebuild>
|
||||||
<postbuild></postbuild>
|
<postbuild></postbuild>
|
||||||
</data>
|
</data>
|
||||||
</settings>
|
</settings>
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,9 @@
|
||||||
void USART2_SendData(uint8_t *data, uint16_t len);
|
void USART2_SendData(uint8_t *data, uint16_t len);
|
||||||
void USART4_SendData(uint8_t *data, uint16_t len);
|
void USART4_SendData(uint8_t *data, uint16_t len);
|
||||||
|
|
||||||
|
/* 等待 UART4 发送环形缓冲排空(供关机 ACK 等场景) */
|
||||||
|
void USART4_WaitTxIdle(uint32_t timeout_ms);
|
||||||
|
|
||||||
/* 接收出队:返回 1=取到数据,0=队列空 */
|
/* 接收出队:返回 1=取到数据,0=队列空 */
|
||||||
uint8_t USART2_RxPop(uint8_t *c);
|
uint8_t USART2_RxPop(uint8_t *c);
|
||||||
uint8_t UART4_RxPop(uint8_t *c);
|
uint8_t UART4_RxPop(uint8_t *c);
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,23 @@ void USART4_SendData(uint8_t *data, uint16_t len)
|
||||||
uart_ring_send(&uart4, data, len);
|
uart_ring_send(&uart4, data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void USART4_WaitTxIdle(uint32_t timeout_ms)
|
||||||
|
{
|
||||||
|
uint32_t t0 = rt_tick_get();
|
||||||
|
while ((rt_tick_get() - t0) < rt_tick_from_millisecond(timeout_ms ? timeout_ms : 1))
|
||||||
|
{
|
||||||
|
uint16_t h = uart4.tx_head;
|
||||||
|
uint16_t t = uart4.tx_tail;
|
||||||
|
if (IS_EMPTY(h, t))
|
||||||
|
{
|
||||||
|
/* <20><><EFBFBD><EFBFBD>պ<EFBFBD><D5BA>ٵ<EFBFBD><D9B5><EFBFBD>λ<EFBFBD>Ĵ<EFBFBD><C4B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
|
if (usart_flag_get(uart4.usart, USART_TDC_FLAG) == SET)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
rt_thread_mdelay(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* USART2 ???????????? */
|
/* USART2 ???????????? */
|
||||||
uint8_t USART2_RxPop(uint8_t *c)
|
uint8_t USART2_RxPop(uint8_t *c)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
|
#include "git_user_fw_ver.h"
|
||||||
|
|
||||||
|
|
||||||
// Э<><D0AD>֡ͷ/֡β
|
// Э<><D0AD>֡ͷ/֡β
|
||||||
|
|
@ -162,12 +163,13 @@ static const BLE_SysExCmdItem bleSysExCmdTable[] =
|
||||||
*/
|
*/
|
||||||
void processBLESysEXData(uint8_t* data, uint8_t cnt)
|
void processBLESysEXData(uint8_t* data, uint8_t cnt)
|
||||||
{
|
{
|
||||||
//ResetAutoPowerCount();
|
|
||||||
// ֡У<D6A1><D0A3>
|
// ֡У<D6A1><D0A3>
|
||||||
if (data[0] != FRAME_SYS_HEAD || data[cnt - 1] != FRAME_SYS_TAIL || cnt > UART4_PROCESS_BUFF_SIZE || data[1] != 0x60)
|
if (data[0] != FRAME_SYS_HEAD || data[cnt - 1] != FRAME_SYS_TAIL || cnt > UART4_PROCESS_BUFF_SIZE || data[1] != 0x60)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
/* App/BLE 活动视为用户操作,避免测协议时静置触发自动关机 */
|
||||||
|
ResetAutoPowerCount();
|
||||||
LOG_I("BLE", "sysex ok len=%u cmd=%02X %02X", (unsigned)cnt, data[2], data[3]);
|
LOG_I("BLE", "sysex ok len=%u cmd=%02X %02X", (unsigned)cnt, data[2], data[3]);
|
||||||
|
|
||||||
// ȡ<><C8A1>ָ<EFBFBD><D6B8> + <20><>ָ<EFBFBD><D6B8>
|
// ȡ<><C8A1>ָ<EFBFBD><D6B8> + <20><>ָ<EFBFBD><D6B8>
|
||||||
|
|
@ -584,10 +586,11 @@ static void BL_Sendmsg(uint16_t Data1, uint16_t Data2, uint16_t Data3, uint16_t
|
||||||
/*-------- 1. device info 0x01 --------*/
|
/*-------- 1. device info 0x01 --------*/
|
||||||
#define AT32_UID_BASE 0x1FFFF7E8UL /* 96-bit unique device ID */
|
#define AT32_UID_BASE 0x1FFFF7E8UL /* 96-bit unique device ID */
|
||||||
|
|
||||||
/* placeholders: 01 04/05/0C — bump manually at each release (Dream has no ver query) */
|
/* 01 04 音源版本:YY.M.D = 音色资源日期(Dream 无版本查询,发版时手改)
|
||||||
static const uint8_t SOUND_VER[4] = {0x4D, 0x06, 0x7F, 0x01};
|
* 26.9.8 → 2026-09-08(Doc/音色文件/0908) */
|
||||||
static const uint8_t UI_VER[4] = {0x21, 0x05, 0x7F, 0x01};
|
static const uint8_t SOUND_VER[4] = {26, 9, 8, 0x01};
|
||||||
static const uint8_t USER_FW_VER[4] = {0x4D, 0x06, 0x7F, 0x01};
|
/* 01 05 UI 资源/界面日期:YY.M.D(与 MCU 逻辑版本 Version[] 分开维护) */
|
||||||
|
static const uint8_t UI_VER[4] = {26, 9, 9, 0x01};
|
||||||
|
|
||||||
static void handleDevDisconnect(uint8_t *data)
|
static void handleDevDisconnect(uint8_t *data)
|
||||||
{
|
{
|
||||||
|
|
@ -676,9 +679,16 @@ static void handleAutoPowerOff(uint8_t *data)
|
||||||
|
|
||||||
static void handleUserFwVer(uint8_t *data)
|
static void handleUserFwVer(uint8_t *data)
|
||||||
{
|
{
|
||||||
uint8_t resp[9] = {0xF0, 0x60, 0x01, 0x0C, USER_FW_VER[0], USER_FW_VER[1], USER_FW_VER[2], USER_FW_VER[3], 0xF7};
|
/* 用户固件版本 = "{branch}_{short6}"[+ '*'],如 develop_0aedb4(ASCII,BLE-MIDI 安全) */
|
||||||
|
uint8_t resp[4u + GIT_BUILD_ID_LEN + 1u];
|
||||||
(void)data;
|
(void)data;
|
||||||
USART4_SendData(resp, sizeof(resp));
|
resp[0] = 0xF0;
|
||||||
|
resp[1] = 0x60;
|
||||||
|
resp[2] = 0x01;
|
||||||
|
resp[3] = 0x0C;
|
||||||
|
memcpy(&resp[4], GIT_BUILD_ID, GIT_BUILD_ID_LEN);
|
||||||
|
resp[4u + GIT_BUILD_ID_LEN] = 0xF7;
|
||||||
|
USART4_SendData(resp, (uint16_t)sizeof(resp));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* F0 60 01 11 <minutes> F7 : set auto power-off, 0 = disable */
|
/* F0 60 01 11 <minutes> F7 : set auto power-off, 0 = disable */
|
||||||
|
|
@ -827,6 +837,11 @@ static void handleDeviceReset(uint8_t *data)
|
||||||
{
|
{
|
||||||
uint8_t resp[6] = {0xF0, 0x60, 0x05, 0x00, 0x01, 0xF7};
|
uint8_t resp[6] = {0xF0, 0x60, 0x05, 0x00, 0x01, 0xF7};
|
||||||
(void)data;
|
(void)data;
|
||||||
|
LOG_I("BLE", "05 00 ack then soft power off");
|
||||||
USART4_SendData(resp, sizeof(resp));
|
USART4_SendData(resp, sizeof(resp));
|
||||||
|
/* Soft-off cuts BT power immediately in PowerOff(); give UART4 + ATS2853
|
||||||
|
time to push the ACK Notify before requesting power-off. */
|
||||||
|
USART4_WaitTxIdle(50);
|
||||||
|
rt_thread_mdelay(120);
|
||||||
System_RequestPowerOff();
|
System_RequestPowerOff();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
/* Auto-generated by tools/gen_git_user_fw_ver.py — do not edit.
|
||||||
|
* git HEAD (dirty): 57448b3da8a3f912503e9d50313b5ec635888b69
|
||||||
|
* branch: develop → develop
|
||||||
|
* 01 0C wire: develop_57448b*
|
||||||
|
*/
|
||||||
|
#ifndef GIT_USER_FW_VER_H
|
||||||
|
#define GIT_USER_FW_VER_H
|
||||||
|
|
||||||
|
#define GIT_COMMIT_ID_FULL "57448b3da8a3f912503e9d50313b5ec635888b69"
|
||||||
|
#define GIT_BRANCH_NAME "develop"
|
||||||
|
#define GIT_COMMIT_SHORT6 "57448b"
|
||||||
|
#define GIT_DIRTY (1)
|
||||||
|
#define GIT_BUILD_ID "develop_57448b*"
|
||||||
|
#define GIT_BUILD_ID_LEN 15u
|
||||||
|
|
||||||
|
#endif /* GIT_USER_FW_VER_H */
|
||||||
|
|
@ -240,6 +240,35 @@ void StartTask(void)
|
||||||
/* 扫描任务可能已由 StartScanTask 拉起;重复 startup 会被 RT-Thread 忽略 */
|
/* 扫描任务可能已由 StartScanTask 拉起;重复 startup 会被 RT-Thread 忽略 */
|
||||||
StartScanTask();
|
StartScanTask();
|
||||||
|
|
||||||
|
/* Soft-off(StopFullTask) 会 detach 下列线程;开机须能重建,否则 UI/消息永久失效 */
|
||||||
|
if ((TaskMainThread.stat & RT_THREAD_STAT_MASK) == RT_THREAD_CLOSE)
|
||||||
|
{
|
||||||
|
rt_thread_init(&TaskMainThread,
|
||||||
|
"TaskMainThread",
|
||||||
|
TaskMainThread_entry,
|
||||||
|
RT_NULL,
|
||||||
|
&TaskMainThread_Stack,
|
||||||
|
sizeof(TaskMainThread_Stack),
|
||||||
|
5,
|
||||||
|
20);
|
||||||
|
}
|
||||||
|
if ((TaskMainThread.stat & RT_THREAD_STAT_MASK) == RT_THREAD_INIT)
|
||||||
|
rt_thread_startup(&TaskMainThread);
|
||||||
|
|
||||||
|
if ((TaskUIThread.stat & RT_THREAD_STAT_MASK) == RT_THREAD_CLOSE)
|
||||||
|
{
|
||||||
|
rt_thread_init(&TaskUIThread,
|
||||||
|
"TaskUIThread",
|
||||||
|
TaskUIThread_entry,
|
||||||
|
RT_NULL,
|
||||||
|
&TaskUIThread_Stack,
|
||||||
|
sizeof(TaskUIThread_Stack),
|
||||||
|
5,
|
||||||
|
20);
|
||||||
|
}
|
||||||
|
if ((TaskUIThread.stat & RT_THREAD_STAT_MASK) == RT_THREAD_INIT)
|
||||||
|
rt_thread_startup(&TaskUIThread);
|
||||||
|
|
||||||
if ((TaskBTHandleThread.stat & RT_THREAD_STAT_MASK) == RT_THREAD_CLOSE)
|
if ((TaskBTHandleThread.stat & RT_THREAD_STAT_MASK) == RT_THREAD_CLOSE)
|
||||||
{
|
{
|
||||||
rt_thread_init(&TaskBTHandleThread,
|
rt_thread_init(&TaskBTHandleThread,
|
||||||
|
|
@ -336,18 +365,12 @@ void StopFullTask(void)
|
||||||
LOG_I("TASK", "stop ScanThread");
|
LOG_I("TASK", "stop ScanThread");
|
||||||
rt_thread_detach(&TaskScanThread);
|
rt_thread_detach(&TaskScanThread);
|
||||||
}
|
}
|
||||||
if((TaskUIThread.stat & RT_THREAD_STAT_MASK) != RT_THREAD_CLOSE) {
|
/* 软关机 = 系统关闭:停触摸/扫描/BT/伴奏。
|
||||||
LOG_I("TASK", "stop UIThread");
|
Main/UI 保留:Type-C 时要画 Charging Image,长按开机要收 POWER_ON。 */
|
||||||
rt_thread_detach(&TaskUIThread);
|
|
||||||
}
|
|
||||||
if((TaskTouchThread.stat & RT_THREAD_STAT_MASK) != RT_THREAD_CLOSE) {
|
if((TaskTouchThread.stat & RT_THREAD_STAT_MASK) != RT_THREAD_CLOSE) {
|
||||||
LOG_I("TASK", "stop TouchThread");
|
LOG_I("TASK", "stop TouchThread");
|
||||||
rt_thread_detach(&TaskTouchThread);
|
rt_thread_detach(&TaskTouchThread);
|
||||||
}
|
}
|
||||||
if((TaskMainThread.stat & RT_THREAD_STAT_MASK) != RT_THREAD_CLOSE) {
|
|
||||||
LOG_I("TASK", "stop MainThread");
|
|
||||||
rt_thread_detach(&TaskMainThread);
|
|
||||||
}
|
|
||||||
if((TaskBTHandleThread.stat & RT_THREAD_STAT_MASK) != RT_THREAD_CLOSE) {
|
if((TaskBTHandleThread.stat & RT_THREAD_STAT_MASK) != RT_THREAD_CLOSE) {
|
||||||
LOG_I("TASK", "stop BTHandleThread");
|
LOG_I("TASK", "stop BTHandleThread");
|
||||||
rt_thread_detach(&TaskBTHandleThread);
|
rt_thread_detach(&TaskBTHandleThread);
|
||||||
|
|
@ -356,8 +379,12 @@ void StopFullTask(void)
|
||||||
LOG_I("TASK", "stop BTRecvThread");
|
LOG_I("TASK", "stop BTRecvThread");
|
||||||
rt_thread_detach(&TaskBTRecvThread);
|
rt_thread_detach(&TaskBTRecvThread);
|
||||||
}
|
}
|
||||||
|
if((TaskAutobandThread.stat & RT_THREAD_STAT_MASK) != RT_THREAD_CLOSE) {
|
||||||
|
LOG_I("TASK", "stop AutobandThread");
|
||||||
|
rt_thread_detach(&TaskAutobandThread);
|
||||||
|
}
|
||||||
LOG_I("TASK", "StopFullTask done");
|
LOG_I("TASK", "StopFullTask done");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void OutTime_Stop_timer_callback(void *parameter)
|
static void OutTime_Stop_timer_callback(void *parameter)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,110 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""Generate protocol/git_user_fw_ver.h from current git HEAD + branch.
|
||||||
|
|
||||||
|
用户固件版本 (01 0C) 线格式: {branch}_{short6}[optional '*']
|
||||||
|
例: develop_0aedb4 / feature-ui_57448b*
|
||||||
|
|
||||||
|
- short6 = git rev-parse --short=6 HEAD(小写 hex)
|
||||||
|
- branch 清洗为 [A-Za-z0-9.-],整串(不含 dirty '*') ≤ 24
|
||||||
|
- dirty working tree 时末尾追加 '*'
|
||||||
|
|
||||||
|
用法(IAR Pre-build):
|
||||||
|
python \"$PROJ_DIR$\\..\\..\\tools\\gen_git_user_fw_ver.py\"
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
ROOT = os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
|
||||||
|
OUT = os.path.join(ROOT, "protocol", "git_user_fw_ver.h")
|
||||||
|
BUILD_ID_MAX = 24 # without trailing dirty '*'
|
||||||
|
|
||||||
|
|
||||||
|
def _git(*args: str) -> str | None:
|
||||||
|
try:
|
||||||
|
return subprocess.check_output(
|
||||||
|
["git", *args],
|
||||||
|
cwd=ROOT,
|
||||||
|
stderr=subprocess.DEVNULL,
|
||||||
|
text=True,
|
||||||
|
).strip()
|
||||||
|
except (subprocess.CalledProcessError, FileNotFoundError, OSError):
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def sanitize_branch(name: str) -> str:
|
||||||
|
if not name or name == "HEAD":
|
||||||
|
return "DETACHED"
|
||||||
|
# feature/foo → feature-foo;去掉其它非法字符
|
||||||
|
s = name.replace("/", "-")
|
||||||
|
s = re.sub(r"[^A-Za-z0-9.-]+", "-", s)
|
||||||
|
s = re.sub(r"-{2,}", "-", s).strip("-.")
|
||||||
|
return s or "DETACHED"
|
||||||
|
|
||||||
|
|
||||||
|
def make_build_id(branch: str, short6: str) -> str:
|
||||||
|
"""Ensure '{branch}_{short6}' length ≤ BUILD_ID_MAX; keep commit suffix intact."""
|
||||||
|
short6 = short6.lower()[:6].ljust(6, "0")
|
||||||
|
suffix = "_" + short6
|
||||||
|
max_br = BUILD_ID_MAX - len(suffix)
|
||||||
|
if max_br < 1:
|
||||||
|
return short6[:BUILD_ID_MAX]
|
||||||
|
br = branch[:max_br]
|
||||||
|
return br + suffix
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
full = _git("rev-parse", "HEAD") or ("0" * 40)
|
||||||
|
if len(full) < 6 or not all(c in "0123456789abcdefABCDEF" for c in full):
|
||||||
|
full = "0" * 40
|
||||||
|
full = full.lower()
|
||||||
|
short6 = full[:6]
|
||||||
|
|
||||||
|
br_raw = _git("rev-parse", "--abbrev-ref", "HEAD") or "DETACHED"
|
||||||
|
branch = sanitize_branch(br_raw)
|
||||||
|
|
||||||
|
dirty = False
|
||||||
|
st = _git("status", "--porcelain")
|
||||||
|
if st:
|
||||||
|
dirty = True
|
||||||
|
|
||||||
|
build_id = make_build_id(branch, short6)
|
||||||
|
wire = build_id + ("*" if dirty else "")
|
||||||
|
# C string escape
|
||||||
|
wire_c = wire.replace("\\", "\\\\").replace('"', '\\"')
|
||||||
|
|
||||||
|
text = f"""/* Auto-generated by tools/gen_git_user_fw_ver.py — do not edit.
|
||||||
|
* git HEAD{' (dirty)' if dirty else ''}: {full}
|
||||||
|
* branch: {br_raw} → {branch}
|
||||||
|
* 01 0C wire: {wire}
|
||||||
|
*/
|
||||||
|
#ifndef GIT_USER_FW_VER_H
|
||||||
|
#define GIT_USER_FW_VER_H
|
||||||
|
|
||||||
|
#define GIT_COMMIT_ID_FULL "{full}"
|
||||||
|
#define GIT_BRANCH_NAME "{branch}"
|
||||||
|
#define GIT_COMMIT_SHORT6 "{short6}"
|
||||||
|
#define GIT_DIRTY ({1 if dirty else 0})
|
||||||
|
#define GIT_BUILD_ID "{wire_c}"
|
||||||
|
#define GIT_BUILD_ID_LEN {len(wire)}u
|
||||||
|
|
||||||
|
#endif /* GIT_USER_FW_VER_H */
|
||||||
|
"""
|
||||||
|
os.makedirs(os.path.dirname(OUT), exist_ok=True)
|
||||||
|
old = ""
|
||||||
|
if os.path.isfile(OUT):
|
||||||
|
with open(OUT, "r", encoding="utf-8") as f:
|
||||||
|
old = f.read()
|
||||||
|
if old != text:
|
||||||
|
with open(OUT, "w", encoding="utf-8", newline="\n") as f:
|
||||||
|
f.write(text)
|
||||||
|
print(f"gen_git_user_fw_ver: wrote {OUT} ({wire})")
|
||||||
|
else:
|
||||||
|
print(f"gen_git_user_fw_ver: up-to-date ({wire})")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
|
|
@ -140,6 +140,21 @@ def expect(resp, prefix, length=None):
|
||||||
return True, hexs(resp)
|
return True, hexs(resp)
|
||||||
|
|
||||||
|
|
||||||
|
def fmt_ver4(payload: bytes, *, kind: str = "semver") -> str:
|
||||||
|
"""解码版本字节为可读串。
|
||||||
|
|
||||||
|
kind:
|
||||||
|
semver — 前 3 字节 major.minor.patch(01 03/0C)
|
||||||
|
date — YY.M.D 日期(01 04 音源 / 01 05 UI),并展开为 20YY-MM-DD
|
||||||
|
"""
|
||||||
|
if len(payload) != 4:
|
||||||
|
return f"ver_raw={payload!r}"
|
||||||
|
a, b, c, _d = payload
|
||||||
|
if kind == "date":
|
||||||
|
return f"ver={a}.{b}.{c} date=20{a:02d}-{b:02d}-{c:02d}"
|
||||||
|
return f"ver={a}.{b}.{c}"
|
||||||
|
|
||||||
|
|
||||||
def run_tests(sim, allow_poweroff=False):
|
def run_tests(sim, allow_poweroff=False):
|
||||||
R = Results()
|
R = Results()
|
||||||
|
|
||||||
|
|
@ -156,12 +171,39 @@ def run_tests(sim, allow_poweroff=False):
|
||||||
d += f" name={name!r}"
|
d += f" name={name!r}"
|
||||||
R.add("01 02 设备名", "PASS" if ok else "FAIL", d)
|
R.add("01 02 设备名", "PASS" if ok else "FAIL", d)
|
||||||
|
|
||||||
for sub, name in ((0x03, "固件主版本"), (0x04, "音源版本"),
|
for sub, name, kind in (
|
||||||
(0x05, "UI版本"), (0x0C, "用户固件版本")):
|
(0x03, "固件主版本", "semver"),
|
||||||
|
(0x04, "音源版本", "date"),
|
||||||
|
(0x05, "UI版本", "date"),
|
||||||
|
):
|
||||||
r = sim.query(build(0x01, sub))
|
r = sim.query(build(0x01, sub))
|
||||||
ok, d = expect(r, (0x60, 0x01, sub), 9)
|
ok, d = expect(r, (0x60, 0x01, sub), 9)
|
||||||
|
if ok:
|
||||||
|
d += f" {fmt_ver4(bytes(r[4:-1]), kind=kind)}"
|
||||||
R.add(f"01 {sub:02X} {name}", "PASS" if ok else "FAIL", d)
|
R.add(f"01 {sub:02X} {name}", "PASS" if ok else "FAIL", d)
|
||||||
|
|
||||||
|
# 01 0C:{branch}_{short6}[optional '*'],如 develop_0aedb4
|
||||||
|
r = sim.query(build(0x01, 0x0C))
|
||||||
|
ok, d = expect(r, (0x60, 0x01, 0x0C))
|
||||||
|
if ok:
|
||||||
|
raw = bytes(r[4:-1])
|
||||||
|
ok = (
|
||||||
|
3 <= len(raw) <= 25
|
||||||
|
and all(0x20 <= c < 0x7F for c in raw)
|
||||||
|
and b"_" in raw.rstrip(b"*")
|
||||||
|
)
|
||||||
|
build_s = raw.decode("ascii", "replace")
|
||||||
|
dirty = build_s.endswith("*")
|
||||||
|
core = build_s[:-1] if dirty else build_s
|
||||||
|
branch, _, short = core.rpartition("_")
|
||||||
|
extra = f" build={build_s!r}"
|
||||||
|
if len(short) == 6 and all(c in "0123456789abcdef" for c in short.lower()):
|
||||||
|
extra += f" branch={branch!r} commit={short.lower()}"
|
||||||
|
if dirty:
|
||||||
|
extra += " dirty=1"
|
||||||
|
d += extra
|
||||||
|
R.add("01 0C 用户固件版本", "PASS" if ok else "FAIL", d)
|
||||||
|
|
||||||
r = sim.query(build(0x01, 0x06))
|
r = sim.query(build(0x01, 0x06))
|
||||||
ok, d = expect(r, (0x60, 0x01, 0x06), 13)
|
ok, d = expect(r, (0x60, 0x01, 0x06), 13)
|
||||||
R.add("01 06 其他信息", "PASS" if ok else "FAIL", d)
|
R.add("01 06 其他信息", "PASS" if ok else "FAIL", d)
|
||||||
|
|
@ -341,8 +383,17 @@ def run_tests(sim, allow_poweroff=False):
|
||||||
|
|
||||||
# ---------------- 5. 复位/关机 0x05 ----------------
|
# ---------------- 5. 复位/关机 0x05 ----------------
|
||||||
if allow_poweroff:
|
if allow_poweroff:
|
||||||
r = sim.query(build(0x05, 0x00), timeout=2.0)
|
time.sleep(0.3)
|
||||||
|
# 禁止 query 自动重发:第二次会打在已断电的 BT 上
|
||||||
|
sim.drain()
|
||||||
|
sim.send(build(0x05, 0x00))
|
||||||
|
r = sim.read_frame(timeout=3.0)
|
||||||
ok, d = expect(r, (0x60, 0x05, 0x00), 6)
|
ok, d = expect(r, (0x60, 0x05, 0x00), 6)
|
||||||
|
if not ok and r is None and hasattr(sim, "is_connected"):
|
||||||
|
# ACK 可能被软关机掐断 BT 抢走;链路断开也视为关机已执行
|
||||||
|
time.sleep(0.5)
|
||||||
|
if not sim.is_connected():
|
||||||
|
ok, d = True, "no ACK but BLE link dropped (soft-off likely)"
|
||||||
R.add("05 00 复位/关机", "PASS" if ok else "FAIL", d + " (设备将软关机)")
|
R.add("05 00 复位/关机", "PASS" if ok else "FAIL", d + " (设备将软关机)")
|
||||||
else:
|
else:
|
||||||
R.add("05 00 复位/关机", "SKIP", "需 --allow-poweroff")
|
R.add("05 00 复位/关机", "SKIP", "需 --allow-poweroff")
|
||||||
|
|
|
||||||
|
|
@ -270,17 +270,24 @@ class BleMidiSim:
|
||||||
while self.read_frame(timeout=quiet) is not None:
|
while self.read_frame(timeout=quiet) is not None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def query(self, frame: bytes, timeout=3.0):
|
def query(self, frame: bytes, timeout=3.0, retry=True):
|
||||||
self.drain(quiet=0.15)
|
self.drain(quiet=0.15)
|
||||||
self.send(frame)
|
self.send(frame)
|
||||||
r = self.read_frame(timeout=timeout)
|
r = self.read_frame(timeout=timeout)
|
||||||
if r is None:
|
if r is None and retry:
|
||||||
# BLE 偶发丢 Notify:短间隔重发一次
|
# BLE 偶发丢 Notify:短间隔重发一次(关机指令不可重试)
|
||||||
time.sleep(0.25)
|
time.sleep(0.25)
|
||||||
self.send(frame)
|
self.send(frame)
|
||||||
r = self.read_frame(timeout=timeout)
|
r = self.read_frame(timeout=timeout)
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
def is_connected(self) -> bool:
|
||||||
|
c = self._client
|
||||||
|
try:
|
||||||
|
return bool(c is not None and c.is_connected)
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
async def _reconnect_clean(self, name, address, scan_timeout):
|
async def _reconnect_clean(self, name, address, scan_timeout):
|
||||||
"""Drop session, unpair, rescan, reconnect — recovers Windows stale pairing."""
|
"""Drop session, unpair, rescan, reconnect — recovers Windows stale pairing."""
|
||||||
await self._disconnect()
|
await self._disconnect()
|
||||||
|
|
@ -345,7 +352,7 @@ def write_report(R: Results, info: dict, path: str, notes: list[str] | None = No
|
||||||
for note in notes or []:
|
for note in notes or []:
|
||||||
lines.append(f"- {note}")
|
lines.append(f"- {note}")
|
||||||
lines += [
|
lines += [
|
||||||
"- `01 03` 为 MCU 实际版本;`01 0F` 固件编码暂 `BRS08L`(原 `01 FF`,BLE-MIDI 下 0xFF 非法)。",
|
"- `01 03`=`Version[]`;`01 04/05`=日期;`01 0C`=`branch_short6`(如 develop_0aedb4);`01 0F`=`BRS08L`。",
|
||||||
"- `01 07` UID 为 24 字符 hex ASCII(96-bit),保证 SysEx 7-bit 安全。",
|
"- `01 07` UID 为 24 字符 hex ASCII(96-bit),保证 SysEx 7-bit 安全。",
|
||||||
"- `04 xx`/`06 xx` 无应答,SENT 表示已发送。",
|
"- `04 xx`/`06 xx` 无应答,SENT 表示已发送。",
|
||||||
"- `FD 01` 升级指令不在本协议范围。",
|
"- `FD 01` 升级指令不在本协议范围。",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue