aports: add fp6-charging-mode (offline charging, charger-boot detection)
Charger-insertion boots (androidboot.mode=charger, ABL-appended) divert to a minimal charging.target instead of the full UI, ending the dead-battery bootloop: ADSP charging/USB-PD runs, splash+panel killed ~6-10s in via an initramfs hook, modem+cdsp stopped, radios/sensors suppressed, CPU capped. Power key reboots to a normal boot, volume-up shows battery status, volume-down enables USB ssh, unplug powers off. Measured >= breakeven on a 100mA-classified SDP port, strongly net-positive on real chargers. Suspend duty-cycling (~13mA floor) exists behind an off-by-default flag: resume from deep suspend intermittently kills the UFS link (hibern8 exit failed ret=5) - do not enable until that kernel bug is fixed. Byte-identical to the deployment verified on the dev phone 2026-08-24 (journal/power: r5 armed tests, crash autopsies, measurements). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
d91963975a
commit
eb13c18ea8
12 changed files with 507 additions and 1 deletions
111
aports/device/fp6-charging-mode/charging-keys.sh
Executable file
111
aports/device/fp6-charging-mode/charging-keys.sh
Executable file
|
|
@ -0,0 +1,111 @@
|
|||
#!/bin/sh
|
||||
# Charging-mode key handler (r4):
|
||||
# volume-down (pmic_resin) -> enable ssh debug mode (inhibits suspend)
|
||||
# volume-up (gpio-keys) -> toggle the on-screen battery status display
|
||||
# The display costs nothing while off: panel + pipeline stay powered down
|
||||
# and suspend cycling continues. While visible, /run/charging-mode-display
|
||||
# inhibits suspend (the monitor checks it); toggling off (or the safety
|
||||
# timeout) blanks everything again and cycling resumes.
|
||||
# The power key is taken (logind: reboot to normal boot).
|
||||
|
||||
log() { echo "charging-keys: $*"; }
|
||||
|
||||
BAT=/sys/class/power_supply/qcom-battmgr-bat
|
||||
USB=/sys/class/power_supply/qcom-battmgr-usb
|
||||
DISPLAY_MARKER=/run/charging-mode-display
|
||||
DISPLAY_TIMEOUT=600 # safety auto-off, seconds
|
||||
|
||||
find_dev() {
|
||||
for e in /sys/class/input/event*; do
|
||||
n=$(cat "$e/device/name" 2>/dev/null)
|
||||
case "$n" in
|
||||
$1) echo "/dev/input/${e##*/}"; return 0 ;;
|
||||
esac
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
read_key() {
|
||||
# echoes the key code of a key RELEASE event (or nothing). Release, not
|
||||
# press: when a key wakes the phone from suspend, the press can be
|
||||
# consumed as the wake event while the release is still delivered — so
|
||||
# triggering on release works both awake and as a wake key.
|
||||
# input_event on arm64: u64 sec, u64 usec, u16 type, u16 code, s32 value
|
||||
# od -tu2 words: 1-8 time, 9 type, 10 code, 11-12 value (lo, hi)
|
||||
_d="$1"
|
||||
set -- $(dd if="$_d" bs=24 count=1 2>/dev/null | od -An -v -tu2)
|
||||
[ $# -ge 11 ] || return 1
|
||||
[ "$9" = "1" ] && [ "${11}" = "0" ] && echo "${10}"
|
||||
return 0
|
||||
}
|
||||
|
||||
enable_ssh() {
|
||||
[ -e /run/charging-mode-ssh ] && return
|
||||
: > /run/charging-mode-ssh
|
||||
log "volume-down pressed: enabling usbnet+sshd, suspend cycling inhibited"
|
||||
systemctl start systemd-user-sessions.service charging-usbnet.service sshd.service
|
||||
}
|
||||
|
||||
draw_status() {
|
||||
cap=$(cat "$BAT/capacity" 2>/dev/null)
|
||||
cur=$(cat "$BAT/current_now" 2>/dev/null)
|
||||
cc=$(cat "$BAT/charge_counter" 2>/dev/null)
|
||||
full=$(cat "$BAT/charge_full" 2>/dev/null)
|
||||
[ -n "$full" ] || full=4415000
|
||||
uv=$(cat "$USB/voltage_now" 2>/dev/null)
|
||||
ui=$(cat "$USB/current_now" 2>/dev/null)
|
||||
eta=$(awk -v f="$full" -v c="$cc" -v i="$cur" 'BEGIN {
|
||||
if (i > 10000) { h = (f - c) / i; printf "%dh%02dm", int(h), (h - int(h)) * 60 }
|
||||
else printf "--"
|
||||
}' 2>/dev/null)
|
||||
{
|
||||
printf '\033[2J\033[H\n\n'
|
||||
printf ' CHARGING %s%%\n\n' "$cap"
|
||||
printf ' battery %d mA\n' "$(( ${cur:-0} / 1000 ))"
|
||||
printf ' input %d mV %d mA\n' "$(( ${uv:-0} / 1000 ))" "$(( ${ui:-0} / 1000 ))"
|
||||
printf ' full in %s\n' "$eta"
|
||||
} > /dev/tty0 2>/dev/null
|
||||
}
|
||||
|
||||
display_off() {
|
||||
rm -f "$DISPLAY_MARKER"
|
||||
printf '\033[2J\033[H' > /dev/tty0 2>/dev/null
|
||||
for b in /sys/class/backlight/*/brightness; do echo 0 > "$b" 2>/dev/null; done
|
||||
for f in /sys/class/graphics/fb*/blank; do { echo 4 > "$f" || echo 1 > "$f"; } 2>/dev/null; done
|
||||
log "status display OFF"
|
||||
}
|
||||
|
||||
display_on() {
|
||||
: > "$DISPLAY_MARKER"
|
||||
log "volume-up pressed: status display ON"
|
||||
for f in /sys/class/graphics/fb*/blank; do echo 0 > "$f" 2>/dev/null; done
|
||||
for b in /sys/class/backlight/*/brightness; do echo 400 > "$b" 2>/dev/null; done
|
||||
(
|
||||
shown=0
|
||||
while [ -e "$DISPLAY_MARKER" ] && [ "$shown" -lt "$DISPLAY_TIMEOUT" ]; do
|
||||
draw_status
|
||||
sleep 5
|
||||
shown=$((shown + 5))
|
||||
done
|
||||
display_off
|
||||
) &
|
||||
}
|
||||
|
||||
VOLDOWN_DEV=$(find_dev "*resin*")
|
||||
VOLUP_DEV=$(find_dev "gpio-keys")
|
||||
|
||||
[ -n "$VOLDOWN_DEV" ] && log "volume-down (ssh) on $VOLDOWN_DEV" \
|
||||
|| log "no resin device - ssh enable unavailable this boot"
|
||||
[ -n "$VOLUP_DEV" ] && log "volume-up (display) on $VOLUP_DEV" \
|
||||
|| log "no gpio-keys device - status display unavailable this boot"
|
||||
|
||||
if [ -n "$VOLDOWN_DEV" ]; then
|
||||
( while :; do [ "$(read_key "$VOLDOWN_DEV")" = "114" ] && enable_ssh; done ) &
|
||||
fi
|
||||
if [ -n "$VOLUP_DEV" ]; then
|
||||
( while :; do
|
||||
[ "$(read_key "$VOLUP_DEV")" = "115" ] || continue
|
||||
if [ -e "$DISPLAY_MARKER" ]; then display_off; else display_on; fi
|
||||
done ) &
|
||||
fi
|
||||
wait
|
||||
Loading…
Reference in a new issue