enet-validator/scripts/session/analyze_ss2.ps1

82 lines
4.4 KiB
PowerShell
Raw Permalink Normal View History

[Console]::OutputEncoding = [Text.Encoding]::UTF8
$ErrorActionPreference = "Stop"
function H2B($hex) {
if (-not $hex) { return $null }
$n = $hex.Length / 2
$b = New-Object byte[] $n
for ($i = 0; $i -lt $n; $i++) { $b[$i] = [Convert]::ToByte($hex.Substring(2*$i, 2), 16) }
return $b
}
function UidStr($b, $o) { if ($b.Length -lt $o+6) { return "?" }; return ($b[$o..($o+5)] | ForEach-Object { $_.ToString("x2") }) -join "" }
function Analyze2($name, $tsv, $devIp, $hostIp) {
$lines = [IO.File]::ReadAllLines($tsv)
Write-Host "`n############ $name ($devIp) ############"
# 真实 RDM 查询: 0x20-0x21 == 0200 (事件B帧), flag 0x30==0
$rdmCmd = @{}; $rdmPid = @{}; $rdmPidUid = @{}
$falsePos = 0
$bFrames = New-Object System.Collections.ArrayList # 所有事件B帧 (时间, 0x22序号, 0x3C, 0x3D)
foreach ($l in $lines) {
$p = $l -split "`t"; if ($p.Count -lt 5 -or -not $p[4]) { continue }
if ($p[1] -ne $hostIp -or $p[2] -ne $devIp) { continue }
$b = H2B $p[4]; if ($b.Length -lt 0x52 -or $b.Length -gt 2000) { continue }
if ([int]$b[4] -ne 4) { continue }
$t = [double]$p[0]
$isB = ($b[0x20] -eq 2 -and $b[0x21] -eq 0)
$isA = ($b[0x20] -eq 1 -and $b[0x21] -eq 1)
if ($isB -and $b.Length -gt 0x44) {
[void]$bFrames.Add(@{ t=$t; seq=([int]$b[0x22]+[int]$b[0x23]*256); c3c=$b[0x3C]; c3d=$b[0x3D]; flag=$b[0x30] })
}
# RDM 判定: 必须 0x3C==01 且 cmd 匹配
if ($b.Length -gt 0x44 -and $b[0x3C] -eq 1 -and ($b[0x3D] -eq 0x24 -or $b[0x3D] -eq 0x18 -or $b[0x3D] -eq 0x19 -or $b[0x3D] -eq 0x1a)) {
if ($b[0x30] -ne 0) { continue }
if ($isA) { $falsePos++; continue } # DMX-A 帧通道数据巧合 = 假阳性
$cmd = $b[0x3D]
$ck = "cmd={0:x2}" -f $cmd
if (-not $rdmCmd.ContainsKey($ck)) { $rdmCmd[$ck] = 0 }; $rdmCmd[$ck]++
if ($cmd -ne 0x24 -and $b.Length -gt 0x51) {
$pidKey = "{0:x2}{1:x2}" -f $b[0x50], $b[0x51]
$uid = UidStr $b 0x3E
if (-not $rdmPid.ContainsKey($pidKey)) { $rdmPid[$pidKey] = 0 }; $rdmPid[$pidKey]++
$k2 = "$pidKey->$uid"; if (-not $rdmPidUid.ContainsKey($k2)) { $rdmPidUid[$k2] = 0 }; $rdmPidUid[$k2]++
}
}
}
Write-Host ("--- 真实 RDM 查询 (排除 DMX-A 假阳性 {0} 条) ---" -f $falsePos)
$rdmCmd.GetEnumerator() | Sort-Object { [int]$_.Value } -Descending | ForEach-Object { Write-Host (" {0} : {1}" -f $_.Key, $_.Value) }
Write-Host "--- PID 分布 ---"
$rdmPid.GetEnumerator() | Sort-Object { [int]$_.Value } -Descending | Select-Object -First 12 | ForEach-Object { Write-Host (" PID={0} : {1}" -f $_.Key, $_.Value) }
Write-Host "--- PID->UID 细分 (0002/0003/0060/00f0/0201) ---"
$rdmPidUid.GetEnumerator() | Where-Object { $_.Name -match "^(0002|0003|0060|00f0|0201)" } | Sort-Object Name | ForEach-Object { Write-Host (" {0} : {1}" -f $_.Name, $_.Value) }
# 42B ACK 相关性: 每个 42B 帧之前 200ms 内最近的 B 帧特征
$acks = New-Object System.Collections.ArrayList
foreach ($l in $lines) {
$p = $l -split "`t"; if ($p.Count -lt 5 -or -not $p[4]) { continue }
if ($p[1] -ne $devIp -or $p[2] -ne $hostIp) { continue }
$b = H2B $p[4]; if ($b.Length -ne 42 -or [int]$b[4] -ne 4) { continue }
[void]$acks.Add(@{ t=([double]$p[0]); seq=([int]$b[0x20]+[int]$b[0x21]*256) })
}
$ackByB = @{}
$ackNoB = 0
foreach ($a in $acks) {
# 找 seq == ack.seq+1 的 B 帧 (§4.3: ACK seq = 事件 seq - 1)
$found = $null
foreach ($bf in $bFrames) {
if ($bf.seq -eq $a.seq + 1) { $found = $bf; break }
}
if ($found) {
$k = "0x3C={0:x2} 0x3D={1:x2} flag={2:x2}" -f $found.c3c, $found.c3d, $found.flag
if (-not $ackByB.ContainsKey($k)) { $ackByB[$k] = 0 }; $ackByB[$k]++
} else { $ackNoB++ }
}
Write-Host ("--- 42B ACK ({0}个) 对应的 B 帧特征 ---" -f $acks.Count)
$ackByB.GetEnumerator() | Sort-Object { [int]$_.Value } -Descending | Select-Object -First 8 | ForEach-Object { Write-Host (" {0} : {1}" -f $_.Key, $_.Value) }
Write-Host (" (无配对 B 帧: {0})" -f $ackNoB)
}
Analyze2 "真机 .1" "$env:TEMP\opencode\ss123.tsv" "192.168.123.1" "192.168.123.113"
Analyze2 "虚拟 .7" "$env:TEMP\opencode\ss58.tsv" "192.168.58.7" "192.168.58.107"
Write-Host "`n分析完成。"