fix(device-test): contain tool processes and add reviewed preview
This commit is contained in:
1 parent
c98d7527a0
commit
7d31e09cb7
59 files changed
+23722
No files matched your search
@@ -0,0 +1,222 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
实时显示并保存设备串口数据。
|
||||
|
||||
.DESCRIPTION
|
||||
使用 .NET SerialPort 直接独占打开串口。收到的数据会原样写入二进制文件,
|
||||
同时解码后实时显示到当前 PowerShell,并按行写入带时间戳的文本日志。
|
||||
默认只读取数据,不向设备发送指令。DtrEnable 和 RtsEnable 会改变硬件控制线,
|
||||
只有用户明确要求时才能启用。
|
||||
|
||||
.EXAMPLE
|
||||
.\serial_monitor.ps1 -Port COMx -LogPath F:\tmp\embedded-app-pc-debug\task\logs\serial.log
|
||||
|
||||
.EXAMPLE
|
||||
.\serial_monitor.ps1 -Port COMx -LogPath .\serial.log -DurationSeconds 60
|
||||
|
||||
.PARAMETER DtrEnable
|
||||
改变 DTR 硬件控制线;仅在用户明确要求时使用。
|
||||
|
||||
.PARAMETER RtsEnable
|
||||
改变 RTS 硬件控制线;仅在用户明确要求时使用。
|
||||
#>
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]$Port,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]$LogPath,
|
||||
|
||||
[ValidateRange(1, 4000000)]
|
||||
[int]$BaudRate = 115200,
|
||||
|
||||
[ValidateRange(5, 8)]
|
||||
[int]$DataBits = 8,
|
||||
|
||||
[ValidateSet('None', 'Odd', 'Even', 'Mark', 'Space')]
|
||||
[string]$Parity = 'None',
|
||||
|
||||
[ValidateSet('One', 'OnePointFive', 'Two')]
|
||||
[string]$StopBits = 'One',
|
||||
|
||||
[ValidateSet('None', 'XOnXOff', 'RequestToSend', 'RequestToSendXOnXOff')]
|
||||
[string]$Handshake = 'None',
|
||||
|
||||
[string]$EncodingName = 'utf-8',
|
||||
|
||||
[ValidateRange(0, 2147483647)]
|
||||
[int]$DurationSeconds = 0,
|
||||
|
||||
[ValidateRange(1, 5000)]
|
||||
[int]$PollMilliseconds = 100,
|
||||
|
||||
[ValidateRange(64, 1048576)]
|
||||
[int]$BufferSize = 4096,
|
||||
|
||||
[string]$RawPath,
|
||||
|
||||
[switch]$DtrEnable,
|
||||
|
||||
[switch]$RtsEnable
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$serialPort = $null
|
||||
$textWriter = $null
|
||||
$rawStream = $null
|
||||
$pendingLine = ''
|
||||
|
||||
function Write-TimestampedLines {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$Text,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[System.IO.StreamWriter]$Writer
|
||||
)
|
||||
|
||||
$script:pendingLine += $Text
|
||||
while ($true) {
|
||||
$newlineIndex = $script:pendingLine.IndexOf("`n", [System.StringComparison]::Ordinal)
|
||||
if ($newlineIndex -lt 0) {
|
||||
break
|
||||
}
|
||||
$line = $script:pendingLine.Substring(0, $newlineIndex).TrimEnd("`r")
|
||||
$script:pendingLine = $script:pendingLine.Substring($newlineIndex + 1)
|
||||
$Writer.WriteLine(('[{0}] {1}' -f (Get-Date -Format 'yyyy-MM-dd HH:mm:ss.fff'), $line))
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$resolvedLogPath = [System.IO.Path]::GetFullPath($LogPath)
|
||||
if ([string]::IsNullOrWhiteSpace($RawPath)) {
|
||||
$resolvedRawPath = $resolvedLogPath + '.raw.bin'
|
||||
}
|
||||
else {
|
||||
$resolvedRawPath = [System.IO.Path]::GetFullPath($RawPath)
|
||||
}
|
||||
|
||||
$logDirectory = [System.IO.Path]::GetDirectoryName($resolvedLogPath)
|
||||
$rawDirectory = [System.IO.Path]::GetDirectoryName($resolvedRawPath)
|
||||
if (-not [string]::IsNullOrWhiteSpace($logDirectory)) {
|
||||
[System.IO.Directory]::CreateDirectory($logDirectory) | Out-Null
|
||||
}
|
||||
if (-not [string]::IsNullOrWhiteSpace($rawDirectory)) {
|
||||
[System.IO.Directory]::CreateDirectory($rawDirectory) | Out-Null
|
||||
}
|
||||
|
||||
$utf8NoBom = New-Object System.Text.UTF8Encoding($false)
|
||||
$textFileStream = New-Object System.IO.FileStream(
|
||||
$resolvedLogPath,
|
||||
[System.IO.FileMode]::Append,
|
||||
[System.IO.FileAccess]::Write,
|
||||
[System.IO.FileShare]::Read
|
||||
)
|
||||
$textWriter = New-Object System.IO.StreamWriter($textFileStream, $utf8NoBom)
|
||||
$textWriter.AutoFlush = $true
|
||||
$rawStream = New-Object System.IO.FileStream(
|
||||
$resolvedRawPath,
|
||||
[System.IO.FileMode]::Append,
|
||||
[System.IO.FileAccess]::Write,
|
||||
[System.IO.FileShare]::Read
|
||||
)
|
||||
|
||||
try {
|
||||
$encoding = [System.Text.Encoding]::GetEncoding($EncodingName)
|
||||
}
|
||||
catch {
|
||||
throw "无法识别编码 '$EncodingName':$($_.Exception.Message)"
|
||||
}
|
||||
$decoder = $encoding.GetDecoder()
|
||||
|
||||
$serialPort = New-Object System.IO.Ports.SerialPort
|
||||
$serialPort.PortName = $Port
|
||||
$serialPort.BaudRate = $BaudRate
|
||||
$serialPort.DataBits = $DataBits
|
||||
$serialPort.Parity = [System.Enum]::Parse([System.IO.Ports.Parity], $Parity)
|
||||
$serialPort.StopBits = [System.Enum]::Parse([System.IO.Ports.StopBits], $StopBits)
|
||||
$serialPort.Handshake = [System.Enum]::Parse([System.IO.Ports.Handshake], $Handshake)
|
||||
$serialPort.DtrEnable = $DtrEnable.IsPresent
|
||||
$serialPort.RtsEnable = $RtsEnable.IsPresent
|
||||
$serialPort.ReadTimeout = $PollMilliseconds
|
||||
$serialPort.ReadBufferSize = [Math]::Max(4096, $BufferSize)
|
||||
|
||||
try {
|
||||
$serialPort.Open()
|
||||
}
|
||||
catch {
|
||||
throw "无法打开串口 $Port。串口可能不存在或正被其他程序占用:$($_.Exception.Message)"
|
||||
}
|
||||
|
||||
$startTime = Get-Date
|
||||
$startMessage = '[{0}] 已打开 {1},{2} {3}{4}{5},流控 {6};原始数据:{7}' -f `
|
||||
(Get-Date -Format 'yyyy-MM-dd HH:mm:ss.fff'),
|
||||
$Port,
|
||||
$BaudRate,
|
||||
$DataBits,
|
||||
$Parity.Substring(0, 1),
|
||||
$(if ($StopBits -eq 'One') { '1' } elseif ($StopBits -eq 'Two') { '2' } else { '1.5' }),
|
||||
$Handshake,
|
||||
$resolvedRawPath
|
||||
[Console]::WriteLine($startMessage)
|
||||
$textWriter.WriteLine($startMessage)
|
||||
|
||||
$byteBuffer = New-Object byte[] $BufferSize
|
||||
$charBuffer = New-Object char[] ($encoding.GetMaxCharCount($BufferSize))
|
||||
|
||||
while ($true) {
|
||||
if ($DurationSeconds -gt 0 -and ((Get-Date) - $startTime).TotalSeconds -ge $DurationSeconds) {
|
||||
break
|
||||
}
|
||||
|
||||
try {
|
||||
$count = $serialPort.Read($byteBuffer, 0, $byteBuffer.Length)
|
||||
}
|
||||
catch [System.TimeoutException] {
|
||||
continue
|
||||
}
|
||||
|
||||
if ($count -le 0) {
|
||||
continue
|
||||
}
|
||||
$rawStream.Write($byteBuffer, 0, $count)
|
||||
$rawStream.Flush()
|
||||
|
||||
$charCount = $decoder.GetChars($byteBuffer, 0, $count, $charBuffer, 0, $false)
|
||||
if ($charCount -gt 0) {
|
||||
$text = New-Object string($charBuffer, 0, $charCount)
|
||||
[Console]::Write($text)
|
||||
Write-TimestampedLines -Text $text -Writer $textWriter
|
||||
}
|
||||
}
|
||||
}
|
||||
catch {
|
||||
# 使用字符串连接保留底层异常文本,避免异常内容再次参与格式化。
|
||||
$errorMessage = '[' + (Get-Date -Format 'yyyy-MM-dd HH:mm:ss.fff') + '] 串口监测失败:' + [string]$_.Exception.Message
|
||||
[Console]::Error.WriteLine($errorMessage)
|
||||
if ($null -ne $textWriter) {
|
||||
$textWriter.WriteLine($errorMessage)
|
||||
}
|
||||
exit 1
|
||||
}
|
||||
finally {
|
||||
if ($null -ne $textWriter -and -not [string]::IsNullOrEmpty($script:pendingLine)) {
|
||||
$textWriter.WriteLine(('[{0}] {1}' -f (Get-Date -Format 'yyyy-MM-dd HH:mm:ss.fff'), $script:pendingLine.TrimEnd("`r")))
|
||||
}
|
||||
if ($null -ne $serialPort) {
|
||||
if ($serialPort.IsOpen) {
|
||||
$serialPort.Close()
|
||||
}
|
||||
$serialPort.Dispose()
|
||||
}
|
||||
if ($null -ne $rawStream) {
|
||||
$rawStream.Dispose()
|
||||
}
|
||||
if ($null -ne $textWriter) {
|
||||
$textWriter.WriteLine('[{0}] 串口监测结束' -f (Get-Date -Format 'yyyy-MM-dd HH:mm:ss.fff'))
|
||||
$textWriter.Dispose()
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user