82 lines
4.4 KiB
PowerShell
82 lines
4.4 KiB
PowerShell
|
|
[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分析完成。"
|