User confirmed the FULL pipeline works with their laptop webcam at
QVGA quality 0.6 — frontend → WS → backend → worker → DLL → I²S →
firmware → esp_camera_fb_get() → user sketch.
[Frame #1] 8192 bytes 320x240 fmt=4
├─ SOI (FF D8 FF): ✓ at offset 0
├─ EOI (FF D9): ✓ at offset 8190
└─ First 16 bytes: FF D8 FF E0 00 10 4A 46 49 46 …
(JFIF, real webcam)
Stats: 10/10 Valid JPEGs at ~3.5 fps.
Changes:
- wokwi-libs/qemu-lcgamboa @ e4321d1 (picsimlab-esp32):
EOFS_PER_FRAME 6→8, inject_eoi_now flag for EOI injection on the
last EOF of each VSYNC burst. Handles JPEGs of arbitrary size by
forcing FF D9 at offset 8190 — JPEG decoders tolerate the
truncation gracefully.
- backend/esp32_worker.py: throttled trace log every 30 frames
(`camera_frame #N received (NNNN bytes)`) so users can confirm
the frontend → worker leg is alive without flooding the log.
- test/test-esp32-cam/autosearch/14: documented bug #9 (the 9th and
final silent bug — real webcam JPEGs exceed the deliverable byte
budget) with full forensic trace + final architecture diagram.
The emulation now handles ANY user webcam → ESP32-CAM use case end
to end. Standard upstream esp_camera_init() / esp_camera_fb_get()
sketches work without modification.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
End-to-end ESP32-CAM emulation now works. esp_camera_fb_get() in
user sketches returns valid camera_fb_t* pointers with JPEG frames
sourced from the user's webcam (or synthetic frames in tests).
Verification: webcam_demo.ino prints
frame N: 6144 bytes 320x240 fmt=4
continuously at ~10 fps under QEMU. 53 frames received in a 25 s
test window with debug logging disabled.
Bumps wokwi-libs/qemu-lcgamboa pointer to 5bbc92b (picsimlab-esp32)
which contains the final two fixes:
- eofs_remaining counter for multi-EOF-per-frame delivery
- reset_descriptor_ring() on rx_start 0→1 edge (matches hardware's
fresh-capture semantics that cam_hal relies on)
Adds:
- test/test-esp32-cam/autosearch/14_complete_emulation.md — full
forensic trace of the 8 distinct bugs found across the pipeline,
with final architecture diagram
- test/test-esp32-cam/tests/test_webcam_demo_live.py — pytest e2e
test that compiles webcam_demo.ino, boots it under the simulator
WebSocket, pushes a JPEG, and asserts fb_get returns frames
- test/test-esp32-cam/tests/debug_worker_direct.py — direct worker
bypass (no WS, no uvicorn) for dev-time tracing
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bumps wokwi-libs/qemu-lcgamboa pointer to a96c851 (picsimlab-esp32
branch) which contains:
- pack_one_pixel fix (was discarding half the JPEG data)
- split vsync_kick_timer / eof_timer (resolves chicken-and-egg
between VSYNC and rx_start)
- multi-descriptor walker (already in previous commit, recap)
Adds test/test-esp32-cam/autosearch/13_three_remaining_bugs.md
with line refs to upstream esp32-camera and a TODO list for the
next rebuild + verification cycle.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
First open-source end-to-end emulation of the AI-Thinker ESP32-CAM
in QEMU, paired with a browser webcam → firmware bridge so users can
develop camera sketches without hardware. Status: esp_camera_init()
returns ESP_OK; OV2640 chip-id verifies (PID/VER/MIDH/MIDL exactly
match the datasheet); GPIO 25 VSYNC NEGEDGE interrupt enabled by
the upstream driver. Final piece (cam_task accepting frames) is in
progress — descriptor walker fix landed in this commit.
Backend (Python/FastAPI):
- simulation.py: camera_attach/frame/detach WS handlers
- esp32_worker.py: ctypes binding to velxio_push_camera_frame +
feature-detection fallback for older DLLs
- esp32_lib_manager.py: forward camera commands to the worker stdin
- esp-idf-template/main/CMakeLists.txt: esp32-camera headers added
via add_prebuilt_library + REQUIRES driver (resolves i2c_master_*
symbols). LED_BUILTIN=2 fallback for sketches that hardcode it.
Frontend (React/TS):
- EditorToolbar.tsx: ESP32-CAM (and the rest of the ESP32 family)
added to isQemuBoard list — Run button now starts the QEMU bridge
for these boards instead of falling through to the AVR path
- useWebcamFrames.ts: getUserMedia → OffscreenCanvas →
toBlob('image/jpeg') → base64 → WS at ~10 fps
- CameraToggle.tsx: header button with status colors + frame counter
- SimulatorCanvas.tsx: render CameraToggle for esp32-cam boards
- Esp32Bridge.ts: sendCameraAttach/Frame/Detach + chunked btoa
- useSimulatorStore.ts: diagnostic log on compileBoardProgram
- components-metadata.json: regen including esp32-cam component
Submodule pointer:
- wokwi-libs/qemu-lcgamboa → ff8eee0 (camera devices commit on
davidmonterocrespo24/qemu-lcgamboa branch picsimlab-esp32)
Investigation + tests in test/test-esp32-cam/:
- 13 autosearch markdown docs (overview, SOTA, OV2640 spec, DVP/I2S
spec, build blueprint, blockers resolved, descriptor walker fix)
- 5 sketches (camera_init, sccb_probe, dma_smoke, frame_roundtrip,
webcam_demo) + 8 live + WS regression tests
- README with the user-facing flow
.gitignore:
- libqemu-*.dll.{pre-camera,new,bak} (rollback points, regenerated)
- wokwi-libs/esp32-camera/ (clone consumed by arduino-esp32 path,
not part of this repo)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>