#!/usr/bin/env bash # Story C:清空 ring buffer 后试播 HDMI,再保存「仅本次」相关 dmesg(真机、Kaisa) # 用法见:_bmad-output/stories-hdmi-kaisa-bp-2026-04-04.md — Story C 操作卡片 # # sudo ./scripts/collect-storyc-dmesg.sh clear # sudo ./scripts/collect-storyc-dmesg.sh save STOCK|PATCHED # # sudo ./scripts/collect-storyc-dmesg.sh auto STOCK|PATCHED [plughw:卡,设备] # → dmesg -C → speaker-test → 保存 dmesg # 设备优先级:第 3 参数 > 环境变量 STORYC_HDMI_PLUGHW(须 sudo -E 才继承)> aplay 检测首个 HDMI # 推荐:sudo ./scripts/collect-storyc-dmesg.sh auto PATCHED plughw:0,3 # set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" COLLECTED="$REPO_ROOT/audio_topology/collected" mkdir -p "$COLLECTED" need_root() { if [[ "${EUID:-}" -ne 0 ]]; then echo "请使用 sudo 运行本脚本。" >&2 exit 1 fi } # 从 aplay -l 取第一个含 HDMI 的 playback 行,输出 plughw:卡,设备 detect_hdmi_plughw() { local line while IFS= read -r line; do [[ "$line" =~ [Hh][Dd][Mm][Ii] ]] || continue [[ "$line" =~ card[[:space:]]+([0-9]+):.*device[[:space:]]+([0-9]+): ]] || continue echo "plughw:${BASH_REMATCH[1]},${BASH_REMATCH[2]}" return 0 done < <(aplay -l 2>/dev/null) return 1 } write_snapshot() { local label="$1" local host kr ts out host="$(hostname -s)" kr="$(uname -r)" ts="$(date +%Y%m%d_%H%M%S)" out="$COLLECTED/dmesg_storyC_${label}_${kr}_${host}_${ts}.txt" { echo "# Story C — ${label}(仅本次 ring buffer 内自 clear 后的记录)" echo "# 主机: $(hostname)" echo "# 时间: $(date -R)" echo "# 内核: $kr" if [[ -n "${STORYC_AUTO_DEV:-}" ]]; then echo "# auto: speaker-test 设备=${STORYC_AUTO_DEV} 退出码=${STORYC_AUTO_ST:-?}(124=timeout)" fi echo "#" echo "### dpkg(镜像包)" for p in "linux-image-${kr}" "linux-image-unsigned-${kr}"; do dpkg -l "$p" 2>/dev/null || true done echo "" if [[ -n "${STORYC_AUTO_LOG:-}" && -f "${STORYC_AUTO_LOG}" ]]; then echo "### speaker-test 输出(stderr/stdout)" cat "$STORYC_AUTO_LOG" || true echo "" fi echo "### dmesg(过滤:SOF / HDMI / IPC)" dmesg -T 2>/dev/null | grep -iE 'sof-audio|sof_intel|snd_sof|STREAM_PCM|ipc tx|pcm[0-9].*HDMI|HDMI[0-9]:|iDisp|0x60010000|0x80010000|error.*-5|ASoC error' || true echo "" echo "### dmesg(未过滤全文,ring 较短时即「仅本次」)" dmesg -T 2>/dev/null } >"$out" [[ -n "${STORYC_AUTO_LOG:-}" && -f "${STORYC_AUTO_LOG}" ]] && rm -f "$STORYC_AUTO_LOG" unset STORYC_AUTO_DEV STORYC_AUTO_ST STORYC_AUTO_LOG echo "已写入: $out" wc -l "$out" } run_auto() { need_root local lab="${1:?缺少标签 STOCK|PATCHED}" local dev_cli="${2:-}" case "$lab" in STOCK|PATCHED) ;; *) echo "用法: sudo $0 auto STOCK|PATCHED [plughw:卡,设备]" >&2 exit 1 ;; esac command -v aplay >/dev/null 2>&1 || { echo "未找到 aplay,请安装 alsa-utils。" >&2 exit 1 } command -v speaker-test >/dev/null 2>&1 || { echo "未找到 speaker-test,请安装 alsa-utils。" >&2 exit 1 } local dev if [[ -n "$dev_cli" ]]; then dev="$dev_cli" echo "使用命令行设备参数: $dev" elif [[ -n "${STORYC_HDMI_PLUGHW:-}" ]]; then dev="$STORYC_HDMI_PLUGHW" echo "使用环境变量 STORYC_HDMI_PLUGHW: $dev(若未生效,请用第 3 参数或 sudo -E)" else dev="$(detect_hdmi_plughw)" || { echo "aplay -l 中未找到 HDMI 设备。请指定:sudo $0 auto $lab plughw:卡,设备号" >&2 exit 1 } echo "检测到 HDMI 设备: $dev(可用第 3 参数或 STORYC_HDMI_PLUGHW 覆盖)" fi STORYC_AUTO_LOG="$(mktemp)" dmesg -C echo "已 dmesg -C;开始 speaker-test(约 10s 超时)…" set +e timeout 10 speaker-test -c 2 -l 1 -D "$dev" "$STORYC_AUTO_LOG" 2>&1 STORYC_AUTO_ST=$? set -e STORYC_AUTO_DEV="$dev" write_snapshot "$lab" } case "${1:-}" in clear) need_root dmesg -C echo "已执行 dmesg -C。请立即用 HDMI 试播一次,然后运行:" echo " sudo $0 save STOCK" echo "或: sudo $0 auto STOCK" ;; save) need_root lab="${2:-STOCK}" case "$lab" in STOCK|PATCHED) ;; *) echo "第二个参数应为 STOCK 或 PATCHED,收到: $lab" >&2 exit 1 ;; esac write_snapshot "$lab" ;; auto) if [[ -z "${2:-}" ]]; then echo "用法: sudo $0 auto STOCK|PATCHED(须显式指定,以免与当前内核状态不符)" >&2 exit 1 fi run_auto "$2" "${3:-}" ;; *) echo "Story C:采集 dmesg(Kaisa / SOF HDMI)" echo "" echo " sudo $0 clear # 仅清空 ring,再手动试 HDMI,再 save" echo " sudo $0 save STOCK|PATCHED # 保存当前 ring" echo " sudo $0 auto STOCK|PATCHED [plughw:0,3] # clear → speaker-test → save" echo "" echo "指定 HDMI:优先「第 3 参数」;STORYC_HDMI_PLUGHW 需 sudo -E 才能传入子进程。" exit 1 ;; esac