#!/bin/sh # Monitorink — reboot logiciel par TRIPLE-APPUI sur un BOUTON FRONTAL (restaure Nickel). # Lancé en arrière-plan par monitorink.sh. Remplace l'ancien triple-tap finger_trace qui # barbouillait l'écran de points noirs. Appui long sur power = reboot matériel = filet de # secours ultime. # # Pourquoi les boutons frontaux et pas le power : sur ce Kobo (mx6sll) le bouton power n'émet # que des scancodes bruts EV_MSC/MSC_SCAN, parasités par l'état de charge USB (impossible à # distinguer de façon fiable). Les boutons frontaux, eux, émettent des EV_KEY PROPRES # (type=1) codes 193 (KEY_F23) et 194 (KEY_F24), press(val=1)/release(val=0) nets, sans aucun # parasite. On compte 3 appuis (press) sur l'un OU l'autre en moins de 3 s. # # NB suspend : les boutons frontaux ne réveillent pas l'appareil du suspend profond (seul le # power le fait). En usage sur secteur (USB) l'appareil ne suspend pas vraiment -> le watcher # tourne en continu et le triple-appui marche tout le temps. Sur batterie, réveiller d'abord # par un appui power, puis faire les 3 appuis frontaux dans la fenêtre d'éveil. BASE="$(dirname "$0")" cd "$BASE" || exit 1 LOG="$BASE/monitorink.log" FBINK="./bin/fbink/fbink" BB="./bin/busybox_kobo" DEBUG="${MONITORINK_PWR_DEBUG:-0}" # 1 = logge chaque évènement pour caler device/codes BTN_A=193 # bouton frontal 1 (KEY_F23) BTN_B=194 # bouton frontal 2 (KEY_F24) # Repère le périphérique input des boutons (gpio-keys). Repli : event0. find_button_dev() { for ev in /dev/input/event*; do [ -e "$ev" ] || continue case "$(cat "/sys/class/input/${ev##*/}/device/name" 2>/dev/null)" in *gpio*key*|*power*|*Power*|*pmic*|*keys*) echo "$ev"; return 0 ;; esac done [ -e /dev/input/event0 ] && echo /dev/input/event0 } graceful_reboot() { echo "[watcher] TRIPLE-APPUI frontal -> reboot logiciel" >> "$LOG"; sync "$FBINK" -c -pmh "Redemarrage..." 2>/dev/null sleep 1; sync reboot } echo "[watcher] reboot triple-appui frontal actif" >> "$LOG"; sync # Boucle de respawn : si le lecteur meurt (réinit input au réveil, fd fermé), on le relance. # Le watcher ne reste jamais mort -> le reboot logiciel est toujours disponible. while true; do DEV="$(find_button_dev)" if [ -z "$DEV" ]; then echo "[watcher] aucun input bouton trouvé, retry 5s" >> "$LOG"; sync sleep 5; continue fi echo "[watcher] écoute $DEV" >> "$LOG"; sync # IMPORTANT : ouvrir le périphérique UNE seule fois (FD 4) et lire séquentiellement. # Rouvrir à chaque évènement (dd if=$DEV) crée un gap qui fait perdre des évènements. # FD persistant = flux continu, zéro perte, zéro buffering. if ! exec 4< "$DEV"; then echo "[watcher] ouverture $DEV KO -> retry 5s" >> "$LOG"; sync sleep 5; continue fi # Lit le flux evdev par enregistrements de 16 octets (struct input_event 32 bits : # timeval 8o + type 2o + code 2o + value 4o). od -> 16 octets décimaux (little-endian). count=0 last=0 while rec="$("$BB" dd bs=16 count=1 <&4 2>/dev/null | "$BB" od -An -tu1)"; do [ -z "$rec" ] && break # fd fermé/EOF -> respawn # shellcheck disable=SC2086 set -- $rec # $1..$16 [ "$#" -ge 13 ] || continue type=$(( $9 + ${10} * 256 )) code=$(( ${11} + ${12} * 256 )) val="${13}" [ "$DEBUG" = 1 ] && { echo "[ft] type=$type code=$code val=$val" >> "$LOG"; sync; } # On ne compte que les PRESS (val=1) EV_KEY (type=1) d'un bouton frontal. [ "$type" -eq 1 ] && [ "$val" -eq 1 ] || continue [ "$code" -eq "$BTN_A" ] || [ "$code" -eq "$BTN_B" ] || continue now=$(date +%s) [ $((now - last)) -gt 3 ] && count=0 # reset si > 3 s depuis le dernier appui count=$((count + 1)) last=$now echo "[watcher] appui $count/3" >> "$LOG"; sync [ "$count" -ge 3 ] && graceful_reboot done exec 4<&- echo "[watcher] lecteur input arrêté -> respawn" >> "$LOG"; sync sleep 1 done