Repository navigation
Conversation
"Battery level" is a fifth value of the Xbox button brightness setting. The guide LED is monochrome, so following the battery means brightness steps, taken from the presets so each one is a level the user has already seen: full Bright, medium Normal, low Dim - and a slow blink at critical, since a warning has to look like one and a dimmer steady LED across a room does not. A pad with no battery fitted, running off its cable, goes Bright. GuideButtonLed holds every LED constant and the ladder on the Java side, where it is tested; PreferenceConfiguration.getGuideButtonLedValue() now returns it, with "battery" starting at Normal until the pad reports. The native side only applies what it is handed: Controller::setLed() stores the command and sends it once the device has started, startDevice() applies whatever is stored, and both build the frame through one applyLed(), so a brightness of zero means the same thing on every path. ledBrightness loses its const - the comment that justified it said nothing re-sends the command, which is no longer true - and gains a pattern, both std::atomic against the startThread fallback. A pattern outside enum LedMode is refused, which is what catches the Java constants drifting from gip.h. Also fixed on the way: on the cabled path the read thread runs before the Java object exists, and a status in that window armed the driver's change filter with nobody listening, so Java heard nothing until the battery actually moved. The filter now stays unarmed until a report is delivered; MS-GIPUSB 2.2.9 has the pad repeat status every second for its first ten seconds. Latency: nothing on a per-frame path. One GIP frame per level change, on the driver's read thread, deduplicated against charge-only status changes. Tests: GuideButtonLedTest and the guide LED cases in PreferenceConfigurationTest. HARDWARE_TESTING.md 31 lists what needs a device - in particular whether a pad honours LED_BLINK_SLOW at all, which Table 42 leaves open. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
Summary
"Battery level" as a fifth value of the Xbox button brightness setting. The guide LED is monochrome, so following the battery means brightness steps, taken from the presets so each is a level the user has already seen:
0x2F0x140x0AGuideButtonLedholds every LED constant and the ladder on the Java side, where it is tested;PreferenceConfiguration.getGuideButtonLedValue()returns it. The native side only applies what it is handed and refuses a pattern outsideenum LedMode, which is what catches the Java constants drifting fromgip.h.Controller::setLed()stores the command and sends it once the device has started;startDevice()applies whatever is stored; both build the frame through oneapplyLed().ledBrightnessloses itsconst(the comment that justified it said nothing re-sends the command, which is no longer true) and gains a pattern, bothstd::atomicagainst the startThread fallback. New JNI entrysetLedNative (JII)Z.Fixed on the way: on the cabled path, a status arriving before the Java object existed armed the driver's change filter with nobody listening, so Java heard nothing until the battery actually moved. The filter now stays unarmed until a report is delivered; MS-GIPUSB 2.2.9 has the pad repeat status every second for its first ten seconds.
Split out of #66, which also carried an on-screen battery label; that work is preserved on
feature/controller-battery-label.Latency and performance impact
None on any per-frame path. One GIP frame per level change, on the driver's read thread, deduplicated against charge-only status changes.
Applies to
GIP pads this app drives (Xbox wireless adapter, or cabled Xbox with the wired driver on), on both boxes. The setting already sits under the USB-driver dependency.
Test plan
./gradlew testDebugUnitTest— 336 tests, 0 failures (GuideButtonLedTestnew;PreferenceConfigurationTestguide LED cases extended)./gradlew assembleRelease lintRelease— both ABIs build; the 2 lint warnings are pre-existing (UsbDriverService,Profiler)HARDWARE_TESTING.md§31 — in particular whether a pad honoursLED_BLINK_SLOWat all, which Table 42 leaves open🤖 Generated with Claude Code