Skip to content

Commit 87d8788

Browse files
committed
tools: extract shared HIL ramlog and serial expect helpers
- Board scripts supply hil-config.sh; common expect logic lives in tools/hil - Decode GDB console dumps via decode_gdb_console.py
1 parent 38c2337 commit 87d8788

3 files changed

Lines changed: 209 additions & 0 deletions

File tree

tools/hil/decode_gdb_console.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#!/usr/bin/env python3
2+
# SPDX-License-Identifier: MIT
3+
"""Decode g_ulmk_console_log dump from tricore-elf-gdb batch output."""
4+
5+
from __future__ import annotations
6+
7+
import re
8+
import sys
9+
10+
11+
def decode_gdb_console(text: str, max_len: int = 2048) -> str:
12+
idx = text.find("g_ulmk_console_log>:")
13+
if idx < 0:
14+
idx = text.find("g_ulmk_console_log")
15+
chunk = text[idx:] if idx >= 0 else text
16+
chars: list[str] = []
17+
for m in re.finditer(r"(-?\d+)\s+'((?:\\.|[^'\\])*)'", chunk):
18+
b = int(m.group(1)) & 0xFF
19+
if b == 0:
20+
break
21+
chars.append(chr(b))
22+
if len(chars) >= max_len:
23+
break
24+
return "".join(chars)
25+
26+
27+
def main() -> int:
28+
path = sys.argv[1] if len(sys.argv) > 1 else "-"
29+
text = sys.stdin.read() if path == "-" else open(path, errors="replace").read()
30+
sys.stdout.write(decode_gdb_console(text))
31+
return 0
32+
33+
34+
if __name__ == "__main__":
35+
raise SystemExit(main())

tools/hil/hil_ramlog_expect.sh

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
#!/usr/bin/env bash
2+
# SPDX-License-Identifier: MIT
3+
#
4+
# tools/hil/hil_ramlog_expect.sh — flash ELF, dump board RAM console via GDB, expect sentinel.
5+
#
6+
# Requires the board to source hil-config.sh first (or export the ULMK_HIL_* vars):
7+
# ULMK_HIL_FLASH path to flash.sh
8+
# ULMK_HIL_OCD openocd binary
9+
# ULMK_HIL_OCD_SCRIPTS openocd script search path (vendor)
10+
# ULMK_HIL_OCD_BOARD_DIR board openocd dir (cfg + scripts)
11+
# ULMK_HIL_OCD_CFG board openocd cfg filename or path
12+
# ULMK_HIL_GDB_PORT gdb remote port (default 3333)
13+
# ULMK_HIL_GDB_IMAGE docker image with tricore-elf-gdb (default ulipe-microkernel:dev)
14+
# ULMK_HIL_BREAK_DONE optional symbol to break on after boot
15+
# ULMK_HIL_REQUIRE_TAS if 1, require tas_server (default 1)
16+
#
17+
# Usage: hil_ramlog_expect.sh <elf> <expect_string> [fail_string]
18+
19+
set -euo pipefail
20+
21+
HIL_DIR="$(cd "$(dirname "$0")" && pwd)"
22+
ELF="${1:?elf}"
23+
EXPECT="${2:?expect string}"
24+
FAIL_STR="${3:-}"
25+
26+
GDB_PORT="${ULMK_HIL_GDB_PORT:-3333}"
27+
GDB_IMAGE="${ULMK_HIL_GDB_IMAGE:-ulipe-microkernel:dev}"
28+
FLASH="${ULMK_HIL_FLASH:?set ULMK_HIL_FLASH (board hil-config.sh)}"
29+
OCD="${ULMK_HIL_OCD:?set ULMK_HIL_OCD}"
30+
OCD_SCRIPTS="${ULMK_HIL_OCD_SCRIPTS:?}"
31+
OCD_BOARD_DIR="${ULMK_HIL_OCD_BOARD_DIR:?}"
32+
OCD_CFG="${ULMK_HIL_OCD_CFG:?}"
33+
REQUIRE_TAS="${ULMK_HIL_REQUIRE_TAS:-1}"
34+
BREAK_DONE="${ULMK_HIL_BREAK_DONE:-}"
35+
36+
if [[ ! -f "$ELF" ]]; then
37+
echo "ELF not found: ${ELF}" >&2
38+
exit 1
39+
fi
40+
if [[ "$REQUIRE_TAS" == "1" ]] && ! pgrep -f tas_server >/dev/null; then
41+
echo "tas_server not running" >&2
42+
exit 1
43+
fi
44+
45+
echo "ELF: $(basename "$ELF")"
46+
echo "expect: ${EXPECT}"
47+
48+
"$FLASH" "$ELF" >/dev/null
49+
50+
pkill -9 -f "${OCD}" 2>/dev/null || true
51+
sleep 1
52+
"$OCD" -s "${OCD_SCRIPTS}" -s "${OCD_BOARD_DIR}" \
53+
-f "${OCD_CFG}" >/tmp/ulmk-ocd-hil.log 2>&1 &
54+
sleep 3
55+
56+
GDB_OUT=/tmp/ulmk-gdb-hil.log
57+
cleanup() { pkill -9 -f "${OCD}" 2>/dev/null || true; }
58+
trap cleanup EXIT
59+
60+
GDB_EX=(
61+
-ex "set remotetimeout 60"
62+
-ex "target extended-remote :${GDB_PORT}"
63+
-ex "monitor reset halt"
64+
-ex "break ulmk_kern_trap_panic"
65+
)
66+
if [[ -n "$BREAK_DONE" ]]; then
67+
GDB_EX+=(-ex "break ${BREAK_DONE}")
68+
fi
69+
GDB_EX+=(
70+
-ex "continue"
71+
-ex "x/wx &g_ulmk_board_hil_scratch"
72+
-ex "x/wx &g_ulmk_console_log_len"
73+
-ex "x/2048cb &g_ulmk_console_log"
74+
-ex "bt 4"
75+
)
76+
77+
docker run --rm --network host -v "$(dirname "$ELF"):/elf" "$GDB_IMAGE" \
78+
timeout 90 tricore-elf-gdb -batch "/elf/$(basename "$ELF")" \
79+
"${GDB_EX[@]}" >"$GDB_OUT" 2>&1 || true
80+
81+
echo "--- gdb ---"
82+
/usr/bin/tail -80 "$GDB_OUT"
83+
echo "--- end gdb ---"
84+
85+
DECODED="$(python3 "${HIL_DIR}/decode_gdb_console.py" "$GDB_OUT")"
86+
87+
echo "--- decoded log ---"
88+
printf '%s\n' "$DECODED"
89+
echo "--- end decoded ---"
90+
91+
if printf '%s' "$DECODED" | grep -qF "$EXPECT"; then
92+
echo "PASS: ${EXPECT}"
93+
exit 0
94+
fi
95+
96+
if [[ -n "$FAIL_STR" ]] && printf '%s' "$DECODED" | grep -qF "$FAIL_STR"; then
97+
echo "FAIL: reported ${FAIL_STR}" >&2
98+
exit 1
99+
fi
100+
101+
if grep -qE "ulmk_kern_trap_panic" "$GDB_OUT"; then
102+
echo "FAIL: trap_panic hit" >&2
103+
exit 1
104+
fi
105+
106+
echo "FAIL: \"${EXPECT}\" not found" >&2
107+
exit 1

