diff options
| author | Your Name <you@example.com> | 2026-05-20 02:14:45 +0530 |
|---|---|---|
| committer | Your Name <you@example.com> | 2026-05-20 02:14:45 +0530 |
| commit | 899016795c389151e6b486ec470653f5688e5c5f (patch) | |
| tree | 64b4c732d6f585552fd14df5f47890764c66ac1a /DISPLAY_UI_PLAN.md | |
| parent | 4f713120dbedd37a3512c2ec1af0766025a59d57 (diff) | |
feat: merge display-fix — touch driver, keyboard, WiFi setup UI
Squash-merge of feature/display-fix (27 commits):
- AXS15231B touch driver with coordinate parsing (touch.c/h)
- On-screen keyboard with layout/hit detection (keyboard.c/h)
- WiFi setup state machine + config_add_wifi (wifi_setup.c/h)
- Web-based WiFi setup via captive portal
- Display rotation fix (stride=480), color fixes, DMA byte-swap
- WiFi QR code on BOOT and ERROR screens
- ERROR state transition after WiFi retries exhausted
- Unit tests: test_touch, test_keyboard, test_wifi_setup
- Integration test: wifi_setup.mjs
- E2E test: wifi-setup.spec.mjs
- Per-board hardware locks for flash targets
Conflicts resolved: took master for config/cvm/api/main (more current),
took display-fix for display/axs15231b (newer fixes).
Diffstat (limited to 'DISPLAY_UI_PLAN.md')
| -rw-r--r-- | DISPLAY_UI_PLAN.md | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/DISPLAY_UI_PLAN.md b/DISPLAY_UI_PLAN.md new file mode 100644 index 0000000..e78db44 --- /dev/null +++ b/DISPLAY_UI_PLAN.md | |||
| @@ -0,0 +1,165 @@ | |||
| 1 | # TollGate Display UI Design | ||
| 2 | |||
| 3 | ## Display Hardware | ||
| 4 | - **Panel:** 3.5" IPS, 320x480 portrait (AXS15231B QSPI) | ||
| 5 | - **Font:** 8x8 bitmap, scalable (1x=8px, 2x=16px, 3x=24px) | ||
| 6 | - **Capabilities:** Text rendering, QR codes, filled rectangles | ||
| 7 | - **No touch input** — display is output-only signage | ||
| 8 | |||
| 9 | ## Color Palette | ||
| 10 | |||
| 11 | | Color | RGB565 | Usage | | ||
| 12 | |-------|--------|-------| | ||
| 13 | | Black | `0x0000` | Background | | ||
| 14 | | White | `0xFFFF` | Primary text | | ||
| 15 | | Cyan | `0x07FF` | Titles, labels | | ||
| 16 | | Yellow | `0xFFE0` | Price, warnings | | ||
| 17 | | Green | `0x07E0` | Success, wallet OK | | ||
| 18 | | Orange | `0xFD20` | Accent (Bitcoin orange) | | ||
| 19 | | Red | `0xF800` | Errors, alerts | | ||
| 20 | | Dim gray | `0x8410` | Secondary info | | ||
| 21 | |||
| 22 | ## Screen States | ||
| 23 | |||
| 24 | ### 1. BOOT | ||
| 25 | Shown during startup until WiFi connects and services start. | ||
| 26 | |||
| 27 | ``` | ||
| 28 | ┌──────────────────────────┐ | ||
| 29 | │ TollGate │ cyan, scale 2 | ||
| 30 | │ connecting... │ yellow, scale 1 | ||
| 31 | │ WiFi: trying... │ dim, scale 1 | ||
| 32 | └──────────────────────────┘ | ||
| 33 | ``` | ||
| 34 | |||
| 35 | ### 2. READY — QR Cycling | ||
| 36 | Cycles every 5 seconds between WiFi QR and Portal QR. | ||
| 37 | |||
| 38 | **View A — WiFi QR:** | ||
| 39 | ``` | ||
| 40 | ┌──────────────────────────┐ | ||
| 41 | │ ┌──────┐ │ | ||
| 42 | │ │ QR │ │ WIFI:S:<ssid>;T:nopass;; | ||
| 43 | │ └──────┘ │ | ||
| 44 | │ Scan to connect │ cyan | ||
| 45 | │ SSID: TollGate-XXXX │ white | ||
| 46 | │ 21 sats/min │ orange | ||
| 47 | │ Wallet: 420 sats │ green/yellow/red | ||
| 48 | └──────────────────────────┘ | ||
| 49 | ``` | ||
| 50 | |||
| 51 | **View B — Portal QR:** | ||
| 52 | ``` | ||
| 53 | ┌──────────────────────────┐ | ||
| 54 | │ ┌──────┐ │ | ||
| 55 | │ │ QR │ │ http://10.x.x.x/ | ||
| 56 | │ └──────┘ │ | ||
| 57 | │ Portal URL │ cyan | ||
| 58 | │ Mint: testnut... │ orange | ||
| 59 | │ 21 sats/min │ orange | ||
| 60 | │ Clients: 3 │ green | ||
| 61 | └──────────────────────────┘ | ||
| 62 | ``` | ||
| 63 | |||
| 64 | ### 3. PAYMENT_RECEIVED | ||
| 65 | Shows for 3 seconds after payment, then returns to READY. | ||
| 66 | |||
| 67 | ``` | ||
| 68 | ┌──────────────────────────┐ | ||
| 69 | │ ████████████████████ │ green bar | ||
| 70 | │ ACCESS GRANTED │ white on green, scale 2 | ||
| 71 | │ ████████████████████ │ | ||
| 72 | │ Paid: 42 sats │ white | ||
| 73 | │ Time: 2 min │ white | ||
| 74 | │ Wallet: 462 sats │ green | ||
| 75 | └──────────────────────────┘ | ||
| 76 | ``` | ||
| 77 | |||
| 78 | ### 4. ERROR | ||
| 79 | Shown when upstream WiFi is disconnected. | ||
| 80 | |||
| 81 | ``` | ||
| 82 | ┌──────────────────────────┐ | ||
| 83 | │ ████████████████████ │ red bar | ||
| 84 | │ NO UPSTREAM │ white on red, scale 2 | ||
| 85 | │ ████████████████████ │ | ||
| 86 | │ Internet unavailable │ white | ||
| 87 | │ Check WiFi config │ yellow | ||
| 88 | │ AP still active │ green | ||
| 89 | │ SSID: TollGate-XXXX │ dim | ||
| 90 | └──────────────────────────┘ | ||
| 91 | ``` | ||
| 92 | |||
| 93 | ## State Synchronization | ||
| 94 | |||
| 95 | ### Data sources and update triggers | ||
| 96 | |||
| 97 | | Display data | Source function | Update trigger | | ||
| 98 | |-------------|----------------|----------------| | ||
| 99 | | SSID | `config.ap_ssid` | Once at `start_services()` | | ||
| 100 | | Portal URL | `config.ap_ip_str` | Once at `start_services()` | | ||
| 101 | | Mint URL | `config.mint_url` | Once at `start_services()` | | ||
| 102 | | Price | `config.price_per_step` | Once at `start_services()` | | ||
| 103 | | **Wallet balance** | `nucula_wallet_balance()` | **Every 5s in main loop** | | ||
| 104 | | **Client count** | `session_active_count()` | **Every 5s in main loop + AP events** | | ||
| 105 | | **Last payment** | `display_notify_payment()` | **On each payment in API handler** | | ||
| 106 | | WiFi status | Event handler | On STA connect/disconnect | | ||
| 107 | |||
| 108 | ### State transitions | ||
| 109 | |||
| 110 | ``` | ||
| 111 | app_main() | ||
| 112 | └─ display_set_state(BOOT) | ||
| 113 | └─ display_update(price, mint, ssid) ← config data available after config_init | ||
| 114 | |||
| 115 | wifi_event_handler(STA_DISCONNECTED) | ||
| 116 | └─ display_set_state(ERROR) | ||
| 117 | └─ display_update(wifi_status="retrying...") | ||
| 118 | |||
| 119 | ip_event_handler(STA_GOT_IP) | ||
| 120 | └─ start_services() | ||
| 121 | └─ display_set_state(READY) | ||
| 122 | └─ display_update(ssid, portal_url, mint, price) | ||
| 123 | |||
| 124 | tollgate_api (POST / payment) | ||
| 125 | └─ session_create() | ||
| 126 | └─ nucula_wallet_receive() | ||
| 127 | └─ display_notify_payment(amount_sats, allotment) ← NEW | ||
| 128 | └─ display_set_state(PAYMENT_RECEIVED) | ||
| 129 | |||
| 130 | display_task (3s timeout) | ||
| 131 | └─ auto-return PAYMENT_RECEIVED → READY | ||
| 132 | |||
| 133 | app_main() main loop (every 5s) | ||
| 134 | └─ display_update(wallet_balance, client_count) ← NEW periodic refresh | ||
| 135 | ``` | ||
| 136 | |||
| 137 | ### New API: `display_notify_payment()` | ||
| 138 | |||
| 139 | ```c | ||
| 140 | void display_notify_payment(int amount_sats, int64_t allotment_ms); | ||
| 141 | ``` | ||
| 142 | |||
| 143 | Stores the last payment amount and time purchased for the PAYMENT screen to display. | ||
| 144 | |||
| 145 | ## Implementation Checklist | ||
| 146 | |||
| 147 | ### Done | ||
| 148 | - [x] QSPI driver working with correct colors (DMA byte-swap + RAMWR) | ||
| 149 | - [x] BOOT screen with title and WiFi status | ||
| 150 | - [x] READY screen with QR cycling, price, mint, balance, clients | ||
| 151 | - [x] PAYMENT screen layout (green banner, amount, time, wallet) | ||
| 152 | - [x] ERROR screen layout (red banner, guidance, AP status) | ||
| 153 | - [x] WiFi disconnect → ERROR state transition | ||
| 154 | - [x] WiFi connect → READY state transition | ||
| 155 | |||
| 156 | ### TODO — State Sync | ||
| 157 | - [ ] Periodic display data refresh in main loop (wallet balance, client count every 5s) | ||
| 158 | - [ ] `display_notify_payment()` API to pass payment amount and allotment | ||
| 159 | - [ ] Call `display_set_state(PAYMENT_RECEIVED)` from tollgate_api.c after payment | ||
| 160 | - [ ] Pass config data (price, mint) to display during boot phase | ||
| 161 | - [ ] Update client count on AP station connect/disconnect events | ||
| 162 | |||
| 163 | ### TODO — Polish | ||
| 164 | - [ ] Run `make test-unit` to check for regressions | ||
| 165 | - [ ] Commit, push, prepare for merge | ||