Main

Source: src/main.c · 2070 lines · 16 functions.

Module entry points

These functions are exposed to the rest of the project. Open one to follow its decisions and the helpers it calls.

How to read these diagrams

Each function has its own expandable diagram using the actual expressions and statements from this file. Decisions split into True and False; loop bodies are indented. Returns end the function immediately; break and continue follow their C meanings. Arrows between statements show their order when execution reaches them.

These are structural source diagrams before preprocessing, not runtime traces. Conditional compilation and macros remain source expressions. Ternary choices remain inside their statement. Calls are linked separately; callback execution and task scheduling are not inferred.

Functions in this file

set_backlight_brightness() · source line 131
static void set_backlight_brightness(uint8_t duty)
  1. ExecuteESP_ERROR_CHECK(ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, duty));
  2. ExecuteESP_ERROR_CHECK(ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0));
Read original function source
static void set_backlight_brightness(uint8_t duty)
{
    ESP_ERROR_CHECK(ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, duty));
    ESP_ERROR_CHECK(ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0));
}
display_color_transfer_done() · source line 144
static bool display_color_transfer_done(esp_lcd_panel_io_handle_t panel_io,
                                        esp_lcd_panel_io_event_data_t *event,
                                        void *user_context)
  1. Execute(void)panel_io;
  2. Execute(void)event;
  3. ExecuteBaseType_t task_woken = pdFALSE;
  4. ExecutexSemaphoreGiveFromISR((SemaphoreHandle_t)user_context, &task_woken);
  5. Exit this functionreturn task_woken == pdTRUE;
Read original function source
static bool display_color_transfer_done(esp_lcd_panel_io_handle_t panel_io,
                                        esp_lcd_panel_io_event_data_t *event,
                                        void *user_context)
{
    (void)panel_io;
    (void)event;
    BaseType_t task_woken = pdFALSE;
    xSemaphoreGiveFromISR((SemaphoreHandle_t)user_context, &task_woken);
    return task_woken == pdTRUE;
}
initialize_display() · source line 155
static esp_lcd_panel_handle_t initialize_display(void)

Calls into this documentation:

  1. Executeconst gpio_config_t output_config = { .pin_bit_mask = (1ULL << PIN_POWER_ON) | (1ULL << PIN_LCD_BL) | (1ULL << PIN_LCD_RD), .mode = GPIO_MODE_OUTPUT, .pull_up_en = GPIO_PULLUP_DISABLE, .pull_down_en = GPIO_PULLDOWN_DISABLE, .intr_type = GPIO_INTR_DISABLE, };
  2. ExecuteESP_ERROR_CHECK(gpio_config(&output_config));
  3. ExecuteESP_ERROR_CHECK(gpio_set_level(PIN_POWER_ON, 1));
  4. ExecuteESP_ERROR_CHECK(gpio_set_level(PIN_LCD_BL, 0));
  5. ExecuteESP_ERROR_CHECK(gpio_set_level(PIN_LCD_RD, 1));
  6. Executeconst ledc_timer_config_t backlight_timer = { .speed_mode = LEDC_LOW_SPEED_MODE, .duty_resolution = LEDC_TIMER_8_BIT, .timer_num = LEDC_TIMER_0, .freq_hz = LCD_BACKLIGHT_PWM_HZ, .clk_cfg = LEDC_AUTO_CLK, };
  7. ExecuteESP_ERROR_CHECK(ledc_timer_config(&backlight_timer));
  8. Executeconst ledc_channel_config_t backlight_channel = { .gpio_num = PIN_LCD_BL, .speed_mode = LEDC_LOW_SPEED_MODE, .channel = LEDC_CHANNEL_0, .intr_type = LEDC_INTR_DISABLE, .timer_sel = LEDC_TIMER_0, .duty = 0, .hpoint = 0, };
  9. ExecuteESP_ERROR_CHECK(ledc_channel_config(&backlight_channel));
  10. Executeconst esp_lcd_i80_bus_config_t bus_config = { .dc_gpio_num = PIN_LCD_DC, .wr_gpio_num = PIN_LCD_WR, .clk_src = LCD_CLK_SRC_DEFAULT, .data_gpio_nums = { PIN_LCD_D0, PIN_LCD_D1, PIN_LCD_D2, PIN_LCD_D3, PIN_LCD_D4, PIN_LCD_D5, PIN_LCD_D6, PIN_LCD_D7, }, .bus_width = 8, .max_transfer_bytes = FRAME_BUFFER_BYTES, };
  11. Executeesp_lcd_i80_bus_handle_t bus = NULL;
  12. ExecuteESP_ERROR_CHECK(esp_lcd_new_i80_bus(&bus_config, &bus));
  13. Executeconst esp_lcd_panel_io_i80_config_t io_config = { .cs_gpio_num = PIN_LCD_CS, .pclk_hz = LCD_PIXEL_CLOCK_HZ, .trans_queue_depth = 4, .on_color_trans_done = display_color_transfer_done, .user_ctx = display_transfer_done, .dc_levels = { .dc_idle_level = 0, .dc_cmd_level = 0, .dc_dummy_level = 0, .dc_data_level = 1, }, .lcd_cmd_bits = 8, .lcd_param_bits = 8, .flags = { .swap_color_bytes = true, }, };
  14. Executeesp_lcd_panel_io_handle_t panel_io = NULL;
  15. ExecuteESP_ERROR_CHECK(esp_lcd_new_panel_io_i80(bus, &io_config, &panel_io));
  16. Executeconst esp_lcd_panel_dev_config_t panel_config = { .reset_gpio_num = PIN_LCD_RST, .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB, .bits_per_pixel = 16, };
  17. Executeesp_lcd_panel_handle_t panel = NULL;
  18. ExecuteESP_ERROR_CHECK(esp_lcd_new_panel_st7789(panel_io, &panel_config, &panel));
  19. ExecuteESP_ERROR_CHECK(esp_lcd_panel_reset(panel));
  20. ExecuteESP_ERROR_CHECK(esp_lcd_panel_init(panel));
  21. ExecuteESP_ERROR_CHECK(esp_lcd_panel_invert_color(panel, true));
  22. ExecuteESP_ERROR_CHECK(esp_lcd_panel_swap_xy(panel, true));
  23. ExecuteESP_ERROR_CHECK(esp_lcd_panel_mirror(panel, true, false));
  24. ExecuteESP_ERROR_CHECK(esp_lcd_panel_set_gap(panel, 0, 35));
  25. ExecuteESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel, true));
  26. Executeset_backlight_brightness(LCD_BACKLIGHT_DUTY);
  27. Exit this functionreturn panel;
Read original function source
static esp_lcd_panel_handle_t initialize_display(void)
{
    const gpio_config_t output_config = {
        .pin_bit_mask = (1ULL << PIN_POWER_ON) | (1ULL << PIN_LCD_BL) |
                        (1ULL << PIN_LCD_RD),
        .mode = GPIO_MODE_OUTPUT,
        .pull_up_en = GPIO_PULLUP_DISABLE,
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .intr_type = GPIO_INTR_DISABLE,
    };
    ESP_ERROR_CHECK(gpio_config(&output_config));
    ESP_ERROR_CHECK(gpio_set_level(PIN_POWER_ON, 1));
    ESP_ERROR_CHECK(gpio_set_level(PIN_LCD_BL, 0));
    ESP_ERROR_CHECK(gpio_set_level(PIN_LCD_RD, 1));

    const ledc_timer_config_t backlight_timer = {
        .speed_mode = LEDC_LOW_SPEED_MODE,
        .duty_resolution = LEDC_TIMER_8_BIT,
        .timer_num = LEDC_TIMER_0,
        .freq_hz = LCD_BACKLIGHT_PWM_HZ,
        .clk_cfg = LEDC_AUTO_CLK,
    };
    ESP_ERROR_CHECK(ledc_timer_config(&backlight_timer));
    const ledc_channel_config_t backlight_channel = {
        .gpio_num = PIN_LCD_BL,
        .speed_mode = LEDC_LOW_SPEED_MODE,
        .channel = LEDC_CHANNEL_0,
        .intr_type = LEDC_INTR_DISABLE,
        .timer_sel = LEDC_TIMER_0,
        .duty = 0,
        .hpoint = 0,
    };
    ESP_ERROR_CHECK(ledc_channel_config(&backlight_channel));

    const esp_lcd_i80_bus_config_t bus_config = {
        .dc_gpio_num = PIN_LCD_DC,
        .wr_gpio_num = PIN_LCD_WR,
        .clk_src = LCD_CLK_SRC_DEFAULT,
        .data_gpio_nums = {
            PIN_LCD_D0,
            PIN_LCD_D1,
            PIN_LCD_D2,
            PIN_LCD_D3,
            PIN_LCD_D4,
            PIN_LCD_D5,
            PIN_LCD_D6,
            PIN_LCD_D7,
        },
        .bus_width = 8,
        .max_transfer_bytes = FRAME_BUFFER_BYTES,
    };

    esp_lcd_i80_bus_handle_t bus = NULL;
    ESP_ERROR_CHECK(esp_lcd_new_i80_bus(&bus_config, &bus));

    const esp_lcd_panel_io_i80_config_t io_config = {
        .cs_gpio_num = PIN_LCD_CS,
        .pclk_hz = LCD_PIXEL_CLOCK_HZ,
        .trans_queue_depth = 4,
        .on_color_trans_done = display_color_transfer_done,
        .user_ctx = display_transfer_done,
        .dc_levels = {
            .dc_idle_level = 0,
            .dc_cmd_level = 0,
            .dc_dummy_level = 0,
            .dc_data_level = 1,
        },
        .lcd_cmd_bits = 8,
        .lcd_param_bits = 8,
        .flags = {
            .swap_color_bytes = true,
        },
    };

    esp_lcd_panel_io_handle_t panel_io = NULL;
    ESP_ERROR_CHECK(esp_lcd_new_panel_io_i80(bus, &io_config, &panel_io));

    const esp_lcd_panel_dev_config_t panel_config = {
        .reset_gpio_num = PIN_LCD_RST,
        .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
        .bits_per_pixel = 16,
    };

    esp_lcd_panel_handle_t panel = NULL;
    ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(panel_io, &panel_config, &panel));
    ESP_ERROR_CHECK(esp_lcd_panel_reset(panel));
    ESP_ERROR_CHECK(esp_lcd_panel_init(panel));
    ESP_ERROR_CHECK(esp_lcd_panel_invert_color(panel, true));
    ESP_ERROR_CHECK(esp_lcd_panel_swap_xy(panel, true));
    ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel, true, false));
    ESP_ERROR_CHECK(esp_lcd_panel_set_gap(panel, 0, 35));
    ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel, true));
    set_backlight_brightness(LCD_BACKLIGHT_DUTY);

    return panel;
}
draw_bob_label() · source line 253
static void draw_bob_label(uint16_t *frame)
  1. Executestatic const uint8_t glyphs[2][7] = { {0x1E, 0x11, 0x11, 0x1E, 0x11, 0x11, 0x1E}, // B {0x0E, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E}, // O };
  2. Executestatic const uint8_t bob_glyphs[] = {0, 1, 0};
  3. Executeconst int scale = 3;
  4. Executeconst int label_x = LCD_WIDTH - 55;
  5. Executeconst int label_y = 6;
  6. Executeconst int label_width = 51;
  7. Executeconst int label_height = 21;
  8. FOR loopint y = label_y - 2; y < label_y + label_height + 2; ++y

    Repeat body while the loop condition permits; then continue below.

      1. FOR loopint x = label_x - 2; x < label_x + label_width + 2; ++x

        Repeat body while the loop condition permits; then continue below.

          1. Executeframe[(size_t)y * LCD_WIDTH + x] = RGB565(0, 0, 0);
  9. FOR loopsize_t character = 0; character < 3; ++character

    Repeat body while the loop condition permits; then continue below.

      1. Executeconst uint8_t *glyph = glyphs[bob_glyphs[character]];
      2. Executeconst int character_x = label_x + (int)character * (5 * scale + scale);
      3. FOR loopint row = 0; row < 7; ++row

        Repeat body while the loop condition permits; then continue below.

          1. FOR loopint column = 0; column < 5; ++column

            Repeat body while the loop condition permits; then continue below.

              1. Decision(glyph[row] & (1U << (4 - column))) == 0
                True
                  1. Next loop iterationcontinue;
                False

                Continue after this decision.

              2. FOR loopint pixel_y = 0; pixel_y < scale; ++pixel_y

                Repeat body while the loop condition permits; then continue below.

                  1. FOR loopint pixel_x = 0; pixel_x < scale; ++pixel_x

                    Repeat body while the loop condition permits; then continue below.

                      1. Executeconst int x = character_x + column * scale + pixel_x;
                      2. Executeconst int y = label_y + row * scale + pixel_y;
                      3. Executeframe[(size_t)y * LCD_WIDTH + x] = RGB565(255, 255, 255);
Read original function source
static void draw_bob_label(uint16_t *frame)
{
    static const uint8_t glyphs[2][7] = {
        {0x1E, 0x11, 0x11, 0x1E, 0x11, 0x11, 0x1E}, // B
        {0x0E, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E}, // O
    };
    static const uint8_t bob_glyphs[] = {0, 1, 0};
    const int scale = 3;
    const int label_x = LCD_WIDTH - 55;
    const int label_y = 6;
    const int label_width = 51;
    const int label_height = 21;

    for (int y = label_y - 2; y < label_y + label_height + 2; ++y) {
        for (int x = label_x - 2; x < label_x + label_width + 2; ++x) {
            frame[(size_t)y * LCD_WIDTH + x] = RGB565(0, 0, 0);
        }
    }

    for (size_t character = 0; character < 3; ++character) {
        const uint8_t *glyph = glyphs[bob_glyphs[character]];
        const int character_x = label_x + (int)character * (5 * scale + scale);

        for (int row = 0; row < 7; ++row) {
            for (int column = 0; column < 5; ++column) {
                if ((glyph[row] & (1U << (4 - column))) == 0) {
                    continue;
                }

                for (int pixel_y = 0; pixel_y < scale; ++pixel_y) {
                    for (int pixel_x = 0; pixel_x < scale; ++pixel_x) {
                        const int x = character_x + column * scale + pixel_x;
                        const int y = label_y + row * scale + pixel_y;
                        frame[(size_t)y * LCD_WIDTH + x] = RGB565(255, 255, 255);
                    }
                }
            }
        }
    }
}
fill_color_bars() · source line 294
static void fill_color_bars(uint16_t *frame)

Calls into this documentation:

  1. Executestatic const uint16_t colors[] = { RGB565(255, 0, 0), RGB565(0, 255, 0), RGB565(0, 0, 0), RGB565(0, 0, 255), RGB565(255, 255, 255), };
  2. FOR loopint y = 0; y < LCD_HEIGHT; ++y

    Repeat body while the loop condition permits; then continue below.

      1. Executeconst size_t color_index = (size_t)y * 5U / LCD_HEIGHT;
      2. FOR loopint x = 0; x < LCD_WIDTH; ++x

        Repeat body while the loop condition permits; then continue below.

          1. Executeframe[(size_t)y * LCD_WIDTH + x] = colors[color_index];
  3. Executedraw_bob_label(frame);
Read original function source
static void fill_color_bars(uint16_t *frame)
{
    static const uint16_t colors[] = {
        RGB565(255, 0, 0),
        RGB565(0, 255, 0),
        RGB565(0, 0, 0),
        RGB565(0, 0, 255),
        RGB565(255, 255, 255),
    };

    for (int y = 0; y < LCD_HEIGHT; ++y) {
        const size_t color_index = (size_t)y * 5U / LCD_HEIGHT;
        for (int x = 0; x < LCD_WIDTH; ++x) {
            frame[(size_t)y * LCD_WIDTH + x] = colors[color_index];
        }
    }

    draw_bob_label(frame);
}
draw_frame() · source line 314
static void draw_frame(esp_lcd_panel_handle_t panel, const uint16_t *frame)

Calls into this documentation:

  1. Executeconst uint16_t *const presentation_frame = globalOverlayCompose(frame);
  2. ExecutescreenshotCapturePresentation(presentation_frame);
  3. ExecuteESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap( panel, 0, 0, LCD_WIDTH, LCD_HEIGHT, presentation_frame));
  4. DecisionxSemaphoreTake(display_transfer_done, pdMS_TO_TICKS(1000)) != pdTRUE
    True
      1. ExecuteESP_LOGE(TAG, "LCD transfer timed out");
      2. ExecuteESP_ERROR_CHECK(ESP_ERR_TIMEOUT);
    False

    Continue after this decision.

Read original function source
static void draw_frame(esp_lcd_panel_handle_t panel, const uint16_t *frame)
{
    // The global overlay is composed last without changing the caller's scene framebuffer.
    // updateDoomCountdownOverlay();
    const uint16_t *const presentation_frame = globalOverlayCompose(frame);
    // Send the fully composed image, including any global overlay, before LCD DMA uses it.
    screenshotCapturePresentation(presentation_frame);
    ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(
        panel, 0, 0, LCD_WIDTH, LCD_HEIGHT, presentation_frame));
    // The framebuffer must stay unchanged until the LCD DMA transfer finishes.
    if (xSemaphoreTake(display_transfer_done, pdMS_TO_TICKS(1000)) != pdTRUE) {
        ESP_LOGE(TAG, "LCD transfer timed out");
        ESP_ERROR_CHECK(ESP_ERR_TIMEOUT);
    }
}
joystick_view_offset() · source line 331
static int joystick_view_offset(int raw, int centre, int travel)
  1. Decisionraw < 0
    True
      1. Executeraw = 0;
    False
    1. Decisionraw > 4095
      True
        1. Executeraw = 4095;
      False

      Continue after this decision.

  2. Executeconst int span = raw >= centre ? 4095 - centre : centre;
  3. Exit this functionreturn (raw - centre) * travel / span;
Read original function source
static int joystick_view_offset(int raw, int centre, int travel)
{
    if (raw < 0) {
        raw = 0;
    } else if (raw > 4095) {
        raw = 4095;
    }
    const int span = raw >= centre ? 4095 - centre : centre;
    return (raw - centre) * travel / span;
}
draw_controller_view() · source line 342
static void draw_controller_view(uint16_t *frame, const joystick_state_t *joystick,
                                 bool joystick_valid, const int *button_levels)

Calls into this documentation:

  1. Executeconst uint16_t background = RGB565(10, 16, 26);
  2. Executeconst uint16_t border = RGB565(76, 94, 115);
  3. Executeconst uint16_t white = RGB565(235, 241, 247);
  4. Executeconst uint16_t green = RGB565(70, 245, 130);
  5. Executeconst uint16_t cyan = RGB565(50, 205, 255);
  6. Executeconst uint16_t red = RGB565(255, 80, 65);
  7. Executeconst uint16_t amber = RGB565(255, 185, 60);
  8. Executestatic const int button_x[6] = {80, 108, 80, 52, 20, 20};
  9. Executestatic const int button_y[6] = {98, 124, 150, 124, 108, 80};
  10. Executestatic const char *button_names[7] = {"A", "B", "C", "D", "E", "F", "K"};
  11. Executeclear(frame, background);
  12. Executefill_rect(frame, 5, 5, 130, 160, RGB565(63, 26, 35));
  13. Executefill_rect(frame, 142, 8, 1, 154, border);
  14. Executeconst uint16_t stick_color = button_levels[6] == 0 ? green : button_levels[6] < 0 ? amber : border;
  15. Executefill_circle(frame, 80, 44, 35, stick_color);
  16. Executefill_circle(frame, 80, 44, 31, background);
  17. Executefill_rect(frame, 53, 44, 55, 1, border);
  18. Executefill_rect(frame, 80, 17, 1, 55, border);
  19. Executedraw_text(frame, 77, 19, "K", 1, stick_color);
  20. Decisionjoystick_valid
    True
      1. Executeconst int dot_x = 80 + joystick_view_offset(joystick->x_raw, JOYSTICK_CENTRE_X, 19);
      2. Executeconst int dot_y = 44 - joystick_view_offset(joystick->y_raw, JOYSTICK_CENTRE_Y, 19);
      3. Executefill_circle(frame, dot_x, dot_y, 5, background);
      4. Executefill_circle(frame, dot_x, dot_y, 4, cyan);
    False
      1. Executedraw_text(frame, 72, 38, "ERR", 1, red);
  21. FOR loopsize_t button = 0; button < 6; ++button

    Repeat body while the loop condition permits; then continue below.

      1. Executeconst uint16_t color = button_levels[button] == 0 ? green : button_levels[button] < 0 ? amber : border;
      2. Executefill_circle(frame, button_x[button], button_y[button], 12, color);
      3. Decisionbutton_levels[button] != 0
        True
          1. Executefill_circle(frame, button_x[button], button_y[button], 10, background);
        False

        Continue after this decision.

      4. Executedraw_text(frame, button_x[button] - 5, button_y[button] - 7, button_names[button], 2, button_levels[button] == 0 ? background : white);
  22. Executedraw_text(frame, 154, 10, "LIVE INPUT", 2, white);
  23. Executedraw_text(frame, 154, 33, joystick_valid ? "JOYSTICK OK" : "ADC READ ERROR", 1, joystick_valid ? cyan : red);
  24. Decisionjoystick_valid
    True
      1. Executechar reading[16];
      2. Executesnprintf(reading, sizeof(reading), "X %4d", joystick->x_raw);
      3. Executedraw_text(frame, 154, 51, reading, 2, white);
      4. Executesnprintf(reading, sizeof(reading), "Y %4d", joystick->y_raw);
      5. Executedraw_text(frame, 154, 73, reading, 2, white);
    False

    Continue after this decision.

  25. FOR loopsize_t button = 0; button < 7; ++button

    Repeat body while the loop condition permits; then continue below.

      1. Executeconst int x = 154 + (int)button * 23;
      2. Executeconst uint16_t color = button_levels[button] == 0 ? green : button_levels[button] < 0 ? amber : border;
      3. Executefill_rect(frame, x, 103, 20, 23, color);
      4. Executedraw_text(frame, x + 5, 108, button_names[button], 2, button_levels[button] == 0 ? background : white);
  26. Executedraw_text(frame, 154, 139, "GREEN MEANS PRESSED", 1, green);
  27. Executedraw_text(frame, 154, 154, "BOOT BACK USER SHOT", 1, white);
Read original function source
static void draw_controller_view(uint16_t *frame, const joystick_state_t *joystick,
                                 bool joystick_valid, const int *button_levels)
{
    const uint16_t background = RGB565(10, 16, 26);
    const uint16_t border = RGB565(76, 94, 115);
    const uint16_t white = RGB565(235, 241, 247);
    const uint16_t green = RGB565(70, 245, 130);
    const uint16_t cyan = RGB565(50, 205, 255);
    const uint16_t red = RGB565(255, 80, 65);
    const uint16_t amber = RGB565(255, 185, 60);
    static const int button_x[6] = {80, 108, 80, 52, 20, 20};
    static const int button_y[6] = {98, 124, 150, 124, 108, 80};
    static const char *button_names[7] = {"A", "B", "C", "D", "E", "F", "K"};

    clear(frame, background);
    fill_rect(frame, 5, 5, 130, 160, RGB565(63, 26, 35));
    fill_rect(frame, 142, 8, 1, 154, border);

    // Stick at top, F/E left; A north, B east, C south, D west.
    const uint16_t stick_color = button_levels[6] == 0 ? green :
                                 button_levels[6] < 0 ? amber : border;
    fill_circle(frame, 80, 44, 35, stick_color);
    fill_circle(frame, 80, 44, 31, background);
    fill_rect(frame, 53, 44, 55, 1, border);
    fill_rect(frame, 80, 17, 1, 55, border);
    draw_text(frame, 77, 19, "K", 1, stick_color);

    if (joystick_valid) {
        const int dot_x = 80 + joystick_view_offset(joystick->x_raw, JOYSTICK_CENTRE_X, 19);
        const int dot_y = 44 - joystick_view_offset(joystick->y_raw, JOYSTICK_CENTRE_Y, 19);
        fill_circle(frame, dot_x, dot_y, 5, background);
        fill_circle(frame, dot_x, dot_y, 4, cyan);
    } else {
        draw_text(frame, 72, 38, "ERR", 1, red);
    }

    for (size_t button = 0; button < 6; ++button) {
        const uint16_t color = button_levels[button] == 0 ? green :
                               button_levels[button] < 0 ? amber : border;
        fill_circle(frame, button_x[button], button_y[button], 12, color);
        if (button_levels[button] != 0) {
            fill_circle(frame, button_x[button], button_y[button], 10, background);
        }
        draw_text(frame, button_x[button] - 5, button_y[button] - 7,
                     button_names[button], 2,
                     button_levels[button] == 0 ? background : white);
    }

    draw_text(frame, 154, 10, "LIVE INPUT", 2, white);
    draw_text(frame, 154, 33, joystick_valid ? "JOYSTICK OK" : "ADC READ ERROR",
                 1, joystick_valid ? cyan : red);
    if (joystick_valid) {
        char reading[16];
        snprintf(reading, sizeof(reading), "X %4d", joystick->x_raw);
        draw_text(frame, 154, 51, reading, 2, white);
        snprintf(reading, sizeof(reading), "Y %4d", joystick->y_raw);
        draw_text(frame, 154, 73, reading, 2, white);
    }

    for (size_t button = 0; button < 7; ++button) {
        const int x = 154 + (int)button * 23;
        const uint16_t color = button_levels[button] == 0 ? green :
                               button_levels[button] < 0 ? amber : border;
        fill_rect(frame, x, 103, 20, 23, color);
        draw_text(frame, x + 5, 108, button_names[button], 2,
                     button_levels[button] == 0 ? background : white);
    }
    draw_text(frame, 154, 139, "GREEN MEANS PRESSED", 1, green);
    draw_text(frame, 154, 154, "BOOT BACK  USER SHOT", 1, white);
}
draw_battery_view() · source line 413
static void draw_battery_view(uint16_t *frame)

Calls into this documentation:

  1. Executeconst uint16_t background = RGB565(10, 16, 26);
  2. Executeconst uint16_t white = RGB565(235, 241, 247);
  3. Executeconst uint16_t cyan = RGB565(50, 205, 255);
  4. Executeconst uint16_t green = RGB565(70, 245, 130);
  5. Executeconst uint16_t red = RGB565(255, 80, 65);
  6. Executechar text[32];
  7. Executeclear(frame, background);
  8. Executedraw_text_centred(frame, 160, 16, "BATTERY", 3, cyan);
  9. Decisionbatt_has_reading()
    True
      1. Executesnprintf(text, sizeof(text), "%.1f V", (double)batt_voltage());
      2. Executedraw_text_centred(frame, 160, 62, text, 4, white);
      3. Executedraw_text_centred(frame, 160, 112, batt_external_power_connected() ? "EXTERNAL POWER" : "BATTERY POWER", 2, batt_external_power_connected() ? green : cyan);
      4. Executedraw_text_centred(frame, 160, 140, "UPDATES EVERY 15 SEC", 1, white);
    False
      1. Executedraw_text_centred(frame, 160, 80, "BATTERY ADC ERROR", 2, red);
  10. Executedraw_text_centred(frame, 160, 157, "BOOT BACK", 1, white);
Read original function source
static void draw_battery_view(uint16_t *frame)
{
    const uint16_t background = RGB565(10, 16, 26);
    const uint16_t white = RGB565(235, 241, 247);
    const uint16_t cyan = RGB565(50, 205, 255);
    const uint16_t green = RGB565(70, 245, 130);
    const uint16_t red = RGB565(255, 80, 65);
    char text[32];

    clear(frame, background);
    draw_text_centred(frame, 160, 16, "BATTERY", 3, cyan);
    if (batt_has_reading()) {
        snprintf(text, sizeof(text), "%.1f V", (double)batt_voltage());
        draw_text_centred(frame, 160, 62, text, 4, white);
        draw_text_centred(frame, 160, 112,
                             batt_external_power_connected() ? "EXTERNAL POWER" : "BATTERY POWER",
                             2, batt_external_power_connected() ? green : cyan);
        draw_text_centred(frame, 160, 140, "UPDATES EVERY 15 SEC", 1, white);
    } else {
        draw_text_centred(frame, 160, 80, "BATTERY ADC ERROR", 2, red);
    }
    draw_text_centred(frame, 160, 157, "BOOT BACK", 1, white);
}
draw_menu_view() · source line 437
static void draw_menu_view(uint16_t *frame, bool joystick_valid)

Calls into this documentation:

  1. Executeconst uint16_t black = RGB565(0, 0, 0);
  2. Executeconst uint16_t white = RGB565(235, 241, 247);
  3. Executeconst uint16_t green = RGB565(70, 245, 130);
  4. Executeconst uint16_t magenta = RGB565(235, 80, 225);
  5. Executeconst uint16_t cyan = RGB565(50, 205, 255);
  6. Executeconst uint16_t grey = RGB565(100, 115, 135);
  7. Executeconst uint16_t red = RGB565(255, 80, 65);
  8. Executeconst bool two_column_menu = menu_current_screen() == SCREEN_MENU || menu_current_screen() == SCREEN_GAMES || menu_current_screen() == SCREEN_SETTINGS || menu_current_screen() == SCREEN_MISC;
  9. Executeconst size_t per_page = two_column_menu ? 8 : 9;
  10. Executeconst size_t count = menu_count();
  11. Executeconst size_t selected = menu_selected_item();
  12. Executeconst size_t page = selected / per_page;
  13. Executeconst size_t first = page * per_page;
  14. Executeconst bool c64_menu = two_column_menu;
  15. Executeconst size_t page_items = count - first < per_page ? count - first : per_page;
  16. Executeconst size_t rows_per_column = two_column_menu && page_items != 0U ? (page_items + 1U) / 2U : 1U;
  17. Executeconst size_t selected_row = two_column_menu ? (selected - first) % rows_per_column : 0U;
  18. Executeconst size_t selected_column = two_column_menu ? (selected - first) / rows_per_column : 0U;
  19. Executeconst bool selected_is_text = strcmp(menu_item_text(selected), "BACK") != 0;
  20. Executeconst int selected_x = selected_column == 0U ? 10 : 166;
  21. Executeconst int selected_y = 46 + (int)selected_row * 25;
  22. Executeconst int selected_width = (int)strlen(menu_item_text(selected)) * PET2001_FONT_GLYPH_WIDTH * 2;
  23. Executechar page_text[32];
  24. Executeclear(frame, c64_menu ? C64_COLOR_BLUE : black);
  25. Decisionc64_menu
    True
    1. ExecutedrawPet2001Text(frame, 10, 10, menu_title(), false, C64_COLOR_LIGHT_GREEN, C64_COLOR_BLUE, 2);
    False
    1. Executedraw_text(frame, 10, 10, menu_title(), 2, cyan);
  26. ExecutedrawGameGold(frame, 174, 3, 80, true);
  27. Executesnprintf(page_text, sizeof(page_text), "%u OF %u", (unsigned)(page + 1), (unsigned)((count + per_page - 1) / per_page));
  28. Executedraw_text(frame, 260, 12, page_text, 1, c64_menu ? C64_COLOR_LIGHT_GREEN : grey);
  29. Decision!joystick_valid
    True
      1. Executedraw_text(frame, 10, 30, "ADC READ ERROR", 1, red);
    False
    1. Decision!aiTimingStorageHealthy()
      True
        1. Executedraw_text(frame, 10, 30, "AI TIMING STORAGE ERROR", 1, red);
      False
      1. Decisionmenu_current_screen() == SCREEN_GAMES && count == 1
        True
          1. Executedraw_text(frame, 10, 30, "NO GAMES YET", 1, grey);
        False

        Continue after this decision.

  30. FOR loopsize_t index = first; index < count && index < first + per_page; ++index

    Repeat body while the loop condition permits; then continue below.

      1. Executeconst size_t position = index - first;
      2. Executeconst bool highlighted = index == selected;
      3. Executeconst char *label = menu_item_text(index);
      4. Executeconst bool back_item = strcmp(label, "BACK") == 0;
      5. Decisiontwo_column_menu
        True
          1. Executeconst size_t column = position / rows_per_column;
          2. Executeconst size_t row = position % rows_per_column;
          3. Executeconst int x = column == 0U ? 10 : 166;
          4. Executeconst int y = 43 + (int)row * 25;
          5. Executeconst int normal_y = y + 7;
          6. Executeconst int normal_width = (int)strlen(label) * PET2001_FONT_GLYPH_WIDTH;
          7. Executeconst bool overlaps_selected = c64_menu && !highlighted && selected_is_text && x < selected_x + selected_width && selected_x < x + normal_width && normal_y < selected_y + 16 && selected_y < normal_y + 8;
          8. Decisionoverlaps_selected
            True
              1. Next loop iterationcontinue;
            False

            Continue after this decision.

          9. Decisionback_item
            True
              1. Executeconst int scale = highlighted ? 2 : 1;
              2. Executeconst int arrow_y = y + (22 - 8 * scale) / 2;
              3. Decisionc64_menu
                True
                  1. Decisionhighlighted
                    True
                    1. Executefill_rect(frame, x, arrow_y, 8 * scale, 8 * scale, C64_COLOR_LIGHT_GREEN);
                    False

                    Continue after this decision.

                  2. Executedraw_bitmap_scaled(frame, x, arrow_y, back_arrow_bitmap, 8, 8, 8 * scale, 8 * scale, highlighted ? C64_COLOR_BLUE : C64_COLOR_LIGHT_GREEN);
                False
                  1. Executedraw_bitmap_scaled(frame, x, arrow_y, back_arrow_bitmap, 8, 8, 8 * scale, 8 * scale, highlighted ? green : white);
            False
              1. Decisionc64_menu
                True
                  1. Executeconst int scale = highlighted ? 2 : 1;
                  2. ExecutedrawPet2001Text(frame, x, y + (highlighted ? 3 : 7), label, highlighted, C64_COLOR_LIGHT_GREEN, C64_COLOR_BLUE, scale);
                False
                  1. Executechar clipped[16];
                  2. Executeconst int maximum = highlighted ? 11 : 15;
                  3. Executeint length = 0;
                  4. WHILE looplabel[length] != '\0' && length < maximum

                    Repeat body while the loop condition permits; then continue below.

                      1. Executeclipped[length] = label[length];
                      2. Execute++length;
                  5. Executeclipped[length] = '\0';
                  6. Executedraw_text(frame, x, y + (highlighted ? 4 : 7), clipped, highlighted ? 2 : 1, highlighted ? green : white);
        False
          1. Executeconst int x = 4 + (int)(position % 3) * 106;
          2. Executeconst int y = 44 + (int)(position / 3) * 35;
          3. Executeconst uint16_t accent = menu_item_is_submenu(index) ? magenta : green;
          4. Decisionback_item
            True
              1. Executeconst int scale = highlighted ? 2 : 1;
              2. Executeconst int size = 8 * scale;
              3. Executedraw_bitmap_scaled(frame, x + (100 - size) / 2, y + (30 - size) / 2, back_arrow_bitmap, 8, 8, size, size, accent);
              4. Next loop iterationcontinue;
            False

            Continue after this decision.

          5. Executechar clipped[17];
          6. Executeconst int maximum = highlighted ? 7 : 14;
          7. Executeint length = 0;
          8. WHILE looplabel[length] != '\0' && length < maximum

            Repeat body while the loop condition permits; then continue below.

              1. Executeclipped[length] = label[length];
              2. Execute++length;
          9. Executeclipped[length] = '\0';
          10. Executeconst int scale = highlighted ? 2 : 1;
          11. Executeconst int text_width = length * UI_FONT_ADVANCE * scale - scale;
          12. Executedraw_text(frame, x + (100 - text_width) / 2, y + (30 - UI_FONT_HEIGHT * scale) / 2, clipped, scale, accent);
  31. Executedraw_text(frame, 8, 156, two_column_menu ? "D/B UP/DOWN STICK MOVE A/K SELECT" : "D/B/STICK MOVE A/K SELECT", 1, c64_menu ? C64_COLOR_LIGHT_GREEN : grey);
  32. Executedraw_text(frame, 250, 156, "BOOT BACK", 1, c64_menu ? C64_COLOR_LIGHT_GREEN : grey);
