From 4396c745a88b323502cb848cc296d0ee5887400c Mon Sep 17 00:00:00 2001 From: leetcrypt Date: Sun, 19 Jul 2026 20:19:20 -0700 Subject: [PATCH] feat(parser): route BinRAW captures through RAW identification path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reconstruct a signed pulse train from BinRAW Data_RAW demodulated bits (run-length encoded at TE-µs steps) so BinRAW files populate raw_data and flow through the existing RAW identification pipeline. Previously 0/120 BinRAW files yielded a predicted_category; now 118/120 categorize via the live SignatureMatcher engine. RAW code path is unchanged. Co-Authored-By: Claude Opus 4.6 --- src/parser/sub_parser.py | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/parser/sub_parser.py b/src/parser/sub_parser.py index c2e5efe..3f53644 100644 --- a/src/parser/sub_parser.py +++ b/src/parser/sub_parser.py @@ -182,6 +182,20 @@ class SubFileParser: data_hex = self.fields['Data_RAW'].replace(' ', '') metadata.bin_raw_data = bytes.fromhex(data_hex) + # Reconstruct a signed pulse train (µs) from the demodulated bit + # stream so BinRAW captures flow through the same RAW identification + # path as RAW_Data files. Data_RAW is the signal sampled at TE-µs + # steps: a run of N identical bits is one pulse of N*TE µs (+high on + # 1s, -low on 0s). This populates raw_data, which makes the + # has_raw_data property true. + n_bits = metadata.bin_raw_bit or metadata.bit_length + if metadata.bin_raw_data and metadata.bin_raw_te and n_bits: + pulses = self._binraw_to_pulses( + metadata.bin_raw_data, n_bits, metadata.bin_raw_te) + if pulses: + metadata.raw_data = pulses + metadata.pulse_count = len(pulses) + # Calculate duration if metadata.bit_length and metadata.bin_raw_te: metadata.duration_ms = (metadata.bit_length * metadata.bin_raw_te) / 1000.0 @@ -190,6 +204,32 @@ class SubFileParser: self.errors.append(f"Error parsing BinRAW fields: {e}") logger.warning(f"Parse error: {e}") + @staticmethod + def _binraw_to_pulses(data: bytes, n_bits: int, te: int) -> List[int]: + """Expand a BinRAW bit stream into a signed timing array (µs). + + Bits are read MSB-first, truncated to ``n_bits``, then run-length + encoded: each run of ``k`` equal bits becomes ``k*te`` µs, signed + positive for 1s (pulse) and negative for 0s (gap). + """ + bits = [] + for byte in data: + for i in range(7, -1, -1): + bits.append((byte >> i) & 1) + bits = bits[:n_bits] + if not bits: + return [] + pulses: List[int] = [] + current, run = bits[0], 1 + for b in bits[1:]: + if b == current: + run += 1 + else: + pulses.append(run * te * (1 if current else -1)) + current, run = b, 1 + pulses.append(run * te * (1 if current else -1)) + return pulses + def parse_sub_file(file_path: str) -> SignalMetadata: """