2026-09-14 15:05:17 +08:00
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
"""packs 套件:资源包 1.bin/2.bin/3.bin 加载校验 + 拨片起奏 + 3.bin 尾奏回归.
|
|
|
|
|
|
|
|
|
|
|
|
- 加载: `tone bin1 N` / `tone bin2 N` / `tone bin3 N` → 期望 TONE_* 行 ret=0 且地址 OK
|
|
|
|
|
|
(`tone bin2` 依赖新固件命令;缺失时 2.bin 用例记 SKIP)
|
|
|
|
|
|
- 起奏: `tone start` 后 3s 内应有 [PITCH] on 事件
|
|
|
|
|
|
- 尾奏(音师需求 20260914): 万能 3.bin 起奏后 `adc key 1 on`(独立尾奏键,
|
|
|
|
|
|
与万能第4段落键同路径 AutoBand_StartOutro)→ 之后 4s 内仍应出现 [PITCH] on,
|
|
|
|
|
|
不再「一按立刻全静音」;结束 `adc key 1 off`
|
|
|
|
|
|
"""
|
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
|
|
from ..transports.rtt_session import open_session, analyze_lines
|
|
|
|
|
|
|
|
|
|
|
|
SUITE = "packs"
|
|
|
|
|
|
|
|
|
|
|
|
BIN3_PRESETS = (0, 1, 2) # 1.1645 / 2.1564 / 3.1364
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-09-14 16:16:11 +08:00
|
|
|
|
def _load_and_check(report, sess, cmd: str, tag: str, name: str, *, missing: str = "FAIL") -> bool:
|
|
|
|
|
|
"""发加载命令,校验 <tag> 行。True=有响应;False=无响应(按 missing 记结果)."""
|
|
|
|
|
|
sess.pump(0.2)
|
|
|
|
|
|
got = sess.cmd_ack(cmd, tag, timeout_s=4.0, retries=4)
|
|
|
|
|
|
if not got:
|
|
|
|
|
|
report.add(SUITE, name, missing, f"无 {tag} 响应")
|
2026-09-14 15:05:17 +08:00
|
|
|
|
return False
|
2026-09-14 16:16:11 +08:00
|
|
|
|
hit = [l for l in sess.lines[-20:] if tag in l]
|
|
|
|
|
|
line = hit[-1] if hit else tag
|
2026-09-14 15:05:17 +08:00
|
|
|
|
ok = "ret=0" in line and "OK" in line and "MISMATCH" not in line
|
2026-09-14 16:16:11 +08:00
|
|
|
|
if "ret=" not in line and tag in line:
|
|
|
|
|
|
ok = "MISMATCH" not in line and "ERR" not in line
|
2026-09-14 15:05:17 +08:00
|
|
|
|
report.add(SUITE, name, "PASS" if ok else "FAIL", line.strip())
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def run(report, ctx) -> None:
|
|
|
|
|
|
with open_session(ctx.device) as sess:
|
2026-09-14 16:16:11 +08:00
|
|
|
|
if not sess.cmd_ack("log status", "LOG_STATUS", timeout_s=3.0, retries=4):
|
|
|
|
|
|
report.add(SUITE, "RTT 下行探测", "FAIL", "log status 无响应(J-Link/固件忙?)")
|
|
|
|
|
|
return
|
|
|
|
|
|
sess.cmd("log clear", 0.3)
|
2026-09-14 15:05:17 +08:00
|
|
|
|
|
|
|
|
|
|
_load_and_check(report, sess, "tone bin1 0", "TONE_BIN1", "1.bin 节奏加载 idx0")
|
|
|
|
|
|
|
2026-09-14 16:16:11 +08:00
|
|
|
|
if not _load_and_check(report, sess, "tone bin2 0", "TONE_BIN2",
|
|
|
|
|
|
"2.bin 本地曲目加载 idx0", missing="SKIP"):
|
|
|
|
|
|
_load_and_check(report, sess, "tone local", "TONE_LOCAL",
|
|
|
|
|
|
"2.bin 本地曲目加载(tone local)", missing="SKIP")
|
2026-09-14 15:05:17 +08:00
|
|
|
|
|
|
|
|
|
|
bin3_ok = True
|
|
|
|
|
|
for idx in BIN3_PRESETS:
|
|
|
|
|
|
if not _load_and_check(report, sess, f"tone bin3 {idx}", "TONE_BIN3",
|
|
|
|
|
|
f"3.bin 万能加载 idx{idx}"):
|
|
|
|
|
|
bin3_ok = False
|
|
|
|
|
|
|
|
|
|
|
|
if not bin3_ok:
|
|
|
|
|
|
report.add(SUITE, "拨片起奏/尾奏", "SKIP", "3.bin 加载失败,级联跳过")
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
# ---- 拨片起奏(万能 idx0)----
|
|
|
|
|
|
sess.cmd("log clear", 0.2)
|
2026-09-14 16:16:11 +08:00
|
|
|
|
sess.cmd_ack("tone bin3 0", "TONE_BIN3", timeout_s=4.0, retries=3)
|
2026-09-14 15:05:17 +08:00
|
|
|
|
base = len(sess.lines)
|
2026-09-14 16:16:11 +08:00
|
|
|
|
sess.cmd_ack("tone start", "TONE_START_DONE", timeout_s=3.0, retries=3)
|
2026-09-14 15:05:17 +08:00
|
|
|
|
sess.pump(3.0)
|
|
|
|
|
|
pick_lines = sess.lines[base:]
|
|
|
|
|
|
pitch_on = [l for l in pick_lines if "[PITCH]" in l and " on " in l]
|
|
|
|
|
|
report.add(SUITE, "3.bin 拨片起奏有声", "PASS" if pitch_on else "FAIL",
|
|
|
|
|
|
f"{len(pitch_on)} 条 PITCH on" if pitch_on else "起奏后无 PITCH on")
|
|
|
|
|
|
|
2026-09-14 16:16:11 +08:00
|
|
|
|
# ---- 尾奏回归 ----
|
|
|
|
|
|
if not sess.cmd_ack("adc key 1 on", "ADC_KEY_OK", timeout_s=2.5, retries=4):
|
|
|
|
|
|
# 兜底:万能第 4 键(固件已映射到 AutoBand_StartOutro)
|
|
|
|
|
|
if sess.cmd_ack("chord key 4", "CHORD_KEY_OK", timeout_s=2.0, retries=3):
|
|
|
|
|
|
report.add(SUITE, "3.bin 尾奏触发", "PASS", "chord key 4(adc key 不可用)")
|
|
|
|
|
|
else:
|
|
|
|
|
|
report.add(SUITE, "3.bin 尾奏(adc key 1)", "SKIP",
|
|
|
|
|
|
"固件缺少 'adc key';chord key 4 也无 ACK")
|
|
|
|
|
|
sess.cmd_ack("chord key 23", "CHORD_KEY_OK", timeout_s=2.0, retries=3)
|
|
|
|
|
|
return
|
|
|
|
|
|
else:
|
|
|
|
|
|
report.add(SUITE, "3.bin 尾奏触发", "PASS", "ADC_KEY_OK")
|
|
|
|
|
|
|
2026-09-14 15:05:17 +08:00
|
|
|
|
out_base = len(sess.lines)
|
|
|
|
|
|
sess.pump(4.0)
|
|
|
|
|
|
outro_lines = sess.lines[out_base:]
|
|
|
|
|
|
outro_pitch = [l for l in outro_lines if "[PITCH]" in l and " on " in l]
|
2026-09-14 16:16:11 +08:00
|
|
|
|
stopped = any(("Stop_AutoBand" in l) or ("stop" in l.lower() and "AUTOBAND" in l)
|
2026-09-14 15:05:17 +08:00
|
|
|
|
for l in outro_lines)
|
|
|
|
|
|
if outro_pitch:
|
|
|
|
|
|
report.add(SUITE, "3.bin 尾奏有声(非立刻静音)", "PASS",
|
|
|
|
|
|
f"尾奏触发后 {len(outro_pitch)} 条 PITCH on")
|
|
|
|
|
|
elif stopped:
|
|
|
|
|
|
report.add(SUITE, "3.bin 尾奏有声(非立刻静音)", "FAIL",
|
|
|
|
|
|
"尾奏触发后立刻停止(3.bin Postamble 数据为空?见音师需求 20260914)")
|
|
|
|
|
|
else:
|
|
|
|
|
|
report.add(SUITE, "3.bin 尾奏有声(非立刻静音)", "FAIL",
|
|
|
|
|
|
"尾奏触发后无任何 PITCH on")
|
2026-09-14 16:16:11 +08:00
|
|
|
|
sess.cmd_ack("adc key 1 off", "ADC_KEY_OK", timeout_s=2.0, retries=2)
|
|
|
|
|
|
sess.cmd_ack("chord key 23", "CHORD_KEY_OK", timeout_s=2.0, retries=3)
|
2026-09-14 15:05:17 +08:00
|
|
|
|
|
|
|
|
|
|
res = analyze_lines(sess.lines)
|
|
|
|
|
|
if res.fail:
|
|
|
|
|
|
report.add(SUITE, "音区映射断言", "FAIL", f"{res.fail} 条 FAIL(详见日志)")
|
|
|
|
|
|
elif res.ok:
|
|
|
|
|
|
report.add(SUITE, "音区映射断言", "PASS", f"{res.ok} OK / {res.skip} SKIP")
|
|
|
|
|
|
else:
|
|
|
|
|
|
report.add(SUITE, "音区映射断言", "SKIP", "无可分析 PITCH 样本")
|