From 220ee4cdc9b372e2a2b41ee48471ad0893b3a68a Mon Sep 17 00:00:00 2001 From: Luke Hoersten Date: Sun, 14 Jun 2026 12:11:43 -0500 Subject: M1+M2 hardware bring-up: 3 fixes + elegant subsystem degradation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit First flash to real hardware (Waveshare ESP32-P4-ETH on USB power, no LAN cable, no panel attached) exposed three bugs and the need to degrade gracefully when peripherals are missing. 1. net_eth.c: RXD0 / RXD1 GPIO swap. ESP32-P4's EMAC iomux table (components/soc/esp32p4/emac_periph.c) fixes RXD0 to GPIO 29 and RXD1 to GPIO 30. The Waveshare-wiki/ESPHome research had them transposed. Symptom was: E (esp.emac.gpio): invalid RXD0 GPIO number E (esp.emac): esp_eth_mac_new_esp32 failed -> ESP_ERROR_CHECK abort Fix: swap the two #defines. CRS_DV / TXD0 / TXD1 / TX_EN / REF_CLK pinout was already correct. 2. mdns_service.c: mdns_service_add() rejects with INVALID_ARG when the hostname isn't set yet (see mdns_responder.c:771 — first guard in mdns_service_add_for_host). We were setting hostname AFTER service_add inside apply_records(). Restructure mdns_service_start to: init -> hostname -> service_add -> txt. apply_hostname() and apply_txt() helpers reuse the same snapshot under viewport_state's mutex; mdns_service_refresh() re-applies both. 3. app_main.c: every subsystem now best-effort instead of ESP_ERROR_CHECK abort. A single missing peripheral can't take down the rest of the firmware. End-of-boot summary line: boot complete — subsystems [EMHdJ-B] ip=(no link) Uppercase letter = up, lowercase = down. E=Ethernet M=mDNS H=HTTP D=Display J=JPEG T=Touch B=BootButton. Touch shows '-' when display didn't come up (it shares the panel I2C bus). On a stripped board (just ESP32-P4-ETH on USB, no panel, no LAN) the line above prints and the device serves /state, /config, and mDNS over the loopback; plugging Ethernet in later picks up DHCP without a reboot. Side-effects: the DHCP timeout in app_main shortened from 30s to 15s so a no-cable boot finishes quickly. Reaching the "ready" state with no link is fine — the driver keeps the link-up event handler armed and gets the IP whenever a cable appears. Verified on hardware (bare ESP32-P4-ETH, no LAN, no panel): - ESP-IDF v5.4.1, esp32p4, 32 MB PSRAM detected, 16 MB flash config (actual 32 MB silkscreen — keeping 16 MB until access-beyond-16MB support lands in flash driver). - Ethernet driver started — MAC e8:f6:0a:e0:90:94. - mDNS up advertising viewport.local on _scrypted-viewport._tcp:80. - HTTP up listening :80. - JPEG decoder ready. - Display reports "panel MCU @0x45 unreachable" — exactly correct for no-panel state. - Touch skipped as designed. - BOOT button registered on GPIO 0 (still a guess; harmless if wrong). This is enough to flip M1's "code" status to ✅ on hardware once Ethernet is plugged in. M2 (mDNS browse + GET /state) ready to verify. --- main/mdns_service.c | 74 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 52 insertions(+), 22 deletions(-) (limited to 'main/mdns_service.c') diff --git a/main/mdns_service.c b/main/mdns_service.c index 761ade5..d389161 100644 --- a/main/mdns_service.c +++ b/main/mdns_service.c @@ -14,52 +14,82 @@ static const char *SERVICE = "_scrypted-viewport"; static const char *PROTO = "_tcp"; static const uint16_t PORT = 80; -static esp_err_t apply_records(void) +// Pull the current hostname + TXT values from viewport_state under the lock. +static void snapshot_state(char *hostname, size_t host_cap, + const char **resolution, + const char **orientation, + char *name, size_t name_cap) { viewport_state_lock(); viewport_state_t *st = viewport_state_get(); - char hostname[80]; if (st->viewport_name[0]) { - snprintf(hostname, sizeof(hostname), "viewport-%s", st->viewport_name); + snprintf(hostname, host_cap, "viewport-%s", st->viewport_name); } else { - snprintf(hostname, sizeof(hostname), "viewport"); + snprintf(hostname, host_cap, "viewport"); } - - const char *resolution = viewport_state_resolution_str(); - const char *orientation = (st->orientation == VIEWPORT_ORIENTATION_PORTRAIT) - ? "portrait" : "landscape"; - const char *name_value = st->viewport_name[0] ? st->viewport_name : ""; + *resolution = viewport_state_resolution_str(); + *orientation = (st->orientation == VIEWPORT_ORIENTATION_PORTRAIT) + ? "portrait" : "landscape"; + snprintf(name, name_cap, "%s", st->viewport_name[0] ? st->viewport_name : ""); viewport_state_unlock(); +} + +static esp_err_t apply_hostname(void) +{ + char hostname[80]; + const char *resolution, *orientation; + char name[64]; + snapshot_state(hostname, sizeof(hostname), + &resolution, &orientation, + name, sizeof(name)); + return mdns_hostname_set(hostname); +} + +static esp_err_t apply_txt(void) +{ + char hostname[80]; + const char *resolution, *orientation; + char name[64]; + snapshot_state(hostname, sizeof(hostname), + &resolution, &orientation, + name, sizeof(name)); mdns_txt_item_t txt[] = { { "version", VIEWPORT_VERSION }, { "resolution", resolution }, { "orientation", orientation }, - { "name", name_value }, + { "name", name }, }; - const size_t txt_count = sizeof(txt) / sizeof(txt[0]); - - ESP_RETURN_ON_ERROR(mdns_hostname_set(hostname), TAG, "hostname_set"); - ESP_RETURN_ON_ERROR(mdns_service_txt_set(SERVICE, PROTO, txt, txt_count), - TAG, "txt_set"); - - ESP_LOGI(TAG, "advertising %s.local on %s.%s.local:%u", - hostname, SERVICE, PROTO, PORT); - return ESP_OK; + return mdns_service_txt_set(SERVICE, PROTO, txt, + sizeof(txt) / sizeof(txt[0])); } esp_err_t mdns_service_start(void) { - ESP_RETURN_ON_ERROR(mdns_init(), TAG, "mdns_init"); + // Order matters: mdns_service_add() rejects with INVALID_ARG if the + // hostname isn't set yet. So: init -> hostname -> service_add -> TXT. + ESP_RETURN_ON_ERROR(mdns_init(), TAG, "mdns_init"); + ESP_RETURN_ON_ERROR(apply_hostname(), TAG, "hostname_set"); ESP_RETURN_ON_ERROR( mdns_service_add(NULL, SERVICE, PROTO, PORT, NULL, 0), TAG, "service_add"); - return apply_records(); + ESP_RETURN_ON_ERROR(apply_txt(), TAG, "txt_set"); + + char hostname[80]; + const char *resolution, *orientation; + char name[64]; + snapshot_state(hostname, sizeof(hostname), + &resolution, &orientation, + name, sizeof(name)); + ESP_LOGI(TAG, "mDNS up — %s.local advertising %s.%s.local on :%u", + hostname, SERVICE, PROTO, PORT); + return ESP_OK; } esp_err_t mdns_service_refresh(void) { - return apply_records(); + ESP_RETURN_ON_ERROR(apply_hostname(), TAG, "hostname_set"); + return apply_txt(); } -- cgit v1.2.3