diff options
| author | Your Name <you@example.com> | 2026-05-18 19:58:12 +0530 |
|---|---|---|
| committer | Your Name <you@example.com> | 2026-05-18 19:58:12 +0530 |
| commit | 7820837d79ebc8e00221b5206bdd8e3ca0ae4c15 (patch) | |
| tree | 98070e83e4e8bfa0b46009d202e7b81410c960f6 /DISPLAY_UI_PLAN.md | |
| parent | 7dd532cee475d486552e886dd7173c8853f80b60 (diff) | |
Sync display with live TollGate state
- Periodic refresh: wallet balance + client count every 5s from main loop
- display_notify_payment() API: passes payment amount and time allotment
- tollgate_api.c: triggers PAYMENT_RECEIVED state after wallet receive
- AP station events update client count in real-time
- Config data (price, mint) passed to display during boot phase
- Payment screen shows actual sats paid and time purchased
- Updated DISPLAY_UI_PLAN.md with state-sync audit and checklist
Diffstat (limited to 'DISPLAY_UI_PLAN.md')
| -rw-r--r-- | DISPLAY_UI_PLAN.md | 171 |
1 files changed, 100 insertions, 71 deletions
diff --git a/DISPLAY_UI_PLAN.md b/DISPLAY_UI_PLAN.md index 3050b8a..e78db44 100644 --- a/DISPLAY_UI_PLAN.md +++ b/DISPLAY_UI_PLAN.md | |||
| @@ -18,7 +18,6 @@ | |||
| 18 | | Orange | `0xFD20` | Accent (Bitcoin orange) | | 18 | | Orange | `0xFD20` | Accent (Bitcoin orange) | |
| 19 | | Red | `0xF800` | Errors, alerts | | 19 | | Red | `0xF800` | Errors, alerts | |
| 20 | | Dim gray | `0x8410` | Secondary info | | 20 | | Dim gray | `0x8410` | Secondary info | |
| 21 | | Dark bg | `0x2104` | Card backgrounds | | ||
| 22 | 21 | ||
| 23 | ## Screen States | 22 | ## Screen States |
| 24 | 23 | ||
| @@ -26,111 +25,141 @@ | |||
| 26 | Shown during startup until WiFi connects and services start. | 25 | Shown during startup until WiFi connects and services start. |
| 27 | 26 | ||
| 28 | ``` | 27 | ``` |
| 29 | ┌──────────────────────────┐ 0 | 28 | ┌──────────────────────────┐ |
| 30 | │ │ | 29 | │ TollGate │ cyan, scale 2 |
| 31 | │ TollGate │ y=180, cyan, scale 2 | 30 | │ connecting... │ yellow, scale 1 |
| 32 | │ connecting... │ y=205, yellow, scale 1 | 31 | │ WiFi: trying... │ dim, scale 1 |
| 33 | │ │ | 32 | └──────────────────────────┘ |
| 34 | │ WiFi: trying... │ y=260, dim, scale 1 | ||
| 35 | │ │ | ||
| 36 | └──────────────────────────┘ 479 | ||
| 37 | ``` | 33 | ``` |
| 38 | 34 | ||
| 39 | WiFi status line shows: "trying...", "connected!", "failed (retry)" | 35 | ### 2. READY — QR Cycling |
| 40 | |||
| 41 | ### 2. READY — QR Cycling (primary screen) | ||
| 42 | Cycles every 5 seconds between WiFi QR and Portal QR. | 36 | Cycles every 5 seconds between WiFi QR and Portal QR. |
| 43 | 37 | ||
| 44 | **View A — WiFi QR:** | 38 | **View A — WiFi QR:** |
| 45 | ``` | 39 | ``` |
| 46 | ┌──────────────────────────┐ 0 | 40 | ┌──────────────────────────┐ |
| 47 | │ ┌──────┐ │ | 41 | │ ┌──────┐ │ |
| 48 | │ │ QR │ │ QR: WIFI:S:<ssid>;T:nopass;; | 42 | │ │ QR │ │ WIFI:S:<ssid>;T:nopass;; |
| 49 | │ │ │ │ Centered in top 2/3 of screen | ||
| 50 | │ └──────┘ │ | 43 | │ └──────┘ │ |
| 51 | │ │ ~y=320 | 44 | │ Scan to connect │ cyan |
| 52 | │ Scan to connect │ cyan, scale 1 | 45 | │ SSID: TollGate-XXXX │ white |
| 53 | │ SSID: TollGate-XXXX │ white, scale 1 | 46 | │ 21 sats/min │ orange |
| 54 | │ 21 sats/min │ orange, scale 1 | 47 | │ Wallet: 420 sats │ green/yellow/red |
| 55 | │ Wallet: 420 sats │ green, scale 1 | 48 | └──────────────────────────┘ |
| 56 | └──────────────────────────┘ 479 | ||
| 57 | ``` | 49 | ``` |
| 58 | 50 | ||
| 59 | **View B — Portal QR:** | 51 | **View B — Portal QR:** |
| 60 | ``` | 52 | ``` |
| 61 | ┌──────────────────────────┐ 0 | 53 | ┌──────────────────────────┐ |
| 62 | │ ┌──────┐ │ | 54 | │ ┌──────┐ │ |
| 63 | │ │ QR │ │ QR: http://10.x.x.x/ | 55 | │ │ QR │ │ http://10.x.x.x/ |
| 64 | │ │ │ │ | ||
| 65 | │ └──────┘ │ | 56 | │ └──────┘ │ |
| 66 | │ │ ~y=320 | 57 | │ Portal URL │ cyan |
| 67 | │ Portal URL │ cyan, scale 1 | 58 | │ Mint: testnut... │ orange |
| 68 | │ testnut.cashu.space │ orange, scale 1 (mint domain) | 59 | │ 21 sats/min │ orange |
| 69 | │ 21 sats/min │ yellow, scale 1 | 60 | │ Clients: 3 │ green |
| 70 | │ Clients: 3 │ green, scale 1 | 61 | └──────────────────────────┘ |
| 71 | └──────────────────────────┘ 479 | ||
| 72 | ``` | 62 | ``` |
| 73 | 63 | ||
| 74 | ### 3. PAYMENT_RECEIVED | 64 | ### 3. PAYMENT_RECEIVED |
| 75 | Shows for 3 seconds after payment, then returns to READY. | 65 | Shows for 3 seconds after payment, then returns to READY. |
| 76 | 66 | ||
| 77 | ``` | 67 | ``` |
| 78 | ┌──────────────────────────┐ 0 | 68 | ┌──────────────────────────┐ |
| 79 | │ │ | 69 | │ ████████████████████ │ green bar |
| 80 | │ ████████████████████ │ green filled bar, y=190..230 | ||
| 81 | │ ACCESS GRANTED │ white on green, scale 2 | 70 | │ ACCESS GRANTED │ white on green, scale 2 |
| 82 | │ ████████████████████ │ | 71 | │ ████████████████████ │ |
| 83 | │ │ | 72 | │ Paid: 42 sats │ white |
| 84 | │ Paid: 21 sats │ white, scale 1 | 73 | │ Time: 2 min │ white |
| 85 | │ Time: 1 min │ white, scale 1 | 74 | │ Wallet: 462 sats │ green |
| 86 | │ │ | 75 | └──────────────────────────┘ |
| 87 | │ Wallet: 441 sats │ green, scale 1 | ||
| 88 | └──────────────────────────┘ 479 | ||
| 89 | ``` | 76 | ``` |
| 90 | 77 | ||
| 91 | ### 4. ERROR | 78 | ### 4. ERROR |
| 92 | Shown when upstream WiFi is disconnected. | 79 | Shown when upstream WiFi is disconnected. |
| 93 | 80 | ||
| 94 | ``` | 81 | ``` |
| 95 | ┌──────────────────────────┐ 0 | 82 | ┌──────────────────────────┐ |
| 96 | │ ████████████████████ │ red filled bar, y=190..230 | 83 | │ ████████████████████ │ red bar |
| 97 | │ NO UPSTREAM │ white on red, scale 2 | 84 | │ NO UPSTREAM │ white on red, scale 2 |
| 98 | │ ████████████████████ │ | 85 | │ ████████████████████ │ |
| 99 | │ │ | 86 | │ Internet unavailable │ white |
| 100 | │ Internet unavailable │ white, scale 1 | 87 | │ Check WiFi config │ yellow |
| 101 | │ Check WiFi config │ yellow, scale 1 | 88 | │ AP still active │ green |
| 102 | │ │ | 89 | │ SSID: TollGate-XXXX │ dim |
| 103 | │ AP still active │ green, scale 1 | 90 | └──────────────────────────┘ |
| 104 | │ SSID: TollGate-XXXX │ dim, scale 1 | ||
| 105 | └──────────────────────────┘ 479 | ||
| 106 | ``` | 91 | ``` |
| 107 | 92 | ||
| 108 | ## Data Flow | 93 | ## State Synchronization |
| 109 | 94 | ||
| 110 | ### display_update() receives: | 95 | ### Data sources and update triggers |
| 111 | ```c | ||
| 112 | void display_update(const char *ap_ssid, int active_clients, | ||
| 113 | uint64_t wallet_balance, const char *portal_url); | ||
| 114 | ``` | ||
| 115 | 96 | ||
| 116 | ### Enhanced to also receive: | 97 | | Display data | Source function | Update trigger | |
| 117 | ```c | 98 | |-------------|----------------|----------------| |
| 118 | void display_update(const char *ap_ssid, int active_clients, | 99 | | SSID | `config.ap_ssid` | Once at `start_services()` | |
| 119 | uint64_t wallet_balance, const char *portal_url, | 100 | | Portal URL | `config.ap_ip_str` | Once at `start_services()` | |
| 120 | const char *mint_url, int price_per_step, | 101 | | Mint URL | `config.mint_url` | Once at `start_services()` | |
| 121 | const char *wifi_status); | 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 | ||
| 122 | ``` | 135 | ``` |
| 123 | 136 | ||
| 124 | ### display_set_state() triggers: | 137 | ### New API: `display_notify_payment()` |
| 125 | - `DISPLAY_BOOT` → at startup | ||
| 126 | - `DISPLAY_READY` → when services start (WiFi connected) | ||
| 127 | - `DISPLAY_PAYMENT_RECEIVED` → on successful payment (auto-returns to READY) | ||
| 128 | - `DISPLAY_ERROR` → when upstream WiFi disconnects | ||
| 129 | 138 | ||
| 130 | ## Implementation Notes | 139 | ```c |
| 140 | void display_notify_payment(int amount_sats, int64_t allotment_ms); | ||
| 141 | ``` | ||
| 131 | 142 | ||
| 132 | - Render every 2 seconds (reduces SPI bus load vs 1 second) | 143 | Stores the last payment amount and time purchased for the PAYMENT screen to display. |
| 133 | - QR codes: auto-size based on string length, centered in top portion | 144 | |
| 134 | - Mint URL: show only domain part (truncate at first `/`) | 145 | ## Implementation Checklist |
| 135 | - Wallet balance: color-coded (green > 100, yellow > 0, red = 0) | 146 | |
| 136 | - Client count: "Clients: N" or empty string if 0 | 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 | ||