Skip to content

Conversation

@FreeOnlineUser
Copy link

Description

Adds support for the Waveshare 2.8" DPI LCD (480x640) with capacitive touchscreen, addressing the bounty in issue #150.

Key features:

  • Direct framebuffer rendering via PIL/Pillow + mmap (no windowing/mirroring)
  • Pure Python touch input reading raw /dev/input/ events (no C extensions, no external libs)
  • 240x240 UI scaled 2x to 480x480, with 480x160 touch bar below
  • Auto-detection: existing 1.3" SPI HAT continues to work unchanged
  • Touch bar adapts to context (navigation vs keyboard modes)

Demo videos: See issue #150 comment

Hardware: Waveshare 2.8" DPI LCD (~$25-45)
https://www.waveshare.com/2.8inch-DPI-LCD.htm

Closes #150

This pull request is categorized as a:

  • New feature
  • Bug fix
  • Code refactor
  • Documentation
  • Other

Checklist

  • I've run pytest and made sure all unit tests pass before submitting the PR

If you modified or added functionality/workflow, did you add new unit tests?

  • No, I'm a fool
  • Yes
  • N/A

I have tested this PR on the following platforms/os:

kdmukai and others added 26 commits January 3, 2026 10:33
The ili9341 module imports RPi.GPIO at module level. When renderer.py
imported it unconditionally, ST7789-only setups would crash before
any display code could run.

This is an upstream bug in the new display driver code.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add DPI28 framebuffer driver (480x640, touch bar at bottom)
- Add touch input handler using evdev
- Add TouchButtons adapter with get_buttons() factory
- Update display_driver.py for DPI28 support
- Update renderer.py with auto-detection for display and touch
- Update settings_definition.py with DPI28 option
- Update screen.py with full touch interaction support
- Update seed_screens.py with keyboard touch bar labels
- Update controller.py to use get_buttons() for screensaver
- Update screensaver.py to hide touch bar during screensaver
- Add PC emulator for development testing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Orange/grey button states based on list position
- Black text on orange buttons for better contrast
- Add PR_DESCRIPTION.md and DPI28_SETUP.md

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Replace text labels with SeedSigner icon font glyphs
- Language-agnostic: no translation needed
- Uses seedsigner-icons.otf for arrows/check/delete
- Uses FontAwesome for keyboard icon

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- ToolsDiceEntropyEntryScreen: Single tap on dice icons to select
- ToolsCoinFlipEntryScreen: Single tap on 0/1 to select
- Both screens hide the touch bar (not needed for direct key taps)
- Maintains D-pad navigation fallback for non-touch input

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove check_for_low parameter (not supported by TouchButtons)
- Use get_last_tap_native_coords() instead of last_touch_coords
- Restructure touch check for early non-touch fallback

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
set_selected_key() expects a character, not a Key object.
Use set_selected_key_indices(key.index_x, key.index_y) instead.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Key class has 'letter' for display char, not 'text_content'.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Parent class KeyboardScreen._run() initializes cursor_position,
but since we override _run(), we need to do it ourselves.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add debug logging for tap coordinates and key detection
- Check for back button tap in addition to KEY_LEFT
- Fall back to using selected key when direct tap doesn't find a key
- This ensures taps in the center area still work via the selected key

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- seed_screens.py: Full touch support for SeedAddPassphraseScreen
  - Direct key tap detection on keyboard
  - Right panel button hit detection (ABC/123/checkmark)
  - Touch bar hidden (screen has own buttons)
  - Clear pending input on screen entry

- keyboard.py: Add is_active check in get_key_at_screen_coords

- screen.py: Add clear_pending_input calls, KEY_PRESS ignore logic

- tools_screens.py: Touch support for dice/coin entry screens

All touch code guarded with hasattr() - zero risk to GPIO path.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use mmap for fast framebuffer access instead of file I/O
- Add RGB→BGR conversion (Pi framebuffer uses 32-bit BGRA format)
- Support 3 performance tiers: Cython (~17 fps), Numpy (~7 fps), Python (~1 fps)
- Add RGBtoBGR.pyx Cython module for optional fastest conversion
- Auto-detect framebuffer config from /sys/class/graphics/fb0/
- Update PR_DESCRIPTION.md with framebuffer performance section

Based on mutatrum's fast-pillow-fb approach:
https://github.com/mutatrum/fast-pillow-fb

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Ensures file handles are properly closed if mmap initialization fails partway through.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The check 'hasattr(self.renderer, set_touch_bar_labels)' is always true
since Renderer always has this method. This caused DPI28 import on
ST7789 hardware, leading to lockups on passphrase screen.

Changed to check 'hasattr(disp.display, set_touch_bar_labels)' which
only returns true when using DPI28 display.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Prevents tapping the scroll arrow indicators from triggering button
selection on the underlying list item, fixing scroll behavior.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- renderer.py: Use auto-detected DPI28 display from environment
- DPI28.py: Disable Cython import (pyximport hangs on Pi Zero)

Note: Also requires dpi_output_format=0x7F206 in /boot/config.txt
- renderer.py: Update touch detection to use sysfs instead of evdev
  (evdev not available on SeedSignerOS)
- touch.py: Add raw input fallback for when evdev is unavailable,
  fix 32-bit ARM event size (16 bytes), fix coordinate timing issue
  where stale coordinates were used, add proper calibration transform
- touchbuttons.py: Add missing check_for_low() method

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- touch.py: Remove evdev dependency, use raw Linux input only
- Add config_dpi28.txt and cmdline_dpi28.txt for clean boot
- Add DPI28_SETUP.md with setup instructions
- Update .gitignore for local dev files

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- cmdline_dpi28.txt: Use /dev/mmcblk0p2 instead of PARTUUID
- config_dpi28.txt: Use legacy DPI mode with Waveshare overlays

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add overlays_dpi28/ with required .dtbo files
- Update DPI28_SETUP.md with overlay copy step

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- config_spi13.txt: Standard SeedSignerOS config for ST7789 SPI display

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Rename DPI28_SETUP.md to DISPLAY_SETUP.md
- Add documentation for both 1.3" SPI and 2.8" DPI displays
- Include setup table for quick reference

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add touch bar hiding to PowerOffNotRequiredScreen
- Add camera support to config_dpi28.txt (start_x, gpu_mem)
- Add USB gadget mode for SSH over USB
- Update .gitignore to exclude local dev files

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 Million Sat Bounty for Touchscreen Demo

2 participants