From 93e633472a7da8e2582ac6b760705398be9130bb Mon Sep 17 00:00:00 2001 From: yuquanjun Date: Wed, 23 Sep 2026 07:43:46 +0800 Subject: [PATCH] fix(xpose): allow neck transpose in universal after pick hold-up Universal TM1629 path dropped keys 0-21 before BP_Transpose. Route pick-hold neck keys to transpose, add RTT pick hold inject and a HIL script. Co-authored-by: Cursor --- APP/app_log.c | 11 ++++++ Global/Global.c | 7 +++- tools/test_uni_bp_xpose.py | 75 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 tools/test_uni_bp_xpose.py diff --git a/APP/app_log.c b/APP/app_log.c index de3ae7c..f104468 100644 --- a/APP/app_log.c +++ b/APP/app_log.c @@ -321,6 +321,17 @@ uint8_t app_log_try_command(const char *cmd) SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "BP_PICK_OK\n"); return 1U; } + /* 拨片上推快移调门闩:1=进入 / 0=退出(琴颈键经 BP_Transpose) */ + if (strncmp(cmd, "pick hold ", 10) == 0 && cmd[10] != '\0') { + uint8_t on = (cmd[10] == '1'); + pick_hold_up = on ? 1 : 0; + { + char line[40]; + snprintf(line, sizeof(line), "PICK_HOLD_OK on=%u\n", (unsigned)on); + SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line); + } + return 1U; + } /* band dirty:强制下次冷启动先 Stop(验证 Stop→Start 紧挨是否必被吞) */ if (strncmp(cmd, "band dirty", 10) == 0) { Band_ForceStopBeforeStart(); diff --git a/Global/Global.c b/Global/Global.c index cfdc079..edb12a0 100644 --- a/Global/Global.c +++ b/Global/Global.c @@ -990,9 +990,10 @@ uint8_t BP_Transpose(uint8_t key_idx) } if(new_trans != 15) { + LOG_I("xpose", "bp key=%u trans=%u", (unsigned)key_idx, (unsigned)new_trans); MainTask_Sendmsg(MSG_ID_BP_TRANSPOSE, new_trans, 0, 0); return 1; - } + } } return 0; } @@ -1214,11 +1215,13 @@ void TM1629_Handle(uint8_t key) STRING_MIDI *MIDI; const STRING_MIDI *ORGAN_MIDI; - /* 万能:指板不改和弦、不启停伴奏;保留拍速/停止 */ + /* 万能:指板不改和弦、不启停伴奏;保留拍速/停止/拨片上推快移调 */ if (mGuiData[GUI_TAB_INDEX].Current == 0) { if (key == 22) { Tap_to_Speed(); return; } if (key == 23) { Stop_AutoBand_Request(); return; } + if (BP_Transpose(key)) return; + LOG_I("xpose", "uni skip key=%u hold=%u", (unsigned)key, (unsigned)pick_hold_up); return; /* 忽略 0~21:不改 KEY_ID/USE_MIDI/PressFlag,不启停 OutTime_Stop */ } diff --git a/tools/test_uni_bp_xpose.py b/tools/test_uni_bp_xpose.py new file mode 100644 index 0000000..e846209 --- /dev/null +++ b/tools/test_uni_bp_xpose.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 +"""万能模式:拨片上推 + 琴颈键快移调 RTT 验证。 + +路径:tone bin3 → pick hold 1 → chord key 2/20 +期望:MSG id=24 (BP_TRANSPOSE),[xpose] bp key=… trans=… +""" +from __future__ import annotations + +import sys +import time +from pathlib import Path + +TOOLS = Path(__file__).resolve().parent +if str(TOOLS) not in sys.path: + sys.path.insert(0, str(TOOLS)) + +from k1_harness.transports.rtt_session import open_session # noqa: E402 + + +def has_any(lines, *needles): + return any(all(n in ln for n in needles) for ln in lines) + + +def main() -> int: + results = [] + with open_session(reset=True) as sess: + sess.cmd_ack("tone bin3", "TONE_BIN3", timeout_s=4.0, retries=4) + sess.pump(0.4) + tab_ok = has_any(sess.lines, "TONE_BIN3") or has_any(sess.lines, "tab=0") + results.append(("tone bin3 进万能", tab_ok, "TONE_BIN3" if tab_ok else "无 ACK")) + + mark = len(sess.lines) + sess.cmd("chord key 2", settle=0.6) + after = sess.lines[mark:] + key_ok = has_any(after, "CHORD_KEY_OK") or has_any(after, "tm1629 key=2") + no_xpose = not has_any(after, "id=24") and not has_any(after, "bp key=") + results.append(( + "无上推时 key2 不移调", + key_ok and no_xpose, + f"key_ok={key_ok} leaked_xpose={not no_xpose} lines={after[-8:]}", + )) + + mark = len(sess.lines) + hold_ok = sess.cmd_ack("pick hold 1", "PICK_HOLD_OK", timeout_s=2.5, retries=5) + results.append(("pick hold 1", hold_ok, "PICK_HOLD_OK" if hold_ok else "固件无 pick hold 命令,需重烧")) + + if hold_ok: + mark = len(sess.lines) + sess.cmd_ack("chord key 2", "CHORD_KEY_OK", timeout_s=2.5, retries=4) + sess.pump(0.5) + after = sess.lines[mark:] + got_c = has_any(after, "bp key=2") or has_any(after, "id=24") + results.append(("上推+key2 → C(0)", got_c, " ".join(after[-12:]))) + + mark = len(sess.lines) + sess.cmd_ack("chord key 20", "CHORD_KEY_OK", timeout_s=2.5, retries=4) + sess.pump(0.5) + after = sess.lines[mark:] + got_b = has_any(after, "trans=11") or has_any(after, "bp key=20") + results.append(("上推+key20 → B(11)", got_b, " ".join(after[-12:]))) + + sess.cmd("pick hold 0", settle=0.2) + sess.cmd("chord key 0", settle=0.2) + + print("\n=== 万能琴颈移调 RTT ===") + fail = 0 + for name, ok, detail in results: + print(f"{'PASS' if ok else 'FAIL'} {name} {detail}") + if not ok: + fail += 1 + return 1 if fail else 0 + + +if __name__ == "__main__": + raise SystemExit(main())