tools/hil/hil_serial_expect.sh

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#!/usr/bin/env bash
2+
# SPDX-License-Identifier: MIT
3+
#
4+
# tools/hil/hil_serial_expect.sh — flash ELF, capture serial until pattern/timeout.
5+
#
6+
# Requires board hil-config (or exports):
7+
# ULMK_HIL_FLASH, ULMK_HIL_SERIAL, ULMK_HIL_SERIAL_BAUD (default 115200)
8+
# Optional:
9+
# ULMK_HIL_OCD, ULMK_HIL_OCD_SCRIPTS, ULMK_HIL_OCD_BOARD_DIR, ULMK_HIL_OCD_CFG
10+
# — if set, re-resume target after opening the serial port
11+
#
12+
# Usage: hil_serial_expect.sh <elf> <regex_pattern> [timeout_s]
13+
14+
set -euo pipefail
15+
16+
ELF="${1:?elf}"
17+
PATTERN="${2:?regex pattern}"
18+
TIMEOUT_S="${3:-30}"
19+
20+
FLASH="${ULMK_HIL_FLASH:?set ULMK_HIL_FLASH}"
21+
SERIAL="${ULMK_HIL_SERIAL:-/dev/ttyUSB0}"
22+
BAUD="${ULMK_HIL_SERIAL_BAUD:-115200}"
23+
24+
pkill -9 -x openocd 2>/dev/null || true
25+
fuser -k "$SERIAL" 2>/dev/null || true
26+
sleep 0.3
27+
28+
"$FLASH" "$ELF"
29+
30+
OUT="$(mktemp)"
31+
python3 - "$OUT" "$PATTERN" "$TIMEOUT_S" "$SERIAL" "$BAUD" <<'PY' &
32+
import serial, time, sys, re
33+
34+
out, pat, to, port, baud = sys.argv[1], sys.argv[2], float(sys.argv[3]), sys.argv[4], int(sys.argv[5])
35+
rx = re.compile(pat.encode() if isinstance(pat, str) else pat)
36+
s = serial.Serial(port, baud, timeout=0.2)
37+
time.sleep(0.05)
38+
s.reset_input_buffer()
39+
buf = b''
40+
t0 = time.time()
41+
while time.time() - t0 < to:
42+
d = s.read(4096)
43+
if d:
44+
buf += d
45+
if rx.search(buf):
46+
time.sleep(0.5)
47+
buf += s.read(8192)
48+
break
49+
open(out, 'wb').write(buf)
50+
s.close()
51+
print(f'captured {len(buf)} bytes -> {out}', file=sys.stderr)
52+
PY
53+
CAP=$!
54+
sleep 0.2
55+
56+
if [[ -n "${ULMK_HIL_OCD:-}" && -n "${ULMK_HIL_OCD_CFG:-}" ]]; then
57+
pkill -9 -x openocd 2>/dev/null || true
58+
"${ULMK_HIL_OCD}" -s "${ULMK_HIL_OCD_SCRIPTS}" -s "${ULMK_HIL_OCD_BOARD_DIR}" \
59+
-f "${ULMK_HIL_OCD_CFG}" \
60+
-c "gdb port disabled; init; reset halt; resume; shutdown" \
61+
>/dev/null 2>&1 || true
62+
fi
63+
64+
wait "$CAP"
65+
echo "===== uart ====="
66+
cat "$OUT"
67+
rm -f "$OUT"

0 commit comments

Comments
 (0)