fix(esp32_worker): skip per-byte log+emit for I2CWriteSink display drivers
A 1024-byte oled.show() writevto generates ~1025 calls into _on_i2c_event, one per byte. The previous code called _log (stderr write+flush) AND _emit (stdout JSON write+flush) for every event, saturating the worker subprocess's stdout pipe. The QEMU thread blocks on the synchronous write, the firmware's ESP-IDF i2c_master ISR re-enters before the previous one finished, and the Interrupt watchdog trips on CPU1 with a "Guru Meditation Error: Interrupt wdt timeout" panic on the second consecutive oled.show() call. I2CWriteSink already buffers writes internally and emits a single i2c_transaction event on FINISH, so the per-byte log+emit was pure overhead with no observability value for display drivers (SSD1306, PCF8574). Keep them for everything else. Verified end-to-end via chrome devtools MCP: - Test minimal (init + 1 explicit show): markers OK, no panic - Loop test (10x oled.show() + sleep(0.5)): DONE_LOOP, no panic
This commit is contained in:
parent
b09c8339ac
commit
d6442180b0
|
|
@ -947,15 +947,25 @@ def main() -> None: # noqa: C901 (complexity OK for inline worker)
|
|||
else:
|
||||
note = ''
|
||||
|
||||
if type(slave).__name__ == 'MPU6050Slave':
|
||||
slave_type_name = type(slave).__name__
|
||||
if slave_type_name == 'MPU6050Slave':
|
||||
seq = _i2c_event_seq
|
||||
n = seq[addr] = seq.get(addr, 0) + 1
|
||||
_log(f'I2C #{n:03d} bus={bus_id} addr=0x{addr:02x} {op_name} {note}')
|
||||
else:
|
||||
elif slave_type_name != 'I2CWriteSink':
|
||||
# I2CWriteSink fires per-byte for display drivers (SSD1306,
|
||||
# PCF8574). A 1024-byte writevto (oled.show()) generates
|
||||
# ~1025 events. Logging each one + emitting a WS message
|
||||
# blocks the QEMU thread long enough that the firmware's
|
||||
# ESP-IDF I2C ISR re-enters and trips IWDT on the SECOND
|
||||
# consecutive show() call. Skip the verbose per-event log
|
||||
# and WS trace for write-only sinks — the user-visible
|
||||
# OLED render is what matters, not byte-level tracing.
|
||||
_log(f'I2C bus={bus_id} addr=0x{addr:02x} event=0x{event:04x} '
|
||||
f'op={op_name} result=0x{result:02x} slave={type(slave).__name__}')
|
||||
# Emit trace event to WebSocket so JS test can observe I2C traffic
|
||||
if not _stopped.is_set():
|
||||
f'op={op_name} result=0x{result:02x} slave={slave_type_name}')
|
||||
# Emit trace event to WebSocket so JS test can observe I2C traffic.
|
||||
# Skip for I2CWriteSink (display data dumps) — see comment above.
|
||||
if not _stopped.is_set() and slave_type_name != 'I2CWriteSink':
|
||||
_emit({'type': 'i2c_trace', 'bus': bus_id, 'addr': addr,
|
||||
'event': event, 'op': op_name, 'result': result,
|
||||
'reg_ptr': reg_ptr})
|
||||
|
|
|
|||
Loading…
Reference in New Issue