Read original function source
static void draw_menu_view(uint16_t *frame, bool joystick_valid)
{
    const uint16_t black = RGB565(0, 0, 0);
    const uint16_t white = RGB565(235, 241, 247);
    const uint16_t green = RGB565(70, 245, 130);
    const uint16_t magenta = RGB565(235, 80, 225);
    const uint16_t cyan = RGB565(50, 205, 255);
    const uint16_t grey = RGB565(100, 115, 135);
    const uint16_t red = RGB565(255, 80, 65);
    const bool two_column_menu = menu_current_screen() == SCREEN_MENU ||
                                 menu_current_screen() == SCREEN_GAMES ||
                                 menu_current_screen() == SCREEN_SETTINGS ||
                                 menu_current_screen() == SCREEN_MISC;
    const size_t per_page = two_column_menu ? 8 : 9;
    const size_t count = menu_count();
    const size_t selected = menu_selected_item();
    const size_t page = selected / per_page;
    const size_t first = page * per_page;
    const bool c64_menu = two_column_menu;
    const size_t page_items = count - first < per_page ? count - first : per_page;
    const size_t rows_per_column = two_column_menu && page_items != 0U ?
                                       (page_items + 1U) / 2U : 1U;
    const size_t selected_row = two_column_menu ? (selected - first) % rows_per_column : 0U;
    const size_t selected_column = two_column_menu ?
                                       (selected - first) / rows_per_column : 0U;
    const bool selected_is_text = strcmp(menu_item_text(selected), "BACK") != 0;
    const int selected_x = selected_column == 0U ? 10 : 166;
    const int selected_y = 46 + (int)selected_row * 25;
    const int selected_width = (int)strlen(menu_item_text(selected)) *
                               PET2001_FONT_GLYPH_WIDTH * 2;
    char page_text[32];

    clear(frame, c64_menu ? C64_COLOR_BLUE : black);
    if (c64_menu)
        drawPet2001Text(frame, 10, 10, menu_title(), false,
                        C64_COLOR_LIGHT_GREEN, C64_COLOR_BLUE, 2);
    else draw_text(frame, 10, 10, menu_title(), 2, cyan);
    drawGameGold(frame, 174, 3, 80, true);
    snprintf(page_text, sizeof(page_text), "%u OF %u", (unsigned)(page + 1),
             (unsigned)((count + per_page - 1) / per_page));
    draw_text(frame, 260, 12, page_text, 1,
              c64_menu ? C64_COLOR_LIGHT_GREEN : grey);
    if (!joystick_valid) {
        draw_text(frame, 10, 30, "ADC READ ERROR", 1, red);
    } else if (!aiTimingStorageHealthy()) {
        draw_text(frame, 10, 30, "AI TIMING STORAGE ERROR", 1, red);
    } else if (menu_current_screen() == SCREEN_GAMES && count == 1) {
        draw_text(frame, 10, 30, "NO GAMES YET", 1, grey);
    }

    for (size_t index = first; index < count && index < first + per_page; ++index) {
        const size_t position = index - first;
        const bool highlighted = index == selected;
        const char *label = menu_item_text(index);
        const bool back_item = strcmp(label, "BACK") == 0;
        if (two_column_menu) {
            const size_t column = position / rows_per_column;
            const size_t row = position % rows_per_column;
            const int x = column == 0U ? 10 : 166;
            const int y = 43 + (int)row * 25;
            const int normal_y = y + 7;
            const int normal_width = (int)strlen(label) * PET2001_FONT_GLYPH_WIDTH;
            const bool overlaps_selected = c64_menu && !highlighted && selected_is_text &&
                                           x < selected_x + selected_width &&
                                           selected_x < x + normal_width &&
                                           normal_y < selected_y + 16 &&
                                           selected_y < normal_y + 8;
            if (overlaps_selected) {
                continue;
            }
            if (back_item) {
                const int scale = highlighted ? 2 : 1;
                const int arrow_y = y + (22 - 8 * scale) / 2;
                if (c64_menu) {
                    if (highlighted)
                        fill_rect(frame, x, arrow_y, 8 * scale, 8 * scale,
                                  C64_COLOR_LIGHT_GREEN);
                    draw_bitmap_scaled(frame, x, arrow_y, back_arrow_bitmap, 8, 8,
                                       8 * scale, 8 * scale,
                                       highlighted ? C64_COLOR_BLUE : C64_COLOR_LIGHT_GREEN);
                } else {
                    draw_bitmap_scaled(frame, x, arrow_y, back_arrow_bitmap, 8, 8,
                                       8 * scale, 8 * scale, highlighted ? green : white);
                }
            } else {
                if (c64_menu) {
                    const int scale = highlighted ? 2 : 1;
                    drawPet2001Text(frame, x, y + (highlighted ? 3 : 7), label, highlighted,
                                    C64_COLOR_LIGHT_GREEN, C64_COLOR_BLUE, scale);
                } else {
                    char clipped[16];
                    const int maximum = highlighted ? 11 : 15;
                    int length = 0;
                    while (label[length] != '\0' && length < maximum) {
                        clipped[length] = label[length];
                        ++length;
                    }
                    clipped[length] = '\0';
                    draw_text(frame, x, y + (highlighted ? 4 : 7), clipped,
                              highlighted ? 2 : 1, highlighted ? green : white);
                }
            }
        } else {
            const int x = 4 + (int)(position % 3) * 106;
            const int y = 44 + (int)(position / 3) * 35;
            const uint16_t accent = menu_item_is_submenu(index) ? magenta : green;
            if (back_item) {
                const int scale = highlighted ? 2 : 1;
                const int size = 8 * scale;
                draw_bitmap_scaled(frame, x + (100 - size) / 2, y + (30 - size) / 2,
                               back_arrow_bitmap, 8, 8, size, size, accent);
                continue;
            }
            char clipped[17];
            const int maximum = highlighted ? 7 : 14;
            int length = 0;
            while (label[length] != '\0' && length < maximum) {
                clipped[length] = label[length];
                ++length;
            }
            clipped[length] = '\0';
            const int scale = highlighted ? 2 : 1;
            const int text_width = length * UI_FONT_ADVANCE * scale - scale;
            draw_text(frame, x + (100 - text_width) / 2,
                         y + (30 - UI_FONT_HEIGHT * scale) / 2, clipped, scale,
                         accent);
        }
    }
    draw_text(frame, 8, 156, two_column_menu ? "D/B UP/DOWN  STICK MOVE  A/K SELECT" :
                                               "D/B/STICK MOVE  A/K SELECT", 1,
              c64_menu ? C64_COLOR_LIGHT_GREEN : grey);
    draw_text(frame, 250, 156, "BOOT BACK", 1,
              c64_menu ? C64_COLOR_LIGHT_GREEN : grey);
}
initialize_buttons() · source line 572
static void initialize_buttons(void)
  1. Execute(void)gpio_hold_dis(PIN_BUTTON_BOOT);
  2. Execute(void)gpio_hold_dis(PIN_BUTTON_USER);
  3. ExecuteESP_ERROR_CHECK(gpio_reset_pin(PIN_BUTTON_BOOT));
  4. ExecuteESP_ERROR_CHECK(gpio_reset_pin(PIN_BUTTON_USER));
  5. Executeconst gpio_config_t button_config = { .pin_bit_mask = (1ULL << PIN_BUTTON_BOOT) | (1ULL << PIN_BUTTON_USER), .mode = GPIO_MODE_INPUT, .pull_up_en = GPIO_PULLUP_ENABLE, .pull_down_en = GPIO_PULLDOWN_DISABLE, .intr_type = GPIO_INTR_DISABLE, };
  6. ExecuteESP_ERROR_CHECK(gpio_config(&button_config));
Read original function source
static void initialize_buttons(void)
{
    // A software reset after light sleep can retain a pad's prior sleep state.
    // Clear it before restoring the board buttons as active-low pull-up inputs.
    (void)gpio_hold_dis(PIN_BUTTON_BOOT);
    (void)gpio_hold_dis(PIN_BUTTON_USER);
    ESP_ERROR_CHECK(gpio_reset_pin(PIN_BUTTON_BOOT));
    ESP_ERROR_CHECK(gpio_reset_pin(PIN_BUTTON_USER));
    const gpio_config_t button_config = {
        .pin_bit_mask = (1ULL << PIN_BUTTON_BOOT) | (1ULL << PIN_BUTTON_USER),
        .mode = GPIO_MODE_INPUT,
        .pull_up_en = GPIO_PULLUP_ENABLE,
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .intr_type = GPIO_INTR_DISABLE,
    };
    ESP_ERROR_CHECK(gpio_config(&button_config));
}
initialize_audio_shutdown() · source line 590
static void initialize_audio_shutdown(void)
  1. Execute(void)gpio_hold_dis(PIN_AUDIO_SHUTDOWN);
  2. ExecuteESP_ERROR_CHECK(gpio_reset_pin(PIN_AUDIO_SHUTDOWN));
  3. Executeconst gpio_config_t shutdown_config = { .pin_bit_mask = 1ULL << PIN_AUDIO_SHUTDOWN, .mode = GPIO_MODE_OUTPUT, .pull_up_en = GPIO_PULLUP_DISABLE, .pull_down_en = GPIO_PULLDOWN_DISABLE, .intr_type = GPIO_INTR_DISABLE, };
  4. ExecuteESP_ERROR_CHECK(gpio_config(&shutdown_config));
  5. ExecuteESP_ERROR_CHECK(gpio_set_level(PIN_AUDIO_SHUTDOWN, 1));
  6. ExecuteESP_LOGI(TAG, "Amplifier shutdown control ready on GPIO%d", PIN_AUDIO_SHUTDOWN);
Read original function source
static void initialize_audio_shutdown(void)
{
    (void)gpio_hold_dis(PIN_AUDIO_SHUTDOWN);
    ESP_ERROR_CHECK(gpio_reset_pin(PIN_AUDIO_SHUTDOWN));
    const gpio_config_t shutdown_config = {
        .pin_bit_mask = 1ULL << PIN_AUDIO_SHUTDOWN,
        .mode = GPIO_MODE_OUTPUT,
        .pull_up_en = GPIO_PULLUP_DISABLE,
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .intr_type = GPIO_INTR_DISABLE,
    };
    ESP_ERROR_CHECK(gpio_config(&shutdown_config));
    ESP_ERROR_CHECK(gpio_set_level(PIN_AUDIO_SHUTDOWN, 1));
    ESP_LOGI(TAG, "Amplifier shutdown control ready on GPIO%d", PIN_AUDIO_SHUTDOWN);
}
restore_light_sleep_button_inputs() · source line 606
static void restore_light_sleep_button_inputs(void)

Calls into this documentation:

  1. Execute(void)gpio_hold_dis(PIN_BUTTON_BOOT);
  2. Execute(void)gpio_hold_dis(PIN_BUTTON_USER);
  3. Execute(void)gpio_hold_dis(PIN_LIGHT_SLEEP_WAKE);
  4. Executeinitialize_buttons();
  5. Executeconst gpio_config_t wake_button_config = { .pin_bit_mask = 1ULL << PIN_LIGHT_SLEEP_WAKE, .mode = GPIO_MODE_INPUT, .pull_up_en = GPIO_PULLUP_ENABLE, .pull_down_en = GPIO_PULLDOWN_DISABLE, .intr_type = GPIO_INTR_DISABLE, };
  6. ExecuteESP_ERROR_CHECK(gpio_config(&wake_button_config));
  7. Executereset_button_debounce_after_sleep = true;
Read original function source
static void restore_light_sleep_button_inputs(void)
{
    (void)gpio_hold_dis(PIN_BUTTON_BOOT);
    (void)gpio_hold_dis(PIN_BUTTON_USER);
    (void)gpio_hold_dis(PIN_LIGHT_SLEEP_WAKE);
    initialize_buttons();
    const gpio_config_t wake_button_config = {
        .pin_bit_mask = 1ULL << PIN_LIGHT_SLEEP_WAKE,
        .mode = GPIO_MODE_INPUT,
        .pull_up_en = GPIO_PULLUP_ENABLE,
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .intr_type = GPIO_INTR_DISABLE,
    };
    ESP_ERROR_CHECK(gpio_config(&wake_button_config));
    reset_button_debounce_after_sleep = true;
}
initialize_tf_card() · source line 624
static bool initialize_tf_card(void)
  1. ExecuteESP_LOGI(TAG, "Initializing TF card on CS=%d, MOSI=%d, SCK=%d, MISO=%d", PIN_TF_CS, PIN_TF_MOSI, PIN_TF_SCK, PIN_TF_MISO);
  2. Executesdmmc_host_t host = SDSPI_HOST_DEFAULT();
  3. Executehost.slot = SPI2_HOST;
  4. Executehost.max_freq_khz = TF_MAX_FREQUENCY_KHZ;
  5. Executeconst spi_bus_config_t bus_config = { .mosi_io_num = PIN_TF_MOSI, .miso_io_num = PIN_TF_MISO, .sclk_io_num = PIN_TF_SCK, .quadwp_io_num = -1, .quadhd_io_num = -1, .max_transfer_sz = 4096, };
  6. Executeesp_err_t result = spi_bus_initialize(host.slot, &bus_config, SPI_DMA_CH_AUTO);
  7. Decisionresult != ESP_OK
    True
      1. ExecuteESP_LOGE(TAG, "TF SPI bus initialization failed: %s", esp_err_to_name(result));
      2. Exit this functionreturn false;
    False

    Continue after this decision.

  8. Executesdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT();
  9. Executeslot_config.gpio_cs = PIN_TF_CS;
  10. Executeslot_config.host_id = host.slot;
  11. Executeconst esp_vfs_fat_sdmmc_mount_config_t mount_config = { .format_if_mount_failed = false, .max_files = 5, .allocation_unit_size = 16 * 1024, };
  12. Executeresult = esp_vfs_fat_sdspi_mount( TF_MOUNT_POINT, &host, &slot_config, &mount_config, &tf_card);
  13. Decisionresult != ESP_OK
    True
      1. ExecuteESP_LOGE(TAG, "TF card mount failed: %s", esp_err_to_name(result));
      2. Executespi_bus_free(host.slot);
      3. Exit this functionreturn false;
    False

    Continue after this decision.

  14. ExecuteESP_LOGI(TAG, "TF card mounted read/write at %s", TF_MOUNT_POINT);
  15. Executesdmmc_card_print_info(stdout, tf_card);
  16. Executestruct statvfs filesystem = {0};
  17. Decisionstatvfs(TF_MOUNT_POINT, &filesystem) == 0
    True
      1. Executeconst uint64_t total_bytes = (uint64_t)filesystem.f_blocks * filesystem.f_frsize;
      2. Executeconst uint64_t free_bytes = (uint64_t)filesystem.f_bfree * filesystem.f_frsize;
      3. ExecuteESP_LOGI(TAG, "TF filesystem total/free: %" PRIu64 " / %" PRIu64 " bytes", total_bytes, free_bytes);
    False
      1. ExecuteESP_LOGW(TAG, "TF card mounted, but filesystem space could not be read");
  18. Exit this functionreturn true;
Read original function source
static bool initialize_tf_card(void)
{
    ESP_LOGI(TAG, "Initializing TF card on CS=%d, MOSI=%d, SCK=%d, MISO=%d",
             PIN_TF_CS, PIN_TF_MOSI, PIN_TF_SCK, PIN_TF_MISO);

    sdmmc_host_t host = SDSPI_HOST_DEFAULT();
    host.slot = SPI2_HOST;
    host.max_freq_khz = TF_MAX_FREQUENCY_KHZ;

    const spi_bus_config_t bus_config = {
        .mosi_io_num = PIN_TF_MOSI,
        .miso_io_num = PIN_TF_MISO,
        .sclk_io_num = PIN_TF_SCK,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1,
        .max_transfer_sz = 4096,
    };

    esp_err_t result = spi_bus_initialize(host.slot, &bus_config, SPI_DMA_CH_AUTO);
    if (result != ESP_OK) {
        ESP_LOGE(TAG, "TF SPI bus initialization failed: %s", esp_err_to_name(result));
        return false;
    }

    sdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT();
    slot_config.gpio_cs = PIN_TF_CS;
    slot_config.host_id = host.slot;

    const esp_vfs_fat_sdmmc_mount_config_t mount_config = {
        .format_if_mount_failed = false,
        .max_files = 5,
        .allocation_unit_size = 16 * 1024,
    };

    result = esp_vfs_fat_sdspi_mount(
        TF_MOUNT_POINT, &host, &slot_config, &mount_config, &tf_card);
    if (result != ESP_OK) {
        ESP_LOGE(TAG, "TF card mount failed: %s", esp_err_to_name(result));
        spi_bus_free(host.slot);
        return false;
    }

    ESP_LOGI(TAG, "TF card mounted read/write at %s", TF_MOUNT_POINT);
    sdmmc_card_print_info(stdout, tf_card);

    struct statvfs filesystem = {0};
    if (statvfs(TF_MOUNT_POINT, &filesystem) == 0) {
        const uint64_t total_bytes =
            (uint64_t)filesystem.f_blocks * filesystem.f_frsize;
        const uint64_t free_bytes =
            (uint64_t)filesystem.f_bfree * filesystem.f_frsize;
        ESP_LOGI(TAG, "TF filesystem total/free: %" PRIu64 " / %" PRIu64 " bytes",
                 total_bytes, free_bytes);
    } else {
        ESP_LOGW(TAG, "TF card mounted, but filesystem space could not be read");
    }

    return true;
}
enter_light_sleep() · source line 685
static bool enter_light_sleep(esp_lcd_panel_handle_t panel, bool *tf_available)

Calls into this documentation:

  1. Preprocessor directive#if !TF_CARD_ENABLED
  2. Execute(void)tf_available;
  3. Preprocessor directive#endif
  4. Executeconst int wake_button_level = gpio_get_level(PIN_LIGHT_SLEEP_WAKE);
  5. Decisionwake_button_level == 0
    True
      1. ExecuteESP_LOGW(TAG, "Light sleep cancelled; release shield B (GPIO%d)", PIN_LIGHT_SLEEP_WAKE);
      2. Exit this functionreturn false;
    False

    Continue after this decision.

  6. Executeconst uint64_t wake_pins = 1ULL << PIN_LIGHT_SLEEP_WAKE;
  7. Executeconst esp_err_t wake_result = esp_sleep_enable_ext1_wakeup( wake_pins, ESP_EXT1_WAKEUP_ANY_LOW);
  8. Decisionwake_result != ESP_OK
    True
      1. ExecuteESP_LOGE(TAG, "Light-sleep wake configuration failed: %s", esp_err_to_name(wake_result));
      2. Exit this functionreturn false;
    False

    Continue after this decision.

  9. ExecutetimeSyncStop();
  10. Execute(void)wifiServiceStop();
  11. Preprocessor directive#if TF_CARD_ENABLED
  12. Decision*tf_available && tf_card != NULL
    True
      1. Executeconst esp_err_t unmount_result = esp_vfs_fat_sdcard_unmount(TF_MOUNT_POINT, tf_card);
      2. Decisionunmount_result == ESP_OK
        True
          1. Executetf_card = NULL;
          2. Execute*tf_available = false;
          3. Executeconst esp_err_t bus_result = spi_bus_free(SPI2_HOST);
          4. Decisionbus_result != ESP_OK
            True
              1. ExecuteESP_LOGW(TAG, "TF SPI release failed: %s", esp_err_to_name(bus_result));
            False

            Continue after this decision.

        False
          1. ExecuteESP_LOGW(TAG, "TF card unmount failed: %s", esp_err_to_name(unmount_result));
    False

    Continue after this decision.

  13. Preprocessor directive#endif
  14. ExecuteESP_ERROR_CHECK(ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 0));
  15. ExecuteESP_ERROR_CHECK(ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0));
  16. ExecuteESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel, false));
  17. ExecuteESP_ERROR_CHECK(gpio_set_level(PIN_AUDIO_SHUTDOWN, 0));
  18. ExecuteESP_ERROR_CHECK(gpio_hold_en(PIN_AUDIO_SHUTDOWN));
  19. ExecuteESP_LOGI(TAG, "Entering light sleep; press shield B to wake");
  20. Executeconst esp_err_t sleep_result = esp_light_sleep_start();
  21. Decisionsleep_result != ESP_OK
    True
      1. ExecuteESP_LOGE(TAG, "Light sleep failed: %s", esp_err_to_name(sleep_result));
    False

    Continue after this decision.

  22. ExecuteESP_ERROR_CHECK(esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_EXT1));
  23. ExecuteESP_ERROR_CHECK(gpio_hold_dis(PIN_AUDIO_SHUTDOWN));
  24. ExecuteESP_ERROR_CHECK(gpio_set_level(PIN_AUDIO_SHUTDOWN, 1));
  25. Executerestore_light_sleep_button_inputs();
  26. ExecuteESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel, true));
  27. Executeset_backlight_brightness(settingsBrightness());
  28. Preprocessor directive#if TF_CARD_ENABLED
  29. Decision!*tf_available
    True
      1. Execute*tf_available = initialize_tf_card();
      2. ExecuteESP_LOGI(TAG, "TF CARD AFTER WAKE: %s", *tf_available ? "READY" : "NOT AVAILABLE");
    False

    Continue after this decision.

  30. Preprocessor directive#endif
  31. ExecuteESP_LOGI(TAG, "Resumed from light sleep");
  32. Exit this functionreturn sleep_result == ESP_OK;
Read original function source
static bool enter_light_sleep(esp_lcd_panel_handle_t panel, bool *tf_available)
{
#if !TF_CARD_ENABLED
    (void)tf_available;
#endif
    const int wake_button_level = gpio_get_level(PIN_LIGHT_SLEEP_WAKE);
    if (wake_button_level == 0) {
        ESP_LOGW(TAG, "Light sleep cancelled; release shield B (GPIO%d)",
                 PIN_LIGHT_SLEEP_WAKE);
        return false;
    }

    const uint64_t wake_pins = 1ULL << PIN_LIGHT_SLEEP_WAKE;
    const esp_err_t wake_result = esp_sleep_enable_ext1_wakeup(
        wake_pins, ESP_EXT1_WAKEUP_ANY_LOW);
    if (wake_result != ESP_OK) {
        ESP_LOGE(TAG, "Light-sleep wake configuration failed: %s",
                 esp_err_to_name(wake_result));
        return false;
    }

    timeSyncStop();
    (void)wifiServiceStop();
#if TF_CARD_ENABLED
    if (*tf_available && tf_card != NULL) {
        const esp_err_t unmount_result = esp_vfs_fat_sdcard_unmount(TF_MOUNT_POINT, tf_card);
        if (unmount_result == ESP_OK) {
            tf_card = NULL;
            *tf_available = false;
            const esp_err_t bus_result = spi_bus_free(SPI2_HOST);
            if (bus_result != ESP_OK) {
                ESP_LOGW(TAG, "TF SPI release failed: %s", esp_err_to_name(bus_result));
            }
        } else {
            ESP_LOGW(TAG, "TF card unmount failed: %s", esp_err_to_name(unmount_result));
        }
    }
#endif

    ESP_ERROR_CHECK(ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 0));
    ESP_ERROR_CHECK(ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0));
    ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel, false));
    ESP_ERROR_CHECK(gpio_set_level(PIN_AUDIO_SHUTDOWN, 0));
    ESP_ERROR_CHECK(gpio_hold_en(PIN_AUDIO_SHUTDOWN));
    ESP_LOGI(TAG, "Entering light sleep; press shield B to wake");
    const esp_err_t sleep_result = esp_light_sleep_start();
    if (sleep_result != ESP_OK) {
        ESP_LOGE(TAG, "Light sleep failed: %s", esp_err_to_name(sleep_result));
    }
    ESP_ERROR_CHECK(esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_EXT1));
    ESP_ERROR_CHECK(gpio_hold_dis(PIN_AUDIO_SHUTDOWN));
    ESP_ERROR_CHECK(gpio_set_level(PIN_AUDIO_SHUTDOWN, 1));
    restore_light_sleep_button_inputs();

    ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel, true));
    set_backlight_brightness(settingsBrightness());
#if TF_CARD_ENABLED
    if (!*tf_available) {
        *tf_available = initialize_tf_card();
        ESP_LOGI(TAG, "TF CARD AFTER WAKE: %s",
                 *tf_available ? "READY" : "NOT AVAILABLE");
    }
#endif
    ESP_LOGI(TAG, "Resumed from light sleep");
    return sleep_result == ESP_OK;
}
app_main() · source line 752
void app_main(void)

