Recover Indicator display after warm reset
This commit is contained in:
1 parent
1abc36f636
commit
8351effff1
3 files changed
+46
-3
No files matched your search
@@ -825,6 +825,7 @@ void halt() {
|
||||
static CompanionWiFiDisplayState companion_wifi_display_state =
|
||||
CompanionWiFiDisplayState::NotRendered;
|
||||
static uint32_t companion_wifi_display_frames = 0;
|
||||
static bool companion_display_available = false;
|
||||
|
||||
#if defined(COMPANION_EXCLUSIVE_WIFI_BLE)
|
||||
static CompanionTransportMode companion_transport_boot_mode =
|
||||
@@ -1173,9 +1174,10 @@ void halt() {
|
||||
const bool idf_associated =
|
||||
esp_wifi_sta_get_ap_info(&access_point) == ESP_OK;
|
||||
snprintf(reply, reply_size,
|
||||
"> state=%s, frames=%lu, requested=%u, services=%u, "
|
||||
"> state=%s, frames=%lu, display=%u, requested=%u, services=%u, "
|
||||
"wl=%d, idf=%u, IP=%s",
|
||||
names[state], (unsigned long)companion_wifi_display_frames,
|
||||
companion_display_available ? 1U : 0U,
|
||||
companion_wifi_requested ? 1U : 0U,
|
||||
companion_wifi_active ? 1U : 0U, (int)WiFi.status(),
|
||||
idf_associated ? 1U : 0U,
|
||||
@@ -1733,6 +1735,9 @@ void setup() {
|
||||
disp->drawTextCentered(disp->width() / 2, 28, "Loading...");
|
||||
disp->endFrame();
|
||||
}
|
||||
#if defined(ESP32) && defined(WIFI_SSID)
|
||||
companion_display_available = disp != NULL;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int radioinit_attempts = 0;
|
||||
|
||||
@@ -9,6 +9,9 @@ import unittest
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
PROFILE = ROOT / "variants" / "sensecap_indicator-espnow" / "platformio.ini"
|
||||
DISPLAY = ROOT / "src" / "helpers" / "ui" / "LGFXDisplay.cpp"
|
||||
INDICATOR_DISPLAY = (
|
||||
ROOT / "variants" / "sensecap_indicator-espnow" / "SCIndicatorDisplay.h"
|
||||
)
|
||||
FONT = ROOT / "variants" / "sensecap_indicator-espnow" / "sd" / "ui-font.vlw"
|
||||
|
||||
|
||||
@@ -36,6 +39,14 @@ def numeric_flag(name: str) -> float:
|
||||
|
||||
|
||||
class IndicatorDisplayProfileTest(unittest.TestCase):
|
||||
def test_panel_cs_release_cannot_discard_initialized_display(self):
|
||||
display = INDICATOR_DISPLAY.read_text()
|
||||
self.assertIn("releasePanelChipSelectWithRetry()", display)
|
||||
self.assertIn("if (!initialized) return false;", display)
|
||||
self.assertNotIn("if (!initialized || !released) return false;", display)
|
||||
self.assertIn("panel_chip_select_released =", display)
|
||||
self.assertIn("void startFrame(ColorVal bkg", display)
|
||||
|
||||
def test_preserves_original_indicator_memory_profile(self):
|
||||
profile = base_profile()
|
||||
self.assertIn("board_build.arduino.memory_type = qio_opi", profile)
|
||||
|
||||
@@ -129,6 +129,7 @@ class SCIndicatorDisplay : public LGFXDisplay {
|
||||
LGFX disp;
|
||||
uint8_t expander_address = 0;
|
||||
uint16_t expander_output = 0;
|
||||
bool panel_chip_select_released = false;
|
||||
|
||||
static constexpr gpio_num_t BACKLIGHT_PIN = GPIO_NUM_45;
|
||||
static constexpr uint8_t I2C_PORT = 0;
|
||||
@@ -230,6 +231,20 @@ class SCIndicatorDisplay : public LGFXDisplay {
|
||||
expander_output);
|
||||
}
|
||||
|
||||
bool releasePanelChipSelectWithRetry() {
|
||||
// LovyanGFX initializes the touch controller on this same I2C bus. On a
|
||||
// warm ESP32-S3 reset its final transaction can briefly leave the
|
||||
// expander unavailable even though the RGB panel and render buffer were
|
||||
// initialized successfully. Re-open the bus and retry before LoRa starts
|
||||
// using the panel's shared SCLK/MOSI pins.
|
||||
for (uint8_t attempt = 0; attempt < 10; ++attempt) {
|
||||
if (releasePanelChipSelect()) return true;
|
||||
delay(5);
|
||||
lgfx::i2c::init(I2C_PORT, PIN_BOARD_SDA, PIN_BOARD_SCL);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
#if defined(INDICATOR_TRANSPORT_RENDER_PROFILE)
|
||||
// Full builds always use the established 160x160 logical layout. State it
|
||||
@@ -245,8 +260,13 @@ public:
|
||||
bool begin() {
|
||||
if (!prepareControllers()) return false;
|
||||
const bool initialized = LGFXDisplay::begin();
|
||||
const bool released = releasePanelChipSelect();
|
||||
if (!initialized || !released) return false;
|
||||
if (!initialized) return false;
|
||||
|
||||
// A failed CS release must not discard an otherwise valid 115 KiB render
|
||||
// buffer and leave the LCD showing its pre-reset scanout forever. Keep the
|
||||
// UI alive and retry from startFrame(); the common case succeeds here
|
||||
// before the external LoRa radio is initialized.
|
||||
panel_chip_select_released = releasePanelChipSelectWithRetry();
|
||||
setBacklight(true);
|
||||
size_t fontSize;
|
||||
uint8_t* fontData = IndicatorFontClient::load(fontSize);
|
||||
@@ -263,6 +283,13 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
void startFrame(ColorVal bkg = UIColor::window_bkg) override {
|
||||
if (!panel_chip_select_released) {
|
||||
panel_chip_select_released = releasePanelChipSelectWithRetry();
|
||||
}
|
||||
LGFXDisplay::startFrame(bkg);
|
||||
}
|
||||
|
||||
#ifdef INDICATOR_WIFI_FONT_RECOVERY
|
||||
void serviceFontRecovery() {
|
||||
size_t fontSize = 0;
|
||||
|
||||
Reference in new issue
Block a user