Power button events were setting any_activity before the power handler's
continue, causing the generic wake logic to immediately re-enable the screen.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Allwinner /dev/disp driver resets brightness to 0 when the fd is
closed, so the screen monitor's SIGTERM brightness restore was undone
before the wrapper wrote goodbye.png. Restore brightness in the wrapper
itself, right before the framebuffer write.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Broaden wake events beyond EV_KEY so d-pad (EV_ABS) wakes the screen
- Use EVIOCGRAB for exclusive input while screen is off, preventing the
wake button press from also acting in sdlamp2
- Auto-shutdown after 10 minutes of no input and no audio playback,
detected by monitoring the audio file's read position via /proc fdinfo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Persist the current cassette filename to last_cassette.txt so the player
resumes the same cassette after restart. Switching cassettes now always
lands in a paused state to avoid jarring mid-playback jumps.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Both the evtest-based power monitor and the Python screen monitor were
reading /dev/input/event0 simultaneously, causing missed events on the
device's Linux 4.9 kernel. Moved long-press shutdown into the screen
monitor (which already reads event0 directly) and removed the evtest
dependency entirely.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New Python screen monitor uses Allwinner /dev/disp ioctls to turn off
the display after 15s of no input and toggle it with a short power
button press. Launched by the wrapper alongside sdlamp2.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The in-app shutdown visual didn't work because SDL cleanup wiped the
framebuffer. Instead of hacking around that, move the shutdown display
to the device wrapper where it belongs. The wrapper now decodes the
stock firmware's goodbye.png with Python3+PIL and writes raw BGRA
pixels directly to /dev/fb0 before calling poweroff.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
sdlamp2 now catches SIGTERM and SIGINT via a sig_atomic_t flag checked
in the main loop, ensuring position and volume are saved before exit.
Previously, a kill signal would terminate instantly without saving.
New tools/rg35xx-wrapper.sh replaces sdlamp2 as the dmenu_ln CMD on
the RG35XX Plus. Skeleton includes placeholders for WiFi hotspot and
power button monitoring (TBD after on-device investigation).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Merge the separate Stop and Play buttons into one slot that toggles
between play/stop and shows the corresponding icon. Use the freed
slot for a Previous Cassette button, mirroring Next Cassette.
Layout: [Volume] [Prev] [Rewind] [Play/Stop] [FF] [Next]
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Player was autoplaying on startup and on file switch. Now switch_file()
preserves the current paused state so the app launches paused and
"next tape" only continues playing if already playing. Joystick name
printf moved behind --debug flag.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace Buildroot toolchain references with the new docker-arm64 setup
in CLAUDE.md, TOOLCHAIN.md, and the changelog.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Single Makefile supports native builds (pkg-config) and cross-compilation
(CROSS_COMPILE/PREFIX env vars). Fixes -Wformat-truncation and
-Wstringop-truncation warnings at -O2 by sizing current_file to match
audio_files (256) and replacing strncpy with snprintf.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Open the joystick via SDL_JoystickOpen() when no GameController mapping
exists, fixing d-pad and face button input on devices like the Anbernic
retro handheld (GUID not in SDL's database). Handles JOYHATMOTION for
d-pad navigation and JOYBUTTONDOWN button 0 for activation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The spritesheet is compiled in as a C byte array. An external
controls.png in cwd still takes precedence for skinning. Includes
tools/embed_png.py to regenerate the header if the asset changes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Logs joystick enumeration at startup (name, GameController status, GUID)
and all SDL input events in the main loop to help diagnose why the retro
handheld's d-pad/buttons aren't recognized by the GameController API.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Shell script to recombine individual story m4a files back into
per-cassette files using ffmpeg concat demuxer (stream copy, no
re-encoding). Generates chapter markers from input filenames and
preserves album art.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace mouse input with cursor-based navigation (arrow keys / d-pad +
Enter / A button) and add app-level volume control with a persistent
vertical slider, enabling use on a handheld gaming device without mouse
or system mixer access.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace fire-and-forget decode_audio() with a streaming Decoder that uses
libswresample to convert planar float to interleaved stereo, fixing the
sped-up audio bug and eliminating multi-GB memory usage for long files.
Add 10-second rewind/fast-forward, stop (pause in place), position
persistence per file via positions.txt, directory scanning with file
switching, embedded album art display, and a progress bar. Handles both
old and new FFmpeg channel layout APIs via version preprocessor check.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>