(** Two-dimensional bit buffer for storing decoded pulse data. A bitbuffer stores multiple rows of bits, where each row represents a separate packet or transmission. This is useful for sensors that send repeated transmissions of the same data. *) (** {1 Constants} *) (** Maximum number of bytes per row. *) val max_cols : int (** Maximum number of rows. *) val max_rows : int (** {1 Types} *) (** A bit buffer containing multiple rows of bits. *) type t (** {1 Construction} *) (** Create a new empty bitbuffer. *) val create : unit -> t (** Clear all data from the bitbuffer. *) val clear : t -> unit (** {1 Adding Data} *) (** Add a single bit (0 or 1) to the current row. Bits are added MSB first within each byte. @param bits The bitbuffer @param bit 0 or 1 *) val add_bit : t -> int -> unit (** Start a new row in the bitbuffer. The current row is finalized and a new empty row is started. *) val add_row : t -> unit (** Add a sync marker and optionally start a new row. If the current row has data, starts a new row. Otherwise, increments the sync counter for the current row. *) val add_sync : t -> unit (** {1 Accessing Data} *) (** Get the number of active rows. *) val num_rows : t -> int (** Get the number of bits in a specific row. @param bits The bitbuffer @param row Row index (0-based) @return Number of bits in the row *) val bits_per_row : t -> int -> int (** Get the number of sync pulses before a row. @param bits The bitbuffer @param row Row index @return Number of sync pulses *) val syncs_before_row : t -> int -> int (** Get the raw bytes of a row. @param bits The bitbuffer @param row Row index @return Bytes containing the row data *) val get_row : t -> int -> bytes (** Get a single bit from a specific position. @param bits The bitbuffer @param row Row index @param bit Bit index within the row @return 0 or 1 *) val get_bit : t -> row:int -> bit:int -> int (** Get a byte from a potentially unaligned bit position. @param bits The bitbuffer @param row Row index @param bit_offset Bit offset within the row @return Byte value *) val get_byte : t -> row:int -> bit_offset:int -> int (** Extract bytes from a row, handling unaligned access. @param bits The bitbuffer @param row Row index @param bit_offset Starting bit offset @param len Number of bits to extract @return Extracted bytes *) val extract_bytes : t -> row:int -> bit_offset:int -> len:int -> bytes (** {1 Transformations} *) (** Invert all bits in the bitbuffer (0 becomes 1 and vice versa). *) val invert : t -> unit (** Non-Return-to-Zero Space (NRZI) decode the bitbuffer. "One" is represented by no change in level, "Zero" is represented by change in level. *) val nrzs_decode : t -> unit (** Non-Return-to-Zero Mark (NRZM) decode the bitbuffer. "One" is represented by change in level, "Zero" is represented by no change in level. *) val nrzm_decode : t -> unit (** Manchester decode from one bitbuffer into another. Decodes at most [max] data bits (2*max input bits) from the specified row and starting position. Manchester per IEEE 802.3: high-low is 0, low-high is 1. @param inbuf Input bitbuffer @param row Row to decode from @param start Starting bit position @param max Maximum data bits to decode @return Tuple of (output bitbuffer, input bit position after decode) *) val manchester_decode : t -> row:int -> start:int -> max:int -> t * int (** Differential Manchester decode. *) val differential_manchester_decode : t -> row:int -> start:int -> max:int -> t * int (** {1 Searching} *) (** Search for a bit pattern in a row. @param bits The bitbuffer @param row Row to search @param start Starting bit position @param pattern Pattern bytes to search for (MSB aligned) @param pattern_bits Number of bits in the pattern @return Bit position of match, or end of row if not found *) val search : t -> row:int -> start:int -> pattern:bytes -> pattern_bits:int -> int (** {1 Row Comparison} *) (** Compare two rows for equality. @param bits The bitbuffer @param row_a First row index @param row_b Second row index @param max_bits Maximum bits to compare (0 = all) @return 0 if equal, non-zero otherwise *) val compare_rows : t -> row_a:int -> row_b:int -> max_bits:int -> int (** Count how many times a row is repeated. @param bits The bitbuffer @param row Row to check @param max_bits Maximum bits to compare @return Number of identical rows (at least 1) *) val count_repeats : t -> row:int -> max_bits:int -> int (** Find a row that appears at least min_repeats times. @param bits The bitbuffer @param min_repeats Minimum number of repetitions @param min_bits Minimum row length in bits @return Row index or None if not found *) val find_repeated_row : t -> min_repeats:int -> min_bits:int -> int option (** Find a repeated row by prefix matching. Like [find_repeated_row] but only compares up to [min_bits] bits. *) val find_repeated_prefix : t -> min_repeats:int -> min_bits:int -> int option (** {1 Parsing} *) (** Parse a hex string into a bitbuffer. The string may be prefixed with "0x" and rows can be separated by "/" or have length prefixes in braces like "{24}". @param bits Output bitbuffer (will be cleared first) @param code Hex string to parse *) val parse : t -> string -> unit (** {1 Printing} *) (** Pretty-print the bitbuffer contents. *) val pp : Format.formatter -> t -> unit (** Format a single row as a hex string with bit count. *) val row_to_string : t -> int -> string