Add 0902 full-screen boot logo to external UI resource pack.

Draw POWER_ON from UI0902_BOOT_LOGO, add ui boot RTT preview command, and harden RTT flash ACK pacing.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
yuquanjun 2026-09-02 16:57:36 +08:00
parent 41052d334d
commit 2f84c3bb9b
6 changed files with 66 additions and 31 deletions

View File

@ -51,11 +51,9 @@ static void app_log_flash_flush_page(void)
s_flash_remain -= s_flash_page_len; s_flash_remain -= s_flash_page_len;
s_flash_page_len = 0U; s_flash_page_len = 0U;
/* 扇区边界或结束时 ACK主机据此节流 */ /* 每页 ACK避免主机打爆 RTT 下行缓冲 */
if ((s_flash_addr & 0xFFFU) == 0U || s_flash_remain == 0U) { snprintf(ack, sizeof(ack), "FLASH_ACK %lu\n", (unsigned long)s_flash_addr);
snprintf(ack, sizeof(ack), "FLASH_ACK %lu\n", (unsigned long)s_flash_addr); SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, ack);
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, ack);
}
} }
static void app_log_flash_feed(const uint8_t *data, unsigned len) static void app_log_flash_feed(const uint8_t *data, unsigned len)
@ -266,6 +264,13 @@ uint8_t app_log_try_command(const char *cmd)
app_log_flash_start(size); app_log_flash_start(size);
return 1U; return 1U;
} }
if (strncmp(cmd, "ui boot", 7) == 0) {
LCD_BLK_Set();
LCD_WR_PIC_FROM_FLASH(0, 0, UI0902_BOOT_LOGO_W, UI0902_BOOT_LOGO_H,
UI0902_BOOT_LOGO_ADDR);
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "UI_BOOT_OK\n");
return 1U;
}
return 0U; return 0U;
} }

View File

