tm: full frame Wire codec — eliminate all manual byte-picking
Replace the split header-codec + manual-byte-picking architecture
with a single frame_codec that covers header + data + OCF + FECF
in one Wire.Codec definition.
The frame codec uses:
- Wire.Param.input for frame_len (total frame length, mission
config) and expect_fecf (FECF presence)
- Wire.Expr arithmetic for data_size: frame_len - 6 - 4*ocf_flag
- 2*expect_fecf
- Wire.optional with Wire.Expr.(Field.ref w_ocf_flag_int <> int 0)
for the OCF field — present when the header's ocf_flag bit is set
- Wire.optional with Param.expr for the FECF field
- Wire.byte_array ~size:data_size for the variable-length data
This is the first use of Wire's dynamic optional (Field.ref in a
bool expr) and Param.input in a Codec, enabled by the recent
ocaml-wire fixes.
Removed:
- get_u8, get_u16_be, get_u32_be, set_u8, set_u16_be, set_u32_be
manual byte helpers
- split_data_zone (the codec handles OCF/FECF structurally)
- packed_frame_of_packed_header (no longer needed)
Changed:
- packed_frame.pf_ocf_flag: bool -> int (0/1) for Wire.Field.ref
- packed_frame: data_zone: string replaced by pf_data + pf_ocf + pf_fecf
- decode_packed_frame/encode_packed_frame: now take ~frame_len and
~expect_fecf params
Kept:
- Header-only codec unchanged (for EverParse 3D, field-level access)
- FECF CRC fixup after encoding (Bytes.set_uint16_be — protocol
logic, not format parsing)
All 19 unit + 3 interop + 6 fuzz tests pass.