K1Guitar/tools/k1_harness/suites/packs_bin123.py

107 lines
5.0 KiB
Python
Raw Normal View History

# -*- 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
def _load_and_check(report, sess, cmd: str, tag: str, name: str) -> bool:
"""发加载命令,校验 <tag> 行 ret=0 且 OK。返回是否可用False=命令缺失→SKIP"""
sess.pump(0.15)
sess.cmd(cmd, settle=0.1)
deadline_lines = sess.pump(2.5)
hit = [l for l in deadline_lines if tag in l]
if not hit:
return False
line = hit[-1]
ok = "ret=0" in line and "OK" in line and "MISMATCH" not in line
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:
sess.cmd("log clear", 0.2)
# ---- 加载校验 ----
_load_and_check(report, sess, "tone bin1 0", "TONE_BIN1", "1.bin 节奏加载 idx0")
if not _load_and_check(report, sess, "tone bin2 0", "TONE_BIN2", "2.bin 本地曲目加载 idx0"):
# 老固件没有 tone bin2退回 tone local 做基本校验
sess.cmd("tone local", settle=0.1)
lines = sess.pump(2.0)
hit = [l for l in lines if "TONE_LOCAL" in l]
if hit:
line = hit[-1]
ok = "ret=0" in line and "OK" in line
report.add(SUITE, "2.bin 本地曲目加载(tone local)", "PASS" if ok else "FAIL", line.strip())
else:
report.add(SUITE, "2.bin 本地曲目加载", "SKIP", "无 TONE_BIN2/TONE_LOCAL 响应")
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
report.add(SUITE, f"3.bin 万能加载 idx{idx}", "FAIL", "无 TONE_BIN3 响应")
if not bin3_ok:
report.add(SUITE, "拨片起奏/尾奏", "SKIP", "3.bin 加载失败,级联跳过")
return
# ---- 拨片起奏(万能 idx0----
sess.cmd("log clear", 0.2)
sess.cmd("tone bin3 0", settle=0.8)
base = len(sess.lines)
sess.cmd("tone start", settle=0.2)
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")
# ---- 尾奏回归adc key 1 = 独立尾奏键与万能第4键同路径----
if not sess.cmd_ack("adc key 1 on", "ADC_KEY_OK", timeout_s=2.0, retries=3):
report.add(SUITE, "3.bin 尾奏(adc key 1)", "SKIP",
"固件缺少 'adc key' 命令;请用含 ADC 注入钩子的固件")
sess.cmd_ack("chord key 23", "CHORD_KEY_OK", timeout_s=2.0, retries=3)
return
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]
stopped = any("Stop_AutoBand" in l or "AUTOBAND" in l and "stop" in l.lower()
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")
sess.cmd_ack("adc key 1 off", "ADC_KEY_OK", timeout_s=2.0, retries=3)
sess.cmd_ack("chord key 23", "CHORD_KEY_OK", timeout_s=2.0, retries=3) # 停止伴奏
# ---- 音区断言(复用 pitch 分析器,软判定)----
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 样本")