Decode radio transmissions from devices on the ISM bands in OCaml
1(** Two-dimensional bit buffer for storing decoded pulse data.
2
3 A bitbuffer stores multiple rows of bits, where each row represents
4 a separate packet or transmission. This is useful for sensors that
5 send repeated transmissions of the same data. *)
6
7(** {1 Constants} *)
8
9(** Maximum number of bytes per row. *)
10val max_cols : int
11
12(** Maximum number of rows. *)
13val max_rows : int
14
15(** {1 Types} *)
16
17(** A bit buffer containing multiple rows of bits. *)
18type t
19
20(** {1 Construction} *)
21
22(** Create a new empty bitbuffer. *)
23val create : unit -> t
24
25(** Clear all data from the bitbuffer. *)
26val clear : t -> unit
27
28(** {1 Adding Data} *)
29
30(** Add a single bit (0 or 1) to the current row.
31
32 Bits are added MSB first within each byte.
33
34 @param bits The bitbuffer
35 @param bit 0 or 1 *)
36val add_bit : t -> int -> unit
37
38(** Start a new row in the bitbuffer.
39
40 The current row is finalized and a new empty row is started. *)
41val add_row : t -> unit
42
43(** Add a sync marker and optionally start a new row.
44
45 If the current row has data, starts a new row. Otherwise,
46 increments the sync counter for the current row. *)
47val add_sync : t -> unit
48
49(** {1 Accessing Data} *)
50
51(** Get the number of active rows. *)
52val num_rows : t -> int
53
54(** Get the number of bits in a specific row.
55
56 @param bits The bitbuffer
57 @param row Row index (0-based)
58 @return Number of bits in the row *)
59val bits_per_row : t -> int -> int
60
61(** Get the number of sync pulses before a row.
62
63 @param bits The bitbuffer
64 @param row Row index
65 @return Number of sync pulses *)
66val syncs_before_row : t -> int -> int
67
68(** Get the raw bytes of a row.
69
70 @param bits The bitbuffer
71 @param row Row index
72 @return Bytes containing the row data *)
73val get_row : t -> int -> bytes
74
75(** Get a single bit from a specific position.
76
77 @param bits The bitbuffer
78 @param row Row index
79 @param bit Bit index within the row
80 @return 0 or 1 *)
81val get_bit : t -> row:int -> bit:int -> int
82
83(** Get a byte from a potentially unaligned bit position.
84
85 @param bits The bitbuffer
86 @param row Row index
87 @param bit_offset Bit offset within the row
88 @return Byte value *)
89val get_byte : t -> row:int -> bit_offset:int -> int
90
91(** Extract bytes from a row, handling unaligned access.
92
93 @param bits The bitbuffer
94 @param row Row index
95 @param bit_offset Starting bit offset
96 @param len Number of bits to extract
97 @return Extracted bytes *)
98val extract_bytes : t -> row:int -> bit_offset:int -> len:int -> bytes
99
100(** {1 Transformations} *)
101
102(** Invert all bits in the bitbuffer (0 becomes 1 and vice versa). *)
103val invert : t -> unit
104
105(** Non-Return-to-Zero Space (NRZI) decode the bitbuffer.
106
107 "One" is represented by no change in level,
108 "Zero" is represented by change in level. *)
109val nrzs_decode : t -> unit
110
111(** Non-Return-to-Zero Mark (NRZM) decode the bitbuffer.
112
113 "One" is represented by change in level,
114 "Zero" is represented by no change in level. *)
115val nrzm_decode : t -> unit
116
117(** Manchester decode from one bitbuffer into another.
118
119 Decodes at most [max] data bits (2*max input bits) from the
120 specified row and starting position. Manchester per IEEE 802.3:
121 high-low is 0, low-high is 1.
122
123 @param inbuf Input bitbuffer
124 @param row Row to decode from
125 @param start Starting bit position
126 @param max Maximum data bits to decode
127 @return Tuple of (output bitbuffer, input bit position after decode) *)
128val manchester_decode : t -> row:int -> start:int -> max:int -> t * int
129
130(** Differential Manchester decode. *)
131val differential_manchester_decode : t -> row:int -> start:int -> max:int -> t * int
132
133(** {1 Searching} *)
134
135(** Search for a bit pattern in a row.
136
137 @param bits The bitbuffer
138 @param row Row to search
139 @param start Starting bit position
140 @param pattern Pattern bytes to search for (MSB aligned)
141 @param pattern_bits Number of bits in the pattern
142 @return Bit position of match, or end of row if not found *)
143val search : t -> row:int -> start:int -> pattern:bytes -> pattern_bits:int -> int
144
145(** {1 Row Comparison} *)
146
147(** Compare two rows for equality.
148
149 @param bits The bitbuffer
150 @param row_a First row index
151 @param row_b Second row index
152 @param max_bits Maximum bits to compare (0 = all)
153 @return 0 if equal, non-zero otherwise *)
154val compare_rows : t -> row_a:int -> row_b:int -> max_bits:int -> int
155
156(** Count how many times a row is repeated.
157
158 @param bits The bitbuffer
159 @param row Row to check
160 @param max_bits Maximum bits to compare
161 @return Number of identical rows (at least 1) *)
162val count_repeats : t -> row:int -> max_bits:int -> int
163
164(** Find a row that appears at least min_repeats times.
165
166 @param bits The bitbuffer
167 @param min_repeats Minimum number of repetitions
168 @param min_bits Minimum row length in bits
169 @return Row index or None if not found *)
170val find_repeated_row : t -> min_repeats:int -> min_bits:int -> int option
171
172(** Find a repeated row by prefix matching.
173
174 Like [find_repeated_row] but only compares up to [min_bits] bits. *)
175val find_repeated_prefix : t -> min_repeats:int -> min_bits:int -> int option
176
177(** {1 Parsing} *)
178
179(** Parse a hex string into a bitbuffer.
180
181 The string may be prefixed with "0x" and rows can be separated
182 by "/" or have length prefixes in braces like "{24}".
183
184 @param bits Output bitbuffer (will be cleared first)
185 @param code Hex string to parse *)
186val parse : t -> string -> unit
187
188(** {1 Printing} *)
189
190(** Pretty-print the bitbuffer contents. *)
191val pp : Format.formatter -> t -> unit
192
193(** Format a single row as a hex string with bit count. *)
194val row_to_string : t -> int -> string