175 lines
6.2 KiB
PowerShell
175 lines
6.2 KiB
PowerShell
<#
|
|
run_boot_test.ps1 - Automated boot-log capture + verify in one call.
|
|
|
|
Uses the repo's Python serial assistant (tools/serial_tool/serial_tool.py,
|
|
resident daemon on 127.0.0.1:18765, auto-started on first call):
|
|
1. open COM port + clear log (fresh generation for this run)
|
|
2. flash via -FlashCmd (download.bat: download + Reset & Run)
|
|
3. wait-idle: until RX silence >= SettleMs, or MaxWaitMs timeout
|
|
4. extract [RX] payload lines from the log file (prefix/timestamp stripped)
|
|
5. verify_log.ps1 marker check
|
|
|
|
The capture is armed (port open, log cleared) BEFORE flashing, and the
|
|
resident daemon buffers everything in tools/serial_tool/state/serial.log -
|
|
no capture-window timing ritual, no first-byte wait, no EOF retries.
|
|
|
|
Usage:
|
|
powershell -ExecutionPolicy Bypass -File run_boot_test.ps1 `
|
|
[-Port COM6] [-BaudRate 115200] `
|
|
[-SettleMs 8000] [-MaxWaitMs 30000] `
|
|
[-FlashCmd "D:\...\download.bat"] `
|
|
[-Required "App init OK;Network Init;net init: OK"] `
|
|
[-Forbidden "FAIL;ERROR;HardFault"] `
|
|
[-OutDir C:\temp] [-ShowTailLines 15]
|
|
|
|
-Port default: .opencode/serial_config.json "portName" entry.
|
|
-SettleMs: RX silence that ends the capture (default 8000 - boot has a
|
|
natural 3~4s silent gap between tasks; 2000 would truncate the log).
|
|
|
|
Exit codes:
|
|
0 = PASS (captured + all required markers + no forbidden)
|
|
1 = FAIL (marker miss / forbidden hit)
|
|
2 = capture or flash error
|
|
3 = usage / preflight error
|
|
|
|
NOTE: ASCII-only on purpose - project source files contain Chinese and must
|
|
never be rewritten by encoding-sensitive PowerShell. Keep this script ASCII.
|
|
#>
|
|
|
|
[CmdletBinding()]
|
|
param(
|
|
[string]$Port = "",
|
|
[int]$BaudRate = 115200,
|
|
[int]$SettleMs = 8000,
|
|
[int]$MaxWaitMs = 30000,
|
|
[string]$FlashCmd = "",
|
|
[string]$Required = "App init OK;Network Init;net init: OK",
|
|
[string]$Forbidden = "FAIL;ERROR;HardFault",
|
|
[string]$OutDir = "$env:TEMP\opencode",
|
|
[int]$ShowTailLines = 15
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
$repoRoot = Split-Path -Parent $scriptDir
|
|
$py = Join-Path $repoRoot ".venv\Scripts\python.exe"
|
|
$tool = Join-Path $repoRoot "tools\serial_tool\serial_tool.py"
|
|
$verifyScript = Join-Path $scriptDir "verify_log.ps1"
|
|
$cfgFile = Join-Path $repoRoot ".opencode\serial_config.json"
|
|
|
|
# -Port default: the single source of truth is .opencode/serial_config.json
|
|
if (-not $Port) {
|
|
if (Test-Path -LiteralPath $cfgFile) {
|
|
$Port = (Get-Content -LiteralPath $cfgFile -Raw | ConvertFrom-Json).portName
|
|
}
|
|
}
|
|
if (-not $Port) {
|
|
Write-Output "RUN_TEST_ERROR: no -Port given and no portName in $cfgFile"
|
|
exit 3
|
|
}
|
|
|
|
# Default flash command: resolve relative to the repo (no stale absolute paths)
|
|
if (-not $FlashCmd) {
|
|
$FlashCmd = Join-Path $repoRoot "MDK-ARM\download.bat"
|
|
}
|
|
|
|
foreach ($p in @($py, $tool, $verifyScript)) {
|
|
if (-not (Test-Path -LiteralPath $p)) {
|
|
Write-Output "RUN_TEST_ERROR: missing $p"
|
|
exit 3
|
|
}
|
|
}
|
|
if (-not (Test-Path -LiteralPath $FlashCmd)) {
|
|
Write-Output "RUN_TEST_ERROR: flash command not found: $FlashCmd"
|
|
exit 3
|
|
}
|
|
|
|
if (-not (Test-Path -LiteralPath $OutDir)) {
|
|
New-Item -ItemType Directory -Path $OutDir -Force | Out-Null
|
|
}
|
|
|
|
$stamp = Get-Date -Format "yyyyMMdd_HHmmss"
|
|
$bootTxt = Join-Path $OutDir "boot_log_$stamp.txt"
|
|
|
|
function Invoke-Tool {
|
|
param(
|
|
[Parameter(Position = 0)][string]$Command,
|
|
[Parameter(ValueFromRemainingArguments = $true)][string[]]$Rest
|
|
)
|
|
$script:toolOut = (& $py $tool $Command @Rest 2>$null) -join "`n"
|
|
$script:toolRc = $LASTEXITCODE
|
|
}
|
|
|
|
Write-Output "=== Boot test $stamp ==="
|
|
Write-Output "Port: $Port @ ${BaudRate} settle=${SettleMs}ms max=${MaxWaitMs}ms"
|
|
|
|
# 1. open port (auto-starts the serial daemon if it is not running)
|
|
Invoke-Tool "open" "--port" $Port "--baud" $BaudRate "--timeout" 15
|
|
if ($script:toolRc -ne 0) {
|
|
Write-Output "RUN_TEST_ERROR: open failed: $($script:toolOut)"
|
|
exit 2
|
|
}
|
|
|
|
# 2. clear log (fresh generation; only data after this belongs to the run)
|
|
Invoke-Tool "clear" "--timeout" 15
|
|
if ($script:toolRc -ne 0) {
|
|
Write-Output "RUN_TEST_ERROR: clear failed: $($script:toolOut)"
|
|
exit 2
|
|
}
|
|
|
|
# 3. flash (download + Reset & Run). A failed flash does not abort: the
|
|
# board may still have reset; capture + marker check will judge the result.
|
|
Write-Output "FLASH_START: $FlashCmd"
|
|
$sw = [System.Diagnostics.Stopwatch]::StartNew()
|
|
& $FlashCmd
|
|
$flashRc = $LASTEXITCODE
|
|
$sw.Stop()
|
|
Write-Output ("FLASH_RC: {0} elapsed_ms={1}" -f $flashRc, $sw.ElapsedMilliseconds)
|
|
if ($flashRc -ne 0) {
|
|
Write-Output "RUN_TEST_WARN: flash rc=$flashRc (continuing: board may still have reset)"
|
|
}
|
|
|
|
# 4. wait for RX silence (settle) or the overall timeout
|
|
$waitTimeoutS = [int]($MaxWaitMs / 1000) + 20
|
|
Invoke-Tool "wait-idle" "--settle-ms" $SettleMs "--max-ms" $MaxWaitMs "--timeout" $waitTimeoutS
|
|
if ($script:toolRc -ne 0) {
|
|
Write-Output "RUN_TEST_ERROR: wait-idle failed: $($script:toolOut)"
|
|
exit 2
|
|
}
|
|
$wait = $script:toolOut | ConvertFrom-Json
|
|
Write-Output ("WAIT: reason={0} rx_bytes={1} waited_ms={2}" -f $wait.reason, $wait.rx_bytes, $wait.waited_ms)
|
|
if ($wait.reason -eq "no_data") {
|
|
Write-Output "RUN_TEST_ERROR: no RX data at all (check port / board power / flash)"
|
|
exit 2
|
|
}
|
|
|
|
# 5. extract [RX] payload lines (strip the "[RX] <iso-timestamp> " prefix)
|
|
Invoke-Tool "log" "--tail" 0 "--timeout" 15
|
|
if ($script:toolRc -ne 0) {
|
|
Write-Output "RUN_TEST_ERROR: log read failed: $($script:toolOut)"
|
|
exit 2
|
|
}
|
|
$logJson = $script:toolOut | ConvertFrom-Json
|
|
$rx = New-Object System.Collections.Generic.List[string]
|
|
foreach ($l in $logJson.lines) {
|
|
if ($l -is [string] -and $l.StartsWith("[RX] ")) {
|
|
$rest = $l.Substring(5)
|
|
$sp = $rest.IndexOf(" ")
|
|
if ($sp -ge 0) { $rx.Add($rest.Substring($sp + 1)) } else { $rx.Add($rest) }
|
|
}
|
|
}
|
|
if ($rx.Count -eq 0) {
|
|
Write-Output "RUN_TEST_ERROR: no [RX] lines in log (device silent?)"
|
|
exit 2
|
|
}
|
|
[System.IO.File]::WriteAllLines($bootTxt, $rx, (New-Object System.Text.UTF8Encoding($false)))
|
|
Write-Output "Boot log: $bootTxt (lines=$($rx.Count) gen=$($logJson.gen))"
|
|
|
|
# 6. marker verification
|
|
& $verifyScript -LogPath $bootTxt -Required $Required -Forbidden $Forbidden `
|
|
-ShowTailLines $ShowTailLines
|
|
$verifyRc = $LASTEXITCODE
|
|
Write-Output "RUN_TEST_RC=$verifyRc"
|
|
exit $verifyRc
|