112 lines
5.9 KiB
Markdown
112 lines
5.9 KiB
Markdown
|
|
# 07 — Phased emulation plan
|
|||
|
|
|
|||
|
|
## North-star architecture
|
|||
|
|
|
|||
|
|
**One Web Component**, **one simulation hook**, **one state machine** —
|
|||
|
|
parameterised by panel kind. The state machine internally branches per
|
|||
|
|
controller family (SSD168x, UC81xx, Spectra6) but exposes a single
|
|||
|
|
`metadataId = 'epaper-<panel-kind>'` for ComponentRegistry.
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
┌─────────────────── frontend/src/components/velxio-components ──────────────┐
|
|||
|
|
│ │
|
|||
|
|
│ EPaperElement.ts (Web Component <velxio-epaper panel-kind=…>) │
|
|||
|
|
│ EPaper.tsx (React wrapper — thin) │
|
|||
|
|
│ │
|
|||
|
|
└──────────────────────────────────┬──────────────────────────────────────────┘
|
|||
|
|
│ pinInfo + canvas
|
|||
|
|
▼
|
|||
|
|
┌────────────────── frontend/src/simulation/parts/EPaperPart.ts ─────────────┐
|
|||
|
|
│ │
|
|||
|
|
│ const familyDecoders = { │
|
|||
|
|
│ 'ssd168x': new SSD168xDecoder(panel), │
|
|||
|
|
│ 'uc81xx': new UC81xxDecoder(panel), │
|
|||
|
|
│ 'spectra6': new Spectra6Decoder(panel), │
|
|||
|
|
│ } │
|
|||
|
|
│ │
|
|||
|
|
│ spi.onByte = (b) => decoder.feed(b, dcState) │
|
|||
|
|
│ onActivate() → composeAndFlush() → pulseBusy(REFRESH_MS) │
|
|||
|
|
│ │
|
|||
|
|
└─────────────────────────────────────────────────────────────────────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Phase 1 — SSD168x mono (1.54", 2.13", 2.9", 4.2", 7.5")
|
|||
|
|
|
|||
|
|
Smallest scope that ships something useful. Five metadata IDs, one
|
|||
|
|
decoder, one Web Component.
|
|||
|
|
|
|||
|
|
**Deliverables:**
|
|||
|
|
1. `EPaperElement.ts` — Web Component supporting `panel-kind` ∈
|
|||
|
|
`epaper-1in54-bw | epaper-2in13-bw | epaper-2in9-bw | epaper-4in2-bw |
|
|||
|
|
epaper-7in5-bw`. SVG body + active area canvas + FPC pins.
|
|||
|
|
2. `EPaper.tsx` — React wrapper, forwards canvas readiness via
|
|||
|
|
`canvas-ready` custom event (mirrors ILI9341).
|
|||
|
|
3. `EPaperPart.ts` — registers all 5 metadata IDs with the same
|
|||
|
|
`ssd168x` decoder + a per-panel resolution + bezel config.
|
|||
|
|
4. `ComponentRegistry.ts` — wire the IDs.
|
|||
|
|
5. Library auto-install: ensure GxEPD2 + Adafruit_GFX trigger via the
|
|||
|
|
sketch's `#include`.
|
|||
|
|
6. Pixel-buffer fingerprint test (one per panel size).
|
|||
|
|
|
|||
|
|
**Decoder scope:** the 17 SSD168x commands listed in `02_controllers.md` ×
|
|||
|
|
two RAM planes × the 0x20 ACTIVATION trigger. Anything else (LUT writes
|
|||
|
|
0x32, gate driving voltage 0x03, etc.) is **silently consumed** so the
|
|||
|
|
init sequence completes without warnings.
|
|||
|
|
|
|||
|
|
**Acceptance test:**
|
|||
|
|
- Compile `GxEPD2_HelloWorld.ino` for the 1.54" panel against ESP32, Pi
|
|||
|
|
Pico, and Arduino Uno. Compile success on all three.
|
|||
|
|
- Run on ESP32 + Pi Pico in the simulator. After ~50 ms BUSY pulse the
|
|||
|
|
canvas shows "Hello World" with a sharp 200×200 buffer.
|
|||
|
|
|
|||
|
|
## Phase 2 — Tri-colour SSD168x (B/W/Red 2.13" + 2.9")
|
|||
|
|
|
|||
|
|
Reuses 90% of Phase 1. Adds:
|
|||
|
|
|
|||
|
|
- Two-plane composition (`0x24` black + `0x26` red).
|
|||
|
|
- Two new metadata IDs: `epaper-2in13-bwr`, `epaper-2in9-bwr`.
|
|||
|
|
- Web Component palette change.
|
|||
|
|
|
|||
|
|
## Phase 3 — UC81xx (4.2" UC8176, 7.5" UC8179, 5.65" 7-colour ACeP UC8159c)
|
|||
|
|
|
|||
|
|
New decoder. Different command set (0x10 DTM1, 0x12 DRF, etc.) but
|
|||
|
|
**same wiring + same Web Component**. Scope:
|
|||
|
|
|
|||
|
|
- `UC81xxDecoder.ts` for mono 4.2" / 7.5".
|
|||
|
|
- `ACePDecoder.ts` for 7-colour 5.65" (4 px / byte palette).
|
|||
|
|
|
|||
|
|
## Phase 4 — Spectra 6 (the user's 13.3" 1200×1600)
|
|||
|
|
|
|||
|
|
New decoder; different command set again. Slowest refresh (12 s real,
|
|||
|
|
emulator default 200 ms). Massive framebuffer (1.2 MB raw at 6 colours;
|
|||
|
|
~470 KB packed) — make sure the canvas downscales properly for gallery
|
|||
|
|
preview thumbnails.
|
|||
|
|
|
|||
|
|
## Phase 5 — IT8951 (Carta 6"–10.3" greyscale)
|
|||
|
|
|
|||
|
|
Different beast. Command-packet protocol over SPI. Deferred until a
|
|||
|
|
concrete user asks.
|
|||
|
|
|
|||
|
|
## Out-of-scope forever (probably)
|
|||
|
|
|
|||
|
|
- LUT-driven custom waveforms — accept silently, never validate.
|
|||
|
|
- Real-time partial-window updates — Phase 1 just full-frames.
|
|||
|
|
- Capacitive touch overlay — different component (EPD has no touch panel
|
|||
|
|
built in; touch is an upper layer in some bundles like Waveshare's CFAF).
|
|||
|
|
|
|||
|
|
## Risk register
|
|||
|
|
|
|||
|
|
| Risk | Mitigation |
|
|||
|
|
|---|---|
|
|||
|
|
| GxEPD2 + Adafruit_GFX too big for AVR (Uno) at 4.2"+ | Ship the small panels (1.54", 2.13") for AVR; the rest get an "AVR not supported" hint in the Library Manager modal. |
|
|||
|
|
| Spectra 6 reverse-engineering may be incomplete | Ship Phase 1–3 first; Spectra 6 can land after we capture real SPI traces from a Seeed EE02 via Saleae and adjust. |
|
|||
|
|
| BUSY emulation timing too short → firmware loops never see HIGH | Default to 50 ms refresh. Add a `refresh-ms` attribute on the Web Component. |
|
|||
|
|
| Controller silently differs across panel revisions | Fingerprint commands: log to `chip_log` events whenever an unknown opcode is seen so users can report panel quirks. |
|
|||
|
|
|
|||
|
|
## What can ship today
|
|||
|
|
|
|||
|
|
Just the dossier (this folder), a couple of pure-state-machine Python
|
|||
|
|
unit tests (next file), and one canonical sketch in `sketches/`. Real
|
|||
|
|
emulator code is a separate PR — explicitly **deferred** until the user
|
|||
|
|
greenlights phase 1.
|