Add LilyGO T-Deck support, CI improvements, and keyboard features#3
Open
3rdIteration wants to merge 22 commits into
Open
Add LilyGO T-Deck support, CI improvements, and keyboard features#33rdIteration wants to merge 22 commits into
3rdIteration wants to merge 22 commits into
Conversation
…loop) Passing explicit flashMode/flashFreq/flashSize makes esptool-js patch the bootloader image header in flash without recomputing the appended SHA-256 digest. The ESP32-S3 ROM verifies that digest when loading the second-stage bootloader, rejects the image (ets_loader.c 78) and the device bootloops. Use 'keep' so the image is written byte-identical to the build output. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
power_backlight_on() scaled brightness as a 0-255 value, but Jade passes levels BACKLIGHT_MIN..BACKLIGHT_MAX (1..5), so the result was always 0 and the backlight switched off as soon as the stored brightness was applied after boot. Clamp and map levels 1..5 linearly onto dimmer steps 1..16. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Drop the pulse-train step dimmer; drive the backlight GPIO high for any requested brightness level and low for off. Level-based dimming can be reinstated once the display path is proven out. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Restore the pulse-step dimmer, mapping Jade brightness levels BACKLIGHT_MIN..BACKLIGHT_MAX (1..5) linearly onto dimmer steps 1..16 (the earlier code scaled as if brightness were 0-255, always yielding 0). Add short delays around the step pulses to respect dimmer timing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The trackball direction lines toggle level once per step of ball travel; driving them through iot_button meant that whenever a line came to rest low the driver saw a held button and fired LONG_PRESS_HOLD forever, causing runaway scrolling until the ball was nudged. Handle all four direction lines with ANYEDGE GPIO interrupts feeding a queue/watcher task (same pattern as the Jade v1 wheel), with a 2ms debounce. Also wire up the previously unused up/down lines: up scrolls prev, down scrolls next, matching forward/back in vertical UI contexts. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…vity Mnemonic word entry only understood the on-screen keyboard: - letters: the screen posts uppercase A-Z, but the T-Deck keyboard sends lowercase ascii, so typed letters were ignored; accept either case - enter: the on-screen enter button is inactive during mnemonic entry, but a physical keyboard can post BTN_KEYBOARD_ENTER at any time, which set done_entering_words early and tripped the words_entered==nwords assert (mnemonic.c:865); only honour enter when the on-screen button would be active - letter validity: the on-screen keyboard disables letters that match no word, a physical keyboard cannot - reject letters yielding a stem with no matching words (previously would trip the possible_words>0 assert) Also halve trackball sensitivity: require 2 edges per scroll step, with the accumulator reset on direction change or a 300ms pause. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add HAS_KEYBOARD config (selected by the T-Deck board) and lay out the on-screen keyboards qwerty to match the physical keys: the mnemonic word-entry keyboard and the upper/lower-case passphrase keyboards. The passphrase space key moves to the end of the middle row as qwerty needs all ten bottom-row columns for zxcvbnm plus the control keys. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Passphrase: replace the show-and-confirm (Yes/No) screen with a second, deliberately blank, keyboard entry titled Confirm Passphrase; the two entries are compared and a mismatch restarts entry from scratch. The old display-confirm activity is removed, and both entry buffers are registered with the sensitive-data stack. PIN/number entry: accept physical keyboard input alongside the wheel. Adds gui_activity_wait_event_of_either_base() so the digit-entry loop can wait on gui navigation and keyboard button events simultaneously. Digits accepted as ascii 0-9 plus the letter keys with digits printed on them on the T-Deck (w,e,r,s,d,f,z,x,c = 1-9); backspace steps back (abandoning entry on the first digit), enter completes index entry. Also log raw keyboard bytes at DEBUG level to identify unmapped keys (eg. the mic key, which carries the printed 0). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The CI shallow/tagless checkout (plus the git dubious-ownership error inside the IDF container) made git describe fail, so JADE_VERSION in get_version_info was "1". Companion apps parse this as semver against a minimum firmware version and refuse to proceed (endless get_version_info retries / "please reconnect your hardware wallet"). Fetch full history and tags, mark the workspace safe for git in the container, and log the version at build time. Also report BOARD_TYPE "TDECK" instead of "UNKNOWN", and simplify PIN entry keys to actual ascii digits only - the T-Deck keyboard sends these with the SYM modifier held, so the letter-alias mapping is unnecessary. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Send the keyboard controller brightness command (0x01 <level>) so the keyboard backlight turns on/off and dims with the screen (levels 1-5 map to 51-255). The request is latched and applied by the keyboard task, which owns the i2c device, retrying until the write succeeds. The Alt+B manual toggle in the keyboard firmware still works. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Average 8 adc samples and use a 2.11 divider multiplier (2.0 nominal plus ~10% load correction, matching other t-deck firmwares) instead of a single noisy sample scaled by 2. - usb/charging detection used tud_mounted(), which is always false on the debug (usb-serial-jtag) build where TinyUSB is never initialised; infer usb connection from usb_serial_jtag_is_connected() there. - Report charging as usb present while below 4300mV - with no charger status line, a higher reading means the charger is holding up the sense node with the battery full. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
handle_display_battery_volts() only formats a reading for a hardcoded set of boards and falls back to "NO BAT" otherwise; add the tdeck (power_get_vbat() already returns divider-corrected millivolts). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This pull request introduces initial support for the LilyGO T-Deck (ESP32-S3) hardware variant, adds physical-keyboard-aware UI behavior, and adds a GitHub Pages–hosted web flasher that consumes CI-produced firmware artifacts.
Changes:
- Added T-Deck as a selectable board type with associated display/input/power configuration, plus new sdkconfig defaults for normal and debug variants.
- Updated UI/input handling to better support physical keyboards (QWERTY on-screen layouts, physical key events for mnemonic/digit entry, and trackball navigation).
- Added a new CI workflow to build and publish T-Deck firmware artifacts, plus a new web flasher UI and bundled JSZip dependency.
Reviewed changes
Copilot reviewed 19 out of 23 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| tools/switch_to.sh | Adds a tdeck target option for local switching/build convenience. |
| main/ui/mnemonic.c | QWERTY on-screen keyboard layout when a physical keyboard is present; removes old passphrase confirm activity UI. |
| main/ui/keyboard.c | Adjusts on-screen keyboard rows to mirror physical keyboard layout under CONFIG_HAS_KEYBOARD. |
| main/ui/digit_entry.c | Adds physical keyboard event handling for digit entry and waits on either GUI or keyboard events. |
| main/ui/dashboard.c | Enables brightness/orientation settings UI for T-Deck builds. |
| main/process/ota_defines.h | Adds OTA board type identifier for T-Deck. |
| main/process/mnemonic.c | Improves physical keyboard handling during word entry; switches passphrase confirmation to blind re-entry with sensitive-buffer guards. |
| main/process/dashboard.c | Enables brightness handling and battery-voltage display path for T-Deck. |
| main/power/tdeck.inc | Implements T-Deck-specific power, backlight, and battery measurement behavior. |
| main/power.c | Wires T-Deck power implementation into the build via board type. |
| main/Kconfig.projbuild | Adds BOARD_TYPE_TDECK and HAS_KEYBOARD, plus T-Deck defaults for many pins/display settings. |
| main/input/tdeck.inc | Adds T-Deck keyboard (I2C) + trackball navigation integration. |
| main/input.c | Selects the T-Deck input implementation when configured. |
| main/gui.h | Declares a new helper to wait on either of two event bases. |
| main/gui.c | Implements gui_activity_wait_event_of_either_base. |
| flasher/vendor/jszip-3.10.1.min.js | Adds JSZip vendor dependency for ZIP artifact parsing in the web flasher. |
| flasher/index.html | Adds a new web flasher UI (CI artifact fetch + ZIP upload + WebSerial flashing + serial monitor). |
| flasher/branding/logo.svg | Adds a simple flasher logo asset. |
| configs/sdkconfig_display_tdeck.defaults | Adds normal T-Deck sdkconfig defaults. |
| configs/sdkconfig_display_tdeck_debug.defaults | Adds debug T-Deck sdkconfig defaults (USB-Serial-JTAG console). |
| .gitignore | Ignores the generated/published flasher/firmware/ directory. |
| .github/workflows/build.yml | Adds CI build + artifact publishing and GitHub Pages deployment for T-Deck firmware/flasher. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+54
to
+56
| deploy: | ||
| if: github.event_name == 'push' | ||
| needs: build |
Comment on lines
+38
to
+43
| mkdir -p firmware-${{ matrix.variant.name }}/bootloader firmware-${{ matrix.variant.name }}/partition_table | ||
| cp build_${{ matrix.variant.name }}/bootloader/bootloader.bin firmware-${{ matrix.variant.name }}/bootloader/ | ||
| cp build_${{ matrix.variant.name }}/partition_table/partition-table.bin firmware-${{ matrix.variant.name }}/partition_table/ | ||
| cp build_${{ matrix.variant.name }}/ota_data_initial.bin firmware-${{ matrix.variant.name }}/ 2>/dev/null || true | ||
| cp build_${{ matrix.variant.name }}/jade.bin firmware-${{ matrix.variant.name }}/ 2>/dev/null || true | ||
| cp build_${{ matrix.variant.name }}/flasher_args.json firmware-${{ matrix.variant.name }}/ 2>/dev/null || true |
Comment on lines
+299
to
+310
| function serialWrite(text) { | ||
| const last = serialDiv.lastChild; | ||
| if (last && last.nodeType === Node.TEXT_NODE) { | ||
| last.textContent += text; | ||
| } else { | ||
| serialDiv.appendChild(document.createTextNode(text)); | ||
| } | ||
| serialDiv.scrollTop = serialDiv.scrollHeight; | ||
| if (serialDiv.children.length > 500) { | ||
| serialDiv.removeChild(serialDiv.firstChild); | ||
| } | ||
| } |
Comment on lines
+559
to
+576
| const totalBytes = layout.reduce((s, e) => s + e.data.length, 0); | ||
| let writtenBytes = 0; | ||
|
|
||
| const progressFill = document.getElementById('progressFill'); | ||
| document.getElementById('progressSection').style.display = 'block'; | ||
|
|
||
| await esploader.writeFlash({ | ||
| fileArray: layout.map(e => ({ data: e.data, address: e.address })), | ||
| flashMode: b.flashMode, | ||
| flashFreq: b.flashFreq, | ||
| flashSize: b.flashSize, | ||
| eraseAll: false, | ||
| compress: true, | ||
| reportProgress: (fileIndex, written, total) => { | ||
| const pct = Math.round(((writtenBytes + written) / totalBytes) * 100); | ||
| progressFill.style.width = Math.min(pct, 100) + '%'; | ||
| }, | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This pull request adds initial support for the LilyGO T-Deck hardware variant. It introduces new build configurations, updates the build workflow to handle the T-Deck and its debug variant, and integrates the required hardware-specific settings into the project configuration system.
The most important changes include:
Build System and Workflow Updates:
.github/workflows/build.yml) to build and deploy firmware for both the standard and debug variants of the T-Deck, including artifact staging and publishing to GitHub Pages.Hardware Configuration:
sdkconfig_display_tdeck.defaultsandsdkconfig_display_tdeck_debug.defaults, specifying hardware, Bluetooth, display, memory, and debug settings tailored for the T-Deck and its debug mode. [1] [2]Project Configuration System (
Kconfig.projbuild):BOARD_TYPE_TDECKas a selectable board, with associated settings for display, input pins, battery, and keyboard support. This includes pin assignments, display parameters, and enabling theHAS_KEYBOARDflag for devices with a physical keyboard. [1] [2]BOARD_TYPE_TDECK, ensuring correct hardware initialization and feature enablement for the new board. [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14]