Keep Indicator RGB scanout alive during expander recovery

This commit is contained in:
mikecarper committed 2026-08-31 19:10:54 -07:00
1 parent 8351effff1
commit 3bd738c1c9
3 files changed
+41 -8

No files matched your search

+4 -1
View File
@@ -826,6 +826,7 @@ void halt() {
CompanionWiFiDisplayState::NotRendered;
static uint32_t companion_wifi_display_frames = 0;
static bool companion_display_available = false;
static uint8_t companion_display_begin_status = 0;
#if defined(COMPANION_EXCLUSIVE_WIFI_BLE)
static CompanionTransportMode companion_transport_boot_mode =
@@ -1174,10 +1175,11 @@ void halt() {
const bool idf_associated =
esp_wifi_sta_get_ap_info(&access_point) == ESP_OK;
snprintf(reply, reply_size,
"> state=%s, frames=%lu, display=%u, requested=%u, services=%u, "
"> state=%s, frames=%lu, display=%u/%02X, requested=%u, services=%u, "
"wl=%d, idf=%u, IP=%s",
names[state], (unsigned long)companion_wifi_display_frames,
companion_display_available ? 1U : 0U,
(unsigned int)companion_display_begin_status,
companion_wifi_requested ? 1U : 0U,
companion_wifi_active ? 1U : 0U, (int)WiFi.status(),
idf_associated ? 1U : 0U,
@@ -1737,6 +1739,7 @@ void setup() {
}
#if defined(ESP32) && defined(WIFI_SSID)
companion_display_available = disp != NULL;
companion_display_begin_status = display.beginStatus();
#endif
#endif
+6 -1
View File
@@ -42,10 +42,15 @@ 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.assertIn("if (!initialized) {", display)
self.assertIn("begin_status = 0x82;", display)
self.assertNotIn("if (!initialized || !released) return false;", display)
self.assertIn("panel_chip_select_released =", display)
self.assertIn("void startFrame(ColorVal bkg", display)
self.assertIn("const bool controllers_prepared = prepareControllers()", display)
self.assertIn("begin_status = controllers_prepared ? 4 : 0x84", display)
self.assertIn("if (expander_address == 0 && prepareControllers())", display)
self.assertIn("uint8_t beginStatus() const", display)
def test_preserves_original_indicator_memory_profile(self):
profile = base_profile()
@@ -130,6 +130,7 @@ class SCIndicatorDisplay : public LGFXDisplay {
uint8_t expander_address = 0;
uint16_t expander_output = 0;
bool panel_chip_select_released = false;
uint8_t begin_status = 0;
static constexpr gpio_num_t BACKLIGHT_PIN = GPIO_NUM_45;
static constexpr uint8_t I2C_PORT = 0;
@@ -218,10 +219,14 @@ class SCIndicatorDisplay : public LGFXDisplay {
}
bool prepareControllers() {
if (!lgfx::i2c::init(I2C_PORT, PIN_BOARD_SDA, PIN_BOARD_SCL).has_value()) {
return false;
for (uint8_t attempt = 0; attempt < 10; ++attempt) {
if (lgfx::i2c::init(I2C_PORT, PIN_BOARD_SDA, PIN_BOARD_SCL).has_value()
&& (prepareControllersAt(0x20) || prepareControllersAt(0x39))) {
return true;
}
delay(20);
}
return prepareControllersAt(0x20) || prepareControllersAt(0x39);
return false;
}
bool releasePanelChipSelect() {
@@ -258,15 +263,23 @@ public:
#endif
bool begin() {
if (!prepareControllers()) return false;
begin_status = 1;
const bool controllers_prepared = prepareControllers();
begin_status = controllers_prepared ? 2 : 0x81;
const bool initialized = LGFXDisplay::begin();
if (!initialized) return false;
if (!initialized) {
begin_status = 0x82;
return false;
}
begin_status = controllers_prepared ? 3 : 0x83;
// 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();
if (controllers_prepared) {
panel_chip_select_released = releasePanelChipSelectWithRetry();
}
setBacklight(true);
size_t fontSize;
uint8_t* fontData = IndicatorFontClient::load(fontSize);
@@ -280,16 +293,28 @@ public:
}
#endif
}
begin_status = controllers_prepared ? 4 : 0x84;
return true;
}
void startFrame(ColorVal bkg = UIColor::window_bkg) override {
if (expander_address == 0 && prepareControllers()) {
// The RGB scanout can start while the shared expander is temporarily
// unavailable. Once it recovers, re-run the panel command sequence and
// release CS before presenting the next complete frame.
if (disp.init()) {
panel_chip_select_released = releasePanelChipSelectWithRetry();
begin_status = 5;
}
}
if (!panel_chip_select_released) {
panel_chip_select_released = releasePanelChipSelectWithRetry();
}
LGFXDisplay::startFrame(bkg);
}
uint8_t beginStatus() const { return begin_status; }
#ifdef INDICATOR_WIFI_FONT_RECOVERY
void serviceFontRecovery() {
size_t fontSize = 0;