{"record":{"id":"8d045f6635e24134","repo":"ruvnet/RuView","slug":"invalid-esp32-csi-data-format","errorCode":null,"errorMessage":"Invalid ESP32 CSI data format","messagePattern":"Invalid ESP32 CSI data format","errorType":"exception","errorClass":"CSIParseError","httpStatus":null,"severity":"error","filePath":"archive/v1/src/hardware/csi_extractor.py","lineNumber":74,"sourceCode":"    def parse(self, raw_data: bytes) -> CSIData:\n        \"\"\"Parse ESP32 CSI data format.\n        \n        Args:\n            raw_data: Raw bytes from ESP32\n            \n        Returns:\n            Parsed CSI data\n            \n        Raises:\n            CSIParseError: If data format is invalid\n        \"\"\"\n        if not raw_data:\n            raise CSIParseError(\"Empty data received\")\n        \n        try:\n            data_str = raw_data.decode('utf-8')\n            if not data_str.startswith('CSI_DATA:'):\n                raise CSIParseError(\"Invalid ESP32 CSI data format\")\n            \n            # Parse ESP32 format: CSI_DATA:timestamp,antennas,subcarriers,freq,bw,snr,[amp],[phase]\n            parts = data_str[9:].split(',')  # Remove 'CSI_DATA:' prefix\n            \n            timestamp_ms = int(parts[0])\n            num_antennas = int(parts[1])\n            num_subcarriers = int(parts[2])\n            frequency_mhz = float(parts[3])\n            bandwidth_mhz = float(parts[4])\n            snr = float(parts[5])\n            \n            # Convert to proper units\n            frequency = frequency_mhz * 1e6  # MHz to Hz\n            bandwidth = bandwidth_mhz * 1e6  # MHz to Hz\n            \n            # Parse amplitude and phase arrays from the remaining CSV fields.\n            # Expected format after the header fields: comma-separated float values\n            # representing interleaved amplitude and phase per antenna per subcarrier.","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/ruvnet/RuView/blob/4685618388a5e49fad5b3005806f3bdd6a7c25c3/archive/v1/src/hardware/csi_extractor.py#L56-L92","documentation":"After utf-8 decoding, ESP32CSIParser requires the payload to start with the literal 'CSI_DATA:' prefix; anything else raises CSIParseError('Invalid ESP32 CSI data format'). This parser understands only that exact CSV text protocol, so the error means the bytes on the wire are not a text CSI frame — logs, boot output, binary frames, or garbage.","triggerScenarios":"Feeding ESP32 boot/log lines ('rst:0x1 ...', 'I (320) wifi:...') printed on the same UART; sending an ADR-018 binary frame while config parser_format is not 'binary'; leading whitespace/CR before the prefix; firmware that prints a different CSV header.","commonSituations":"Firmware console logs interleaved with CSI output on one serial line; forgetting parser_format='binary' when the node streams ADR-018 frames; chunked reads that begin mid-line so the prefix is missed.","solutions":["Filter before parsing: only pass bytes whose stripped value starts with b'CSI_DATA:' (see validationCode)","If the firmware emits ADR-018 binary frames, construct CSIExtractor with parser_format='binary' so ESP32BinaryParser is selected","Flash a firmware build that outputs the CSI_DATA CSV line format per docs/hardware-setup.md"],"exampleFix":"# before\nfor chunk in stream:\n    data = parser.parse(chunk)  # raises on every log/boot line\n\n# after\nfor line in stream:\n    line = line.strip()\n    if not line.startswith(b'CSI_DATA:'):\n        continue  # skip console noise\n    data = parser.parse(line)","handlingStrategy":"validation","validationCode":"line = raw.strip()\nif not line.startswith(b'CSI_DATA:'):\n    return None  # console/log noise or wrong protocol\nreturn parser.parse(line)","typeGuard":"def is_esp32_text_csi(raw: bytes) -> bool:\n    return bool(raw) and raw.strip().startswith(b'CSI_DATA:')","tryCatchPattern":"try:\n    data = parser.parse(raw)\nexcept CSIParseError as e:\n    logger.debug('non-CSI line dropped: %r -> %s', raw[:40], e)","preventionTips":["Prefix-filter every line before parsing so firmware logs never reach the parser","Set parser_format='binary' in the extractor config when the node streams ADR-018 frames","Pin the firmware build so the CSI_DATA line layout matches what the parser expects"],"tags":["esp32","parsing","protocol","firmware"],"backgroundTag":null,"analyzedSha":"4685618388a5e49fad5b3005806f3bdd6a7c25c3","analyzedAt":"2026-08-16T06:09:40.886Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}