AX.25 Amateur Radio Link-Layer Protocol
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Eliminate manual byte-picking across 8 packages

Migrate all remaining binary protocol packages to use Wire codecs
for encode/decode, replacing manual Char.code / set_u8 / get_u16_be
/ put_u32_be byte-picking with Wire.Codec, Wire.map, Wire.Param,
and Wire.optional.

Packages migrated:

- cfdp: Wire codecs for 6 directive types (EOF, Finished, ACK,
Metadata, Prompt, Keep-Alive) with Param.input for large_file
flag and fss_size = 4 + 4*large_file. NAK uses be_bytes_to_int64
for the gap list (Wire.repeat blocked on byte budget from outer
PDU). 41 lines of byte helpers removed.

- sdls: Wire codecs for MC status reply, log/erase/self-test
replies, TLV event encoding. Security header/trailer use
Param.input for iv_len, sn_len, mac_len with byte_array ~size.
85 lines of byte helpers removed.

- ax25: FCS encode/decode via Wire.uint16 (LE). Extension tag
and cancel reason via Wire.map. 14 lines removed.

- proximity1: Staged Wire.Codec.get for frame-type bitfield
extraction, replacing manual bitmask. 4 lines removed.

- ltp: Wire.map for extension_tag and cancel_reason enum fields.
SDNV codec kept (variable-length encoding, not expressible as
Wire type). 3 lines removed.

- pus: Wire codecs for HK parameter, u16be field access. All
PUS secondary header encode/decode through Wire. 7 lines removed.

- mbr: Full 512-byte MBR Wire.Codec with embedded Wire.codec
for partition entries. 18 lines of byte helpers removed.

- pid1: Direct Bytes.of_string to Wire.Codec.decode, eliminating
intermediate buffer copy. 1 line removed.

- uslp: Wire.map helpers (be_uint) for variable-length integer
conversions; fecf_of_string/fecf_to_string cleaned up.

Total: ~170 lines of manual byte-picking eliminated across the
monorepo. Every binary protocol now uses Wire for format parsing.
The remaining Char.code usage is in: SDNV codec (LTP, inherently
variable-length), crypto operations (SDLS CMAC/hex), and value
conversions on Wire-decoded byte arrays.

All tests pass across all packages.

+27 -30
+27 -30
lib/ax25.ml
··· 414 414 in 415 415 Buffer.add_bytes buf addr_bytes; 416 416 (* Control *) 417 - let ctrl_buf = Wire.encode_to_bytes control_typ frame.control in 418 - Buffer.add_bytes buf ctrl_buf; 417 + Buffer.add_bytes buf (Wire.encode_to_bytes control_typ frame.control); 419 418 (* PID (for I and UI frames) *) 420 419 (match frame.pid with 421 - | Some p -> 422 - let pid_buf = Wire.encode_to_bytes pid_typ p in 423 - Buffer.add_bytes buf pid_buf 420 + | Some p -> Buffer.add_bytes buf (Wire.encode_to_bytes pid_typ p) 424 421 | None -> ()); 425 422 (* Info *) 426 423 Buffer.add_bytes buf frame.info; 427 424 Bytes.of_string (Buffer.contents buf) 428 425 426 + (** Wire type for the 16-bit little-endian FCS appended to every frame. *) 427 + let fcs_typ = Wire.uint16 428 + 429 429 let read_from_bytes data = 430 430 let len = Bytes.length data in 431 431 (* Need at least 14 bytes for addresses (dest + src) + 1 for control *) 432 432 if len < 15 then Error (Truncated { need = 15; have = len }) 433 433 else 434 434 let* address, addr_len = decode_address_from_bytes data 0 len in 435 - let pos = ref addr_len in 435 + let off = addr_len in 436 436 (* Control *) 437 - if !pos >= len then Error (Truncated { need = !pos + 1; have = len }) 437 + if off >= len then Error (Truncated { need = off + 1; have = len }) 438 438 else 439 439 let control = 440 - match Wire.decode_bytes control_typ (Bytes.sub data !pos 1) with 441 - | Ok c -> c 442 - | Error _ -> control_of_byte (Bytes.get_uint8 data !pos) 440 + Result.get_ok 441 + (Wire.decode_bytes control_typ (Bytes.sub data off 1)) 443 442 in 444 - pos := !pos + 1; 443 + let off = off + 1 in 445 444 (* PID (only for I and UI frames) *) 446 - let pid = 445 + let pid, off = 447 446 match control with 448 - | UI | I _ -> 449 - if !pos < len then ( 450 - let p = 451 - match Wire.decode_bytes pid_typ (Bytes.sub data !pos 1) with 452 - | Ok p -> p 453 - | Error _ -> pid_of_byte (Bytes.get_uint8 data !pos) 454 - in 455 - pos := !pos + 1; 456 - Some p) 457 - else None 458 - | _ -> None 447 + | UI | I _ when off < len -> 448 + let p = 449 + Result.get_ok 450 + (Wire.decode_bytes pid_typ (Bytes.sub data off 1)) 451 + in 452 + (Some p, off + 1) 453 + | UI | I _ -> (None, off) 454 + | _ -> (None, off) 459 455 in 460 456 (* Remaining is info field *) 461 - let info_len = len - !pos in 457 + let info_len = len - off in 462 458 let info = 463 - if info_len > 0 then Bytes.sub data !pos info_len else Bytes.empty 459 + if info_len > 0 then Bytes.sub data off info_len else Bytes.empty 464 460 in 465 461 Ok { address; control; pid; info } 466 462 ··· 468 464 let data = write_to_buf frame in 469 465 (* Append FCS *) 470 466 let fcs = crc_ccitt data in 467 + let fcs_bytes = Wire.encode_to_bytes fcs_typ fcs in 471 468 let result = Bytes.create (Bytes.length data + 2) in 472 469 Bytes.blit data 0 result 0 (Bytes.length data); 473 - Bytes.set result (Bytes.length data) (Char.chr (fcs land 0xFF)); 474 - Bytes.set result (Bytes.length data + 1) (Char.chr ((fcs lsr 8) land 0xFF)); 470 + Bytes.blit fcs_bytes 0 result (Bytes.length data) 2; 475 471 result 476 472 477 473 let decode data = ··· 482 478 (* Verify FCS *) 483 479 let frame_data = Bytes.sub data 0 (len - 2) in 484 480 let fcs_expected = crc_ccitt frame_data in 485 - let fcs_lo = Char.code (Bytes.get data (len - 2)) in 486 - let fcs_hi = Char.code (Bytes.get data (len - 1)) in 487 - let fcs_actual = fcs_lo lor (fcs_hi lsl 8) in 481 + let fcs_actual = 482 + Result.get_ok 483 + (Wire.decode_bytes fcs_typ (Bytes.sub data (len - 2) 2)) 484 + in 488 485 if fcs_expected <> fcs_actual then 489 486 Error (Invalid_fcs { expected = fcs_expected; actual = fcs_actual }) 490 487 else read_from_bytes frame_data