Skip to content

Suspend MediaTek boards only while discharging - #118

Open
abhishek-anand wants to merge 15 commits into
betafrom
fix/mediatek-suspend-wake
Open

Suspend MediaTek boards only while discharging#118
abhishek-anand wants to merge 15 commits into
betafrom
fix/mediatek-suspend-wake

Conversation

@abhishek-anand

@abhishek-anand abhishek-anand commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Suspend a MediaTek board only when the battery says it is discharging.
  • Recover sleep/wake ownership and the network after a suspend, and find the ARM binary where CARGO_TARGET_DIR actually puts it.

Test plan

  • Clara BW / MediaTek: sleep while unplugged, stay awake while charging
  • After wake, Wi-Fi and the panel session come back without a reboot

View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

abhishek-anand and others added 6 commits August 27, 2026 14:07
Nickel is stopped for the session, so the button had no owner. A short press now sleeps without handing the panel back; a hold of two seconds powers off. MediaTek boards skip kernel suspend while charging.

Co-authored-by: Cursor <cursoragent@cursor.com>
A missed battery read must not write mem on boards that hang when
suspended on a charger. Kernel power writes stay behind device-write.

Co-authored-by: Cursor <cursoragent@cursor.com>
Both the device build and the packaging step hard-coded a relative
"target/" prefix when locating the cross-compiled artifact to verify.
Anyone building with CARGO_TARGET_DIR pointed somewhere else — a shared
cache, or a worktree on a different volume — got a missing-file error
from verify_arm_elf instead of a verified binary, even though cargo had
just built it successfully.

Resolve the prefix from the environment the same way cargo does, and
fall back to "target" only when nothing is set.

Co-authored-by: Cursor <cursoragent@cursor.com>
Battery::charging answers a two-state question by treating everything
that is not "Charging" as not charging. That is the right answer for a
status band, and the wrong one for suspend: a MediaTek kernel hangs on
"Full" and on "Not charging" just as readily as on "Charging", and an
unreadable status has to count as unsafe rather than safe.

Add discharging()/discharging_from() alongside it, returning None when
the status cannot be read so the caller can decide, and cover every
status string the sysfs node is known to produce.

Co-authored-by: Cursor <cursoragent@cursor.com>
charger_blocks_mem asked Battery::charging, so "Full" and "Not charging"
both read as safe to suspend and both hang the kernel. Ask the stricter
question instead, and re-check it inside try_mem: the gap between
flagging subsystems and writing mem is two seconds, which is long enough
for a charger to be plugged in after the decision was made. A cancelled
attempt unflags the subsystems it already flagged.

Wake was also handing the panel to the wrong owner. Some firmware
restarts Nickel during resume even though Cobalt stopped it before
taking the panel; yielding to it left Cobalt's sleep screen painted over
Nickel, so wake looked like it had returned to the wrong program. Stop
that second owner and repaint instead of bailing out.

Finally, drop resleep_at and UNEXPECTED_WAKE. The power-key edge that
wakes the kernel is not reliably replayed to userspace, so the loop was
waiting fifteen seconds for an event that never arrived and then going
back to sleep on a reader somebody was holding. Treat the completed
resume as the wake signal and lean on WAKE_GRACE to swallow the late
release edge.

Co-authored-by: Cursor <cursoragent@cursor.com>
Copilot AI lite review requested due to automatic review settings September 4, 2026 07:51

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.

🟡 Changes recommended

The sleep UI/docs currently describe wake and sleep-screen behavior that doesn’t match the implemented runtime behavior, which can mislead users.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR extends the device runtime’s in-session sleep/wake behavior (including MediaTek charging constraints), adds an owner-visible “Sleep after idle” setting, and improves post-suspend recovery (panel ownership + Wi‑Fi) while aligning the protocol/SDK/simulator surfaces to support the new capability.

Changes:

  • Add an IdleSleep preference end-to-end (protocol wire tags + SDK API + Settings UI + device runtime persistence).
  • Implement in-session sleep/wake handling (power button + cover), including MediaTek “suspend only when explicitly discharging” gating and panel invalidation after resume.
  • Improve network recovery/robustness around sleep/wake and session hand-off (Wi‑Fi bring-up hooks, link/lease handling, and reader ownership detection).
File summaries
File Description
examples/settings/src/main.rs Adds “Sleep after idle” screen and device request plumbing for idle-sleep preference.
docs/PORTING.md Tightens required evidence to include short power-button sleep/wake into the same app.
docs/DEVICES.md Documents in-session sleep behavior and MediaTek charging suspend limitations.
crates/kobod/src/main.rs Updates KOBO_IDLE_SECONDS handling to support “never/from settings” modes.
crates/kobod/src/device.rs Implements sleep overlay, idle-sleep enforcement, suspend gating, Wi‑Fi/session restoration, and reader-ownership-aware handoff.
crates/kobod/src/app_link.rs Ensures relay path runs network-prepare hook before opening sockets.
crates/kobo-ui/src/lib.rs Adds FramePlanner::invalidate() to force full refresh after untrusted framebuffer restore.
crates/kobo-sim/src/lib.rs Restricts idle-sleep requests to Settings in the simulator authority model.
crates/kobo-sdk/src/lib.rs Exposes IdleSleep plus read_idle_sleep/set_idle_sleep on Device.
crates/kobo-protocol/src/lib.rs Defines IdleSleep, adds device requests/results, and encodes/decodes new wire tags.
crates/kobo-profile/src/lib.rs Adds MediaTek charging-suspend predicate; enables supplicant reaping for Clara BW profiles.
crates/kobo-policy/src/services.rs Tracks idle-sleep in services and marks idle-sleep requests as capability-free.
crates/kobo-net/src/lib.rs Adds on_prepare hook and calls prepare() before opening sockets; adds idle-connection reset helper.
crates/kobo-hal/src/wifi.rs Adds wake/keep/restore logic for saved Wi‑Fi with route/lease handling and sleep staleness tracking.
crates/kobo-hal/src/reader.rs Adds “any reader running” detection and safer restart behavior to avoid double-Nickel ownership.
crates/kobo-hal/src/power.rs New module for power-button action classification and kernel suspend sysfs access (device-write gated).
crates/kobo-hal/src/network.rs Adds non-owning DHCP renew helper and makes wait_until_online public for reuse.
crates/kobo-hal/src/lib.rs Exposes the new power module.
crates/kobo-hal/src/gpio.rs Detects MediaTek pwrkey node separately from gpio-keys; updates discovery and validation.
crates/kobo-hal/src/battery.rs Adds strict “explicitly discharging” check for safe suspend gating on MediaTek boards.
crates/kobo-cli/src/main.rs Resolves ARM binary paths via CARGO_TARGET_DIR instead of assuming target/.
Review details
  • Files reviewed: 21/21 changed files
  • Comments generated: 2
  • Review effort level: Lite

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

Comment on lines +944 to +945
title: "Sleeping".to_owned(),
summary: "Press the power button or open the cover to wake.".to_owned(),
Comment thread docs/DEVICES.md
Comment on lines +38 to +40
the default. Sleep keeps the current screen and writes "Sleeping" in the
status strip; it does not replace the panel with a splash. The radio is
powered down for sleep and brought back on wake when it was up. If it is
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