menu "ESPresso Frame Configuration"

    config FRAME_BOARD_NAME
        string "Board variant name, reported to the server"
        default "devkit"
        help
            Sent as the X-Frame-Board request header on every
            GET /frame/config poll, so the server can learn which board
            this device is and automatically fetch the right OTA build
            from a configured Gitea repo's releases -- no manual "which
            board" picker in the web UI. Must match one of the asset
            names .gitea/workflows/firmware-release-build.yml publishes
            (firmware-<name>.bin): "devkit" (this default, for the
            plain ESP32-C6-DevKitC-1 build) or "xiao" (set via
            sdkconfig.xiao for the Seeed XIAO ESP32-C6 build -- see
            build_for_board.sh).

    config FRAME_XIAO_ANTENNA_INIT
        bool "Select onboard antenna on Seeed XIAO ESP32-C6 (RF switch init)"
        default n
        help
            The XIAO ESP32-C6 routes its antenna through an FM8625H RF
            switch (GPIO3 = switch power enable, GPIO14 = antenna
            select) so it can optionally use an external u.FL antenna
            instead of the onboard ceramic one. Seeed's own Arduino
            board package powers the switch and selects the onboard
            antenna automatically at boot; plain ESP-IDF (what this
            firmware uses) does not -- without this, the switch's
            GPIOs are left floating and the radio may not reliably
            reach the onboard antenna at all. Symptom: a softAP (or
            STA connection) that starts successfully in the log but
            is never actually visible/reachable over the air. Enabled
            by default in sdkconfig.xiao; leave off for the DevKitC-1
            dev board, which has no such switch.

    config ESP_AP_SSID
        string "Provisioning softAP SSID prefix"
        default "ESPRESSO"
        help
            SSID prefix of the softAP the device brings up when it needs
            provisioning; the device appends "_XXXXXX" (last 3 bytes of its
            WiFi MAC) so multiple frames never collide on the same SSID.
            The password is generated randomly per device on first boot and
            shown on the e-ink panel both as a WiFi-join QR code and as
            plaintext underneath it, so it can be typed in by hand on a
            desktop/laptop that can't scan the QR.

    config ESP_MAX_STA_CONN
        int "Maximal STA connections"
        default 4
        range 1 4 if IDF_TARGET_ESP32C2
        range 1 15
        help
            Maximum number of STAs allowed to connect to the soft-AP (wifi_config_t.ap.max_connection).
            Upper bound matches ESP_WIFI_MAX_CONN_NUM in esp_wifi_types_native.h:
            1-4 on ESP32-C2, 1-15 on other Wi-Fi chips.
            Soft-AP and ESP-NOW share encryption keys; see Wi-Fi driver documentation
            if ESP-NOW is enabled.

    config ESP_ENABLE_DHCP_CAPTIVEPORTAL
        bool "DHCP Captive portal"
        default y
        help
            Enables more modern DHCP-based Option 114 to provide clients with the captive portal URI

    config FRAME_STA_CONNECT_MAX_RETRIES
        int "Home WiFi connect max retries before falling back to provisioning"
        default 3
        help
            Number of failed connection attempts to the stored home WiFi network
            before the device gives up and re-enters provisioning (softAP) mode.

    config FRAME_STA_CONNECT_TIMEOUT_MS
        int "Home WiFi connect timeout per attempt (ms)"
        default 15000
        help
            How long to wait for an IP address on each connection attempt to the
            stored home WiFi network before counting it as a failed retry.

    config FRAME_SERVER_CHECK_TIMEOUT_MS
        int "Tools server /frame/config request timeout (ms)"
        default 3000
        help
            How long to wait for a GET /frame/config response from the
            tools server -- doubles as both the reachability check for the
            post-connect status screen and the source of the
            server-configured refresh interval below.

    config FRAME_FETCH_TIMEOUT_MS
        int "Image fetch HTTP timeout (ms)"
        default 15000
        help
            How long to wait on the GET /frame/image request before giving
            up. The server does real work per request (Immich download +
            resize + dither), so this is longer than the reachability
            check's timeout.

    config FRAME_SLEEP_INTERVAL_S
        int "Fallback deep sleep interval between refreshes (seconds)"
        default 3600
        help
            The refresh interval is normally set server-side (the "Refresh
            interval" field in the server's web UI, delivered via GET
            /frame/config) so it can be changed without reflashing. This
            value is only a fallback: used before the device has ever
            successfully reached a configured server, or if the server's
            response doesn't include a valid interval (e.g. an older
            server version). Lower this for bench testing so you don't
            have to wait an hour per iteration.

    config FRAME_RETRY_INTERVAL_S
        int "Deep sleep interval after a failed cycle (seconds)"
        default 300
        help
            How long the device deep-sleeps before retrying after the
            server was unreachable or the fetch/display failed, instead of
            waiting the full FRAME_SLEEP_INTERVAL_S.

    config FRAME_NEXT_BUTTON_GPIO
        int "Next-photo button GPIO (-1 to disable)"
        default 2
        range -1 7
        help
            Button wired between this GPIO and GND (active-low, internal
            pull-up enabled in firmware -- no external resistor needed).
            Pressing it wakes the device (if asleep), forces the server to
            advance to the next photo immediately (POST /frame/advance)
            regardless of the configured refresh interval, and displays
            it. Must be GPIO 0-7 -- the only pins the ESP32-C6 can use as
            a deep-sleep GPIO wakeup source, which is what lets a press
            wake the device promptly instead of only being noticed during
            its brief awake windows. Set to -1 to disable the feature.

    config FRAME_BACK_BUTTON_GPIO
        int "Back-photo button GPIO (-1 to disable)"
        default 0
        range -1 7
        help
            Button wired between this GPIO and GND (active-low, internal
            pull-up enabled in firmware -- no external resistor needed).
            Pressing it wakes the device (if asleep), forces the server
            to return to the previously-current photo immediately
            (POST /frame/back), and displays it. Pressing next
            afterwards returns to where you were before pressing back.
            Must be GPIO 0-7 for the same deep-sleep-wakeup reason as
            FRAME_NEXT_BUTTON_GPIO above; defaults to a different pin
            than the other buttons. Set to -1 to disable the feature.

    config FRAME_COMBO_BUTTON_GPIO
        int "Menu/reset button GPIO (-1 to disable)"
        default 1
        range -1 7
        help
            Button wired between this GPIO and GND (active-low, internal
            pull-up enabled in firmware -- no external resistor needed).
            One pin, three actions depending on how long it's held:
            a quick press shows the management menu (same as before);
            holding it FRAME_COMBO_SOFT_RESET_HOLD_MS then releasing
            soft-resets the device (reboots, keeps the stored WiFi/
            server config); holding it all the way to
            FRAME_COMBO_FACTORY_RESET_HOLD_MS clears the stored config
            and restarts into provisioning, regardless of whether it's
            released yet. Must be GPIO 0-7 for the same deep-sleep-
            wakeup reason as FRAME_NEXT_BUTTON_GPIO above; defaults to
            a different pin than the other buttons. Set to -1 to
            disable the feature entirely (also disables the management
            menu, both reset tiers, and factory-reset-via-button --
            reconfiguring then only works by erasing NVS over USB, see
            firmware/README.md).

    config FRAME_COMBO_SOFT_RESET_HOLD_MS
        int "Soft-reset hold duration (ms)"
        default 3000
        depends on FRAME_COMBO_BUTTON_GPIO >= 0
        help
            How long the menu/reset button must be held before releasing
            it triggers a soft reset (reboot, config kept). Long enough
            to be clearly distinct from a quick menu-opening press.

    config FRAME_COMBO_FACTORY_RESET_HOLD_MS
        int "Factory-reset hold duration (ms)"
        default 15000
        depends on FRAME_COMBO_BUTTON_GPIO >= 0
        help
            How long the menu/reset button must be held continuously
            before the device clears its stored config and reboots into
            provisioning, regardless of release. Comfortably longer than
            FRAME_COMBO_SOFT_RESET_HOLD_MS so the two tiers can't be
            confused for each other.

    config FRAME_BATTERY_ADC_GPIO
        int "Battery voltage-divider ADC GPIO (-1 to disable)"
        default -1
        range -1 6
        help
            GPIO wired to the midpoint of a 2x200k voltage divider from
            BAT+ to GND (halving the battery voltage into ADC range --
            the wiring Seeed documents for the XIAO ESP32-C6's A0).
            Must be GPIO 0-6, the ESP32-C6's only ADC-capable pins. The
            settled XIAO design shares this with the back button's pin
            (0): a high-impedance divider coexists fine with the
            button's pull-up and deep-sleep wake, and the firmware
            time-shares the pin (brief ADC read once per wake, restored
            to button duty right after). -1 (the default) disables
            battery reporting entirely -- correct for boards with no
            battery wired, like the DevKitC-1 dev board.

    config FRAME_VBUS_SENSE_GPIO
        int "USB-power (VBUS) sense GPIO (-1 to disable)"
        default -1
        range -1 23
        depends on FRAME_BATTERY_ADC_GPIO >= 0
        help
            GPIO wired to the midpoint of a 2x100k divider from the 5V
            pin (which only carries voltage when USB is plugged in --
            it's dead on battery power) -- a plain digital high/low
            "on mains" signal, no ADC needed. The divider is required:
            raw 5V exceeds the 3.3V pin limit. When on mains, the
            battery indicator is hidden and no battery report is sent
            (the charging voltage would read misleadingly full). -1
            disables mains detection -- the indicator then shows
            whenever the battery reading is plausible.

endmenu