Calls into this documentation:

  1. Executeesp_chip_info_t chip_info = {0};
  2. Executeuint32_t flash_size = 0;
  3. Executeesp_chip_info(&chip_info);
  4. Executeconst esp_err_t flash_result = esp_flash_get_size(NULL, &flash_size);
  5. Executeconst bool psram_initialized = esp_psram_is_initialized();
  6. Executeconst size_t psram_chip_size = esp_psram_get_size();
  7. Executeconst size_t psram_total = heap_caps_get_total_size(MALLOC_CAP_SPIRAM);
  8. Executeconst size_t psram_free = heap_caps_get_free_size(MALLOC_CAP_SPIRAM);
  9. ExecuteESP_LOGI(TAG, "LilyGO T-Display-S3 V1.1 diagnostic");
  10. ExecuteESP_LOGI(TAG, "Chip: ESP32-S3, revision %d, %d CPU cores", chip_info.revision, chip_info.cores);
  11. ExecuteESP_LOGI(TAG, "Configured CPU frequency: %d MHz", CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ);
  12. Decisionflash_result == ESP_OK
    True
      1. ExecuteESP_LOGI(TAG, "Detected flash: %" PRIu32 " MB", flash_size / (1024U * 1024U));
    False
      1. ExecuteESP_LOGE(TAG, "Unable to read flash size: %s", esp_err_to_name(flash_result));
  13. ExecuteESP_LOGI(TAG, "PSRAM initialized: %s", psram_initialized ? "yes" : "no");
  14. ExecuteESP_LOGI(TAG, "PSRAM chip size: %u bytes", (unsigned)psram_chip_size);
  15. ExecuteESP_LOGI(TAG, "PSRAM heap total/free: %u / %u bytes", (unsigned)psram_total, (unsigned)psram_free);
  16. Executeconst bool memory_ok = flash_result == ESP_OK && flash_size == EXPECTED_FLASH_BYTES && psram_initialized && psram_chip_size >= EXPECTED_PSRAM_BYTES;
  17. Decision!memory_ok
    True
      1. ExecuteESP_LOGE(TAG, "Memory check FAILED: expected 16 MB flash and 8 MB PSRAM");
    False

    Continue after this decision.

  18. Executeuint16_t *frame = heap_caps_malloc( FRAME_BUFFER_BYTES, MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA | MALLOC_CAP_8BIT);
  19. Decisionframe == NULL
    True
      1. ExecuteESP_LOGE(TAG, "Unable to allocate the %u-byte PSRAM display buffer", (unsigned)FRAME_BUFFER_BYTES);
      2. Exit this functionreturn;
    False

    Continue after this decision.

  20. ExecuteESP_LOGI(TAG, "PSRAM display buffer allocated: %u bytes", (unsigned)FRAME_BUFFER_BYTES);
  21. Decision!globalOverlayInitialize()
    True
      1. ExecuteESP_LOGE(TAG, "Unable to allocate the %u-byte PSRAM overlay presentation buffer", (unsigned)FRAME_BUFFER_BYTES);
      2. Executeheap_caps_free(frame);
      3. Exit this functionreturn;
    False

    Continue after this decision.

  22. Executedisplay_transfer_done = xSemaphoreCreateBinary();
  23. Decisiondisplay_transfer_done == NULL
    True
      1. ExecuteESP_LOGE(TAG, "Unable to allocate LCD transfer semaphore");
      2. ExecuteglobalOverlayDeinitialize();
      3. Executeheap_caps_free(frame);
      4. Exit this functionreturn;
    False

    Continue after this decision.

  24. Executeinitialize_buttons();
  25. Executeinitialize_audio_shutdown();
  26. Executeesp_lcd_panel_handle_t panel = initialize_display();
  27. Decisionmemory_ok
    True
      1. Executeclear(frame, RGB565(0, 0, 0));
    False
      1. Executeclear(frame, RGB565(255, 0, 255));
      2. ExecuteESP_LOGE(TAG, "Magenta screen indicates a memory diagnostic failure");
  28. Executedraw_frame(panel, frame);
  29. ExecuteESP_LOGI(TAG, "LilyGO T-Display-S3 V1.1 diagnostic report");
  30. ExecuteESP_LOGI(TAG, "Chip: ESP32-S3, revision %d, %d CPU cores", chip_info.revision, chip_info.cores);
  31. ExecuteESP_LOGI(TAG, "Configured CPU frequency: %d MHz", CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ);
  32. Decisionflash_result == ESP_OK
    True
      1. ExecuteESP_LOGI(TAG, "Detected flash: %" PRIu32 " MB", flash_size / (1024U * 1024U));
    False
      1. ExecuteESP_LOGE(TAG, "Unable to read flash size: %s", esp_err_to_name(flash_result));
  33. ExecuteESP_LOGI(TAG, "PSRAM initialized: %s", psram_initialized ? "yes" : "no");
  34. ExecuteESP_LOGI(TAG, "PSRAM chip size: %u bytes", (unsigned)psram_chip_size);
  35. ExecuteESP_LOGI(TAG, "PSRAM heap total/free at startup: %u / %u bytes", (unsigned)psram_total, (unsigned)psram_free);
  36. ExecuteESP_LOGI(TAG, "PSRAM display buffer: %u bytes", (unsigned)FRAME_BUFFER_BYTES);
  37. Decisionmemory_ok
    True
      1. ExecuteESP_LOGI(TAG, "BOARD DIAGNOSTIC: PASS");
    False
      1. ExecuteESP_LOGE(TAG, "BOARD DIAGNOSTIC: FAIL");
  38. Executebool tf_available = false;
  39. Preprocessor directive#if TF_CARD_ENABLED
  40. Executetf_available = initialize_tf_card();
  41. ExecuteESP_LOGI(TAG, "TF CARD: %s", tf_available ? "READY" : "NOT AVAILABLE");
  42. Preprocessor directive#else
  43. ExecuteESP_LOGI(TAG, "TF CARD: DISABLED");
  44. Preprocessor directive#endif
  45. Executeconst bool dungeon_files_ready = dungeonFilesInitialize(tf_available);
  46. ExecuteESP_LOGI(TAG, "DUNGEON DATA: %s", dungeon_files_ready ? "READY" : "NOT AVAILABLE");
  47. Preprocessor directive#if RAM_MONITOR_ENABLED
  48. Decisiondungeon_files_ready
    True
    1. ExecuteramMonitorInitialize();
    False
    1. ExecuteESP_LOGW(TAG, "RAM MONITOR: DISABLED (SPIFFS NOT AVAILABLE)");
  49. Preprocessor directive#else
  50. ExecuteESP_LOGI(TAG, "RAM MONITOR: DISABLED (FEATURE SWITCH)");
  51. Preprocessor directive#endif
  52. Executeconst bool storage_ready = game_storage_initialize();
  53. Executeconst bool gold_ready = storage_ready && initGold();
  54. Executeconst bool timing_ready = storage_ready && initAITiming();
  55. Executeconst bool settings_ready = storage_ready && settingsInitialize();
  56. Executeconst bool clock_time_ready = storage_ready && timeSyncInitialize();
  57. Executeconst bool audio_ready = audioInitialize();
  58. Executeset_backlight_brightness(settingsBrightness());
  59. ExecuteESP_LOGI(TAG, "GAME STORAGE: %s; GOLD: %s; AI TIMING: %s; SETTINGS: %s; CLOCK: %s; AUDIO: %s", storage_ready ? "READY" : "FAILED", gold_ready ? "READY" : "FAILED", timing_ready ? "READY" : "DEFAULTS ONLY", settings_ready ? "READY" : "DEFAULTS ONLY", clock_time_ready ? "READY" : "DEFAULTS ONLY", audio_ready ? "READY" : "FAILED");
  60. Decisionstorage_ready
    True
      1. Executenvs_stats_t stats = {0};
      2. Executeconst esp_err_t stats_result = nvs_get_stats(NULL, &stats);
      3. Decisionstats_result == ESP_OK
        True
          1. ExecuteESP_LOGI(TAG, "NVS entries: used %u; available %u; total %u", (unsigned)stats.used_entries, (unsigned)stats.available_entries, (unsigned)stats.total_entries);
        False
          1. ExecuteESP_LOGW(TAG, "Cannot read NVS capacity: %s", esp_err_to_name(stats_result));
    False

    Continue after this decision.

  61. ExecuteESP_LOGI(TAG, "Initializing raw joystick test");
  62. ExecuteESP_LOGI(TAG, "Joystick X: GPIO1 / ADC1 channel 0");
  63. ExecuteESP_LOGI(TAG, "Joystick Y: GPIO2 / ADC1 channel 1");
  64. Executeconst esp_err_t joystick_result = controller_input_initialize();
  65. Decisionjoystick_result != ESP_OK
    True
      1. ExecuteESP_LOGE(TAG, "Joystick initialization failed: %s", esp_err_to_name(joystick_result));
      2. Exit this functionreturn;
    False

    Continue after this decision.

  66. Executeconst bool battery_ready = batt_initialize();
  67. ExecuteESP_LOGI(TAG, "BATTERY ADC: %s", battery_ready ? "READY" : "FAILED");
  68. ExecuteESP_LOGI(TAG, "RAW JOYSTICK TEST: READY");
  69. ExecuteESP_LOGI(TAG, "USER short press captures a screenshot; hold USER in Demo opens its selector");
  70. Executeconst gpio_num_t shield_button_pins[] = { GPIO_NUM_16, GPIO_NUM_21, GPIO_NUM_17, GPIO_NUM_18, GPIO_NUM_44, GPIO_NUM_43, GPIO_NUM_3, };
  71. Executeconst char *shield_button_names[] = { "A", "B", "C", "D", "E", "F", "K", };
  72. Executeconst size_t shield_button_count = sizeof(shield_button_pins) / sizeof(shield_button_pins[0]);
  73. Executeint previous_shield_levels[7];
  74. Executeint stable_shield_levels[7];
  75. ExecuteTickType_t shield_changed_at[7];
  76. Executeuint64_t shield_button_mask = 0;
  77. FOR loopsize_t button = 0; button < shield_button_count; ++button

    Repeat body while the loop condition permits; then continue below.

      1. Executeshield_button_mask |= 1ULL << shield_button_pins[button];
  78. Executeconst gpio_config_t shield_button_config = { .pin_bit_mask = shield_button_mask, .mode = GPIO_MODE_INPUT, .pull_up_en = GPIO_PULLUP_ENABLE, .pull_down_en = GPIO_PULLDOWN_DISABLE, .intr_type = GPIO_INTR_DISABLE, };
  79. ExecuteESP_ERROR_CHECK(gpio_config(&shield_button_config));
  80. FOR loopsize_t button = 0; button < shield_button_count; ++button

    Repeat body while the loop condition permits; then continue below.

      1. Executeprevious_shield_levels[button] = gpio_get_level(shield_button_pins[button]);
      2. Executestable_shield_levels[button] = -1;
      3. Executeshield_changed_at[button] = xTaskGetTickCount();
  81. ExecuteESP_LOGI(TAG, "SHIELD BUTTON TEST: READY");
  82. Executeint previous_user_level = gpio_get_level(PIN_BUTTON_USER);
  83. Executeint stable_user_level = previous_user_level;
  84. ExecuteTickType_t user_changed_at = xTaskGetTickCount();
  85. ExecuteTickType_t user_pressed_at = user_changed_at;
  86. Executebool user_long_sent = false;
  87. Executebool user_capture_cancelled = false;
  88. ExecuteTickType_t last_controller_refresh = xTaskGetTickCount() - pdMS_TO_TICKS(CONTROLLER_REFRESH_MS);
  89. ExecuteTickType_t last_render_refresh = xTaskGetTickCount() - pdMS_TO_TICKS(RENDER_REFRESH_MS);
  90. Executebool previous_joystick_valid = true;
  91. Executejoystick_state_t live_joystick = {0};
  92. Executebool joystick_valid = true;
  93. Executebool joystick_validity_changed = true;
  94. Executebool menu_redraw_pending = true;
  95. Executeint previous_boot_level = gpio_get_level(PIN_BUTTON_BOOT);
  96. Executeint stable_boot_level = previous_boot_level;
  97. ExecuteTickType_t boot_changed_at = xTaskGetTickCount();
  98. ExecuteTickType_t boot_pressed_at = boot_changed_at;
  99. Executebool boot_long_sent = false;
  100. ExecuteTickType_t full_reset_pressed_at = 0;
  101. Executebool full_reset_armed = stable_boot_level != 0 || stable_user_level != 0;
  102. ExecuteESP_LOGI(TAG, "Board BOOT (GPIO%d): %s", PIN_BUTTON_BOOT, stable_boot_level == 0 ? "PRESSED" : "RELEASED");
  103. Executebool checkers_active = false;
  104. Executebool othello_active = false;
  105. Executebool connect_four_active = false;
  106. Executebool battleships_active = false;
  107. Executebool yahtzee_active = false;
  108. Executebool blackjack_active = false;
  109. Executebool poker_active = false;
  110. Executebool poker_dice_active = false;
  111. Executebool pig_active = false;
  112. Executebool brightness_settings_active = false;
  113. Executebool volume_settings_active = false;
  114. Executebool wifi_settings_active = false;
  115. Executebool esp_info_active = false;
  116. Executebool ram_log_active = false;
  117. Executebool power_off_settings_active = false;
  118. Executebool restart_settings_active = false;
  119. Executebool game_config_active = false;
  120. Executebool font_test_active = false;
  121. Executebool about_active = false;
  122. Executebool matrix_active = false;
  123. Executebool boing_ball_active = false;
  124. Executebool demo_active = false;
  125. Executebool simon_active = false;
  126. Executebool calculator_active = false;
  127. Executebool kaleidoscope_active = false;
  128. Executebool warp_tunnel_active = false;
  129. Executebool mandelbrot_active = false;
  130. Executebool clock_active = false;
  131. Executebool slideshow_active = false;
  132. Executebool spiffs_test_active = false;
  133. Executebool sound_test_active = false;
  134. Executebool sd_card_test_active = false;
  135. Executebool asteroids_active = false;
  136. Executebool battle_zone_active = false;
  137. Executebool boulder_dash_active = false;
  138. Executebool tempest_active = false;
  139. Executebool invaders_active = false;
  140. Executebool missile_command_active = false;
  141. Executebool breakout_active = false;
  142. Executebool crawler_active = false;
  143. Executebool maze_chase_active = false;
  144. Executebool scramble_active = false;
  145. Executebool defender_active = false;
  146. Executebool galaga_active = false;
  147. Executebool dungeon_active = false;
  148. Executebool hall_of_fame_active = false;
  149. Executebool game_paused = false;
  150. Executebool pause_redraw = false;
  151. Executestatic const uint16_t pause_colors[] = { COLOR_RED, COLOR_YELLOW, COLOR_CYAN, COLOR_WHITE, COLOR_BLACK, COLOR_MAGENTA };
  152. Executesize_t pause_color_index = 0;
  153. Executeuint32_t pause_color_changed_ms = 0;
  154. Executeuint32_t game_clock_last_ms = (uint32_t)(xTaskGetTickCount() * portTICK_PERIOD_MS);
  155. Executeuint32_t game_now_ms = game_clock_last_ms;
  156. Executemenu_initialize((uint32_t)(xTaskGetTickCount() * portTICK_PERIOD_MS));
  157. ExecuteESP_LOGI(TAG, "MENU: %s", memory_ok ? "READY" : "DISABLED BY MEMORY CHECK");
  158. WHILE looptrue

    Repeat body while the loop condition permits; then continue below.

      1. Decisionreset_button_debounce_after_sleep
        True
          1. Executeprevious_boot_level = stable_boot_level = gpio_get_level(PIN_BUTTON_BOOT);
          2. Executeprevious_user_level = stable_user_level = gpio_get_level(PIN_BUTTON_USER);
          3. Executeboot_changed_at = boot_pressed_at = user_changed_at = user_pressed_at = xTaskGetTickCount();
          4. Executeboot_long_sent = false;
          5. Executeuser_long_sent = false;
          6. Executeuser_capture_cancelled = stable_boot_level == 0 && stable_user_level == 0;
          7. Executefull_reset_armed = stable_boot_level != 0 || stable_user_level != 0;
          8. Executefull_reset_pressed_at = 0;
          9. FOR loopsize_t button = 0; button < shield_button_count; ++button

            Repeat body while the loop condition permits; then continue below.

              1. Executeprevious_shield_levels[button] = stable_shield_levels[button] = gpio_get_level(shield_button_pins[button]);
              2. Executeshield_changed_at[button] = xTaskGetTickCount();
          10. Executereset_button_debounce_after_sleep = false;
        False

        Continue after this decision.

      2. Executeconst int user_level = gpio_get_level(PIN_BUTTON_USER);
      3. Executeconst TickType_t now = xTaskGetTickCount();
      4. Executeconst uint32_t now_ms = (uint32_t)(now * portTICK_PERIOD_MS);
      5. Preprocessor directive#if RAM_MONITOR_ENABLED
      6. Decisiondungeon_files_ready
        True
        1. ExecuteramMonitorUpdate(now_ms);
        False

        Continue after this decision.

      7. Preprocessor directive#endif
      8. Decision!game_paused
        True
        1. Executegame_now_ms += now_ms - game_clock_last_ms;
        False

        Continue after this decision.

      9. Executegame_clock_last_ms = now_ms;
      10. Executebool k_pressed = false;
      11. Executebool a_pressed = false;
      12. Executebool b_pressed = false;
      13. Executebool c_pressed = false;
      14. Executebool d_pressed = false;
      15. Executebool e_pressed = false;
      16. Executebool f_pressed = false;
      17. Executebool user_short_pressed = false;
      18. Executebool user_long_pressed = false;
      19. Executebool boot_short = false;
      20. Executebool boot_long = false;
      21. Executeconst int boot_level = gpio_get_level(PIN_BUTTON_BOOT);
      22. Decisionboot_level != previous_boot_level
        True
          1. Executeprevious_boot_level = boot_level;
          2. Executeboot_changed_at = now;
        False

        Continue after this decision.

      23. Decisionboot_level != stable_boot_level && (now - boot_changed_at) >= pdMS_TO_TICKS(30)
        True
          1. Executestable_boot_level = boot_level;
          2. ExecuteESP_LOGI(TAG, "Board BOOT (GPIO%d): %s", PIN_BUTTON_BOOT, stable_boot_level == 0 ? "PRESSED" : "RELEASED");
          3. Decisionstable_boot_level == 0
            True
              1. Executeboot_pressed_at = now;
              2. Executeboot_long_sent = false;
            False
              1. Executeboot_short = !boot_long_sent;
        False

        Continue after this decision.

      24. Decisionstable_boot_level == 0 && !boot_long_sent && (now - boot_pressed_at) >= pdMS_TO_TICKS(800)
        True
          1. Executeboot_long_sent = true;
          2. Executeboot_long = true;
        False

        Continue after this decision.

      25. Decisionuser_level != previous_user_level
        True
          1. Executeprevious_user_level = user_level;
          2. Executeuser_changed_at = now;
        False

        Continue after this decision.

      26. Decisionuser_level != stable_user_level && (now - user_changed_at) >= pdMS_TO_TICKS(30)
        True
          1. Executestable_user_level = user_level;
          2. Decisionstable_user_level == 0
            True
              1. Executeuser_pressed_at = now;
              2. Executeuser_long_sent = false;
              3. Executeuser_capture_cancelled = stable_boot_level == 0;
            False
            1. Decision!user_long_sent && !user_capture_cancelled
              True
                1. Executeuser_short_pressed = true;
              False

              Continue after this decision.

        False

        Continue after this decision.

      27. Decisionstable_boot_level == 0 && stable_user_level == 0
        True
          1. Executeuser_capture_cancelled = true;
        False

        Continue after this decision.

      28. Decisionstable_user_level == 0 && stable_boot_level != 0 && !user_capture_cancelled && !user_long_sent && (now - user_pressed_at) >= pdMS_TO_TICKS(USER_LONG_PRESS_MS)
        True
          1. Executeuser_long_sent = true;
          2. Executeuser_long_pressed = true;
        False

        Continue after this decision.

      29. FOR loopsize_t button = 0; button < shield_button_count; ++button

        Repeat body while the loop condition permits; then continue below.

          1. Executeconst int level = gpio_get_level(shield_button_pins[button]);
          2. Decisionlevel != previous_shield_levels[button]
            True
              1. Executeprevious_shield_levels[button] = level;
              2. Executeshield_changed_at[button] = now;
            False

            Continue after this decision.

          3. Decisionlevel != stable_shield_levels[button] && (now - shield_changed_at[button]) >= pdMS_TO_TICKS(30)
            True
              1. Decisionbutton == 6 && stable_shield_levels[button] == 1 && level == 0
                True
                  1. Executek_pressed = true;
                False

                Continue after this decision.

              2. Decisionstable_shield_levels[button] == 1 && level == 0
                True
                  1. Decisionbutton == 0
                    True
                    1. Executea_pressed = true;
                    False

                    Continue after this decision.

                  2. Decisionbutton == 1
                    True
                    1. Executeb_pressed = true;
                    False

                    Continue after this decision.

                  3. Decisionbutton == 2
                    True
                    1. Executec_pressed = true;
                    False

                    Continue after this decision.

                  4. Decisionbutton == 3
                    True
                    1. Executed_pressed = true;
                    False

                    Continue after this decision.

                  5. Decisionbutton == 4
                    True
                    1. Executee_pressed = true;
                    False

                    Continue after this decision.

                  6. Decisionbutton == 5
                    True
                    1. Executef_pressed = true;
                    False

                    Continue after this decision.

                False

                Continue after this decision.

              3. Executestable_shield_levels[button] = level;
              4. ExecuteESP_LOGI(TAG, "Shield button %s (GPIO%d): %s", shield_button_names[button], (int)shield_button_pins[button], level == 0 ? "PRESSED" : "RELEASED");
            False

            Continue after this decision.

      30. Decisionstable_boot_level != 0 || stable_user_level != 0
        True
          1. Executefull_reset_armed = true;
          2. Executefull_reset_pressed_at = 0;
        False
        1. Decisionfull_reset_armed && full_reset_pressed_at == 0
          True
            1. Executefull_reset_pressed_at = now;
          False
          1. Decisionfull_reset_armed && (now - full_reset_pressed_at) >= pdMS_TO_TICKS(FULL_RESET_HOLD_MS)
            True
              1. ExecuteESP_LOGW(TAG, "BOOT and USER held: restarting ESP");
              2. Executeesp_restart();
            False

            Continue after this decision.

      31. Decisionuser_short_pressed
        True
          1. Executeconst char *const screenshot_source_label = demo_active ? demoScreenshotLabel() : hall_of_fame_active ? hallOfFameScreenshotLabel() : menuScreenshotLabel();
          2. ExecutescreenshotRequest(screenshot_source_label);
          3. Executemenu_redraw_pending = true;
        False

        Continue after this decision.

      32. Executeconst bool left_held = stable_shield_levels[3] == 0;
      33. Executeconst bool right_held = stable_shield_levels[1] == 0;
      34. Executeconst bool app_active = checkers_active || othello_active || connect_four_active || battleships_active || yahtzee_active || blackjack_active || poker_active || poker_dice_active || pig_active || brightness_settings_active || volume_settings_active || wifi_settings_active || esp_info_active || ram_log_active || power_off_settings_active || restart_settings_active || game_config_active || font_test_active || about_active || matrix_active || boing_ball_active || demo_active || simon_active || calculator_active || kaleidoscope_active || warp_tunnel_active || mandelbrot_active || clock_active || slideshow_active || spiffs_test_active || sound_test_active || sd_card_test_active || asteroids_active || battle_zone_active || boulder_dash_active || tempest_active || invaders_active || missile_command_active || breakout_active || crawler_active || maze_chase_active || scramble_active || defender_active || galaga_active || dungeon_active || hall_of_fame_active;
      35. Decision!app_active || boot_short || boot_long
        True
          1. Executegame_paused = false;
          2. Executepause_redraw = false;
        False
        1. Decisionf_pressed
          True
            1. Executegame_paused = !game_paused;
            2. Executepause_redraw = game_paused;
            3. ExecuteESP_LOGI(TAG, "App %s", game_paused ? "PAUSED" : "RESUMED");
          False

          Continue after this decision.

      36. Decisionboot_long
        True
          1. ExecuteESP_LOGI(TAG, "BOOT HOME");
          2. Executemenu_home(now_ms);
        False
        1. Decisionboot_short
          True
            1. ExecuteESP_LOGI(TAG, "BOOT BACK");
            2. Executemenu_back(now_ms);
          False
          1. Decisiongame_paused || (app_active && f_pressed)
            True
              False
              1. DecisionhighScoreEntryActive()
                True
                  1. ExecutehighScoreEntryAction(a_pressed);
                False
                1. Decisioncheckers_active
                  True
                    1. ExecutecheckersAction(k_pressed || a_pressed, e_pressed, c_pressed, game_now_ms);
                  False
                  1. Decisionothello_active
                    True
                      1. ExecuteothelloAction(k_pressed || a_pressed, e_pressed, c_pressed, game_now_ms);
                    False
                    1. Decisionconnect_four_active
                      True
                        1. ExecuteconnectFourAction(k_pressed || a_pressed, e_pressed, c_pressed, game_now_ms);
                      False
                      1. Decisionbattleships_active
                        True
                          1. ExecutebattleshipsAction(k_pressed || a_pressed, e_pressed, c_pressed, game_now_ms);
                        False
                        1. Decisionyahtzee_active
                          True
                            1. ExecuteyahtzeeAction(k_pressed || a_pressed, e_pressed, c_pressed, game_now_ms);
                          False
                          1. Decisionblackjack_active
                            True
                              1. ExecuteblackjackAction(k_pressed || a_pressed, e_pressed, c_pressed, game_now_ms);
                            False
                            1. Decisionpoker_active
                              True
                                1. ExecutepokerAction(k_pressed || a_pressed, c_pressed, e_pressed, game_now_ms);
                              False
                              1. Decisionpoker_dice_active
                                True
                                  1. ExecutepokerDiceAction(k_pressed || a_pressed, c_pressed, e_pressed, game_now_ms);
                                False
                                1. Decisionpig_active
                                  True
                                    1. ExecutepigAction(k_pressed || a_pressed, e_pressed, c_pressed, game_now_ms);
                                  False
                                  1. Decisionbrightness_settings_active
                                    True
                                      1. ExecutesettingsAction(k_pressed || a_pressed, now_ms);
                                    False
                                    1. Decisionvolume_settings_active
                                      True
                                        1. ExecutesettingsAction(k_pressed || a_pressed, now_ms);
                                      False
                                      1. Decisionwifi_settings_active
                                        True
                                          1. ExecutesettingsAction(k_pressed || a_pressed, now_ms);
                                        False
                                        1. Decisionesp_info_active
                                          True
                                            1. ExecutesettingsAction(k_pressed || a_pressed, now_ms);
                                          False
                                          1. Decisionram_log_active
                                            True
                                              1. ExecutesettingsAction(k_pressed || a_pressed, now_ms);
                                            False
                                            1. Decisionrestart_settings_active
                                              True
                                                1. ExecutesettingsAction(k_pressed || a_pressed, now_ms);
                                              False
                                              1. Decisionpower_off_settings_active
                                                True
                                                  1. ExecutesettingsAction(k_pressed || a_pressed, now_ms);
                                                False
                                                1. Decisiongame_config_active
                                                  True
                                                    1. ExecutegameConfigAction(a_pressed, k_pressed, now_ms);
                                                  False
                                                  1. Decisionfont_test_active
                                                    True
                                                      1. ExecutefontTestAction(k_pressed || a_pressed);
                                                    False
                                                    1. Decisionabout_active
                                                      True
                                                        1. ExecuteaboutAction(a_pressed, f_pressed, now_ms);
                                                      False
                                                      1. Decisionmatrix_active
                                                        True
                                                          1. ExecutematrixAction(a_pressed, e_pressed, now_ms);
                                                        False
                                                        1. Decisionboing_ball_active
                                                          True
                                                            1. ExecuteboingBallAction(d_pressed, b_pressed, a_pressed, c_pressed, now_ms);
                                                          False
                                                          1. Decisiondemo_active
                                                            True
                                                              1. ExecutedemoAction(k_pressed || a_pressed, b_pressed, c_pressed, user_long_pressed, d_pressed, b_pressed, now_ms);
                                                            False
                                                            1. Decisionsimon_active
                                                              True
                                                                1. ExecutesimonAction(a_pressed, b_pressed, c_pressed, d_pressed, now_ms);
                                                              False
                                                              1. Decisioncalculator_active
                                                                True
                                                                  1. ExecutecalculatorAction(k_pressed || a_pressed, c_pressed, d_pressed, b_pressed, now_ms);
                                                                False
                                                                1. Decisionkaleidoscope_active
                                                                  True
                                                                    1. ExecutekaleidoscopeAction(k_pressed || a_pressed, d_pressed, c_pressed, e_pressed, now_ms);
                                                                  False
                                                                  1. Decisionwarp_tunnel_active
                                                                    True
                                                                      1. ExecutewarpTunnelAction(k_pressed || a_pressed, c_pressed, e_pressed, now_ms);
                                                                    False
                                                                    1. Decisionmandelbrot_active
                                                                      True
                                                                        1. ExecutemandelbrotAction(k_pressed || a_pressed, c_pressed, b_pressed, e_pressed, now_ms);
                                                                      False
                                                                      1. Decisionslideshow_active
                                                                        True
                                                                          1. ExecuteslideshowAction(k_pressed || a_pressed, c_pressed, now_ms);
                                                                        False
                                                                        1. Decisionspiffs_test_active
                                                                          True
                                                                            1. ExecutespiffsTestAction(k_pressed || a_pressed);
                                                                          False
                                                                          1. Decisionsound_test_active
                                                                            True
                                                                              1. ExecutesoundTestAction(k_pressed || a_pressed, d_pressed, b_pressed, e_pressed);
                                                                            False
                                                                            1. Decisionsd_card_test_active
                                                                              True
                                                                                1. ExecutesdCardTestAction(k_pressed || a_pressed, c_pressed, now_ms);
                                                                              False
                                                                              1. Decisionasteroids_active
                                                                                True
                                                                                  1. ExecuteasteroidsAction(k_pressed || a_pressed, c_pressed, game_now_ms);
                                                                                False
                                                                                1. Decisionbattle_zone_active
                                                                                  True
                                                                                    1. ExecutebattleZoneAction(k_pressed || a_pressed, c_pressed, game_now_ms);
                                                                                  False
                                                                                  1. Decisionboulder_dash_active
                                                                                    True
                                                                                      1. ExecuteboulderDashAction(k_pressed || a_pressed, game_now_ms);
                                                                                    False
                                                                                    1. Decisiontempest_active
                                                                                      True
                                                                                        1. ExecutetempestAction(k_pressed || a_pressed, e_pressed, game_now_ms);
                                                                                      False
                                                                                      1. Decisioninvaders_active
                                                                                        True
                                                                                          1. ExecuteinvadersAction(k_pressed || a_pressed, c_pressed, game_now_ms);
                                                                                        False
                                                                                        1. Decisionmissile_command_active
                                                                                          True
                                                                                            1. ExecutemissileCommandAction(k_pressed || a_pressed, e_pressed, game_now_ms);
                                                                                          False
                                                                                          1. Decisionbreakout_active
                                                                                            True
                                                                                              1. ExecutebreakoutAction(k_pressed || a_pressed, e_pressed, game_now_ms);
                                                                                            False
                                                                                            1. Decisioncrawler_active
                                                                                              True
                                                                                                1. ExecutecrawlerAction(k_pressed || a_pressed, stable_shield_levels[0] == 0 || stable_shield_levels[6] == 0, game_now_ms);
                                                                                              False
                                                                                              1. Decisionmaze_chase_active
                                                                                                True
                                                                                                  1. ExecutemazeChaseAction(k_pressed || a_pressed, game_now_ms);
                                                                                                False
                                                                                                1. Decisionscramble_active
                                                                                                  True
                                                                                                    1. ExecutescrambleAction(k_pressed || a_pressed, game_now_ms);
                                                                                                  False
                                                                                                  1. Decisiondefender_active
                                                                                                    True
                                                                                                      1. ExecutedefenderAction(k_pressed || a_pressed, c_pressed, game_now_ms);
                                                                                                    False
                                                                                                    1. Decisiongalaga_active
                                                                                                      True
                                                                                                        1. ExecutegalagaAction(k_pressed || a_pressed, game_now_ms);
                                                                                                      False
                                                                                                      1. Decisiondungeon_active
                                                                                                        True
                                                                                                          1. ExecutedungeonAIControl(e_pressed, game_now_ms);
                                                                                                          2. ExecutedungeonAction(k_pressed || a_pressed, b_pressed, c_pressed, d_pressed, game_now_ms);
                                                                                                        False
                                                                                                        1. Decisionk_pressed || a_pressed
                                                                                                          True
                                                                                                            1. Executemenu_select(now_ms);
                                                                                                          False

                                                                                                          Continue after this decision.

        2. ExecuteturboLoaderUpdate(menu_current_screen(), now_ms);
        3. Executeconst bool checkers_requested = memory_ok && menu_current_screen() == SCREEN_CHECKERS;
        4. Decisioncheckers_requested && !checkers_active && !turboLoaderActive()
          True
            1. ExecutestartCheckers(game_now_ms);
            2. Executecheckers_active = true;
          False
          1. Decision!checkers_requested && checkers_active
            True
              1. ExecutestopCheckers();
              2. Executecheckers_active = false;
            False

            Continue after this decision.

        5. Executeconst bool othello_requested = memory_ok && menu_current_screen() == SCREEN_OTHELLO;
        6. Decisionothello_requested && !othello_active && !turboLoaderActive()
          True
            1. ExecutestartOthello(game_now_ms);
            2. Executeothello_active = true;
          False
          1. Decision!othello_requested && othello_active
            True
              1. ExecutestopOthello();
              2. Executeothello_active = false;
            False

            Continue after this decision.

        7. Executeconst bool connect_four_requested = memory_ok && menu_current_screen() == SCREEN_CONNECT_FOUR;
        8. Decisionconnect_four_requested && !connect_four_active && !turboLoaderActive()
          True
            1. ExecutestartConnectFour(game_now_ms);
            2. Executeconnect_four_active = true;
          False
          1. Decision!connect_four_requested && connect_four_active
            True
              1. ExecutestopConnectFour();
              2. Executeconnect_four_active = false;
            False

            Continue after this decision.

        9. Executeconst bool battleships_requested = memory_ok && menu_current_screen() == SCREEN_BATTLESHIPS;
        10. Decisionbattleships_requested && !battleships_active && !turboLoaderActive()
          True
            1. ExecutestartBattleships(game_now_ms);
            2. Executebattleships_active = true;
          False
          1. Decision!battleships_requested && battleships_active
            True
              1. ExecutestopBattleships();
              2. Executebattleships_active = false;
            False

            Continue after this decision.

        11. Executeconst bool yahtzee_requested = memory_ok && menu_current_screen() == SCREEN_YAHTZEE;
        12. Decisionyahtzee_requested && !yahtzee_active && !turboLoaderActive()
          True
            1. ExecutestartYahtzee(game_now_ms);
            2. Executeyahtzee_active = true;
          False
          1. Decision!yahtzee_requested && yahtzee_active
            True
              1. ExecutestopYahtzee();
              2. Executeyahtzee_active = false;
            False

            Continue after this decision.

        13. Executeconst bool blackjack_requested = memory_ok && menu_current_screen() == SCREEN_BLACKJACK;
        14. Decisionblackjack_requested && !blackjack_active && !turboLoaderActive()
          True
            1. ExecutestartBlackjack(game_now_ms);
            2. Executeblackjack_active = true;
          False
          1. Decision!blackjack_requested && blackjack_active
            True
              1. ExecutestopBlackjack();
              2. Executeblackjack_active = false;
            False

            Continue after this decision.

        15. Executeconst bool poker_requested = memory_ok && menu_current_screen() == SCREEN_POKER;
        16. Decisionpoker_requested && !poker_active && !turboLoaderActive()
          True
            1. ExecutestartPoker(game_now_ms);
            2. Executepoker_active = true;
          False
          1. Decision!poker_requested && poker_active
            True
              1. ExecutestopPoker();
              2. Executepoker_active = false;
            False

            Continue after this decision.

        17. Executeconst bool poker_dice_requested = memory_ok && menu_current_screen() == SCREEN_POKER_DICE;
        18. Decisionpoker_dice_requested && !poker_dice_active && !turboLoaderActive()
          True
            1. ExecutestartPokerDice(game_now_ms);
            2. Executepoker_dice_active = true;
          False
          1. Decision!poker_dice_requested && poker_dice_active
            True
              1. ExecutestopPokerDice();
              2. Executepoker_dice_active = false;
            False

            Continue after this decision.

        19. Executeconst bool pig_requested = memory_ok && menu_current_screen() == SCREEN_PIG;
        20. Decisionpig_requested && !pig_active && !turboLoaderActive()
          True
            1. ExecutestartPig(game_now_ms);
            2. Executepig_active = true;
          False
          1. Decision!pig_requested && pig_active
            True
              1. ExecutestopPig();
              2. Executepig_active = false;
            False

            Continue after this decision.

        21. Executeconst bool brightness_settings_requested = memory_ok && menu_current_screen() == SCREEN_BRIGHTNESS;
        22. Decisionbrightness_settings_requested && !brightness_settings_active
          True
            1. ExecutesettingsStart(SETTINGS_BRIGHTNESS);
            2. Executebrightness_settings_active = true;
          False
          1. Decision!brightness_settings_requested && brightness_settings_active
            True
              1. ExecutesettingsStop();
              2. Executebrightness_settings_active = false;
            False

            Continue after this decision.

        23. Executeconst bool volume_settings_requested = memory_ok && menu_current_screen() == SCREEN_VOLUME;
        24. Decisionvolume_settings_requested && !volume_settings_active
          True
            1. ExecutesettingsStart(SETTINGS_VOLUME);
            2. Executevolume_settings_active = true;
          False
          1. Decision!volume_settings_requested && volume_settings_active
            True
              1. ExecutesettingsStop();
              2. Executevolume_settings_active = false;
            False

            Continue after this decision.

        25. Executeconst bool wifi_settings_requested = memory_ok && menu_current_screen() == SCREEN_WIFI;
        26. Decisionwifi_settings_requested && !wifi_settings_active
          True
            1. ExecutesettingsStart(SETTINGS_WIFI);
            2. Executewifi_settings_active = true;
          False
          1. Decision!wifi_settings_requested && wifi_settings_active
            True
              1. ExecutesettingsStop();
              2. Executewifi_settings_active = false;
            False

            Continue after this decision.

        27. Executeconst bool esp_info_requested = memory_ok && menu_current_screen() == SCREEN_ESP_INFO;
        28. Decisionesp_info_requested && !esp_info_active
          True
            1. ExecutesettingsStart(SETTINGS_ESP_INFO);
            2. Executeesp_info_active = true;
          False
          1. Decision!esp_info_requested && esp_info_active
            True
              1. ExecutesettingsStop();
              2. Executeesp_info_active = false;
            False

            Continue after this decision.

        29. Preprocessor directive#if RAM_MONITOR_ENABLED
        30. Executeconst bool ram_log_requested = memory_ok && menu_current_screen() == SCREEN_RAM_LOG;
        31. Decisionram_log_requested && !ram_log_active
          True
            1. ExecutesettingsStart(SETTINGS_RAM_LOG);
            2. Executeram_log_active = true;
          False
          1. Decision!ram_log_requested && ram_log_active
            True
              1. ExecutesettingsStop();
              2. Executeram_log_active = false;
            False

            Continue after this decision.

        32. Preprocessor directive#endif
        33. Executeconst bool restart_settings_requested = memory_ok && menu_current_screen() == SCREEN_RESTART;
        34. Decisionrestart_settings_requested && !restart_settings_active
          True
            1. ExecutesettingsStart(SETTINGS_RESTART);
            2. Executerestart_settings_active = true;
          False
          1. Decision!restart_settings_requested && restart_settings_active
            True
              1. ExecutesettingsStop();
              2. Executerestart_settings_active = false;
            False

            Continue after this decision.

        35. Decisionrestart_settings_active && settingsRestartRequested()
          True
            1. ExecuteESP_LOGI(TAG, "Settings restart confirmed");
            2. Executeesp_restart();
          False

          Continue after this decision.

        36. Executeconst bool power_off_settings_requested = memory_ok && menu_current_screen() == SCREEN_POWER_OFF;
        37. Decisionpower_off_settings_requested && !power_off_settings_active
          True
            1. ExecutesettingsStart(SETTINGS_POWER_OFF);
            2. Executepower_off_settings_active = true;
          False
          1. Decision!power_off_settings_requested && power_off_settings_active
            True
              1. ExecutesettingsStop();
              2. Executepower_off_settings_active = false;
            False

            Continue after this decision.

        38. Decisionpower_off_settings_active && settingsPowerOffRequested()
          True
            1. Executeconst bool slept = enter_light_sleep(panel, &tf_available);
            2. ExecutesettingsCancelPowerOffRequest();
            3. Decisionslept
              True
                1. ExecutesettingsStop();
                2. Executepower_off_settings_active = false;
                3. Executemenu_home((uint32_t)(xTaskGetTickCount() * portTICK_PERIOD_MS));
              False

              Continue after this decision.

          False

          Continue after this decision.

        39. Executeconst bool game_config_requested = memory_ok && menu_current_screen() == SCREEN_GAME_CONFIG;
        40. Decisiongame_config_requested && !game_config_active
          True
            1. ExecutestartGameConfig(now_ms);
            2. Executegame_config_active = true;
          False
          1. Decision!game_config_requested && game_config_active
            True
              1. ExecutestopGameConfig();
              2. Executegame_config_active = false;
            False

            Continue after this decision.

        41. Executeconst bool font_test_requested = memory_ok && menu_current_screen() == SCREEN_FONT_TEST;
        42. Decisionfont_test_requested && !font_test_active
          True
            1. ExecutestartFontTest();
            2. Executefont_test_active = true;
          False
          1. Decision!font_test_requested && font_test_active
            True
              1. ExecutestopFontTest();
              2. Executefont_test_active = false;
            False

            Continue after this decision.

        43. Executeconst bool matrix_requested = memory_ok && menu_current_screen() == SCREEN_MATRIX;
        44. Decisionmatrix_requested && !matrix_active
          True
            1. ExecutestartMatrix(now_ms);
            2. Executematrix_active = true;
          False
          1. Decision!matrix_requested && matrix_active
            True
              1. ExecutestopMatrix();
              2. Executematrix_active = false;
            False

            Continue after this decision.

        45. Executeconst bool boing_ball_requested = memory_ok && menu_current_screen() == SCREEN_BOING_BALL;
        46. Decisionboing_ball_requested && !boing_ball_active
          True
            1. ExecutestartBoingBall(now_ms);
            2. Executeboing_ball_active = true;
          False
          1. Decision!boing_ball_requested && boing_ball_active
            True
              1. ExecutestopBoingBall();
              2. Executeboing_ball_active = false;
            False

            Continue after this decision.

        47. Executeconst bool demo_requested = memory_ok && menu_current_screen() == SCREEN_ABOUT;
        48. Decisiondemo_requested && !demo_active
          True
            1. ExecutestartDemo(now_ms);
            2. Executedemo_active = true;
          False
          1. Decision!demo_requested && demo_active
            True
              1. ExecutestopDemo();
              2. Executedemo_active = false;
            False

            Continue after this decision.

        49. Executeconst bool simon_requested = memory_ok && menu_current_screen() == SCREEN_SIMON;
        50. Decisionsimon_requested && !simon_active
          True
            1. ExecutestartSimon(now_ms);
            2. Executesimon_active = true;
          False
          1. Decision!simon_requested && simon_active
            True
              1. ExecutestopSimon();
              2. Executesimon_active = false;
            False

            Continue after this decision.

        51. Executeconst bool calculator_requested = memory_ok && menu_current_screen() == SCREEN_CALCULATOR;
        52. Decisioncalculator_requested && !calculator_active
          True
            1. ExecutestartCalculator(now_ms);
            2. Executecalculator_active = true;
          False
          1. Decision!calculator_requested && calculator_active
            True
              1. ExecutestopCalculator();
              2. Executecalculator_active = false;
            False

            Continue after this decision.

        53. Executeconst bool kaleidoscope_requested = memory_ok && menu_current_screen() == SCREEN_KALEIDOSCOPE;
        54. Decisionkaleidoscope_requested && !kaleidoscope_active
          True
            1. ExecutestartKaleidoscope(now_ms);
            2. Executekaleidoscope_active = true;
          False
          1. Decision!kaleidoscope_requested && kaleidoscope_active
            True
              1. ExecutestopKaleidoscope();
              2. Executekaleidoscope_active = false;
            False

            Continue after this decision.

        55. Executeconst bool warp_tunnel_requested = memory_ok && menu_current_screen() == SCREEN_WARP_TUNNEL;
        56. Decisionwarp_tunnel_requested && !warp_tunnel_active
          True
            1. ExecutestartWarpTunnel(now_ms);
            2. Executewarp_tunnel_active = true;
          False
          1. Decision!warp_tunnel_requested && warp_tunnel_active
            True
              1. ExecutestopWarpTunnel();
              2. Executewarp_tunnel_active = false;
            False

            Continue after this decision.

        57. Executeconst bool mandelbrot_requested = memory_ok && menu_current_screen() == SCREEN_MANDELBROT;
        58. Decisionmandelbrot_requested && !mandelbrot_active
          True
            1. ExecutestartMandelbrot(now_ms);
            2. Executemandelbrot_active = true;
          False
          1. Decision!mandelbrot_requested && mandelbrot_active
            True
              1. ExecutestopMandelbrot();
              2. Executemandelbrot_active = false;
            False

            Continue after this decision.

        59. Executeconst bool clock_requested = memory_ok && menu_current_screen() == SCREEN_CLOCK;
        60. Decisionclock_requested && !clock_active
          True
            1. ExecutestartClock(now_ms);
            2. Executeclock_active = true;
          False
          1. Decision!clock_requested && clock_active
            True
              1. ExecutestopClock();
              2. Executeclock_active = false;
            False

            Continue after this decision.

        61. Decisionstorage_ready
          True
          1. ExecutesettingsClockAutoSyncUpdate(now_ms);
          False

          Continue after this decision.

        62. Executeconst bool slideshow_requested = memory_ok && menu_current_screen() == SCREEN_SLIDESHOW;
        63. Decisionslideshow_requested && !slideshow_active
          True
            1. ExecutestartSlideshow(now_ms);
            2. Executeslideshow_active = true;
          False
          1. Decision!slideshow_requested && slideshow_active
            True
              1. ExecutestopSlideshow();
              2. Executeslideshow_active = false;
            False

            Continue after this decision.

        64. Executeconst bool spiffs_test_requested = memory_ok && menu_current_screen() == SCREEN_SPIFFS_TEST;
        65. Decisionspiffs_test_requested && !spiffs_test_active
          True
            1. ExecutestartSpiffsTest();
            2. Executespiffs_test_active = true;
          False
          1. Decision!spiffs_test_requested && spiffs_test_active
            True
              1. ExecutestopSpiffsTest();
              2. Executespiffs_test_active = false;
            False

            Continue after this decision.

        66. Executeconst bool sound_test_requested = memory_ok && menu_current_screen() == SCREEN_SOUND_TEST;
        67. Decisionsound_test_requested && !sound_test_active
          True
            1. ExecutestartSoundTest();
            2. Executesound_test_active = true;
          False
          1. Decision!sound_test_requested && sound_test_active
            True
              1. ExecutestopSoundTest();
              2. Executesound_test_active = false;
            False

            Continue after this decision.

        68. Executeconst bool sd_card_test_requested = memory_ok && menu_current_screen() == SCREEN_SD_CARD_TEST;
        69. Decisionsd_card_test_requested && !sd_card_test_active
          True
            1. ExecutestartSdCardTest(now_ms);
            2. Executesd_card_test_active = true;
          False
          1. Decision!sd_card_test_requested && sd_card_test_active
            True
              1. ExecutestopSdCardTest();
              2. Executesd_card_test_active = false;
            False

            Continue after this decision.

        70. Executeconst bool hall_of_fame_requested = memory_ok && menu_current_screen() == SCREEN_HALL_OF_FAME;
        71. Decisionhall_of_fame_requested && !hall_of_fame_active
          True
            1. ExecutestartHallOfFame(now_ms);
            2. Executehall_of_fame_active = true;
          False
          1. Decision!hall_of_fame_requested && hall_of_fame_active
            True
              1. ExecutestopHallOfFame();
              2. Executehall_of_fame_active = false;
            False

            Continue after this decision.

        72. Executeconst bool asteroids_requested = memory_ok && menu_current_screen() == SCREEN_ASTEROIDS;
        73. Decisionasteroids_requested && !asteroids_active && !turboLoaderActive()
          True
            1. ExecutestartAsteroids(game_now_ms);
            2. Executeasteroids_active = true;
          False
          1. Decision!asteroids_requested && asteroids_active
            True
              1. ExecutestopAsteroids();
              2. Executeasteroids_active = false;
            False

            Continue after this decision.

        74. Executeconst bool battle_zone_requested = memory_ok && menu_current_screen() == SCREEN_BATTLE_ZONE;
        75. Decisionbattle_zone_requested && !battle_zone_active && !turboLoaderActive()
          True
            1. ExecutestartBattleZone(game_now_ms);
            2. Executebattle_zone_active = true;
          False
          1. Decision!battle_zone_requested && battle_zone_active
            True
              1. ExecutestopBattleZone();
              2. Executebattle_zone_active = false;
            False

            Continue after this decision.

        76. Executeconst bool boulder_dash_requested = memory_ok && menu_current_screen() == SCREEN_BOULDER_DASH;
        77. Decisionboulder_dash_requested && !boulder_dash_active && !turboLoaderActive()
          True
            1. ExecutestartBoulderDash(game_now_ms);
            2. Executeboulder_dash_active = true;
          False
          1. Decision!boulder_dash_requested && boulder_dash_active
            True
              1. ExecutestopBoulderDash();
              2. Executeboulder_dash_active = false;
            False

            Continue after this decision.

        78. Executeconst bool tempest_requested = memory_ok && menu_current_screen() == SCREEN_TEMPEST;
        79. Decisiontempest_requested && !tempest_active && !turboLoaderActive()
          True
            1. ExecutestartTempest(game_now_ms);
            2. Executetempest_active = true;
          False
          1. Decision!tempest_requested && tempest_active
            True
              1. ExecutestopTempest();
              2. Executetempest_active = false;
            False

            Continue after this decision.

        80. Executeconst bool invaders_requested = memory_ok && menu_current_screen() == SCREEN_INVADERS;
        81. Decisioninvaders_requested && !invaders_active && !turboLoaderActive()
          True
            1. ExecutestartInvaders(game_now_ms);
            2. Executeinvaders_active = true;
          False
          1. Decision!invaders_requested && invaders_active
            True
              1. ExecutestopInvaders();
              2. Executeinvaders_active = false;
            False

            Continue after this decision.

        82. Executeconst bool missile_command_requested = memory_ok && menu_current_screen() == SCREEN_MISSILE_COMMAND;
        83. Decisionmissile_command_requested && !missile_command_active && !turboLoaderActive()
          True
            1. ExecutestartMissileCommand(game_now_ms);
            2. Executemissile_command_active = true;
          False
          1. Decision!missile_command_requested && missile_command_active
            True
              1. ExecutestopMissileCommand();
              2. Executemissile_command_active = false;
            False

            Continue after this decision.

        84. Executeconst bool breakout_requested = memory_ok && menu_current_screen() == SCREEN_BREAKOUT;
        85. Decisionbreakout_requested && !breakout_active && !turboLoaderActive()
          True
            1. ExecutestartBreakout(game_now_ms);
            2. Executebreakout_active = true;
          False
          1. Decision!breakout_requested && breakout_active
            True
              1. ExecutestopBreakout();
              2. Executebreakout_active = false;
            False

            Continue after this decision.

        86. Executeconst bool crawler_requested = memory_ok && menu_current_screen() == SCREEN_CRAWLER;
        87. Decisioncrawler_requested && !crawler_active && !turboLoaderActive()
          True
            1. ExecutestartCrawler(game_now_ms);
            2. Executecrawler_active = true;
          False
          1. Decision!crawler_requested && crawler_active
            True
              1. ExecutestopCrawler();
              2. Executecrawler_active = false;
            False

            Continue after this decision.

        88. Executeconst bool maze_chase_requested = memory_ok && menu_current_screen() == SCREEN_MAZE_CHASE;
        89. Decisionmaze_chase_requested && !maze_chase_active && !turboLoaderActive()
          True
            1. ExecutestartMazeChase(game_now_ms);
            2. Executemaze_chase_active = true;
          False
          1. Decision!maze_chase_requested && maze_chase_active
            True
              1. ExecutestopMazeChase();
              2. Executemaze_chase_active = false;
            False

            Continue after this decision.

        90. Executeconst bool scramble_requested = memory_ok && menu_current_screen() == SCREEN_SCRAMBLE;
        91. Decisionscramble_requested && !scramble_active && !turboLoaderActive()
          True
            1. ExecutestartScramble(game_now_ms);
            2. Executescramble_active = true;
          False
          1. Decision!scramble_requested && scramble_active
            True
              1. ExecutestopScramble();
              2. Executescramble_active = false;
            False

            Continue after this decision.

        92. Executeconst bool defender_requested = memory_ok && menu_current_screen() == SCREEN_DEFENDER;
        93. Decisiondefender_requested && !defender_active && !turboLoaderActive()
          True
            1. ExecutestartDefender(game_now_ms);
            2. Executedefender_active = true;
          False
          1. Decision!defender_requested && defender_active
            True
              1. ExecutestopDefender();
              2. Executedefender_active = false;
            False

            Continue after this decision.

        94. Executeconst bool galaga_requested = memory_ok && menu_current_screen() == SCREEN_GALAGA;
        95. Decisiongalaga_requested && !galaga_active && !turboLoaderActive()
          True
            1. ExecutestartGalaga(game_now_ms);
            2. Executegalaga_active = true;
          False
          1. Decision!galaga_requested && galaga_active
            True
              1. ExecutestopGalaga();
              2. Executegalaga_active = false;
            False

            Continue after this decision.

        96. Executeconst bool dungeon_requested = memory_ok && menu_current_screen() == SCREEN_DUNGEON;
        97. Decisiondungeon_requested && !dungeon_active && !turboLoaderActive()
          True
            1. ExecutestartDungeon(game_now_ms);
            2. Executedungeon_active = true;
          False
          1. Decision!dungeon_requested && dungeon_active
            True
              1. ExecutestopDungeon(game_now_ms);
              2. Executedungeon_active = false;
            False

            Continue after this decision.

        98. Decision(now - last_controller_refresh) >= pdMS_TO_TICKS(CONTROLLER_REFRESH_MS)
          True
            1. Executelast_controller_refresh = now;
            2. Executeconst esp_err_t live_result = controller_input_read(&live_joystick);
            3. Executejoystick_valid = live_result == ESP_OK;
            4. Decision!joystick_valid && previous_joystick_valid
              True
                1. ExecuteESP_LOGE(TAG, "Live joystick read failed: %s", esp_err_to_name(live_result));
              False
              1. Decisionjoystick_valid && !previous_joystick_valid
                True
                  1. ExecuteESP_LOGI(TAG, "Live joystick readings recovered");
                False

                Continue after this decision.

            5. Executeconst bool validity_changed = joystick_valid != previous_joystick_valid;
            6. Executeprevious_joystick_valid = joystick_valid;
            7. Executejoystick_validity_changed = joystick_validity_changed || validity_changed;
            8. Executebatt_update(now_ms);
            9. Decision!app_active
              True
                1. Decision!menu_update_buttons(left_held, right_held, now_ms)
                  True
                    1. Executemenu_update_joystick(live_joystick.x_raw - JOYSTICK_CENTRE_X, live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid, now_ms);
                  False

                  Continue after this decision.

                2. Executemenu_update(now_ms);
              False

              Continue after this decision.

          False

          Continue after this decision.

        99. Executemenu_redraw_pending = menu_redraw_pending || menu_take_redraw();
        100. Decision(now - last_render_refresh) >= pdMS_TO_TICKS(RENDER_REFRESH_MS)
          True
            1. Executelast_render_refresh = now;
            2. Executeconst bool menu_redraw = menu_redraw_pending;
            3. Executeconst bool validity_changed = joystick_validity_changed;
            4. Executemenu_redraw_pending = false;
            5. Executejoystick_validity_changed = false;
            6. Decisionmemory_ok
              True
                1. DecisionturboLoaderActive()
                  True
                    1. ExecutedrawTurboLoader(frame, now_ms);
                    2. Executedraw_frame(panel, frame);
                  False
                  1. Decisiongame_paused
                    True
                      1. Decisionpause_redraw || now_ms - pause_color_changed_ms >= 500U
                        True
                          1. Executepause_color_index = pause_redraw ? 0 : (pause_color_index + 1U) % (sizeof(pause_colors) / sizeof(pause_colors[0]));
                          2. Executedraw_text_centred(frame, 160, 78, "PAUSED", 2, pause_colors[pause_color_index]);
                          3. Executedraw_frame(panel, frame);
                          4. Executepause_color_changed_ms = now_ms;
                          5. Executepause_redraw = false;
                        False

                        Continue after this decision.

                    False
                    1. Decisioncheckers_active
                      True
                        1. ExecuteupdateCheckers(live_joystick.x_raw - JOYSTICK_CENTRE_X, live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid, left_held, right_held, game_now_ms);
                        2. ExecutedrawCheckers(frame);
                        3. Executedraw_frame(panel, frame);
                      False
                      1. Decisionothello_active
                        True
                          1. ExecuteupdateOthello(live_joystick.x_raw - JOYSTICK_CENTRE_X, live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid, left_held, right_held, game_now_ms);
                          2. ExecutedrawOthello(frame);
                          3. Executedraw_frame(panel, frame);
                        False
                        1. Decisionconnect_four_active
                          True
                            1. ExecuteupdateConnectFour(live_joystick.x_raw - JOYSTICK_CENTRE_X, live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid, left_held, right_held, game_now_ms);
                            2. ExecutedrawConnectFour(frame);
                            3. Executedraw_frame(panel, frame);
                          False
                          1. Decisionbattleships_active
                            True
                              1. ExecuteupdateBattleships(live_joystick.x_raw - JOYSTICK_CENTRE_X, live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid, left_held, right_held, game_now_ms);
                              2. ExecutedrawBattleships(frame);
                              3. Executedraw_frame(panel, frame);
                            False
                            1. Decisionyahtzee_active
                              True
                                1. ExecuteupdateYahtzee(live_joystick.x_raw - JOYSTICK_CENTRE_X, live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid, left_held, right_held, game_now_ms);
                                2. ExecutedrawYahtzee(frame);
                                3. Executedraw_frame(panel, frame);
                              False
                              1. Decisionblackjack_active
                                True
                                  1. ExecuteupdateBlackjack(live_joystick.x_raw - JOYSTICK_CENTRE_X, live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid, left_held, right_held, game_now_ms);
                                  2. ExecutedrawBlackjack(frame);
                                  3. Executedraw_frame(panel, frame);
                                False
                                1. Decisionpoker_active
                                  True
                                    1. ExecuteupdatePoker(frame, live_joystick.x_raw - JOYSTICK_CENTRE_X, live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid, left_held, right_held, game_now_ms);
                                    2. ExecutedrawPoker(frame);
                                    3. Executedraw_frame(panel, frame);
                                  False
                                  1. Decisionpoker_dice_active
                                    True
                                      1. ExecuteupdatePokerDice(live_joystick.x_raw - JOYSTICK_CENTRE_X, live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid, left_held, right_held, game_now_ms);
                                      2. ExecutedrawPokerDice(frame);
                                      3. Executedraw_frame(panel, frame);
                                    False
                                    1. Decisionpig_active
                                      True
                                        1. ExecuteupdatePig(live_joystick.x_raw - JOYSTICK_CENTRE_X, live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid, left_held, right_held, game_now_ms);
                                        2. ExecutedrawPig(frame);
                                        3. Executedraw_frame(panel, frame);
                                      False
                                      1. Decisionbrightness_settings_active
                                        True
                                          1. ExecutesettingsUpdate(live_joystick.x_raw - JOYSTICK_CENTRE_X, live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid, left_held, right_held, now_ms);
                                          2. Executeset_backlight_brightness(settingsBrightness());
                                          3. ExecutesettingsDraw(frame);
                                          4. Executedraw_frame(panel, frame);
                                        False
                                        1. Decisionvolume_settings_active
                                          True
                                            1. ExecutesettingsUpdate(live_joystick.x_raw - JOYSTICK_CENTRE_X, live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid, left_held, right_held, now_ms);
                                            2. ExecutesettingsDraw(frame);
                                            3. Executedraw_frame(panel, frame);
                                          False
                                          1. Decisionwifi_settings_active
                                            True
                                              1. ExecutesettingsUpdate(live_joystick.x_raw - JOYSTICK_CENTRE_X, live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid, left_held, right_held, now_ms);
                                              2. ExecutesettingsDraw(frame);
                                              3. Executedraw_frame(panel, frame);
                                            False
                                            1. Decisionesp_info_active
                                              True
                                                1. ExecutesettingsUpdate(live_joystick.x_raw - JOYSTICK_CENTRE_X, live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid, left_held, right_held, now_ms);
                                                2. ExecutesettingsDraw(frame);
                                                3. Executedraw_frame(panel, frame);
                                              False
                                              1. Decisionram_log_active
                                                True
                                                  1. ExecutesettingsUpdate(live_joystick.x_raw - JOYSTICK_CENTRE_X, live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid, left_held, right_held, now_ms);
                                                  2. ExecutesettingsDraw(frame);
                                                  3. Executedraw_frame(panel, frame);
                                                False
                                                1. Decisionrestart_settings_active
                                                  True
                                                    1. ExecutesettingsUpdate(live_joystick.x_raw - JOYSTICK_CENTRE_X, live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid, left_held, right_held, now_ms);
                                                    2. ExecutesettingsDraw(frame);
                                                    3. Executedraw_frame(panel, frame);
                                                  False
                                                  1. Decisionpower_off_settings_active
                                                    True
                                                      1. ExecutesettingsUpdate(live_joystick.x_raw - JOYSTICK_CENTRE_X, live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid, left_held, right_held, now_ms);
                                                      2. ExecutesettingsDraw(frame);
                                                      3. Executedraw_frame(panel, frame);
                                                    False
                                                    1. Decisiongame_config_active
                                                      True
                                                        1. ExecuteupdateGameConfig(live_joystick.x_raw - JOYSTICK_CENTRE_X, live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid, now_ms);
                                                        2. ExecutedrawGameConfig(frame);
                                                        3. Executedraw_frame(panel, frame);
                                                      False
                                                      1. Decisionfont_test_active
                                                        True
                                                          1. ExecutedrawFontTest(frame);
                                                          2. Executedraw_frame(panel, frame);
                                                        False
                                                        1. Decisionabout_active
                                                          True
                                                            1. ExecuteupdateAbout(now_ms);
                                                            2. ExecutedrawAbout(frame);
                                                            3. Executedraw_frame(panel, frame);
                                                          False
                                                          1. Decisionmatrix_active
                                                            True
                                                              1. ExecuteupdateMatrix(now_ms);
                                                              2. DecisionmatrixTakeFrame()
                                                                True
                                                                  1. ExecutedrawMatrix(frame);
                                                                  2. Executedraw_frame(panel, frame);
                                                                False

                                                                Continue after this decision.

                                                            False
                                                            1. Decisionboing_ball_active
                                                              True
                                                                1. ExecuteupdateBoingBall(now_ms);
                                                                2. ExecutedrawBoingBall(frame);
                                                                3. Executedraw_frame(panel, frame);
                                                              False
                                                              1. Decisiondemo_active
                                                                True
                                                                  1. ExecuteupdateDemo(live_joystick.x_raw - JOYSTICK_CENTRE_X, live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid, now_ms);
                                                                  2. ExecutedrawDemo(frame);
                                                                  3. Executedraw_frame(panel, frame);
                                                                False
                                                                1. Decisionsimon_active
                                                                  True
                                                                    1. ExecuteupdateSimon(now_ms);
                                                                    2. ExecutedrawSimon(frame);
                                                                    3. Executedraw_frame(panel, frame);
                                                                  False
                                                                  1. Decisioncalculator_active
                                                                    True
                                                                      1. ExecuteupdateCalculator(live_joystick.x_raw - JOYSTICK_CENTRE_X, live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid, now_ms);
                                                                      2. ExecutedrawCalculator(frame);
                                                                      3. Executedraw_frame(panel, frame);
                                                                    False
                                                                    1. Decisionkaleidoscope_active
                                                                      True
                                                                        1. ExecuteupdateKaleidoscope(now_ms);
                                                                        2. ExecutedrawKaleidoscope(frame);
                                                                        3. Executedraw_frame(panel, frame);
                                                                      False
                                                                      1. Decisionwarp_tunnel_active
                                                                        True
                                                                          1. ExecuteupdateWarpTunnel(now_ms);
                                                                          2. ExecutedrawWarpTunnel(frame);
                                                                          3. Executedraw_frame(panel, frame);
                                                                        False
                                                                        1. Decisionmandelbrot_active
                                                                          True
                                                                            1. ExecuteupdateMandelbrot(live_joystick.x_raw - JOYSTICK_CENTRE_X, live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid, now_ms);
                                                                            2. DecisionmandelbrotTakeFrame()
                                                                              True
                                                                                1. ExecutedrawMandelbrot(frame);
                                                                                2. Executedraw_frame(panel, frame);
                                                                              False

                                                                              Continue after this decision.

                                                                          False
                                                                          1. Decisionclock_active
                                                                            True
                                                                              1. ExecuteupdateClock(now_ms);
                                                                              2. DecisionclockTakeFrame()
                                                                                True
                                                                                  1. ExecutedrawClock(frame);
                                                                                  2. Executedraw_frame(panel, frame);
                                                                                False

                                                                                Continue after this decision.

                                                                            False
                                                                            1. Decisionslideshow_active
                                                                              True
                                                                                1. ExecuteupdateSlideshow(frame, now_ms);
                                                                                2. ExecutedrawSlideshow(frame);
                                                                                3. Executedraw_frame(panel, frame);
                                                                              False
                                                                              1. Decisionspiffs_test_active
                                                                                True
                                                                                  1. ExecutedrawSpiffsTest(frame);
                                                                                  2. Executedraw_frame(panel, frame);
                                                                                False
                                                                                1. Decisionsound_test_active
                                                                                  True
                                                                                    1. ExecutedrawSoundTest(frame);
                                                                                    2. Executedraw_frame(panel, frame);
                                                                                  False
                                                                                  1. Decisionsd_card_test_active
                                                                                    True
                                                                                      1. ExecuteupdateSdCardTest(frame, live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid, now_ms);
                                                                                      2. ExecutedrawSdCardTest(frame);
                                                                                      3. Executedraw_frame(panel, frame);
                                                                                    False
                                                                                    1. Decisionasteroids_active
                                                                                      True
                                                                                        1. ExecuteupdateAsteroids(live_joystick.x_raw - JOYSTICK_CENTRE_X, live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid, left_held, right_held, stable_shield_levels[0] == 0, game_now_ms);
                                                                                        2. ExecutedrawAsteroids(frame);
                                                                                        3. Executedraw_frame(panel, frame);
                                                                                      False
                                                                                      1. Decisionbattle_zone_active
                                                                                        True
                                                                                          1. ExecuteupdateBattleZone(live_joystick.x_raw - JOYSTICK_CENTRE_X, live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid, left_held, right_held, stable_shield_levels[0] == 0, game_now_ms);
                                                                                          2. ExecutedrawBattleZone(frame);
                                                                                          3. Executedraw_frame(panel, frame);
                                                                                        False
                                                                                        1. Decisionboulder_dash_active
                                                                                          True
                                                                                            1. ExecuteupdateBoulderDash(live_joystick.x_raw - JOYSTICK_CENTRE_X, live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid, left_held, right_held, stable_shield_levels[0] == 0, game_now_ms);
                                                                                            2. ExecutedrawBoulderDash(frame);
                                                                                            3. Executedraw_frame(panel, frame);
                                                                                          False
                                                                                          1. Decisiontempest_active
                                                                                            True
                                                                                              1. ExecuteupdateTempest(live_joystick.x_raw - JOYSTICK_CENTRE_X, live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid, left_held, right_held, stable_shield_levels[0] == 0, game_now_ms);
                                                                                              2. ExecutedrawTempest(frame);
                                                                                              3. Executedraw_frame(panel, frame);
                                                                                            False
                                                                                            1. Decisioninvaders_active
                                                                                              True
                                                                                                1. ExecuteupdateInvaders(live_joystick.x_raw - JOYSTICK_CENTRE_X, live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid, left_held, right_held, stable_shield_levels[0] == 0, game_now_ms);
                                                                                                2. ExecutedrawInvaders(frame);
                                                                                                3. Executedraw_frame(panel, frame);
                                                                                              False
                                                                                              1. Decisionmissile_command_active
                                                                                                True
                                                                                                  1. ExecuteupdateMissileCommand(live_joystick.x_raw - JOYSTICK_CENTRE_X, live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid, left_held, stable_shield_levels[0] == 0, right_held, game_now_ms);
                                                                                                  2. ExecutedrawMissileCommand(frame);
                                                                                                  3. Executedraw_frame(panel, frame);
                                                                                                False
                                                                                                1. Decisionbreakout_active
                                                                                                  True
                                                                                                    1. ExecuteupdateBreakout(live_joystick.x_raw - JOYSTICK_CENTRE_X, live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid, left_held, right_held, game_now_ms);
                                                                                                    2. ExecutedrawBreakout(frame);
                                                                                                    3. Executedraw_frame(panel, frame);
                                                                                                  False
                                                                                                  1. Decisioncrawler_active
                                                                                                    True
                                                                                                      1. ExecuteupdateCrawler(live_joystick.x_raw - JOYSTICK_CENTRE_X, live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid, left_held, right_held, game_now_ms);
                                                                                                      2. ExecutedrawCrawler(frame);
                                                                                                      3. Executedraw_frame(panel, frame);
                                                                                                    False
                                                                                                    1. Decisionmaze_chase_active
                                                                                                      True
                                                                                                        1. ExecuteupdateMazeChase(live_joystick.x_raw - JOYSTICK_CENTRE_X, live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid, left_held, right_held, game_now_ms);
                                                                                                        2. ExecutedrawMazeChase(frame);
                                                                                                        3. Executedraw_frame(panel, frame);
                                                                                                      False
                                                                                                      1. Decisionscramble_active
                                                                                                        True
                                                                                                          1. ExecuteupdateScramble(live_joystick.x_raw - JOYSTICK_CENTRE_X, live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid, stable_shield_levels[0] == 0, stable_shield_levels[1] == 0, game_now_ms);
                                                                                                          2. ExecutedrawScramble(frame);
                                                                                                          3. Executedraw_frame(panel, frame);
                                                                                                        False
                                                                                                        1. Decisiondefender_active
                                                                                                          True
                                                                                                            1. ExecuteupdateDefender(live_joystick.x_raw - JOYSTICK_CENTRE_X, live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid, stable_shield_levels[0] == 0, stable_shield_levels[1] == 0, game_now_ms);
                                                                                                            2. ExecutedrawDefender(frame);
                                                                                                            3. Executedraw_frame(panel, frame);
                                                                                                          False
                                                                                                          1. Decisiongalaga_active
                                                                                                            True
                                                                                                              1. ExecuteupdateGalaga(live_joystick.x_raw - JOYSTICK_CENTRE_X, live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid, stable_shield_levels[0] == 0, game_now_ms);
                                                                                                              2. ExecutedrawGalaga(frame);
                                                                                                              3. Executedraw_frame(panel, frame);
                                                                                                            False
                                                                                                            1. Decisiondungeon_active
                                                                                                              True
                                                                                                                1. ExecuteupdateDungeon(frame, live_joystick.x_raw - JOYSTICK_CENTRE_X, live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid, game_now_ms);
                                                                                                                2. ExecutedrawDungeon(frame);
                                                                                                                3. Executedraw_frame(panel, frame);
                                                                                                              False
                                                                                                              1. Decisionhall_of_fame_active
                                                                                                                True
                                                                                                                  1. ExecuteupdateHallOfFame(live_joystick.x_raw - JOYSTICK_CENTRE_X, live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid, left_held, right_held, now_ms);
                                                                                                                  2. ExecutedrawHallOfFame(frame);
                                                                                                                  3. Executedraw_frame(panel, frame);
                                                                                                                False
                                                                                                                1. Decisionmenu_current_screen() == SCREEN_CONTROLLER_TEST
                                                                                                                  True
                                                                                                                    1. Executedraw_controller_view(frame, &live_joystick, joystick_valid, stable_shield_levels);
                                                                                                                    2. Executedraw_frame(panel, frame);
                                                                                                                  False
                                                                                                                  1. Decisionmenu_current_screen() == SCREEN_GRAPHICS_TEST
                                                                                                                    True
                                                                                                                      1. Decisionmenu_redraw
                                                                                                                        True
                                                                                                                          1. Executefill_color_bars(frame);
                                                                                                                          2. Executedraw_frame(panel, frame);
                                                                                                                        False

                                                                                                                        Continue after this decision.

                                                                                                                    False
                                                                                                                    1. Decisionmenu_current_screen() == SCREEN_BATTERY
                                                                                                                      True
                                                                                                                        1. Executedraw_battery_view(frame);
                                                                                                                        2. Executedraw_frame(panel, frame);
                                                                                                                      False
                                                                                                                      1. Decisionmenu_redraw || validity_changed
                                                                                                                        True
                                                                                                                          1. Executedraw_menu_view(frame, joystick_valid);
                                                                                                                          2. Executedraw_frame(panel, frame);
                                                                                                                        False

                                                                                                                        Continue after this decision.

              False

              Continue after this decision.

          False

          Continue after this decision.

        101. ExecutevTaskDelay(pdMS_TO_TICKS(1));
    Read original function source
    void app_main(void)
    {
        esp_chip_info_t chip_info = {0};
        uint32_t flash_size = 0;
        esp_chip_info(&chip_info);
        const esp_err_t flash_result = esp_flash_get_size(NULL, &flash_size);
        const bool psram_initialized = esp_psram_is_initialized();
        const size_t psram_chip_size = esp_psram_get_size();
        const size_t psram_total = heap_caps_get_total_size(MALLOC_CAP_SPIRAM);
        const size_t psram_free = heap_caps_get_free_size(MALLOC_CAP_SPIRAM);
    
        ESP_LOGI(TAG, "LilyGO T-Display-S3 V1.1 diagnostic");
        ESP_LOGI(TAG, "Chip: ESP32-S3, revision %d, %d CPU cores", chip_info.revision,
                 chip_info.cores);
        ESP_LOGI(TAG, "Configured CPU frequency: %d MHz", CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ);
        if (flash_result == ESP_OK) {
            ESP_LOGI(TAG, "Detected flash: %" PRIu32 " MB", flash_size / (1024U * 1024U));
        } else {
            ESP_LOGE(TAG, "Unable to read flash size: %s", esp_err_to_name(flash_result));
        }
        ESP_LOGI(TAG, "PSRAM initialized: %s", psram_initialized ? "yes" : "no");
        ESP_LOGI(TAG, "PSRAM chip size: %u bytes", (unsigned)psram_chip_size);
        ESP_LOGI(TAG, "PSRAM heap total/free: %u / %u bytes", (unsigned)psram_total,
                 (unsigned)psram_free);
    
        const bool memory_ok = flash_result == ESP_OK &&
                               flash_size == EXPECTED_FLASH_BYTES &&
                               psram_initialized &&
                               psram_chip_size >= EXPECTED_PSRAM_BYTES;
        if (!memory_ok) {
            ESP_LOGE(TAG, "Memory check FAILED: expected 16 MB flash and 8 MB PSRAM");
        }
    
        uint16_t *frame = heap_caps_malloc(
            FRAME_BUFFER_BYTES,
            MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA | MALLOC_CAP_8BIT);
        if (frame == NULL) {
            ESP_LOGE(TAG, "Unable to allocate the %u-byte PSRAM display buffer",
                     (unsigned)FRAME_BUFFER_BYTES);
            return;
        }
        ESP_LOGI(TAG, "PSRAM display buffer allocated: %u bytes",
                 (unsigned)FRAME_BUFFER_BYTES);
    
        if (!globalOverlayInitialize()) {
            ESP_LOGE(TAG, "Unable to allocate the %u-byte PSRAM overlay presentation buffer",
                     (unsigned)FRAME_BUFFER_BYTES);
            heap_caps_free(frame);
            return;
        }
    
        display_transfer_done = xSemaphoreCreateBinary();
        if (display_transfer_done == NULL) {
            ESP_LOGE(TAG, "Unable to allocate LCD transfer semaphore");
            globalOverlayDeinitialize();
            heap_caps_free(frame);
            return;
        }
    
        initialize_buttons();
        initialize_audio_shutdown();
        esp_lcd_panel_handle_t panel = initialize_display();
    
        if (memory_ok) {
            clear(frame, RGB565(0, 0, 0));
        } else {
            clear(frame, RGB565(255, 0, 255));
            ESP_LOGE(TAG, "Magenta screen indicates a memory diagnostic failure");
        }
        draw_frame(panel, frame);
    
        ESP_LOGI(TAG, "LilyGO T-Display-S3 V1.1 diagnostic report");
        ESP_LOGI(TAG, "Chip: ESP32-S3, revision %d, %d CPU cores", chip_info.revision,
                 chip_info.cores);
        ESP_LOGI(TAG, "Configured CPU frequency: %d MHz", CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ);
        if (flash_result == ESP_OK) {
            ESP_LOGI(TAG, "Detected flash: %" PRIu32 " MB", flash_size / (1024U * 1024U));
        } else {
            ESP_LOGE(TAG, "Unable to read flash size: %s", esp_err_to_name(flash_result));
        }
        ESP_LOGI(TAG, "PSRAM initialized: %s", psram_initialized ? "yes" : "no");
        ESP_LOGI(TAG, "PSRAM chip size: %u bytes", (unsigned)psram_chip_size);
        ESP_LOGI(TAG, "PSRAM heap total/free at startup: %u / %u bytes",
                 (unsigned)psram_total, (unsigned)psram_free);
        ESP_LOGI(TAG, "PSRAM display buffer: %u bytes", (unsigned)FRAME_BUFFER_BYTES);
        if (memory_ok) {
            ESP_LOGI(TAG, "BOARD DIAGNOSTIC: PASS");
        } else {
            ESP_LOGE(TAG, "BOARD DIAGNOSTIC: FAIL");
        }
        bool tf_available = false;
    #if TF_CARD_ENABLED
        tf_available = initialize_tf_card();
        ESP_LOGI(TAG, "TF CARD: %s", tf_available ? "READY" : "NOT AVAILABLE");
    #else
        ESP_LOGI(TAG, "TF CARD: DISABLED");
    #endif
        const bool dungeon_files_ready = dungeonFilesInitialize(tf_available);
        ESP_LOGI(TAG, "DUNGEON DATA: %s", dungeon_files_ready ? "READY" : "NOT AVAILABLE");
    #if RAM_MONITOR_ENABLED
        if (dungeon_files_ready) ramMonitorInitialize();
        else ESP_LOGW(TAG, "RAM MONITOR: DISABLED (SPIFFS NOT AVAILABLE)");
    #else
        ESP_LOGI(TAG, "RAM MONITOR: DISABLED (FEATURE SWITCH)");
    #endif
        const bool storage_ready = game_storage_initialize();
        const bool gold_ready = storage_ready && initGold();
        const bool timing_ready = storage_ready && initAITiming();
        const bool settings_ready = storage_ready && settingsInitialize();
        const bool clock_time_ready = storage_ready && timeSyncInitialize();
        const bool audio_ready = audioInitialize();
        set_backlight_brightness(settingsBrightness());
        ESP_LOGI(TAG, "GAME STORAGE: %s; GOLD: %s; AI TIMING: %s; SETTINGS: %s; CLOCK: %s; AUDIO: %s",
                 storage_ready ? "READY" : "FAILED",
                 gold_ready ? "READY" : "FAILED",
                 timing_ready ? "READY" : "DEFAULTS ONLY",
                 settings_ready ? "READY" : "DEFAULTS ONLY", clock_time_ready ? "READY" : "DEFAULTS ONLY",
                 audio_ready ? "READY" : "FAILED");
        if (storage_ready) {
            nvs_stats_t stats = {0};
            const esp_err_t stats_result = nvs_get_stats(NULL, &stats);
            if (stats_result == ESP_OK) {
                ESP_LOGI(TAG, "NVS entries: used %u; available %u; total %u",
                         (unsigned)stats.used_entries, (unsigned)stats.available_entries,
                         (unsigned)stats.total_entries);
            } else {
                ESP_LOGW(TAG, "Cannot read NVS capacity: %s", esp_err_to_name(stats_result));
            }
        }
        ESP_LOGI(TAG, "Initializing raw joystick test");
        ESP_LOGI(TAG, "Joystick X: GPIO1 / ADC1 channel 0");
        ESP_LOGI(TAG, "Joystick Y: GPIO2 / ADC1 channel 1");
    
        const esp_err_t joystick_result = controller_input_initialize();
        if (joystick_result != ESP_OK) {
            ESP_LOGE(TAG, "Joystick initialization failed: %s",
                     esp_err_to_name(joystick_result));
            return;
        }
    
        const bool battery_ready = batt_initialize();
        ESP_LOGI(TAG, "BATTERY ADC: %s", battery_ready ? "READY" : "FAILED");
    
        ESP_LOGI(TAG, "RAW JOYSTICK TEST: READY");
    
        ESP_LOGI(TAG, "USER short press captures a screenshot; hold USER in Demo opens its selector");
    
        const gpio_num_t shield_button_pins[] = {
            GPIO_NUM_16, GPIO_NUM_21, GPIO_NUM_17, GPIO_NUM_18,
            GPIO_NUM_44, GPIO_NUM_43, GPIO_NUM_3,
        };
        const char *shield_button_names[] = {
            "A", "B", "C", "D", "E", "F", "K",
        };
        const size_t shield_button_count =
            sizeof(shield_button_pins) / sizeof(shield_button_pins[0]);
    
        int previous_shield_levels[7];
        int stable_shield_levels[7];
        TickType_t shield_changed_at[7];
    
        uint64_t shield_button_mask = 0;
        for (size_t button = 0; button < shield_button_count; ++button) {
            shield_button_mask |= 1ULL << shield_button_pins[button];
        }
    
        const gpio_config_t shield_button_config = {
            .pin_bit_mask = shield_button_mask,
            .mode = GPIO_MODE_INPUT,
            .pull_up_en = GPIO_PULLUP_ENABLE,
            .pull_down_en = GPIO_PULLDOWN_DISABLE,
            .intr_type = GPIO_INTR_DISABLE,
        };
        ESP_ERROR_CHECK(gpio_config(&shield_button_config));
    
        for (size_t button = 0; button < shield_button_count; ++button) {
            previous_shield_levels[button] =
                gpio_get_level(shield_button_pins[button]);
            stable_shield_levels[button] = -1;
            shield_changed_at[button] = xTaskGetTickCount();
        }
    
        ESP_LOGI(TAG, "SHIELD BUTTON TEST: READY");
    
        int previous_user_level = gpio_get_level(PIN_BUTTON_USER);
        int stable_user_level = previous_user_level;
        TickType_t user_changed_at = xTaskGetTickCount();
        TickType_t user_pressed_at = user_changed_at;
        bool user_long_sent = false;
        bool user_capture_cancelled = false;
        TickType_t last_controller_refresh =
            xTaskGetTickCount() - pdMS_TO_TICKS(CONTROLLER_REFRESH_MS);
        TickType_t last_render_refresh =
            xTaskGetTickCount() - pdMS_TO_TICKS(RENDER_REFRESH_MS);
        bool previous_joystick_valid = true;
        joystick_state_t live_joystick = {0};
        bool joystick_valid = true;
        bool joystick_validity_changed = true;
        bool menu_redraw_pending = true;
        int previous_boot_level = gpio_get_level(PIN_BUTTON_BOOT);
        int stable_boot_level = previous_boot_level;
        TickType_t boot_changed_at = xTaskGetTickCount();
        TickType_t boot_pressed_at = boot_changed_at;
        bool boot_long_sent = false;
        TickType_t full_reset_pressed_at = 0;
        bool full_reset_armed = stable_boot_level != 0 || stable_user_level != 0;
        ESP_LOGI(TAG, "Board BOOT (GPIO%d): %s", PIN_BUTTON_BOOT,
                 stable_boot_level == 0 ? "PRESSED" : "RELEASED");
        bool checkers_active = false;
        bool othello_active = false;
        bool connect_four_active = false;
        bool battleships_active = false;
        bool yahtzee_active = false;
        bool blackjack_active = false;
        bool poker_active = false;
        bool poker_dice_active = false;
        bool pig_active = false;
        bool brightness_settings_active = false;
        bool volume_settings_active = false;
        bool wifi_settings_active = false;
        bool esp_info_active = false;
        bool ram_log_active = false;
        bool power_off_settings_active = false;
        bool restart_settings_active = false;
        bool game_config_active = false;
        bool font_test_active = false;
        bool about_active = false;
        bool matrix_active = false;
        bool boing_ball_active = false;
        bool demo_active = false;
        bool simon_active = false;
        bool calculator_active = false;
        bool kaleidoscope_active = false;
        bool warp_tunnel_active = false;
        bool mandelbrot_active = false;
        bool clock_active = false;
        bool slideshow_active = false;
        bool spiffs_test_active = false;
        bool sound_test_active = false;
        bool sd_card_test_active = false;
        bool asteroids_active = false;
        bool battle_zone_active = false;
        bool boulder_dash_active = false;
        bool tempest_active = false;
        bool invaders_active = false;
        bool missile_command_active = false;
        bool breakout_active = false;
        bool crawler_active = false;
        bool maze_chase_active = false;
        bool scramble_active = false;
        bool defender_active = false;
        bool galaga_active = false;
        bool dungeon_active = false;
        bool hall_of_fame_active = false;
    
        bool game_paused = false;
        bool pause_redraw = false;
        static const uint16_t pause_colors[] = {
            COLOR_RED, COLOR_YELLOW, COLOR_CYAN, COLOR_WHITE, COLOR_BLACK, COLOR_MAGENTA
        };
        size_t pause_color_index = 0;
        uint32_t pause_color_changed_ms = 0;
        uint32_t game_clock_last_ms = (uint32_t)(xTaskGetTickCount() * portTICK_PERIOD_MS);
        uint32_t game_now_ms = game_clock_last_ms;
    
        menu_initialize((uint32_t)(xTaskGetTickCount() * portTICK_PERIOD_MS));
    
        ESP_LOGI(TAG, "MENU: %s",
                 memory_ok ? "READY" : "DISABLED BY MEMORY CHECK");
    
        while (true) {
            if (reset_button_debounce_after_sleep) {
                previous_boot_level = stable_boot_level = gpio_get_level(PIN_BUTTON_BOOT);
                previous_user_level = stable_user_level = gpio_get_level(PIN_BUTTON_USER);
                boot_changed_at = boot_pressed_at = user_changed_at = user_pressed_at =
                    xTaskGetTickCount();
                boot_long_sent = false;
                user_long_sent = false;
                user_capture_cancelled = stable_boot_level == 0 && stable_user_level == 0;
                full_reset_armed = stable_boot_level != 0 || stable_user_level != 0;
                full_reset_pressed_at = 0;
                for (size_t button = 0; button < shield_button_count; ++button) {
                    previous_shield_levels[button] = stable_shield_levels[button] =
                        gpio_get_level(shield_button_pins[button]);
                    shield_changed_at[button] = xTaskGetTickCount();
                }
                reset_button_debounce_after_sleep = false;
            }
            const int user_level = gpio_get_level(PIN_BUTTON_USER);
            const TickType_t now = xTaskGetTickCount();
            const uint32_t now_ms = (uint32_t)(now * portTICK_PERIOD_MS);
    #if RAM_MONITOR_ENABLED
            if (dungeon_files_ready) ramMonitorUpdate(now_ms);
    #endif
            // Games share a clock that excludes paused time. Hardware and menus use real time.
            if (!game_paused) game_now_ms += now_ms - game_clock_last_ms;
            game_clock_last_ms = now_ms;
            bool k_pressed = false;
            bool a_pressed = false;
            bool b_pressed = false;
            bool c_pressed = false;
            bool d_pressed = false;
            bool e_pressed = false;
            bool f_pressed = false;
            bool user_short_pressed = false;
            bool user_long_pressed = false;
            bool boot_short = false;
            bool boot_long = false;
    
            const int boot_level = gpio_get_level(PIN_BUTTON_BOOT);
            if (boot_level != previous_boot_level) {
                previous_boot_level = boot_level;
                boot_changed_at = now;
            }
            if (boot_level != stable_boot_level &&
                (now - boot_changed_at) >= pdMS_TO_TICKS(30)) {
                stable_boot_level = boot_level;
                ESP_LOGI(TAG, "Board BOOT (GPIO%d): %s", PIN_BUTTON_BOOT,
                         stable_boot_level == 0 ? "PRESSED" : "RELEASED");
                if (stable_boot_level == 0) {
                    boot_pressed_at = now;
                    boot_long_sent = false;
                } else {
                    boot_short = !boot_long_sent;
                }
            }
            if (stable_boot_level == 0 && !boot_long_sent &&
                (now - boot_pressed_at) >= pdMS_TO_TICKS(800)) {
                boot_long_sent = true;
                boot_long = true;
            }
    
            if (user_level != previous_user_level) {
                previous_user_level = user_level;
                user_changed_at = now;
            }
    
            if (user_level != stable_user_level &&
                (now - user_changed_at) >= pdMS_TO_TICKS(30)) {
                stable_user_level = user_level;
    
                if (stable_user_level == 0) {
                    user_pressed_at = now;
                    user_long_sent = false;
                    user_capture_cancelled = stable_boot_level == 0;
                } else if (!user_long_sent && !user_capture_cancelled) {
                    user_short_pressed = true;
                }
            }
    
            // The BOOT + USER restart chord always takes precedence over capture or Demo control.
            if (stable_boot_level == 0 && stable_user_level == 0) {
                user_capture_cancelled = true;
            }
            if (stable_user_level == 0 && stable_boot_level != 0 && !user_capture_cancelled &&
                !user_long_sent &&
                (now - user_pressed_at) >= pdMS_TO_TICKS(USER_LONG_PRESS_MS)) {
                user_long_sent = true;
                user_long_pressed = true;
            }
    
            for (size_t button = 0; button < shield_button_count; ++button) {
                const int level = gpio_get_level(shield_button_pins[button]);
    
                if (level != previous_shield_levels[button]) {
                    previous_shield_levels[button] = level;
                    shield_changed_at[button] = now;
                }
    
                if (level != stable_shield_levels[button] &&
                    (now - shield_changed_at[button]) >= pdMS_TO_TICKS(30)) {
                    if (button == 6 && stable_shield_levels[button] == 1 && level == 0) {
                        k_pressed = true;
                    }
                    if (stable_shield_levels[button] == 1 && level == 0) {
                        if (button == 0) a_pressed = true;
                        if (button == 1) b_pressed = true;
                        if (button == 2) c_pressed = true;
                        if (button == 3) d_pressed = true;
                        if (button == 4) e_pressed = true;
                        if (button == 5) f_pressed = true;
                    }
                    // C is game-specific; only the board's BOOT button navigates back/home.
                    stable_shield_levels[button] = level;
    
                    ESP_LOGI(TAG, "Shield button %s (GPIO%d): %s",
                             shield_button_names[button],
                             (int)shield_button_pins[button],
                             level == 0 ? "PRESSED" : "RELEASED");
                }
            }
    
            // Both board buttons held together perform a normal ESP reboot.
            // Require a release first so buttons held during startup cannot loop resets.
            if (stable_boot_level != 0 || stable_user_level != 0) {
                full_reset_armed = true;
                full_reset_pressed_at = 0;
            } else if (full_reset_armed && full_reset_pressed_at == 0) {
                full_reset_pressed_at = now;
            } else if (full_reset_armed &&
                       (now - full_reset_pressed_at) >= pdMS_TO_TICKS(FULL_RESET_HOLD_MS)) {
                ESP_LOGW(TAG, "BOOT and USER held: restarting ESP");
                esp_restart();
            }
    
            if (user_short_pressed) {
                const char *const screenshot_source_label = demo_active ? demoScreenshotLabel() :
                    hall_of_fame_active ? hallOfFameScreenshotLabel() : menuScreenshotLabel();
                screenshotRequest(screenshot_source_label);
                // Static menu screens need one scheduled render before their queued capture can send.
                menu_redraw_pending = true;
            }
    
            const bool left_held = stable_shield_levels[3] == 0;  // D
            const bool right_held = stable_shield_levels[1] == 0; // B
    
            const bool app_active = checkers_active || othello_active || connect_four_active || battleships_active ||
                                    yahtzee_active || blackjack_active || poker_active || poker_dice_active || pig_active ||
                                    brightness_settings_active || volume_settings_active || wifi_settings_active || esp_info_active || ram_log_active ||
                                    power_off_settings_active || restart_settings_active || game_config_active || font_test_active ||
                                    about_active || matrix_active || boing_ball_active || demo_active || simon_active || calculator_active || kaleidoscope_active || warp_tunnel_active || mandelbrot_active ||
                                    clock_active || slideshow_active || spiffs_test_active || sound_test_active || sd_card_test_active ||
                                    asteroids_active || battle_zone_active || boulder_dash_active || tempest_active || invaders_active || missile_command_active ||
                                    breakout_active || crawler_active || maze_chase_active || scramble_active || defender_active || galaga_active ||
                                    dungeon_active || hall_of_fame_active;
            if (!app_active || boot_short || boot_long) {
                game_paused = false;
                pause_redraw = false;
            } else if (f_pressed) {
                game_paused = !game_paused;
                pause_redraw = game_paused;
                ESP_LOGI(TAG, "App %s", game_paused ? "PAUSED" : "RESUMED");
            }
    
            if (boot_long) {
                ESP_LOGI(TAG, "BOOT HOME");
                menu_home(now_ms);
            } else if (boot_short) {
                ESP_LOGI(TAG, "BOOT BACK");
                menu_back(now_ms);
            } else if (game_paused || (app_active && f_pressed)) {
                // Consume pause/resume and discard module actions while paused.
            } else if (highScoreEntryActive()) {
                highScoreEntryAction(a_pressed);
            } else if (checkers_active) {
                checkersAction(k_pressed || a_pressed, e_pressed, c_pressed, game_now_ms);
            } else if (othello_active) {
                othelloAction(k_pressed || a_pressed, e_pressed, c_pressed, game_now_ms);
            } else if (connect_four_active) {
                connectFourAction(k_pressed || a_pressed, e_pressed, c_pressed, game_now_ms);
            } else if (battleships_active) {
                battleshipsAction(k_pressed || a_pressed, e_pressed, c_pressed, game_now_ms);
            } else if (yahtzee_active) {
                yahtzeeAction(k_pressed || a_pressed, e_pressed, c_pressed, game_now_ms);
            } else if (blackjack_active) {
                blackjackAction(k_pressed || a_pressed, e_pressed, c_pressed, game_now_ms);
            } else if (poker_active) {
                pokerAction(k_pressed || a_pressed, c_pressed, e_pressed, game_now_ms);
            } else if (poker_dice_active) {
                pokerDiceAction(k_pressed || a_pressed, c_pressed, e_pressed, game_now_ms);
            } else if (pig_active) {
                pigAction(k_pressed || a_pressed, e_pressed, c_pressed, game_now_ms);
            } else if (brightness_settings_active) {
                settingsAction(k_pressed || a_pressed, now_ms);
            } else if (volume_settings_active) {
                settingsAction(k_pressed || a_pressed, now_ms);
            } else if (wifi_settings_active) {
                settingsAction(k_pressed || a_pressed, now_ms);
            } else if (esp_info_active) {
                settingsAction(k_pressed || a_pressed, now_ms);
            } else if (ram_log_active) {
                settingsAction(k_pressed || a_pressed, now_ms);
            } else if (restart_settings_active) {
                settingsAction(k_pressed || a_pressed, now_ms);
            } else if (power_off_settings_active) {
                settingsAction(k_pressed || a_pressed, now_ms);
            } else if (game_config_active) {
                gameConfigAction(a_pressed, k_pressed, now_ms);
            } else if (font_test_active) {
                fontTestAction(k_pressed || a_pressed);
            } else if (about_active) {
                aboutAction(a_pressed, f_pressed, now_ms);
            } else if (matrix_active) {
                matrixAction(a_pressed, e_pressed, now_ms);
            } else if (boing_ball_active) {
                boingBallAction(d_pressed, b_pressed, a_pressed, c_pressed, now_ms);
            } else if (demo_active) {
                demoAction(k_pressed || a_pressed, b_pressed, c_pressed, user_long_pressed,
                           d_pressed, b_pressed, now_ms);
            } else if (simon_active) {
                simonAction(a_pressed, b_pressed, c_pressed, d_pressed, now_ms);
            } else if (calculator_active) {
                calculatorAction(k_pressed || a_pressed, c_pressed, d_pressed, b_pressed, now_ms);
            } else if (kaleidoscope_active) {
                kaleidoscopeAction(k_pressed || a_pressed, d_pressed, c_pressed, e_pressed, now_ms);
            } else if (warp_tunnel_active) {
                warpTunnelAction(k_pressed || a_pressed, c_pressed, e_pressed, now_ms);
            } else if (mandelbrot_active) {
                mandelbrotAction(k_pressed || a_pressed, c_pressed, b_pressed, e_pressed, now_ms);
            } else if (slideshow_active) {
                slideshowAction(k_pressed || a_pressed, c_pressed, now_ms);
            } else if (spiffs_test_active) {
                spiffsTestAction(k_pressed || a_pressed);
            } else if (sound_test_active) {
                soundTestAction(k_pressed || a_pressed, d_pressed, b_pressed, e_pressed);
            } else if (sd_card_test_active) {
                sdCardTestAction(k_pressed || a_pressed, c_pressed, now_ms);
            } else if (asteroids_active) {
                asteroidsAction(k_pressed || a_pressed, c_pressed, game_now_ms);
            } else if (battle_zone_active) {
                battleZoneAction(k_pressed || a_pressed, c_pressed, game_now_ms);
            } else if (boulder_dash_active) {
                boulderDashAction(k_pressed || a_pressed, game_now_ms);
            } else if (tempest_active) {
                tempestAction(k_pressed || a_pressed, e_pressed, game_now_ms);
            } else if (invaders_active) {
                invadersAction(k_pressed || a_pressed, c_pressed, game_now_ms);
            } else if (missile_command_active) {
                missileCommandAction(k_pressed || a_pressed, e_pressed, game_now_ms);
            } else if (breakout_active) {
                breakoutAction(k_pressed || a_pressed, e_pressed, game_now_ms);
            } else if (crawler_active) {
                crawlerAction(k_pressed || a_pressed,
                              stable_shield_levels[0] == 0 || stable_shield_levels[6] == 0,
                              game_now_ms);
            } else if (maze_chase_active) {
                mazeChaseAction(k_pressed || a_pressed, game_now_ms);
            } else if (scramble_active) {
                scrambleAction(k_pressed || a_pressed, game_now_ms);
            } else if (defender_active) {
                defenderAction(k_pressed || a_pressed, c_pressed, game_now_ms);
            } else if (galaga_active) {
                galagaAction(k_pressed || a_pressed, game_now_ms);
            } else if (dungeon_active) {
                dungeonAIControl(e_pressed, game_now_ms);
                dungeonAction(k_pressed || a_pressed, b_pressed, c_pressed, d_pressed, game_now_ms);
            } else if (k_pressed || a_pressed) {
                menu_select(now_ms);
            }
    
            // One shared C64 Turbo Tape transition.  It delays only a new game start;
            // returning to the Games menu cancels it immediately through menu_back().
            turboLoaderUpdate(menu_current_screen(), now_ms);
    
            const bool checkers_requested = memory_ok && menu_current_screen() == SCREEN_CHECKERS;
            if (checkers_requested && !checkers_active && !turboLoaderActive()) {
                startCheckers(game_now_ms);
                checkers_active = true;
            } else if (!checkers_requested && checkers_active) {
                stopCheckers();
                checkers_active = false;
            }
    
            const bool othello_requested = memory_ok && menu_current_screen() == SCREEN_OTHELLO;
            if (othello_requested && !othello_active && !turboLoaderActive()) {
                startOthello(game_now_ms);
                othello_active = true;
            } else if (!othello_requested && othello_active) {
                stopOthello();
                othello_active = false;
            }
    
            const bool connect_four_requested =
                memory_ok && menu_current_screen() == SCREEN_CONNECT_FOUR;
            if (connect_four_requested && !connect_four_active && !turboLoaderActive()) {
                startConnectFour(game_now_ms);
                connect_four_active = true;
            } else if (!connect_four_requested && connect_four_active) {
                stopConnectFour();
                connect_four_active = false;
            }
    
            const bool battleships_requested =
                memory_ok && menu_current_screen() == SCREEN_BATTLESHIPS;
            if (battleships_requested && !battleships_active && !turboLoaderActive()) {
                startBattleships(game_now_ms);
                battleships_active = true;
            } else if (!battleships_requested && battleships_active) {
                stopBattleships();
                battleships_active = false;
            }
    
            const bool yahtzee_requested = memory_ok && menu_current_screen() == SCREEN_YAHTZEE;
            if (yahtzee_requested && !yahtzee_active && !turboLoaderActive()) {
                startYahtzee(game_now_ms);
                yahtzee_active = true;
            } else if (!yahtzee_requested && yahtzee_active) {
                stopYahtzee();
                yahtzee_active = false;
            }
    
            const bool blackjack_requested = memory_ok && menu_current_screen() == SCREEN_BLACKJACK;
            if (blackjack_requested && !blackjack_active && !turboLoaderActive()) {
                startBlackjack(game_now_ms);
                blackjack_active = true;
            } else if (!blackjack_requested && blackjack_active) {
                stopBlackjack();
                blackjack_active = false;
            }
    
            const bool poker_requested = memory_ok && menu_current_screen() == SCREEN_POKER;
            if (poker_requested && !poker_active && !turboLoaderActive()) {
                startPoker(game_now_ms);
                poker_active = true;
            } else if (!poker_requested && poker_active) {
                stopPoker();
                poker_active = false;
            }
    
            const bool poker_dice_requested = memory_ok && menu_current_screen() == SCREEN_POKER_DICE;
            if (poker_dice_requested && !poker_dice_active && !turboLoaderActive()) {
                startPokerDice(game_now_ms);
                poker_dice_active = true;
            } else if (!poker_dice_requested && poker_dice_active) {
                stopPokerDice();
                poker_dice_active = false;
            }
    
            const bool pig_requested = memory_ok && menu_current_screen() == SCREEN_PIG;
            if (pig_requested && !pig_active && !turboLoaderActive()) {
                startPig(game_now_ms);
                pig_active = true;
            } else if (!pig_requested && pig_active) {
                stopPig();
                pig_active = false;
            }
    
            const bool brightness_settings_requested =
                memory_ok && menu_current_screen() == SCREEN_BRIGHTNESS;
            if (brightness_settings_requested && !brightness_settings_active) {
                settingsStart(SETTINGS_BRIGHTNESS);
                brightness_settings_active = true;
            } else if (!brightness_settings_requested && brightness_settings_active) {
                settingsStop();
                brightness_settings_active = false;
            }
    
            const bool volume_settings_requested = memory_ok && menu_current_screen() == SCREEN_VOLUME;
            if (volume_settings_requested && !volume_settings_active) {
                settingsStart(SETTINGS_VOLUME);
                volume_settings_active = true;
            } else if (!volume_settings_requested && volume_settings_active) {
                settingsStop();
                volume_settings_active = false;
            }
    
            const bool wifi_settings_requested = memory_ok && menu_current_screen() == SCREEN_WIFI;
            if (wifi_settings_requested && !wifi_settings_active) {
                settingsStart(SETTINGS_WIFI);
                wifi_settings_active = true;
            } else if (!wifi_settings_requested && wifi_settings_active) {
                settingsStop();
                wifi_settings_active = false;
            }
    
            const bool esp_info_requested = memory_ok && menu_current_screen() == SCREEN_ESP_INFO;
            if (esp_info_requested && !esp_info_active) {
                settingsStart(SETTINGS_ESP_INFO);
                esp_info_active = true;
            } else if (!esp_info_requested && esp_info_active) {
                settingsStop();
                esp_info_active = false;
            }
    
    #if RAM_MONITOR_ENABLED
            const bool ram_log_requested = memory_ok && menu_current_screen() == SCREEN_RAM_LOG;
            if (ram_log_requested && !ram_log_active) {
                settingsStart(SETTINGS_RAM_LOG);
                ram_log_active = true;
            } else if (!ram_log_requested && ram_log_active) {
                settingsStop();
                ram_log_active = false;
            }
    #endif
    
            const bool restart_settings_requested =
                memory_ok && menu_current_screen() == SCREEN_RESTART;
            if (restart_settings_requested && !restart_settings_active) {
                settingsStart(SETTINGS_RESTART);
                restart_settings_active = true;
            } else if (!restart_settings_requested && restart_settings_active) {
                settingsStop();
                restart_settings_active = false;
            }
            if (restart_settings_active && settingsRestartRequested()) {
                ESP_LOGI(TAG, "Settings restart confirmed");
                esp_restart();
            }
    
            const bool power_off_settings_requested =
                memory_ok && menu_current_screen() == SCREEN_POWER_OFF;
            if (power_off_settings_requested && !power_off_settings_active) {
                settingsStart(SETTINGS_POWER_OFF);
                power_off_settings_active = true;
            } else if (!power_off_settings_requested && power_off_settings_active) {
                settingsStop();
                power_off_settings_active = false;
            }
            if (power_off_settings_active && settingsPowerOffRequested()) {
                const bool slept = enter_light_sleep(panel, &tf_available);
                settingsCancelPowerOffRequest();
                if (slept) {
                    settingsStop();
                    power_off_settings_active = false;
                    menu_home((uint32_t)(xTaskGetTickCount() * portTICK_PERIOD_MS));
                }
            }
    
            const bool game_config_requested = memory_ok && menu_current_screen() == SCREEN_GAME_CONFIG;
            if (game_config_requested && !game_config_active) {
                startGameConfig(now_ms);
                game_config_active = true;
            } else if (!game_config_requested && game_config_active) {
                stopGameConfig();
                game_config_active = false;
            }
    
            const bool font_test_requested = memory_ok && menu_current_screen() == SCREEN_FONT_TEST;
            if (font_test_requested && !font_test_active) {
                startFontTest();
                font_test_active = true;
            } else if (!font_test_requested && font_test_active) {
                stopFontTest();
                font_test_active = false;
            }
    
            const bool matrix_requested = memory_ok && menu_current_screen() == SCREEN_MATRIX;
            if (matrix_requested && !matrix_active) {
                startMatrix(now_ms);
                matrix_active = true;
            } else if (!matrix_requested && matrix_active) {
                stopMatrix();
                matrix_active = false;
            }
    
            const bool boing_ball_requested = memory_ok && menu_current_screen() == SCREEN_BOING_BALL;
            if (boing_ball_requested && !boing_ball_active) {
                startBoingBall(now_ms);
                boing_ball_active = true;
            } else if (!boing_ball_requested && boing_ball_active) {
                stopBoingBall();
                boing_ball_active = false;
            }
    
            // The main-menu DEMO entry presents the current Demo visual module.
            // Keep SCREEN_ABOUT as the route so Back returns to the main menu.
            const bool demo_requested = memory_ok && menu_current_screen() == SCREEN_ABOUT;
            if (demo_requested && !demo_active) {
                startDemo(now_ms);
                demo_active = true;
            } else if (!demo_requested && demo_active) {
                stopDemo();
                demo_active = false;
            }
    
            const bool simon_requested = memory_ok && menu_current_screen() == SCREEN_SIMON;
            if (simon_requested && !simon_active) {
                startSimon(now_ms);
                simon_active = true;
            } else if (!simon_requested && simon_active) {
                stopSimon();
                simon_active = false;
            }
    
            const bool calculator_requested = memory_ok && menu_current_screen() == SCREEN_CALCULATOR;
            if (calculator_requested && !calculator_active) {
                startCalculator(now_ms);
                calculator_active = true;
            } else if (!calculator_requested && calculator_active) {
                stopCalculator();
                calculator_active = false;
            }
    
            const bool kaleidoscope_requested =
                memory_ok && menu_current_screen() == SCREEN_KALEIDOSCOPE;
            if (kaleidoscope_requested && !kaleidoscope_active) {
                startKaleidoscope(now_ms);
                kaleidoscope_active = true;
            } else if (!kaleidoscope_requested && kaleidoscope_active) {
                stopKaleidoscope();
                kaleidoscope_active = false;
            }
    
            const bool warp_tunnel_requested =
                memory_ok && menu_current_screen() == SCREEN_WARP_TUNNEL;
            if (warp_tunnel_requested && !warp_tunnel_active) {
                startWarpTunnel(now_ms);
                warp_tunnel_active = true;
            } else if (!warp_tunnel_requested && warp_tunnel_active) {
                stopWarpTunnel();
                warp_tunnel_active = false;
            }
    
            const bool mandelbrot_requested = memory_ok && menu_current_screen() == SCREEN_MANDELBROT;
            if (mandelbrot_requested && !mandelbrot_active) {
                startMandelbrot(now_ms);
                mandelbrot_active = true;
            } else if (!mandelbrot_requested && mandelbrot_active) {
                stopMandelbrot();
                mandelbrot_active = false;
            }
    
            const bool clock_requested = memory_ok && menu_current_screen() == SCREEN_CLOCK;
            if (clock_requested && !clock_active) {
                startClock(now_ms);
                clock_active = true;
            } else if (!clock_requested && clock_active) {
                stopClock();
                clock_active = false;
            }
            if (storage_ready) settingsClockAutoSyncUpdate(now_ms);
    
            const bool slideshow_requested = memory_ok && menu_current_screen() == SCREEN_SLIDESHOW;
            if (slideshow_requested && !slideshow_active) {
                startSlideshow(now_ms);
                slideshow_active = true;
            } else if (!slideshow_requested && slideshow_active) {
                stopSlideshow();
                slideshow_active = false;
            }
    
            const bool spiffs_test_requested = memory_ok && menu_current_screen() == SCREEN_SPIFFS_TEST;
            if (spiffs_test_requested && !spiffs_test_active) {
                startSpiffsTest();
                spiffs_test_active = true;
            } else if (!spiffs_test_requested && spiffs_test_active) {
                stopSpiffsTest();
                spiffs_test_active = false;
            }
    
            const bool sound_test_requested = memory_ok && menu_current_screen() == SCREEN_SOUND_TEST;
            if (sound_test_requested && !sound_test_active) {
                startSoundTest();
                sound_test_active = true;
            } else if (!sound_test_requested && sound_test_active) {
                stopSoundTest();
                sound_test_active = false;
            }
    
            const bool sd_card_test_requested = memory_ok && menu_current_screen() == SCREEN_SD_CARD_TEST;
            if (sd_card_test_requested && !sd_card_test_active) {
                startSdCardTest(now_ms);
                sd_card_test_active = true;
            } else if (!sd_card_test_requested && sd_card_test_active) {
                stopSdCardTest();
                sd_card_test_active = false;
            }
    
            const bool hall_of_fame_requested =
                memory_ok && menu_current_screen() == SCREEN_HALL_OF_FAME;
            if (hall_of_fame_requested && !hall_of_fame_active) {
                startHallOfFame(now_ms);
                hall_of_fame_active = true;
            } else if (!hall_of_fame_requested && hall_of_fame_active) {
                stopHallOfFame();
                hall_of_fame_active = false;
            }
    
            const bool asteroids_requested = memory_ok && menu_current_screen() == SCREEN_ASTEROIDS;
            if (asteroids_requested && !asteroids_active && !turboLoaderActive()) {
                startAsteroids(game_now_ms);
                asteroids_active = true;
            } else if (!asteroids_requested && asteroids_active) {
                stopAsteroids();
                asteroids_active = false;
            }
    
            const bool battle_zone_requested = memory_ok && menu_current_screen() == SCREEN_BATTLE_ZONE;
            if (battle_zone_requested && !battle_zone_active && !turboLoaderActive()) {
                startBattleZone(game_now_ms);
                battle_zone_active = true;
            } else if (!battle_zone_requested && battle_zone_active) {
                stopBattleZone();
                battle_zone_active = false;
            }
    
            const bool boulder_dash_requested = memory_ok && menu_current_screen() == SCREEN_BOULDER_DASH;
            if (boulder_dash_requested && !boulder_dash_active && !turboLoaderActive()) {
                startBoulderDash(game_now_ms);
                boulder_dash_active = true;
            } else if (!boulder_dash_requested && boulder_dash_active) {
                stopBoulderDash();
                boulder_dash_active = false;
            }
    
            const bool tempest_requested = memory_ok && menu_current_screen() == SCREEN_TEMPEST;
            if (tempest_requested && !tempest_active && !turboLoaderActive()) {
                startTempest(game_now_ms);
                tempest_active = true;
            } else if (!tempest_requested && tempest_active) {
                stopTempest();
                tempest_active = false;
            }
    
            const bool invaders_requested = memory_ok && menu_current_screen() == SCREEN_INVADERS;
            if (invaders_requested && !invaders_active && !turboLoaderActive()) {
                startInvaders(game_now_ms);
                invaders_active = true;
            } else if (!invaders_requested && invaders_active) {
                stopInvaders();
                invaders_active = false;
            }
    
            const bool missile_command_requested =
                memory_ok && menu_current_screen() == SCREEN_MISSILE_COMMAND;
            if (missile_command_requested && !missile_command_active && !turboLoaderActive()) {
                startMissileCommand(game_now_ms);
                missile_command_active = true;
            } else if (!missile_command_requested && missile_command_active) {
                stopMissileCommand();
                missile_command_active = false;
            }
    
            const bool breakout_requested = memory_ok && menu_current_screen() == SCREEN_BREAKOUT;
            if (breakout_requested && !breakout_active && !turboLoaderActive()) {
                startBreakout(game_now_ms);
                breakout_active = true;
            } else if (!breakout_requested && breakout_active) {
                stopBreakout();
                breakout_active = false;
            }
    
            const bool crawler_requested = memory_ok && menu_current_screen() == SCREEN_CRAWLER;
            if (crawler_requested && !crawler_active && !turboLoaderActive()) {
                startCrawler(game_now_ms);
                crawler_active = true;
            } else if (!crawler_requested && crawler_active) {
                stopCrawler();
                crawler_active = false;
            }
    
            const bool maze_chase_requested = memory_ok && menu_current_screen() == SCREEN_MAZE_CHASE;
            if (maze_chase_requested && !maze_chase_active && !turboLoaderActive()) {
                startMazeChase(game_now_ms);
                maze_chase_active = true;
            } else if (!maze_chase_requested && maze_chase_active) {
                stopMazeChase();
                maze_chase_active = false;
            }
    
            const bool scramble_requested = memory_ok && menu_current_screen() == SCREEN_SCRAMBLE;
            if (scramble_requested && !scramble_active && !turboLoaderActive()) {
                startScramble(game_now_ms);
                scramble_active = true;
            } else if (!scramble_requested && scramble_active) {
                stopScramble();
                scramble_active = false;
            }
    
            const bool defender_requested = memory_ok && menu_current_screen() == SCREEN_DEFENDER;
            if (defender_requested && !defender_active && !turboLoaderActive()) {
                startDefender(game_now_ms);
                defender_active = true;
            } else if (!defender_requested && defender_active) {
                stopDefender();
                defender_active = false;
            }
    
            const bool galaga_requested = memory_ok && menu_current_screen() == SCREEN_GALAGA;
            if (galaga_requested && !galaga_active && !turboLoaderActive()) {
                startGalaga(game_now_ms);
                galaga_active = true;
            } else if (!galaga_requested && galaga_active) {
                stopGalaga();
                galaga_active = false;
            }
    
            const bool dungeon_requested = memory_ok && menu_current_screen() == SCREEN_DUNGEON;
            if (dungeon_requested && !dungeon_active && !turboLoaderActive()) {
                startDungeon(game_now_ms);
                dungeon_active = true;
            } else if (!dungeon_requested && dungeon_active) {
                stopDungeon(game_now_ms);
                dungeon_active = false;
            }
    
            if ((now - last_controller_refresh) >= pdMS_TO_TICKS(CONTROLLER_REFRESH_MS)) {
                last_controller_refresh = now;
                const esp_err_t live_result = controller_input_read(&live_joystick);
                joystick_valid = live_result == ESP_OK;
                if (!joystick_valid && previous_joystick_valid) {
                    ESP_LOGE(TAG, "Live joystick read failed: %s", esp_err_to_name(live_result));
                } else if (joystick_valid && !previous_joystick_valid) {
                    ESP_LOGI(TAG, "Live joystick readings recovered");
                }
                const bool validity_changed = joystick_valid != previous_joystick_valid;
                previous_joystick_valid = joystick_valid;
                joystick_validity_changed = joystick_validity_changed || validity_changed;
                batt_update(now_ms);
    
                // An active module owns input; menu idle timeouts must not end a paused module.
                if (!app_active) {
                    if (!menu_update_buttons(left_held, right_held, now_ms)) {
                        menu_update_joystick(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                             live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                             joystick_valid, now_ms);
                    }
                    menu_update(now_ms);
                }
            }
    
            // Keep input at 20 ms, but render independently at a 60 fps target.
            // One task remains the sole owner of the framebuffer and LCD transfer.
            menu_redraw_pending = menu_redraw_pending || menu_take_redraw();
            if ((now - last_render_refresh) >= pdMS_TO_TICKS(RENDER_REFRESH_MS)) {
                last_render_refresh = now;
                const bool menu_redraw = menu_redraw_pending;
                const bool validity_changed = joystick_validity_changed;
                menu_redraw_pending = false;
                joystick_validity_changed = false;
    
                if (memory_ok) {
                    if (turboLoaderActive()) {
                        drawTurboLoader(frame, now_ms);
                        draw_frame(panel, frame);
                    } else if (game_paused) {
                        if (pause_redraw || now_ms - pause_color_changed_ms >= 500U) {
                            pause_color_index = pause_redraw ? 0 :
                                (pause_color_index + 1U) % (sizeof(pause_colors) / sizeof(pause_colors[0]));
                            // Repaint only the same letter pixels; leave the frozen scene visible.
                            draw_text_centred(frame, 160, 78, "PAUSED", 2, pause_colors[pause_color_index]);
                            draw_frame(panel, frame);
                            pause_color_changed_ms = now_ms;
                            pause_redraw = false;
                        }
                    } else if (checkers_active) {
                        updateCheckers(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                       live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                       joystick_valid, left_held, right_held, game_now_ms);
                        drawCheckers(frame);
                        draw_frame(panel, frame);
                    } else if (othello_active) {
                        updateOthello(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                      live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                      joystick_valid, left_held, right_held, game_now_ms);
                        drawOthello(frame);
                        draw_frame(panel, frame);
                    } else if (connect_four_active) {
                        updateConnectFour(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                          live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                          joystick_valid, left_held, right_held, game_now_ms);
                        drawConnectFour(frame);
                        draw_frame(panel, frame);
                    } else if (battleships_active) {
                        updateBattleships(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                          live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                          joystick_valid, left_held, right_held, game_now_ms);
                        drawBattleships(frame);
                        draw_frame(panel, frame);
                    } else if (yahtzee_active) {
                        updateYahtzee(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                      live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                      joystick_valid, left_held, right_held, game_now_ms);
                        drawYahtzee(frame);
                        draw_frame(panel, frame);
                    } else if (blackjack_active) {
                        updateBlackjack(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                        live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                        joystick_valid, left_held, right_held, game_now_ms);
                        drawBlackjack(frame);
                        draw_frame(panel, frame);
                    } else if (poker_active) {
                        updatePoker(frame, live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                    live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                    joystick_valid, left_held, right_held, game_now_ms);
                        drawPoker(frame);
                        draw_frame(panel, frame);
                    } else if (poker_dice_active) {
                        updatePokerDice(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                        live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                        joystick_valid, left_held, right_held, game_now_ms);
                        drawPokerDice(frame);
                        draw_frame(panel, frame);
                    } else if (pig_active) {
                        updatePig(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                  live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                  joystick_valid, left_held, right_held, game_now_ms);
                        drawPig(frame);
                        draw_frame(panel, frame);
                    } else if (brightness_settings_active) {
                        settingsUpdate(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                       live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid,
                                       left_held, right_held, now_ms);
                        set_backlight_brightness(settingsBrightness());
                        settingsDraw(frame);
                        draw_frame(panel, frame);
                    } else if (volume_settings_active) {
                        settingsUpdate(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                       live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid,
                                       left_held, right_held, now_ms);
                        settingsDraw(frame);
                        draw_frame(panel, frame);
                    } else if (wifi_settings_active) {
                        settingsUpdate(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                       live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid,
                                       left_held, right_held, now_ms);
                        settingsDraw(frame);
                        draw_frame(panel, frame);
                    } else if (esp_info_active) {
                        settingsUpdate(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                       live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid,
                                       left_held, right_held, now_ms);
                        settingsDraw(frame);
                        draw_frame(panel, frame);
                    } else if (ram_log_active) {
                        settingsUpdate(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                       live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid,
                                       left_held, right_held, now_ms);
                        settingsDraw(frame);
                        draw_frame(panel, frame);
                    } else if (restart_settings_active) {
                        settingsUpdate(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                       live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid,
                                       left_held, right_held, now_ms);
                        settingsDraw(frame);
                        draw_frame(panel, frame);
                    } else if (power_off_settings_active) {
                        settingsUpdate(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                       live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid,
                                       left_held, right_held, now_ms);
                        settingsDraw(frame);
                        draw_frame(panel, frame);
                    } else if (game_config_active) {
                        updateGameConfig(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                         live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                         joystick_valid, now_ms);
                        drawGameConfig(frame);
                        draw_frame(panel, frame);
                    } else if (font_test_active) {
                        drawFontTest(frame);
                        draw_frame(panel, frame);
                    } else if (about_active) {
                        updateAbout(now_ms);
                        drawAbout(frame);
                        draw_frame(panel, frame);
                    } else if (matrix_active) {
                        updateMatrix(now_ms);
                        if (matrixTakeFrame()) {
                            drawMatrix(frame);
                            draw_frame(panel, frame);
                        }
                    } else if (boing_ball_active) {
                        updateBoingBall(now_ms);
                        drawBoingBall(frame);
                        draw_frame(panel, frame);
                    } else if (demo_active) {
                        updateDemo(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                   live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                   joystick_valid, now_ms);
                        drawDemo(frame);
                        draw_frame(panel, frame);
                    } else if (simon_active) {
                        updateSimon(now_ms);
                        drawSimon(frame);
                        draw_frame(panel, frame);
                    } else if (calculator_active) {
                        updateCalculator(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                         live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                         joystick_valid, now_ms);
                        drawCalculator(frame);
                        draw_frame(panel, frame);
                    } else if (kaleidoscope_active) {
                        updateKaleidoscope(now_ms);
                        drawKaleidoscope(frame);
                        draw_frame(panel, frame);
                    } else if (warp_tunnel_active) {
                        updateWarpTunnel(now_ms);
                        drawWarpTunnel(frame);
                        draw_frame(panel, frame);
                    } else if (mandelbrot_active) {
                        updateMandelbrot(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                        live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                        joystick_valid, now_ms);
                        if (mandelbrotTakeFrame()) {
                            drawMandelbrot(frame);
                            draw_frame(panel, frame);
                        }
                    } else if (clock_active) {
                        updateClock(now_ms);
                        if (clockTakeFrame()) {
                            drawClock(frame);
                            draw_frame(panel, frame);
                        }
                    } else if (slideshow_active) {
                        updateSlideshow(frame, now_ms);
                        drawSlideshow(frame);
                        draw_frame(panel, frame);
                    } else if (spiffs_test_active) {
                        drawSpiffsTest(frame);
                        draw_frame(panel, frame);
                    } else if (sound_test_active) {
                        drawSoundTest(frame);
                        draw_frame(panel, frame);
                    } else if (sd_card_test_active) {
                        updateSdCardTest(frame, live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid, now_ms);
                        drawSdCardTest(frame);
                        draw_frame(panel, frame);
                    } else if (asteroids_active) {
                        updateAsteroids(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                        live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                        joystick_valid, left_held, right_held,
                                        stable_shield_levels[0] == 0, game_now_ms);
                        drawAsteroids(frame);
                        draw_frame(panel, frame);
                    } else if (battle_zone_active) {
                        updateBattleZone(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                         live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                         joystick_valid, left_held, right_held,
                                         stable_shield_levels[0] == 0, game_now_ms);
                        drawBattleZone(frame);
                        draw_frame(panel, frame);
                    } else if (boulder_dash_active) {
                        updateBoulderDash(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                          live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                          joystick_valid, left_held, right_held,
                                          stable_shield_levels[0] == 0, game_now_ms);
                        drawBoulderDash(frame);
                        draw_frame(panel, frame);
                    } else if (tempest_active) {
                        updateTempest(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                      live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                      joystick_valid, left_held, right_held,
                                      stable_shield_levels[0] == 0, game_now_ms);
                        drawTempest(frame);
                        draw_frame(panel, frame);
                    } else if (invaders_active) {
                        updateInvaders(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                       live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                       joystick_valid, left_held, right_held,
                                       stable_shield_levels[0] == 0, game_now_ms);
                        drawInvaders(frame);
                        draw_frame(panel, frame);
                    } else if (missile_command_active) {
                        updateMissileCommand(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                             live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                             joystick_valid, left_held,
                                             stable_shield_levels[0] == 0, right_held, game_now_ms);
                        drawMissileCommand(frame);
                        draw_frame(panel, frame);
                    } else if (breakout_active) {
                        updateBreakout(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                       live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                       joystick_valid, left_held, right_held, game_now_ms);
                        drawBreakout(frame);
                        draw_frame(panel, frame);
                    } else if (crawler_active) {
                        updateCrawler(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                      live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                      joystick_valid, left_held, right_held, game_now_ms);
                        drawCrawler(frame);
                        draw_frame(panel, frame);
                    } else if (maze_chase_active) {
                        updateMazeChase(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                        live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                        joystick_valid, left_held, right_held, game_now_ms);
                        drawMazeChase(frame);
                        draw_frame(panel, frame);
                    } else if (scramble_active) {
                        updateScramble(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                       live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                       joystick_valid, stable_shield_levels[0] == 0,
                                       stable_shield_levels[1] == 0, game_now_ms);
                        drawScramble(frame);
                        draw_frame(panel, frame);
                    } else if (defender_active) {
                        updateDefender(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                       live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                       joystick_valid, stable_shield_levels[0] == 0,
                                       stable_shield_levels[1] == 0, game_now_ms);
                        drawDefender(frame);
                        draw_frame(panel, frame);
                    } else if (galaga_active) {
                        updateGalaga(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                     live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                     joystick_valid, stable_shield_levels[0] == 0, game_now_ms);
                        drawGalaga(frame);
                        draw_frame(panel, frame);
                    } else if (dungeon_active) {
                        updateDungeon(frame,
                                      live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                      live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                      joystick_valid, game_now_ms);
                        drawDungeon(frame);
                        draw_frame(panel, frame);
                    } else if (hall_of_fame_active) {
                        updateHallOfFame(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                         live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                         joystick_valid, left_held, right_held, now_ms);
                        drawHallOfFame(frame);
                        draw_frame(panel, frame);
                    } else if (menu_current_screen() == SCREEN_CONTROLLER_TEST) {
                        draw_controller_view(frame, &live_joystick, joystick_valid,
                                             stable_shield_levels);
                        draw_frame(panel, frame);
                    } else if (menu_current_screen() == SCREEN_GRAPHICS_TEST) {
                        if (menu_redraw) {
                            fill_color_bars(frame);
                            draw_frame(panel, frame);
                        }
                    } else if (menu_current_screen() == SCREEN_BATTERY) {
                        draw_battery_view(frame);
                        draw_frame(panel, frame);
                    } else if (menu_redraw || validity_changed) {
                        draw_menu_view(frame, joystick_valid);
                        draw_frame(panel, frame);
                    }
                }
            }
    
            // With the 1 kHz FreeRTOS tick, yield briefly without quantising a
            // 16 ms render cadence onto the old 10 ms scheduler boundaries.
            vTaskDelay(pdMS_TO_TICKS(1));
        }
    }
    Complete original file, including constants and data
    /* Coded By JD(2026) */
    #error "Reference listing only — not provided as build-ready source."
    
    
    #define PIN_LCD_BL 38
    #define PIN_LCD_D0 39
    #define PIN_LCD_D1 40
    #define PIN_LCD_D2 41
    #define PIN_LCD_D3 42
    #define PIN_LCD_D4 45
    #define PIN_LCD_D5 46
    #define PIN_LCD_D6 47
    #define PIN_LCD_D7 48
    #define PIN_LCD_RST 5
    #define PIN_LCD_CS 6
    #define PIN_LCD_DC 7
    #define PIN_LCD_WR 8
    #define PIN_LCD_RD 9
    #define PIN_POWER_ON 15
    #define PIN_BUTTON_BOOT 0
    #define PIN_BUTTON_USER 14
    #define PIN_LIGHT_SLEEP_WAKE 21
    #define PIN_AUDIO_SHUTDOWN 10
    #define PIN_TF_CS 10
    #define PIN_TF_MOSI 11
    #define PIN_TF_SCK 12
    #define PIN_TF_MISO 13
    
    #define LCD_PIXEL_CLOCK_HZ (20 * 1000 * 1000)
    #define LCD_BACKLIGHT_PWM_HZ 5000U
    #define LCD_BACKLIGHT_DUTY 128U
    #define FRAME_BUFFER_BYTES (LCD_WIDTH * LCD_HEIGHT * sizeof(uint16_t))
    #define EXPECTED_FLASH_BYTES (16U * 1024U * 1024U)
    #define EXPECTED_PSRAM_BYTES (8U * 1024U * 1024U)
    #define TF_MOUNT_POINT "/sdcard"
    #define TF_MAX_FREQUENCY_KHZ 20000
    #define JOYSTICK_CENTRE_X 1933
    #define JOYSTICK_CENTRE_Y 1915
    #define CONTROLLER_REFRESH_MS 20
    #define RENDER_REFRESH_MS 16
    #define USER_LONG_PRESS_MS 800U
    #define FULL_RESET_HOLD_MS 2000U
    
    static void set_backlight_brightness(uint8_t duty)
    {
        ESP_ERROR_CHECK(ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, duty));
        ESP_ERROR_CHECK(ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0));
    }
    
    static const char *TAG = "board_diagnostic";
    #if TF_CARD_ENABLED
    static sdmmc_card_t *tf_card = NULL;
    #endif
    static SemaphoreHandle_t display_transfer_done = NULL;
    static bool reset_button_debounce_after_sleep;
    
    static bool display_color_transfer_done(esp_lcd_panel_io_handle_t panel_io,
                                            esp_lcd_panel_io_event_data_t *event,
                                            void *user_context)
    {
        (void)panel_io;
        (void)event;
        BaseType_t task_woken = pdFALSE;
        xSemaphoreGiveFromISR((SemaphoreHandle_t)user_context, &task_woken);
        return task_woken == pdTRUE;
    }
    
    static esp_lcd_panel_handle_t initialize_display(void)
    {
        const gpio_config_t output_config = {
            .pin_bit_mask = (1ULL << PIN_POWER_ON) | (1ULL << PIN_LCD_BL) |
                            (1ULL << PIN_LCD_RD),
            .mode = GPIO_MODE_OUTPUT,
            .pull_up_en = GPIO_PULLUP_DISABLE,
            .pull_down_en = GPIO_PULLDOWN_DISABLE,
            .intr_type = GPIO_INTR_DISABLE,
        };
        ESP_ERROR_CHECK(gpio_config(&output_config));
        ESP_ERROR_CHECK(gpio_set_level(PIN_POWER_ON, 1));
        ESP_ERROR_CHECK(gpio_set_level(PIN_LCD_BL, 0));
        ESP_ERROR_CHECK(gpio_set_level(PIN_LCD_RD, 1));
    
        const ledc_timer_config_t backlight_timer = {
            .speed_mode = LEDC_LOW_SPEED_MODE,
            .duty_resolution = LEDC_TIMER_8_BIT,
            .timer_num = LEDC_TIMER_0,
            .freq_hz = LCD_BACKLIGHT_PWM_HZ,
            .clk_cfg = LEDC_AUTO_CLK,
        };
        ESP_ERROR_CHECK(ledc_timer_config(&backlight_timer));
        const ledc_channel_config_t backlight_channel = {
            .gpio_num = PIN_LCD_BL,
            .speed_mode = LEDC_LOW_SPEED_MODE,
            .channel = LEDC_CHANNEL_0,
            .intr_type = LEDC_INTR_DISABLE,
            .timer_sel = LEDC_TIMER_0,
            .duty = 0,
            .hpoint = 0,
        };
        ESP_ERROR_CHECK(ledc_channel_config(&backlight_channel));
    
        const esp_lcd_i80_bus_config_t bus_config = {
            .dc_gpio_num = PIN_LCD_DC,
            .wr_gpio_num = PIN_LCD_WR,
            .clk_src = LCD_CLK_SRC_DEFAULT,
            .data_gpio_nums = {
                PIN_LCD_D0,
                PIN_LCD_D1,
                PIN_LCD_D2,
                PIN_LCD_D3,
                PIN_LCD_D4,
                PIN_LCD_D5,
                PIN_LCD_D6,
                PIN_LCD_D7,
            },
            .bus_width = 8,
            .max_transfer_bytes = FRAME_BUFFER_BYTES,
        };
    
        esp_lcd_i80_bus_handle_t bus = NULL;
        ESP_ERROR_CHECK(esp_lcd_new_i80_bus(&bus_config, &bus));
    
        const esp_lcd_panel_io_i80_config_t io_config = {
            .cs_gpio_num = PIN_LCD_CS,
            .pclk_hz = LCD_PIXEL_CLOCK_HZ,
            .trans_queue_depth = 4,
            .on_color_trans_done = display_color_transfer_done,
            .user_ctx = display_transfer_done,
            .dc_levels = {
                .dc_idle_level = 0,
                .dc_cmd_level = 0,
                .dc_dummy_level = 0,
                .dc_data_level = 1,
            },
            .lcd_cmd_bits = 8,
            .lcd_param_bits = 8,
            .flags = {
                .swap_color_bytes = true,
            },
        };
    
        esp_lcd_panel_io_handle_t panel_io = NULL;
        ESP_ERROR_CHECK(esp_lcd_new_panel_io_i80(bus, &io_config, &panel_io));
    
        const esp_lcd_panel_dev_config_t panel_config = {
            .reset_gpio_num = PIN_LCD_RST,
            .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
            .bits_per_pixel = 16,
        };
    
        esp_lcd_panel_handle_t panel = NULL;
        ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(panel_io, &panel_config, &panel));
        ESP_ERROR_CHECK(esp_lcd_panel_reset(panel));
        ESP_ERROR_CHECK(esp_lcd_panel_init(panel));
        ESP_ERROR_CHECK(esp_lcd_panel_invert_color(panel, true));
        ESP_ERROR_CHECK(esp_lcd_panel_swap_xy(panel, true));
        ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel, true, false));
        ESP_ERROR_CHECK(esp_lcd_panel_set_gap(panel, 0, 35));
        ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel, true));
        set_backlight_brightness(LCD_BACKLIGHT_DUTY);
    
        return panel;
    }
    
    
    static void draw_bob_label(uint16_t *frame)
    {
        static const uint8_t glyphs[2][7] = {
            {0x1E, 0x11, 0x11, 0x1E, 0x11, 0x11, 0x1E}, // B
            {0x0E, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E}, // O
        };
        static const uint8_t bob_glyphs[] = {0, 1, 0};
        const int scale = 3;
        const int label_x = LCD_WIDTH - 55;
        const int label_y = 6;
        const int label_width = 51;
        const int label_height = 21;
    
        for (int y = label_y - 2; y < label_y + label_height + 2; ++y) {
            for (int x = label_x - 2; x < label_x + label_width + 2; ++x) {
                frame[(size_t)y * LCD_WIDTH + x] = RGB565(0, 0, 0);
            }
        }
    
        for (size_t character = 0; character < 3; ++character) {
            const uint8_t *glyph = glyphs[bob_glyphs[character]];
            const int character_x = label_x + (int)character * (5 * scale + scale);
    
            for (int row = 0; row < 7; ++row) {
                for (int column = 0; column < 5; ++column) {
                    if ((glyph[row] & (1U << (4 - column))) == 0) {
                        continue;
                    }
    
                    for (int pixel_y = 0; pixel_y < scale; ++pixel_y) {
                        for (int pixel_x = 0; pixel_x < scale; ++pixel_x) {
                            const int x = character_x + column * scale + pixel_x;
                            const int y = label_y + row * scale + pixel_y;
                            frame[(size_t)y * LCD_WIDTH + x] = RGB565(255, 255, 255);
                        }
                    }
                }
            }
        }
    }
    
    static void fill_color_bars(uint16_t *frame)
    {
        static const uint16_t colors[] = {
            RGB565(255, 0, 0),
            RGB565(0, 255, 0),
            RGB565(0, 0, 0),
            RGB565(0, 0, 255),
            RGB565(255, 255, 255),
        };
    
        for (int y = 0; y < LCD_HEIGHT; ++y) {
            const size_t color_index = (size_t)y * 5U / LCD_HEIGHT;
            for (int x = 0; x < LCD_WIDTH; ++x) {
                frame[(size_t)y * LCD_WIDTH + x] = colors[color_index];
            }
        }
    
        draw_bob_label(frame);
    }
    
    static void draw_frame(esp_lcd_panel_handle_t panel, const uint16_t *frame)
    {
        // The global overlay is composed last without changing the caller's scene framebuffer.
        // updateDoomCountdownOverlay();
        const uint16_t *const presentation_frame = globalOverlayCompose(frame);
        // Send the fully composed image, including any global overlay, before LCD DMA uses it.
        screenshotCapturePresentation(presentation_frame);
        ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(
            panel, 0, 0, LCD_WIDTH, LCD_HEIGHT, presentation_frame));
        // The framebuffer must stay unchanged until the LCD DMA transfer finishes.
        if (xSemaphoreTake(display_transfer_done, pdMS_TO_TICKS(1000)) != pdTRUE) {
            ESP_LOGE(TAG, "LCD transfer timed out");
            ESP_ERROR_CHECK(ESP_ERR_TIMEOUT);
        }
    }
    
    
    static int joystick_view_offset(int raw, int centre, int travel)
    {
        if (raw < 0) {
            raw = 0;
        } else if (raw > 4095) {
            raw = 4095;
        }
        const int span = raw >= centre ? 4095 - centre : centre;
        return (raw - centre) * travel / span;
    }
    
    static void draw_controller_view(uint16_t *frame, const joystick_state_t *joystick,
                                     bool joystick_valid, const int *button_levels)
    {
        const uint16_t background = RGB565(10, 16, 26);
        const uint16_t border = RGB565(76, 94, 115);
        const uint16_t white = RGB565(235, 241, 247);
        const uint16_t green = RGB565(70, 245, 130);
        const uint16_t cyan = RGB565(50, 205, 255);
        const uint16_t red = RGB565(255, 80, 65);
        const uint16_t amber = RGB565(255, 185, 60);
        static const int button_x[6] = {80, 108, 80, 52, 20, 20};
        static const int button_y[6] = {98, 124, 150, 124, 108, 80};
        static const char *button_names[7] = {"A", "B", "C", "D", "E", "F", "K"};
    
        clear(frame, background);
        fill_rect(frame, 5, 5, 130, 160, RGB565(63, 26, 35));
        fill_rect(frame, 142, 8, 1, 154, border);
    
        // Stick at top, F/E left; A north, B east, C south, D west.
        const uint16_t stick_color = button_levels[6] == 0 ? green :
                                     button_levels[6] < 0 ? amber : border;
        fill_circle(frame, 80, 44, 35, stick_color);
        fill_circle(frame, 80, 44, 31, background);
        fill_rect(frame, 53, 44, 55, 1, border);
        fill_rect(frame, 80, 17, 1, 55, border);
        drawPet2001TextTransparent(frame, 77, 19, "K", stick_color, 1);
    
        if (joystick_valid) {
            const int dot_x = 80 + joystick_view_offset(joystick->x_raw, JOYSTICK_CENTRE_X, 19);
            const int dot_y = 44 - joystick_view_offset(joystick->y_raw, JOYSTICK_CENTRE_Y, 19);
            fill_circle(frame, dot_x, dot_y, 5, background);
            fill_circle(frame, dot_x, dot_y, 4, cyan);
        } else {
            drawPet2001TextTransparent(frame, 72, 38, "ERR", red, 1);
        }
    
        for (size_t button = 0; button < 6; ++button) {
            const uint16_t color = button_levels[button] == 0 ? green :
                                   button_levels[button] < 0 ? amber : border;
            fill_circle(frame, button_x[button], button_y[button], 12, color);
            if (button_levels[button] != 0) {
                fill_circle(frame, button_x[button], button_y[button], 10, background);
            }
            drawPet2001TextCentredTransparent(frame, button_x[button], button_y[button] - 8,
                                              button_names[button],
                                              button_levels[button] == 0 ? background : white, 2);
        }
    
        drawPet2001TextTransparent(frame, 154, 10, "LIVE INPUT", white, 2);
        drawPet2001TextTransparent(frame, 154, 33,
                                    joystick_valid ? "JOYSTICK OK" : "ADC READ ERROR",
                                    joystick_valid ? cyan : red, 1);
        if (joystick_valid) {
            char reading[16];
            snprintf(reading, sizeof(reading), "X %4d", joystick->x_raw);
            drawPet2001TextTransparent(frame, 154, 51, reading, white, 2);
            snprintf(reading, sizeof(reading), "Y %4d", joystick->y_raw);
            drawPet2001TextTransparent(frame, 154, 73, reading, white, 2);
        }
    
        for (size_t button = 0; button < 7; ++button) {
            const int x = 154 + (int)button * 23;
            const uint16_t color = button_levels[button] == 0 ? green :
                                   button_levels[button] < 0 ? amber : border;
            fill_rect(frame, x, 103, 20, 23, color);
            drawPet2001TextCentredTransparent(frame, x + 10, 107, button_names[button],
                                              button_levels[button] == 0 ? background : white, 2);
        }
        drawPet2001TextTransparent(frame, 154, 139, "GREEN MEANS PRESSED", green, 1);
        drawPet2001TextTransparent(frame, 154, 154, "BOOT BACK  USER SHOT", white, 1);
    }
    
    static void draw_battery_view(uint16_t *frame)
    {
        const uint16_t background = RGB565(10, 16, 26);
        const uint16_t white = RGB565(235, 241, 247);
        const uint16_t cyan = RGB565(50, 205, 255);
        const uint16_t green = RGB565(70, 245, 130);
        const uint16_t red = RGB565(255, 80, 65);
        char text[32];
    
        clear(frame, background);
        drawPet2001TextCentredTransparent(frame, 160, 16, "BATTERY", cyan, 3);
        if (batt_has_reading()) {
            snprintf(text, sizeof(text), "%.1f V", (double)batt_voltage());
            drawPet2001TextCentredTransparent(frame, 160, 62, text, white, 4);
            drawPet2001TextCentredTransparent(frame, 160, 112,
                                               batt_external_power_connected() ? "EXTERNAL POWER" : "BATTERY POWER",
                                               batt_external_power_connected() ? green : cyan, 2);
            drawPet2001TextCentredTransparent(frame, 160, 140, "UPDATES EVERY 15 SEC", white, 1);
        } else {
            drawPet2001TextCentredTransparent(frame, 160, 80, "BATTERY ADC ERROR", red, 2);
        }
        drawPet2001TextCentredTransparent(frame, 160, 157, "BOOT BACK", white, 1);
    }
    
    static void draw_menu_view(uint16_t *frame, bool joystick_valid)
    {
        const uint16_t black = RGB565(0, 0, 0);
        const uint16_t white = RGB565(235, 241, 247);
        const uint16_t green = RGB565(70, 245, 130);
        const uint16_t magenta = RGB565(235, 80, 225);
        const uint16_t cyan = RGB565(50, 205, 255);
        const uint16_t grey = RGB565(100, 115, 135);
        const uint16_t red = RGB565(255, 80, 65);
        const bool two_column_menu = menu_current_screen() == SCREEN_MENU ||
                                     menu_current_screen() == SCREEN_GAMES ||
                                     menu_current_screen() == SCREEN_SETTINGS ||
                                     menu_current_screen() == SCREEN_MISC;
        const size_t per_page = two_column_menu ? 8 : 9;
        const size_t count = menu_count();
        const size_t selected = menu_selected_item();
        const size_t page = selected / per_page;
        const size_t first = page * per_page;
        const bool c64_menu = two_column_menu;
        const size_t page_items = count - first < per_page ? count - first : per_page;
        const size_t rows_per_column = two_column_menu && page_items != 0U ?
                                           (page_items + 1U) / 2U : 1U;
        const size_t selected_row = two_column_menu ? (selected - first) % rows_per_column : 0U;
        const size_t selected_column = two_column_menu ?
                                           (selected - first) / rows_per_column : 0U;
        const bool selected_is_text = strcmp(menu_item_text(selected), "BACK") != 0;
        const int selected_x = selected_column == 0U ? 10 : 166;
        const int selected_y = 46 + (int)selected_row * 25;
        const int selected_width = (int)strlen(menu_item_text(selected)) *
                                   PET2001_FONT_GLYPH_WIDTH * 2;
        char page_text[32];
    
        clear(frame, c64_menu ? C64_COLOR_BLUE : black);
        if (c64_menu)
            drawPet2001Text(frame, 10, 10, menu_title(), false,
                            C64_COLOR_LIGHT_GREEN, C64_COLOR_BLUE, 2);
        else drawPet2001TextTransparent(frame, 10, 10, menu_title(), cyan, 2);
        drawGameGold(frame, 174, 3, 80, true);
        snprintf(page_text, sizeof(page_text), "%u OF %u", (unsigned)(page + 1),
                 (unsigned)((count + per_page - 1) / per_page));
        drawPet2001TextTransparent(frame, 260, 12, page_text,
                                    c64_menu ? C64_COLOR_LIGHT_GREEN : grey, 1);
        if (!joystick_valid) {
            drawPet2001TextTransparent(frame, 10, 30, "ADC READ ERROR", red, 1);
        } else if (!aiTimingStorageHealthy()) {
            drawPet2001TextTransparent(frame, 10, 30, "AI TIMING STORAGE ERROR", red, 1);
        } else if (menu_current_screen() == SCREEN_GAMES && count == 1) {
            drawPet2001TextTransparent(frame, 10, 30, "NO GAMES YET", grey, 1);
        }
    
        for (size_t index = first; index < count && index < first + per_page; ++index) {
            const size_t position = index - first;
            const bool highlighted = index == selected;
            const char *label = menu_item_text(index);
            const bool back_item = strcmp(label, "BACK") == 0;
            if (two_column_menu) {
                const size_t column = position / rows_per_column;
                const size_t row = position % rows_per_column;
                const int x = column == 0U ? 10 : 166;
                const int y = 43 + (int)row * 25;
                const int normal_y = y + 7;
                const int normal_width = (int)strlen(label) * PET2001_FONT_GLYPH_WIDTH;
                const bool overlaps_selected = c64_menu && !highlighted && selected_is_text &&
                                               x < selected_x + selected_width &&
                                               selected_x < x + normal_width &&
                                               normal_y < selected_y + 16 &&
                                               selected_y < normal_y + 8;
                if (overlaps_selected) {
                    continue;
                }
                if (back_item) {
                    const int scale = highlighted ? 2 : 1;
                    const int arrow_y = y + (22 - 8 * scale) / 2;
                    if (c64_menu) {
                        if (highlighted)
                            fill_rect(frame, x, arrow_y, 8 * scale, 8 * scale,
                                      C64_COLOR_LIGHT_GREEN);
                        draw_bitmap_scaled(frame, x, arrow_y, back_arrow_bitmap, 8, 8,
                                           8 * scale, 8 * scale,
                                           highlighted ? C64_COLOR_BLUE : C64_COLOR_LIGHT_GREEN);
                    } else {
                        draw_bitmap_scaled(frame, x, arrow_y, back_arrow_bitmap, 8, 8,
                                           8 * scale, 8 * scale, highlighted ? green : white);
                    }
                } else {
                    if (c64_menu) {
                        const int scale = highlighted ? 2 : 1;
                        drawPet2001Text(frame, x, y + (highlighted ? 3 : 7), label, highlighted,
                                        C64_COLOR_LIGHT_GREEN, C64_COLOR_BLUE, scale);
                    } else {
                        char clipped[16];
                        const int maximum = highlighted ? 9 : 15;
                        int length = 0;
                        while (label[length] != '\0' && length < maximum) {
                            clipped[length] = label[length];
                            ++length;
                        }
                        clipped[length] = '\0';
                        drawPet2001TextTransparent(frame, x, y + (highlighted ? 3 : 7), clipped,
                                                    highlighted ? green : white,
                                                    highlighted ? 2 : 1);
                    }
                }
            } else {
                const int x = 4 + (int)(position % 3) * 106;
                const int y = 44 + (int)(position / 3) * 35;
                const uint16_t accent = menu_item_is_submenu(index) ? magenta : green;
                if (back_item) {
                    const int scale = highlighted ? 2 : 1;
                    const int size = 8 * scale;
                    draw_bitmap_scaled(frame, x + (100 - size) / 2, y + (30 - size) / 2,
                                   back_arrow_bitmap, 8, 8, size, size, accent);
                    continue;
                }
                char clipped[17];
                const int maximum = highlighted ? 6 : 12;
                int length = 0;
                while (label[length] != '\0' && length < maximum) {
                    clipped[length] = label[length];
                    ++length;
                }
                clipped[length] = '\0';
                const int scale = highlighted ? 2 : 1;
                // PET cells are 8 pixels wide, so preserve each 100-pixel column's margins.
                const int text_width = length * PET2001_FONT_GLYPH_WIDTH * scale;
                drawPet2001TextTransparent(frame, x + (100 - text_width) / 2,
                                            y + (30 - PET2001_FONT_GLYPH_HEIGHT * scale) / 2,
                                            clipped, accent, scale);
            }
        }
        drawPet2001TextTransparent(frame, 8, 156,
                                    two_column_menu ? "D/B UP/DOWN  JS  A/K SELECT" :
                                                      "D/B/JS  A/K SELECT",
                                    c64_menu ? C64_COLOR_LIGHT_GREEN : grey, 1);
        drawPet2001TextTransparent(frame, 250, 156, "BOOT BACK",
                                    c64_menu ? C64_COLOR_LIGHT_GREEN : grey, 1);
    }
    
    static void initialize_buttons(void)
    {
        // A software reset after light sleep can retain a pad's prior sleep state.
        // Clear it before restoring the board buttons as active-low pull-up inputs.
        (void)gpio_hold_dis(PIN_BUTTON_BOOT);
        (void)gpio_hold_dis(PIN_BUTTON_USER);
        ESP_ERROR_CHECK(gpio_reset_pin(PIN_BUTTON_BOOT));
        ESP_ERROR_CHECK(gpio_reset_pin(PIN_BUTTON_USER));
        const gpio_config_t button_config = {
            .pin_bit_mask = (1ULL << PIN_BUTTON_BOOT) | (1ULL << PIN_BUTTON_USER),
            .mode = GPIO_MODE_INPUT,
            .pull_up_en = GPIO_PULLUP_ENABLE,
            .pull_down_en = GPIO_PULLDOWN_DISABLE,
            .intr_type = GPIO_INTR_DISABLE,
        };
        ESP_ERROR_CHECK(gpio_config(&button_config));
    }
    
    static void initialize_audio_shutdown(void)
    {
        (void)gpio_hold_dis(PIN_AUDIO_SHUTDOWN);
        ESP_ERROR_CHECK(gpio_reset_pin(PIN_AUDIO_SHUTDOWN));
        const gpio_config_t shutdown_config = {
            .pin_bit_mask = 1ULL << PIN_AUDIO_SHUTDOWN,
            .mode = GPIO_MODE_OUTPUT,
            .pull_up_en = GPIO_PULLUP_DISABLE,
            .pull_down_en = GPIO_PULLDOWN_DISABLE,
            .intr_type = GPIO_INTR_DISABLE,
        };
        ESP_ERROR_CHECK(gpio_config(&shutdown_config));
        ESP_ERROR_CHECK(gpio_set_level(PIN_AUDIO_SHUTDOWN, 1));
        ESP_LOGI(TAG, "Amplifier shutdown control ready on GPIO%d", PIN_AUDIO_SHUTDOWN);
    }
    
    static void restore_light_sleep_button_inputs(void)
    {
        (void)gpio_hold_dis(PIN_BUTTON_BOOT);
        (void)gpio_hold_dis(PIN_BUTTON_USER);
        (void)gpio_hold_dis(PIN_LIGHT_SLEEP_WAKE);
        initialize_buttons();
        const gpio_config_t wake_button_config = {
            .pin_bit_mask = 1ULL << PIN_LIGHT_SLEEP_WAKE,
            .mode = GPIO_MODE_INPUT,
            .pull_up_en = GPIO_PULLUP_ENABLE,
            .pull_down_en = GPIO_PULLDOWN_DISABLE,
            .intr_type = GPIO_INTR_DISABLE,
        };
        ESP_ERROR_CHECK(gpio_config(&wake_button_config));
        reset_button_debounce_after_sleep = true;
    }
    
    #if TF_CARD_ENABLED
    static bool initialize_tf_card(void)
    {
        ESP_LOGI(TAG, "Initializing TF card on CS=%d, MOSI=%d, SCK=%d, MISO=%d",
                 PIN_TF_CS, PIN_TF_MOSI, PIN_TF_SCK, PIN_TF_MISO);
    
        sdmmc_host_t host = SDSPI_HOST_DEFAULT();
        host.slot = SPI2_HOST;
        host.max_freq_khz = TF_MAX_FREQUENCY_KHZ;
    
        const spi_bus_config_t bus_config = {
            .mosi_io_num = PIN_TF_MOSI,
            .miso_io_num = PIN_TF_MISO,
            .sclk_io_num = PIN_TF_SCK,
            .quadwp_io_num = -1,
            .quadhd_io_num = -1,
            .max_transfer_sz = 4096,
        };
    
        esp_err_t result = spi_bus_initialize(host.slot, &bus_config, SPI_DMA_CH_AUTO);
        if (result != ESP_OK) {
            ESP_LOGE(TAG, "TF SPI bus initialization failed: %s", esp_err_to_name(result));
            return false;
        }
    
        sdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT();
        slot_config.gpio_cs = PIN_TF_CS;
        slot_config.host_id = host.slot;
    
        const esp_vfs_fat_sdmmc_mount_config_t mount_config = {
            .format_if_mount_failed = false,
            .max_files = 5,
            .allocation_unit_size = 16 * 1024,
        };
    
        result = esp_vfs_fat_sdspi_mount(
            TF_MOUNT_POINT, &host, &slot_config, &mount_config, &tf_card);
        if (result != ESP_OK) {
            ESP_LOGE(TAG, "TF card mount failed: %s", esp_err_to_name(result));
            spi_bus_free(host.slot);
            return false;
        }
    
        ESP_LOGI(TAG, "TF card mounted read/write at %s", TF_MOUNT_POINT);
        sdmmc_card_print_info(stdout, tf_card);
    
        struct statvfs filesystem = {0};
        if (statvfs(TF_MOUNT_POINT, &filesystem) == 0) {
            const uint64_t total_bytes =
                (uint64_t)filesystem.f_blocks * filesystem.f_frsize;
            const uint64_t free_bytes =
                (uint64_t)filesystem.f_bfree * filesystem.f_frsize;
            ESP_LOGI(TAG, "TF filesystem total/free: %" PRIu64 " / %" PRIu64 " bytes",
                     total_bytes, free_bytes);
        } else {
            ESP_LOGW(TAG, "TF card mounted, but filesystem space could not be read");
        }
    
        return true;
    }
    #endif
    
    static bool enter_light_sleep(esp_lcd_panel_handle_t panel, bool *tf_available)
    {
    #if !TF_CARD_ENABLED
        (void)tf_available;
    #endif
        const int wake_button_level = gpio_get_level(PIN_LIGHT_SLEEP_WAKE);
        if (wake_button_level == 0) {
            ESP_LOGW(TAG, "Light sleep cancelled; release shield B (GPIO%d)",
                     PIN_LIGHT_SLEEP_WAKE);
            return false;
        }
    
        const uint64_t wake_pins = 1ULL << PIN_LIGHT_SLEEP_WAKE;
        const esp_err_t wake_result = esp_sleep_enable_ext1_wakeup(
            wake_pins, ESP_EXT1_WAKEUP_ANY_LOW);
        if (wake_result != ESP_OK) {
            ESP_LOGE(TAG, "Light-sleep wake configuration failed: %s",
                     esp_err_to_name(wake_result));
            return false;
        }
    
        timeSyncStop();
        (void)wifiServiceStop();
    #if TF_CARD_ENABLED
        if (*tf_available && tf_card != NULL) {
            const esp_err_t unmount_result = esp_vfs_fat_sdcard_unmount(TF_MOUNT_POINT, tf_card);
            if (unmount_result == ESP_OK) {
                tf_card = NULL;
                *tf_available = false;
                const esp_err_t bus_result = spi_bus_free(SPI2_HOST);
                if (bus_result != ESP_OK) {
                    ESP_LOGW(TAG, "TF SPI release failed: %s", esp_err_to_name(bus_result));
                }
            } else {
                ESP_LOGW(TAG, "TF card unmount failed: %s", esp_err_to_name(unmount_result));
            }
        }
    #endif
    
        ESP_ERROR_CHECK(ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 0));
        ESP_ERROR_CHECK(ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0));
        ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel, false));
        ESP_ERROR_CHECK(gpio_set_level(PIN_AUDIO_SHUTDOWN, 0));
        ESP_ERROR_CHECK(gpio_hold_en(PIN_AUDIO_SHUTDOWN));
        ESP_LOGI(TAG, "Entering light sleep; press shield B to wake");
        const esp_err_t sleep_result = esp_light_sleep_start();
        if (sleep_result != ESP_OK) {
            ESP_LOGE(TAG, "Light sleep failed: %s", esp_err_to_name(sleep_result));
        }
        ESP_ERROR_CHECK(esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_EXT1));
        ESP_ERROR_CHECK(gpio_hold_dis(PIN_AUDIO_SHUTDOWN));
        ESP_ERROR_CHECK(gpio_set_level(PIN_AUDIO_SHUTDOWN, 1));
        restore_light_sleep_button_inputs();
    
        ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel, true));
        set_backlight_brightness(settingsBrightness());
    #if TF_CARD_ENABLED
        if (!*tf_available) {
            *tf_available = initialize_tf_card();
            ESP_LOGI(TAG, "TF CARD AFTER WAKE: %s",
                     *tf_available ? "READY" : "NOT AVAILABLE");
        }
    #endif
        ESP_LOGI(TAG, "Resumed from light sleep");
        return sleep_result == ESP_OK;
    }
    
    void app_main(void)
    {
        esp_chip_info_t chip_info = {0};
        uint32_t flash_size = 0;
        esp_chip_info(&chip_info);
        const esp_err_t flash_result = esp_flash_get_size(NULL, &flash_size);
        const bool psram_initialized = esp_psram_is_initialized();
        const size_t psram_chip_size = esp_psram_get_size();
        const size_t psram_total = heap_caps_get_total_size(MALLOC_CAP_SPIRAM);
        const size_t psram_free = heap_caps_get_free_size(MALLOC_CAP_SPIRAM);
    
        ESP_LOGI(TAG, "LilyGO T-Display-S3 V1.1 diagnostic");
        ESP_LOGI(TAG, "Chip: ESP32-S3, revision %d, %d CPU cores", chip_info.revision,
                 chip_info.cores);
        ESP_LOGI(TAG, "Configured CPU frequency: %d MHz", CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ);
        if (flash_result == ESP_OK) {
            ESP_LOGI(TAG, "Detected flash: %" PRIu32 " MB", flash_size / (1024U * 1024U));
        } else {
            ESP_LOGE(TAG, "Unable to read flash size: %s", esp_err_to_name(flash_result));
        }
        ESP_LOGI(TAG, "PSRAM initialized: %s", psram_initialized ? "yes" : "no");
        ESP_LOGI(TAG, "PSRAM chip size: %u bytes", (unsigned)psram_chip_size);
        ESP_LOGI(TAG, "PSRAM heap total/free: %u / %u bytes", (unsigned)psram_total,
                 (unsigned)psram_free);
    
        const bool memory_ok = flash_result == ESP_OK &&
                               flash_size == EXPECTED_FLASH_BYTES &&
                               psram_initialized &&
                               psram_chip_size >= EXPECTED_PSRAM_BYTES;
        if (!memory_ok) {
            ESP_LOGE(TAG, "Memory check FAILED: expected 16 MB flash and 8 MB PSRAM");
        }
    
        uint16_t *frame = heap_caps_malloc(
            FRAME_BUFFER_BYTES,
            MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA | MALLOC_CAP_8BIT);
        if (frame == NULL) {
            ESP_LOGE(TAG, "Unable to allocate the %u-byte PSRAM display buffer",
                     (unsigned)FRAME_BUFFER_BYTES);
            return;
        }
        ESP_LOGI(TAG, "PSRAM display buffer allocated: %u bytes",
                 (unsigned)FRAME_BUFFER_BYTES);
    
        if (!globalOverlayInitialize()) {
            ESP_LOGE(TAG, "Unable to allocate the %u-byte PSRAM overlay presentation buffer",
                     (unsigned)FRAME_BUFFER_BYTES);
            heap_caps_free(frame);
            return;
        }
    
        display_transfer_done = xSemaphoreCreateBinary();
        if (display_transfer_done == NULL) {
            ESP_LOGE(TAG, "Unable to allocate LCD transfer semaphore");
            globalOverlayDeinitialize();
            heap_caps_free(frame);
            return;
        }
    
        initialize_buttons();
        initialize_audio_shutdown();
        esp_lcd_panel_handle_t panel = initialize_display();
    
        if (memory_ok) {
            clear(frame, RGB565(0, 0, 0));
        } else {
            clear(frame, RGB565(255, 0, 255));
            ESP_LOGE(TAG, "Magenta screen indicates a memory diagnostic failure");
        }
        draw_frame(panel, frame);
    
        ESP_LOGI(TAG, "LilyGO T-Display-S3 V1.1 diagnostic report");
        ESP_LOGI(TAG, "Chip: ESP32-S3, revision %d, %d CPU cores", chip_info.revision,
                 chip_info.cores);
        ESP_LOGI(TAG, "Configured CPU frequency: %d MHz", CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ);
        if (flash_result == ESP_OK) {
            ESP_LOGI(TAG, "Detected flash: %" PRIu32 " MB", flash_size / (1024U * 1024U));
        } else {
            ESP_LOGE(TAG, "Unable to read flash size: %s", esp_err_to_name(flash_result));
        }
        ESP_LOGI(TAG, "PSRAM initialized: %s", psram_initialized ? "yes" : "no");
        ESP_LOGI(TAG, "PSRAM chip size: %u bytes", (unsigned)psram_chip_size);
        ESP_LOGI(TAG, "PSRAM heap total/free at startup: %u / %u bytes",
                 (unsigned)psram_total, (unsigned)psram_free);
        ESP_LOGI(TAG, "PSRAM display buffer: %u bytes", (unsigned)FRAME_BUFFER_BYTES);
        if (memory_ok) {
            ESP_LOGI(TAG, "BOARD DIAGNOSTIC: PASS");
        } else {
            ESP_LOGE(TAG, "BOARD DIAGNOSTIC: FAIL");
        }
        bool tf_available = false;
    #if TF_CARD_ENABLED
        tf_available = initialize_tf_card();
        ESP_LOGI(TAG, "TF CARD: %s", tf_available ? "READY" : "NOT AVAILABLE");
    #else
        ESP_LOGI(TAG, "TF CARD: DISABLED");
    #endif
        const bool dungeon_files_ready = dungeonFilesInitialize(tf_available);
        ESP_LOGI(TAG, "DUNGEON DATA: %s", dungeon_files_ready ? "READY" : "NOT AVAILABLE");
    #if RAM_MONITOR_ENABLED
        if (dungeon_files_ready) ramMonitorInitialize();
        else ESP_LOGW(TAG, "RAM MONITOR: DISABLED (SPIFFS NOT AVAILABLE)");
    #else
        ESP_LOGI(TAG, "RAM MONITOR: DISABLED (FEATURE SWITCH)");
    #endif
        const bool storage_ready = game_storage_initialize();
        const bool gold_ready = storage_ready && initGold();
        const bool timing_ready = storage_ready && initAITiming();
        const bool settings_ready = storage_ready && settingsInitialize();
        const bool clock_time_ready = storage_ready && timeSyncInitialize();
        const bool audio_ready = audioInitialize();
        set_backlight_brightness(settingsBrightness());
        ESP_LOGI(TAG, "GAME STORAGE: %s; GOLD: %s; AI TIMING: %s; SETTINGS: %s; CLOCK: %s; AUDIO: %s",
                 storage_ready ? "READY" : "FAILED",
                 gold_ready ? "READY" : "FAILED",
                 timing_ready ? "READY" : "DEFAULTS ONLY",
                 settings_ready ? "READY" : "DEFAULTS ONLY", clock_time_ready ? "READY" : "DEFAULTS ONLY",
                 audio_ready ? "READY" : "FAILED");
        if (storage_ready) {
            nvs_stats_t stats = {0};
            const esp_err_t stats_result = nvs_get_stats(NULL, &stats);
            if (stats_result == ESP_OK) {
                ESP_LOGI(TAG, "NVS entries: used %u; available %u; total %u",
                         (unsigned)stats.used_entries, (unsigned)stats.available_entries,
                         (unsigned)stats.total_entries);
            } else {
                ESP_LOGW(TAG, "Cannot read NVS capacity: %s", esp_err_to_name(stats_result));
            }
        }
        ESP_LOGI(TAG, "Initializing raw joystick test");
        ESP_LOGI(TAG, "Joystick X: GPIO1 / ADC1 channel 0");
        ESP_LOGI(TAG, "Joystick Y: GPIO2 / ADC1 channel 1");
    
        const esp_err_t joystick_result = controller_input_initialize();
        if (joystick_result != ESP_OK) {
            ESP_LOGE(TAG, "Joystick initialization failed: %s",
                     esp_err_to_name(joystick_result));
            return;
        }
    
        const bool battery_ready = batt_initialize();
        ESP_LOGI(TAG, "BATTERY ADC: %s", battery_ready ? "READY" : "FAILED");
    
        ESP_LOGI(TAG, "RAW JOYSTICK TEST: READY");
    
        ESP_LOGI(TAG, "USER short press captures a screenshot; hold USER in Demo opens its selector");
    
        const gpio_num_t shield_button_pins[] = {
            GPIO_NUM_16, GPIO_NUM_21, GPIO_NUM_17, GPIO_NUM_18,
            GPIO_NUM_44, GPIO_NUM_43, GPIO_NUM_3,
        };
        const char *shield_button_names[] = {
            "A", "B", "C", "D", "E", "F", "K",
        };
        const size_t shield_button_count =
            sizeof(shield_button_pins) / sizeof(shield_button_pins[0]);
    
        int previous_shield_levels[7];
        int stable_shield_levels[7];
        TickType_t shield_changed_at[7];
    
        uint64_t shield_button_mask = 0;
        for (size_t button = 0; button < shield_button_count; ++button) {
            shield_button_mask |= 1ULL << shield_button_pins[button];
        }
    
        const gpio_config_t shield_button_config = {
            .pin_bit_mask = shield_button_mask,
            .mode = GPIO_MODE_INPUT,
            .pull_up_en = GPIO_PULLUP_ENABLE,
            .pull_down_en = GPIO_PULLDOWN_DISABLE,
            .intr_type = GPIO_INTR_DISABLE,
        };
        ESP_ERROR_CHECK(gpio_config(&shield_button_config));
    
        for (size_t button = 0; button < shield_button_count; ++button) {
            previous_shield_levels[button] =
                gpio_get_level(shield_button_pins[button]);
            stable_shield_levels[button] = -1;
            shield_changed_at[button] = xTaskGetTickCount();
        }
    
        ESP_LOGI(TAG, "SHIELD BUTTON TEST: READY");
    
        int previous_user_level = gpio_get_level(PIN_BUTTON_USER);
        int stable_user_level = previous_user_level;
        TickType_t user_changed_at = xTaskGetTickCount();
        TickType_t user_pressed_at = user_changed_at;
        bool user_long_sent = false;
        bool user_capture_cancelled = false;
        TickType_t last_controller_refresh =
            xTaskGetTickCount() - pdMS_TO_TICKS(CONTROLLER_REFRESH_MS);
        TickType_t last_render_refresh =
            xTaskGetTickCount() - pdMS_TO_TICKS(RENDER_REFRESH_MS);
        bool previous_joystick_valid = true;
        joystick_state_t live_joystick = {0};
        bool joystick_valid = true;
        bool joystick_validity_changed = true;
        bool menu_redraw_pending = true;
        int previous_boot_level = gpio_get_level(PIN_BUTTON_BOOT);
        int stable_boot_level = previous_boot_level;
        TickType_t boot_changed_at = xTaskGetTickCount();
        TickType_t boot_pressed_at = boot_changed_at;
        bool boot_long_sent = false;
        TickType_t full_reset_pressed_at = 0;
        bool full_reset_armed = stable_boot_level != 0 || stable_user_level != 0;
        ESP_LOGI(TAG, "Board BOOT (GPIO%d): %s", PIN_BUTTON_BOOT,
                 stable_boot_level == 0 ? "PRESSED" : "RELEASED");
        bool checkers_active = false;
        bool othello_active = false;
        bool connect_four_active = false;
        bool battleships_active = false;
        bool yahtzee_active = false;
        bool blackjack_active = false;
        bool poker_active = false;
        bool poker_dice_active = false;
        bool pig_active = false;
        bool brightness_settings_active = false;
        bool volume_settings_active = false;
        bool wifi_settings_active = false;
        bool esp_info_active = false;
        bool ram_log_active = false;
        bool power_off_settings_active = false;
        bool restart_settings_active = false;
        bool game_config_active = false;
        bool font_test_active = false;
        bool about_active = false;
        bool matrix_active = false;
        bool boing_ball_active = false;
        bool demo_active = false;
        bool simon_active = false;
        bool calculator_active = false;
        bool kaleidoscope_active = false;
        bool warp_tunnel_active = false;
        bool mandelbrot_active = false;
        bool clock_active = false;
        bool slideshow_active = false;
        bool spiffs_test_active = false;
        bool sound_test_active = false;
        bool sd_card_test_active = false;
        bool asteroids_active = false;
        bool battle_zone_active = false;
        bool boulder_dash_active = false;
        bool tempest_active = false;
        bool invaders_active = false;
        bool missile_command_active = false;
        bool breakout_active = false;
        bool crawler_active = false;
        bool maze_chase_active = false;
        bool scramble_active = false;
        bool defender_active = false;
        bool galaga_active = false;
        bool dungeon_active = false;
        bool hall_of_fame_active = false;
    
        bool game_paused = false;
        bool pause_redraw = false;
        static const uint16_t pause_colors[] = {
            COLOR_RED, COLOR_YELLOW, COLOR_CYAN, COLOR_WHITE, COLOR_BLACK, COLOR_MAGENTA
        };
        size_t pause_color_index = 0;
        uint32_t pause_color_changed_ms = 0;
        uint32_t game_clock_last_ms = (uint32_t)(xTaskGetTickCount() * portTICK_PERIOD_MS);
        uint32_t game_now_ms = game_clock_last_ms;
    
        menu_initialize((uint32_t)(xTaskGetTickCount() * portTICK_PERIOD_MS));
    
        ESP_LOGI(TAG, "MENU: %s",
                 memory_ok ? "READY" : "DISABLED BY MEMORY CHECK");
    
        while (true) {
            if (reset_button_debounce_after_sleep) {
                previous_boot_level = stable_boot_level = gpio_get_level(PIN_BUTTON_BOOT);
                previous_user_level = stable_user_level = gpio_get_level(PIN_BUTTON_USER);
                boot_changed_at = boot_pressed_at = user_changed_at = user_pressed_at =
                    xTaskGetTickCount();
                boot_long_sent = false;
                user_long_sent = false;
                user_capture_cancelled = stable_boot_level == 0 && stable_user_level == 0;
                full_reset_armed = stable_boot_level != 0 || stable_user_level != 0;
                full_reset_pressed_at = 0;
                for (size_t button = 0; button < shield_button_count; ++button) {
                    previous_shield_levels[button] = stable_shield_levels[button] =
                        gpio_get_level(shield_button_pins[button]);
                    shield_changed_at[button] = xTaskGetTickCount();
                }
                reset_button_debounce_after_sleep = false;
            }
            const int user_level = gpio_get_level(PIN_BUTTON_USER);
            const TickType_t now = xTaskGetTickCount();
            const uint32_t now_ms = (uint32_t)(now * portTICK_PERIOD_MS);
    #if RAM_MONITOR_ENABLED
            if (dungeon_files_ready) ramMonitorUpdate(now_ms);
    #endif
            // Games share a clock that excludes paused time. Hardware and menus use real time.
            if (!game_paused) game_now_ms += now_ms - game_clock_last_ms;
            game_clock_last_ms = now_ms;
            bool k_pressed = false;
            bool a_pressed = false;
            bool b_pressed = false;
            bool c_pressed = false;
            bool d_pressed = false;
            bool e_pressed = false;
            bool f_pressed = false;
            bool user_short_pressed = false;
            bool user_long_pressed = false;
            bool boot_short = false;
            bool boot_long = false;
    
            const int boot_level = gpio_get_level(PIN_BUTTON_BOOT);
            if (boot_level != previous_boot_level) {
                previous_boot_level = boot_level;
                boot_changed_at = now;
            }
            if (boot_level != stable_boot_level &&
                (now - boot_changed_at) >= pdMS_TO_TICKS(30)) {
                stable_boot_level = boot_level;
                ESP_LOGI(TAG, "Board BOOT (GPIO%d): %s", PIN_BUTTON_BOOT,
                         stable_boot_level == 0 ? "PRESSED" : "RELEASED");
                if (stable_boot_level == 0) {
                    boot_pressed_at = now;
                    boot_long_sent = false;
                } else {
                    boot_short = !boot_long_sent;
                }
            }
            if (stable_boot_level == 0 && !boot_long_sent &&
                (now - boot_pressed_at) >= pdMS_TO_TICKS(800)) {
                boot_long_sent = true;
                boot_long = true;
            }
    
            if (user_level != previous_user_level) {
                previous_user_level = user_level;
                user_changed_at = now;
            }
    
            if (user_level != stable_user_level &&
                (now - user_changed_at) >= pdMS_TO_TICKS(30)) {
                stable_user_level = user_level;
    
                if (stable_user_level == 0) {
                    user_pressed_at = now;
                    user_long_sent = false;
                    user_capture_cancelled = stable_boot_level == 0;
                } else if (!user_long_sent && !user_capture_cancelled) {
                    user_short_pressed = true;
                }
            }
    
            // The BOOT + USER restart chord always takes precedence over capture or Demo control.
            if (stable_boot_level == 0 && stable_user_level == 0) {
                user_capture_cancelled = true;
            }
            if (stable_user_level == 0 && stable_boot_level != 0 && !user_capture_cancelled &&
                !user_long_sent &&
                (now - user_pressed_at) >= pdMS_TO_TICKS(USER_LONG_PRESS_MS)) {
                user_long_sent = true;
                user_long_pressed = true;
            }
    
            for (size_t button = 0; button < shield_button_count; ++button) {
                const int level = gpio_get_level(shield_button_pins[button]);
    
                if (level != previous_shield_levels[button]) {
                    previous_shield_levels[button] = level;
                    shield_changed_at[button] = now;
                }
    
                if (level != stable_shield_levels[button] &&
                    (now - shield_changed_at[button]) >= pdMS_TO_TICKS(30)) {
                    if (button == 6 && stable_shield_levels[button] == 1 && level == 0) {
                        k_pressed = true;
                    }
                    if (stable_shield_levels[button] == 1 && level == 0) {
                        if (button == 0) a_pressed = true;
                        if (button == 1) b_pressed = true;
                        if (button == 2) c_pressed = true;
                        if (button == 3) d_pressed = true;
                        if (button == 4) e_pressed = true;
                        if (button == 5) f_pressed = true;
                    }
                    // C is game-specific; only the board's BOOT button navigates back/home.
                    stable_shield_levels[button] = level;
    
                    ESP_LOGI(TAG, "Shield button %s (GPIO%d): %s",
                             shield_button_names[button],
                             (int)shield_button_pins[button],
                             level == 0 ? "PRESSED" : "RELEASED");
                }
            }
    
            // Both board buttons held together perform a normal ESP reboot.
            // Require a release first so buttons held during startup cannot loop resets.
            if (stable_boot_level != 0 || stable_user_level != 0) {
                full_reset_armed = true;
                full_reset_pressed_at = 0;
            } else if (full_reset_armed && full_reset_pressed_at == 0) {
                full_reset_pressed_at = now;
            } else if (full_reset_armed &&
                       (now - full_reset_pressed_at) >= pdMS_TO_TICKS(FULL_RESET_HOLD_MS)) {
                ESP_LOGW(TAG, "BOOT and USER held: restarting ESP");
                esp_restart();
            }
    
            if (user_short_pressed) {
                const char *const screenshot_source_label = demo_active ? demoScreenshotLabel() :
                    hall_of_fame_active ? hallOfFameScreenshotLabel() : menuScreenshotLabel();
                screenshotRequest(screenshot_source_label);
                // Static menu screens need one scheduled render before their queued capture can send.
                menu_redraw_pending = true;
            }
    
            const bool left_held = stable_shield_levels[3] == 0;  // D
            const bool right_held = stable_shield_levels[1] == 0; // B
    
            const bool app_active = checkers_active || othello_active || connect_four_active || battleships_active ||
                                    yahtzee_active || blackjack_active || poker_active || poker_dice_active || pig_active ||
                                    brightness_settings_active || volume_settings_active || wifi_settings_active || esp_info_active || ram_log_active ||
                                    power_off_settings_active || restart_settings_active || game_config_active || font_test_active ||
                                    about_active || matrix_active || boing_ball_active || demo_active || simon_active || calculator_active || kaleidoscope_active || warp_tunnel_active || mandelbrot_active ||
                                    clock_active || slideshow_active || spiffs_test_active || sound_test_active || sd_card_test_active ||
                                    asteroids_active || battle_zone_active || boulder_dash_active || tempest_active || invaders_active || missile_command_active ||
                                    breakout_active || crawler_active || maze_chase_active || scramble_active || defender_active || galaga_active ||
                                    dungeon_active || hall_of_fame_active;
            if (!app_active || boot_short || boot_long) {
                game_paused = false;
                pause_redraw = false;
            } else if (f_pressed) {
                game_paused = !game_paused;
                pause_redraw = game_paused;
                ESP_LOGI(TAG, "App %s", game_paused ? "PAUSED" : "RESUMED");
            }
    
            if (boot_long) {
                ESP_LOGI(TAG, "BOOT HOME");
                menu_home(now_ms);
            } else if (boot_short) {
                ESP_LOGI(TAG, "BOOT BACK");
                menu_back(now_ms);
            } else if (game_paused || (app_active && f_pressed)) {
                // Consume pause/resume and discard module actions while paused.
            } else if (highScoreEntryActive()) {
                highScoreEntryAction(a_pressed);
            } else if (checkers_active) {
                checkersAction(k_pressed || a_pressed, e_pressed, c_pressed, game_now_ms);
            } else if (othello_active) {
                othelloAction(k_pressed || a_pressed, e_pressed, c_pressed, game_now_ms);
            } else if (connect_four_active) {
                connectFourAction(k_pressed || a_pressed, e_pressed, c_pressed, game_now_ms);
            } else if (battleships_active) {
                battleshipsAction(k_pressed || a_pressed, e_pressed, c_pressed, game_now_ms);
            } else if (yahtzee_active) {
                yahtzeeAction(k_pressed || a_pressed, e_pressed, c_pressed, game_now_ms);
            } else if (blackjack_active) {
                blackjackAction(k_pressed || a_pressed, e_pressed, c_pressed, game_now_ms);
            } else if (poker_active) {
                pokerAction(k_pressed || a_pressed, c_pressed, e_pressed, game_now_ms);
            } else if (poker_dice_active) {
                pokerDiceAction(k_pressed || a_pressed, c_pressed, e_pressed, game_now_ms);
            } else if (pig_active) {
                pigAction(k_pressed || a_pressed, e_pressed, c_pressed, game_now_ms);
            } else if (brightness_settings_active) {
                settingsAction(k_pressed || a_pressed, now_ms);
            } else if (volume_settings_active) {
                settingsAction(k_pressed || a_pressed, now_ms);
            } else if (wifi_settings_active) {
                settingsAction(k_pressed || a_pressed, now_ms);
            } else if (esp_info_active) {
                settingsAction(k_pressed || a_pressed, now_ms);
            } else if (ram_log_active) {
                settingsAction(k_pressed || a_pressed, now_ms);
            } else if (restart_settings_active) {
                settingsAction(k_pressed || a_pressed, now_ms);
            } else if (power_off_settings_active) {
                settingsAction(k_pressed || a_pressed, now_ms);
            } else if (game_config_active) {
                gameConfigAction(a_pressed, k_pressed, now_ms);
            } else if (font_test_active) {
                fontTestAction(k_pressed || a_pressed);
            } else if (about_active) {
                aboutAction(a_pressed, f_pressed, now_ms);
            } else if (matrix_active) {
                matrixAction(a_pressed, e_pressed, now_ms);
            } else if (boing_ball_active) {
                boingBallAction(d_pressed, b_pressed, a_pressed, c_pressed, now_ms);
            } else if (demo_active) {
                demoAction(k_pressed || a_pressed, b_pressed, c_pressed, user_long_pressed,
                           d_pressed, b_pressed, now_ms);
            } else if (simon_active) {
                simonAction(a_pressed, b_pressed, c_pressed, d_pressed, now_ms);
            } else if (calculator_active) {
                calculatorAction(k_pressed || a_pressed, c_pressed, d_pressed, b_pressed, now_ms);
            } else if (kaleidoscope_active) {
                kaleidoscopeAction(k_pressed || a_pressed, d_pressed, c_pressed, e_pressed, now_ms);
            } else if (warp_tunnel_active) {
                warpTunnelAction(k_pressed || a_pressed, c_pressed, e_pressed, now_ms);
            } else if (mandelbrot_active) {
                mandelbrotAction(k_pressed || a_pressed, c_pressed, b_pressed, e_pressed, now_ms);
            } else if (slideshow_active) {
                slideshowAction(k_pressed || a_pressed, c_pressed, now_ms);
            } else if (spiffs_test_active) {
                spiffsTestAction(k_pressed || a_pressed);
            } else if (sound_test_active) {
                soundTestAction(k_pressed || a_pressed, d_pressed, b_pressed, e_pressed);
            } else if (sd_card_test_active) {
                sdCardTestAction(k_pressed || a_pressed, c_pressed, now_ms);
            } else if (asteroids_active) {
                asteroidsAction(k_pressed || a_pressed, c_pressed, game_now_ms);
            } else if (battle_zone_active) {
                battleZoneAction(k_pressed || a_pressed, c_pressed, game_now_ms);
            } else if (boulder_dash_active) {
                boulderDashAction(k_pressed || a_pressed, game_now_ms);
            } else if (tempest_active) {
                tempestAction(k_pressed || a_pressed, e_pressed, game_now_ms);
            } else if (invaders_active) {
                invadersAction(k_pressed || a_pressed, c_pressed, game_now_ms);
            } else if (missile_command_active) {
                missileCommandAction(k_pressed || a_pressed, e_pressed, game_now_ms);
            } else if (breakout_active) {
                breakoutAction(k_pressed || a_pressed, e_pressed, game_now_ms);
            } else if (crawler_active) {
                crawlerAction(k_pressed || a_pressed,
                              stable_shield_levels[0] == 0 || stable_shield_levels[6] == 0,
                              game_now_ms);
            } else if (maze_chase_active) {
                mazeChaseAction(k_pressed || a_pressed, game_now_ms);
            } else if (scramble_active) {
                scrambleAction(k_pressed || a_pressed, game_now_ms);
            } else if (defender_active) {
                defenderAction(k_pressed || a_pressed, c_pressed, game_now_ms);
            } else if (galaga_active) {
                galagaAction(k_pressed || a_pressed, game_now_ms);
            } else if (dungeon_active) {
                dungeonAIControl(e_pressed, game_now_ms);
                dungeonAction(k_pressed || a_pressed, b_pressed, c_pressed, d_pressed, game_now_ms);
            } else if (k_pressed || a_pressed) {
                menu_select(now_ms);
            }
    
            // One shared C64 Turbo Tape transition.  It delays only a new game start;
            // returning to the Games menu cancels it immediately through menu_back().
            turboLoaderUpdate(menu_current_screen(), now_ms);
    
            const bool checkers_requested = memory_ok && menu_current_screen() == SCREEN_CHECKERS;
            if (checkers_requested && !checkers_active && !turboLoaderActive()) {
                startCheckers(game_now_ms);
                checkers_active = true;
            } else if (!checkers_requested && checkers_active) {
                stopCheckers();
                checkers_active = false;
            }
    
            const bool othello_requested = memory_ok && menu_current_screen() == SCREEN_OTHELLO;
            if (othello_requested && !othello_active && !turboLoaderActive()) {
                startOthello(game_now_ms);
                othello_active = true;
            } else if (!othello_requested && othello_active) {
                stopOthello();
                othello_active = false;
            }
    
            const bool connect_four_requested =
                memory_ok && menu_current_screen() == SCREEN_CONNECT_FOUR;
            if (connect_four_requested && !connect_four_active && !turboLoaderActive()) {
                startConnectFour(game_now_ms);
                connect_four_active = true;
            } else if (!connect_four_requested && connect_four_active) {
                stopConnectFour();
                connect_four_active = false;
            }
    
            const bool battleships_requested =
                memory_ok && menu_current_screen() == SCREEN_BATTLESHIPS;
            if (battleships_requested && !battleships_active && !turboLoaderActive()) {
                startBattleships(game_now_ms);
                battleships_active = true;
            } else if (!battleships_requested && battleships_active) {
                stopBattleships();
                battleships_active = false;
            }
    
            const bool yahtzee_requested = memory_ok && menu_current_screen() == SCREEN_YAHTZEE;
            if (yahtzee_requested && !yahtzee_active && !turboLoaderActive()) {
                startYahtzee(game_now_ms);
                yahtzee_active = true;
            } else if (!yahtzee_requested && yahtzee_active) {
                stopYahtzee();
                yahtzee_active = false;
            }
    
            const bool blackjack_requested = memory_ok && menu_current_screen() == SCREEN_BLACKJACK;
            if (blackjack_requested && !blackjack_active && !turboLoaderActive()) {
                startBlackjack(game_now_ms);
                blackjack_active = true;
            } else if (!blackjack_requested && blackjack_active) {
                stopBlackjack();
                blackjack_active = false;
            }
    
            const bool poker_requested = memory_ok && menu_current_screen() == SCREEN_POKER;
            if (poker_requested && !poker_active && !turboLoaderActive()) {
                startPoker(game_now_ms);
                poker_active = true;
            } else if (!poker_requested && poker_active) {
                stopPoker();
                poker_active = false;
            }
    
            const bool poker_dice_requested = memory_ok && menu_current_screen() == SCREEN_POKER_DICE;
            if (poker_dice_requested && !poker_dice_active && !turboLoaderActive()) {
                startPokerDice(game_now_ms);
                poker_dice_active = true;
            } else if (!poker_dice_requested && poker_dice_active) {
                stopPokerDice();
                poker_dice_active = false;
            }
    
            const bool pig_requested = memory_ok && menu_current_screen() == SCREEN_PIG;
            if (pig_requested && !pig_active && !turboLoaderActive()) {
                startPig(game_now_ms);
                pig_active = true;
            } else if (!pig_requested && pig_active) {
                stopPig();
                pig_active = false;
            }
    
            const bool brightness_settings_requested =
                memory_ok && menu_current_screen() == SCREEN_BRIGHTNESS;
            if (brightness_settings_requested && !brightness_settings_active) {
                settingsStart(SETTINGS_BRIGHTNESS);
                brightness_settings_active = true;
            } else if (!brightness_settings_requested && brightness_settings_active) {
                settingsStop();
                brightness_settings_active = false;
            }
    
            const bool volume_settings_requested = memory_ok && menu_current_screen() == SCREEN_VOLUME;
            if (volume_settings_requested && !volume_settings_active) {
                settingsStart(SETTINGS_VOLUME);
                volume_settings_active = true;
            } else if (!volume_settings_requested && volume_settings_active) {
                settingsStop();
                volume_settings_active = false;
            }
    
            const bool wifi_settings_requested = memory_ok && menu_current_screen() == SCREEN_WIFI;
            if (wifi_settings_requested && !wifi_settings_active) {
                settingsStart(SETTINGS_WIFI);
                wifi_settings_active = true;
            } else if (!wifi_settings_requested && wifi_settings_active) {
                settingsStop();
                wifi_settings_active = false;
            }
    
            const bool esp_info_requested = memory_ok && menu_current_screen() == SCREEN_ESP_INFO;
            if (esp_info_requested && !esp_info_active) {
                settingsStart(SETTINGS_ESP_INFO);
                esp_info_active = true;
            } else if (!esp_info_requested && esp_info_active) {
                settingsStop();
                esp_info_active = false;
            }
    
    #if RAM_MONITOR_ENABLED
            const bool ram_log_requested = memory_ok && menu_current_screen() == SCREEN_RAM_LOG;
            if (ram_log_requested && !ram_log_active) {
                settingsStart(SETTINGS_RAM_LOG);
                ram_log_active = true;
            } else if (!ram_log_requested && ram_log_active) {
                settingsStop();
                ram_log_active = false;
            }
    #endif
    
            const bool restart_settings_requested =
                memory_ok && menu_current_screen() == SCREEN_RESTART;
            if (restart_settings_requested && !restart_settings_active) {
                settingsStart(SETTINGS_RESTART);
                restart_settings_active = true;
            } else if (!restart_settings_requested && restart_settings_active) {
                settingsStop();
                restart_settings_active = false;
            }
            if (restart_settings_active && settingsRestartRequested()) {
                ESP_LOGI(TAG, "Settings restart confirmed");
                esp_restart();
            }
    
            const bool power_off_settings_requested =
                memory_ok && menu_current_screen() == SCREEN_POWER_OFF;
            if (power_off_settings_requested && !power_off_settings_active) {
                settingsStart(SETTINGS_POWER_OFF);
                power_off_settings_active = true;
            } else if (!power_off_settings_requested && power_off_settings_active) {
                settingsStop();
                power_off_settings_active = false;
            }
            if (power_off_settings_active && settingsPowerOffRequested()) {
                const bool slept = enter_light_sleep(panel, &tf_available);
                settingsCancelPowerOffRequest();
                if (slept) {
                    settingsStop();
                    power_off_settings_active = false;
                    menu_home((uint32_t)(xTaskGetTickCount() * portTICK_PERIOD_MS));
                }
            }
    
            const bool game_config_requested = memory_ok && menu_current_screen() == SCREEN_GAME_CONFIG;
            if (game_config_requested && !game_config_active) {
                startGameConfig(now_ms);
                game_config_active = true;
            } else if (!game_config_requested && game_config_active) {
                stopGameConfig();
                game_config_active = false;
            }
    
            const bool font_test_requested = memory_ok && menu_current_screen() == SCREEN_FONT_TEST;
            if (font_test_requested && !font_test_active) {
                startFontTest();
                font_test_active = true;
            } else if (!font_test_requested && font_test_active) {
                stopFontTest();
                font_test_active = false;
            }
    
            const bool matrix_requested = memory_ok && menu_current_screen() == SCREEN_MATRIX;
            if (matrix_requested && !matrix_active) {
                startMatrix(now_ms);
                matrix_active = true;
            } else if (!matrix_requested && matrix_active) {
                stopMatrix();
                matrix_active = false;
            }
    
            const bool boing_ball_requested = memory_ok && menu_current_screen() == SCREEN_BOING_BALL;
            if (boing_ball_requested && !boing_ball_active) {
                startBoingBall(now_ms);
                boing_ball_active = true;
            } else if (!boing_ball_requested && boing_ball_active) {
                stopBoingBall();
                boing_ball_active = false;
            }
    
            // The main-menu DEMO entry presents the current Demo visual module.
            // Keep SCREEN_ABOUT as the route so Back returns to the main menu.
            const bool demo_requested = memory_ok && menu_current_screen() == SCREEN_ABOUT;
            if (demo_requested && !demo_active) {
                startDemo(now_ms);
                demo_active = true;
            } else if (!demo_requested && demo_active) {
                stopDemo();
                demo_active = false;
            }
    
            const bool simon_requested = memory_ok && menu_current_screen() == SCREEN_SIMON;
            if (simon_requested && !simon_active && !turboLoaderActive()) {
                startSimon(now_ms);
                simon_active = true;
            } else if (!simon_requested && simon_active) {
                stopSimon();
                simon_active = false;
            }
    
            const bool calculator_requested = memory_ok && menu_current_screen() == SCREEN_CALCULATOR;
            if (calculator_requested && !calculator_active) {
                startCalculator(now_ms);
                calculator_active = true;
            } else if (!calculator_requested && calculator_active) {
                stopCalculator();
                calculator_active = false;
            }
    
            const bool kaleidoscope_requested =
                memory_ok && menu_current_screen() == SCREEN_KALEIDOSCOPE;
            if (kaleidoscope_requested && !kaleidoscope_active) {
                startKaleidoscope(now_ms);
                kaleidoscope_active = true;
            } else if (!kaleidoscope_requested && kaleidoscope_active) {
                stopKaleidoscope();
                kaleidoscope_active = false;
            }
    
            const bool warp_tunnel_requested =
                memory_ok && menu_current_screen() == SCREEN_WARP_TUNNEL;
            if (warp_tunnel_requested && !warp_tunnel_active) {
                startWarpTunnel(now_ms);
                warp_tunnel_active = true;
            } else if (!warp_tunnel_requested && warp_tunnel_active) {
                stopWarpTunnel();
                warp_tunnel_active = false;
            }
    
            const bool mandelbrot_requested = memory_ok && menu_current_screen() == SCREEN_MANDELBROT;
            if (mandelbrot_requested && !mandelbrot_active) {
                startMandelbrot(now_ms);
                mandelbrot_active = true;
            } else if (!mandelbrot_requested && mandelbrot_active) {
                stopMandelbrot();
                mandelbrot_active = false;
            }
    
            const bool clock_requested = memory_ok && menu_current_screen() == SCREEN_CLOCK;
            if (clock_requested && !clock_active) {
                startClock(now_ms);
                clock_active = true;
            } else if (!clock_requested && clock_active) {
                stopClock();
                clock_active = false;
            }
            if (storage_ready) settingsClockAutoSyncUpdate(now_ms);
    
            const bool slideshow_requested = memory_ok && menu_current_screen() == SCREEN_SLIDESHOW;
            if (slideshow_requested && !slideshow_active) {
                startSlideshow(now_ms);
                slideshow_active = true;
            } else if (!slideshow_requested && slideshow_active) {
                stopSlideshow();
                slideshow_active = false;
            }
    
            const bool spiffs_test_requested = memory_ok && menu_current_screen() == SCREEN_SPIFFS_TEST;
            if (spiffs_test_requested && !spiffs_test_active) {
                startSpiffsTest();
                spiffs_test_active = true;
            } else if (!spiffs_test_requested && spiffs_test_active) {
                stopSpiffsTest();
                spiffs_test_active = false;
            }
    
            const bool sound_test_requested = memory_ok && menu_current_screen() == SCREEN_SOUND_TEST;
            if (sound_test_requested && !sound_test_active) {
                startSoundTest();
                sound_test_active = true;
            } else if (!sound_test_requested && sound_test_active) {
                stopSoundTest();
                sound_test_active = false;
            }
    
            const bool sd_card_test_requested = memory_ok && menu_current_screen() == SCREEN_SD_CARD_TEST;
            if (sd_card_test_requested && !sd_card_test_active) {
                startSdCardTest(now_ms);
                sd_card_test_active = true;
            } else if (!sd_card_test_requested && sd_card_test_active) {
                stopSdCardTest();
                sd_card_test_active = false;
            }
    
            const bool hall_of_fame_requested =
                memory_ok && menu_current_screen() == SCREEN_HALL_OF_FAME;
            if (hall_of_fame_requested && !hall_of_fame_active) {
                startHallOfFame(now_ms);
                hall_of_fame_active = true;
            } else if (!hall_of_fame_requested && hall_of_fame_active) {
                stopHallOfFame();
                hall_of_fame_active = false;
            }
    
            const bool asteroids_requested = memory_ok && menu_current_screen() == SCREEN_ASTEROIDS;
            if (asteroids_requested && !asteroids_active && !turboLoaderActive()) {
                startAsteroids(game_now_ms);
                asteroids_active = true;
            } else if (!asteroids_requested && asteroids_active) {
                stopAsteroids();
                asteroids_active = false;
            }
    
            const bool battle_zone_requested = memory_ok && menu_current_screen() == SCREEN_BATTLE_ZONE;
            if (battle_zone_requested && !battle_zone_active && !turboLoaderActive()) {
                startBattleZone(game_now_ms);
                battle_zone_active = true;
            } else if (!battle_zone_requested && battle_zone_active) {
                stopBattleZone();
                battle_zone_active = false;
            }
    
            const bool boulder_dash_requested = memory_ok && menu_current_screen() == SCREEN_BOULDER_DASH;
            if (boulder_dash_requested && !boulder_dash_active && !turboLoaderActive()) {
                startBoulderDash(game_now_ms);
                boulder_dash_active = true;
            } else if (!boulder_dash_requested && boulder_dash_active) {
                stopBoulderDash();
                boulder_dash_active = false;
            }
    
            const bool tempest_requested = memory_ok && menu_current_screen() == SCREEN_TEMPEST;
            if (tempest_requested && !tempest_active && !turboLoaderActive()) {
                startTempest(game_now_ms);
                tempest_active = true;
            } else if (!tempest_requested && tempest_active) {
                stopTempest();
                tempest_active = false;
            }
    
            const bool invaders_requested = memory_ok && menu_current_screen() == SCREEN_INVADERS;
            if (invaders_requested && !invaders_active && !turboLoaderActive()) {
                startInvaders(game_now_ms);
                invaders_active = true;
            } else if (!invaders_requested && invaders_active) {
                stopInvaders();
                invaders_active = false;
            }
    
            const bool missile_command_requested =
                memory_ok && menu_current_screen() == SCREEN_MISSILE_COMMAND;
            if (missile_command_requested && !missile_command_active && !turboLoaderActive()) {
                startMissileCommand(game_now_ms);
                missile_command_active = true;
            } else if (!missile_command_requested && missile_command_active) {
                stopMissileCommand();
                missile_command_active = false;
            }
    
            const bool breakout_requested = memory_ok && menu_current_screen() == SCREEN_BREAKOUT;
            if (breakout_requested && !breakout_active && !turboLoaderActive()) {
                startBreakout(game_now_ms);
                breakout_active = true;
            } else if (!breakout_requested && breakout_active) {
                stopBreakout();
                breakout_active = false;
            }
    
            const bool crawler_requested = memory_ok && menu_current_screen() == SCREEN_CRAWLER;
            if (crawler_requested && !crawler_active && !turboLoaderActive()) {
                startCrawler(game_now_ms);
                crawler_active = true;
            } else if (!crawler_requested && crawler_active) {
                stopCrawler();
                crawler_active = false;
            }
    
            const bool maze_chase_requested = memory_ok && menu_current_screen() == SCREEN_MAZE_CHASE;
            if (maze_chase_requested && !maze_chase_active && !turboLoaderActive()) {
                startMazeChase(game_now_ms);
                maze_chase_active = true;
            } else if (!maze_chase_requested && maze_chase_active) {
                stopMazeChase();
                maze_chase_active = false;
            }
    
            const bool scramble_requested = memory_ok && menu_current_screen() == SCREEN_SCRAMBLE;
            if (scramble_requested && !scramble_active && !turboLoaderActive()) {
                startScramble(game_now_ms);
                scramble_active = true;
            } else if (!scramble_requested && scramble_active) {
                stopScramble();
                scramble_active = false;
            }
    
            const bool defender_requested = memory_ok && menu_current_screen() == SCREEN_DEFENDER;
            if (defender_requested && !defender_active && !turboLoaderActive()) {
                startDefender(game_now_ms);
                defender_active = true;
            } else if (!defender_requested && defender_active) {
                stopDefender();
                defender_active = false;
            }
    
            const bool galaga_requested = memory_ok && menu_current_screen() == SCREEN_GALAGA;
            if (galaga_requested && !galaga_active && !turboLoaderActive()) {
                startGalaga(game_now_ms);
                galaga_active = true;
            } else if (!galaga_requested && galaga_active) {
                stopGalaga();
                galaga_active = false;
            }
    
            const bool dungeon_requested = memory_ok && menu_current_screen() == SCREEN_DUNGEON;
            if (dungeon_requested && !dungeon_active && !turboLoaderActive()) {
                startDungeon(game_now_ms);
                dungeon_active = true;
            } else if (!dungeon_requested && dungeon_active) {
                stopDungeon(game_now_ms);
                dungeon_active = false;
            }
    
            if ((now - last_controller_refresh) >= pdMS_TO_TICKS(CONTROLLER_REFRESH_MS)) {
                last_controller_refresh = now;
                const esp_err_t live_result = controller_input_read(&live_joystick);
                joystick_valid = live_result == ESP_OK;
                if (!joystick_valid && previous_joystick_valid) {
                    ESP_LOGE(TAG, "Live joystick read failed: %s", esp_err_to_name(live_result));
                } else if (joystick_valid && !previous_joystick_valid) {
                    ESP_LOGI(TAG, "Live joystick readings recovered");
                }
                const bool validity_changed = joystick_valid != previous_joystick_valid;
                previous_joystick_valid = joystick_valid;
                joystick_validity_changed = joystick_validity_changed || validity_changed;
                batt_update(now_ms);
    
                // An active module owns input; menu idle timeouts must not end a paused module.
                if (!app_active) {
                    if (!menu_update_buttons(left_held, right_held, now_ms)) {
                        menu_update_joystick(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                             live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                             joystick_valid, now_ms);
                    }
                    menu_update(now_ms);
                }
            }
    
            // Keep input at 20 ms, but render independently at a 60 fps target.
            // One task remains the sole owner of the framebuffer and LCD transfer.
            menu_redraw_pending = menu_redraw_pending || menu_take_redraw();
            if ((now - last_render_refresh) >= pdMS_TO_TICKS(RENDER_REFRESH_MS)) {
                last_render_refresh = now;
                const bool menu_redraw = menu_redraw_pending;
                const bool validity_changed = joystick_validity_changed;
                menu_redraw_pending = false;
                joystick_validity_changed = false;
    
                if (memory_ok) {
                    if (turboLoaderActive()) {
                        drawTurboLoader(frame, now_ms);
                        draw_frame(panel, frame);
                    } else if (game_paused) {
                        if (pause_redraw || now_ms - pause_color_changed_ms >= 500U) {
                            pause_color_index = pause_redraw ? 0 :
                                (pause_color_index + 1U) % (sizeof(pause_colors) / sizeof(pause_colors[0]));
                            // Repaint only the same letter pixels; leave the frozen scene visible.
                            drawPet2001TextCentredTransparent(frame, 160, 78, "PAUSED",
                                                               pause_colors[pause_color_index], 2);
                            draw_frame(panel, frame);
                            pause_color_changed_ms = now_ms;
                            pause_redraw = false;
                        }
                    } else if (checkers_active) {
                        updateCheckers(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                       live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                       joystick_valid, left_held, right_held, game_now_ms);
                        drawCheckers(frame);
                        draw_frame(panel, frame);
                    } else if (othello_active) {
                        updateOthello(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                      live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                      joystick_valid, left_held, right_held, game_now_ms);
                        drawOthello(frame);
                        draw_frame(panel, frame);
                    } else if (connect_four_active) {
                        updateConnectFour(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                          live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                          joystick_valid, left_held, right_held, game_now_ms);
                        drawConnectFour(frame);
                        draw_frame(panel, frame);
                    } else if (battleships_active) {
                        updateBattleships(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                          live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                          joystick_valid, left_held, right_held, game_now_ms);
                        drawBattleships(frame);
                        draw_frame(panel, frame);
                    } else if (yahtzee_active) {
                        updateYahtzee(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                      live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                      joystick_valid, left_held, right_held, game_now_ms);
                        drawYahtzee(frame);
                        draw_frame(panel, frame);
                    } else if (blackjack_active) {
                        updateBlackjack(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                        live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                        joystick_valid, left_held, right_held, game_now_ms);
                        drawBlackjack(frame);
                        draw_frame(panel, frame);
                    } else if (poker_active) {
                        updatePoker(frame, live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                    live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                    joystick_valid, left_held, right_held, game_now_ms);
                        drawPoker(frame);
                        draw_frame(panel, frame);
                    } else if (poker_dice_active) {
                        updatePokerDice(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                        live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                        joystick_valid, left_held, right_held, game_now_ms);
                        drawPokerDice(frame);
                        draw_frame(panel, frame);
                    } else if (pig_active) {
                        updatePig(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                  live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                  joystick_valid, left_held, right_held, game_now_ms);
                        drawPig(frame);
                        draw_frame(panel, frame);
                    } else if (brightness_settings_active) {
                        settingsUpdate(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                       live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid,
                                       left_held, right_held, now_ms);
                        set_backlight_brightness(settingsBrightness());
                        settingsDraw(frame);
                        draw_frame(panel, frame);
                    } else if (volume_settings_active) {
                        settingsUpdate(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                       live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid,
                                       left_held, right_held, now_ms);
                        settingsDraw(frame);
                        draw_frame(panel, frame);
                    } else if (wifi_settings_active) {
                        settingsUpdate(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                       live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid,
                                       left_held, right_held, now_ms);
                        settingsDraw(frame);
                        draw_frame(panel, frame);
                    } else if (esp_info_active) {
                        settingsUpdate(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                       live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid,
                                       left_held, right_held, now_ms);
                        settingsDraw(frame);
                        draw_frame(panel, frame);
                    } else if (ram_log_active) {
                        settingsUpdate(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                       live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid,
                                       left_held, right_held, now_ms);
                        settingsDraw(frame);
                        draw_frame(panel, frame);
                    } else if (restart_settings_active) {
                        settingsUpdate(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                       live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid,
                                       left_held, right_held, now_ms);
                        settingsDraw(frame);
                        draw_frame(panel, frame);
                    } else if (power_off_settings_active) {
                        settingsUpdate(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                       live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid,
                                       left_held, right_held, now_ms);
                        settingsDraw(frame);
                        draw_frame(panel, frame);
                    } else if (game_config_active) {
                        updateGameConfig(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                         live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                         joystick_valid, now_ms);
                        drawGameConfig(frame);
                        draw_frame(panel, frame);
                    } else if (font_test_active) {
                        drawFontTest(frame);
                        draw_frame(panel, frame);
                    } else if (about_active) {
                        updateAbout(now_ms);
                        drawAbout(frame);
                        draw_frame(panel, frame);
                    } else if (matrix_active) {
                        updateMatrix(now_ms);
                        if (matrixTakeFrame()) {
                            drawMatrix(frame);
                            draw_frame(panel, frame);
                        }
                    } else if (boing_ball_active) {
                        updateBoingBall(now_ms);
                        drawBoingBall(frame);
                        draw_frame(panel, frame);
                    } else if (demo_active) {
                        updateDemo(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                   live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                   joystick_valid, now_ms);
                        drawDemo(frame);
                        draw_frame(panel, frame);
                    } else if (simon_active) {
                        updateSimon(now_ms);
                        drawSimon(frame);
                        draw_frame(panel, frame);
                    } else if (calculator_active) {
                        updateCalculator(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                         live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                         joystick_valid, now_ms);
                        drawCalculator(frame);
                        draw_frame(panel, frame);
                    } else if (kaleidoscope_active) {
                        updateKaleidoscope(now_ms);
                        drawKaleidoscope(frame);
                        draw_frame(panel, frame);
                    } else if (warp_tunnel_active) {
                        updateWarpTunnel(now_ms);
                        drawWarpTunnel(frame);
                        draw_frame(panel, frame);
                    } else if (mandelbrot_active) {
                        updateMandelbrot(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                        live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                        joystick_valid, now_ms);
                        if (mandelbrotTakeFrame()) {
                            drawMandelbrot(frame);
                            draw_frame(panel, frame);
                        }
                    } else if (clock_active) {
                        updateClock(now_ms);
                        if (clockTakeFrame()) {
                            drawClock(frame);
                            draw_frame(panel, frame);
                        }
                    } else if (slideshow_active) {
                        updateSlideshow(frame, now_ms);
                        drawSlideshow(frame);
                        draw_frame(panel, frame);
                    } else if (spiffs_test_active) {
                        drawSpiffsTest(frame);
                        draw_frame(panel, frame);
                    } else if (sound_test_active) {
                        drawSoundTest(frame);
                        draw_frame(panel, frame);
                    } else if (sd_card_test_active) {
                        updateSdCardTest(frame, live_joystick.y_raw - JOYSTICK_CENTRE_Y, joystick_valid, now_ms);
                        drawSdCardTest(frame);
                        draw_frame(panel, frame);
                    } else if (asteroids_active) {
                        updateAsteroids(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                        live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                        joystick_valid, left_held, right_held,
                                        stable_shield_levels[0] == 0, game_now_ms);
                        drawAsteroids(frame);
                        draw_frame(panel, frame);
                    } else if (battle_zone_active) {
                        updateBattleZone(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                         live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                         joystick_valid, left_held, right_held,
                                         stable_shield_levels[0] == 0, game_now_ms);
                        drawBattleZone(frame);
                        draw_frame(panel, frame);
                    } else if (boulder_dash_active) {
                        updateBoulderDash(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                          live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                          joystick_valid, left_held, right_held,
                                          stable_shield_levels[0] == 0, game_now_ms);
                        drawBoulderDash(frame);
                        draw_frame(panel, frame);
                    } else if (tempest_active) {
                        updateTempest(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                      live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                      joystick_valid, left_held, right_held,
                                      stable_shield_levels[0] == 0, game_now_ms);
                        drawTempest(frame);
                        draw_frame(panel, frame);
                    } else if (invaders_active) {
                        updateInvaders(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                       live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                       joystick_valid, left_held, right_held,
                                       stable_shield_levels[0] == 0, game_now_ms);
                        drawInvaders(frame);
                        draw_frame(panel, frame);
                    } else if (missile_command_active) {
                        updateMissileCommand(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                             live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                             joystick_valid, left_held,
                                             stable_shield_levels[0] == 0, right_held, game_now_ms);
                        drawMissileCommand(frame);
                        draw_frame(panel, frame);
                    } else if (breakout_active) {
                        updateBreakout(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                       live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                       joystick_valid, left_held, right_held, game_now_ms);
                        drawBreakout(frame);
                        draw_frame(panel, frame);
                    } else if (crawler_active) {
                        updateCrawler(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                      live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                      joystick_valid, left_held, right_held, game_now_ms);
                        drawCrawler(frame);
                        draw_frame(panel, frame);
                    } else if (maze_chase_active) {
                        updateMazeChase(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                        live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                        joystick_valid, left_held, right_held, game_now_ms);
                        drawMazeChase(frame);
                        draw_frame(panel, frame);
                    } else if (scramble_active) {
                        updateScramble(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                       live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                       joystick_valid, stable_shield_levels[0] == 0,
                                       stable_shield_levels[1] == 0, game_now_ms);
                        drawScramble(frame);
                        draw_frame(panel, frame);
                    } else if (defender_active) {
                        updateDefender(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                       live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                       joystick_valid, stable_shield_levels[0] == 0,
                                       stable_shield_levels[1] == 0, game_now_ms);
                        drawDefender(frame);
                        draw_frame(panel, frame);
                    } else if (galaga_active) {
                        updateGalaga(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                     live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                     joystick_valid, stable_shield_levels[0] == 0, game_now_ms);
                        drawGalaga(frame);
                        draw_frame(panel, frame);
                    } else if (dungeon_active) {
                        updateDungeon(frame,
                                      live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                      live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                      joystick_valid, game_now_ms);
                        drawDungeon(frame);
                        draw_frame(panel, frame);
                    } else if (hall_of_fame_active) {
                        updateHallOfFame(live_joystick.x_raw - JOYSTICK_CENTRE_X,
                                         live_joystick.y_raw - JOYSTICK_CENTRE_Y,
                                         joystick_valid, left_held, right_held, now_ms);
                        drawHallOfFame(frame);
                        draw_frame(panel, frame);
                    } else if (menu_current_screen() == SCREEN_CONTROLLER_TEST) {
                        draw_controller_view(frame, &live_joystick, joystick_valid,
                                             stable_shield_levels);
                        draw_frame(panel, frame);
                    } else if (menu_current_screen() == SCREEN_GRAPHICS_TEST) {
                        if (menu_redraw) {
                            fill_color_bars(frame);
                            draw_frame(panel, frame);
                        }
                    } else if (menu_current_screen() == SCREEN_BATTERY) {
                        draw_battery_view(frame);
                        draw_frame(panel, frame);
                    } else if (menu_redraw || validity_changed) {
                        draw_menu_view(frame, joystick_valid);
                        draw_frame(panel, frame);
                    }
                }
            }
    
            // With the 1 kHz FreeRTOS tick, yield briefly without quantising a
            // 16 ms render cadence onto the old 10 ms scheduler boundaries.
            vTaskDelay(pdMS_TO_TICKS(1));
        }
    }