Skip to content

feat(power): improve X4 Pro battery life - drop RC_FAST frontlight retention + add shutdown-reason RTC marker - #70

Closed
Belphemur wants to merge 1 commit into
Free-Ink:mainfrom
Belphemur:feat/freeink-sdk-battery-improvement
Closed

feat(power): improve X4 Pro battery life - drop RC_FAST frontlight retention + add shutdown-reason RTC marker#70
Belphemur wants to merge 1 commit into
Free-Ink:mainfrom
Belphemur:feat/freeink-sdk-battery-improvement

Conversation

@Belphemur

@Belphemur Belphemur commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Prepare the FreeInk SDK for the crosspoint firmware changes that improve X4 Pro battery life.

This PR includes the SDK-side changes needed for the crosspoint battery-drain improvement:

  • Drop RC_FAST frontlight retention in light sleep (removes LEDC_SLEEP_MODE_KEEP_ALIVE / FREEINK_FRONTLIGHT_LS)
  • Restore 25 kHz frontlight PWM timer (was downgraded to 10 kHz by the RC_FAST workaround)
  • Add shutdown-reason RTC marker so crosspoint can detect power-off shutdowns via RTC
  • Add park() support for frontlight power-gating during sleep

The light-sleep RC_FAST keep-alive is intentionally removed per discussion with the @itsthisjustin - upstream PR #39 compatibility is not preserved.

Crosspoint consumer-side changes (auto-shutdown timer, HalPowerManager, HalFrontlight) will follow in a separate draft PR after this merges.

…tention + add shutdown-reason RTC marker

Prepare the FreeInk SDK for the crosspoint firmware changes that improve X4 Pro battery life.

1. Drop the RC_FAST frontlight retention path (FREEINK_FRONTLIGHT_LS).
   The fork only deep-sleeps (never light-sleeps), so RC_FAST retention bought
   nothing while it forced the X4 Pro frontlight down to 10 kHz. Removing the
   RC_FAST path lets the LEDC timer run on the default AUTO clock (XTAL/APB,
   >=40 MHz), so the OEM 25 kHz/10-bit profile is valid again. The frontlight
   is still cut at deep sleep by park()/releaseOnWake() pad-holds; clock-agnostic.

2. Add a stock-parity shutdown-reason RTC marker (ShutdownReason enum +
   setShutdownReason/takeShutdownReason). xteink_app v7.4.4 writes magic
   0x58435253 (SRCX) + a u8 reason to RTC slow RAM before its power-off
   commit and reads/clears it at boot. RTC slow RAM survives deep sleep
   and most resets, so the consumer can record why the device powered off
   and report it at wake.
@Belphemur Belphemur changed the title feat(power): improve X4 Pro battery life feat(power): improve X4 Pro battery life - drop RC_FAST frontlight retention + add shutdown-reason RTC marker Sep 1, 2026
@Belphemur
Belphemur marked this pull request as ready for review September 1, 2026 01:50
Copilot AI lite review requested due to automatic review settings September 1, 2026 01:50

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Prepares the FreeInk SDK for upcoming crosspoint firmware power-management changes by removing the RC_FAST/KEEP_ALIVE light-sleep frontlight retention approach (and its 10 kHz PWM limitation), restoring the OEM frontlight PWM frequency for X4 Pro, and introducing an RTC slow-memory shutdown-reason marker to support stock-parity power-off detection.

Changes:

  • Added a shutdown-reason marker API in PowerManager backed by RTC slow RAM (write + consume-once read).
  • Updated the FREEINK_FRONTLIGHT_LS LEDC setup to drop RC_FAST/KEEP_ALIVE and return to auto-clock selection so 25 kHz / 10-bit works again.
  • Restored X4 Pro’s board-profile frontlight PWM setting to 25 kHz and updated documentation/comments around deep-sleep leakage mitigation (park()).

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
libs/hardware/PowerManager/src/PowerManager.cpp Implements RTC slow-RAM shutdown marker read/write logic.
libs/hardware/PowerManager/include/PowerManager.h Exposes new shutdown-reason API and enum.
libs/hardware/FrontlightManager/src/FrontlightManager.cpp Removes RC_FAST/KEEP_ALIVE configuration; uses auto clocking and keeps deep-sleep park() behavior.
libs/hardware/FrontlightManager/include/FrontlightManager.h Updates park() contract/comments and removes LS keep-alive bookkeeping fields.
libs/hardware/BoardConfig/include/BoardConfig.h Restores X4 Pro frontlight PWM frequency to OEM 25 kHz / 10-bit.
Suppressed comments (3)

libs/hardware/PowerManager/src/PowerManager.cpp:123

  • The shutdown reason is documented as a single byte, but this writes a full 32-bit word to RTC slow RAM. That will zero/overwrite the other 3 bytes at 0x50000000..03, which could conflict with other RTC-slow users now or later. Use a volatile uint8_t* for the reason cell and store only the byte.
  auto* magicCell = reinterpret_cast<volatile uint32_t*>(kShutdownMagicAddr);
  auto* reasonCell = reinterpret_cast<volatile uint32_t*>(kShutdownReasonAddr);
  // Reason first, magic last: a torn write (power cut mid-sequence) leaves NO

libs/hardware/PowerManager/src/PowerManager.cpp:134

  • Same issue on read/clear: using a volatile uint32_t* for the reason cell reads and clears 4 bytes even though only the low byte is meaningful. Read/clear the reason as a uint8_t to avoid clobbering neighboring bytes in RTC slow RAM.
  auto* magicCell = reinterpret_cast<volatile uint32_t*>(kShutdownMagicAddr);
  auto* reasonCell = reinterpret_cast<volatile uint32_t*>(kShutdownReasonAddr);
  if (*magicCell != kShutdownMagic) return 0;
  const uint16_t result = static_cast<uint16_t>(((*reasonCell & 0xffu) << 8) | 1u);
  // Clear both cells: the marker is consumed exactly once (stock behavior).

libs/hardware/FrontlightManager/src/FrontlightManager.cpp:106

  • Similarly, the channel config currently relies on the zero-initialized sleep_mode being "not KEEP_ALIVE". Make this explicit with LEDC_SLEEP_MODE_NO_ALIVE so future enum/value changes can’t accidentally re-enable KEEP_ALIVE behavior.
  ledc_channel_config_t chan = {};
  chan.gpio_num = gpio;
  chan.speed_mode = LEDC_LOW_SPEED_MODE;
  chan.channel = static_cast<ledc_channel_t>(ch);
  chan.intr_type = LEDC_INTR_DISABLE;

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +115 to +117
constexpr uintptr_t kShutdownMagicAddr = 0x50000004; // RTC slow RAM + 4
constexpr uintptr_t kShutdownReasonAddr = 0x50000000; // RTC slow RAM + 0
constexpr uint32_t kShutdownMagic = 0x58435253u; // "SRCX" little-endian
Comment on lines 92 to 96
ledc_timer_config_t timer = {};
timer.speed_mode = LEDC_LOW_SPEED_MODE;
timer.duty_resolution = static_cast<ledc_timer_bit_t>(bits);
timer.timer_num = LEDC_TIMER_0;
timer.freq_hz = freq;
@Belphemur

Copy link
Copy Markdown
Contributor Author

@itsthisjustin relates to what we talked about about disabling RC_FAST to keep the same refresh rate on the frontlight + other findings relating to how the stock firmware works.

I plan to add to upstream an auto shutdown feature, different from sleep, akin to what the stock firmware has, and store in the slow mem the reason (as stock does it) for the sleep.

@Belphemur Belphemur closed this Sep 4, 2026
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.

2 participants