(* Two-dimensional bit buffer *) let max_cols = 128 let max_rows = 50 type t = { mutable num_rows : int; mutable free_row : int; bits_per_row : int array; syncs_before_row : int array; bb : bytes array; } let create () = { num_rows = 0; free_row = 0; bits_per_row = Array.make max_rows 0; syncs_before_row = Array.make max_rows 0; bb = Array.init max_rows (fun _ -> Bytes.make max_cols '\000'); } let clear t = t.num_rows <- 0; t.free_row <- 0; Array.fill t.bits_per_row 0 max_rows 0; Array.fill t.syncs_before_row 0 max_rows 0; Array.iter (fun b -> Bytes.fill b 0 max_cols '\000') t.bb let add_bit t bit = if t.free_row < max_rows then begin let row = t.free_row in let bit_pos = t.bits_per_row.(row) in if bit_pos < max_cols * 8 then begin let byte_pos = bit_pos / 8 in let bit_in_byte = 7 - (bit_pos mod 8) in if bit <> 0 then begin let b = Bytes.get_uint8 t.bb.(row) byte_pos in Bytes.set_uint8 t.bb.(row) byte_pos (b lor (1 lsl bit_in_byte)) end; t.bits_per_row.(row) <- bit_pos + 1; if t.num_rows = 0 then t.num_rows <- 1 end end let add_row t = if t.bits_per_row.(t.free_row) > 0 && t.free_row + 1 < max_rows then begin t.free_row <- t.free_row + 1; t.num_rows <- t.num_rows + 1 end let add_sync t = if t.bits_per_row.(t.free_row) > 0 then add_row t else t.syncs_before_row.(t.free_row) <- t.syncs_before_row.(t.free_row) + 1 let num_rows t = t.num_rows let bits_per_row t row = if row < max_rows then t.bits_per_row.(row) else 0 let syncs_before_row t row = if row < max_rows then t.syncs_before_row.(row) else 0 let get_row t row = if row < max_rows then t.bb.(row) else Bytes.empty let get_bit t ~row ~bit = if row < max_rows && bit < t.bits_per_row.(row) then let byte_pos = bit / 8 in let bit_in_byte = 7 - (bit mod 8) in (Bytes.get_uint8 t.bb.(row) byte_pos lsr bit_in_byte) land 1 else 0 let get_byte t ~row ~bit_offset = if row >= max_rows then 0 else let b1 = Bytes.get_uint8 t.bb.(row) (bit_offset / 8) in let b2 = if bit_offset / 8 + 1 < max_cols then Bytes.get_uint8 t.bb.(row) ((bit_offset / 8) + 1) else 0 in let shift = bit_offset mod 8 in ((b1 lsl shift) lor (b2 lsr (8 - shift))) land 0xff let extract_bytes t ~row ~bit_offset ~len = let num_bytes = (len + 7) / 8 in let result = Bytes.make num_bytes '\000' in for i = 0 to num_bytes - 1 do Bytes.set_uint8 result i (get_byte t ~row ~bit_offset:(bit_offset + (i * 8))) done; result let invert t = for row = 0 to t.num_rows - 1 do let num_bytes = (t.bits_per_row.(row) + 7) / 8 in for i = 0 to num_bytes - 1 do Bytes.set_uint8 t.bb.(row) i (lnot (Bytes.get_uint8 t.bb.(row) i) land 0xff) done done let nrzs_decode _t = () (* TODO *) let nrzm_decode _t = () (* TODO *) let manchester_decode _t ~row ~start ~max = ignore (row, start, max); (create (), 0) let differential_manchester_decode _t ~row ~start ~max = ignore (row, start, max); (create (), 0) let search t ~row ~start ~pattern ~pattern_bits = ignore (pattern, pattern_bits); if row < max_rows then t.bits_per_row.(row) else start let compare_rows t ~row_a ~row_b ~max_bits = ignore max_bits; if row_a >= max_rows || row_b >= max_rows then 1 else if t.bits_per_row.(row_a) <> t.bits_per_row.(row_b) then 1 else Bytes.compare t.bb.(row_a) t.bb.(row_b) let count_repeats t ~row ~max_bits = let count = ref 1 in for i = 0 to t.num_rows - 1 do if i <> row && compare_rows t ~row_a:row ~row_b:i ~max_bits = 0 then incr count done; !count let find_repeated_row t ~min_repeats ~min_bits = let rec check row = if row >= t.num_rows then None else if t.bits_per_row.(row) >= min_bits && count_repeats t ~row ~max_bits:0 >= min_repeats then Some row else check (row + 1) in check 0 let find_repeated_prefix t ~min_repeats ~min_bits = find_repeated_row t ~min_repeats ~min_bits let parse t _code = clear t (* TODO: implement parsing *) let row_to_string t row = if row >= t.num_rows then "" else let bits = t.bits_per_row.(row) in let num_bytes = (bits + 7) / 8 in let hex = Rtl433_util.bytes_to_hex t.bb.(row) num_bytes in Printf.sprintf "{%d} %s" bits hex let pp fmt t = Format.fprintf fmt "Bitbuffer: %d rows@." t.num_rows; for i = 0 to t.num_rows - 1 do Format.fprintf fmt " [%d] %s@." i (row_to_string t i) done