# SPDX-License-Identifier: Apache-2.0 source "$(ZEPHYR_BASE)/Kconfig.zephyr" # DT-driven PSRAM auto-enable for ESP32 boards (see Kconfig.psram). rsource "Kconfig.psram" module = ZEPHCORE_MAIN module-str = zephcore_main source "$(ZEPHYR_BASE)/subsys/logging/Kconfig.template.log_config" module = ZEPHCORE_BLE module-str = zephcore_ble source "$(ZEPHYR_BASE)/subsys/logging/Kconfig.template.log_config" module = ZEPHCORE_LORA module-str = zephcore_lora source "$(ZEPHYR_BASE)/subsys/logging/Kconfig.template.log_config" module = ZEPHCORE_BOARD module-str = zephcore_board source "$(ZEPHYR_BASE)/subsys/logging/Kconfig.template.log_config" module = ZEPHCORE_DATASTORE module-str = zephcore_datastore source "$(ZEPHYR_BASE)/subsys/logging/Kconfig.template.log_config" module = ZEPHCORE_GPS module-str = zephcore_gps source "$(ZEPHYR_BASE)/subsys/logging/Kconfig.template.log_config" module = ZEPHCORE_SENSORS module-str = zephcore_sensors source "$(ZEPHYR_BASE)/subsys/logging/Kconfig.template.log_config" module = ZEPHCORE_USB module-str = zephcore_usb source "$(ZEPHYR_BASE)/subsys/logging/Kconfig.template.log_config" module = ZEPHCORE_UI_ACTIONS module-str = zephcore_ui_actions source "$(ZEPHYR_BASE)/subsys/logging/Kconfig.template.log_config" module = ZEPHCORE_WIFI_OTA module-str = zephcore_wifi_ota source "$(ZEPHYR_BASE)/subsys/logging/Kconfig.template.log_config" module = ZEPHCORE_OBSERVER module-str = zephcore_observer source "$(ZEPHYR_BASE)/subsys/logging/Kconfig.template.log_config" menu "ZephCore" config ZEPHCORE_RESET_ON_FATAL_ERROR bool "Reboot on fatal error" default y help Cold-reboot instead of halting when a fatal error occurs (CPU exception, stack overflow, k_panic, kernel oops). Production default; turn it off (boards/common/debug.conf does) so a debugger can inspect the halted core. Implemented via a k_sys_fatal_error_handler() override in helpers/fatal_reboot.c — Zephyr has no built-in Kconfig for this. menu "Device Role" choice ZEPHCORE_ROLE prompt "Device Role" default ZEPHCORE_ROLE_COMPANION help Select the device role. Companion devices connect to mobile apps via BLE. Repeaters forward packets and are configured via USB serial CLI. config ZEPHCORE_ROLE_COMPANION bool "Companion Device" help BLE companion device that connects to ZephCore mobile app. Includes BLE stack, contact management, offline queue, channels. config ZEPHCORE_ROLE_REPEATER bool "Repeater" help LoRa mesh repeater with USB serial CLI interface. No BLE stack. Has ACL authentication, region filtering, neighbor tracking, and full CLI command set. config ZEPHCORE_ROLE_OBSERVER bool "Observer (listen-only, WiFi+MQTT)" help ESP32-only listen-only node. Receives LoRa packets without forwarding. Connects to WiFi (STA mode) and publishes received packets to an MQTT broker in meshcoretomqtt-compatible format. All parameters (WiFi SSID/PSK, MQTT host/port/TLS/user/pass, IATA location code) are configured at runtime via serial CLI and stored in LittleFS. No BLE, no advertising, no routing. config ZEPHCORE_ROLE_ROOM_SERVER bool "Room Server (shared BBS, USB serial CLI)" help Store-and-forward shared message room (a "BBS"). Clients log in with an admin or guest password and post messages; the server pushes each new post to all other logged-in clients and tracks a per-client sync cursor. No BLE — configured via USB serial CLI. Reuses the repeater's ACL, region filtering and CLI command set. endchoice config ZEPHCORE_COMPANION_USB bool "Enable USB CDC companion transport" depends on USB_DEVICE_STACK_NEXT default y if ZEPHCORE_ROLE_COMPANION help Compile and init the USB CDC-ACM companion protocol stack (ZephyrCompanionUSB / ZephyrUSBCDC) independently of CONFIG_LOG. The full ~60-opcode binary protocol is available over USB even in production builds (CONFIG_LOG=n). USB and BLE arbitrate the active interface first-come-first-served: CMD_APP_START claims it for USB only if no BLE session is already active (and is ignored while BLE is live); on USB unplug the interface is handed back to BLE or released to idle. Enabled by default for all companion builds on platforms that already have CONFIG_USB_DEVICE_STACK_NEXT=y (all nRF52840 boards). On platforms without USB hardware (MG24, ESP32 classic, C3/C6) the depends forces this to n automatically — no conf change needed. For ESP32-S3 boards, USB_DEVICE_STACK_NEXT must be enabled first via boards/common/esp32s3_usb.conf before this becomes active. if ZEPHCORE_ROLE_REPEATER || ZEPHCORE_ROLE_ROOM_SERVER config ZEPHCORE_REPEATER_UPLINK bool "Enable repeater WiFi+MQTT uplink" depends on ZEPHCORE_ROLE_REPEATER && SOC_FAMILY_ESPRESSIF_ESP32 default n help Adds observer-style WiFi station and MQTT packet publishing to repeater builds. Configuration is stored in LittleFS and applied on reboot. config ZEPHCORE_MAX_CLIENTS int "Maximum ACL clients" default 32 help Maximum clients in the Access Control List. Each client stores pubkey, permissions, and shared secret. config ZEPHCORE_MAX_NEIGHBOURS int "Maximum tracked neighbors" default 16 help Maximum number of neighboring repeaters to track. Set to 0 to disable neighbor tracking. config ZEPHCORE_MAX_REGION_ENTRIES int "Maximum region entries" default 32 help Maximum entries in the region map for flood filtering. Regions control which transport codes are allowed to flood. config ZEPHCORE_ADMIN_PASSWORD string "Default admin password" default "password" help Default password for admin access to the repeater. Should be changed on first configuration! config ZEPHCORE_GUEST_PASSWORD string "Default guest password" default "" help Default password for guest access. Empty string disables guest access. config ZEPHCORE_MAX_UNSYNCED_POSTS int "Room server: max buffered posts" default 32 depends on ZEPHCORE_ROLE_ROOM_SERVER help Size of the room server's circular post buffer. When full, the oldest unsynced post is overwritten. Matches upstream MeshCore (32). endif # ZEPHCORE_ROLE_REPEATER || ZEPHCORE_ROLE_ROOM_SERVER endmenu # Device Role if ZEPHCORE_ROLE_COMPANION config ZEPHCORE_MAX_CONTACTS int "Maximum number of contacts" default 350 help Maximum number of contacts that can be stored. config ZEPHCORE_MAX_CHANNELS int "Maximum number of channels" default 40 help Maximum number of group channels that can be stored. config ZEPHCORE_OFFLINE_QUEUE_SIZE int "Offline message queue size" default 256 help Size of the offline message queue for incoming messages. Arduino MeshCore uses 256 for both T1000-E and Wio Tracker. config ZEPHCORE_ACK_TABLE_SIZE int "ACK tracking table size" default 8 help Number of pending ACKs that can be tracked. config ZEPHCORE_MAX_CONNECTIONS int "Maximum server connections" default 16 help Maximum number of simultaneous room server connections with keep-alive. config ZEPHCORE_ADVERT_PATH_TABLE_SIZE int "Advert path table size" default 16 help Size of recently-heard advert path table. menu "BLE Configuration" config ZEPHCORE_BLE_PASSKEY int "BLE pairing passkey (6 digits)" default 123456 range 0 999999 help Fixed 6-digit passkey for BLE MITM pairing. config ZEPHCORE_BLE_QUEUE_SIZE int "BLE TX/RX message queue depth" default 12 range 4 64 help Number of frames that can be queued for BLE TX/RX. Larger = better buffering for bursty traffic, more RAM. config ZEPHCORE_BLE_CONN_MIN_INTERVAL int "BLE minimum connection interval (units: 1.25ms)" default 12 range 6 3200 help Minimum BLE connection interval in 1.25ms units. 12 = 15ms. Matches Arduino default. Lower = more responsive, higher power. config ZEPHCORE_BLE_CONN_MAX_INTERVAL int "BLE maximum connection interval (units: 1.25ms)" default 36 range 6 3200 help Maximum BLE connection interval in 1.25ms units. 36 = 45ms. Matches Arduino default. Higher = lower power when idle. config ZEPHCORE_BLE_CONN_LATENCY int "BLE connection latency (skip events)" default 4 range 0 500 help Skip up to N connection events when idle to save power. 4 = skip 4 events (effective interval up to 375ms idle). config ZEPHCORE_BLE_CONN_TIMEOUT int "BLE supervision timeout (units: 10ms)" default 500 range 10 3200 help Supervision timeout in 10ms units. 500 = 5000ms. Connection drops if no data for this duration. config ZEPHCORE_BLE_ADV_SLOW_INTERVAL int "BLE advertising interval (units: 0.625ms)" default 338 range 244 3200 help Advertising interval in 0.625ms units. 338 = 211.25ms (Apple-compliant, used after 60s fast window). endmenu # BLE Configuration menu "Linux Companion Transport (native_sim)" config ZEPHCORE_TRANSPORT_TCP bool "Use TCP socket transport instead of BLE NUS" default n help Replaces the ZephyrBLE adapter with LinuxTCPTransport, exposing the companion NUS protocol over a TCP socket on Linux SBC builds (BOARD=native_sim). Auto-enabled by boards/linux_native/linux_common.conf. The wire format is MeshCore's SerialWifiInterface framing: ['<'][len_LSB][len_MSB][NUS payload] app->node and ['>']... node->app. config ZEPHCORE_LINUX_TCP_PORT int "TCP listen port" depends on ZEPHCORE_TRANSPORT_TCP default 5000 range 1 65535 help Port the companion TCP transport binds to. Default 5000 matches the upstream MeshCore Linux companion service so a single mobile app TCP configuration works against both backends. endmenu # Linux Companion Transport endif # ZEPHCORE_ROLE_COMPANION config ZEPHCORE_HOUSEKEEPING_INTERVAL_MS int "Periodic housekeeping interval (ms)" default 5000 range 1000 60000 help Wake interval for noise floor calibration, battery reads, and UI refresh. Longer = lower power, less responsive monitoring. menu "Radio Configuration" choice ZEPHCORE_RADIO_TYPE prompt "LoRa Radio Type" default ZEPHCORE_RADIO_NATIVE help Select the LoRa radio driver. config ZEPHCORE_RADIO_NATIVE bool "Zephyr native LoRa driver (SX126x, SX127x, LLCC68, STM32WL)" help Uses Zephyr's built-in LoRa driver. Supports all radios that Zephyr has device tree bindings for: SX126x: SX1261, SX1262, SX1268 SX127x: SX1272, SX1276, SX1278 LLCC68: Semtech LLCC68 STM32WL: STM32WL SUBGHZ radio (SX126x-based) Used by: RAK4631, Wio Tracker L1, all XIAO + Wio-SX1262 boards config ZEPHCORE_RADIO_LR1110 bool "LR1110/LR1120/LR1121 (custom driver)" select LORA select SPI help Semtech LR11xx via custom ZephCore driver (not upstream Zephyr). Uses SPI mutex for thread safety + BUSY stuck recovery. TCXO, RF switch, and PA config are in the device tree. For any board with an LR1110, LR1120, or LR1121 radio. config ZEPHCORE_RADIO_LR2021 bool "LR2021 (custom driver)" select LORA select SPI help Semtech LR2021 (LoRa Plus, 4th-gen) via custom ZephCore driver. Supports sub-GHz + 2.4 GHz ISM + NTN/SATCOM. TCXO, RF switch, and PA config are in the device tree. config ZEPHCORE_RADIO_SX127X bool "SX127x (SX1272/SX1276/SX1278) via Zephyr loramac-node driver" help Uses Zephyr's loramac-node-based LoRa driver for SX127x radios. Supports SX1272, SX1276, and SX1278 chips via the standard Zephyr LoRa API (lora_config, lora_send_async, lora_recv_async). Chip-specific features not available via standard API are stubbed: - Instantaneous RSSI (hwGetCurrentRSSI returns -80 dBm sentinel) - Preamble detection (always false — TX won't abort mid-preamble) - RX boost (no-op — SX127x has no dedicated boost register) - AGC reset (no-op — loramac-node manages AGC internally) - BUSY pin (false — SX127x has no BUSY signal) Used by: TTGO LoRa32, Heltec LoRa32 V1/V2, and any board with an SX1272/SX1276/SX1278 radio. endchoice config ZEPHCORE_DEFAULT_TX_POWER_DBM int "Default TX power (dBm)" default 22 range -9 22 help Default SX1262 TX power in dBm for fresh devices (no saved prefs). Boards with external PA should set this lower to avoid overdriving. Example: Station G2 with 20dB PA gain uses 15 dBm (→ 35 dBm output). config ZEPHCORE_MAX_TX_POWER_DBM int "Maximum TX power (dBm)" default 22 range -9 22 help Hard cap on SX1262 TX power. The radio adapter clamps any value above this, protecting external PAs from damage. Example: Station G2 caps at 19 dBm to stay below PA P1dB (35 dBm). config ZEPHCORE_SX126X_HELTEC_REG_PATCH bool "Apply undocumented SX126x register 0x8B5 RX improvement (Heltec V4)" depends on ZEPHCORE_RADIO_NATIVE default n help Sets the LSB of undocumented register 0x8B5 after the first lora_config(). Described by Heltec engineer @Quency-D in MeshCore PR#1398 — consistently improves RX reception on boards with GC1109 or KCT8103L PA (Heltec V4/V4.3). Enable in board.conf for Heltec V4 boards. endmenu # Radio Configuration menu "Board Configuration" config ZEPHCORE_BOARD_NAME string "Board name for identification" default "Zephyr Device" help Human-readable board name returned by the 'board' CLI command and reported in device info. Should match Arduino variant names for consistency (e.g., "RAK 4631", "Wio Tracker L1", "T1000-E"). config ZEPHCORE_SD_FWID hex "SoftDevice firmware ID for DFU packages" default 0x00B6 depends on SOC_SERIES_NRF52 help SoftDevice firmware ID used by adafruit-nrfutil when generating DFU zip packages (--sd-req parameter). Must match the SoftDevice version flashed with the Adafruit bootloader on the target device. Only applicable to nRF52 boards with Adafruit bootloader. Common values: 0x00B6 - S140 v6.1.1 (RAK4631, Wio Tracker, T1000-E) 0x0123 - S140 v7.3.0 (XIAO nRF52840, Ikoka Nano) config ZEPHCORE_VBAT_MV_MULTIPLIER int "Battery voltage ADC multiplier (fallback)" default 7200 help Fallback multiplier if vbat-mv-multiplier is not defined in devicetree zephyr,user node. Prefer defining in devicetree alongside ADC channel: zephyr,user { io-channels = <&adc 7>; vbat-mv-multiplier = <7200>; }; Formula: mv = (raw * multiplier) / 4096 endmenu menu "Debug & Logging" config ZEPHCORE_PACKET_LOGGING bool "Enable mesh packet logging" default n depends on LOG help Log all RX and TX mesh packets in Arduino-compatible format. Output format matches Arduino MESH_PACKET_LOGGING exactly: "HH:MM:SS - D/M/YYYY U: RX, len=N (type=N, route=D/F, payload_len=N) SNR=N RSSI=N score=N time=N hash=XXXX [XX -> XX]" config ZEPHCORE_PACKET_LOGGING_ONLY bool "Quiet mode - only packet logs, no debug spam" default n depends on ZEPHCORE_PACKET_LOGGING help When enabled, suppresses all other log messages and only outputs packet logging (RAW, RX, TX lines). Uses printk() to bypass log level filtering. endmenu menu "LoRa Power Saving" config ZEPHCORE_LORA_RX_DUTY_CYCLE bool "Enable LoRa RX duty cycle power saving" default n help Enable RX duty cycling for power saving on battery-powered devices. Uses RadioLib's algorithm to calculate optimal timing based on SF/BW. Disabled by default for all roles. Enable manually if you want power savings and have verified acceptable packet loss/latency for your environment and radio. Duty cycle mode also resets AGC state after every received packet via Calibrate(ALL), preventing the "near-far" gain-lock problem where a strong signal desensitises the receiver. Still disabled for LR1110 (cannot lock on mid-preamble, causes packet loss) and LR2021 (untested — enable manually after verifying no packet loss). Can be toggled at runtime via CLI. The key insight is that LoRa preamble symbols are all identical, so CAD/RX can detect preamble even if we wake mid-stream. The algorithm ensures we always catch at least 8 symbols regardless of when we wake within the preamble window. Power savings: ~60-70% reduction in RX current (10-15mA to 3-5mA). Can be toggled at runtime via CLI "set rxduty on/off". config ZEPHCORE_APC bool "Adaptive Power Control (APC)" default y help Automatically reduce TX power when echo packets from neighbors indicate excess SNR margin. Saves battery and reduces channel congestion. Ramps back to full power within 2 minutes if no echoes are heard. Uses rogue-filtering: clusters echo SNRs to avoid one badly placed high-SNR neighbor from over-reducing power. Compiled in by default; disabled at runtime (enable per-node via CLI "set tx apc" — persisted in prefs). endmenu menu "GPS Configuration" config ZEPHCORE_GPS_POLL_INTERVAL_SEC int "GPS poll interval in seconds" default 300 range 10 86400 help How often to wake GPS and acquire a fix. Default 300 seconds (5 minutes). config ZEPHCORE_GPS_FIX_TIMEOUT_SEC int "GPS fix acquisition timeout in seconds" default 120 range 10 300 help Maximum time to wait for GPS fix before giving up. GPS will be powered off after this timeout. Default 120s — 30s was too aggressive for Air530Z / MAX-7Q warm starts in marginal sky conditions; the acquire loop would time out before the 3-consecutive-good-fix gate could promote. Only applies to wake cycles after the first successful fix since enable. endmenu menu "WiFi OTA Update" config ZEPHCORE_WIFI_OTA bool "WiFi OTA firmware update" depends on ZEPHCORE_ROLE_REPEATER help Enable WiFi AP + HTTP server for OTA firmware updates. Auto-enabled for ESP32 repeater builds via wifi_ota.conf. When "start ota" is issued, starts WiFi AP "ZephCore-OTA" and HTTP server. User uploads firmware via browser at http://192.168.100.1/update. Requires MCUboot (--sysbuild). if ZEPHCORE_WIFI_OTA config ZEPHCORE_OTA_AP_SSID string "WiFi AP SSID for OTA" default "ZephCore-OTA" help SSID of the WiFi access point started for OTA updates. Open network (no password), matching Arduino behavior. config ZEPHCORE_OTA_AP_IP string "WiFi AP static IP address" default "192.168.100.1" help Static IP address assigned to the WiFi AP interface. DHCP server hands out addresses starting at .10. endif # ZEPHCORE_WIFI_OTA endmenu menu "UI Configuration" config ZEPHCORE_UI_BUTTONS bool "Enable button input" default y depends on INPUT help Enable button/joystick input with long-press, double-click, and triple-click detection using Zephyr's native input subsystem. config ZEPHCORE_UI_MULTI_TAP bool "Enable multi-tap input filter" default y depends on ZEPHCORE_UI_BUTTONS help Enable the multi-tap input filter that counts rapid taps within a configurable window and emits different key codes based on tap count. Supports 1-4 tap levels via devicetree. Single-tap has ~400ms latency (waits for window to expire). config ZEPHCORE_UI_BUZZER bool "Enable buzzer" default y if $(dt_nodelabel_enabled,buzzer) select PWM help Enable PWM buzzer with RTTTL melody support. Auto-enabled when a "buzzer" nodelabel exists in devicetree. Pulls in CONFIG_PWM automatically. DT_CHOSEN_ZEPHCORE_DISPLAY := zephyr,display config ZEPHCORE_UI_DISPLAY bool "Enable display (OLED, LCD, e-ink)" default y if $(dt_chosen_enabled,$(DT_CHOSEN_ZEPHCORE_DISPLAY)) select DISPLAY select CHARACTER_FRAMEBUFFER help Enable page-based UI on any Zephyr-supported display. Auto-enabled when "zephyr,display" chosen node exists in DT. Auto-detects display via chosen node or legacy nodelabels (sh1106, ssd1306). Resolution and font are queried at runtime. Supports OLED (SSD1306, SH1106), LCD, e-ink, etc. config ZEPHCORE_UI_DISPLAY_AUTO_OFF_MS int "Display auto-off timeout (ms)" default 10000 depends on ZEPHCORE_UI_DISPLAY help Time in milliseconds before the display turns off after the last user interaction. Set to 0 to disable. config ZEPHCORE_UI_CONFIRM_WINDOW_MS int "Double-press confirmation window (ms)" default 500 depends on ZEPHCORE_UI_DISPLAY help Maximum time between the two KEY_ENTER presses that confirm destructive actions (shutdown, DFU, offgrid toggle). The default 500 ms suits boards where ENTER is a direct short tap. Boards with only one button that emit ENTER via a zephyr,input-longpress filter (T-Echo, RAK4631 Pocket) need a longer window — two 1 s holds plus the release gap do not fit in 500 ms. Set to 3000 on such boards. config ZEPHCORE_DISPLAY_INSET int "Display inset margin (pixels)" default 0 depends on ZEPHCORE_UI_DISPLAY help Shrink the usable drawing area by this many pixels on each side. mc_display_width/height() report the reduced size and all draw primitives are offset by this amount. Useful on panels (e.g. LilyGo T-Echo SSD1681) where the outermost rows/columns show hardware artefacts — a small inset hides them behind a clean background margin. Set to 0 on boards without edge artefacts. config ZEPHCORE_DISPLAY_LARGE_FONT bool "Use a larger built-in CFB font" default n depends on ZEPHCORE_UI_DISPLAY && CHARACTER_FRAMEBUFFER_USE_DEFAULT_FONTS help Select the smallest Zephyr built-in CFB font whose height is >= 16 pixels (typically the 10x16 font). Intended for larger e-paper panels (T-Echo, ThinkNode M1) where the default 6x8 glyph is too small to read comfortably. The ui_pages.c layout auto-centers its content rows using the active font height, so no per-page changes are needed. Requires Zephyr's default CFB fonts to be compiled in (CONFIG_CHARACTER_FRAMEBUFFER_USE_DEFAULT_FONTS). config ZEPHCORE_DISPLAY_MONO_TFT bool "Monochrome TFT wrapper (MONO01 => RGB565)" default y if DT_HAS_ZEPHCORE_MONO_TFT_ENABLED depends on DT_HAS_ZEPHCORE_MONO_TFT_ENABLED help Wraps an RGB TFT (e.g. ST7789V) as a PIXEL_FORMAT_MONO01 display. CFB allocates x*y/8 bytes (~4 KB for 240×135) instead of ~64 KB RGB565, making a colour TFT viable on RAM-constrained devices like the nRF52840. On display_write(), converts 1bpp row-major MONO01 to RGB565 row by row. Auto-enabled when a "zephcore,mono-tft" device exists in the devicetree. config ZEPHCORE_EASTER_EGG_DOOM bool "Enable Doom raycaster easter egg" default n depends on ZEPHCORE_UI_DISPLAY && ZEPHCORE_UI_BUTTONS help Hidden easter egg: Wolf3D-style raycaster on the OLED. Button UI: triple-press ENTER on the Messages page. Joystick UI: open the Tools menu and select "Doom". Press BACK/ESC to exit. Adds ~5KB flash and ~1.7KB RAM when enabled. config ZEPHCORE_UI_JOYSTICK bool help Set by board-level Kconfig when the hardware has a 5-way joystick or D-pad. Not user-selectable; set by the board configuration. Follows the same pattern as ZEPHCORE_UI_BUTTONS and ZEPHCORE_UI_DISPLAY. config ZEPHCORE_UI_DESIGN_BUTTON bool "Button-based page UI" default y if (ZEPHCORE_UI_BUTTONS || ZEPHCORE_UI_DISPLAY || ZEPHCORE_UI_BUZZER) && !ZEPHCORE_UI_DESIGN_JOYSTICK depends on (ZEPHCORE_UI_BUTTONS || ZEPHCORE_UI_DISPLAY || ZEPHCORE_UI_BUZZER) && !ZEPHCORE_UI_DESIGN_JOYSTICK help Compile the default page-based button UI (helpers/ui-button/). Auto-selected when any UI hardware is present and the joystick UI design is not active. Disable to supply a custom ui_task.h implementation without touching this Kconfig. config ZEPHCORE_UI_DESIGN_JOYSTICK bool "Joystick-based companion UI" default y if ZEPHCORE_ROLE_COMPANION && ZEPHCORE_UI_DISPLAY && ZEPHCORE_UI_BUTTONS && ZEPHCORE_UI_JOYSTICK depends on ZEPHCORE_ROLE_COMPANION && ZEPHCORE_UI_DISPLAY && ZEPHCORE_UI_BUTTONS && ZEPHCORE_UI_JOYSTICK help Full joystick-driven companion UI (helpers/ui-joystick/). Provides GPS, contacts, channels, snake game, repeater admin, and all other companion screens via a 5-way joystick or D-pad. Replaces ZEPHCORE_UI_DESIGN_BUTTON for companion builds on boards with joystick hardware. endmenu endmenu