diff options
| author | Luke Hoersten <[email protected]> | 2026-06-14 20:11:21 -0500 |
|---|---|---|
| committer | Luke Hoersten <[email protected]> | 2026-06-14 20:11:21 -0500 |
| commit | 865c4859d710870245ae7954e729edcaf442a921 (patch) | |
| tree | c22cb7d60fb8ea3bba6e9e85b45779d0dfa87d4f /main | |
| parent | 8e2de89efb540fd6a3dce2086216d3afc49e6831 (diff) | |
Default name = MAC; brief wake on boot; drop dead touch defences
- Seed viewport_name with the full base MAC, colons stripped
(e8:f6:0a:e0:90:94 → "e8f60ae09094"). Stable across reboots, globally
unique, 12 alphanumeric chars — well inside the mDNS hostname limit
even with the "viewport-" prefix.
- Add a mac_str field to viewport_state and expose it as the new "mac"
key in GET /state and as a "mac" line on the info screen.
- "Configured" no longer requires a viewport_name (it always has the
MAC default); the scrypted URL alone gates outbound POSTs and the
loading-vs-info screen choice.
- Strip viewport_name[0] fallbacks in http_api / mdns / local_screens
now that the field is never empty.
- Replace the wake-on-boot-stays-on behaviour with a ~600 ms flash
followed by sleep — long enough for the FT5426 touch IC to come out
of its initial unresponsive state, short enough that an idle device
doesn't burn the backlight.
- Drop the touch defensive cruft added when we were chasing a PoE-power
theory: the DEV_MODE=0x00 write at init, the touch_reset_pulse() call
at init, and the runtime wedge-self-heal in the polling loop didn't
actually fix anything — the wake-on-boot flash did. Also delete the
display_touch_reset_pulse() helper since it now has zero callers.
Diffstat (limited to 'main')
| -rw-r--r-- | main/app_main.c | 13 | ||||
| -rw-r--r-- | main/display.c | 16 | ||||
| -rw-r--r-- | main/display.h | 5 | ||||
| -rw-r--r-- | main/http_api.c | 16 | ||||
| -rw-r--r-- | main/local_screens.c | 9 | ||||
| -rw-r--r-- | main/mdns_service.c | 13 | ||||
| -rw-r--r-- | main/nvs_config.c | 26 | ||||
| -rw-r--r-- | main/touch.c | 56 | ||||
| -rw-r--r-- | main/viewport_state.c | 20 | ||||
| -rw-r--r-- | main/viewport_state.h | 3 |
10 files changed, 70 insertions, 107 deletions
diff --git a/main/app_main.c b/main/app_main.c index c411c46..a60496d 100644 --- a/main/app_main.c +++ b/main/app_main.c @@ -103,13 +103,16 @@ static void display_setup_task(void *arg) ESP_LOGI(TAG, "display subsystems [%s] up", flags); - // Wake the display on boot. Empirically the FT5426 touch IC only - // reports contacts when the LCD is actively streaming with the - // backlight on — booting straight into ASLEEP leaves taps silently - // unread. The idle timer (idle_timeout_ms) puts the device back to - // sleep on its own if nothing happens. + // Briefly wake the display on boot so the FT5426 touch IC can come + // out of its initial unresponsive state — empirically it only + // reports contacts when the LCD has been actively streaming with + // the backlight on at least once since power-up. A 600 ms flash is + // enough; we then sleep so an idle device doesn't burn the + // backlight until the idle timer fires. if (dsp_err == ESP_OK) { state_machine_set(VIEWPORT_STATE_AWAKE); + vTaskDelay(pdMS_TO_TICKS(600)); + state_machine_set(VIEWPORT_STATE_ASLEEP); } vTaskDelete(NULL); diff --git a/main/display.c b/main/display.c index 8c5ffb2..a704891 100644 --- a/main/display.c +++ b/main/display.c @@ -218,22 +218,6 @@ static esp_err_t touch_release_reset(void) PC_LED_EN | PC_RST_TP_N | PC_RST_LCD_N | PC_RST_BRIDGE_N); } -// Hard-reset the touch IC: drop PC_RST_TP_N for ~20 ms, then release. -// touch_init() calls this if its dev_mode read keeps returning 0xff — -// usually unwedges a stuck FT5426 without needing a power cycle. -esp_err_t display_touch_reset_pulse(void) -{ - if (!s_panel_mcu) return ESP_ERR_INVALID_STATE; - // Hold touch in reset (clear PC_RST_TP_N), keep everything else as-is. - esp_err_t err = mcu_write_u8(REG_PORTC, - PC_LED_EN | PC_RST_LCD_N | PC_RST_BRIDGE_N); - if (err != ESP_OK) return err; - vTaskDelay(pdMS_TO_TICKS(20)); - err = touch_release_reset(); - vTaskDelay(pdMS_TO_TICKS(50)); - return err; -} - // ============================================================================ // TC358762 bridge configuration (DSI Generic Long Write packets) // Sequence mirrors Linux drivers/gpu/drm/bridge/tc358762.c tc358762_init(). diff --git a/main/display.h b/main/display.h index cb2b913..9092efb 100644 --- a/main/display.h +++ b/main/display.h @@ -27,11 +27,6 @@ esp_err_t display_set_brightness(uint8_t brightness_0_100); esp_err_t display_sleep(void); esp_err_t display_wake(void); -// Pulse the touch IC's reset line (PC_RST_TP_N) via the panel MCU. Used -// by touch_init() when the FT5426 boots into a wedged state and refuses -// to leave dev_mode=0xff. -esp_err_t display_touch_reset_pulse(void); - // Blit an RGB565 source image to the panel, applying the current // orientation. Source dimensions must match the effective resolution: // portrait -> src is 480x800 (rotated 90° CW into the 800x480 panel) diff --git a/main/http_api.c b/main/http_api.c index 028d3a7..2c5ce87 100644 --- a/main/http_api.c +++ b/main/http_api.c @@ -39,9 +39,8 @@ static esp_err_t state_get_handler(httpd_req_t *req) : (int64_t)((now_us - (uint64_t)st->last_frame_us) / 1000); cJSON *root = cJSON_CreateObject(); - cJSON_AddItemToObject(root, "name", - st->viewport_name[0] ? cJSON_CreateString(st->viewport_name) - : cJSON_CreateNull()); + cJSON_AddStringToObject(root, "name", st->viewport_name); + cJSON_AddStringToObject(root, "mac", st->mac_str); cJSON_AddStringToObject(root, "version", VIEWPORT_VERSION); cJSON_AddBoolToObject (root, "configured", st->configured); cJSON_AddStringToObject(root, "state", @@ -81,9 +80,7 @@ static esp_err_t config_get_handler(httpd_req_t *req) viewport_state_t *st = viewport_state_get(); cJSON *root = cJSON_CreateObject(); - cJSON_AddItemToObject(root, "viewport", - st->viewport_name[0] ? cJSON_CreateString(st->viewport_name) - : cJSON_CreateNull()); + cJSON_AddStringToObject(root, "viewport", st->viewport_name); cJSON_AddItemToObject(root, "scrypted", st->scrypted_url[0] ? cJSON_CreateString(st->scrypted_url) : cJSON_CreateNull()); @@ -233,8 +230,11 @@ static esp_err_t config_post_handler(httpd_req_t *req) st->brightness = bright; } - // A configured device has both a viewport name and a scrypted URL. - st->configured = (st->viewport_name[0] && st->scrypted_url[0]); + // "Configured" means a scrypted URL has been registered — that's + // what gates outbound POSTs and the loading-vs-info screen content + // choice. The viewport_name always has a value (MAC-derived default + // until POST /config overrides), so it doesn't factor in here. + st->configured = (st->scrypted_url[0] != '\0'); viewport_state_unlock(); diff --git a/main/local_screens.c b/main/local_screens.c index f25754d..5c72f26 100644 --- a/main/local_screens.c +++ b/main/local_screens.c @@ -199,6 +199,7 @@ esp_err_t local_screens_show_info(void) // is on a 3 KiB stack and can't carry ~1.6 KiB of locals here. Single // caller protected by display ownership, so static is fine. static char vp_name[64]; + static char mac_str[18]; static char scrypt[256]; static char lines[INFO_MAX_LINES][INFO_LINE_BYTES]; bool configured; @@ -212,8 +213,10 @@ esp_err_t local_screens_show_info(void) viewport_state_lock(); viewport_state_t *st = viewport_state_get(); strncpy(vp_name, st->viewport_name, sizeof(vp_name)); + strncpy(mac_str, st->mac_str, sizeof(mac_str)); strncpy(scrypt, st->scrypted_url, sizeof(scrypt)); vp_name[sizeof(vp_name) - 1] = '\0'; + mac_str[sizeof(mac_str) - 1] = '\0'; scrypt[sizeof(scrypt) - 1] = '\0'; configured = st->configured; state = st->state; @@ -237,8 +240,7 @@ esp_err_t local_screens_show_info(void) // 8-char label is prefixed. Long names get visibly truncated; ok for // an info dump on a 480-wide screen. char host[32]; - if (vp_name[0]) snprintf(host, sizeof(host), "viewport-%.15s.local", vp_name); - else snprintf(host, sizeof(host), "viewport.local"); + snprintf(host, sizeof(host), "viewport-%.15s.local", vp_name); char scrypt_short[32]; if (!scrypt[0]) { @@ -292,7 +294,8 @@ esp_err_t local_screens_show_info(void) snprintf(lines[n_lines++], INFO_LINE_BYTES, fmt, ##__VA_ARGS__); \ } while (0) - ADD("name %s", vp_name[0] ? vp_name : "unset"); + ADD("name %s", vp_name); + ADD("mac %s", mac_str); ADD("host %s", host); ADD("ip %s", (ip && ip[0]) ? ip : "no network"); ADD("state %s", state_str); diff --git a/main/mdns_service.c b/main/mdns_service.c index 21cd464..05d8c23 100644 --- a/main/mdns_service.c +++ b/main/mdns_service.c @@ -17,6 +17,8 @@ static const uint16_t PORT = 80; // Pull hostname + TXT values from viewport_state under one lock acquisition, // then push them at the mDNS service. mdns_service_add() rejects with // INVALID_ARG if the hostname isn't set, so order matters on first apply. +// viewport_name is always populated (MAC-derived default) so the hostname +// is always `viewport-<name>`. static esp_err_t apply_state(bool include_hostname) { char hostname[80]; @@ -25,11 +27,8 @@ static esp_err_t apply_state(bool include_hostname) viewport_state_lock(); viewport_state_t *st = viewport_state_get(); - snprintf(hostname, sizeof(hostname), "viewport%s%s", - st->viewport_name[0] ? "-" : "", - st->viewport_name[0] ? st->viewport_name : ""); - snprintf(name, sizeof(name), "%s", - st->viewport_name[0] ? st->viewport_name : ""); + snprintf(hostname, sizeof(hostname), "viewport-%s", st->viewport_name); + snprintf(name, sizeof(name), "%s", st->viewport_name); resolution = viewport_state_resolution_str(); orientation = (st->orientation == VIEWPORT_ORIENTATION_PORTRAIT) ? "portrait" : "landscape"; @@ -53,9 +52,7 @@ esp_err_t mdns_service_start(void) char hostname[80]; viewport_state_lock(); viewport_state_t *st = viewport_state_get(); - snprintf(hostname, sizeof(hostname), "viewport%s%s", - st->viewport_name[0] ? "-" : "", - st->viewport_name[0] ? st->viewport_name : ""); + snprintf(hostname, sizeof(hostname), "viewport-%s", st->viewport_name); viewport_state_unlock(); ESP_RETURN_ON_ERROR(mdns_init(), TAG, "mdns_init"); diff --git a/main/nvs_config.c b/main/nvs_config.c index 7f7586c..8ba2078 100644 --- a/main/nvs_config.c +++ b/main/nvs_config.c @@ -58,20 +58,18 @@ esp_err_t nvs_config_load(void) err = ESP_OK; - // A device is "configured" only once both name and Scrypted URL are set. - if (st->viewport_name[0] && st->scrypted_url[0]) { - st->configured = true; - st->state = VIEWPORT_STATE_ASLEEP; // configured devices boot asleep - ESP_LOGI(TAG, "loaded config: viewport=%s scrypted=%s " - "idle_ms=%u orient=%s bright=%u", - st->viewport_name, st->scrypted_url, - (unsigned)st->idle_timeout_ms, - st->orientation == VIEWPORT_ORIENTATION_LANDSCAPE - ? "landscape" : "portrait", - st->brightness); - } else { - ESP_LOGI(TAG, "partial config in NVS — viewport or scrypted URL still missing"); - } + // "Configured" = a scrypted URL has been registered. viewport_name + // always has a value (MAC-derived default seeded in viewport_state_init). + st->configured = (st->scrypted_url[0] != '\0'); + ESP_LOGI(TAG, "loaded config: viewport=%s scrypted=%s " + "idle_ms=%u orient=%s bright=%u (%s)", + st->viewport_name, + st->scrypted_url[0] ? st->scrypted_url : "(none)", + (unsigned)st->idle_timeout_ms, + st->orientation == VIEWPORT_ORIENTATION_LANDSCAPE + ? "landscape" : "portrait", + st->brightness, + st->configured ? "configured" : "no scrypted URL"); done: viewport_state_unlock(); diff --git a/main/touch.c b/main/touch.c index 4615f45..b470536 100644 --- a/main/touch.c +++ b/main/touch.c @@ -54,13 +54,6 @@ static void on_long_press(void) if (display_is_up()) local_screens_overlay(OVERLAY_MS); } -// If we see N consecutive bogus polls (TD_STATUS > 5, i.e. the FT5426 is -// returning 0xff), pulse PC_RST_TP_N to try to bring it back. PoE-only -// cold boots leave the touch IC in a wedged state for ~seconds before it -// recovers; this lets us keep nudging it without blocking init. -#define WEDGE_THRESHOLD (3000 / POLL_PERIOD_MS) // ~3 s of bad polls -#define WEDGE_BACKOFF_MS 2000 - static void touch_task(void *arg) { bool was_down = false; @@ -68,35 +61,16 @@ static void touch_task(void *arg) bool long_fired = false; uint64_t last_tap_us = 0; uint8_t buf[7]; - unsigned wedged_cycles = 0; - uint64_t last_reset_us = 0; - bool announced_up = false; for (;;) { vTaskDelay(pdMS_TO_TICKS(POLL_PERIOD_MS)); if (ft_read(FT_REG_DEV_MODE, buf, sizeof(buf)) != ESP_OK) continue; - uint64_t now_us = (uint64_t)esp_timer_get_time(); uint8_t touches = buf[FT_REG_TD_STATUS] & 0x0F; - // FT5x06 supports max 5 simultaneous points. A reading above that - // is bogus (typically the bus is parking 0xff because the IC isn't - // responding) — drop the cycle and bump the wedge counter. - if (touches > 5) { - if (++wedged_cycles >= WEDGE_THRESHOLD && - now_us - last_reset_us > (uint64_t)WEDGE_BACKOFF_MS * 1000ULL) { - ESP_LOGW(TAG, "touch wedged — pulsing reset"); - display_touch_reset_pulse(); - last_reset_us = now_us; - wedged_cycles = 0; - } - continue; - } - if (wedged_cycles > 0 || !announced_up) { - ESP_LOGI(TAG, "touch online (TD_STATUS=%u)", touches); - wedged_cycles = 0; - announced_up = true; - } - uint64_t now = now_us; + // FT5x06 supports max 5 simultaneous points; anything above that + // is a bogus reading (chip parking 0xff during a transient). + if (touches > 5) continue; + uint64_t now = (uint64_t)esp_timer_get_time(); if (touches > 0) { if (!was_down) { @@ -141,23 +115,11 @@ esp_err_t touch_init(void) ESP_RETURN_ON_ERROR(i2c_master_bus_add_device(bus, &cfg, &s_dev), TAG, "i2c add FT5426"); - // Force DEV_MODE=0x00 (Working Mode) — chip might have powered up in - // System Info mode (0x40) or Factory Test mode (0x40) which would - // explain steady 0x00 TD_STATUS but no touch detection. Cheap to - // attempt; ignore result since some firmware revisions reject it - // pre-reset and the polling loop handles the alternative anyway. - { - uint8_t set_working[2] = { FT_REG_DEV_MODE, 0x00 }; - i2c_master_transmit(s_dev, set_working, sizeof(set_working), 50); - } - - // Pulse the touch reset line and don't read dev_mode at init time: - // on PoE-only boots the FT5426 hasn't finished its internal firmware - // load when touch_init runs, and any read returns 0xff. The polling - // loop already drops cycles where TD_STATUS > 5, so a wedged chip is - // harmless; once its firmware finishes (often after a few hundred ms - // of being prodded by polling reads), real touches start landing. - display_touch_reset_pulse(); + // No dev_mode read here: the FT5426 starts reporting contacts only + // after the LCD has streamed with the backlight on at least once + // (handled by the wake-on-boot flash in app_main). Any read before + // that returns 0xff, which the polling loop's >5 sanity filter + // already drops. ESP_LOGI(TAG, "FT5426 polling started " "(tap=toggle wake/sleep, %dms hold=info overlay)", LONG_PRESS_MS); diff --git a/main/viewport_state.c b/main/viewport_state.c index 7ddf737..a67745a 100644 --- a/main/viewport_state.c +++ b/main/viewport_state.c @@ -1,7 +1,9 @@ #include "viewport_state.h" +#include <stdio.h> #include <string.h> +#include "esp_mac.h" #include "esp_timer.h" #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" @@ -9,6 +11,22 @@ static viewport_state_t s_state; static SemaphoreHandle_t s_mutex; +// Populate viewport_name with the full base MAC, colons stripped +// (e.g. e8:f6:0a:e0:90:94 → "e8f60ae09094"). Stable across reboots, +// globally unique, and 12 alphanumeric chars — fits comfortably under +// the 32-char mDNS hostname limit with the "viewport-" prefix. +// POST /config can override it with a friendlier name. +static void seed_mac_and_name(char *mac_str, size_t mac_cap, + char *name, size_t name_cap) +{ + uint8_t mac[6] = {0}; + esp_read_mac(mac, ESP_MAC_BASE); + snprintf(mac_str, mac_cap, "%02x:%02x:%02x:%02x:%02x:%02x", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + snprintf(name, name_cap, "%02x%02x%02x%02x%02x%02x", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); +} + void viewport_state_init(void) { memset(&s_state, 0, sizeof(s_state)); @@ -19,6 +37,8 @@ void viewport_state_init(void) s_state.orientation = VIEWPORT_ORIENTATION_PORTRAIT; s_state.boot_us = (uint64_t)esp_timer_get_time(); s_state.last_frame_us = -1; + seed_mac_and_name(s_state.mac_str, sizeof(s_state.mac_str), + s_state.viewport_name, sizeof(s_state.viewport_name)); s_mutex = xSemaphoreCreateMutex(); } diff --git a/main/viewport_state.h b/main/viewport_state.h index 4e6fbd6..264d07d 100644 --- a/main/viewport_state.h +++ b/main/viewport_state.h @@ -20,7 +20,8 @@ typedef enum { // Read-mostly snapshot of device state used by /state. Counters are // updated under a mutex by the modules that own them. typedef struct { - char viewport_name[64]; // empty before /config + char mac_str[18]; // "aa:bb:cc:dd:ee:ff" — populated at init + char viewport_name[64]; // MAC-derived default; can be overridden via /config char scrypted_url[256]; // empty before /config bool configured; viewport_run_state_t state; |
