CCSDS Synchronization and Channel Coding (131.0-B, 231.0-B)
0
fork

Configure Feed

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

Remove self-test interop tests (COP-1, SCC, TCF)

These used pure Python generators (struct.pack, manual bitfield
encoding) that reimplemented the spec — not independent oracles.

Per interop-testing skill: "The generator MUST call the upstream
tool's public API. Never reimplement, transcribe, or inline."

A Python script that packs the same bits our OCaml code does
validates nothing about cross-implementation compatibility.

Proper replacements:
- COP-1: dariol83/ccsds has COP-1 support (Java)
- SCC: dariol83/ccsds has CLTU/randomizer (Java)
- TCF: spacepackets has CDS/CUC time code support (Python)

-272
-1
test/interop/python/.gitignore
··· 1 - scripts/.venv/
-19
test/interop/python/dune
··· 1 - (test 2 - (name test) 3 - (libraries scc alcotest) 4 - (deps 5 - (source_tree traces) 6 - (source_tree scripts))) 7 - 8 - ; Regenerate traces: REGEN_TRACES=1 dune build @regen-traces 9 - 10 - (rule 11 - (alias regen-traces) 12 - (enabled_if 13 - (= %{env:REGEN_TRACES=0} 1)) 14 - (deps 15 - (source_tree scripts)) 16 - (action 17 - (chdir 18 - scripts 19 - (run ./generate.py))))
-125
test/interop/python/scripts/generate.py
··· 1 - #!/usr/bin/env python3 2 - """Generate SCC interop traces for ocaml-scc. 3 - 4 - Oracle: Python (no deps needed for ASM pattern + randomizer LFSR + CLTU BCH) 5 - Install: no dependencies 6 - 7 - Tests: 8 - - ASM marker: 0x1ACFFC1D 9 - - Randomizer: CCSDS LFSR pseudo-random sequence (first 255 bytes) 10 - - CLTU BCH: BCH(63,56) parity for known inputs 11 - 12 - Traces are committed to git. Only re-run when changing inputs 13 - or upgrading the oracle. 14 - """ 15 - import os, sys, struct 16 - 17 - TRACE_DIR = os.path.join(os.path.dirname(__file__), "..", "traces") 18 - 19 - 20 - # --- ASM marker --- 21 - ASM_MARKER = bytes([0x1A, 0xCF, 0xFC, 0x1D]) 22 - 23 - 24 - # --- CCSDS Randomizer (LFSR) --- 25 - # Polynomial: h(x) = x^8 + x^7 + x^5 + x^3 + 1 26 - # Initial state: 0xFF 27 - # LFSR shifts right; output from bit 0; feedback enters at bit 7 28 - # Feedback is XOR of bits 0, 3, 5, 7 29 - # Output bits are packed MSB-first into bytes 30 - def ccsds_randomizer_sequence(n_bytes): 31 - state = 0xFF 32 - result = [] 33 - for _ in range(n_bytes): 34 - byte = 0 35 - for _ in range(8): 36 - out = state & 1 37 - xor_all = (state ^ (state >> 3) ^ (state >> 5) ^ (state >> 7)) & 1 38 - state = (state >> 1) | (xor_all << 7) 39 - byte = (byte << 1) | out 40 - result.append(byte) 41 - return bytes(result) 42 - 43 - 44 - # --- CLTU BCH(63,56) --- 45 - # Generator polynomial: g(x) = x^7 + x^6 + x^2 + 1 = 0x45 46 - # Processes 56 data bits (7 bytes) MSB-first through LFSR 47 - # Parity bits are complemented, placed in MSB 7 bits with filler bit (0) in LSB 48 - BCH_POLY = 0x45 49 - 50 - def bch_parity(data_7bytes): 51 - """Compute BCH(63,56) parity for 7 data bytes. 52 - Returns the parity byte (complemented, MSB-aligned with filler bit).""" 53 - sr = 0 54 - for byte_val in data_7bytes: 55 - for j in range(7, -1, -1): 56 - din = (byte_val >> j) & 1 57 - fb = ((sr >> 6) ^ din) & 1 58 - sr = ((sr << 1) ^ (BCH_POLY if fb else 0)) & 0x7F 59 - # Complement parity bits, shift to MSB 7 bits, filler bit (0) in LSB 60 - return ((~sr & 0x7F) << 1) & 0xFF 61 - 62 - 63 - def cltu_encode(frame): 64 - """Encode a TC frame as CLTU with BCH codeblocks.""" 65 - start_seq = b'\xEB\x90' 66 - tail_seq = b'\xC5\xC5\xC5\xC5\xC5\xC5\xC5\x79' 67 - fill_byte = 0x55 68 - codeblock_data = 7 69 - 70 - # Split frame into 7-byte chunks 71 - codeblocks = [] 72 - for i in range(0, len(frame), codeblock_data): 73 - chunk = frame[i:i + codeblock_data] 74 - # Pad with fill bytes if needed 75 - if len(chunk) < codeblock_data: 76 - chunk = chunk + bytes([fill_byte] * (codeblock_data - len(chunk))) 77 - parity = bch_parity(chunk) 78 - codeblocks.append(chunk + bytes([parity])) 79 - 80 - return start_seq + b''.join(codeblocks) + tail_seq 81 - 82 - 83 - # --- Generate traces --- 84 - os.makedirs(TRACE_DIR, exist_ok=True) 85 - with open(os.path.join(TRACE_DIR, "vectors.csv"), "w") as f: 86 - f.write("# SCC interop test vectors\n") 87 - f.write("# Oracle: Python (CCSDS spec reference implementation)\n") 88 - f.write("# Format: type,name,params...\n") 89 - f.write("#\n") 90 - f.write("# asm,name,marker_hex\n") 91 - f.write("# randomizer,name,length,sequence_hex\n") 92 - f.write("# bch,name,data_hex,parity_hex\n") 93 - f.write("# cltu,name,frame_hex,cltu_hex\n") 94 - 95 - # ASM marker 96 - f.write(f"asm,marker,{ASM_MARKER.hex()}\n") 97 - 98 - # Randomizer sequence 99 - for n in [20, 255]: 100 - seq = ccsds_randomizer_sequence(n) 101 - f.write(f"randomizer,pn_{n},{n},{seq.hex()}\n") 102 - 103 - # BCH parity for known inputs 104 - bch_inputs = [ 105 - ("zeros", bytes(7)), 106 - ("ones", bytes([0x01] * 7)), 107 - ("ascending", bytes(range(7))), 108 - ("all_ff", bytes([0xFF] * 7)), 109 - ("hello", b"Hello, " ), 110 - ] 111 - for name, data in bch_inputs: 112 - parity = bch_parity(data) 113 - f.write(f"bch,{name},{data.hex()},{parity:02x}\n") 114 - 115 - # CLTU encode for known frames 116 - cltu_frames = [ 117 - ("short_frame", bytes(range(7))), 118 - ("two_codeblocks", bytes(range(10))), 119 - ("hello_frame", b"Hello, CCSDS!"), 120 - ] 121 - for name, frame in cltu_frames: 122 - cltu = cltu_encode(frame) 123 - f.write(f"cltu,{name},{frame.hex()},{cltu.hex()}\n") 124 - 125 - print(f"Wrote {TRACE_DIR}/vectors.csv")
-108
test/interop/python/test.ml
··· 1 - (** Python interop tests for ocaml-scc. 2 - 3 - Traces generated by: Python (CCSDS spec reference implementation) 4 - Regenerate: REGEN_TRACES=1 dune build @regen-traces *) 5 - 6 - let trace path = Filename.concat "traces" path 7 - 8 - (* Parse CSV trace: skip comments (#), split on comma *) 9 - let parse_csv path = 10 - let ic = open_in (trace path) in 11 - let lines = ref [] in 12 - (try 13 - while true do 14 - let line = input_line ic in 15 - if String.length line > 0 && line.[0] <> '#' then 16 - lines := String.split_on_char ',' line :: !lines 17 - done 18 - with End_of_file -> ()); 19 - close_in ic; 20 - List.rev !lines 21 - 22 - let bytes_of_hex hex = 23 - let len = String.length hex / 2 in 24 - Bytes.init len (fun i -> 25 - Char.chr (int_of_string ("0x" ^ String.sub hex (i * 2) 2))) 26 - 27 - let hex_of_bytes b = 28 - let buf = Buffer.create (Bytes.length b * 2) in 29 - Bytes.iter 30 - (fun c -> Buffer.add_string buf (Printf.sprintf "%02x" (Char.code c))) 31 - b; 32 - Buffer.contents buf 33 - 34 - (* --- ASM tests --- *) 35 - 36 - let test_asm_marker expected_hex () = 37 - let expected = bytes_of_hex expected_hex in 38 - let marker = Scc.Sync.Asm.marker in 39 - if marker <> expected then 40 - Alcotest.failf "ASM marker mismatch\n expected: %s\n got: %s" 41 - expected_hex (hex_of_bytes marker) 42 - 43 - (* --- Randomizer tests --- *) 44 - 45 - let test_randomizer_sequence expected_len expected_hex () = 46 - let expected = bytes_of_hex expected_hex in 47 - let got = Scc.Coding.Randomizer.sequence expected_len in 48 - if got <> expected then 49 - Alcotest.failf 50 - "randomizer sequence (%d bytes) mismatch\n expected: %s\n got: %s" 51 - expected_len expected_hex (hex_of_bytes got) 52 - 53 - (* --- BCH parity tests --- *) 54 - 55 - let test_bch_parity data_hex expected_parity_hex () = 56 - let data = bytes_of_hex data_hex in 57 - let expected = int_of_string ("0x" ^ expected_parity_hex) in 58 - let got = Char.code (Scc.Sync.Cltu.bch_parity data 0) in 59 - if got <> expected then 60 - Alcotest.failf 61 - "BCH parity mismatch for %s\n expected: %02x\n got: %02x" data_hex 62 - expected got 63 - 64 - (* --- CLTU encode tests --- *) 65 - 66 - let test_cltu_encode frame_hex expected_hex () = 67 - let frame = bytes_of_hex frame_hex in 68 - let expected = bytes_of_hex expected_hex in 69 - let got = Scc.Sync.Cltu.encode frame in 70 - if got <> expected then 71 - Alcotest.failf "CLTU encode mismatch\n expected: %s\n got: %s" 72 - expected_hex (hex_of_bytes got) 73 - 74 - let () = 75 - let rows = parse_csv "vectors.csv" in 76 - let asm_tests = ref [] in 77 - let randomizer_tests = ref [] in 78 - let bch_tests = ref [] in 79 - let cltu_tests = ref [] in 80 - List.iter 81 - (fun row -> 82 - match row with 83 - | [ "asm"; name; marker_hex ] -> 84 - asm_tests := 85 - Alcotest.test_case name `Quick (test_asm_marker marker_hex) 86 - :: !asm_tests 87 - | [ "randomizer"; name; len_s; seq_hex ] -> 88 - randomizer_tests := 89 - Alcotest.test_case name `Quick 90 - (test_randomizer_sequence (int_of_string len_s) seq_hex) 91 - :: !randomizer_tests 92 - | [ "bch"; name; data_hex; parity_hex ] -> 93 - bch_tests := 94 - Alcotest.test_case name `Quick (test_bch_parity data_hex parity_hex) 95 - :: !bch_tests 96 - | [ "cltu"; name; frame_hex; cltu_hex ] -> 97 - cltu_tests := 98 - Alcotest.test_case name `Quick (test_cltu_encode frame_hex cltu_hex) 99 - :: !cltu_tests 100 - | _ -> Alcotest.failf "bad CSV row: %s" (String.concat "," row)) 101 - rows; 102 - Alcotest.run "scc-interop" 103 - [ 104 - ("asm", List.rev !asm_tests); 105 - ("randomizer", List.rev !randomizer_tests); 106 - ("bch", List.rev !bch_tests); 107 - ("cltu", List.rev !cltu_tests); 108 - ]
-19
test/interop/python/traces/vectors.csv
··· 1 - # SCC interop test vectors 2 - # Oracle: Python (CCSDS spec reference implementation) 3 - # Format: type,name,params... 4 - # 5 - # asm,name,marker_hex 6 - # randomizer,name,length,sequence_hex 7 - # bch,name,data_hex,parity_hex 8 - # cltu,name,frame_hex,cltu_hex 9 - asm,marker,1acffc1d 10 - randomizer,pn_20,20,ff480ec09a0d70bc8e2c93ada7b746ce5a977dcc 11 - randomizer,pn_255,255,ff480ec09a0d70bc8e2c93ada7b746ce5a977dcc32a2bf3e0a10f18894cdeab1fe901d81341ae1791c59275b4f6e8d9cb52efb9865457e7c1421e311299bd563fd203b026835c2f238b24eb69edd1b396a5df730ca8afcf82843c6225337aac7fa407604d06b85e471649d6d3dba3672d4bbee619515f9f050878c44a66f558ff480ec09a0d70bc8e2c93ada7b746ce5a977dcc32a2bf3e0a10f18894cdeab1fe901d81341ae1791c59275b4f6e8d9cb52efb9865457e7c1421e311299bd563fd203b026835c2f238b24eb69edd1b396a5df730ca8afcf82843c6225337aac7fa407604d06b85e471649d6d3dba3672d4bbee619515f9f050878c44a66f558 12 - bch,zeros,00000000000000,fe 13 - bch,ones,01010101010101,42 14 - bch,ascending,00010203040506,c6 15 - bch,all_ff,ffffffffffffff,86 16 - bch,hello,48656c6c6f2c20,8a 17 - cltu,short_frame,00010203040506,eb9000010203040506c6c5c5c5c5c5c5c579 18 - cltu,two_codeblocks,00010203040506070809,eb9000010203040506c607080955555555f2c5c5c5c5c5c5c579 19 - cltu,hello_frame,48656c6c6f2c20434353445321,eb9048656c6c6f2c208a43435344532155b6c5c5c5c5c5c5c579