feat: show mode for standalone 1-32 rainbow DMX + RDM status polling
- Merge show/hybrid paths: use dmx_a template for DMX payload and replay-extracted SL frame skeleton for RDM. - HOSTDEMO_MODE=show runs indefinitely when secs=0; wave period slowed for smoother breathing. - Update README with show mode usage.
This commit is contained in:
commit
9995335d74
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
/target
|
||||||
|
*.log
|
||||||
|
*.pcap
|
||||||
|
*.tsv
|
||||||
7
Cargo.lock
generated
Normal file
7
Cargo.lock
generated
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "enet-validator"
|
||||||
|
version = "0.1.0"
|
||||||
10
Cargo.toml
Normal file
10
Cargo.toml
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
[package]
|
||||||
|
name = "enet-validator"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
# 闆跺閮ㄤ緷璧栵細std::net::UdpSocket + std::fs 瓒冲
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
opt-level = 2
|
||||||
86
README.md
Normal file
86
README.md
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
# enet-validator — e:cue SymphoLight ↔ Butler e:net 协议逆向与复现
|
||||||
|
|
||||||
|
对 e:cue SymphoLight 5.5 与 Butler S2 之间 UDP/31772 私有协议(e:net)的完整逆向:
|
||||||
|
**AECH 认领算法破解、DMX 帧混淆破解、RDM over e:net 解码**,并分别实现了
|
||||||
|
**设备端仿真**(虚拟 Butler)与**主机端仿真**(hostdemo 直接接管真机)。
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
|
||||||
|
```
|
||||||
|
├── src/ Rust 源码(std only,无外部依赖)
|
||||||
|
│ ├── main.rs 子命令入口
|
||||||
|
│ ├── enet.rs e:net 帧模板 / SO_REUSEADDR 绑定
|
||||||
|
│ ├── tests.rs 虚拟 Butler 设备端(AECH 本地应答 + RDM 灯具仿真 + 解密日志)
|
||||||
|
│ ├── aech.rs AgiosElias.G 认领算法、DMX zPprv0TXRRW 混淆加解密、dmxdec/dmxsend
|
||||||
|
│ ├── hostdemo.rs 主机侧等效示例(真机接管:认领→RDM 发现→加密 DMX 控制)
|
||||||
|
│ └── dmxhash.rs 早期帧标签分析
|
||||||
|
├── samples/ 37 个真实抓包帧样本(hex)
|
||||||
|
├── docs/
|
||||||
|
│ ├── enet_protocol.md ★协议逆向文档(帧布局/算法/实证,最核心)
|
||||||
|
│ └── rust_verification_plan.md 验证计划
|
||||||
|
├── scripts/
|
||||||
|
│ ├── Verify-EnetProtocol.ps1 协议验证套件
|
||||||
|
│ ├── Verify-Rdm.ps1 RDM 验证
|
||||||
|
│ ├── enet_lib.ps1 PS 公共库
|
||||||
|
│ └── session/ 逆向过程中的会话脚本(抓包/分析/部署/推送)
|
||||||
|
└── tools/ DLL 反编译辅助工具(C#)
|
||||||
|
├── IlDump.cs / GetTable.cs / Scan.cs
|
||||||
|
```
|
||||||
|
|
||||||
|
## 构建
|
||||||
|
|
||||||
|
```
|
||||||
|
cargo build --release # std only, 无外部依赖
|
||||||
|
```
|
||||||
|
|
||||||
|
## 子命令(设备端仿真,跑在任意机器,绑 58 网段示例)
|
||||||
|
|
||||||
|
```
|
||||||
|
enet-validator device # 虚拟 Butler 主循环(192.168.58.7)
|
||||||
|
enet-validator discover|announce|heartbeat|euce|session|all
|
||||||
|
```
|
||||||
|
|
||||||
|
## 子命令(主机侧 / 离线分析)
|
||||||
|
|
||||||
|
```
|
||||||
|
enet-validator hostdemo <目标IP> [秒] # 主机侧等效:认领→RDM 发现→加密 DMX 控制
|
||||||
|
# 环境变量 HOSTDEMO_MODE=quick 最小认领+统一会话环
|
||||||
|
# =claimonly 最小认领探针
|
||||||
|
# HOSTDEMO_PRE=<秒> 前奏时长(默认45)
|
||||||
|
enet-validator dmxsend <目标IP> [秒] # 主机侧加密 DMX 播放(自证闭环)
|
||||||
|
enet-validator dmxdec <tsv> # DMX 帧解密验证(离线)
|
||||||
|
enet-validator dmxroll <tsv> # 滚动值分析(离线)
|
||||||
|
enet-validator aechprobe <tsv> <ip> # AECH 在线探测
|
||||||
|
```
|
||||||
|
|
||||||
|
## show 模式:地址 1-32 炫彩呼吸 + RDM 状态轮询
|
||||||
|
|
||||||
|
无需 SymphoLight 运行,独立接管 Butler,持续输出炫彩呼吸 DMX 并轮询设备状态。
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# 永久运行(按 Ctrl+C 停止)
|
||||||
|
$env:HOSTDEMO_MODE = "show"
|
||||||
|
.\target\release\enet-validator.exe hostdemo 192.168.123.1 0
|
||||||
|
|
||||||
|
# 或运行固定秒数
|
||||||
|
.\target\release\enet-validator.exe hostdemo 192.168.123.1 600
|
||||||
|
```
|
||||||
|
|
||||||
|
- DMX:地址 1-32 彩虹呼吸渐变(HMKJ 32 通道灯具)
|
||||||
|
- RDM:每 700ms 轮询 3 台已知 UID,实时打印 `DEVICE_INFO` 与 `DMX_START_ADDRESS`
|
||||||
|
- 依赖:仅需首次抓包文件 `replay_frames.txt` 作为帧骨架模板(程序自带 `samples/` 中亦有备用模板)
|
||||||
|
|
||||||
|
## 已破解要点(详见 docs/enet_protocol.md)
|
||||||
|
|
||||||
|
- **AECH 认领**:`G(x) = x ^ TABLE[(x%32 + 1 + (x*13)%30) % 32]`(无密钥,表内嵌 DLL)
|
||||||
|
- **DMX 混淆**:`r=Random.Next()`;`out[i]=src[(i+rot)%512]^cnt[i]`,`rot=(B12^r)&511`
|
||||||
|
- **RDM**:标准 E1.20 内嵌 type=04 帧(0x3C 起,免 0xCC 起始字节,checksum 含隐含 0xCC)
|
||||||
|
- **1947 端口**:40B ASCII 许可令牌广播(`BlZRQphA…`,每 ~34s 一轮)
|
||||||
|
- 真机固件过滤:AECH 仅应答源 IP=192.168.123.113
|
||||||
|
|
||||||
|
## Ubuntu 虚拟 Butler 部署
|
||||||
|
|
||||||
|
```
|
||||||
|
scp -r enet-validator/ user@192.168.58.7:~/
|
||||||
|
ssh user@192.168.58.7 "cd ~/enet-validator && cargo build --release && ~/run_butler_local.sh"
|
||||||
|
```
|
||||||
80
docs/hostdemo_recap_2026-09-10.md
Normal file
80
docs/hostdemo_recap_2026-09-10.md
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
# hostdemo 攻坚总结 — 真机 Butler .1 主机侧仿真全链路打通
|
||||||
|
|
||||||
|
**日期**:2026-09-10 晚 ~ 09-11 凌晨
|
||||||
|
**结论**:✅ 认领 + RDM 设备发现(3/3)+ DMX 呼吸控制(灯光肉眼确认)
|
||||||
|
**代码**:`HOSTDEMO_MODE=slfull`(src/hostdemo.rs),commit fcb20a7/3056a69
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、最终工作配方
|
||||||
|
|
||||||
|
```
|
||||||
|
1. 发现: type=1 (180B) → 217B 应答
|
||||||
|
2. 认领: announce144 (=102B 身份帧) 单播 → 47B 注册应答
|
||||||
|
→ AECH 质询 (nonce/B12 自选随机) → AERE = G(nonce) ✓
|
||||||
|
3. 循环 verbatim 重放 SL 真实会话帧流 (32540 帧 / 126.7s):
|
||||||
|
- DMX 数据帧: 保留 SL 原帧全部结构, 仅替换 r1/r2 + 密文段
|
||||||
|
(呼吸图案用本次认领的 B12 重加密 → Butler 解密上灯)
|
||||||
|
- RDM 请求: SL 原帧原样 (UN_MUTE / UNIQUE_BRANCH / GET, ff+fe 成对)
|
||||||
|
4. 被动解码应答: DISC 脉冲 → UID; DEVICE_INFO / START_ADDRESS → DMX 地址
|
||||||
|
```
|
||||||
|
|
||||||
|
**实测**:3/3 灯具发现(NFS1K2D@101/2ch、NFM680S@123、HMKJ@1/32ch,
|
||||||
|
应答 15.5k 帧)+ 三色异相呼吸(fade-in),**灯光肉眼确认**。
|
||||||
|
|
||||||
|
运行方式:
|
||||||
|
```
|
||||||
|
set HOSTDEMO_MODE=slfull
|
||||||
|
set REPLAY_FILE=<重放清单.txt> (tshark 提取: time|dst|dstport|payload)
|
||||||
|
enet-validator hostdemo 192.168.123.1 480
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、假设-证伪链(当晚完整过程)
|
||||||
|
|
||||||
|
| # | 假设 | 实验 | 结果 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 1 | 认领后需长前奏 | 45s discovery/announce 广播 | ❌ 无效 |
|
||||||
|
| 2 | 需要 sub=07 绑定帧 | 按实测节奏重放 ×4 | ❌ 无效 |
|
||||||
|
| 3 | 宣告时间戳过期被拒 | live 模板 + 新鲜时间戳 | ❌ 无效 |
|
||||||
|
| 4 | 会话保持 ~2h 需等待 | 45→86 分钟轮询探针 | ❌ 超时后仍拒 |
|
||||||
|
| 5 | 1947 密钥/EUCE 6s 节奏门控 | 会话内补发 | ❌ 单独无效 |
|
||||||
|
| 6 | RDM 帧字段差异 | 模板 vs 实帧 0 差异 | ❌ 排除 |
|
||||||
|
| 7 | **verbatim 重放二分** | 阶段 A(无认领)/B(先认领) | ✅ **B 全通** |
|
||||||
|
|
||||||
|
**教训**:帧级逐字节比对全通过后仍被拒时,问题在会话状态层——
|
||||||
|
用 verbatim 重放做二分是定位此类问题的最快路径。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、深层发现(已写入协议文档 §3.7/§11.7)
|
||||||
|
|
||||||
|
1. **AECH 握手成功 ≠ 会话通道打通**:47B/AERE 全过但自构造 type=4 帧被静默丢弃;
|
||||||
|
verbatim 的 SL 历史帧立即全通 → Butler 在帧级校验某种会话一致性(规则未破解)。
|
||||||
|
2. **RDM 请求帧消息起始位置可变**:UN_MUTE@0x3A vs UNIQUE_BRANCH@0x3C
|
||||||
|
(前置 len16 字段浮动 2B)→ 固定偏移构造必被拒 → 重放绕过。
|
||||||
|
3. **announce144 == ident102**(同一帧两种称呼);真机冷启动序列:
|
||||||
|
广播前奏 → 身份帧 → 47B → AECH×3 → DMX+RDM(首应答延迟 ~1.4s 属正常)。
|
||||||
|
4. **1947 端口"密钥报文"** = 40B ASCII 许可令牌(安装级常量,双目标 21 帧 @200ms
|
||||||
|
每 ~34s 一轮);**EUCE** = 全程每 6s 的许可信标。
|
||||||
|
5. **灯具 MUTE 态跨会话持久**(SL 遗留 mute 挡后续 branch 查询)。
|
||||||
|
6. **密钥盘点**:nonce/B12 逐会话随机自主可控;G 表固定;1947 令牌安装级常量
|
||||||
|
(未做必需性消融)。详见协议文档 §3.7 密钥盘点表。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、遗留事项
|
||||||
|
|
||||||
|
- [ ] RDM 帧变长结构规则(破解后可纯自构造帧发现,摆脱对 SL 原帧依赖)
|
||||||
|
- [ ] 1947 令牌必需性消融实验
|
||||||
|
- [ ] NFM680S 通道数应答漂移(2ch vs 1ch,疑查询时机差异)
|
||||||
|
- [ ] 会话级校验的具体算法(当前只知道"verbatim 能过")
|
||||||
|
|
||||||
|
## 五、产物清单
|
||||||
|
|
||||||
|
- 代码:`src/hostdemo.rs`(slfull/slclaim/sls/hybrid/replay 五模式)
|
||||||
|
- 重放清单:`replay_merged.txt`(sym_startup 101-520s + rdm3 全程,32540 帧)
|
||||||
|
- 抓包:`sym_startup.pcap`(认领+发现全程)、`sym_claim2.pcap`(接管+重启)、
|
||||||
|
`allports.pcap`(全端口,1947 发现)、`hd_claim3.pcap` 等
|
||||||
|
- 文档:`enet_protocol.md` §3.7/§11.7 本夜更新
|
||||||
1
samples/ack_84.hex
Normal file
1
samples/ack_84.hex
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
454e65740400000000001c7c00000000000001002a00000002004275746c010018030000010000000000
|
||||||
1
samples/aere_594.hex
Normal file
1
samples/aere_594.hex
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
454e65740200000000001c7c0000000000000100280200000600017ba8c000161cf12e3900717ba84145524559bb367fffffff0107346701250015000a00000001017ba8c000ffffff00161cf12e39000000000000000000001a0000000101fa0c000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023010000000024000000240000001c001c001d001d8361bf1d00f00af00a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
1
samples/aerep_113.hex
Normal file
1
samples/aerep_113.hex
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
454e65740200000000001c7c0000000000000100280200000600017ba8c000161cf12e3900717ba84145524559bb367ffffffd0107348809000015000a00000001017ba8c000ffffff00161cf12e39000000000000000000001a0000000101fa0c000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023010000000023000000230000001c001c001d001d5904e1c100f00af00a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
1
samples/aerep_115.hex
Normal file
1
samples/aerep_115.hex
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
454e65740200000000001c7c0000000000000100280200000600017ba8c000161cf12e3900717ba84145524559bb367ffffffd0107348809000015000a00000001017ba8c000ffffff00161cf12e39000000000000000000001a0000000101fa0c000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023010000000023000000230000001c001c001d001d51cf405000f00af00a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
1
samples/aerep_117.hex
Normal file
1
samples/aerep_117.hex
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
454e65740200000000001c7c0000000000000100280200000600017ba8c000161cf12e3900717ba84145524559bb367ffffffd0107348809000015000a00000001017ba8c000ffffff00161cf12e39000000000000000000001a0000000101fa0c000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023010000000023000000230000001c001c001d001dfce6923d00f00af00a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
1
samples/announce_144.hex
Normal file
1
samples/announce_144.hex
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
454e65740200000000001c7c0000000000000100660000000100717ba8c0300ed559bb361a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
1
samples/announce_686.hex
Normal file
1
samples/announce_686.hex
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
454e65740100000000001c7c000000000000010084020000150000000000000000000000000000000000000000000000000000000000000000001a000000000001717ba8c000ffffff300ed559bb3600000000000000000000000000000001ce43050500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000043a0f4f7ec175641812b909bdc99f2ff4000000000010003000000000000000000000000000100030000000000000000000000000074006f006e007900630061006f004400450053004b0054004f0050002d0050004500440032004c00560044002d00660037006600340061003000340033002d0031003700650063002d0034003100350036002d0038003100320062002d0039003000390062006400630039003900660032006600660000000000000000000000911f343cf708bf342e8e519da944bd8a5a4a24433989ea070902001819410343003a005c00550073006500720073005c0074006f006e007900630061006f005c0041007000700044006100740061005c004c006f00630061006c005c0065006300750065005c00530059004d00500048004f004c004900470048005400200035002e0035005c00430075007200720065006e007400530068006f0077000000000000000000000000000000000000000000d00df1e81900000081710b0e000000008ee4f7f6190000001e00000000000000010000005a00ffffea07090717182f16010200000000000000000000000002000000000000000000000000201c0000000000000000000001000000000000000000000001000000000000000100000001000000
|
||||||
1
samples/announce_live.hex
Normal file
1
samples/announce_live.hex
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
454e65740100000000001c7c000000000000010084020000150000000000000000000000000000000000000000000000000000000000000000001a000000000001717ba8c000ffffff300ed559bb3600000000000000000000000000000001ce43050500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000043a0f4f7ec175641812b909bdc99f2ff4000000000010003000000000000000000000000000100030000000000000000000000000074006f006e007900630061006f004400450053004b0054004f0050002d0050004500440032004c00560044002d00660037006600340061003000340033002d0031003700650063002d0034003100350036002d0038003100320062002d0039003000390062006400630039003900660032006600660000000000000000000000911f0000000000000000000000000000000000000000d00701010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1bf21b20c0000001e00000000000000010000005a00ffffea07090a163432e003020000000000000000000000000200000000000000000000000098080000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
1
samples/claim_h112.hex
Normal file
1
samples/claim_h112.hex
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
454e65740200000000001c7c0000000000000100280200000500717ba8c0300ed559bb36000000004145434841cad262b4c0d9aea3e3c1cc0898bffec74c63aca7b51e5727a7ae330ca7d61e162e57e9fa86044d898e5f16a8249dd5d6ab360eedef3a8cab7a3a0d12a6a1fb0da2b5d940d50340481523195508af0309d95c6071c73027f4ca3e80e2545f3b9bb5327e4cf63be3ec6408056ec49400a7f6c6d7cc2136a3cb37043849418945728ee5769783f351da3f2cf1ffa99445455bb87a01585bd3949ab415f20299abdac393e0de1e69240274fd8cf445a422a2bef3ed880e44193212e1fccede5fd8a681163c16b46626f294788d5bcfdf4ef69272330eac22cb7e79adcc3c6c55231525e5722e670bed58ccfbf496b7be633393063c6c2bc9fa0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
1
samples/claim_h114.hex
Normal file
1
samples/claim_h114.hex
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
454e65740200000000001c7c0000000000000100280200000500717ba8c0300ed559bb3600000000414543484bbd9d079aea853e547835e96c208e8685db41b02e35c7ba4998a96619b7e95beb13e3aa6ee5bde275b5413f897ac67277b5e64f87493016f5e2bd01411e259c8ed9fd593de4189f1d5f3a78f38830cfd236ee63d099d4a2e2cdb48b5f2e2a1f9bb5327e27bca0578fa4b0af7c6d35939c4731280eb8226db1ee2f0a30c2ccf4055a77702f8d7761bee3e94ed7815265015ac68967ac9429aa47d9398d9626cdd8bca921f5c4640fd0d0692aced495309bca09d5fb438c59c64dc6e8b33dd428bc1c751bd7306f3cf6b6b89742695bd6b1a99ec38d51d1952f505ba7fe7b5c92fb416eb25e7a586a5accde458af5165df2f0370a9f119b6b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
1
samples/claim_h116.hex
Normal file
1
samples/claim_h116.hex
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
454e65740200000000001c7c0000000000000100280200000500717ba8c0300ed559bb360000000041454348e0eb87d5c73e7a5a269b01faa87737503368c0728c0b3a39fdb50e4452f3eaa602687e8ed195928e64ea645915624a7800ba6ca8daf9bdd5b14dd8122f360833b15af840f9a87e9dd6320ea1a6e1239a6b9644978641cb09aaa8dc834a22993e9bb5327ebd805e2de231a8bb6a0a7e573bced2a8ea1c2ed02a3da799f170ac6f8fee9550cbfae056d3e0bf7539682f6117ec5cb76f231f8e7a0c597fd8c53b7284382c7c742e8b40ee7cd50a5db897c10d45820413f4006bcf07d6bfa0607d0da44cf0003cb3ede8611cc9f34d1430c17598719342365e9037c0ad6c57cc9f8dfec76510c796855a5899a3f72a0d1ebad6144a08eeeaca6d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
1
samples/discovery_req_222.hex
Normal file
1
samples/discovery_req_222.hex
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
454e65740100000000001c7c0000000000000100b40000000100746f6e7963616f4445534b544f502d504544324c56442d66376634613034332d1a000000000002717ba8c000ffffff300ed559bb3600000000000000000000000000000001ce430505000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000900
|
||||||
1
samples/discovery_resp_259.hex
Normal file
1
samples/discovery_resp_259.hex
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
454e65740100000000001c7c0000000000000100d90000000f004275746c657220533200000000001b00cc0119453a7ffffff30107346701250015000a00000001017ba8c000ffffff00161cf12e396b3aa8c0300ed559bb351a0000000101fa0c00020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002301000000001e0000001e000000240024002400240020002000720d720d1e0000000a0000000000000000000a00
|
||||||
1
samples/discovery_resp_259_orig.hex
Normal file
1
samples/discovery_resp_259_orig.hex
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
454e65740100000000001c7c0000000000000100d90000000f004275746c657220533200000000000000aaaa5dbbddfa55aa55ae77ebddaf570015000a00000001017ba8c000ffffff00161cf12e39000000000000000000001a0000000101fa0c000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023010000000024000000240000001c001c001d001d001c001c00f00af00a00000000000000000000000000000000
|
||||||
1
samples/discovery_resp_259_rdm.hex
Normal file
1
samples/discovery_resp_259_rdm.hex
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
454e65740100000000001c7c0000000000000100d90000000f004275746c657220533200000000000000aaaa5dbbddfa55aa55ae77ebddaf570015000a00000001017ba8c000ffffff00161cf12e39000000000000000000001a0000000101fa0c000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023010000000024000000240000001c001c001d001d001c001c00f00af00a00000000000000000000000000000000
|
||||||
1
samples/dmx_a_1126.hex
Normal file
1
samples/dmx_a_1126.hex
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
454e65740400000000001c7c00000000000001003c040000010097010000000001011a8c191563d67616000000000100000001000002000201000000abaaa9a8a7a6a5a4a3a2a1a09f9e9d9c9b9a999897969594939291908f8e8d8c8b8a898887868584838281807f7e7d7c7b7a797877767574737271706f6e6d6c6b6a696867666564636261605f5e5d5c5b5a595857565554535251504f4e4d4c4b4a494847464544434241403f3e3d3c3b3a393837363534333231302f2e2d2c2b2a292827262524232221201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0efeeedecebeae9e8e7e6e5e4e3e2e1e0dfdedddcdbdad9d8d7d6d5d4d3d2d1d0cfcecdcccbcac9c8c7c6c5c4c3c2c1c0bfbebdbcbbbab9b8b7b6b5b4b3b2b1b0afaeadacabaaa9a8a7a6a5a4a3a2a1a09f9e9d9c9b9a999897969594939291908f8e8d8c8b8a898887868584838281807f7e7d7c7b7a797877767574737271706f6e6d6c6b6a696867666564636261605f5e5d5c5b5a595857565554535251504f4e4d4c4b4a494847464544434241403f3e3d3c3b3a393837363534333231302f2e2d2c2b2a292827262524232221201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a0908070605040302015554535251504f4e4d4c4b4a494847464544434241403f3e3d3c3b3a393837363534333231302f2e2d2c2b2a292827262524232221201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201d4d3d2d1d0cfcecdcccbcac9c8c7c6c5c4c3c2c1c0bfbebdbcbbbab9b8b7b6b5b4b3b2b1b0afaeadacabaaa9a8a7a6a5a4a3a2a1a09f9e9d9c9b9a999897969594939291908f8e8d8c8b8a898887868584838281807f7e7d7c7b7a797877767574737271706f6e6d6c6b6a696867666564636261605f5e5d5c5b5a595857565554535251504f4e4d4c4b4a494847464544434241403f3e3d3c3b3a393837363534333231302f2e2d2c2b2a292827262524232221201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0efeeedecebeae9e8e7e6e5e4e3e2e1e0dfdedddcdbdad9d8d7d6d5d4d3d2d1d0cfcecdcccbcac9c8c7c6c5c4c3c2c1c0bfbebdbcbbbab9b8b7b6b5b4b3b2b1b0afaeadacabaaa9a8a7a6a5a4a3a2a1a09f9e9d9c9b9a999897969594939291908f8e8d8c8b8a898887868584838281807f7e7d7c7b7a797877767574737271706f6e6d6c6b6a696867666564636261605f5e5d5c5b5a595857565554535251504f4e4d4c4b4a494847464544434241403f3e3d3c3b3a393837363534333231302f2e2d2c2b2a292827262524232221201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a0908070605040302012c2b2a292827262524232221201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201
|
||||||
1
samples/euce_582.hex
Normal file
1
samples/euce_582.hex
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
4555434500000000000000000500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000746f6e7963616f4445534b544f502d504544324c56442d66376634613034332d313765632d343135362d383132622d3930396264633939663266660000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300ed559bb36
|
||||||
1
samples/event_b_1126.hex
Normal file
1
samples/event_b_1126.hex
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
454e65740400000000001c7c00000000000001003c040000010000000000000002001903000000000000cc00000001000100000025000000010000000124ffffffffffff453a7ffffffe96010000001000010c80007ffffffffffffffffffe158e1b1a191817161514131211100f0e0d0c0b0a09080706050403020100fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0efeeedecebeae9e8e7e6e5e4e3e2e1e0dfdedddcdbdad9d8d7d6d5d4d3d2d1d0cfcecdcccbcac9c8c7c6c5c4c3c2c1c0bfbebdbcbbbab9b8b7b6b5b4b3b2b1b0afaeadacabaaa9a8a7a6a5a4a3a2a1a09f9e9d9c9b9a999897969594939291908f8e8d8c8b8a898887868584838281807f7e7d7c7b7a797877767574737271706f6e6d6c6b6a696867666564636261605f5e5d5c5b5a595857565554535251504f4e4d4c4b4a494847464544434241403f3e3d3c3b3a393837363534333231302f2e2d2c2b2a292827262524232221201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201c0bfbebdbcbbbab9b8b7b6b5b4b3b2b1b0afaeadacabaaa9a8a7a6a5a4a3a2a1a09f9e9d9c9b9a999897969594939291908f8e8d8c8b8a898887868584838281807f7e7d7c7b7a797877767574737271706f6e6d6c6b6a696867666564636261605f5e5d5c5b5a595857565554535251504f4e4d4c4b4a494847464544434241403f3e3d3c3b3a393837363534333231302f2e2d2c2b2a292827262524232221201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a0908070605040302018b8a898887868584838281807f7e7d7c7b7a797877767574737271706f6e6d6c6b6a696867666564636261605f5e5d5c5b5a595857565554535251504f4e4d4c4b4a494847464544434241403f3e3d3c3b3a393837363534333231302f2e2d2c2b2a292827262524232221201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a0908070605040302017574737271706f6e6d6c6b6a696867666564636261605f5e5d5c5b5a595857565554535251504f4e4d4c4b4a494847464544434241403f3e3d3c3b3a393837363534333231302f2e2d2c2b2a292827262524232221201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0efeeedecebeae9e8e7e6e5e4e3e2e1e0dfdedddcdbdad9d8d7d6d5d4d3d2d1d0cfcecdcccbcac9c8c7c6c5c4c3c2c1c0bfbebdbcbbbab9b8b7b6b5b4b3b2b1b0afaeadacabaaa9a8a7a6a5a4a3a2a1a09f9e9d9c9b9a999897969594939291908f8e8d8c8b8a898887868584838281807f7e7d7c7b7a797877767574737271706f6e6d6c6b6a696867666564636261605f5e5d5c5b5a595857565554535251504f4e4d4c4b4a494847464544434241403f3e3d3c3b3a393837363534333231302f2e2d2c2b2a292827262524232221201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201
|
||||||
1
samples/heartbeat_78.hex
Normal file
1
samples/heartbeat_78.hex
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
454e65740200000000001c7c0000000000000100240000000300717ba8c0300ed559bb36
|
||||||
50
samples/pid_map.txt
Normal file
50
samples/pid_map.txt
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
0080 454e65740400000000001c7c00000000000001005200000002004275746c000098000000000000002800cc0126453a7fffffff01073467012584000000002100800e4e46532d314b32447878784278200b32
|
||||||
|
0504 454e65740400000000001c7c00000000000001003b0000000200017ba8c001000d010000000000001100aaab55af57be75aaddab5daa55ae57efd7
|
||||||
|
8013 454e65740400000000001c7c00000000000001004500000002004275746c0000a2000000000000001b00cc0119453a7fffffff0107346701258e00000000218013010106ee
|
||||||
|
8074 454e65740400000000001c7c00000000000001004500000002004275746c0000b9000000000000001b00cc0119453a7fffffff010734670125a50000000021807401000765
|
||||||
|
0060 454e65740400000000001c7c00000000000001005700000002004275746c000021010000000000002d00cc012b453a7fffffff0107348809000c00000000210060130100020005090001000100010101006f00001106f6
|
||||||
|
8021 454e65740400000000001c7c00000000000001004500000002004275746c0000a4000000000000001b00cc0119453a7fffffff0107346701259000000000218021010106fe
|
||||||
|
8064 454e65740400000000001c7c00000000000001004600000002004275746c0000b3000000000000001c00cc011a453a7fffffff0107346701259f000000002180640200000751
|
||||||
|
00c0 454e65740400000000001c7c00000000000001005700000002004275746c000096000000000000002d00cc012b453a7fffffff01073467012582000000002100c0134e46532d314b324478787842782056312e30310c90
|
||||||
|
8051 454e65740400000000001c7c00000000000001004500000002004275746c0000ac000000000000001b00cc0119453a7fffffff010734670125980000000021805101000735
|
||||||
|
8072 454e65740400000000001c7c00000000000001004500000002004275746c0000b7000000000000001b00cc0119453a7fffffff010734670125a30000000021807201000761
|
||||||
|
8063 454e65740400000000001c7c00000000000001004600000002004275746c0000b2000000000000001c00cc011a453a7fffffff0107346701259e0000000021806302154d07b1
|
||||||
|
8084 454e65740400000000001c7c00000000000001004600000002004275746c0000bf000000000000001c00cc011a453a7fffffff010734670125aa0000000021808402005c07d8
|
||||||
|
8050 454e65740400000000001c7c00000000000001004500000002004275746c0000ab000000000000001b00cc0119453a7fffffff010734670125970000000021805001010734
|
||||||
|
8071 454e65740400000000001c7c00000000000001004500000002004275746c0000b6000000000000001b00cc0119453a7fffffff010734670125a2000000002180710100075f
|
||||||
|
0082 454e65740400000000001c7c00000000000001005000000002004275746c00009a000000000000002600cc0124453a7fffffff01073467012586000000002100820c4e4653314b324478787842780ae5
|
||||||
|
8041 454e65740400000000001c7c00000000000001004500000002004275746c0000a8000000000000001b00cc0119453a7fffffff010734670125940000000021804101fe081f
|
||||||
|
0003 454e65740400000000001c7c00000000000001005700000002004275746c00005c000000000000002d00cc012b453a7fffffff010734670125510000000021006013010001030509000100010002010100650000170736
|
||||||
|
0401 454e65740400000000001c7c00000000000001004800000002004275746c00009c000000000000001e00cc011c453a7fffffff0107346701258800000000210401040000000d066c
|
||||||
|
8090 454e65740400000000001c7c00000000000001004500000002004275746c0000c2000000000000001b00cc0119453a7fffffff010734670125ad00000000218090013207bb
|
||||||
|
8053 454e65740400000000001c7c00000000000001004500000002004275746c0000ae000000000000001b00cc0119453a7fffffff0107346701259a0000000021805301000739
|
||||||
|
8010 454e65740400000000001c7c00000000000001004500000002004275746c0000a0000000000000001b00cc0119453a7fffffff0107346701258c00000000218010010106e9
|
||||||
|
8042 454e65740400000000001c7c00000000000001004500000002004275746c0000a9000000000000001b00cc0119453a7fffffff010734670125950000000021804201ff0822
|
||||||
|
8061 454e65740400000000001c7c00000000000001004800000002004275746c0000b0000000000000001e00cc011c453a7fffffff0107346701259c00000000218061040000a3650857
|
||||||
|
8081 454e65740400000000001c7c00000000000001004800000002004275746c00007c010000000000001e00cc011c453a7fffffff0107348809005e00000000218081040008a67b085e
|
||||||
|
0405 454e65740400000000001c7c00000000000001004800000002004275746c00009f000000000000001e00cc011c453a7fffffff0107346701258b00000000210405040000006906cf
|
||||||
|
00f0 454e65740400000000001c7c0000000000000100460000000200017ba8c000002e020000000000001c00cc011a453a7fffffff0107346701250f000000002100f00200650732
|
||||||
|
0002 454e65740400000000001c7c00000000000001004600000002004275746c000020010000000000001c00cc011a453a7fffffff0107348809000b0000000011000202000005cf
|
||||||
|
0403 454e65740400000000001c7c00000000000001004500000002004275746c00009e000000000000001b00cc0119453a7fffffff0107346701258a00000000210403017f06dc
|
||||||
|
8060 454e65740400000000001c7c00000000000001004700000002004275746c0000af000000000000001d00cc011b453a7fffffff0107346701259b000000002180600309334707ce
|
||||||
|
8022 454e65740400000000001c7c00000000000001004500000002004275746c0000a5000000000000001b00cc0119453a7fffffff010734670125910000000021802201010700
|
||||||
|
8065 454e65740400000000001c7c00000000000001004800000002004275746c0000b4000000000000001e00cc011c453a7fffffff010734670125a00000000021806504000000000757
|
||||||
|
8085 454e65740400000000001c7c00000000000001004800000002004275746c0000c0000000000000001e00cc011c453a7fffffff010734670125ab0000000021808504000000040786
|
||||||
|
8011 454e65740400000000001c7c00000000000001004500000002004275746c0000a1000000000000001b00cc0119453a7fffffff0107346701258d00000000218011013c0726
|
||||||
|
8070 454e65740400000000001c7c00000000000001004500000002004275746c0000b5000000000000001b00cc0119453a7fffffff010734670125a1000000002180700100075d
|
||||||
|
8040 454e65740400000000001c7c00000000000001004500000002004275746c0000a7000000000000001b00cc0119453a7fffffff010734670125930000000021804001010720
|
||||||
|
8023 454e65740400000000001c7c00000000000001004500000002004275746c0000a6000000000000001b00cc0119453a7fffffff010734670125920000000021802301000701
|
||||||
|
8083 454e65740400000000001c7c00000000000001004600000002004275746c0000be000000000000001c00cc011a453a7fffffff010734670125a9000000002180830208f60878
|
||||||
|
8052 454e65740400000000001c7c00000000000001004500000002004275746c0000ad000000000000001b00cc0119453a7fffffff010734670125990000000021805201010738
|
||||||
|
1000 454e65740400000000001c7c00000000000001004500000002004275746c000097000000000000001b00cc0119453a7fffffff01073467012583000000002110000100065f
|
||||||
|
0081 454e65740400000000001c7c00000000000001005f00000002004275746c000099000000000000003500cc0133453a7fffffff01073467012585000000002100811b496e76656e74726f6e6963732848616e677a686f75292c496e632e1111
|
||||||
|
8043 454e65740400000000001c7c00000000000001004500000002004275746c0000aa000000000000001b00cc0119453a7fffffff010734670125960000000021804301ff0824
|
||||||
|
8087 454e65740400000000001c7c00000000000001004800000002004275746c0000c1000000000000001e00cc011c453a7fffffff010734670125ac0000000021808704000000d30858
|
||||||
|
0050 454e65740400000000001c7c00000000000001004e0000000200017ba8c00000fd010000000000002400cc0122453a7fffffff0899500026c9de000000002100500a020002010081008204030932
|
||||||
|
8073 454e65740400000000001c7c00000000000001004500000002004275746c0000b8000000000000001b00cc0119453a7fffffff010734670125a40000000021807301000763
|
||||||
|
8082 454e65740400000000001c7c00000000000001004500000002004275746c0000bd000000000000001b00cc0119453a7fffffff010734670125a80000000021808201210797
|
||||||
|
0400 454e65740400000000001c7c00000000000001004800000002004275746c00009b000000000000001e00cc011c453a7fffffff010734670125870000000021040004000000c80725
|
||||||
|
8080 454e65740400000000001c7c00000000000001004700000002004275746c0000ba000000000000001d00cc011b453a7fffffff010734670125a6000000002180800300006907df
|
||||||
|
8062 454e65740400000000001c7c00000000000001004500000002004275746c0000b1000000000000001b00cc0119453a7fffffff0107346701259d00000000218062017f07ca
|
||||||
|
0402 454e65740400000000001c7c00000000000001004800000002004275746c00009d000000000000001e00cc011c453a7fffffff010734670125890000000021040204000933840721
|
||||||
|
8020 454e65740400000000001c7c00000000000001004500000002004275746c0000a3000000000000001b00cc0119453a7fffffff0107346701258f00000000218020010006fb
|
||||||
1
samples/rdm_coldpulse_0.hex
Normal file
1
samples/rdm_coldpulse_0.hex
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
454e65740400000000001c7c00000000000001003b00000002004275746c0100bc010000000000001100aaaa5dbbddfa55aa55ae77ebddaf57fadf
|
||||||
1
samples/rdm_coldpulse_1.hex
Normal file
1
samples/rdm_coldpulse_1.hex
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
454e65740400000000001c7c00000000000001003b00000002004275746c010036000000000000001100aaab55af57be75ef77ab55af75ae57ebd7
|
||||||
1
samples/rdm_coldpulse_2.hex
Normal file
1
samples/rdm_coldpulse_2.hex
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
454e65740400000000001c7c00000000000001003b0000000200017ba8c00100fb000000000000001100aaab55af57be75aaddab5daa55ae57efd7
|
||||||
1
samples/rdm_coldpulse_3.hex
Normal file
1
samples/rdm_coldpulse_3.hex
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
454e65740400000000001c7c00000000000001003b00000002004275746c01009c050000000000001100fefefeffffffddffbfbfbfbfbfbf57efd7
|
||||||
1
samples/rdm_coldpulse_4.hex
Normal file
1
samples/rdm_coldpulse_4.hex
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
454e65740400000000001c7c00000000000001003b0000000200017ba8c001001b000000000000001100fefefefefefffffff7f7bfbfff35ddedd7
|
||||||
1
samples/rdm_disc_req_1126.hex
Normal file
1
samples/rdm_disc_req_1126.hex
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
454e65740400000000001c7c00000000000001003c04000001000000000000000200090f000000000000cc00000001000000000025000000010000000124ffffffffffff453a7ffffffd86000000001000010c089950001767089950001f660e6c050500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000043a0f4f7ec175641812b909bdc99f2ff4000000000010003000000000000000000000000000100030000000000000000000000000074006f006e007900630061006f004400450053004b0054004f0050002d0050004500440032004c00560044002d00660037006600340061003000340033002d0031003700650063002d0034003100350036002d0038003100320062002d0039003000390062006400630039003900660032006600660000000000000000000000911f343cf708bf342e8e519da944bd8a5a4a24433989ea070902001819410343003a005c00550073006500720073005c0074006f006e007900630061006f005c0041007000700044006100740061005c004c006f00630061006c005c0065006300750065005c00530059004d00500048004f004c004900470048005400200035002e0035005c00430075007200720065006e007400530068006f0077000000000000000000000000000000000000000000d00df1e819000000f6d1c94c090000003737b635230000001e00000000000000010000005a00ffffea0709080a1a2245020200000000000000000000000002000000000000000000000000000000000000000000000000010000000100000000000000010000000000000001000000010000002f2e2d2c2b2a292827262524232221201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201898887868584838281807f7e7d7c7b7a797877767574737271706f6e6d6c6b6a696867666564636261605f5e5d5c5b5a595857565554535251504f4e4d4c4b4a494847464544434241403f3e3d3c3b3a393837363534333231302f2e2d2c2b2a292827262524232221201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0efeeedecebeae9e8e7e6e5e4e3e2e1e0dfdedddcdbdad9d8d7d6d5d4d3d2d1d0cfcecdcccbcac9c8c7c6c5c4c3c2c1c0bfbebdbcbbbab9b8b7b6b5b4b3b2b1b0afaeadacabaaa9a8a7a6a5a4a3a2a1a09f9e9d9c9b9a999897969594939291908f8e8d8c8b8a898887868584838281807f7e7d7c7b7a797877767574737271706f6e6d6c6b6a696867666564636261605f5e5d5c5b5a595857565554535251504f4e4d4c4b4a494847464544434241403f3e3d3c3b3a393837363534333231302f2e2d2c2b2a292827262524232221201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201
|
||||||
1
samples/rdm_info_119.hex
Normal file
1
samples/rdm_info_119.hex
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
454e65740400000000001c7c00000000000001004d00000002004275746c00007e0f0000000000002300cc0121453a7ffffffd010734670125c00000000021020109000280000000000000071f
|
||||||
178
samples/rdm_pool.txt
Normal file
178
samples/rdm_pool.txt
Normal file
|
|
@ -0,0 +1,178 @@
|
||||||
|
59 454e65740400000000001c7c00000000000001003b00000002004275746c01000b0f0000000000001100aaaa5dbbddfa55aa55ae77ebddaf57fadf
|
||||||
|
70 454e65740400000000001c7c00000000000001004600000002004275746c00002f0f0000000000001c00cc011a453a7ffffffd0899500026c99900000000110002020000076e
|
||||||
|
87 454e65740400000000001c7c00000000000001005700000002004275746c0000310f0000000000002d00cc012b453a7ffffffd0899500026c99a0000000021006013010001000100010009050020000000010000040836
|
||||||
|
59 454e65740400000000001c7c00000000000001003b00000002004275746c0100790f0000000000001100aaff7fffffaa5feaf5bad7ab7dab57ab77
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c00007e0f0000000000002300cc0121453a7ffffffd010734670125c00000000021020109000280000000000000071f
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c0000800f0000000000002300cc0121453a7ffffffd010734670125c1000000002102010901001b00000000000006ba
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c0000830f0000000000002300cc0121453a7ffffffd010734670125c200000000210201090208dd08bc094000000893
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c0000850f0000000000002300cc0121453a7ffffffd010734670125c30000000021020109030010000505c900000786
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c0000870f0000000000002300cc0121453a7ffffffd010734670125c4000000002102010904003200000000000006d7
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c0000890f0000000000002300cc0121453a7ffffffd010734670125c500000000210201090500040004087f00000736
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c00008b0f0000000000002300cc0121453a7ffffffd010734670125c6000000002102010906000000000000000006a9
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c00008d0f0000000000002300cc0121453a7ffffffd010734670125c70000000021020109070019000b0d20000006fc
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c00008f0f0000000000002300cc0121453a7ffffffd010734670125c8000000002102010908000000000000000006ad
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c0000910f0000000000002300cc0121453a7ffffffd010734670125c9000000002102010909000b00000000000006ba
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c0000930f0000000000002300cc0121453a7ffffffd010734670125ca00000000210201090a000000000000000006b1
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c0000950f0000000000002300cc0121453a7ffffffd010734670125cb00000000210201090b002900000000000006dc
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c0000960f0000000000002300cc0121453a7ffffffd010734670125cc00000000210201090c007f0000000000000734
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c0000980f0000000000002300cc0121453a7ffffffd010734670125cd00000000210201090d0503002a163200000731
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c0000990f0000000000002300cc0121453a7ffffffd010734670125ce00000000210201090e0000000000c700000780
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c00009b0f0000000000002300cc0121453a7ffffffd010734670125cf00000000210201090f00000000037e0000073c
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c00009d0f0000000000002300cc0121453a7ffffffd010734670125d0000000002102010910000000000000000006bd
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c0000a00f0000000000002300cc0121453a7ffffffd010734670125d1000000002102010911001200000000000006d1
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c0000a20f0000000000002300cc0121453a7ffffffd010734670125d2000000002102010912007f0000000000000740
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c0000a30f0000000000002300cc0121453a7ffffffd010734670125d3000000002102010913051c0044163b00000779
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c0000a60f0000000000002300cc0121453a7ffffffd010734670125d4000000002102010914000000000015000006da
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c0000a70f0000000000002300cc0121453a7ffffffd010734670125d500000000210201091500000000004200000709
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c0000a90f0000000000002300cc0121453a7ffffffd010734670125d6000000002102010916000000000000000006c9
|
||||||
|
70 454e65740400000000001c7c00000000000001004600000002004275746c0000ab0f0000000000001c00cc011a453a7ffffffd0899500026c9d7000000002100f002000108ab
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c0000ac0f0000000000002300cc0121453a7ffffffd0899500026c9d80000000021020109000ce400000000000008bc
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c0000ae0f0000000000002300cc0121453a7ffffffd0899500026c9d90000000021020109010945000000000000081c
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c0000b00f0000000000002300cc0121453a7ffffffd0899500026c9da000000002102010902001800000000000007e8
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c0000b20f0000000000002300cc0121453a7ffffffd0899500026c9db00000000210201090320db00000000000008cd
|
||||||
|
70 454e65740400000000001c7c00000000000001004600000002004275746c0000b50f0000000000001c00cc011a453a7ffffffd010734880900dc000000002100f0020070080c
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c0000b70f0000000000001b00cc0119453a7ffffffd010734880900dd00000000218011013c0778
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c0000b90f0000000000001b00cc0119453a7ffffffd010734880900de000000002180200100074c
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c0000ba0f0000000000001b00cc0119453a7ffffffd010734880900df000000002180210101074f
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c0000bc0f0000000000001b00cc0119453a7ffffffd010734880900e00000000021802201010751
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c0000be0f0000000000001b00cc0119453a7ffffffd010734880900e10000000021802301000752
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c0000bf0f0000000000001b00cc0119453a7ffffffd010734880900e20000000021804001010771
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c0000c10f0000000000001b00cc0119453a7ffffffd010734880900e30000000021804101fe0870
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c0000c30f0000000000001b00cc0119453a7ffffffd010734880900e40000000021804201ff0873
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c0000c50f0000000000001b00cc0119453a7ffffffd010734880900e50000000021804301ff0875
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c0000c70f0000000000001b00cc0119453a7ffffffd010734880900e60000000021805001010785
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c0000c90f0000000000001b00cc0119453a7ffffffd010734880900e70000000021805101000786
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c0000cb0f0000000000001b00cc0119453a7ffffffd010734880900e80000000021805201010789
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c0000ce0f0000000000001b00cc0119453a7ffffffd010734880900e9000000002180530100078a
|
||||||
|
71 454e65740400000000001c7c00000000000001004700000002004275746c0000cf0f0000000000001d00cc011b453a7ffffffd010734880900ea00000000218060030006d8087a
|
||||||
|
72 454e65740400000000001c7c00000000000001004800000002004275746c0000d10f0000000000001e00cc011c453a7ffffffd010734880900eb000000002180610400039c2a0869
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c0000d30f0000000000001b00cc0119453a7ffffffd010734880900ec0000000021806201d80874
|
||||||
|
70 454e65740400000000001c7c00000000000001004600000002004275746c0000d50f0000000000001c00cc011a453a7ffffffd010734880900ed0000000021806302005e07fe
|
||||||
|
70 454e65740400000000001c7c00000000000001004600000002004275746c0000d60f0000000000001c00cc011a453a7ffffffd010734880900ee0000000021806402000007a2
|
||||||
|
72 454e65740400000000001c7c00000000000001004800000002004275746c0000d80f0000000000001e00cc011c453a7ffffffd010734880900ef00000000218065040000000007a8
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c0000da0f0000000000001b00cc0119453a7ffffffd010734880900f000000000218070010007ae
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c0000db0f0000000000001b00cc0119453a7ffffffd010734880900f100000000218071010007b0
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c0000de0f0000000000001b00cc0119453a7ffffffd010734880900f200000000218072010007b2
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c0000e00f0000000000001b00cc0119453a7ffffffd010734880900f300000000218073010007b4
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c0000e10f0000000000001b00cc0119453a7ffffffd010734880900f400000000218074010007b6
|
||||||
|
71 454e65740400000000001c7c00000000000001004700000002004275746c0000e30f0000000000001d00cc011b453a7ffffffd010734880900f50000000021808003000075083c
|
||||||
|
72 454e65740400000000001c7c00000000000001004800000002004275746c0000e50f0000000000001e00cc011c453a7ffffffd010734880900f6000000002180810400082b820880
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c0000e70f0000000000001b00cc0119453a7ffffffd010734880900f700000000218082011b07e2
|
||||||
|
70 454e65740400000000001c7c00000000000001004600000002004275746c0000e90f0000000000001c00cc011a453a7ffffffd010734880900f8000000002180830208fe08d1
|
||||||
|
70 454e65740400000000001c7c00000000000001004600000002004275746c0000eb0f0000000000001c00cc011a453a7ffffffd010734880900f90000000021808402000007cd
|
||||||
|
72 454e65740400000000001c7c00000000000001004800000002004275746c0000ed0f0000000000001e00cc011c453a7ffffffd010734880900fa00000000218085040000000407d7
|
||||||
|
72 454e65740400000000001c7c00000000000001004800000002004275746c0000ee0f0000000000001e00cc011c453a7ffffffd010734880900fb00000000218087040000000007d6
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c0000f10f0000000000001b00cc0119453a7ffffffd010734880900fc000000002180900134080e
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c0000f20f0000000000002300cc0121453a7ffffffd010734880900fd000000002102010900021700000000000006f7
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c0000f40f0000000000002300cc0121453a7ffffffd010734880900fe000000002102010901001b00000000000006fb
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c0100f60f0000000000002300cc0121453a7ffffffd010734880900ff00000000210201090208fe08cc096100000926
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c0000f80f0000000000002300cc0121453a7ffffffd0107348809000000000000210201090300000000024e00000634
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c0000fa0f0000000000002300cc0121453a7ffffffd010734880900010000000021020109040034000000000000061a
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c0000fc0f0000000000002300cc0121453a7ffffffd01073488090002000000002102010905000400040405000005f9
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c0000fe0f0000000000002300cc0121453a7ffffffd01073488090003000000002102010906000000000000000005ea
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c000000100000000000002300cc0121453a7ffffffd0107348809000400000000210201090700000000054e0000063f
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c000003100000000000002300cc0121453a7ffffffd01073488090005000000002102010908000000000000000005ee
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c000004100000000000002300cc0121453a7ffffffd0107348809000600000000210201090900630000000000000653
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c000007100000000000002300cc0121453a7ffffffd0107348809000700000000210201090a000000000000000005f2
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c000008100000000000002300cc0121453a7ffffffd0107348809000800000000210201090b00ec00000000000006e0
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c00000a100000000000002300cc0121453a7ffffffd0107348809000900000000210201090c000000000000000005f6
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c00000c100000000000002300cc0121453a7ffffffd0107348809000a00000000210201090d005c00081536000006a7
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c00000e100000000000002300cc0121453a7ffffffd0107348809000b00000000210201090e00000000057c0000067b
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c000010100000000000002300cc0121453a7ffffffd0107348809000c00000000210201090f000000001dbb000006d4
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c000012100000000000002300cc0121453a7ffffffd0107348809000d000000002102010910000000000000000005fe
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c000014100000000000001b00cc0119453a7ffffffd0107346701250e00000000210403017f065e
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c000016100000000000001b00cc0119453a7ffffffd0899500026c90f00000000210403010106f8
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c000019100000000000001b00cc0119453a7ffffffd0107348809001000000000210403017f0664
|
||||||
|
65 454e65740400000000001c7c00000000000001004100000002004275746c01001f100000000000001700fefefefefefffffffdf5fdeff7ddf7ddd5f775f5d7ffdf
|
||||||
|
66 454e65740400000000001c7c00000000000001004200000002004275746c010021100000000000001800fefefefffffffcfdddfd7ffbffb5f5aeae7bffdf7f75ffff
|
||||||
|
66 454e65740400000000001c7c00000000000001004200000002004275746c010023100000000000001800fefefffffdfffff7ba357fd7ddf75d55bbdff7dfffef9ddf
|
||||||
|
67 454e65740400000000001c7c00000000000001004300000002004275746c010025100000000000001900feffffffffffffffabd5353dff5fabf7ddf57debd7bd75ffff
|
||||||
|
57 454e65740400000000001c7c00000000000001003900000002004275746c010028100000000000000f00fefeffffffffffffd5ffffffffdfff
|
||||||
|
59 454e65740400000000001c7c00000000000001003b00000002004275746c01002c100000000000001100aaab55af57be75efffab5deff5aed7ffff
|
||||||
|
62 454e65740400000000001c7c00000000000001003e00000002004275746c010030100000000000001400fefefefefefefefffeffabffffffffffae57efd7
|
||||||
|
66 454e65740400000000001c7c00000000000001004200000002004275746c010032100000000000001800fefefeffffffffffffffff7d7f757ffff7bdfdeff7b5dfff
|
||||||
|
54 454e65740400000000001c7c00000000000001003600000002004275746c010034100000000000000c00fefe75fffffffbbbbbafdfff
|
||||||
|
60 454e65740400000000001c7c00000000000001003c00000002004275746c010036100000000000001200fefefefeffff5fffdff57d7ff7ff3fddedd7
|
||||||
|
54 454e65740400000000001c7c00000000000001003600000002004275746c010038100000000000000c00fefefffff5fffbfbfbffffd7
|
||||||
|
58 454e65740400000000001c7c00000000000001003a00000002004275746c01003e100000000000001000fefefefffdff5ffff7f7fddf7f57efd7
|
||||||
|
66 454e65740400000000001c7c00000000000001004200000002004275746c010042100000000000001800fefefefefffffffffffffffdff75ff57f7fddf5f7357efd7
|
||||||
|
56 454e65740400000000001c7c00000000000001003800000002004275746c010044100000000000000e00fff57dfdfffffddf7dfd5fff7fff
|
||||||
|
61 454e65740400000000001c7c00000000000001003d00000002004275746c010046100000000000001300fefefefffffffdb7fdf375f5fffdfbbf57efd7
|
||||||
|
60 454e65740400000000001c7c00000000000001003c00000002004275746c010048100000000000001200fefefefefeffffffeed7ffbfbfffcd777bd7
|
||||||
|
53 454e65740400000000001c7c00000000000001003500000002004275746c01004c100000000000000b00fefefeffffffffffb5dfff
|
||||||
|
64 454e65740400000000001c7c00000000000001004000000002004275746c010051100000000000001600fefefefefefefffffffff777f777f7ff7f55ae57efd7
|
||||||
|
70 454e65740400000000001c7c00000000000001004600000002004275746c010052100000000000001c00fefefefefefefeffffffffbeffffbfd7bef7badfabfdeb55ae57efd7
|
||||||
|
53 454e65740400000000001c7c00000000000001003500000002004275746c010058100000000000000b00febfffbfbfffffffbff5fd
|
||||||
|
50 454e65740400000000001c7c00000000000001003200000002004275746c01005c100000000000000800fefdfffffffffffd
|
||||||
|
59 454e65740400000000001c7c00000000000001003b00000002004275746c01005f100000000000001100aaab55af57be75ef77ab55af75ae57ebd7
|
||||||
|
70 454e65740400000000001c7c00000000000001004600000002004275746c0000a7100000000000001c00cc011a453a7ffffffd01073467012557000000001100020200000615
|
||||||
|
87 454e65740400000000001c7c00000000000001005700000002004275746c0000aa100000000000002d00cc012b453a7ffffffd01073467012558000000002100601301000103050900010001000201010065000017073b
|
||||||
|
59 454e65740400000000001c7c00000000000001003b00000002004275746c0100be100000000000001100aaab55af57be75aaddab5daa55ae57efd7
|
||||||
|
70 454e65740400000000001c7c00000000000001004600000002004275746c000006110000000000001c00cc011a453a7ffffffd0107348809008800000000110002020000064a
|
||||||
|
87 454e65740400000000001c7c00000000000001005700000002004275746c000008110000000000002d00cc012b453a7ffffffd010734880900890000000021006013010002000509000100010001010100700000110772
|
||||||
|
70 454e65740400000000001c7c00000000000001004600000002004275746c0000b6110000000000001c00cc011a453a7ffffffd0899500026c9df0000000011000202000007b4
|
||||||
|
87 454e65740400000000001c7c00000000000001005700000002004275746c0000b7110000000000002d00cc012b453a7ffffffd0899500026c9e0000000002100601301000100010001000905002000000001000004087c
|
||||||
|
70 454e65740400000000001c7c00000000000001004600000002004275746c000006120000000000001c00cc011a453a7ffffffd01073467012508000000002100f00200650729
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c000008120000000000001b00cc0119453a7ffffffd010734670125090000000021801001010664
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c00000b120000000000001b00cc0119453a7ffffffd0107346701250a00000000218011013c06a1
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c00000d120000000000001b00cc0119453a7fbffffd0107346701250b0000000021801301010669
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c00000d120000000000001b00cc0119453a7ffffffd0107346701250b0000000021801301010669
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c000010120000000000001b00cc0119453a7ffffffd0107346701250c0000000021802001000676
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c000011120000000000001b00cc0119453a7ffffffd0107346701250d0000000021802101010679
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c000013120000000000001b00cc0119453a7ffffffd0107346701250e000000002180220101067b
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c000015120000000000001b00cc0119453a7ffffffd0107346701250f000000002180230100067c
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c000017120000000000001b00cc0119453a7ffffffd01073467012510000000002180400101069b
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c000019120000000000001b00cc0119453a7ffffffd010734670125110000000021804101fe079a
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c00001b120000000000001b00cc0119453a7ffffffd010734670125120000000021804201ff079d
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c00001d120000000000001b00cc0119453a7ffffffd010734670125130000000021804301ff079f
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c00001f120000000000001b00cc0119453a7ffffffd0107346701251400000000218050010106af
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c000021120000000000001b00cc0119453a7ffffffd0107346701251500000000218051010006b0
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c000023120000000000001b00cc0119453a7ffffffd0107346701251600000000218052010106b3
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c000025120000000000001b00cc0119453a7ffffffd0107346701251700000000218053010006b4
|
||||||
|
71 454e65740400000000001c7c00000000000001004700000002004275746c000027120000000000001d00cc011b453a7ffffffd0107346701251800000000218060030933470749
|
||||||
|
72 454e65740400000000001c7c00000000000001004800000002004275746c000029120000000000001e00cc011c453a7ffffffd0107346701251900000000218061040000a36507d2
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c00002b120000000000001b00cc0119453a7ffffffd0107346701251a00000000218062017f0745
|
||||||
|
70 454e65740400000000001c7c00000000000001004600000002004275746c00002e120000000000001c00cc011a453a7ffffffd0107346701251b0000000021806302050306d2
|
||||||
|
70 454e65740400000000001c7c00000000000001004600000002004275746c000030120000000000001c00cc011a453a7ffffffd0107346701251c0000000021806402000006cc
|
||||||
|
72 454e65740400000000001c7c00000000000001004800000002004275746c000031120000000000001e00cc011c453a7ffffffd0107346701251d00000000218065040000000006d2
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c000033120000000000001b00cc0119453a7ffffffd0107346701251e00000000218070010006d8
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c000035120000000000001b00cc0119453a7ffffffd0107346701251f00000000218071010006da
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c000037120000000000001b00cc0119453a7ffffffd0107346701252000000000218072010006dc
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c000039120000000000001b00cc0119453a7ffffffd0107346701252100000000218073010006de
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c00003b120000000000001b00cc0119453a7ffffffd0107346701252200000000218074010006e0
|
||||||
|
71 454e65740400000000001c7c00000000000001004700000002004275746c00003d120000000000001d00cc011b453a7ffffffd010734670125230000000021808003000069075a
|
||||||
|
72 454e65740400000000001c7c00000000000001004800000002004275746c000040120000000000001e00cc011c453a7ffffffd0107346701252400000000218081040009c587084a
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c000041120000000000001b00cc0119453a7ffffffd0107346701252500000000218082011b070c
|
||||||
|
70 454e65740400000000001c7c00000000000001004600000002004275746c000043120000000000001c00cc011a453a7ffffffd01073467012526000000002180830208e507e2
|
||||||
|
70 454e65740400000000001c7c00000000000001004600000002004275746c000045120000000000001c00cc011a453a7ffffffd010734670125270000000021808402000b0702
|
||||||
|
72 454e65740400000000001c7c00000000000001004800000002004275746c000047120000000000001e00cc011c453a7ffffffd010734670125280000000021808504000000040701
|
||||||
|
72 454e65740400000000001c7c00000000000001004800000002004275746c000049120000000000001e00cc011c453a7ffffffd010734670125290000000021808704000000190719
|
||||||
|
69 454e65740400000000001c7c00000000000001004500000002004275746c00004b120000000000001b00cc0119453a7ffffffd0107346701252a0000000021809001320736
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c00004d120000000000002300cc0121453a7ffffffd0107346701252b0000000021020109000280000000000000068a
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c00004f120000000000002300cc0121453a7ffffffd0107346701252c000000002102010901001b0000000000000625
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c000051120000000000002300cc0121453a7ffffffd0107346701252d00000000210201090208dd08bc0940000007fe
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c000053120000000000002300cc0121453a7ffffffd0107346701252e0000000021020109030010000505c9000006f1
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c000055120000000000002300cc0121453a7ffffffd0107346701252f00000000210201090400320000000000000642
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c000057120000000000002300cc0121453a7ffffffd0107346701253000000000210201090500040004087f000006a1
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c000059120000000000002300cc0121453a7ffffffd0107346701253100000000210201090600000000000000000614
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c00005b120000000000002300cc0121453a7ffffffd010734670125320000000021020109070019000b0d2000000667
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c00005d120000000000002300cc0121453a7ffffffd0107346701253300000000210201090800000000000000000618
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c00005e120000000000002300cc0121453a7ffffffd010734670125340000000021020109090010000000000000062a
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c000060120000000000002300cc0121453a7ffffffd0107346701253500000000210201090a0000000000000000061c
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c000062120000000000002300cc0121453a7ffffffd0107346701253600000000210201090b00290000000000000647
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c000064120000000000002300cc0121453a7ffffffd0107346701253700000000210201090c007f000000000000069f
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c000066120000000000002300cc0121453a7ffffffd0107346701253800000000210201090d04fa002a163200000792
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c000068120000000000002300cc0121453a7ffffffd0107346701253900000000210201090e0000000000c7000006eb
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c00006a120000000000002300cc0121453a7ffffffd0107346701253a00000000210201090f00000000037e000006a7
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c00006c120000000000002300cc0121453a7ffffffd0107346701253b00000000210201091000000000000000000628
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c00006e120000000000002300cc0121453a7ffffffd0107346701253c0000000021020109110012000000000000063c
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c000070120000000000002300cc0121453a7ffffffd0107346701253d000000002102010912007f00000000000006ab
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c000073120000000000002300cc0121453a7ffffffd0107346701253e000000002102010913051c0044163b000006e4
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c000074120000000000002300cc0121453a7ffffffd0107346701253f00000000210201091400000000001500000645
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c000076120000000000002300cc0121453a7ffffffd0107346701254000000000210201091500000000004200000674
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c000078120000000000002300cc0121453a7ffffffd0107346701254100000000210201091600000000000000000634
|
||||||
|
70 454e65740400000000001c7c00000000000001004600000002004275746c00007a120000000000001c00cc011a453a7ffffffd0899500026c942000000002100f00200010816
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c00007c120000000000002300cc0121453a7ffffffd0899500026c9430000000021020109000ce40000000000000827
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c00007f120000000000002300cc0121453a7ffffffd0899500026c94400000000210201090109450000000000000787
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c000080120000000000002300cc0121453a7ffffffd0899500026c94500000000210201090200180000000000000753
|
||||||
|
77 454e65740400000000001c7c00000000000001004d00000002004275746c000082120000000000002300cc0121453a7ffffffd0899500026c94600000000210201090320dd000000000000083a
|
||||||
1
samples/rdm_pulse_101.hex
Normal file
1
samples/rdm_pulse_101.hex
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
454e65740400000000001c7c00000000000001003b00000002004275746c01000b0f0000000000001100aaaa5dbbddfa55aa55ae77ebddaf57fadf
|
||||||
1
samples/rdm_pulse_101_0.hex
Normal file
1
samples/rdm_pulse_101_0.hex
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
454e65740400000000001c7c00000000000001003b00000002004275746c01000b0f0000000000001100aaaa5dbbddfa55aa55ae77ebddaf57fadf
|
||||||
1
samples/rdm_pulse_101_1.hex
Normal file
1
samples/rdm_pulse_101_1.hex
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
454e65740400000000001c7c00000000000001003b00000002004275746c01005f100000000000001100aaab55af57be75ef77ab55af75ae57ebd7
|
||||||
1
samples/rdm_pulse_101_2.hex
Normal file
1
samples/rdm_pulse_101_2.hex
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
454e65740400000000001c7c00000000000001003b00000002004275746c0100be100000000000001100aaab55af57be75aaddab5daa55ae57efd7
|
||||||
1
samples/rdm_pulse_101_3.hex
Normal file
1
samples/rdm_pulse_101_3.hex
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
454e65740400000000001c7c00000000000001003b00000002004275746c0100790f0000000000001100aaff7fffffaa5feaf5bad7ab7dab57ab77
|
||||||
1
samples/rdm_pulse_101_4.hex
Normal file
1
samples/rdm_pulse_101_4.hex
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
454e65740400000000001c7c00000000000001003b00000002004275746c01002c100000000000001100aaab55af57be75efffab5deff5aed7ffff
|
||||||
1
samples/rdm_req_1126.hex
Normal file
1
samples/rdm_req_1126.hex
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
454e65740400000000001c7c00000000000001003c040000010000000000000002007f0f000000000000cc00000001000100000025000000010000000124ffffffffffff453a7ffffffccc010000001000010c80007ffffffffffffffffffe15c291908f8e8d8c8b8a898887868584838281807f7e7d7c7b7a797877767574737271706f6e6d6c6b6a696867666564636261605f5e5d5c5b5a595857565554535251504f4e4d4c4b4a494847464544434241403f3e3d3c3b3a393837363534333231302f2e2d2c2b2a292827262524232221201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0efeeedecebeae9e8e7e6e5e4e3e2e1e0dfdedddcdbdad9d8d7d6d5d4d3d2d1d0cfcecdcccbcac9c8c7c6c5c4c3c2c1c0bfbebdbcbbbab9b8b7b6b5b4b3b2b1b0afaeadacabaaa9a8a7a6a5a4a3a2a1a09f9e9d9c9b9a999897969594939291908f8e8d8c8b8a898887868584838281807f7e7d7c7b7a797877767574737271706f6e6d6c6b6a696867666564636261605f5e5d5c5b5a595857565554535251504f4e4d4c4b4a494847464544434241403f3e3d3c3b3a393837363534333231302f2e2d2c2b2a292827262524232221201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a0908070605040302014a494847464544434241403f3e3d3c3b3a393837363534333231302f2e2d2c2b2a292827262524232221201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201c0bfbebdbcbbbab9b8b7b6b5b4b3b2b1b0afaeadacabaaa9a8a7a6a5a4a3a2a1a09f9e9d9c9b9a999897969594939291908f8e8d8c8b8a898887868584838281807f7e7d7c7b7a797877767574737271706f6e6d6c6b6a696867666564636261605f5e5d5c5b5a595857565554535251504f4e4d4c4b4a494847464544434241403f3e3d3c3b3a393837363534333231302f2e2d2c2b2a292827262524232221201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0efeeedecebeae9e8e7e6e5e4e3e2e1e0dfdedddcdbdad9d8d7d6d5d4d3d2d1d0cfcecdcccbcac9c8c7c6c5c4c3c2c1c0bfbebdbcbbbab9b8b7b6b5b4b3b2b1b0afaeadacabaaa9a8a7a6a5a4a3a2a1a09f9e9d9c9b9a999897969594939291908f8e8d8c8b8a898887868584838281807f7e7d7c7b7a797877767574737271706f6e6d6c6b6a696867666564636261605f5e5d5c5b5a595857565554535251504f4e4d4c4b4a494847464544434241403f3e3d3c3b3a393837363534333231302f2e2d2c2b2a292827262524232221201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201403f3e3d3c3b3a393837363534333231302f2e2d2c2b2a292827262524232221201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201
|
||||||
1
samples/rdm_resp_111.hex
Normal file
1
samples/rdm_resp_111.hex
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
454e65740400000000001c7c00000000000001004500000002004275746c0000b70f0000000000001b00cc0119453a7ffffffd010734880900dd00000000218011013c0778
|
||||||
1
samples/rdm_setack_68.hex
Normal file
1
samples/rdm_setack_68.hex
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
454e65740400000000001c7c00000000000001004400000002004275746c00006efa0600000000001a00cc0118453a7fffffff010734880900b1000000003100f000077f
|
||||||
1
samples/register_89.hex
Normal file
1
samples/register_89.hex
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
454e65740200000000001c7c00000000000001002f0000000200017ba8c000161cf12e3900717ba8c0300ed559bb36
|
||||||
1
samples/status_84.hex
Normal file
1
samples/status_84.hex
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
454e65740400000000001c7c00000000000001002a00000002004275746c010062000000010000000000
|
||||||
1226
src/aech.rs
Normal file
1226
src/aech.rs
Normal file
File diff suppressed because it is too large
Load Diff
1201
src/dmxhash.rs
Normal file
1201
src/dmxhash.rs
Normal file
File diff suppressed because it is too large
Load Diff
239
src/enet.rs
Normal file
239
src/enet.rs
Normal file
|
|
@ -0,0 +1,239 @@
|
||||||
|
// enet.rs - e:net 协议公共设施
|
||||||
|
use std::net::{SocketAddr, UdpSocket};
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
|
pub const BIND: &str = "192.168.123.113:31772";
|
||||||
|
pub const BUTLER: &str = "192.168.123.1:31772";
|
||||||
|
pub const BCAST_SUB: &str = "192.168.123.255:31772";
|
||||||
|
pub const BCAST_ALL: &str = "255.255.255.255:31772";
|
||||||
|
|
||||||
|
// ---------- 瀛楁璇诲啓 (灏忕) ----------
|
||||||
|
pub fn g16(b: &[u8], o: usize) -> u16 { b[o] as u16 | (b[o + 1] as u16) << 8 }
|
||||||
|
pub fn g32(b: &[u8], o: usize) -> u32 {
|
||||||
|
b[o] as u32 | (b[o + 1] as u32) << 8 | (b[o + 2] as u32) << 16 | (b[o + 3] as u32) << 24
|
||||||
|
}
|
||||||
|
pub fn p16(b: &mut [u8], o: usize, v: u16) { b[o] = v as u8; b[o + 1] = (v >> 8) as u8; }
|
||||||
|
pub fn p32(b: &mut [u8], o: usize, v: u32) {
|
||||||
|
b[o] = v as u8; b[o + 1] = (v >> 8) as u8; b[o + 2] = (v >> 16) as u8; b[o + 3] = (v >> 24) as u8;
|
||||||
|
}
|
||||||
|
pub fn find(b: &[u8], pat: &[u8]) -> bool {
|
||||||
|
b.windows(pat.len()).any(|w| w == pat)
|
||||||
|
}
|
||||||
|
pub fn hexs(b: &[u8]) -> String { b.iter().map(|x| format!("{:02x}", x)).collect() }
|
||||||
|
|
||||||
|
// ---------- 妯℃澘鍔犺浇 (缂栬瘧鏈熷祵鍏?pcap 瀹炴祴鏍锋湰) ----------
|
||||||
|
/// 真机 RDM 应答帧池: 每行 "<载荷长度> <hex>"
|
||||||
|
pub fn load_rdm_pool() -> Vec<Vec<u8>> {
|
||||||
|
let txt = include_str!("../samples/rdm_pool.txt");
|
||||||
|
let mut out = Vec::new();
|
||||||
|
for line in txt.lines() {
|
||||||
|
let line = line.trim();
|
||||||
|
if line.is_empty() { continue; }
|
||||||
|
if let Some(pos) = line.find(' ') {
|
||||||
|
let hex = line[pos + 1..].trim();
|
||||||
|
let b: Vec<u8> = (0..hex.len()).step_by(2)
|
||||||
|
.map(|i| u8::from_str_radix(&hex[i..i + 2], 16).unwrap()).collect();
|
||||||
|
out.push(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_template(name: &str) -> Vec<u8> {
|
||||||
|
let hex = match name {
|
||||||
|
"discovery_req" => include_str!("../samples/discovery_req_222.hex"),
|
||||||
|
"discovery_resp" => include_str!("../samples/discovery_resp_259.hex"),
|
||||||
|
"announce" => include_str!("../samples/announce_686.hex"),
|
||||||
|
"announce_live" => include_str!("../samples/announce_live.hex"),
|
||||||
|
"heartbeat" => include_str!("../samples/heartbeat_78.hex"),
|
||||||
|
"euce" => include_str!("../samples/euce_582.hex"),
|
||||||
|
"dmx_a" => include_str!("../samples/dmx_a_1126.hex"),
|
||||||
|
"event_b" => include_str!("../samples/event_b_1126.hex"),
|
||||||
|
"ack" => include_str!("../samples/ack_84.hex"),
|
||||||
|
"rdm_req" => include_str!("../samples/rdm_req_1126.hex"),
|
||||||
|
"rdm_disc_req" => include_str!("../samples/rdm_disc_req_1126.hex"),
|
||||||
|
"claim_h112" => include_str!("../samples/claim_h112.hex"),
|
||||||
|
"claim_h114" => include_str!("../samples/claim_h114.hex"),
|
||||||
|
"claim_h116" => include_str!("../samples/claim_h116.hex"),
|
||||||
|
"aerep" => include_str!("../samples/aerep_113.hex"),
|
||||||
|
"status" => include_str!("../samples/status_84.hex"),
|
||||||
|
"rdm_pulse_0" => include_str!("../samples/rdm_pulse_101_0.hex"),
|
||||||
|
"rdm_pulse_1" => include_str!("../samples/rdm_pulse_101_1.hex"),
|
||||||
|
"rdm_pulse_2" => include_str!("../samples/rdm_pulse_101_2.hex"),
|
||||||
|
"rdm_pulse_3" => include_str!("../samples/rdm_pulse_101_3.hex"),
|
||||||
|
"rdm_pulse_4" => include_str!("../samples/rdm_pulse_101_4.hex"),
|
||||||
|
"rdm_resp111" => include_str!("../samples/rdm_resp_111.hex"),
|
||||||
|
"rdm_setack68" => include_str!("../samples/rdm_setack_68.hex"),
|
||||||
|
|
||||||
|
"rdm_info119" => include_str!("../samples/rdm_info_119.hex"),
|
||||||
|
"register89" => include_str!("../samples/register_89.hex"),
|
||||||
|
"aere594" => include_str!("../samples/aere_594.hex"),
|
||||||
|
"announce144" => include_str!("../samples/announce_144.hex"),
|
||||||
|
"rdm_disc_req" => include_str!("../samples/rdm_disc_req_1126.hex"),
|
||||||
|
_ => panic!("unknown template {}", name),
|
||||||
|
};
|
||||||
|
let h = hex.trim();
|
||||||
|
(0..h.len()).step_by(2).map(|i| u8::from_str_radix(&h[i..i + 2], 16).unwrap()).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- Socket ----------
|
||||||
|
pub fn open() -> UdpSocket {
|
||||||
|
let s = UdpSocket::bind(BIND).expect("bind 192.168.123.113:31772 澶辫触(缃戝彛/绔彛鍗犵敤?)");
|
||||||
|
s.set_broadcast(true).unwrap();
|
||||||
|
s.set_read_timeout(Some(Duration::from_millis(2))).unwrap();
|
||||||
|
s
|
||||||
|
}
|
||||||
|
|
||||||
|
/// SO_REUSEADDR bind (Windows)
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
pub fn open_reuse(bind_addr: &str) -> UdpSocket {
|
||||||
|
use std::os::windows::io::FromRawSocket;
|
||||||
|
#[repr(C)]
|
||||||
|
struct SockAddrIn { sin_family: u16, sin_port: u16, sin_addr: u32, sin_zero: [u8; 8] }
|
||||||
|
#[repr(C)]
|
||||||
|
struct WsaData { wversion: u16, whighversion: u16, szdescription: [u8; 257], szsystemstatus: [u8; 129], imaxsockets: u16, imaxudpdg: u16, lpvendorinfo: usize }
|
||||||
|
#[link(name = "ws2_32")]
|
||||||
|
extern "system" {
|
||||||
|
fn WSAStartup(wver: u16, data: *mut WsaData) -> i32;
|
||||||
|
fn socket(af: i32, ty: i32, proto: i32) -> usize;
|
||||||
|
fn setsockopt(s: usize, level: i32, optname: i32, optval: *const u8, optlen: i32) -> i32;
|
||||||
|
fn bind(s: usize, addr: *const SockAddrIn, len: i32) -> i32;
|
||||||
|
}
|
||||||
|
unsafe {
|
||||||
|
let mut wd: WsaData = std::mem::zeroed();
|
||||||
|
WSAStartup(0x0202, &mut wd);
|
||||||
|
let s = socket(2, 2, 17); // AF_INET, SOCK_DGRAM, IPPROTO_UDP
|
||||||
|
assert!(s != usize::MAX, "ws socket 澶辫触");
|
||||||
|
const SOL_SOCKET: i32 = 0xFFFF;
|
||||||
|
const SO_REUSEADDR: i32 = 4;
|
||||||
|
const SO_BROADCAST: i32 = 6;
|
||||||
|
let one: u8 = 1;
|
||||||
|
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, 1);
|
||||||
|
setsockopt(s, SOL_SOCKET, SO_BROADCAST, &one, 1);
|
||||||
|
let (ip, port) = bind_addr.rsplit_once(':').unwrap();
|
||||||
|
let o: Vec<u8> = ip.split('.').map(|x| x.parse().unwrap()).collect();
|
||||||
|
let a = SockAddrIn {
|
||||||
|
sin_family: 2,
|
||||||
|
sin_port: port.parse::<u16>().unwrap().to_be(),
|
||||||
|
sin_addr: u32::from_ne_bytes([o[0], o[1], o[2], o[3]]),
|
||||||
|
sin_zero: [0; 8],
|
||||||
|
};
|
||||||
|
let r = bind(s, &a, std::mem::size_of::<SockAddrIn>() as i32);
|
||||||
|
if r != 0 {
|
||||||
|
let err: i32 = { extern "system" { fn WSAGetLastError() -> i32; } WSAGetLastError() };
|
||||||
|
panic!("reuse bind {} 澶辫触 r={} WSAE={}", bind_addr, r, err);
|
||||||
|
}
|
||||||
|
let u = UdpSocket::from_raw_socket(s as _);
|
||||||
|
u.set_broadcast(true).unwrap();
|
||||||
|
u.set_read_timeout(Some(Duration::from_millis(2))).unwrap();
|
||||||
|
u
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Linux: 鏍囧噯 bind 鍗冲厑璁稿杩涚▼ SO_REUSEADDR 鍏卞瓨, 鐩存帴杩斿洖 (daemon 鐢?
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
pub fn open_reuse(bind_addr: &str) -> UdpSocket {
|
||||||
|
use std::net::UdpSocket as S;
|
||||||
|
use std::os::unix::io::FromRawFd;
|
||||||
|
#[repr(C)]
|
||||||
|
struct SockAddrIn { sin_family: u16, sin_port: u16, sin_addr: u32, sin_zero: [u8; 8] }
|
||||||
|
#[link(name = "c")]
|
||||||
|
extern "C" {
|
||||||
|
fn socket(af: i32, ty: i32, proto: i32) -> i32;
|
||||||
|
fn setsockopt(s: i32, level: i32, optname: i32, optval: *const u8, optlen: u32) -> i32;
|
||||||
|
fn bind(s: i32, addr: *const SockAddrIn, len: u32) -> i32;
|
||||||
|
}
|
||||||
|
const AF_INET: i32 = 2;
|
||||||
|
const SOCK_DGRAM: i32 = 2;
|
||||||
|
const IPPROTO_UDP: i32 = 17;
|
||||||
|
const IPPROTO_IP: i32 = 0;
|
||||||
|
const IP_TTL: i32 = 2;
|
||||||
|
const IP_MTU_DISCOVER: i32 = 10;
|
||||||
|
const SOL_SOCKET: i32 = 1;
|
||||||
|
const SO_REUSEADDR: i32 = 2;
|
||||||
|
const SO_BROADCAST: i32 = 6;
|
||||||
|
unsafe {
|
||||||
|
let s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||||
|
assert!(s >= 0, "socket 澶辫触");
|
||||||
|
let one: i32 = 1;
|
||||||
|
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one as *const i32 as *const u8, 4);
|
||||||
|
setsockopt(s, SOL_SOCKET, SO_BROADCAST, &one as *const i32 as *const u8, 4);
|
||||||
|
// 鎸囩汗瀵归綈鐪熸満 Butler: TTL=100, 鍏抽棴 DF (PMTUDISC_DONT)
|
||||||
|
let ttl: i32 = 100;
|
||||||
|
setsockopt(s, IPPROTO_IP, IP_TTL, &ttl as *const i32 as *const u8, 4);
|
||||||
|
let pmtu: i32 = 0; // IP_PMTUDISC_DONT
|
||||||
|
setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &pmtu as *const i32 as *const u8, 4);
|
||||||
|
let (ip, port) = bind_addr.rsplit_once(':').unwrap();
|
||||||
|
let o: Vec<u8> = ip.split('.').map(|x| x.parse().unwrap()).collect();
|
||||||
|
let a = SockAddrIn {
|
||||||
|
sin_family: AF_INET as u16,
|
||||||
|
sin_port: port.parse::<u16>().unwrap().to_be(),
|
||||||
|
sin_addr: u32::from_ne_bytes([o[0], o[1], o[2], o[3]]),
|
||||||
|
sin_zero: [0; 8],
|
||||||
|
};
|
||||||
|
let r = bind(s, &a, std::mem::size_of::<SockAddrIn>() as u32);
|
||||||
|
if r != 0 {
|
||||||
|
panic!("reuse bind {} 澶辫触 r={} errno={}", bind_addr, r, std::io::Error::last_os_error());
|
||||||
|
}
|
||||||
|
let u = S::from_raw_fd(s);
|
||||||
|
u.set_broadcast(true).unwrap();
|
||||||
|
u.set_read_timeout(Some(Duration::from_millis(2))).unwrap();
|
||||||
|
u
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 鍦?dur 鏃堕棿绐楀唴鏀堕泦鎵€鏈夊埌杈剧殑 UDP 包)
|
||||||
|
pub fn recv_window(s: &UdpSocket, dur: Duration) -> Vec<(SocketAddr, Vec<u8>)> {
|
||||||
|
let deadline = Instant::now() + dur;
|
||||||
|
let mut out = Vec::new();
|
||||||
|
loop {
|
||||||
|
let now = Instant::now();
|
||||||
|
if now >= deadline { break; }
|
||||||
|
s.set_read_timeout(Some(deadline.saturating_duration_since(now))).unwrap();
|
||||||
|
let mut buf = [0u8; 2048];
|
||||||
|
match s.recv_from(&mut buf) {
|
||||||
|
Ok((n, a)) => out.push((a, buf[..n].to_vec())),
|
||||||
|
Err(_) => break, // 瓒呮椂
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- 鏀跺寘鍒嗙被 ----------
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Rx {
|
||||||
|
/// Butler 鍙戠幇搴旂瓟 (259B 甯?/ 217B 璐熻浇)
|
||||||
|
DiscoveryResp(Vec<u8>),
|
||||||
|
/// Butler ACK (84B 甯?/ 42B 璐熻浇) ack_seq
|
||||||
|
Ack(u32),
|
||||||
|
/// Butler 鐘舵€佸抚 (>90B 璐熻浇, 0200+Butl)
|
||||||
|
Status(Vec<u8>),
|
||||||
|
/// RDM 搴旂瓟 (璐熻浇 60-90B, 0x28 闀垮害 + cc01)
|
||||||
|
RdmResp(Vec<u8>, usize),
|
||||||
|
/// 涓绘満瀹e憡搴旂瓟/鍏朵粬 ENet type=01
|
||||||
|
EnetType1(usize),
|
||||||
|
/// 鍏跺畠
|
||||||
|
Other(usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn classify(b: &[u8]) -> Rx {
|
||||||
|
if b.len() < 8 || &b[0..4] != b"ENet" {
|
||||||
|
return Rx::Other(b.len());
|
||||||
|
}
|
||||||
|
let t = g32(b, 4);
|
||||||
|
if t == 1 { return Rx::EnetType1(b.len()); }
|
||||||
|
if t == 4 {
|
||||||
|
if b.len() == 42 && g16(b, 0x18) == 2 && &b[0x1A..0x1E] == b"Butl" {
|
||||||
|
return Rx::Ack(g32(b, 0x20));
|
||||||
|
}
|
||||||
|
if b.len() > 0x2C && g16(b, 0x18) == 2 && &b[0x1A..0x1E] == b"Butl" {
|
||||||
|
let rlen = g16(b, 0x28) as usize;
|
||||||
|
if b.len() >= 0x2A + rlen && b[0x2A] == 0xCC && b[0x2B] == 0x01 {
|
||||||
|
return Rx::RdmResp(b.to_vec(), rlen);
|
||||||
|
}
|
||||||
|
return Rx::Status(b.to_vec());
|
||||||
|
}
|
||||||
|
if b.len() == 217 { return Rx::DiscoveryResp(b.to_vec()); }
|
||||||
|
}
|
||||||
|
Rx::Other(b.len())
|
||||||
|
}
|
||||||
1731
src/hostdemo.rs
Normal file
1731
src/hostdemo.rs
Normal file
File diff suppressed because it is too large
Load Diff
194
src/main.rs
Normal file
194
src/main.rs
Normal file
|
|
@ -0,0 +1,194 @@
|
||||||
|
// main.rs — enet-validator: e:net 协议独立验证程序 (模拟 e:cue 主机, 连接真机 Butler S2)
|
||||||
|
mod enet;
|
||||||
|
mod tests;
|
||||||
|
mod dmxhash;
|
||||||
|
mod aech;
|
||||||
|
mod hostdemo;
|
||||||
|
|
||||||
|
use tests::Item;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let arg = std::env::args().nth(1).unwrap_or_else(|| "help".into());
|
||||||
|
let mut results: Vec<Item> = Vec::new();
|
||||||
|
|
||||||
|
println!("enet-validator — e:net 协议实测验证 (Butler S2 @ 192.168.123.1)");
|
||||||
|
println!("================================================================");
|
||||||
|
match arg.as_str() {
|
||||||
|
"discover" => results.push(tests::t1_discover()),
|
||||||
|
"announce" => results.push(tests::tx_observe("T2", "announce", false)),
|
||||||
|
"heartbeat" => results.push(tests::tx_observe("T3", "heartbeat", false)),
|
||||||
|
"euce" => results.push(tests::tx_observe("T4", "euce", false)),
|
||||||
|
"session" => {
|
||||||
|
let secs: u64 = std::env::args().nth(2).and_then(|a| a.parse().ok()).unwrap_or(60);
|
||||||
|
results.extend(tests::t5_t8_session(secs));
|
||||||
|
}
|
||||||
|
"fallback" => results.push(tests::t9_fallback()),
|
||||||
|
"claim" => results.push(tests::t12_claim_replay()),
|
||||||
|
"takeover" => {
|
||||||
|
let secs: u64 = std::env::args().nth(2).and_then(|a| a.parse().ok()).unwrap_or(15);
|
||||||
|
results.extend(tests::t13_takeover(secs));
|
||||||
|
}
|
||||||
|
"holdbind" => {
|
||||||
|
// Rust 先 bind, 等待期间由 SymphoLight 认证; 之后 Rust 发帧测试共存
|
||||||
|
let s = enet::open_reuse("0.0.0.0:31772");
|
||||||
|
println!("Rust 已 bind 31772 (REUSEADDR)。等待 30s (此间启动 SymphoLight 认领)…");
|
||||||
|
std::thread::sleep(std::time::Duration::from_secs(30));
|
||||||
|
println!("开始发送测试帧 15s…");
|
||||||
|
results.extend(tests::t13_takeover_on(s, 15));
|
||||||
|
}
|
||||||
|
"device" => {
|
||||||
|
// 用法: device [设备IP] [MAC_hex12] [秒] (默认 192.168.123.200, 本机网卡MAC)
|
||||||
|
let ip_s = std::env::args().nth(2).unwrap_or_else(|| "192.168.123.200".into());
|
||||||
|
let mac_s = std::env::args().nth(3).unwrap_or_else(|| "300ed559bb36".into());
|
||||||
|
let secs: u64 = std::env::args().nth(4).and_then(|a| a.parse().ok()).unwrap_or(180);
|
||||||
|
let relay_s = std::env::args().nth(5); // 第5参: 中继目标 ip[:port] (默31772)
|
||||||
|
let ip: Vec<u8> = ip_s.split('.').filter_map(|x| x.parse().ok()).collect();
|
||||||
|
let mac: Vec<u8> = (0..mac_s.len()).step_by(2).filter_map(|i| u8::from_str_radix(&mac_s[i..i + 2], 16).ok()).collect();
|
||||||
|
let relay: Option<([u8; 4], u16)> = relay_s.and_then(|s| {
|
||||||
|
let (ips, port) = match s.rsplit_once(':') {
|
||||||
|
Some((a, p)) => (a.to_string(), p.parse::<u16>().unwrap_or(31772)),
|
||||||
|
None => (s, 31772),
|
||||||
|
};
|
||||||
|
let o: Vec<u8> = ips.split('.').filter_map(|x| x.parse().ok()).collect();
|
||||||
|
if o.len() == 4 { Some(([o[0], o[1], o[2], o[3]], port)) } else { None }
|
||||||
|
});
|
||||||
|
if ip.len() == 4 && mac.len() == 6 {
|
||||||
|
let mut ipa = [0u8; 4]; ipa.copy_from_slice(&ip);
|
||||||
|
let mut maca = [0u8; 6]; maca.copy_from_slice(&mac);
|
||||||
|
results.extend(tests::device2(ipa, maca, secs, relay));
|
||||||
|
} else {
|
||||||
|
println!("device 参数错误");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"rdm" => {
|
||||||
|
let secs: u64 = std::env::args().nth(2).and_then(|a| a.parse().ok()).unwrap_or(30);
|
||||||
|
results.extend(tests::t10_t11_rdm(secs));
|
||||||
|
}
|
||||||
|
"bridge" => {
|
||||||
|
// bridge <listen_ip:port> <real_ip> [secs] — AECH 桥 (非123网段设备认领桥)
|
||||||
|
let lp = std::env::args().nth(2).unwrap_or_else(|| "192.168.58.107:41772".into());
|
||||||
|
let rip_s = std::env::args().nth(3).unwrap_or_else(|| "192.168.123.1".into());
|
||||||
|
let secs: u64 = std::env::args().nth(4).and_then(|a| a.parse().ok()).unwrap_or(7200);
|
||||||
|
let (lip_s, lport) = match lp.rsplit_once(':') {
|
||||||
|
Some((a, p)) => (a.to_string(), p.parse::<u16>().unwrap_or(41772)),
|
||||||
|
None => (lp, 41772),
|
||||||
|
};
|
||||||
|
let lip: Vec<u8> = lip_s.split('.').filter_map(|x| x.parse().ok()).collect();
|
||||||
|
let rip: Vec<u8> = rip_s.split('.').filter_map(|x| x.parse().ok()).collect();
|
||||||
|
if lip.len() == 4 && rip.len() == 4 {
|
||||||
|
tests::bridge([lip[0], lip[1], lip[2], lip[3]], lport, [rip[0], rip[1], rip[2], rip[3]], secs);
|
||||||
|
} else {
|
||||||
|
println!("bridge 参数错误");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
"all" => {
|
||||||
|
results.push(tests::t1_discover());
|
||||||
|
results.push(tests::tx_observe("T2", "announce", false));
|
||||||
|
results.push(tests::tx_observe("T3", "heartbeat", false));
|
||||||
|
results.push(tests::tx_observe("T4", "euce", false));
|
||||||
|
results.extend(tests::t5_t8_session(60));
|
||||||
|
results.push(tests::t9_fallback());
|
||||||
|
}
|
||||||
|
"rdmprobe" => {
|
||||||
|
let target = std::env::args().nth(2).unwrap_or_else(|| "192.168.123.1".into());
|
||||||
|
let secs: u64 = std::env::args().nth(3).and_then(|a| a.parse().ok()).unwrap_or(10);
|
||||||
|
results.push(tests::rdm_probe(&target, secs));
|
||||||
|
}
|
||||||
|
"dmxhash" => {
|
||||||
|
// dmxhash <tsv> [主机IP] — DMX-A 帧标签算法爆破 (离线分析, 无网络)
|
||||||
|
let tsv = std::env::args().nth(2).unwrap_or_else(|| "dmx.tsv".into());
|
||||||
|
let host = std::env::args().nth(3).unwrap_or_else(|| "192.168.123.113".into());
|
||||||
|
dmxhash::run(&tsv, &host);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
"evtf" => {
|
||||||
|
// evtf <tsv> [主机IP] [设备IP] [tsv2跨包] — 形态B事件帧结构分析 (离线)
|
||||||
|
let tsv = std::env::args().nth(2).unwrap_or_else(|| "dmx.tsv".into());
|
||||||
|
let host = std::env::args().nth(3).unwrap_or_else(|| "192.168.123.113".into());
|
||||||
|
let dev = std::env::args().nth(4).unwrap_or_else(|| "192.168.123.1".into());
|
||||||
|
let tsv2 = std::env::args().nth(5);
|
||||||
|
dmxhash::evt(&tsv, &host, &dev, tsv2.as_deref());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
"aech" => {
|
||||||
|
// aech <tsv1> [tsv2 ...] — AECH 密钥协商密码学分析 (离线)
|
||||||
|
let tsvs: Vec<String> = std::env::args().skip(2).collect();
|
||||||
|
if tsvs.is_empty() {
|
||||||
|
println!("用法: enet-validator aech <tsv1> [tsv2 ...]");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
aech::run(&tsvs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
"aechprobe" => {
|
||||||
|
// aechprobe <tsv模板> <目标IP> — 选择密文仿射性分析 (在线探测真机)
|
||||||
|
let tsv = std::env::args().nth(2).unwrap_or_else(|| "cold2.tsv".into());
|
||||||
|
let target = std::env::args().nth(3).unwrap_or_else(|| "192.168.123.1".into());
|
||||||
|
aech::probe(&tsv, &target);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
"aechprobe2" => {
|
||||||
|
// aechprobe2 <tsv模板> <目标IP> — part1 块/字节影响图谱 (在线)
|
||||||
|
let tsv = std::env::args().nth(2).unwrap_or_else(|| "cold2.tsv".into());
|
||||||
|
let target = std::env::args().nth(3).unwrap_or_else(|| "192.168.123.1".into());
|
||||||
|
aech::probe2(&tsv, &target);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
"aechid" => {
|
||||||
|
// aechid <tsv> — f(last4) 离线候选函数鉴别
|
||||||
|
let tsv = std::env::args().nth(2).unwrap_or_else(|| "cold2.tsv".into());
|
||||||
|
aech::identify(&tsv);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
"dmxroll" => {
|
||||||
|
// dmxroll <tsv> — DMX 滚动值/保护字节数据驱动分析 (离线)
|
||||||
|
let tsv = std::env::args().nth(2).unwrap_or_else(|| "dmx.tsv".into());
|
||||||
|
aech::dmxroll(&tsv);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
"dmxdec" => {
|
||||||
|
// dmxdec <tsv> — DMX 帧加密假说验证 (kWarv47o79k/zPprv0TXRRW 逆运算, 需 TSV 含 AECH)
|
||||||
|
let tsv = std::env::args().nth(2).unwrap_or_else(|| "dmx.tsv".into());
|
||||||
|
aech::dmxdec(&tsv);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
"dmxsend" => {
|
||||||
|
// dmxsend <目标IP> [秒] — 主机侧等效播放: 认领 + 加密 DMX 全链路自证
|
||||||
|
let ip = std::env::args().nth(2).unwrap_or_else(|| "192.168.58.7".into());
|
||||||
|
let secs: u64 = std::env::args().nth(3).and_then(|s| s.parse().ok()).unwrap_or(30);
|
||||||
|
aech::dmxsend(&ip, secs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
"hostdemo" => {
|
||||||
|
// hostdemo [目标IP] [秒] — 主机侧等效示例: 认领真机 + RDM 发现 + 加密 DMX 控制
|
||||||
|
// 源 IP 固定 192.168.123.113 (真机 .1 的 AECH 固件过滤); 秒=0 只做认领+RDM 不发 DMX
|
||||||
|
let ip = std::env::args().nth(2).unwrap_or_else(|| "192.168.123.1".into());
|
||||||
|
let secs: u64 = std::env::args().nth(3).and_then(|s| s.parse().ok()).unwrap_or(30);
|
||||||
|
hostdemo::run(&ip, "192.168.123.113", secs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
println!("用法: enet-validator <discover|announce|heartbeat|euce|session [秒]|fallback|claim|rdm [秒]|all>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("----------------------------------------------------------------");
|
||||||
|
let p = results.iter().filter(|r| r.pass).count();
|
||||||
|
for r in &results { r.show(); }
|
||||||
|
println!("================================================================");
|
||||||
|
println!("汇总: PASS={} FAIL={}", p, results.len() - p);
|
||||||
|
|
||||||
|
// 写 JSON 报告
|
||||||
|
let mut j = String::from("{\n \"target\": \"192.168.123.1\",\n \"results\": [\n");
|
||||||
|
for (i, r) in results.iter().enumerate() {
|
||||||
|
j.push_str(&format!(
|
||||||
|
" {{ \"id\": \"{}\", \"pass\": {}, \"detail\": \"{}\" }}{}\n",
|
||||||
|
r.id, r.pass, r.detail.replace('"', "'"),
|
||||||
|
if i + 1 < results.len() { "," } else { "" }));
|
||||||
|
}
|
||||||
|
j.push_str(" ]\n}\n");
|
||||||
|
let _ = std::fs::write("validation_report.json", j);
|
||||||
|
println!("报告已写: validation_report.json");
|
||||||
|
}
|
||||||
905
src/tests.rs
Normal file
905
src/tests.rs
Normal file
|
|
@ -0,0 +1,905 @@
|
||||||
|
// tests.rs — T1..T11 协议验证实现 (判据 = Butler 实际应答)
|
||||||
|
use crate::enet::*;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
use std::net::UdpSocket;
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
|
pub struct Item {
|
||||||
|
pub id: &'static str,
|
||||||
|
pub pass: bool,
|
||||||
|
pub detail: String,
|
||||||
|
}
|
||||||
|
impl Item {
|
||||||
|
fn new(id: &'static str, pass: bool, detail: String) -> Item { Item { id, pass, detail } }
|
||||||
|
pub fn show(&self) {
|
||||||
|
println!(" [{}] {} {}", if self.pass { "PASS" } else { "FAIL" }, self.id, self.detail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- T1: 发现请求 → Butler 应答 (§3.1→§3.2) ----------
|
||||||
|
pub fn t1_discover() -> Item {
|
||||||
|
let s = open();
|
||||||
|
let req = load_template("discovery_req");
|
||||||
|
let _ = s.send_to(&req, BCAST_SUB);
|
||||||
|
let _ = s.send_to(&req, BCAST_ALL);
|
||||||
|
let replies = recv_window(&s, Duration::from_secs(4));
|
||||||
|
let mut detail = format!("收到{}包; ", replies.len());
|
||||||
|
for (_, b) in &replies {
|
||||||
|
if b.len() == 217 && &b[0..4] == b"ENet" {
|
||||||
|
let len_ok = g32(b, 0x14) == 217;
|
||||||
|
let name_ok = find(b, b"Butler S2");
|
||||||
|
let mac_ok = find(b, &[0x00, 0x16, 0x1c, 0xf1, 0x2e, 0x39]);
|
||||||
|
let pass = len_ok && name_ok && mac_ok;
|
||||||
|
detail.push_str(&format!(
|
||||||
|
"应答217B: len字段={} 名字={} MAC={}",
|
||||||
|
len_ok, name_ok, mac_ok
|
||||||
|
));
|
||||||
|
return Item::new("T1", pass, detail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
detail.push_str("未收到 217B 发现应答");
|
||||||
|
Item::new("T1", false, detail)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- T2/T3/T4: 单向帧发送 → 观察会话反应 ----------
|
||||||
|
pub fn tx_observe(id: &'static str, tpl: &str, expect_reply: bool) -> Item {
|
||||||
|
let s = open();
|
||||||
|
let f = load_template(tpl);
|
||||||
|
let dst = if tpl == "heartbeat" { BCAST_SUB } else { BCAST_ALL };
|
||||||
|
let n = s.send_to(&f, dst).expect("send");
|
||||||
|
let replies = recv_window(&s, Duration::from_secs(3));
|
||||||
|
let mut detail = format!("发送{}B→{}; 收到{}包", n, dst, replies.len());
|
||||||
|
let mut pass = true;
|
||||||
|
if expect_reply {
|
||||||
|
pass = !replies.is_empty();
|
||||||
|
if !pass { detail.push_str("; 无应答"); }
|
||||||
|
}
|
||||||
|
Item::new(id, pass, detail)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- T5-T8: 会话 (DMX + 事件×2 + ACK配对 + 状态帧) ----------
|
||||||
|
pub struct SessionStats {
|
||||||
|
pub dmx_sent: u64,
|
||||||
|
pub evt_sent: u64,
|
||||||
|
pub acks: u64,
|
||||||
|
pub ack_matched: u64,
|
||||||
|
pub status: u64,
|
||||||
|
pub rdm: u64,
|
||||||
|
pub other: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn session(secs: u64, mutate_channels: bool) -> (SessionStats, Vec<(u32, u64)>) {
|
||||||
|
let s = open();
|
||||||
|
session_on(s, secs, mutate_channels, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 会话核心 (可注入 socket): takeover 模式跳过 preamble 且使用抢 bind 的 socket
|
||||||
|
pub fn session_on(s: UdpSocket, secs: u64, mutate_channels: bool, preamble: bool) -> (SessionStats, Vec<(u32, u64)>) {
|
||||||
|
if preamble {
|
||||||
|
// --- 前置认领 (§6 时序): 发现请求 → 宣告帧 → 短暂等待 ---
|
||||||
|
let disc = load_template("discovery_req");
|
||||||
|
let ann = load_template("announce");
|
||||||
|
let _ = s.send_to(&disc, BCAST_SUB);
|
||||||
|
let _ = s.send_to(&disc, BCAST_ALL);
|
||||||
|
let _ = s.send_to(&ann, BCAST_ALL);
|
||||||
|
let _ = recv_window(&s, Duration::from_secs(2)); // 吸收发现应答/宣告反应
|
||||||
|
}
|
||||||
|
let dmx_t = load_template("dmx_a");
|
||||||
|
let evt_t = load_template("event_b");
|
||||||
|
let mut dmx_seq = g16(&dmx_t, 0x1A).wrapping_add(1);
|
||||||
|
let mut evt_seq = g32(&evt_t, 0x22).wrapping_add(1);
|
||||||
|
let tick = Duration::from_millis(25);
|
||||||
|
let start = Instant::now();
|
||||||
|
let mut st = SessionStats { dmx_sent: 0, evt_sent: 0, acks: 0, ack_matched: 0, status: 0, rdm: 0, other: 0 };
|
||||||
|
let mut recent: HashSet<u32> = HashSet::new();
|
||||||
|
let mut timeline: Vec<(u32, u64)> = Vec::new();
|
||||||
|
let mut tick_n: u64 = 0;
|
||||||
|
while start.elapsed().as_secs() < secs {
|
||||||
|
// --- DMX 帧 (形态A) ---
|
||||||
|
let mut d = dmx_t.clone();
|
||||||
|
p16(&mut d, 0x1A, dmx_seq);
|
||||||
|
let tms = tick_n * 25;
|
||||||
|
for i in 0..8 { d[0x22 + i] = ((tms >> (i * 8)) & 0xFF) as u8; }
|
||||||
|
if mutate_channels {
|
||||||
|
let ph = start.elapsed().as_secs();
|
||||||
|
for i in 0..1024usize {
|
||||||
|
d[0x3C + i] = match ph {
|
||||||
|
0..=9 => 0,
|
||||||
|
10..=19 => 255,
|
||||||
|
_ => (((1024usize).wrapping_sub(i + (tick_n as usize) * 4)) & 0xFF) as u8,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let _ = s.send_to(&d, BUTLER);
|
||||||
|
st.dmx_sent += 1;
|
||||||
|
dmx_seq = dmx_seq.wrapping_add(1);
|
||||||
|
// --- 事件帧 ×2 (形态B) ---
|
||||||
|
for _ in 0..2 {
|
||||||
|
let mut e = evt_t.clone();
|
||||||
|
p32(&mut e, 0x22, evt_seq);
|
||||||
|
recent.insert(evt_seq);
|
||||||
|
if recent.len() > 64 { recent.remove(&(evt_seq.wrapping_sub(64))); }
|
||||||
|
let _ = s.send_to(&e, BUTLER);
|
||||||
|
st.evt_sent += 1;
|
||||||
|
evt_seq = evt_seq.wrapping_add(1);
|
||||||
|
}
|
||||||
|
// --- 收集应答 ---
|
||||||
|
for (_, b) in recv_window(&s, tick) {
|
||||||
|
match classify(&b) {
|
||||||
|
Rx::Ack(sq) => {
|
||||||
|
st.acks += 1;
|
||||||
|
if recent.contains(&sq) { st.ack_matched += 1; }
|
||||||
|
timeline.push((sq, tick_n));
|
||||||
|
}
|
||||||
|
Rx::Status(_) => st.status += 1,
|
||||||
|
Rx::RdmResp(_, _) => st.rdm += 1,
|
||||||
|
Rx::DiscoveryResp(_) | Rx::EnetType1(_) => {}
|
||||||
|
Rx::Other(_) => st.other += 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tick_n += 1;
|
||||||
|
}
|
||||||
|
(st, timeline)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn t5_t8_session(secs: u64) -> Vec<Item> {
|
||||||
|
println!(" 会话运行 {}s (DMX→事件×2, 25ms/tick)…", secs);
|
||||||
|
let (st, _) = session(secs, true);
|
||||||
|
let rate_dmx = st.dmx_sent as f64 / secs as f64;
|
||||||
|
let pair = if st.acks > 0 { st.ack_matched as f64 / st.acks as f64 } else { 0.0 };
|
||||||
|
vec![
|
||||||
|
Item::new("T5", st.dmx_sent > secs * 30 && st.status > 0,
|
||||||
|
format!("DMX发送={} (~{:.0}Hz) 状态帧={}", st.dmx_sent, rate_dmx, st.status)),
|
||||||
|
Item::new("T6", pair >= 0.95,
|
||||||
|
format!("ACK={} 配对={} ({:.1}%)", st.acks, st.ack_matched, pair * 100.0)),
|
||||||
|
Item::new("T7", st.status > 0, format!("状态帧={}", st.status)),
|
||||||
|
Item::new("T8", st.dmx_sent > secs * 30 && st.acks > secs,
|
||||||
|
format!("会话{}s无中断", secs)),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- T9: 回落与恢复 ----------
|
||||||
|
pub fn t9_fallback() -> Item {
|
||||||
|
println!(" 阶段1: 会话 10s…");
|
||||||
|
let (a, _) = session(10, false);
|
||||||
|
println!(" 阶段2: 静默 12s (只收不发)…");
|
||||||
|
let s = open();
|
||||||
|
let quiet = recv_window(&s, Duration::from_secs(12));
|
||||||
|
let mut quiet_status = 0usize;
|
||||||
|
for (_, b) in &quiet {
|
||||||
|
if let Rx::Status(_) = classify(b) { quiet_status += 1; }
|
||||||
|
}
|
||||||
|
println!(" 阶段3: 恢复会话 8s…");
|
||||||
|
let (b, _) = session(8, false);
|
||||||
|
let pass = a.acks > 5 && b.acks > 5; // 恢复后 ACK 恢复 = 重新接管成功
|
||||||
|
Item::new("T9", pass, format!(
|
||||||
|
"会话前段ACK={}; 静默期收{}包(状态{}); 恢复后ACK={}",
|
||||||
|
a.acks, quiet.len(), quiet_status, b.acks))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- T12(实验): AECHA 认领重放 ----------
|
||||||
|
pub fn t12_claim_replay() -> Item {
|
||||||
|
let s = open();
|
||||||
|
let tick = Duration::from_millis(25);
|
||||||
|
let c1 = load_template("claim_h112");
|
||||||
|
let c2 = load_template("claim_h114");
|
||||||
|
let c3 = load_template("claim_h116");
|
||||||
|
let mut aereps = 0u64;
|
||||||
|
let mut last_detail = String::new();
|
||||||
|
for (i, f) in [&c1, &c2, &c3].into_iter().enumerate() {
|
||||||
|
let _ = s.send_to(f, BUTLER);
|
||||||
|
let replies = recv_window(&s, Duration::from_millis(800));
|
||||||
|
let mut got = false;
|
||||||
|
for (_, b) in &replies {
|
||||||
|
if find(b, b"AEREP") { aereps += 1; got = true; }
|
||||||
|
}
|
||||||
|
last_detail.push_str(&format!("[{}] 应答{}包{} ", i + 1, replies.len(), if got { "+AEREP" } else { "" }));
|
||||||
|
}
|
||||||
|
// 若 3 轮完成 → 立即试探 DMX: 发 10 个 tick 看是否出现 ACK
|
||||||
|
let mut acks = 0u64;
|
||||||
|
if aereps >= 1 {
|
||||||
|
let dmx_t = load_template("dmx_a");
|
||||||
|
let evt_t = load_template("event_b");
|
||||||
|
let mut dmx_seq = g16(&dmx_t, 0x1A).wrapping_add(1);
|
||||||
|
let mut evt_seq = g32(&evt_t, 0x22).wrapping_add(1);
|
||||||
|
for _ in 0..10 {
|
||||||
|
let mut d = dmx_t.clone();
|
||||||
|
p16(&mut d, 0x1A, dmx_seq);
|
||||||
|
let _ = s.send_to(&d, BUTLER);
|
||||||
|
dmx_seq = dmx_seq.wrapping_add(1);
|
||||||
|
for _ in 0..2 {
|
||||||
|
let mut e = evt_t.clone();
|
||||||
|
p32(&mut e, 0x22, evt_seq);
|
||||||
|
evt_seq += 1;
|
||||||
|
let _ = s.send_to(&e, BUTLER);
|
||||||
|
}
|
||||||
|
for (_, b) in recv_window(&s, tick) {
|
||||||
|
if let Rx::Ack(_) = classify(&b) { acks += 1; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
last_detail.push_str(&format!("; AEREP={} 试探ACK={}", aereps, acks));
|
||||||
|
Item::new("T12", acks > 0, last_detail)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// takeover 变体: 使用外部传入的已 bind socket
|
||||||
|
pub fn t13_takeover_on(s: UdpSocket, secs: u64) -> Vec<Item> {
|
||||||
|
println!(" 发帧 {}s (共存模式)…", secs);
|
||||||
|
let (st, _) = session_on(s, secs, true, false);
|
||||||
|
let pair = if st.acks > 0 { st.ack_matched as f64 / st.acks as f64 } else { 0.0 };
|
||||||
|
vec![
|
||||||
|
Item::new("T13a", st.dmx_sent > secs * 20, format!("DMX发送={}", st.dmx_sent)),
|
||||||
|
Item::new("T13b", st.acks > 0, format!("Rust收到ACK={} 配对={:.1}% 状态={}",
|
||||||
|
st.acks, pair * 100.0, st.status)),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- T13(实验): 挂起 SymphoLight 后 Rust 抢占接管会话 ----------
|
||||||
|
pub fn t13_takeover(secs: u64) -> Vec<Item> {
|
||||||
|
// 用抢 bind 的 socket 跑会话核心 (无 preamble: 认证已由 SymphoLight 完成)
|
||||||
|
let s = open_reuse(BIND);
|
||||||
|
println!(" 接管会话 {}s (SO_REUSEADDR 模式)…", secs);
|
||||||
|
let (st, _) = session_on(s, secs, true, false);
|
||||||
|
let pair = if st.acks > 0 { st.ack_matched as f64 / st.acks as f64 } else { 0.0 };
|
||||||
|
vec![
|
||||||
|
Item::new("T13a", st.dmx_sent > secs * 20, format!("接管后 DMX发送={}", st.dmx_sent)),
|
||||||
|
Item::new("T13b", st.acks > 0, format!("ACK={} 配对={} ({:.1}%) 状态={}",
|
||||||
|
st.acks, st.ack_matched, pair * 100.0, st.status)),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- 设备端模拟 v2 (Secondary IP, 与真 Butler 并存) ----------
|
||||||
|
// 双 socket: wildcard(REUSEADDR) 收广播发现; dev_ip:31772 收会话/发应答(源IP正确)
|
||||||
|
pub fn device2(dev_ip: [u8; 4], dev_mac: [u8; 6], secs: u64, relay: Option<([u8; 4], u16)>) -> Vec<Item> {
|
||||||
|
let mut items = Vec::new();
|
||||||
|
let bind_addr = format!("{}.{}.{}.{}:31772", dev_ip[0], dev_ip[1], dev_ip[2], dev_ip[3]);
|
||||||
|
let sess = open_reuse(&bind_addr);
|
||||||
|
// wildcard(REUSEADDR) 收广播发现; 注意: 必须先启动本程序、后启动 SymphoLight
|
||||||
|
let disc = std::panic::catch_unwind(|| open_reuse("0.0.0.0:31772")).ok();
|
||||||
|
// AECH 中继 socket: 优先绑 113 (本机 123 网段时直接中继 .1); 非本网段则绑自身 IP (经桥中继)
|
||||||
|
let relay_sock: Option<UdpSocket> = relay.map(|_| {
|
||||||
|
std::panic::catch_unwind(|| open_reuse("192.168.123.113:0"))
|
||||||
|
.unwrap_or_else(|_| open_reuse(&format!("{}.{}.{}.{}:0", dev_ip[0], dev_ip[1], dev_ip[2], dev_ip[3])))
|
||||||
|
});
|
||||||
|
sess.set_read_timeout(Some(Duration::from_millis(2))).unwrap();
|
||||||
|
println!(" 虚拟 Butler @ {} (MAC {:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}), 运行 {}s",
|
||||||
|
bind_addr, dev_mac[0], dev_mac[1], dev_mac[2], dev_mac[3], dev_mac[4], dev_mac[5], secs);
|
||||||
|
|
||||||
|
let resp_t = load_template("discovery_resp");
|
||||||
|
let aerep_t = load_template("aerep");
|
||||||
|
let ack_t = load_template("ack");
|
||||||
|
let status_t = load_template("status"); // 84B "Butl" 设备状态遥测帧
|
||||||
|
let reg89_t = load_template("register89"); // 89B 主机注册应答 (sub=02)
|
||||||
|
let aere594_t = load_template("aere594"); // 594B AECH 认领应答 (sub=06, AERE)
|
||||||
|
let ann144_t = load_template("announce144"); // 144B 宣告 (sub=01, 中继唤醒用)
|
||||||
|
// RDM 应答模板: 5种DISC脉冲(101B) + 分支应答(111B) + 参数信息(119B)
|
||||||
|
let pulse_ts = vec![load_template("rdm_pulse_0"), load_template("rdm_pulse_1"),
|
||||||
|
load_template("rdm_pulse_2"), load_template("rdm_pulse_3"), load_template("rdm_pulse_4")];
|
||||||
|
let rdm111_t = load_template("rdm_resp111");
|
||||||
|
let rdm119_t = load_template("rdm_info119");
|
||||||
|
let setack68_t = load_template("rdm_setack68"); // RDM SET 应答模板 (CC=31, PDL=0, 68B, set123b 实证)
|
||||||
|
// 真机 .1 完整 RDM 应答帧池 (178 唯一帧: 56/59/70/77/87B 全部应答词表)
|
||||||
|
let rdm_pool = crate::enet::load_rdm_pool();
|
||||||
|
println!(" RDM 帧池: {} 帧", rdm_pool.len());
|
||||||
|
// PID→应答模板映射 (cmd=18=RDM GET, 查询 PID 在 0x50, 应答含 21<PID>)
|
||||||
|
let mut pid_map: std::collections::HashMap<[u8; 2], Vec<u8>> = std::collections::HashMap::new();
|
||||||
|
// SET 写路径状态: 主机 SET (CC=0x30) 的值按 (UID, PID) 落存, 后续 GET 同 PID 回显新值
|
||||||
|
// (真机行为: SET 立即生效, 主机 +33ms GET 验证 — set123b 实证, §5.6)
|
||||||
|
let mut set_store: std::collections::HashMap<([u8; 6], [u8; 2]), Vec<u8>> = std::collections::HashMap::new();
|
||||||
|
for line in include_str!("../samples/pid_map.txt").lines() {
|
||||||
|
let line = line.trim();
|
||||||
|
if line.len() < 8 { continue; }
|
||||||
|
let pid_hex = &line[..4];
|
||||||
|
let frame_hex = line[5..].trim();
|
||||||
|
let pb: Vec<u8> = (0..pid_hex.len()).step_by(2).map(|i| u8::from_str_radix(&pid_hex[i..i + 2], 16).unwrap()).collect();
|
||||||
|
let fb: Vec<u8> = (0..frame_hex.len()).step_by(2).map(|i| u8::from_str_radix(&frame_hex[i..i + 2], 16).unwrap()).collect();
|
||||||
|
if pb.len() == 2 { pid_map.insert([pb[0], pb[1]], fb); }
|
||||||
|
}
|
||||||
|
println!(" PID 映射: {} 个", pid_map.len());
|
||||||
|
|
||||||
|
let start = Instant::now();
|
||||||
|
let mut n_disc = 0u64; let mut n_aecha = 0u64; let mut n_dmx = 0u64;
|
||||||
|
let mut n_evt = 0u64; let mut n_ack = 0u64; let mut n_other = 0u64;
|
||||||
|
let mut n_status = 0u64; let mut status_seq = 0x62u32;
|
||||||
|
let mut n_rdm_pulse = 0u64; let mut n_rdm_111 = 0u64; let mut n_rdm_119 = 0u64;
|
||||||
|
let mut n_rdm_set = 0u64;
|
||||||
|
let mut n_announce = 0u64;
|
||||||
|
let mut pulse_idx = 0usize; let mut pulse_seq = 0x0f0bu32; let mut info_ctr = 0xc0u8;
|
||||||
|
let mut pulse_step: u32 = 2;
|
||||||
|
let mut pool_idx = 0usize;
|
||||||
|
let mut cur_pulse = 0usize; let mut branch_ctr = 0u64;
|
||||||
|
let mut cur_fixture = 0usize;
|
||||||
|
let mut rdm_req_dumped = 0u32;
|
||||||
|
let mut n_reg = 0u64; let mut n_claim = 0u64; let mut claim_nonce: u32 = 0x51f31ab9;
|
||||||
|
let mut dmx_b12: Option<u32> = None; // AECH 质询 0x8C-0x8F 实例随机 → DMX 解密 rot 基值
|
||||||
|
let mut n_rdm_relay = 0u64; let mut n_rdm_fwd = 0u64;
|
||||||
|
let mut pending_rdm_bridge = [0u8; 6];
|
||||||
|
// AECH 中继: (认领者地址, 主机IP LE, 主机MAC) — 质询转发真机后暂存
|
||||||
|
let mut pending_claim: Option<(std::net::SocketAddr, [u8;4], [u8;6])> = None;
|
||||||
|
let mut last_pulse = Instant::now() - Duration::from_secs(10);
|
||||||
|
let mut first_channels: Option<[u8; 32]> = None;
|
||||||
|
let mut last_channels: [u8; 32] = [0; 32];
|
||||||
|
let mut ch_changes = 0u64;
|
||||||
|
let mut last_ch_show = Instant::now() - Duration::from_secs(10);
|
||||||
|
let mut peer: Option<std::net::SocketAddr> = None;
|
||||||
|
// RDM 应答延迟队列 (真机灯具经 RS485 应答延迟 12-48ms, 中位 29ms — 瞬时应答是假指纹)
|
||||||
|
let mut rdm_queue: Vec<(Instant, Vec<u8>, std::net::SocketAddr)> = Vec::new();
|
||||||
|
let mut delay_lcg: u32 = 0x9e3779b9;
|
||||||
|
let mut next_delay = move |base_ms: u64, span_ms: u64| -> u64 {
|
||||||
|
delay_lcg = delay_lcg.wrapping_mul(2654435761).wrapping_add(0x9e3779b9);
|
||||||
|
base_ms + ((delay_lcg >> 16) as u64 % span_ms)
|
||||||
|
};
|
||||||
|
// 42B 遥测: 真机 ~每 115ms 上报一次"已收事件计数" (0x20-0x23 严格递增,
|
||||||
|
// 增量=事件B帧数, ss123 实证 +2959 计数 ≈ 2963 事件)
|
||||||
|
let mut event_ctr: u32 = 0;
|
||||||
|
let mut ack42_sent_val: u32 = 0;
|
||||||
|
let mut last_ack42 = Instant::now() - Duration::from_secs(1);
|
||||||
|
let mut evt_dst: Option<std::net::SocketAddr> = None;
|
||||||
|
|
||||||
|
while start.elapsed().as_secs() < secs {
|
||||||
|
// --- 真机无自发状态帧 (168s 仅 1 帧 42B, 已全部删除突发遥测) ---
|
||||||
|
// --- 到期的 RDM 延迟应答 ---
|
||||||
|
if !rdm_queue.is_empty() {
|
||||||
|
let now = Instant::now();
|
||||||
|
let mut i = 0;
|
||||||
|
while i < rdm_queue.len() {
|
||||||
|
if rdm_queue[i].0 <= now {
|
||||||
|
let (_, r, dst) = rdm_queue.remove(i);
|
||||||
|
let _ = sess.send_to(&r, dst);
|
||||||
|
} else { i += 1; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// --- 42B 遥测: 真机 ~每 115ms 上报一次"已收事件计数" (ss123 实证) ---
|
||||||
|
if last_ack42.elapsed() > Duration::from_millis(115) && event_ctr != ack42_sent_val {
|
||||||
|
if let Some(dst) = evt_dst {
|
||||||
|
let mut a = ack_t.to_vec();
|
||||||
|
p32(&mut a, 0x20, event_ctr);
|
||||||
|
let _ = sess.send_to(&a, dst);
|
||||||
|
ack42_sent_val = event_ctr;
|
||||||
|
last_ack42 = Instant::now();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut buf = [0u8; 2048];
|
||||||
|
// --- wildcard socket: 收广播发现 (仅初始发现阶段用) ---
|
||||||
|
if let Some(ref d) = disc {
|
||||||
|
if let Ok((n, src)) = d.recv_from(&mut buf) {
|
||||||
|
let b = &buf[..n];
|
||||||
|
if b.len() == 180 && &b[0..4] == b"ENet" && g32(b, 4) == 1 {
|
||||||
|
// 真机处理延迟 ~160ms (指纹对齐)
|
||||||
|
std::thread::sleep(Duration::from_millis(150));
|
||||||
|
let mut r = resp_t.clone();
|
||||||
|
patch_dev(&mut r, dev_ip, dev_mac);
|
||||||
|
patch_259_host(&mut r, src, b);
|
||||||
|
let _ = sess.send_to(&r, src);
|
||||||
|
n_disc += 1;
|
||||||
|
println!(" [{}] 发现请求 type1 from {} len={}", chrono_t(start), src, b.len());
|
||||||
|
} else if b.len() >= 0x1A && &b[0..4] == b"ENet" && g32(b, 4) == 2 && g16(b, 0x18) == 1 {
|
||||||
|
// 广播主机宣告 sub=01 → 也回 89B 注册帧 (从 sess 口发出)
|
||||||
|
let mut r = reg89_t.clone();
|
||||||
|
let ip_le = [dev_ip[3], dev_ip[2], dev_ip[1], dev_ip[0]];
|
||||||
|
r[0x1A..0x1E].copy_from_slice(&ip_le);
|
||||||
|
r[0x1E..0x24].copy_from_slice(&dev_mac);
|
||||||
|
if b.len() > 0x24 {
|
||||||
|
r[0x25..0x29].copy_from_slice(&b[0x1A..0x1E]);
|
||||||
|
r[0x29..0x2F].copy_from_slice(&b[0x1E..0x24]);
|
||||||
|
}
|
||||||
|
let _ = sess.send_to(&r, src);
|
||||||
|
n_reg += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// --- 中继回程轮询: 真机 AERE 回到 relay_sock (113:随机端口) ---
|
||||||
|
if let Some(rs) = relay_sock.as_ref() {
|
||||||
|
if let Ok((n, src)) = rs.recv_from(&mut buf) {
|
||||||
|
let b2 = &buf[..n];
|
||||||
|
if b2.len() >= 8 && &b2[0..4] == b"ENet" {
|
||||||
|
// --- RDM 应答回程: 真机灯具的 type=04 应答 (脉冲59B/分支69B/参数77B) → 发给主机 ---
|
||||||
|
if g32(b2, 4) == 4 && b2.len() >= 40 {
|
||||||
|
if let Some(p) = peer {
|
||||||
|
let mut r = b2.to_vec();
|
||||||
|
// cc01 帧内含 bridge-id (0x2D-0x32), 替换为查询的 bridge-id
|
||||||
|
if r.len() > 0x33 && r[0x2A] == 0xCC {
|
||||||
|
r[0x2D..0x33].copy_from_slice(&pending_rdm_bridge);
|
||||||
|
}
|
||||||
|
let _ = sess.send_to(&r, p);
|
||||||
|
n_rdm_fwd += 1;
|
||||||
|
if n_rdm_fwd <= 4 { println!(" [{}] RDM 应答回程 → 主机 ({}B)", chrono_t(start), r.len()); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let (Some((pc, hip, hmac)), Some(_)) = (pending_claim, relay) {
|
||||||
|
if b2.len() >= 552 && g32(b2, 4) == 2 && g16(b2, 0x18) == 6 { let mut r = b2.to_vec();
|
||||||
|
let ip_le = [dev_ip[3], dev_ip[2], dev_ip[1], dev_ip[0]];
|
||||||
|
r[0x1A..0x1E].copy_from_slice(&ip_le);
|
||||||
|
r[0x41..0x45].copy_from_slice(&ip_le);
|
||||||
|
r[0x1E..0x24].copy_from_slice(&dev_mac);
|
||||||
|
r[0x49..0x4F].copy_from_slice(&dev_mac);
|
||||||
|
r[0x25..0x28].copy_from_slice(&hip[0..3]);
|
||||||
|
r[0x2C..0x2F].copy_from_slice(&hmac[3..6]);
|
||||||
|
let _ = sess.send_to(&r, pc);
|
||||||
|
pending_claim = None;
|
||||||
|
n_claim += 1;
|
||||||
|
println!(" [{}] ★★ 真机 AERE 中继成功 → {} #{}", chrono_t(start), pc, n_claim);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// --- 会话 socket: 单播发现 / AECHA / DMX / 事件 ---
|
||||||
|
let (n, src) = match sess.recv_from(&mut buf) {
|
||||||
|
Ok(x) => x,
|
||||||
|
Err(_) => continue,
|
||||||
|
};
|
||||||
|
let b = &buf[..n];
|
||||||
|
if b.len() < 8 || &b[0..4] != b"ENet" { continue; }
|
||||||
|
peer = Some(src); // 记录对端(SymphoLight)用于遥测上行
|
||||||
|
let t = g32(b, 4);
|
||||||
|
if t == 1 && b.len() == 180 {
|
||||||
|
let mut r = resp_t.clone();
|
||||||
|
patch_dev(&mut r, dev_ip, dev_mac);
|
||||||
|
patch_259_host(&mut r, src, b);
|
||||||
|
let _ = sess.send_to(&r, src);
|
||||||
|
n_disc += 1;
|
||||||
|
println!(" [{}] 发现请求 type1 from {} len={}", chrono_t(start), src, b.len());
|
||||||
|
} else if t == 2 {
|
||||||
|
let sub = if b.len() >= 0x1A { g16(b, 0x18) } else { 0 };
|
||||||
|
if sub == 5 && find(b, b"AECH") {
|
||||||
|
if let (Some((rip, rport)), Some(rs)) = (relay, relay_sock.as_ref()) {
|
||||||
|
// --- 中继模式: 先向中继目标发 sub=01 宣告唤醒注册态, 再转发质询 ---
|
||||||
|
let hip = [b[0x1A], b[0x1B], b[0x1C], b[0x1D]];
|
||||||
|
let hmac = [b[0x1E], b[0x1F], b[0x20], b[0x21], b[0x22], b[0x23]];
|
||||||
|
pending_claim = Some((src, hip, hmac));
|
||||||
|
let raddr = format!("{}.{}.{}.{}:{}", rip[0], rip[1], rip[2], rip[3], rport);
|
||||||
|
// 宣告帧: 0x1A-1D 主机IP(LE), 0x1E-23 主机MAC
|
||||||
|
let mut ann = ann144_t.clone();
|
||||||
|
ann[0x1A..0x1E].copy_from_slice(&hip);
|
||||||
|
ann[0x1E..0x24].copy_from_slice(&hmac);
|
||||||
|
let _ = rs.send_to(&ann, &raddr);
|
||||||
|
std::thread::sleep(Duration::from_millis(30));
|
||||||
|
let _ = rs.send_to(b, &raddr);
|
||||||
|
println!(" [{}] AECH 质询中继 → 真机 {} (先宣告唤醒)", chrono_t(start), raddr);
|
||||||
|
} else {
|
||||||
|
// --- AECH 认领质询 (594B sub=05) → AERE 应答 (sub=06) ---
|
||||||
|
// 质询帧内: 0x1A-1D 主机IP(LE), 0x1E-23 主机MAC, 0x28 "AECH"
|
||||||
|
let mut r = aere594_t.clone();
|
||||||
|
// 设备 IP (LE) 0x1A 与 0x41; 设备 MAC 0x1E 与 0x49
|
||||||
|
let ip_le = [dev_ip[3], dev_ip[2], dev_ip[1], dev_ip[0]];
|
||||||
|
r[0x1A..0x1E].copy_from_slice(&ip_le);
|
||||||
|
r[0x41..0x45].copy_from_slice(&ip_le);
|
||||||
|
r[0x1E..0x24].copy_from_slice(&dev_mac);
|
||||||
|
r[0x49..0x4F].copy_from_slice(&dev_mac);
|
||||||
|
// AERE 0x25-27 = 主机IP前3字节(LE), 0x2C-2E = 主机MAC后3字节
|
||||||
|
if b.len() > 0x24 {
|
||||||
|
r[0x25..0x28].copy_from_slice(&b[0x1A..0x1D]);
|
||||||
|
r[0x2C..0x2F].copy_from_slice(&b[0x21..0x24]);
|
||||||
|
}
|
||||||
|
// 0xC0-0xC3 = AgiosElias G(nonce@0x88-0x8B LE) — 算法已从 SymphoLight
|
||||||
|
// Ecue.Devices.dll 反编译还原 (无密钥! G(x)=x^TABLE[(x%32+1+(x*13)%30)%32]),
|
||||||
|
// 主机按同式验证 AERE blob[152]。无需真机中继。
|
||||||
|
let nonce = if b.len() > 0x8C { g32(b, 0x88) } else { 0 };
|
||||||
|
p32(&mut r, 0xC0, crate::aech::agios_g(nonce));
|
||||||
|
// 0x8C-0x8F = AgiosElias 实例随机 B12 — DMX 帧混淆 rot=(B12^r)&511 的会话基值
|
||||||
|
if b.len() > 0x90 { dmx_b12 = Some(g32(b, 0x8C)); }
|
||||||
|
let _ = sess.send_to(&r, src);
|
||||||
|
n_claim += 1;
|
||||||
|
println!(" [{}] ★ AECH 认领质询 → 本地计算 AERE (G({:08x})={:08x}) #{}",
|
||||||
|
chrono_t(start), nonce, crate::aech::agios_g(nonce), n_claim);
|
||||||
|
}
|
||||||
|
} else if sub == 1 {
|
||||||
|
// --- 主机身份宣告 sub=01 (102B) → 89B 注册应答 sub=02 ---
|
||||||
|
// 宣告内: 0x1A-1D 主机IP(LE), 0x1E-23 主机MAC
|
||||||
|
let mut r = reg89_t.clone();
|
||||||
|
let ip_le = [dev_ip[3], dev_ip[2], dev_ip[1], dev_ip[0]];
|
||||||
|
r[0x1A..0x1E].copy_from_slice(&ip_le);
|
||||||
|
r[0x1E..0x24].copy_from_slice(&dev_mac);
|
||||||
|
if b.len() > 0x24 {
|
||||||
|
r[0x25..0x29].copy_from_slice(&b[0x1A..0x1E]); // 主机IP(LE)
|
||||||
|
r[0x29..0x2F].copy_from_slice(&b[0x1E..0x24]); // 主机MAC
|
||||||
|
}
|
||||||
|
let _ = sess.send_to(&r, src);
|
||||||
|
n_reg += 1;
|
||||||
|
if n_reg <= 3 { println!(" [{}] 主机宣告 sub=01 → 回 89B 注册帧", chrono_t(start)); }
|
||||||
|
} else {
|
||||||
|
// --- 已认领心跳 sub=03 (36B, 每~6s): 真机从不应答 (cold2 实证), 静默 ---
|
||||||
|
n_status += 1; // 仅计数
|
||||||
|
}
|
||||||
|
} else if t == 4 && b.len() == 1084 {
|
||||||
|
if g16(b, 0x20) != 0x0101 {
|
||||||
|
event_ctr = event_ctr.wrapping_add(1); // 事件B帧计数 (含 RDM 查询, 42B 遥测用)
|
||||||
|
evt_dst = Some(src);
|
||||||
|
}
|
||||||
|
if g16(b, 0x20) == 0x0101 {
|
||||||
|
n_dmx += 1;
|
||||||
|
// DMX 数据经 zPprv0TXRRW 逐帧混淆 (§4.1): r=0x22-0x25 LE, rot=(B12^r)&511
|
||||||
|
let ch16 = match dmx_b12 {
|
||||||
|
Some(b12) => {
|
||||||
|
let r1 = g32(b, 0x22);
|
||||||
|
let plain = crate::aech::agios_dmx_decrypt(&b[0x3C..0x3C + 512], r1, b12);
|
||||||
|
hexs(&plain[..16])
|
||||||
|
}
|
||||||
|
None => hexs(&b[0x3C..0x3C + 16]), // 未认领前: 原始线值
|
||||||
|
};
|
||||||
|
let mut ch = [0u8; 32];
|
||||||
|
ch.copy_from_slice(&b[0x3C..0x3C + 32]);
|
||||||
|
if first_channels.is_none() { first_channels = Some(ch); }
|
||||||
|
if ch != last_channels { ch_changes += 1; last_channels = ch; }
|
||||||
|
if last_ch_show.elapsed() > Duration::from_secs(5) {
|
||||||
|
last_ch_show = Instant::now();
|
||||||
|
println!(" [{}] DMX #{} CH1-16: {}", chrono_t(start), n_dmx, ch16);
|
||||||
|
}
|
||||||
|
} else if b.len() > 0x44 && b[0x3C] == 0x01 && (b[0x3D] == 0x24 || b[0x3D] == 0x18 || b[0x3D] == 0x19 || b[0x3D] == 0x1a) {
|
||||||
|
// --- RDM 请求 (0x20=0200<seq16>, 0x3C=01, 0x3D=cmd, 0x3E+=目标UID) ---
|
||||||
|
let mut uid = [0u8; 6];
|
||||||
|
uid.copy_from_slice(&b[0x3E..0x44]);
|
||||||
|
// RDM 一律本地生成式应答 (全新UID灯具); relay 仅用于 AECH 认领
|
||||||
|
if rdm_req_dumped < 3 {
|
||||||
|
rdm_req_dumped += 1;
|
||||||
|
let dump_len = std::cmp::min(0x80, b.len());
|
||||||
|
println!(" [RDM-REQ#{}] len={} hex[0..{}]={}", rdm_req_dumped, b.len(), dump_len, hexs(&b[..dump_len]));
|
||||||
|
}
|
||||||
|
if b[0x3D] == 0x19 && rdm_req_dumped < 8 {
|
||||||
|
rdm_req_dumped += 1;
|
||||||
|
let dump_len = std::cmp::min(0x90, b.len());
|
||||||
|
println!(" [RDM-19#{}] len={} hex[0..{}]={}", rdm_req_dumped, b.len(), dump_len, hexs(&b[..dump_len]));
|
||||||
|
}
|
||||||
|
if b[0x30] != 0x00 {
|
||||||
|
// flag=01 = DMX 内嵌副本帧: 真机完全不答, 忽略
|
||||||
|
} else if b[0x3D] == 0x24 {
|
||||||
|
// --- DISC_UNIQUE_BRANCH: 分支范围 lo@0x53-0x58 hi@0x59-0x5E (PID 0001@0x50, PDL=12@0x52) ---
|
||||||
|
// 真机灯具只应答 UID 落在分支范围内的查询 (ss123 实证二分收敛);
|
||||||
|
// 此前无视范围全部应答 → 主机二分水远无法排空分支 → 51/s 发现洪水, 稳态轮询不启动
|
||||||
|
if b.len() > 0x5E {
|
||||||
|
let lo = &b[0x53..0x59]; let hi = &b[0x59..0x5F];
|
||||||
|
for fx in FIXTURES.iter() {
|
||||||
|
if &fx[..] >= lo && &fx[..] <= hi {
|
||||||
|
let pulse = rdm_encode_uid(fx);
|
||||||
|
let mut r: Vec<u8> = Vec::with_capacity(59);
|
||||||
|
r.extend_from_slice(&pulse_ts[0][..0x2A]); // 模板头
|
||||||
|
// 脉冲 seq = 设备本地自增序号 (真机行为, 非回显!)
|
||||||
|
p32(&mut r, 0x20, pulse_seq);
|
||||||
|
pulse_seq = pulse_seq.wrapping_add(pulse_step);
|
||||||
|
pulse_step = 1 + (pulse_step * 7 + 0x1d) % 3; // 每帧 +1..3
|
||||||
|
r.extend_from_slice(&pulse);
|
||||||
|
let due = Instant::now() + Duration::from_millis(next_delay(2, 40));
|
||||||
|
rdm_queue.push((due, r, src));
|
||||||
|
n_rdm_pulse += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if n_rdm_pulse <= 5 || n_rdm_pulse % 100 == 0 {
|
||||||
|
println!(" [RDM] 分支发现范围内应答 #{}", n_rdm_pulse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if b[0x3D] == 0x18 && uid == [0xff; 6] {
|
||||||
|
// 广播 UID 的发现命令 (广播 MUTE 0003 等): 真机不应答, 静默
|
||||||
|
} else if b[0x3D] == 0x18 {
|
||||||
|
// cmd=18 = RDM GET. PID 在 0x50-0x51.
|
||||||
|
// PID=0002 = DISC_UN_MUTE → 70B ACK (CC=11, PDL=2, PD=0000) — 冷启动抓包实证
|
||||||
|
let pid = if b.len() > 0x51 { [b[0x50], b[0x51]] } else { [0, 0] };
|
||||||
|
let mirror = mirror_uid(&uid);
|
||||||
|
// 优先帧池中镜像灯具的同 PID 应答 (GET_RESP=0x21, 数据自洽); 其次 pid_map; 兜底 111
|
||||||
|
let pool_hit = rdm_pool.iter().find(|f|
|
||||||
|
f.len() >= 0x42 && f[0x2A] == 0xCC && f[0x33..0x39] == mirror
|
||||||
|
&& f[0x3E] == 0x21 && f[0x3F] == pid[0] && f[0x40] == pid[1]);
|
||||||
|
let mut r = if let Some(t) = pool_hit {
|
||||||
|
t.clone()
|
||||||
|
} else if let Some(t) = pid_map.get(&pid) {
|
||||||
|
t.clone()
|
||||||
|
} else {
|
||||||
|
rdm111_t.clone()
|
||||||
|
};
|
||||||
|
if r.len() > 0x39 { r[0x33..0x39].copy_from_slice(&uid); } // src UID = 虚拟灯具
|
||||||
|
// dest UID (0x2D-0x32) = 查询方 bridge-id; seq 回显; TN 回显查询 TN(0x4A)
|
||||||
|
if b.len() > 0x4A && r.len() > 0x33 { r[0x2D..0x33].copy_from_slice(&b[0x44..0x4A]); }
|
||||||
|
r[0x20] = b[0x22]; r[0x21] = b[0x23];
|
||||||
|
if b.len() > 0x4B && r.len() > 0x3A { r[0x39] = b[0x4A]; }
|
||||||
|
// SET 过的 PID 回显新值 (真机: SET 立即生效, §5.6)
|
||||||
|
if let Some(v) = set_store.get(&(uid, pid)) {
|
||||||
|
let pdl = if r.len() > 0x41 { r[0x41] as usize } else { 0 };
|
||||||
|
if pdl == v.len() && r.len() >= 0x42 + pdl {
|
||||||
|
r[0x42..0x42 + pdl].copy_from_slice(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rdm_checksum(&mut r); // patch 后必须重算 (真机 1396/1396 有效)
|
||||||
|
let due = Instant::now() + Duration::from_millis(next_delay(15, 25));
|
||||||
|
n_rdm_111 += 1;
|
||||||
|
if n_rdm_111 <= 6 || n_rdm_111 % 100 == 0 {
|
||||||
|
println!(" [RDM] GET UID={:02x}{:02x}{:02x}{:02x}{:02x}{:02x} PID={:02x}{:02x} → {}B",
|
||||||
|
uid[0], uid[1], uid[2], uid[3], uid[4], uid[5], pid[0], pid[1], r.len());
|
||||||
|
}
|
||||||
|
rdm_queue.push((due, r, src));
|
||||||
|
} else if b[0x4F] == 0x30 {
|
||||||
|
// --- RDM SET (CC=0x30, msgLen=0x1a+): 真机回 CC=0x31 ACK, RT=00, PDL=0,
|
||||||
|
// 68B, TN/UID 回显, checksum 有效, 延迟 18-25ms (set123b 实证, §5.6) ---
|
||||||
|
let mut r = setack68_t.clone();
|
||||||
|
if r.len() > 0x39 { r[0x33..0x39].copy_from_slice(&uid); } // src UID = 虚拟灯具
|
||||||
|
if b.len() > 0x4A && r.len() > 0x33 { r[0x2D..0x33].copy_from_slice(&b[0x44..0x4A]); } // dest = 查询方
|
||||||
|
r[0x20] = b[0x22]; r[0x21] = b[0x23]; // seq 回显
|
||||||
|
if b.len() > 0x4B && r.len() > 0x3A { r[0x39] = b[0x4A]; } // TN 回显
|
||||||
|
if b.len() > 0x51 && r.len() > 0x41 { r[0x3F] = b[0x50]; r[0x40] = b[0x51]; } // PID 回显
|
||||||
|
rdm_checksum(&mut r); // patch 后必须重算
|
||||||
|
let due = Instant::now() + Duration::from_millis(next_delay(15, 25));
|
||||||
|
let pid = if b.len() > 0x51 { [b[0x50], b[0x51]] } else { [0, 0] };
|
||||||
|
// 应用写入值 (PDL@0x52, PD@0x53): 后续 GET 同 PID 回显新值 (§5.6 主机验证模式)
|
||||||
|
let pdl = if b.len() > 0x52 { b[0x52] as usize } else { 0 };
|
||||||
|
if pdl > 0 && b.len() >= 0x53 + pdl {
|
||||||
|
set_store.insert((uid, pid), b[0x53..0x53 + pdl].to_vec());
|
||||||
|
}
|
||||||
|
rdm_queue.push((due, r, src));
|
||||||
|
n_rdm_set += 1;
|
||||||
|
if n_rdm_set <= 6 || n_rdm_set % 100 == 0 {
|
||||||
|
println!(" [RDM] SET UID={:02x}{:02x}{:02x}{:02x}{:02x}{:02x} PID={:02x}{:02x} PD={} → 68B ACK #{}",
|
||||||
|
uid[0], uid[1], uid[2], uid[3], uid[4], uid[5], pid[0], pid[1],
|
||||||
|
hexs(set_store.get(&(uid, pid)).map(|v| &v[..]).unwrap_or(&[])), n_rdm_set);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// cmd=19/1a (SET类/传感器轮询 SENSOR_VALUE 0201): PID@0x50, PD@0x53
|
||||||
|
// 按镜像灯具 + PID + PD[0](传感器序号) 从帧池取自恰应答
|
||||||
|
let pid = if b.len() > 0x51 { [b[0x50], b[0x51]] } else { [0, 0] };
|
||||||
|
let pd0 = if b.len() > 0x53 { b[0x53] } else { 0 };
|
||||||
|
let mirror = mirror_uid(&uid);
|
||||||
|
let pool_hit = rdm_pool.iter().find(|f|
|
||||||
|
f.len() >= 0x43 && f[0x2A] == 0xCC && f[0x33..0x39] == mirror
|
||||||
|
&& f[0x3F] == pid[0] && f[0x40] == pid[1] && f[0x42] == pd0);
|
||||||
|
let mut r = if let Some(t) = pool_hit {
|
||||||
|
t.clone()
|
||||||
|
} else {
|
||||||
|
rdm119_t.clone()
|
||||||
|
};
|
||||||
|
if r.len() > 0x39 { r[0x33..0x39].copy_from_slice(&uid); }
|
||||||
|
if b.len() > 0x4A && r.len() > 0x33 { r[0x2D..0x33].copy_from_slice(&b[0x44..0x4A]); }
|
||||||
|
r[0x20] = b[0x22]; r[0x21] = b[0x23];
|
||||||
|
if b.len() > 0x4B && r.len() > 0x3A { r[0x39] = b[0x4A]; }
|
||||||
|
rdm_checksum(&mut r);
|
||||||
|
let due = Instant::now() + Duration::from_millis(next_delay(15, 25));
|
||||||
|
let rlen = r.len();
|
||||||
|
rdm_queue.push((due, r, src));
|
||||||
|
n_rdm_119 += 1;
|
||||||
|
if n_rdm_119 <= 6 || n_rdm_119 % 100 == 0 {
|
||||||
|
println!(" [RDM] 参数/传感器 UID={:02x}{:02x}{:02x}{:02x}{:02x}{:02x} PID={:02x}{:02x} PD0={:02x} → {}B #{}",
|
||||||
|
uid[0], uid[1], uid[2], uid[3], uid[4], uid[5], pid[0], pid[1], pd0, rlen, n_rdm_119);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 非 RDM 事件B帧: 真机只计数, 由 42B 周期遥测上报, 无即时 ACK (ss123 实证)
|
||||||
|
n_evt += 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
n_other += 1;
|
||||||
|
if n_other <= 12 {
|
||||||
|
println!(" [?] 其他帧 src={} len={} type={} hex[0..48]={}", src, b.len(), t, hexs(&b[..std::cmp::min(48, b.len())]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
items.push(Item::new("U1", n_disc > 0, format!("发现应答={} 遥测={} RDM脉冲={} RDM111={} RDM119={}", n_disc, n_status, n_rdm_pulse, n_rdm_111, n_rdm_119)));
|
||||||
|
items.push(Item::new("U2", n_aecha > 0, format!("AECHA 认领交换={} 轮 (AEREP 已回)", n_aecha)));
|
||||||
|
items.push(Item::new("U3", n_dmx > 0, format!("明文 DMX 帧接收={}", n_dmx)));
|
||||||
|
items.push(Item::new("U4", n_ack > 0, format!("事件帧={} ACK发送={}", n_evt, n_ack)));
|
||||||
|
items.push(Item::new("U5", n_dmx > secs * 10, format!(
|
||||||
|
"通道值: 首32CH={:?} 变化={} 其他帧={}", first_channels.unwrap_or([0; 32]), ch_changes, n_other)));
|
||||||
|
items
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- RDM 广播发现重放探测: 向目标重放真机 RDM 广播请求, 抓取并分类应答 ----------
|
||||||
|
pub fn rdm_probe(target: &str, secs: u64) -> Item {
|
||||||
|
let req_t = load_template("rdm_disc_req");
|
||||||
|
let bind = "0.0.0.0:0";
|
||||||
|
let s = UdpSocket::bind(bind).expect("rdmprobe bind 失败");
|
||||||
|
s.set_broadcast(true).unwrap();
|
||||||
|
s.set_read_timeout(Some(Duration::from_millis(120))).unwrap();
|
||||||
|
let dst = format!("{}:31772", target);
|
||||||
|
println!(" rdmprobe → {} 运行 {}s", dst, secs);
|
||||||
|
let start = Instant::now();
|
||||||
|
let mut seq: u32 = 0x090f;
|
||||||
|
let mut sent = 0u64;
|
||||||
|
let mut resp_lens: std::collections::HashMap<usize, u64> = std::collections::HashMap::new();
|
||||||
|
let mut first_resp: Option<Vec<u8>> = None;
|
||||||
|
let mut delays: Vec<u32> = Vec::new();
|
||||||
|
let mut last_send = Instant::now() - Duration::from_secs(10);
|
||||||
|
let mut pending: Option<(Instant, u32)> = None;
|
||||||
|
while start.elapsed().as_secs() < secs {
|
||||||
|
// 每 500ms 发一次请求
|
||||||
|
if last_send.elapsed() > Duration::from_millis(500) {
|
||||||
|
let mut r = req_t.clone();
|
||||||
|
p32(&mut r, 0x20, seq);
|
||||||
|
let _ = s.send_to(&r, &dst);
|
||||||
|
pending = Some((Instant::now(), seq));
|
||||||
|
seq = seq.wrapping_add(1);
|
||||||
|
sent += 1;
|
||||||
|
last_send = Instant::now();
|
||||||
|
}
|
||||||
|
let mut buf = [0u8; 2048];
|
||||||
|
match s.recv_from(&mut buf) {
|
||||||
|
Ok((n, src)) => {
|
||||||
|
let b = &buf[..n].to_vec();
|
||||||
|
*resp_lens.entry(n).or_insert(0) += 1;
|
||||||
|
if first_resp.is_none() { first_resp = Some(b.clone()); }
|
||||||
|
if let Some((t0, sq)) = pending {
|
||||||
|
if n >= 0x22 && g32(b, 4) == 4 {
|
||||||
|
let echo = g16(b, 0x20);
|
||||||
|
let expect = ((sq >> 16) as u16) ^ 0; // seq低16位在0x22
|
||||||
|
let _ = expect;
|
||||||
|
delays.push((t0.elapsed().as_millis() as u32));
|
||||||
|
println!(" [{}] 应答 src={} len={} seqEcho=0x{:04x} (请求seq低16=0x{:04x}) 延迟={}ms",
|
||||||
|
chrono_t(start), src, n, echo, (sq & 0xffff) as u16, t0.elapsed().as_millis());
|
||||||
|
} else {
|
||||||
|
println!(" [{}] 应答 src={} len={} type={}", chrono_t(start), src, n, if n>=8 { g32(b,4) } else { 0 });
|
||||||
|
}
|
||||||
|
pending = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut lens_desc = String::new();
|
||||||
|
let mut keys: Vec<_> = resp_lens.keys().cloned().collect();
|
||||||
|
keys.sort();
|
||||||
|
for k in keys { lens_desc.push_str(&format!(" {}B×{}", k, resp_lens[&k])); }
|
||||||
|
let avg_delay = if delays.is_empty() { 0 } else { delays.iter().sum::<u32>() / delays.len() as u32 };
|
||||||
|
Item::new("RDMP", sent > 0 && !resp_lens.is_empty(),
|
||||||
|
format!("请求={} 应答[{}] 平均延迟={}ms", sent, lens_desc.trim(), avg_delay))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- RDM DISC 脉冲编码 (E1.20) ----------
|
||||||
|
/// 虚拟灯具: 全新 UID (同厂 0107 系列, 主机未注册过的序列号)
|
||||||
|
const FIXTURES: [[u8; 6]; 3] = [
|
||||||
|
[0x01, 0x07, 0x34, 0x67, 0x01, 0x30],
|
||||||
|
[0x01, 0x07, 0x34, 0x67, 0x01, 0x31],
|
||||||
|
[0x01, 0x07, 0x34, 0x67, 0x01, 0x32],
|
||||||
|
];
|
||||||
|
/// 镜像映射: 虚拟 UID → 真机灯具 UID (参数数据按镜像灯具从 rdm_pool 取,
|
||||||
|
/// 使 3 台虚拟灯具拥有各自自洽的 DMX 地址/标签/传感器数, 与 .1 总线同构)
|
||||||
|
const FIXTURE_MIRROR: [[u8; 6]; 3] = [
|
||||||
|
[0x01, 0x07, 0x34, 0x67, 0x01, 0x25], // NFS1K2DxxxBx DMX101-102 23传感器
|
||||||
|
[0x01, 0x07, 0x34, 0x88, 0x09, 0x00], // NFM680SxxxGx DMX111 17传感器
|
||||||
|
[0x08, 0x99, 0x50, 0x00, 0x26, 0xc9], // HMKJ DMX1-32 4传感器
|
||||||
|
];
|
||||||
|
fn mirror_uid(uid: &[u8; 6]) -> [u8; 6] {
|
||||||
|
for (i, f) in FIXTURES.iter().enumerate() {
|
||||||
|
if f == uid { return FIXTURE_MIRROR[i]; }
|
||||||
|
}
|
||||||
|
*uid
|
||||||
|
}
|
||||||
|
|
||||||
|
// E1.20 checksum: 从 CC(0x2A) 起 msgLen(0x2C) 字节的 16-bit 和, BE 写于 [0x2A+msgLen]
|
||||||
|
// (冷启动抓包验证: 真机 1396/1396 全部满足此规则)
|
||||||
|
fn rdm_checksum(r: &mut [u8]) {
|
||||||
|
if r.len() < 0x2E || r[0x2A] != 0xCC { return; }
|
||||||
|
let msg_len = r[0x2C] as usize;
|
||||||
|
if r.len() < 0x2A + msg_len + 2 { return; }
|
||||||
|
let mut sum: u16 = 0;
|
||||||
|
for i in 0x2A..0x2A + msg_len { sum = sum.wrapping_add(r[i] as u16); }
|
||||||
|
r[0x2A + msg_len] = (sum >> 8) as u8;
|
||||||
|
r[0x2A + msg_len + 1] = (sum & 0xFF) as u8;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rdm_encode_uid(uid: &[u8; 6]) -> [u8; 17] {
|
||||||
|
let mut out = [0u8; 17];
|
||||||
|
out[0] = 0xAA; // 分隔符
|
||||||
|
let mut sum: u16 = 0;
|
||||||
|
for (i, &b) in uid.iter().enumerate() {
|
||||||
|
let b1 = 0xAA | (b & 0x55);
|
||||||
|
let b2 = 0x55 | (b & 0xAA);
|
||||||
|
out[1 + 2 * i] = b1;
|
||||||
|
out[2 + 2 * i] = b2;
|
||||||
|
sum += b1 as u16 + b2 as u16;
|
||||||
|
}
|
||||||
|
let hi = (sum >> 8) as u8;
|
||||||
|
let lo = (sum & 0xFF) as u8;
|
||||||
|
out[13] = 0xAA | (hi & 0x55);
|
||||||
|
out[14] = 0x55 | (hi & 0xAA);
|
||||||
|
out[15] = 0xAA | (lo & 0x55);
|
||||||
|
out[16] = 0x55 | (lo & 0xAA);
|
||||||
|
out
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- 259 应答的 Connected To 动态化: 从发现请求提取请求方主机 IP+MAC ----------
|
||||||
|
fn patch_259_host(r: &mut [u8], src: std::net::SocketAddr, req: &[u8]) {
|
||||||
|
if let std::net::IpAddr::V4(v4) = src.ip() {
|
||||||
|
let o = v4.octets();
|
||||||
|
let ip_le = [o[3], o[2], o[1], o[0]];
|
||||||
|
// host IP (0x4F-0x52) = 请求方 IP (LE)
|
||||||
|
if r.len() > 0x53 { r[0x4F..0x53].copy_from_slice(&ip_le); }
|
||||||
|
// host MAC (0x53-0x58): 请求里 hostIP(LE) 后 +8 处 (IP4 + 00ffffff掩码 + MAC6)
|
||||||
|
for i in 0..req.len().saturating_sub(14) {
|
||||||
|
if req[i..i + 4] == ip_le && req[i + 4..i + 8] == [0x00, 0xff, 0xff, 0xff] {
|
||||||
|
if r.len() > 0x59 { r[0x53..0x59].copy_from_slice(&req[i + 8..i + 14]); }
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- bridge: AECH 双向桥 (非123网段设备的认领桥) ----------
|
||||||
|
// 监听 listen_ip:listen_port 收远端设备的 AECH, 以源 IP=123.113 转发给真机, 再把真机 AERE 回传给远端设备
|
||||||
|
pub fn bridge(listen_ip: [u8; 4], listen_port: u16, real_ip: [u8; 4], secs: u64) {
|
||||||
|
let listen_addr = format!("{}.{}.{}.{}:{}", listen_ip[0], listen_ip[1], listen_ip[2], listen_ip[3], listen_port);
|
||||||
|
let listen = open_reuse(&listen_addr);
|
||||||
|
let to_real = open_reuse("192.168.123.113:0"); // 源=113, 真机才应答
|
||||||
|
let real_addr = format!("{}.{}.{}.{}:31772", real_ip[0], real_ip[1], real_ip[2], real_ip[3]);
|
||||||
|
println!(" AECH 桥 @ {} ↔ {} (真机源 123.113)", listen_addr, real_addr);
|
||||||
|
let mut pending: Option<std::net::SocketAddr> = None;
|
||||||
|
let start = Instant::now();
|
||||||
|
let mut n_fwd = 0u64; let mut n_back = 0u64;
|
||||||
|
while start.elapsed().as_secs() < secs {
|
||||||
|
let mut buf = [0u8; 2048];
|
||||||
|
// 远端设备 -> 真机 (AECH)
|
||||||
|
if let Ok((n, src)) = listen.recv_from(&mut buf) {
|
||||||
|
let b = &buf[..n];
|
||||||
|
if b.len() >= 8 && &b[0..4] == b"ENet" && g32(b, 4) == 2 && find(b, b"AECH") {
|
||||||
|
pending = Some(src);
|
||||||
|
let _ = to_real.send_to(b, &real_addr);
|
||||||
|
n_fwd += 1;
|
||||||
|
println!(" [{}] 桥: {} → 真机 (AECH #{})", chrono_t(start), src, n_fwd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 真机 -> 远端设备 (AERE)
|
||||||
|
if let Ok((n, src)) = to_real.recv_from(&mut buf) {
|
||||||
|
let b = &buf[..n];
|
||||||
|
if b.len() >= 8 && &b[0..4] == b"ENet" && g32(b, 4) == 2 {
|
||||||
|
if let Some(p) = pending {
|
||||||
|
let _ = listen.send_to(b, p);
|
||||||
|
n_back += 1;
|
||||||
|
println!(" [{}] 桥: 真机 → {} (AERE #{})", chrono_t(start), p, n_back);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn chrono_t(start: Instant) -> String { format!("{:.1}s", start.elapsed().as_secs_f64()) }
|
||||||
|
|
||||||
|
fn patch_dev(b: &mut [u8], ip: [u8; 4], mac: [u8; 6]) {
|
||||||
|
// 找 Butler IP LE (01 7b a8 c0) 替换 — 字段为小端存储: 192.168.123.200 → c8 7b a8 c0
|
||||||
|
for i in 0..b.len().saturating_sub(4) {
|
||||||
|
if b[i] == 0x01 && b[i + 1] == 0x7b && b[i + 2] == 0xa8 && b[i + 3] == 0xc0 {
|
||||||
|
b[i] = ip[3]; b[i + 1] = ip[2]; b[i + 2] = ip[1]; b[i + 3] = ip[0];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 找 Butler MAC 替换
|
||||||
|
for i in 0..b.len().saturating_sub(6) {
|
||||||
|
if b[i] == 0x00 && b[i + 1] == 0x16 && b[i + 2] == 0x1c && b[i + 3] == 0xf1 && b[i + 4] == 0x2e && b[i + 5] == 0x39 {
|
||||||
|
b[i..i + 6].copy_from_slice(&mac);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- T10/T11: RDM 探索 ----------
|
||||||
|
pub fn t10_t11_rdm(secs: u64) -> Vec<Item> {
|
||||||
|
let mut items = Vec::new();
|
||||||
|
let s = open();
|
||||||
|
let req = load_template("rdm_req");
|
||||||
|
// T10: 发送 RDM 请求事件帧模板 (DISC 帧), 解析 Butler RDM 应答
|
||||||
|
println!(" 发送 RDM 请求模板帧并监听 {}s…", secs);
|
||||||
|
let deadline = Instant::now() + Duration::from_secs(secs);
|
||||||
|
let mut uids: HashSet<String> = HashSet::new();
|
||||||
|
let mut rdm_n = 0u64;
|
||||||
|
let mut disc_n = 0u64;
|
||||||
|
let mut req_seq = g32(&req, 0x22);
|
||||||
|
while Instant::now() < deadline {
|
||||||
|
let mut r = req.clone();
|
||||||
|
p32(&mut r, 0x22, req_seq);
|
||||||
|
req_seq = req_seq.wrapping_add(1);
|
||||||
|
let _ = s.send_to(&r, BUTLER);
|
||||||
|
for (_, b) in recv_window(&s, Duration::from_millis(60)) {
|
||||||
|
match classify(&b) {
|
||||||
|
Rx::RdmResp(_, rlen) => {
|
||||||
|
rdm_n += 1;
|
||||||
|
if rlen >= 17 && b[0x2A] == 0xAA { disc_n += 1; } // 发现脉冲
|
||||||
|
if rlen >= 18 && b[0x2A] == 0xCC {
|
||||||
|
let uid = hexs(&b[0x32..0x38]);
|
||||||
|
uids.insert(uid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
items.push(Item::new("T10", rdm_n > 0,
|
||||||
|
format!("RDM应答={} (发现脉冲={}, 设备UID={})", rdm_n, disc_n,
|
||||||
|
uids.iter().cloned().collect::<Vec<_>>().join(" "))));
|
||||||
|
// T11: 写地址 (PID 0x0330) —— e:cue 私有封装下 PID 未知, 仅记录探索结论
|
||||||
|
items.push(Item::new("T11", false,
|
||||||
|
"写地址 SET DMX_START_ADDRESS: e:net 私有 PID 未确认, 需结合 GUI 写地址抓包比对 (见文档 §5.4)".to_string()));
|
||||||
|
items
|
||||||
|
}
|
||||||
10
validation_report.json
Normal file
10
validation_report.json
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"target": "192.168.123.1",
|
||||||
|
"results": [
|
||||||
|
{ "id": "U1", "pass": true, "detail": "发现应答=6898 遥测=19980 RDM脉冲=0 RDM111=0 RDM119=0" },
|
||||||
|
{ "id": "U2", "pass": false, "detail": "AECHA 认领交换=0 轮 (AEREP 已回)" },
|
||||||
|
{ "id": "U3", "pass": true, "detail": "明文 DMX 帧接收=18958" },
|
||||||
|
{ "id": "U4", "pass": false, "detail": "事件帧=0 ACK发送=0" },
|
||||||
|
{ "id": "U5", "pass": false, "detail": "通道值: 首32CH=[45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14] 变化=18897 其他帧=2329" }
|
||||||
|
]
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user