@ -181,8 +181,8 @@ void IdleProcess(DisplayTaskMessage_Type msg)
{ {
case MSG_ID_POWER_ON : case MSG_ID_POWER_ON :
LCD_BLK_Set(); LCD_BLK_Set();
LCD_FillByColor(0, 0, 240, 320, WHITE); LCD_WR_PIC_FROM_FLASH(0, 0, UI0902_BOOT_LOGO_W, UI0902_BOOT_LOGO_H,
LCD_WR_PIC_FROM_FLASH(40, 80, 168, 155, 0x00000000); UI0902_BOOT_LOGO_ADDR);
BSP_SelectAdcChannel(6); BSP_SelectAdcChannel(6);
/* 让出 CPU避免忙等卡住触摸/主循环线程 */ /* 让出 CPU避免忙等卡住触摸/主循环线程 */
rt_thread_mdelay(1000); rt_thread_mdelay(1000);

View File

@ -276,7 +276,11 @@
#define UI0902_TXT_RESTORE_CONFIRM_W 71 #define UI0902_TXT_RESTORE_CONFIRM_W 71
#define UI0902_TXT_RESTORE_CONFIRM_H 14 #define UI0902_TXT_RESTORE_CONFIRM_H 14
#define UI0902_BTN_CANCEL_BIG_ADDR (UI0902_RES_BASE + 0x086000UL) /* 11872 bytes */ #define UI0902_BOOT_LOGO_ADDR (UI0902_RES_BASE + 0x086000UL) /* 153600 bytes */
#define UI0902_BOOT_LOGO_W 240
#define UI0902_BOOT_LOGO_H 320
#define UI0902_BTN_CANCEL_BIG_ADDR (UI0902_RES_BASE + 0x0AC000UL) /* 11872 bytes */
#define UI0902_BTN_CANCEL_BIG_W 106 #define UI0902_BTN_CANCEL_BIG_W 106
#define UI0902_BTN_CANCEL_BIG_H 56 #define UI0902_BTN_CANCEL_BIG_H 56

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

@ -91,9 +91,13 @@ def wait_for(jlink, marker: str, timeout_s: float = 30.0) -> str:
def send_bytes(jlink, payload: bytes) -> None: def send_bytes(jlink, payload: bytes) -> None:
off = 0 off = 0
while off < len(payload): while off < len(payload):
n = jlink.rtt_write(0, list(payload[off : off + 128])) try:
if n <= 0: n = jlink.rtt_write(0, list(payload[off : off + 64]))
time.sleep(0.01) except Exception:
time.sleep(0.05)
continue
if n is None or n <= 0:
time.sleep(0.02)
continue continue
off += n off += n
@ -124,11 +128,9 @@ def main() -> None:
_ = rtt_read_text(jlink, 0.3) _ = rtt_read_text(jlink, 0.3)
if not args.no_reset: if not args.no_reset:
# Hardware reset clears any stuck flash_mode from a previous attempt
print("hardware reset...") print("hardware reset...")
jlink.reset(halt=False) jlink.reset(halt=False)
time.sleep(3.5) time.sleep(3.5)
# RTT CB may move after reboot — re-find
try: try:
jlink.rtt_stop() jlink.rtt_stop()
except Exception: except Exception:
@ -148,26 +150,23 @@ def main() -> None:
print(log.strip().splitlines()[-1]) print(log.strip().splitlines()[-1])
time.sleep(0.2) time.sleep(0.2)
# Smaller chunks + brief pause so erase/write can keep up with RTT down-buffer chunk = 256
chunk = 128
sent = 0 sent = 0
t0 = time.time() t0 = time.time()
send_bytes(jlink, data[0:256]) receiving = False
sent = 256
wait_for(jlink, "FLASH_RX", 20.0)
print("device receiving...")
while sent < size: while sent < size:
end = min(sent + chunk, size) end = min(sent + chunk, size)
send_bytes(jlink, data[sent:end]) send_bytes(jlink, data[sent:end])
sent = end sent = end
if sent % 256 == 0: # 一页对应一次 ACKFLASH_RX 可能夹在同一次读缓冲里,勿分两次 wait
time.sleep(0.002) log = wait_for(jlink, "FLASH_ACK", 60.0)
if sent % 4096 == 0 or sent == size: if (not receiving) and ("FLASH_RX" in log or "FLASH_ACK" in log):
log = wait_for(jlink, "FLASH_ACK", 60.0) receiving = True
if "FLASH_UI0902_OK" in log: print("device receiving...")
print(log.strip().splitlines()[-1]) if "FLASH_UI0902_OK" in log:
print("Done. Mode-select should redraw with new assets.") print(log.strip().splitlines()[-1])
return print("Done. Mode-select should redraw with new assets.")
return
if sent % (64 * 1024) == 0 or sent == size: if sent % (64 * 1024) == 0 or sent == size:
elapsed = time.time() - t0 elapsed = time.time() - t0
print(f" {sent}/{size} ({100.0 * sent / size:.1f}%) {elapsed:.1f}s") print(f" {sent}/{size} ({100.0 * sent / size:.1f}%) {elapsed:.1f}s")

View File

@ -48,9 +48,26 @@ def rgba_to_rgb565(im):
r = (r * a) // 255 r = (r * a) // 255
g = (g * a) // 255 g = (g * a) // 255
b = (b * a) // 255 b = (b * a) // 255
c = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3) v = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3)
out[i] = (c >> 8) & 0xFF out[i] = (v >> 8) & 0xFF
out[i + 1] = c & 0xFF out[i + 1] = v & 0xFF
i += 2
return bytes(out), w, h
def rgba_to_rgb565_opaque(im):
"""Full-screen boot/charge: keep dark background pixels (no near-black punch-through)."""
im = im.convert("RGB")
px = im.load()
w, h = im.size
out = bytearray(w * h * 2)
i = 0
for y in range(h):
for x in range(w):
r, g, b = px[x, y]
v = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3)
out[i] = (v >> 8) & 0xFF
out[i + 1] = v & 0xFF
i += 2 i += 2
return bytes(out), w, h return bytes(out), w, h
@ -172,6 +189,8 @@ EXTERNAL = [
("TXT_RESTORE_V2", "06_控件/文字/文字-25.png"), ("TXT_RESTORE_V2", "06_控件/文字/文字-25.png"),
("TXT_RESTORE_H", "06_控件/文字/文字-26.png"), ("TXT_RESTORE_H", "06_控件/文字/文字-26.png"),
("TXT_RESTORE_CONFIRM", "06_控件/文字/文字-27.png"), ("TXT_RESTORE_CONFIRM", "06_控件/文字/文字-27.png"),
# 整屏开机 Logo避开旧 0x0 / 充电 0xCB70 区,挂在 ui0902 资源包末尾)
("BOOT_LOGO", "07_开机/开机界面-20.png"),
] ]
@ -209,7 +228,15 @@ def main():
im = Image.open(SRC / rel) im = Image.open(SRC / rel)
if name in ("ROW_UNIVERSAL_NOT", "ROW_UNIVERSAL_SEL", "ROW_NORMAL_NOT", "ROW_NORMAL_SEL", "ROW_EXPERT_NOT", "ROW_EXPERT_SEL"): if name in ("ROW_UNIVERSAL_NOT", "ROW_UNIVERSAL_SEL", "ROW_NORMAL_NOT", "ROW_NORMAL_SEL", "ROW_EXPERT_NOT", "ROW_EXPERT_SEL"):
im = im.resize(ROW_RESIZE, Image.LANCZOS) im = im.resize(ROW_RESIZE, Image.LANCZOS)
data, w, h = rgba_to_rgb565(im) data, w, h = rgba_to_rgb565(im)
elif name == "BOOT_LOGO":
if im.size[0] >= 241 and im.size[1] >= 321:
im = im.crop((0, 0, 240, 320))
elif im.size != (240, 320):
im = im.resize((240, 320), Image.LANCZOS)
data, w, h = rgba_to_rgb565_opaque(im)
else:
data, w, h = rgba_to_rgb565(im)
entries[name] = (offset, w, h, len(data)) entries[name] = (offset, w, h, len(data))
blob += data blob += data
pad = (-len(blob)) % ALIGN pad = (-len(blob)) % ALIGN