Decode radio transmissions from devices on the ISM bands in OCaml
at main 194 lines 5.7 kB view raw
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