- 增加可选快速串口模式,缩短虚拟串口和 UART 接收耗时并保留 DMA、组帧与固件回执 - 增加 just stop 和虚拟串口归属记录,支持正常退出及残留端口清理 - 修正 PowerShell 脚本编码,保留升级大帧传输所需的驱动节流 - 补充 Flash 编程并行度寄存器读写,避免固件升级产生未处理位警告 - 修正 Monitor 运行错误处理及 UART 接收队列访问的锁保护 - 删除测试目录、专用客户端与测试运行分支,清理 Web 未引用资源和依赖 - 更新快速串口配置及启动、退出说明 - BREAKING CHANGE: 移除 just test 及其测试选项,项目仅保留运行和环境管理命令
94 lines
4.2 KiB
PowerShell
94 lines
4.2 KiB
PowerShell
param(
|
|
[Parameter(Mandatory = $true)][string]$ComPort,
|
|
[int]$TcpPort,
|
|
[string]$StateDirectory,
|
|
[Parameter(Mandatory = $true)][string]$OwnershipFile,
|
|
[switch]$Cleanup,
|
|
[switch]$Fast
|
|
)
|
|
|
|
# Run in 32-bit Windows PowerShell: the installed virtual-port ActiveX is x86.
|
|
$ErrorActionPreference = 'Stop'
|
|
[Console]::OutputEncoding = [Text.UTF8Encoding]::new($false)
|
|
|
|
function Remove-OwnedPort {
|
|
param($Port)
|
|
if (-not (Test-Path -LiteralPath $OwnershipFile)) { return }
|
|
$owner = Get-Content -LiteralPath $OwnershipFile -Raw -Encoding UTF8 | ConvertFrom-Json
|
|
if ($owner.com_port -ne $ComPort) { throw 'Virtual COM ownership record does not match the requested port' }
|
|
if ($owner.pid -ne $PID) {
|
|
$process = Get-CimInstance Win32_Process -Filter "ProcessId=$([int]$owner.pid)"
|
|
if ($process -and $process.CommandLine -like "*$OwnershipFile*") {
|
|
throw "$ComPort bridge is still running (PID $($owner.pid)); stop its Renode instance first"
|
|
}
|
|
}
|
|
if ([IO.Ports.SerialPort]::GetPortNames() -contains $ComPort) {
|
|
if (-not $Port.IsCreated -and -not $Port.Attach($ComPort)) { throw "Cannot attach owned port $ComPort" }
|
|
if ($Port.IsOpened) { throw "$ComPort is still open in another application; close that application and run just stop again" }
|
|
if (-not $Port.Delete()) { throw "Cannot remove owned port $ComPort" }
|
|
$deadline = [DateTime]::UtcNow.AddSeconds(3)
|
|
while ([IO.Ports.SerialPort]::GetPortNames() -contains $ComPort) {
|
|
if ([DateTime]::UtcNow -ge $deadline) { throw "$ComPort device removal has not completed; run just stop again" }
|
|
Start-Sleep -Milliseconds 100
|
|
}
|
|
}
|
|
Remove-Item -LiteralPath $OwnershipFile
|
|
}
|
|
|
|
$vsp = New-Object -ComObject VSPort.VSPortAx
|
|
$vsp.DeleteOnExit = $false
|
|
$client = New-Object Net.Sockets.TcpClient
|
|
$created = $false
|
|
try {
|
|
if ($Cleanup) {
|
|
Remove-OwnedPort $vsp
|
|
return
|
|
}
|
|
if ([IO.Ports.SerialPort]::GetPortNames() -contains $ComPort) {
|
|
throw "$ComPort already exists; choose an unused virtual port"
|
|
}
|
|
$created = $vsp.CreatePort($ComPort)
|
|
if (-not $created) { throw "Cannot create $ComPort" }
|
|
# 归属记录独立于 run.json,终端中断导致驱动设备残留时仍可恢复清理
|
|
@{ com_port = $ComPort; pid = $PID } | ConvertTo-Json -Compress |
|
|
Set-Content -LiteralPath $OwnershipFile -Encoding UTF8
|
|
$vsp.DeleteOnExit = $true
|
|
# 驱动关闭限速时会截断超过 8192 字节的写入,升级帧最大为 8206 字节,必须保留节流
|
|
if (-not $vsp.SetStrictBaudrate($true)) { throw 'Cannot enable baud-rate emulation' }
|
|
$client.NoDelay = $true
|
|
$client.Connect('127.0.0.1', $TcpPort)
|
|
$stream = $client.GetStream()
|
|
$vsp.SetCTS($true) | Out-Null
|
|
$vsp.SetDSR($true) | Out-Null
|
|
$vsp.SetDCD($true) | Out-Null
|
|
$buffer = New-Object byte[] 65536
|
|
[IO.File]::WriteAllText((Join-Path $StateDirectory 'ready'), $ComPort)
|
|
while (-not (Test-Path -LiteralPath (Join-Path $StateDirectory 'stop'))) {
|
|
# Drain all available driver bytes; no fixed 8000-byte application buffer.
|
|
# 快速模式只提高虚拟驱动的模拟速率,仍保留节流以完整传输超过 8192 字节的帧
|
|
if ($Fast -and $vsp.IsOpened -and $vsp.Baudrate -ne 3000000) { $vsp.Baudrate = 3000000 }
|
|
$count = $vsp.InCount
|
|
if ($count -gt 0) {
|
|
[byte[]]$incoming = $vsp.ReadArray($count)
|
|
$stream.Write($incoming, 0, $incoming.Length)
|
|
}
|
|
if ($client.Available -gt 0) {
|
|
$count = $stream.Read($buffer, 0, [Math]::Min($client.Available, $buffer.Length))
|
|
[byte[]]$outgoing = New-Object byte[] $count
|
|
[Array]::Copy($buffer, $outgoing, $count)
|
|
$written = $vsp.WriteArray($outgoing)
|
|
if ($written -ne $count) { throw "Incomplete virtual-port response: $written/$count bytes" }
|
|
} elseif ($client.Client.Poll(0, [Net.Sockets.SelectMode]::SelectRead)) {
|
|
break
|
|
}
|
|
Start-Sleep -Milliseconds 1
|
|
}
|
|
} finally {
|
|
try {
|
|
$client.Close()
|
|
if ($created) { Remove-OwnedPort $vsp }
|
|
} finally {
|
|
[Runtime.InteropServices.Marshal]::FinalReleaseComObject($vsp) | Out-Null
|
|
}
|
|
}
|