Kobo: corrige le suspend (EPDC/VEE) qui vidait la batterie
Cause racine de l'autonomie médiocre : la liseuse ne suspendait JAMAIS.
Juste après un refresh e-ink, le pilote EPDC (20f4000.epdc) refuse de
suspendre tant que la haute tension VEE n'est pas redescendue
("waiting for VEE stable ... please retry suspend later", error -2) :
le noyau avorte tout le suspend, on tombait dans le repli `sleep` et le
CPU tournait 24h/24 (0 suspend réussi sur 261 itérations dans les logs).
Correctif (suspend_for) : on laisse l'EPDC décharger VEE (~8 s) puis on
RÉESSAIE le suspend jusqu'à ce qu'il prenne, comme le suggère le noyau.
Résultat : rtcwake elapsed ~= REFRESH (vrai sommeil entre les refresh),
duty cycle éveillé ~100% -> ~3%.
Aussi :
- intervalle 5 min -> 15 min (moins de réveils).
- suspend_diag() one-shot conservé comme filet (ne se déclenche qu'en
cas d'échec total après les retries) — à retirer après validation 24 h.
This commit is contained in:
@@ -15,8 +15,9 @@ cd "$BASE" || exit 1
|
||||
|
||||
# --- Configuration ---
|
||||
export MONITORINK_URL="http://192.168.0.43:8899/image.png"
|
||||
export MONITORINK_REFRESH=300 # PROD: refresh partiel 5 min
|
||||
# Cadence du full refresh : côté SERVEUR via MONITORINK_FULL_EVERY (PROD=12 ~1 h à 5 min/cycle).
|
||||
export MONITORINK_REFRESH=900 # PROD: refresh partiel 15 min (moins de réveils = batterie)
|
||||
# Cadence du full refresh : côté SERVEUR via MONITORINK_FULL_EVERY. À 15 min/cycle, FULL_EVERY=4
|
||||
# -> full refresh ~1 h (ajuster côté backend si besoin pour limiter le ghosting).
|
||||
|
||||
echo "===== monitorink start $(date) =====" >> "$LOG"; sync
|
||||
|
||||
|
||||
@@ -121,32 +121,76 @@ frontlight_off() {
|
||||
done
|
||||
}
|
||||
|
||||
DIAG_DONE=0
|
||||
suspend_diag() {
|
||||
# DIAGNOSTIC (one-shot) : quand un suspend échoue sur batterie, capture la raison
|
||||
# du veto noyau dans le log. À retirer une fois la cause identifiée.
|
||||
[ "$DIAG_DONE" = 1 ] && return
|
||||
DIAG_DONE=1
|
||||
log "===== DIAG suspend (one-shot) ====="
|
||||
for d in /sys/class/power_supply/*/; do
|
||||
n=$(basename "$d")
|
||||
log " $n: status=$(cat "${d}status" 2>/dev/null) online=$(cat "${d}online" 2>/dev/null) present=$(cat "${d}present" 2>/dev/null)"
|
||||
done
|
||||
log " wakeup_count=$(cat /sys/power/wakeup_count 2>/dev/null) state-extended=$(cat /sys/power/state-extended 2>/dev/null)"
|
||||
# IRQ responsable du DERNIER réveil — la clé du mystère.
|
||||
log " pm_wakeup_irq=$(cat /sys/power/pm_wakeup_irq 2>/dev/null) last_resume_reason=$(cat /sys/kernel/debug/wakeup/last_resume_reason 2>/dev/null)"
|
||||
# Quels devices d'entrée sont armés comme source de réveil (1=oui).
|
||||
log " -- input devices (name | wakeup) --"
|
||||
for inp in /sys/class/input/input*/; do
|
||||
nm=$(cat "${inp}name" 2>/dev/null)
|
||||
wk=$(cat "${inp}power/wakeup" 2>/dev/null)
|
||||
[ -n "$nm" ] && log " $(basename "$inp"): \"$nm\" wakeup=$wk"
|
||||
done
|
||||
# debugfs (souvent non monté) -> wakeup_sources triés par nb d'évènements.
|
||||
mount -t debugfs none /sys/kernel/debug 2>/dev/null
|
||||
if [ -r /sys/kernel/debug/wakeup_sources ]; then
|
||||
log " -- top wakeup_sources (event_count) --"
|
||||
awk 'NR>1 && ($3+0)>0 {print $3"\t"$1}' /sys/kernel/debug/wakeup_sources 2>/dev/null \
|
||||
| sort -rn | head -8 | while IFS= read -r l; do log " $l"; done
|
||||
fi
|
||||
# Les IRQ qui montent = source matérielle qui spamme (touch elan, gpio, etc.).
|
||||
log " -- /proc/interrupts (lignes non nulles) --"
|
||||
awk 'NR>1 && ($2+0)>0 {print $0}' /proc/interrupts 2>/dev/null \
|
||||
| sort -t: -k2 -rn 2>/dev/null | head -12 | while IFS= read -r l; do log " $l"; done
|
||||
log " -- dmesg : lignes PM/wakeup/elan/gpio (40 dernières) --"
|
||||
dmesg 2>/dev/null | grep -iE 'PM:|wakeup|abort|suspend|elan|gpio|irq' | tail -40 \
|
||||
| while IFS= read -r l; do log " $l"; done
|
||||
log "===== /DIAG ====="
|
||||
}
|
||||
|
||||
suspend_for() {
|
||||
# Séquence Kobo éprouvée (trmnl-kobo) : state-extended=1 AVANT rtcwake, puis
|
||||
# suspend manuel (echo mem) si rtcwake n'a pas vraiment suspendu.
|
||||
# Suspend rtcwake (-m mem), réveil RTC après "secs".
|
||||
#
|
||||
# PIÈGE EPDC : juste après un refresh e-ink, la haute tension VEE du panneau n'est pas
|
||||
# encore redescendue ; le pilote EPDC (20f4000.epdc) refuse alors de suspendre
|
||||
# ("waiting for VEE stable ... please retry suspend later", error -2) et le noyau avorte
|
||||
# TOUT le suspend. Sans gestion, on tombait dans un sleep CPU-allumé -> batterie vidée.
|
||||
# Parade (recommandée par le noyau lui-même) : laisser VEE se décharger, puis RÉESSAYER
|
||||
# le suspend jusqu'à ce qu'il prenne.
|
||||
secs="$1"
|
||||
sync
|
||||
sleep 8 # laisse l'EPDC couper ses rails (VEE) ~10s après le refresh
|
||||
attempt=0
|
||||
while [ "$attempt" -lt 6 ]; do
|
||||
attempt=$((attempt + 1))
|
||||
sync
|
||||
echo 1 > /sys/power/state-extended 2>/dev/null
|
||||
start=$(date +%s)
|
||||
"$BUSYBOX" rtcwake -a -s "$secs" -m mem 2>/dev/null
|
||||
elapsed=$(( $(date +%s) - start ))
|
||||
log "rtcwake elapsed=${elapsed}s"
|
||||
if [ "$elapsed" -le 10 ]; then
|
||||
log "suspend manuel via echo mem"
|
||||
sleep 1; sync; sleep 2
|
||||
m_start=$(date +%s)
|
||||
echo mem > /sys/power/state 2>/dev/null
|
||||
log "echo mem elapsed=$(( $(date +%s) - m_start ))s (≈${secs}=OK, ≈0=USB branché/suspend bloqué)"
|
||||
fi
|
||||
echo 0 > /sys/power/state-extended 2>/dev/null
|
||||
# Repli : si rien n'a réellement suspendu (USB branché, etc.), on attend le temps
|
||||
# restant en sleep pour ne pas boucler en continu (martèlement backend + batterie).
|
||||
total=$(( $(date +%s) - start ))
|
||||
if [ "$total" -lt "$secs" ]; then
|
||||
rem=$(( secs - total ))
|
||||
log "suspend incomplet (${total}s) -> sleep ${rem}s"
|
||||
sleep "$rem"
|
||||
fi
|
||||
log "rtcwake tentative=$attempt elapsed=${elapsed}s"
|
||||
# elapsed grand = on a réellement dormi (réveil RTC ou bouton) -> terminé.
|
||||
[ "$elapsed" -ge 15 ] && return
|
||||
# Échec immédiat (EPDC/VEE pas prêt) : on attend un peu et on retente.
|
||||
sleep 3
|
||||
done
|
||||
# Toujours pas suspendu après les retries (cas anormal) -> diag + repli sleep pour ne pas
|
||||
# marteler le backend, sans laisser le CPU tourner inutilement plus que "secs".
|
||||
log "suspend impossible après $attempt tentatives -> diag + sleep"
|
||||
suspend_diag
|
||||
sleep "$secs"
|
||||
}
|
||||
|
||||
has_ip() { ip addr show 2>/dev/null | grep -o 'inet [0-9.]*' | grep -qv '127.0'; }
|
||||
|
||||
Reference in New Issue
Block a user