Adds 6 vendor parsers under codec/parser/vendor/guangdong/ implementing the
Guangdong "燃料电池汽车数据接入技术规范 v1.0" extension typeCodes that the
city's data ingestion platform sends inside V2016 frames:
0x30 GdFcStackBlockParser §7.2.3.4 表 13/14 fuel-cell stack
0x31 GdFcAuxiliaryBlockParser §7.2.3.5 表 15/16 auxiliary system
0x32 GdFcDcDcBlockParser §7.2.3.6 表 17 DC/DC
0x33 GdFcAirConditionerBlockParser §7.2.3.7 表 18 air conditioner
0x34 GdFcVehicleInfoBlockParser §7.2.3.8 表 19 vehicle info
0x80 GdFcDemoExtensionBlockParser §7.2.3.14 表 27 demo data extension
Each parser uses ProtocolVersion.V2016 + its respective typeCode and is
strictly Guangdong-spec layout, not the GB/T 32960.3-2025 fuel-cell stack
layout (the two share typeCode 0x30 but have different field orders and
extra cell-voltage statistics in the Guangdong variant).
Field model in InfoBlock.java gains:
- GdFcStack(stackCount, stacks: Stack(workState, waterTempC,
h2InletPressureKpa, airInletPressureKpa, airInletTempC, max/min/avg cell
voltage ids and values, cellCount, frameCellStart, frameCellCount,
frameCellVoltagesV))
- GdFcAuxiliary(subSystemCount, subsystems: Subsystem with air compressor,
hydrogen pump, water pump, PTC, low-voltage battery)
- GdFcDcDc, GdFcAirConditioner, GdFcVehicleInfo, GdFcDemoExtension
InfoBlockType enum gains the matching GD_FC_* constants.
Tests:
- GdFcParserTest covers the 4 fixed-length parsers (0x32/0x33/0x34/0x80)
with hand-crafted bytes asserting field-by-field decoded values.
- 0x30/0x31 are variable-length and will be exercised end-to-end via the
body parser integration test in a follow-up.
Spec doc: adds reference/广东燃料电池汽车示范应用城市群综合监管平台-...pdf
(v1.0.220822) used as the source of truth for these parsers.
These parsers exist as classes only; no Spring beans are wired yet.
Wiring + decoder context plumbing land in the next commit.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds a per-context routing layer for InfoBlock parsers, so different
peers can be routed to different parser sets (e.g. standard GB/T 32960
vs. a vendor extension that adds blocks in the 0x30~0x7F reserved range).
New types in protocol-gb32960:
- Gb32960ParserContext (record): version + vin + platformAccount tuple
- codec/profile/VendorExtensionCatalog: name -> list of vendor parsers
- codec/profile/Gb32960ProfileRegistry: name -> InfoBlockParserRegistry,
with a default registry built from the standard parsers and one extra
registry per enabled vendor extension (default + vendor parsers)
- codec/profile/VendorExtensionSelector: interface returning the matching
extension name (or null) for a given context
- codec/profile/RuleBasedVendorExtensionSelector: top-down first-match
scan over Gb32960Properties.vendorExtensions with a (account,vin)
cache keyed on case-insensitive normalized form
Gb32960Properties gains a `vendorExtensions` list with per-entry
`name` + `match` (platformAccounts / vins / vinPrefixes). All matching
fields are OR'd within an entry; entries are scanned top-down with
first-match-wins as documented.
Gb32960BodyParser keeps its legacy single-registry constructor for
back-compat (used by existing tests) and adds a new constructor that
takes the profile registry + selector. The parse loop now lives under
parse(Gb32960ParserContext, ByteBuffer); the legacy parse(version,body)
delegates to it with a minimal context (selector returns null -> default).
This commit only introduces the framework. Vendor parsers, autoconfig
wiring, and decoder/handler context plumbing land in follow-ups.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Captures the themed work that was rolled into the initial import commit
(login-ack time fix, idle handler, parser package split, removal of the
non-standard V2016 0x30 fuel cell stack registration, body-dump diagnostic
enhancement) so the history exists somewhere even though git can't carry
the per-theme commits.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>