diff options
| author | Your Name <you@example.com> | 2026-05-18 19:25:32 +0530 |
|---|---|---|
| committer | Your Name <you@example.com> | 2026-05-18 19:25:32 +0530 |
| commit | e1da6ffc0221abf4d0fb3a8c3e6be0b90d69397a (patch) | |
| tree | 3a0055b5af2bb09492c8c38fdf2712922ecc7123 | |
| parent | f0f8cca10196b265c3b453f71322239d2ecaf4ae (diff) | |
Implement full TollGate display UI
- BOOT screen: centered title + WiFi status line
- READY screen: QR cycling (WiFi/Portal), price, mint domain,
wallet balance (color-coded), client count
- PAYMENT screen: green banner 'ACCESS GRANTED', paid amount, time
- ERROR screen: red banner 'NO UPSTREAM', guidance, AP reassurance
- Enhanced display_update() API with mint_url, price, wifi_status
- Extract domain helper for clean mint URL display
- Render interval: 2s (reduced SPI load)
- Color palette: cyan, yellow, orange, green, red, dim gray
- WiFi events update display status and trigger ERROR state
- Board C now on /dev/ttyACM3
| -rw-r--r-- | DISPLAY_UI_PLAN.md | 136 | ||||
| -rw-r--r-- | main/display.c | 168 | ||||
| -rw-r--r-- | main/display.h | 4 | ||||
| -rw-r--r-- | main/tollgate_main.c | 9 |
4 files changed, 285 insertions, 32 deletions
diff --git a/DISPLAY_UI_PLAN.md b/DISPLAY_UI_PLAN.md new file mode 100644 index 0000000..3050b8a --- /dev/null +++ b/DISPLAY_UI_PLAN.md | |||
| @@ -0,0 +1,136 @@ | |||
| 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 | | Dark bg | `0x2104` | Card backgrounds | | ||
| 22 | |||
| 23 | ## Screen States | ||
| 24 | |||
| 25 | ### 1. BOOT | ||
| 26 | Shown during startup until WiFi connects and services start. | ||
| 27 | |||
| 28 | ``` | ||
| 29 | ┌──────────────────────────┐ 0 | ||
| 30 | │ │ | ||
| 31 | │ TollGate │ y=180, cyan, scale 2 | ||
| 32 | │ connecting... │ y=205, yellow, scale 1 | ||
| 33 | │ │ | ||
| 34 | │ WiFi: trying... │ y=260, dim, scale 1 | ||
| 35 | │ │ | ||
| 36 | └──────────────────────────┘ 479 | ||
| 37 | ``` | ||
| 38 | |||
| 39 | WiFi status line shows: "trying...", "connected!", "failed (retry)" | ||
| 40 | |||
| 41 | ### 2. READY — QR Cycling (primary screen) | ||
| 42 | Cycles every 5 seconds between WiFi QR and Portal QR. | ||
| 43 | |||
| 44 | **View A — WiFi QR:** | ||
| 45 | ``` | ||
| 46 | ┌──────────────────────────┐ 0 | ||
| 47 | │ ┌──────┐ │ | ||
| 48 | │ │ QR │ │ QR: WIFI:S:<ssid>;T:nopass;; | ||
| 49 | │ │ │ │ Centered in top 2/3 of screen | ||
| 50 | │ └──────┘ │ | ||
| 51 | │ │ ~y=320 | ||
| 52 | │ Scan to connect │ cyan, scale 1 | ||
| 53 | │ SSID: TollGate-XXXX │ white, scale 1 | ||
| 54 | │ 21 sats/min │ orange, scale 1 | ||
| 55 | │ Wallet: 420 sats │ green, scale 1 | ||
| 56 | └──────────────────────────┘ 479 | ||
| 57 | ``` | ||
| 58 | |||
| 59 | **View B — Portal QR:** | ||
| 60 | ``` | ||
| 61 | ┌──────────────────────────┐ 0 | ||
| 62 | │ ┌──────┐ │ | ||
| 63 | │ │ QR │ │ QR: http://10.x.x.x/ | ||
| 64 | │ │ │ │ | ||
| 65 | │ └──────┘ │ | ||
| 66 | │ │ ~y=320 | ||
| 67 | │ Portal URL │ cyan, scale 1 | ||
| 68 | │ testnut.cashu.space │ orange, scale 1 (mint domain) | ||
| 69 | │ 21 sats/min │ yellow, scale 1 | ||
| 70 | │ Clients: 3 │ green, scale 1 | ||
| 71 | └──────────────────────────┘ 479 | ||
| 72 | ``` | ||
| 73 | |||
| 74 | ### 3. PAYMENT_RECEIVED | ||
| 75 | Shows for 3 seconds after payment, then returns to READY. | ||
| 76 | |||
| 77 | ``` | ||
| 78 | ┌──────────────────────────┐ 0 | ||
| 79 | │ │ | ||
| 80 | │ ████████████████████ │ green filled bar, y=190..230 | ||
| 81 | │ ACCESS GRANTED │ white on green, scale 2 | ||
| 82 | │ ████████████████████ │ | ||
| 83 | │ │ | ||
| 84 | │ Paid: 21 sats │ white, scale 1 | ||
| 85 | │ Time: 1 min │ white, scale 1 | ||
| 86 | │ │ | ||
| 87 | │ Wallet: 441 sats │ green, scale 1 | ||
| 88 | └──────────────────────────┘ 479 | ||
| 89 | ``` | ||
| 90 | |||
| 91 | ### 4. ERROR | ||
| 92 | Shown when upstream WiFi is disconnected. | ||
| 93 | |||
| 94 | ``` | ||
| 95 | ┌──────────────────────────┐ 0 | ||
| 96 | │ ████████████████████ │ red filled bar, y=190..230 | ||
| 97 | │ NO UPSTREAM │ white on red, scale 2 | ||
| 98 | │ ████████████████████ │ | ||
| 99 | │ │ | ||
| 100 | │ Internet unavailable │ white, scale 1 | ||
| 101 | │ Check WiFi config │ yellow, scale 1 | ||
| 102 | │ │ | ||
| 103 | │ AP still active │ green, scale 1 | ||
| 104 | │ SSID: TollGate-XXXX │ dim, scale 1 | ||
| 105 | └──────────────────────────┘ 479 | ||
| 106 | ``` | ||
| 107 | |||
| 108 | ## Data Flow | ||
| 109 | |||
| 110 | ### display_update() receives: | ||
| 111 | ```c | ||
| 112 | void display_update(const char *ap_ssid, int active_clients, | ||
| 113 | uint64_t wallet_balance, const char *portal_url); | ||
| 114 | ``` | ||
| 115 | |||
| 116 | ### Enhanced to also receive: | ||
| 117 | ```c | ||
| 118 | void display_update(const char *ap_ssid, int active_clients, | ||
| 119 | uint64_t wallet_balance, const char *portal_url, | ||
| 120 | const char *mint_url, int price_per_step, | ||
| 121 | const char *wifi_status); | ||
| 122 | ``` | ||
| 123 | |||
| 124 | ### display_set_state() triggers: | ||
| 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 | |||
| 130 | ## Implementation Notes | ||
| 131 | |||
| 132 | - Render every 2 seconds (reduces SPI bus load vs 1 second) | ||
| 133 | - QR codes: auto-size based on string length, centered in top portion | ||
| 134 | - Mint URL: show only domain part (truncate at first `/`) | ||
| 135 | - Wallet balance: color-coded (green > 100, yellow > 0, red = 0) | ||
| 136 | - Client count: "Clients: N" or empty string if 0 | ||
diff --git a/main/display.c b/main/display.c index 0b641ea..add97db 100644 --- a/main/display.c +++ b/main/display.c | |||
| @@ -12,18 +12,28 @@ | |||
| 12 | static const char *TAG = "display"; | 12 | static const char *TAG = "display"; |
| 13 | 13 | ||
| 14 | #define QR_CYCLE_MS 5000 | 14 | #define QR_CYCLE_MS 5000 |
| 15 | #define RENDER_INTERVAL_MS 2000 | ||
| 16 | |||
| 17 | #define COLOR_BG 0x0000 | ||
| 18 | #define COLOR_WHITE 0xFFFF | ||
| 19 | #define COLOR_CYAN 0x07FF | ||
| 20 | #define COLOR_YELLOW 0xFFE0 | ||
| 21 | #define COLOR_GREEN 0x07E0 | ||
| 22 | #define COLOR_ORANGE 0xFD20 | ||
| 23 | #define COLOR_RED 0xF800 | ||
| 24 | #define COLOR_DIM 0x8410 | ||
| 15 | 25 | ||
| 16 | static volatile display_state_t s_state = DISPLAY_BOOT; | 26 | static volatile display_state_t s_state = DISPLAY_BOOT; |
| 17 | static char s_ap_ssid[32] = ""; | 27 | static char s_ap_ssid[32] = ""; |
| 18 | static char s_portal_url[256] = ""; | 28 | static char s_portal_url[256] = ""; |
| 29 | static char s_mint_url[256] = ""; | ||
| 30 | static char s_wifi_status[32] = "starting..."; | ||
| 19 | static int s_active_clients = 0; | 31 | static int s_active_clients = 0; |
| 20 | static uint64_t s_wallet_balance = 0; | 32 | static uint64_t s_wallet_balance = 0; |
| 33 | static int s_price_per_step = 0; | ||
| 21 | static bool s_initialized = false; | 34 | static bool s_initialized = false; |
| 22 | static int64_t s_last_qr_switch = 0; | 35 | static int64_t s_last_qr_switch = 0; |
| 23 | static display_qr_mode_t s_qr_mode = DISPLAY_QR_WIFI; | 36 | static display_qr_mode_t s_qr_mode = DISPLAY_QR_WIFI; |
| 24 | static display_state_t s_rendered_state = DISPLAY_BOOT; | ||
| 25 | static display_qr_mode_t s_rendered_qr_mode = DISPLAY_QR_WIFI; | ||
| 26 | static bool s_force_render = true; | ||
| 27 | 37 | ||
| 28 | static int qr_version_from_strlen(int len) { | 38 | static int qr_version_from_strlen(int len) { |
| 29 | if (len <= 17) return 1; | 39 | if (len <= 17) return 1; |
| @@ -68,6 +78,16 @@ static void build_wifi_qr_string(char *out, int out_size) { | |||
| 68 | snprintf(out, out_size, "WIFI:S:%s;T:nopass;;", escaped_ssid); | 78 | snprintf(out, out_size, "WIFI:S:%s;T:nopass;;", escaped_ssid); |
| 69 | } | 79 | } |
| 70 | 80 | ||
| 81 | static void extract_domain(const char *url, char *domain, int domain_size) { | ||
| 82 | const char *start = url; | ||
| 83 | if (strncmp(url, "https://", 8) == 0) start = url + 8; | ||
| 84 | else if (strncmp(url, "http://", 7) == 0) start = url + 7; | ||
| 85 | strncpy(domain, start, domain_size - 1); | ||
| 86 | domain[domain_size - 1] = '\0'; | ||
| 87 | char *slash = strchr(domain, '/'); | ||
| 88 | if (slash) *slash = '\0'; | ||
| 89 | } | ||
| 90 | |||
| 71 | void display_render_text(int x, int y, const char *text, uint16_t fg, uint16_t bg, int scale) { | 91 | void display_render_text(int x, int y, const char *text, uint16_t fg, uint16_t bg, int scale) { |
| 72 | int cx = x; | 92 | int cx = x; |
| 73 | int cy = y; | 93 | int cy = y; |
| @@ -146,54 +166,134 @@ void display_render_qr(const char *text) { | |||
| 146 | axs15231b_flush(); | 166 | axs15231b_flush(); |
| 147 | } | 167 | } |
| 148 | 168 | ||
| 169 | static uint16_t wallet_color(void) { | ||
| 170 | if (s_wallet_balance == 0) return COLOR_RED; | ||
| 171 | if (s_wallet_balance < 100) return COLOR_YELLOW; | ||
| 172 | return COLOR_GREEN; | ||
| 173 | } | ||
| 174 | |||
| 149 | static void render_boot_screen(void) { | 175 | static void render_boot_screen(void) { |
| 150 | axs15231b_fill_screen(0x0000); | 176 | int screen_w = axs15231b_get_width(); |
| 151 | display_render_text(96, 220, "TollGate", 0x07FF, 0x0000, 2); | 177 | axs15231b_fill_screen(COLOR_BG); |
| 152 | display_render_text(116, 245, "starting...", 0xFFE0, 0x0000, 1); | 178 | |
| 179 | const char *title = "TollGate"; | ||
| 180 | int title_w = strlen(title) * 8 * 2; | ||
| 181 | display_render_text((screen_w - title_w) / 2, 200, title, COLOR_CYAN, COLOR_BG, 2); | ||
| 182 | |||
| 183 | int status_w = strlen(s_wifi_status) * 8; | ||
| 184 | display_render_text((screen_w - status_w) / 2, 228, s_wifi_status, COLOR_YELLOW, COLOR_BG, 1); | ||
| 185 | |||
| 153 | axs15231b_flush(); | 186 | axs15231b_flush(); |
| 154 | } | 187 | } |
| 155 | 188 | ||
| 156 | static void render_ready_screen(void) { | 189 | static void render_ready_screen(void) { |
| 157 | axs15231b_fill_screen(0x0000); | ||
| 158 | |||
| 159 | int screen_w = axs15231b_get_width(); | 190 | int screen_w = axs15231b_get_width(); |
| 160 | int screen_h = axs15231b_get_height(); | 191 | int text_area_y = 330; |
| 161 | int text_area_y = screen_h - 55; | 192 | axs15231b_fill_screen(COLOR_BG); |
| 162 | 193 | ||
| 163 | char qr_text[320]; | 194 | char qr_text[320]; |
| 164 | const char *label; | ||
| 165 | |||
| 166 | if (s_qr_mode == DISPLAY_QR_WIFI) { | 195 | if (s_qr_mode == DISPLAY_QR_WIFI) { |
| 167 | build_wifi_qr_string(qr_text, sizeof(qr_text)); | 196 | build_wifi_qr_string(qr_text, sizeof(qr_text)); |
| 168 | label = "Scan to connect"; | ||
| 169 | } else { | 197 | } else { |
| 170 | strncpy(qr_text, s_portal_url, sizeof(qr_text) - 1); | 198 | strncpy(qr_text, s_portal_url, sizeof(qr_text) - 1); |
| 171 | qr_text[sizeof(qr_text) - 1] = '\0'; | 199 | qr_text[sizeof(qr_text) - 1] = '\0'; |
| 172 | label = "Portal URL"; | ||
| 173 | } | 200 | } |
| 174 | 201 | ||
| 175 | render_qr_at(qr_text, 0, 0, screen_w, text_area_y - 5); | 202 | render_qr_at(qr_text, 0, 5, screen_w, text_area_y - 10); |
| 176 | 203 | ||
| 177 | display_render_text(10, text_area_y, label, 0xB5B6, 0x0000, 2); | 204 | int y = text_area_y; |
| 205 | char line[48]; | ||
| 178 | 206 | ||
| 179 | char line[64]; | 207 | if (s_qr_mode == DISPLAY_QR_WIFI) { |
| 180 | snprintf(line, sizeof(line), "SSID: %s", s_ap_ssid); | 208 | snprintf(line, sizeof(line), "Scan to connect"); |
| 181 | display_render_text(10, text_area_y + 20, line, 0xB5B6, 0x0000, 2); | 209 | display_render_text(10, y, line, COLOR_CYAN, COLOR_BG, 1); |
| 210 | y += 16; | ||
| 211 | |||
| 212 | snprintf(line, sizeof(line), "SSID: %s", s_ap_ssid); | ||
| 213 | display_render_text(10, y, line, COLOR_WHITE, COLOR_BG, 1); | ||
| 214 | y += 16; | ||
| 215 | } else { | ||
| 216 | snprintf(line, sizeof(line), "Portal URL"); | ||
| 217 | display_render_text(10, y, line, COLOR_CYAN, COLOR_BG, 1); | ||
| 218 | y += 16; | ||
| 219 | |||
| 220 | char domain[48]; | ||
| 221 | extract_domain(s_mint_url, domain, sizeof(domain)); | ||
| 222 | snprintf(line, sizeof(line), "Mint: %.30s", domain); | ||
| 223 | display_render_text(10, y, line, COLOR_ORANGE, COLOR_BG, 1); | ||
| 224 | y += 16; | ||
| 225 | } | ||
| 226 | |||
| 227 | snprintf(line, sizeof(line), "%d sats/min", s_price_per_step); | ||
| 228 | display_render_text(10, y, line, COLOR_ORANGE, COLOR_BG, 1); | ||
| 229 | y += 16; | ||
| 230 | |||
| 231 | snprintf(line, sizeof(line), "Wallet: %llu sats", (unsigned long long)s_wallet_balance); | ||
| 232 | display_render_text(10, y, line, wallet_color(), COLOR_BG, 1); | ||
| 233 | y += 16; | ||
| 234 | |||
| 235 | if (s_active_clients > 0) { | ||
| 236 | snprintf(line, sizeof(line), "Clients: %d", s_active_clients); | ||
| 237 | display_render_text(10, y, line, COLOR_GREEN, COLOR_BG, 1); | ||
| 238 | } | ||
| 182 | 239 | ||
| 183 | axs15231b_flush(); | 240 | axs15231b_flush(); |
| 184 | } | 241 | } |
| 185 | 242 | ||
| 186 | static void render_payment_screen(void) { | 243 | static void render_payment_screen(void) { |
| 187 | axs15231b_fill_screen(0x07E0); | 244 | int screen_w = axs15231b_get_width(); |
| 188 | display_render_text(128, 225, "Paid!", 0x0000, 0x07E0, 2); | 245 | axs15231b_fill_screen(COLOR_BG); |
| 189 | display_render_text(104, 245, "Access granted", 0x0000, 0x07E0, 1); | 246 | |
| 247 | axs15231b_fill_rect(0, 190, screen_w, 50, COLOR_GREEN); | ||
| 248 | const char *msg = "ACCESS GRANTED"; | ||
| 249 | int msg_w = strlen(msg) * 8 * 2; | ||
| 250 | display_render_text((screen_w - msg_w) / 2, 202, msg, COLOR_WHITE, COLOR_GREEN, 2); | ||
| 251 | |||
| 252 | char line[48]; | ||
| 253 | |||
| 254 | snprintf(line, sizeof(line), "Paid: %d sats", s_price_per_step); | ||
| 255 | int lw = strlen(line) * 8; | ||
| 256 | display_render_text((screen_w - lw) / 2, 270, line, COLOR_WHITE, COLOR_BG, 1); | ||
| 257 | |||
| 258 | const char *time_msg = "Time: 1 min"; | ||
| 259 | int tw = strlen(time_msg) * 8; | ||
| 260 | display_render_text((screen_w - tw) / 2, 290, time_msg, COLOR_WHITE, COLOR_BG, 1); | ||
| 261 | |||
| 262 | snprintf(line, sizeof(line), "Wallet: %llu sats", (unsigned long long)s_wallet_balance); | ||
| 263 | lw = strlen(line) * 8; | ||
| 264 | display_render_text((screen_w - lw) / 2, 320, line, wallet_color(), COLOR_BG, 1); | ||
| 265 | |||
| 190 | axs15231b_flush(); | 266 | axs15231b_flush(); |
| 191 | } | 267 | } |
| 192 | 268 | ||
| 193 | static void render_error_screen(void) { | 269 | static void render_error_screen(void) { |
| 194 | axs15231b_fill_screen(0xF800); | 270 | int screen_w = axs15231b_get_width(); |
| 195 | display_render_text(104, 225, "No upstream", 0xFFFF, 0xF800, 2); | 271 | axs15231b_fill_screen(COLOR_BG); |
| 196 | display_render_text(120, 245, "Check config", 0xFFFF, 0xF800, 1); | 272 | |
| 273 | axs15231b_fill_rect(0, 190, screen_w, 50, COLOR_RED); | ||
| 274 | const char *msg = "NO UPSTREAM"; | ||
| 275 | int msg_w = strlen(msg) * 8 * 2; | ||
| 276 | display_render_text((screen_w - msg_w) / 2, 202, msg, COLOR_WHITE, COLOR_RED, 2); | ||
| 277 | |||
| 278 | char line[48]; | ||
| 279 | int lw; | ||
| 280 | |||
| 281 | const char *l1 = "Internet unavailable"; | ||
| 282 | lw = strlen(l1) * 8; | ||
| 283 | display_render_text((screen_w - lw) / 2, 270, l1, COLOR_WHITE, COLOR_BG, 1); | ||
| 284 | |||
| 285 | const char *l2 = "Check WiFi config"; | ||
| 286 | lw = strlen(l2) * 8; | ||
| 287 | display_render_text((screen_w - lw) / 2, 290, l2, COLOR_YELLOW, COLOR_BG, 1); | ||
| 288 | |||
| 289 | const char *l3 = "AP still active"; | ||
| 290 | lw = strlen(l3) * 8; | ||
| 291 | display_render_text((screen_w - lw) / 2, 320, l3, COLOR_GREEN, COLOR_BG, 1); | ||
| 292 | |||
| 293 | snprintf(line, sizeof(line), "SSID: %s", s_ap_ssid); | ||
| 294 | lw = strlen(line) * 8; | ||
| 295 | display_render_text((screen_w - lw) / 2, 340, line, COLOR_DIM, COLOR_BG, 1); | ||
| 296 | |||
| 197 | axs15231b_flush(); | 297 | axs15231b_flush(); |
| 198 | } | 298 | } |
| 199 | 299 | ||
| @@ -220,7 +320,7 @@ static void display_task(void *pvParameters) { | |||
| 220 | break; | 320 | break; |
| 221 | case DISPLAY_PAYMENT_RECEIVED: | 321 | case DISPLAY_PAYMENT_RECEIVED: |
| 222 | render_payment_screen(); | 322 | render_payment_screen(); |
| 223 | vTaskDelay(pdMS_TO_TICKS(2000)); | 323 | vTaskDelay(pdMS_TO_TICKS(3000)); |
| 224 | s_state = DISPLAY_READY; | 324 | s_state = DISPLAY_READY; |
| 225 | break; | 325 | break; |
| 226 | case DISPLAY_ERROR: | 326 | case DISPLAY_ERROR: |
| @@ -228,7 +328,7 @@ static void display_task(void *pvParameters) { | |||
| 228 | break; | 328 | break; |
| 229 | } | 329 | } |
| 230 | 330 | ||
| 231 | vTaskDelay(pdMS_TO_TICKS(1000)); | 331 | vTaskDelay(pdMS_TO_TICKS(RENDER_INTERVAL_MS)); |
| 232 | } | 332 | } |
| 233 | } | 333 | } |
| 234 | 334 | ||
| @@ -252,11 +352,12 @@ esp_err_t display_init(void) { | |||
| 252 | 352 | ||
| 253 | void display_set_state(display_state_t state) { | 353 | void display_set_state(display_state_t state) { |
| 254 | s_state = state; | 354 | s_state = state; |
| 255 | s_force_render = true; | ||
| 256 | } | 355 | } |
| 257 | 356 | ||
| 258 | void display_update(const char *ap_ssid, int active_clients, | 357 | void display_update(const char *ap_ssid, int active_clients, |
| 259 | uint64_t wallet_balance, const char *portal_url) { | 358 | uint64_t wallet_balance, const char *portal_url, |
| 359 | const char *mint_url, int price_per_step, | ||
| 360 | const char *wifi_status) { | ||
| 260 | if (ap_ssid) { | 361 | if (ap_ssid) { |
| 261 | strncpy(s_ap_ssid, ap_ssid, sizeof(s_ap_ssid) - 1); | 362 | strncpy(s_ap_ssid, ap_ssid, sizeof(s_ap_ssid) - 1); |
| 262 | s_ap_ssid[sizeof(s_ap_ssid) - 1] = '\0'; | 363 | s_ap_ssid[sizeof(s_ap_ssid) - 1] = '\0'; |
| @@ -265,6 +366,15 @@ void display_update(const char *ap_ssid, int active_clients, | |||
| 265 | strncpy(s_portal_url, portal_url, sizeof(s_portal_url) - 1); | 366 | strncpy(s_portal_url, portal_url, sizeof(s_portal_url) - 1); |
| 266 | s_portal_url[sizeof(s_portal_url) - 1] = '\0'; | 367 | s_portal_url[sizeof(s_portal_url) - 1] = '\0'; |
| 267 | } | 368 | } |
| 369 | if (mint_url) { | ||
| 370 | strncpy(s_mint_url, mint_url, sizeof(s_mint_url) - 1); | ||
| 371 | s_mint_url[sizeof(s_mint_url) - 1] = '\0'; | ||
| 372 | } | ||
| 373 | if (wifi_status) { | ||
| 374 | strncpy(s_wifi_status, wifi_status, sizeof(s_wifi_status) - 1); | ||
| 375 | s_wifi_status[sizeof(s_wifi_status) - 1] = '\0'; | ||
| 376 | } | ||
| 377 | if (price_per_step > 0) s_price_per_step = price_per_step; | ||
| 268 | s_active_clients = active_clients; | 378 | s_active_clients = active_clients; |
| 269 | s_wallet_balance = wallet_balance; | 379 | s_wallet_balance = wallet_balance; |
| 270 | } | 380 | } |
diff --git a/main/display.h b/main/display.h index 407521b..1530e57 100644 --- a/main/display.h +++ b/main/display.h | |||
| @@ -20,7 +20,9 @@ typedef enum { | |||
| 20 | esp_err_t display_init(void); | 20 | esp_err_t display_init(void); |
| 21 | void display_set_state(display_state_t state); | 21 | void display_set_state(display_state_t state); |
| 22 | void display_update(const char *ap_ssid, int active_clients, | 22 | void display_update(const char *ap_ssid, int active_clients, |
| 23 | uint64_t wallet_balance, const char *portal_url); | 23 | uint64_t wallet_balance, const char *portal_url, |
| 24 | const char *mint_url, int price_per_step, | ||
| 25 | const char *wifi_status); | ||
| 24 | void display_render_text(int x, int y, const char *text, uint16_t fg, uint16_t bg, int scale); | 26 | void display_render_text(int x, int y, const char *text, uint16_t fg, uint16_t bg, int scale); |
| 25 | void display_render_qr(const char *text); | 27 | void display_render_qr(const char *text); |
| 26 | 28 | ||
diff --git a/main/tollgate_main.c b/main/tollgate_main.c index c0ff65f..7fd50ad 100644 --- a/main/tollgate_main.c +++ b/main/tollgate_main.c | |||
| @@ -54,7 +54,11 @@ static void wifi_event_handler(void *arg, esp_event_base_t event_base, | |||
| 54 | s_retry_count++; | 54 | s_retry_count++; |
| 55 | ESP_LOGW(TAG, "WiFi disconnected, retry %d/%d", s_retry_count, MAX_STA_RETRY); | 55 | ESP_LOGW(TAG, "WiFi disconnected, retry %d/%d", s_retry_count, MAX_STA_RETRY); |
| 56 | tollgate_client_on_sta_disconnected(); | 56 | tollgate_client_on_sta_disconnected(); |
| 57 | if (s_services_running) stop_services(); | 57 | if (s_services_running) { |
| 58 | stop_services(); | ||
| 59 | display_set_state(DISPLAY_ERROR); | ||
| 60 | } | ||
| 61 | display_update(NULL, 0, 0, NULL, NULL, 0, "WiFi retry..."); | ||
| 58 | if (s_retry_count < MAX_STA_RETRY) { | 62 | if (s_retry_count < MAX_STA_RETRY) { |
| 59 | esp_wifi_connect(); | 63 | esp_wifi_connect(); |
| 60 | } else { | 64 | } else { |
| @@ -173,7 +177,8 @@ static void start_services(void) | |||
| 173 | display_set_state(DISPLAY_READY); | 177 | display_set_state(DISPLAY_READY); |
| 174 | char portal_url[128]; | 178 | char portal_url[128]; |
| 175 | snprintf(portal_url, sizeof(portal_url), "http://%s/", cfg->ap_ip_str); | 179 | snprintf(portal_url, sizeof(portal_url), "http://%s/", cfg->ap_ip_str); |
| 176 | display_update(cfg->ap_ssid, 0, 0, portal_url); | 180 | display_update(cfg->ap_ssid, 0, 0, portal_url, |
| 181 | cfg->mint_url, cfg->price_per_step, NULL); | ||
| 177 | } | 182 | } |
| 178 | 183 | ||
| 179 | static void stop_services(void) | 184 | static void stop_services(void) |