bds 代码验证
- 作者仓库星标 43
- 许可证 GPL-3.0
- 作者仓库 flightjar
Porting a pyModeS BDS register to FlightJar
FlightJar's Comm-B decoder matches pyModeS 3.x byte-for-byte. When adding another register, keep the wire behaviour identical so we can cross-check golden vectors from pyModeS's own test corpus. Every deviation (even a "cleanup") is a source of silent drift later.
Touchpoints
A full port spans six files and one frontend + one docs update:
dotnet/src/FlightJar.Decoder/ModeS/CommB.cs— addIsBdsXX(payload)validator +DecodeBdsXX(payload)decoder +BdsXXDatarecord. Extend theCandidatesrecord andInfer()to include the new register.dotnet/src/FlightJar.Decoder/ModeS/DecodedMessage.cs— add one field per value the register exposes.dotnet/src/FlightJar.Decoder/ModeS/MessageDecoder.cs— add a branch inInferCommBthat builds aDecodedMessagefor the new register; extendMerge()to copy the new fields.dotnet/src/FlightJar.Core/State/Aircraft.cs— add per-field state + oneBdsXXAttimestamp.dotnet/src/FlightJar.Core/State/AircraftRegistry.cs— add acase "X,Y":branch inApplyCommBthat writes the fields + stamps the timestamp. ExtendBuildCommBSnapshotto gate the fields on freshness and feed theSnapshotCommBrecord.dotnet/src/FlightJar.Core/State/RegistrySnapshot.cs— add the fields toSnapshotCommB(nullable, snake-case on the wire).app/static/detail_panel.js— add metric tiles to the.panel-met-gridplaceholder markup inbuildPopupContentand aset('.pop-met-xxx', …)call per field inrenderCommBSection.dotnet/tests/FlightJar.Decoder.Tests/ModeS/CommBTests.cs— validator accept/reject tests + golden-vector decoder tests using hex captures from pyModeS'stests/test_bds_commb.py.README.md— add the new fields to the "Enhanced Mode S air data" bullet and flag any register-specific caveats.CLAUDE.md— update the decoder list + any behavioural nuances.
Step 1 — Fetch the pyModeS reference
pyModeS lives at junzis/pyModeS on GitHub (default branch main).
BDS decoders live under src/pyModeS/decoder/bds/bdsXX.py, helpers
under _helpers.py. Fetch into /tmp/pymodes/ via the GitHub API
(the raw CDN sometimes 404s; the contents API is reliable):
# List available registers.
curl -sL "https://api.github.com/repos/junzis/pyModeS/contents/src/pyModeS/decoder/bds?ref=main" \
| grep '"download_url"'
# Fetch a specific register + the shared helpers.
for f in bds45 _helpers _infer; do
curl -sL "https://raw.githubusercontent.com/junzis/pyModeS/main/src/pyModeS/decoder/bds/$f.py" \
> /tmp/pymodes/$f.py
done
# And the golden-vector test corpus.
curl -sL "https://raw.githubusercontent.com/junzis/pyModeS/main/tests/test_bds_commb.py" \
> /tmp/pymodes/test_bds_commb.py
Step 2 — Port the validator + decoder
pyModeS operates on a 56-bit payload as a Python int with (payload >> (55 - i)) & mask
indexing (MSB-first from payload bit 0). The C# port keeps identical
bit indexing so the ported arithmetic reads one-to-one next to the Python.
Add your new methods inside public static class CommB in CommB.cs.
Use the existing helpers that are already in CommB.cs:
WrongStatus(payload, statusBit, valueStart, valueWidth)— mirrors pyModeS_helpers.wrong_status(status-bit / value-field consistency).Signed(value, width, sign)— sign-magnitude to signed int (NOT two's complement; Mode S splits sign + magnitude bits).NormaliseAngle(deg)— wrap into[0, 360).
Every range gate in IsBdsXX must match pyModeS's validator. If pyModeS
rejects > 600 kt but you port it as >= 600, you will silently accept
values pyModeS would reject.
Step 3 — Wire into inference
CommB.Infer(payload) returns a Candidates record with one bool per
heuristic register. MessageDecoder.InferCommB(msg) returns a decoded
message only when exactly one candidate validates. This single-match
discipline is intentional: multi-match payloads are ambiguous and
dropped rather than risk polluting aircraft state with fields decoded
against the wrong register. Do not relax it without a replacement
disambiguation strategy (e.g. pyModeS Phase 3 known-state scoring).
BDS 4,5 (meteorological hazard) is opt-in in pyModeS because it
false-positives on non-meteorological payloads. When porting, keep
the validator strict; if ambiguity becomes a problem, add a
Candidates.Bds45 branch behind a config flag rather than unconditionally
accepting it.
Step 4 — Extend state + snapshot
For every decoded field:
- Add a nullable property to
Aircraft(e.g.public int? WindshearLevel { get; set; }). - Add an identically-named property to
SnapshotCommB. - In
ApplyCommB, add acase "X,Y":that assigns from theDecodedMessage; do not touch fields from other registers (each register owns its own slice of state). - In
BuildCommBSnapshot, compute abdsXXFreshflag usingCommBMaxAge(120 s) and use it to gate every field from the register. Include the register'sBdsXXAttimestamp on the snapshot so the frontend can age values out independently.
Naming convention on the wire: snake_case via the global serializer
config in FlightJar.Api.Configuration. MagneticHeadingDeg becomes
magnetic_heading_deg without any extra attributes.
Step 5 — Extend the frontend panel
The Enhanced Mode S panel is driven entirely by a.comm_b in the
snapshot. In detail_panel.js:
- Add placeholder tile markup inside
.panel-met-gridinbuildPopupContent— same shape as existing tiles (<div class="metric pop-met-xxx" hidden><div class="label">…</div><div class="val"></div></div>). - Add a
set('.pop-met-xxx', value)call inrenderCommBSectionthat computes the formatted string or returnsnullto hide the tile.
Use the existing uconv('alt' | 'spd' | 'vrt' | 'dst', value) helper
for unit-system-aware formatting. Raw-unit values (Mach, temperature,
degrees, percent) format inline.
Step 6 — Tests
CommBTests.cs follows two patterns; use both for the new register:
- Validator acceptance + rejection: pick a golden-vector hex
from pyModeS's
test_bds_commb.py, assertIsBdsXXaccepts it, then construct synthetic payloads that should be rejected (all zeros, out-of-range values, status-bit / value-bit inconsistency) and assert they're rejected. - Decode golden vector: decode the pyModeS golden hex and
assert each field matches the pyModeS oracle value to within the
same
abs=tolerance the pyModeS test uses.
Also add an end-to-end test in MessageDecoder_RoutesUnambiguousBdsXXOnDf20
to prove the InferCommB branch wires through.
Step 7 — Add an integration test
dotnet/tests/FlightJar.Core.Tests/State/AircraftRegistryTests.cs +
FakeDecoder.cs use fake hex keys (BD44 → pre-built DecodedMessage)
to exercise ApplyCommB + BuildCommBSnapshot without real wire
bytes. Add a BDxx fixture and a test proving the new field lands
in the snapshot and ages out correctly past CommBMaxAge.
Step 8 — Playwright smoke (optional)
The detail panel renders Enhanced Mode S section when comm_b is present
test in tests/e2e/layout.spec.js injects a fake snapshot with a full
comm_b block. If the new register adds a user-visible tile, extend the
fixture and assert the new label appears.
Step 9 — Verify
cd dotnet && dotnet format FlightJar.slnx --verify-no-changes
dotnet build FlightJar.slnx
dotnet test FlightJar.slnx
cd ..
node --test tests/js/
npx playwright test
All five must pass before the port is done. Formatter drift and Playwright regressions are the two most common surprises.
Do not
- Do not rename pyModeS's field names in the decoded record unless
you have a codebase-wide reason.
static_air_temperaturein pyModeS isStaticAirTemperatureCinCommB.cs— theCsuffix is the only concession, and it's there because our wire convention suffixes every physical-unit field. - Do not persist Comm-B state in
state.json.gz. The 120 s freshness window is far shorter than the 30 s persist cadence + 10 minPersistMaxAge, so restored Comm-B values would be stale on load. - Do not bypass
CommB.Infer's single-match gate by eagerly decoding every register. Multi-match payloads mean one of the decodes is wrong; you cannot tell which without an external reference signal, so dropping ambiguous payloads is the safe default. - Do not add register-specific env vars for opt-in registers without
updating
README.md's configuration reference table.
- 流狐分类
- 文档
- 作者声明 Agent
- 未找到明确声明;不据此推断已兼容或已测试
- 静态检查
- 94 / 100 · 启发式扫描,不代表运行安全
- 作者 / 版本 / 许可
- @MrSuttonmann · GPL-3.0
- 流狐 Token 估算
- 低消耗
- 流狐接入估算
- 需简单配置
- 是否需要外部 API Key
- 未发现要求
- 检测到的系统要求
- macOS · Linux · Windows
- 底层运行要求
- Node.js · Python
- 检测到的文件与系统行为
-
- 只读
- 允许写入 / 修改
- 读取环境变量
- 检测到的网络行为
- 允许外网请求
- 安装命令数
- 无(仅作为资料)
档案由构建时根据 SKILL.md 与安装命令自动衍生,可能与作者实际意图存在差异。
需要注意: 未限定 allowed-tools,默认拥有全部工具权限。
作者没有在当前 SKILL.md 中定义固定输出样例。 pyModeS lives at junzis/pyModeS on GitHub (default branch main). BDS decoders live under src/pyModeS/decoder/bds/bdsXX.py, helpers under helpers.py. Fetch into /tmp/pymodes/ via the GitHub API
pyModeS operates on a 56-bit payload as a Python int with (payload >> (55 - i)) & mask indexing (MSB-first from payload bit 0). The C port keeps identical bit indexing so the ported arithmetic reads one-to-one next to the Python.
CommB.Infer(payload) returns a Candidates record with one bool per heuristic register. MessageDecoder.InferCommB(msg) returns a decoded message only when exactly one candidate validates. This single-match
For every decoded field: Add a nullable property to Aircraft (e.g. public int? WindshearLevel { get; set; }). Add an identically-named property to SnapshotCommB.
The Enhanced Mode S panel is driven entirely by a.commb in the snapshot. In detailpanel.js: Add placeholder tile markup inside .panel-met-grid in
CommBTests.cs follows two patterns; use both for the new register: Validator acceptance + rejection: pick a golden-vector hex from pyModeS's testbdscommb.py, assert IsBdsXX accepts it,
# Porting a pyModeS BDS register to FlightJar
FlightJar's Comm-B decoder matches pyModeS 3.x byte-for-byte. When adding
another register, keep the wire behaviour identical so we can cross-check
golden vectors from pyModeS's own test corpus. Every deviation (even a
"cleanup") is a source of silent drift later.
## Touchpoints
A full port spans six files and one frontend + one docs update:
1. **`dotnet/src/FlightJar.Decoder/ModeS/CommB.cs`** — add
`IsBdsXX(payload)` validator + `DecodeBdsXX(payload)` decoder +
`BdsXXData` record. Extend the `Candidates` record and `Infer()` to
include the new register.
2. **`dotnet/src/FlightJar.Decoder/ModeS/DecodedMessage.cs`** — add
one field per value the register exposes.
3. **`dotnet/src/FlightJar.Decoder/ModeS/MessageDecoder.cs`** — add a
branch in `InferCommB` that builds a `DecodedMessage` for the new
register; extend `Merge()` to copy the new fields.
4. **`dotnet/src/FlightJar.Core/State/Aircraft.cs`** — add per-field
state + one `BdsXXAt` timestamp.
5. **`dotnet/src/FlightJar.Core/State/AircraftRegistry.cs`** — add a
`case "X,Y":` branch in `ApplyCommB` that writes the fields +
stamps the timestamp. Extend `BuildCommBSnapshot` to gate the
fields on freshness and feed the `SnapshotCommB` record.
6. **`dotnet/src/FlightJar.Core/State/RegistrySnapshot.cs`** — add
the fields to `SnapshotCommB` (nullable, snake-case on the wire).
7. **`app/static/detail_panel.js`** — add metric tiles to the
`.panel-met-grid` placeholder markup in `buildPopupContent` and
a `set('.pop-met-xxx', …)` call per field in `renderCommBSection`.
8. **`dotnet/tests/FlightJar.Decoder.Tests/ModeS/CommBTests.cs`** —
validator accept/reject tests + golden-vector decoder tests using
… 作者原文负责流程事实;流狐只索引当前章节、要点、文件与命令。
章节 -> Touchpoints → Step 1 — Fetch the pyModeS reference → Step 2 — Port the validator + decoder → Step 3 — Wire into inference → Step 4 — Extend state + snapshot → Step 5 — Extend the frontend panel
要点 -> dotnet/src/FlightJar.Decoder/ModeS/CommB.cs · dotnet/src/FlightJar.Decoder/ModeS/DecodedMessage.cs · dotnet/src/FlightJar.Decoder/ModeS/MessageDecoder.cs · dotnet/src/FlightJar.Core/State/Aircraft.cs · dotnet/src/FlightJar.Core/State/AircraftRegistry.cs · dotnet/src/FlightJar.Core/State/RegistrySnapshot.cs · app/static/detailpanel.js · dotnet/tests/FlightJar.Decoder.Tests/ModeS/CommBTests.cs
文件/命令 -> dotnet/src/FlightJar.Decoder/ModeS/CommB.cs · IsBdsXX(payload) · DecodeBdsXX(payload) · BdsXXData · Candidates · Infer() · dotnet/src/FlightJar.Decoder/ModeS/DecodedMessage.cs · dotnet/src/FlightJar.Decoder/ModeS/MessageDecoder.cs
内容 SHA-256 -> 810e1dbb1261
方法与流程
适用与边界
原文中的明确线索
dotnet/src/FlightJar.Decoder/ModeS/CommB.cs、IsBdsXX(payload)、DecodeBdsXX(payload)、BdsXXData、Candidates、Infer()、dotnet/src/FlightJar.Decoder/ModeS/DecodedMessage.cs、dotnet/src/FlightJar.Decoder/ModeS/MessageDecoder.cs