Add battery monitoring and LED control features for M9S device

This commit is contained in:
Miguel Fuertes committed 2025-10-21 20:56:15 +02:00
1 parent e451099d6d
commit 4c162d3576
9 files changed
+275 -103

No files matched your search

+3
View File
@@ -15,6 +15,8 @@ CONFIG_PACKAGE_bash=y
CONFIG_PACKAGE_cgi-io=y
CONFIG_PACKAGE_dbus=y
CONFIG_PACKAGE_glib2=y
CONFIG_PACKAGE_inotifywait=y
CONFIG_PACKAGE_inotifywatch=y
CONFIG_PACKAGE_ip-tiny=y
CONFIG_PACKAGE_kmod-crypto-kpp=y
CONFIG_PACKAGE_kmod-crypto-lib-chacha20=y
@@ -30,6 +32,7 @@ CONFIG_PACKAGE_libdbus=y
CONFIG_PACKAGE_libexpat=y
CONFIG_PACKAGE_libfdisk=y
CONFIG_PACKAGE_libffi=y
CONFIG_PACKAGE_libinotifytools=y
CONFIG_PACKAGE_libiwinfo=y
CONFIG_PACKAGE_libiwinfo-data=y
CONFIG_PACKAGE_liblua=y
@@ -1,6 +1,6 @@
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8916-generic-m9s.dts
@@ -0,0 +1,118 @@
@@ -0,0 +1,126 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/dts-v1/;
@@ -119,3 +119,11 @@
+&gpio_leds_default {
+ pins = "gpio0", "gpio1", "gpio72", "gpio73", "gpio84", "gpio85";
+};
+
+&pm8916_0 {
+ pon@800 {
+ watchdog {
+ status = "disabled";
+ };
+ };
+};
@@ -9,22 +9,9 @@
lockfile="/tmp/toff.lock"
delay=1
maybe_notify_display_shutdown() {
. /lib/functions.sh
config_load system
config_get FIFO display fifo "/var/run/display.fifo"
[ -p "$FIFO" ] && {
echo "shutdown" > "$FIFO" 2>/dev/null;
sleep 1;
}
}
shutdown() {
logger -t poweroff "Powering off..."
# maybe_notify_display_shutdown
sync
/sbin/poweroff
}
+8 -2
View File
@@ -11,7 +11,7 @@ define Package/ledcontrol
SECTION:=utils
CATEGORY:=Utilities
TITLE:=Simple LED control utility
DEPENDS:=
DEPENDS:=+kmod-button-hotplug +inotifywait
endef
define Package/ledcontrol/description
@@ -25,13 +25,19 @@ endef
define Package/ledcontrol/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) ./files/ledcontrol $(1)/usr/sbin/
$(INSTALL_BIN) ./files/ledcontrol.sh $(1)/usr/sbin/
$(INSTALL_DIR) $(1)/etc/hotplug.d/ieee80211
$(INSTALL_DATA) ./files/99-wifi-led $(1)/etc/hotplug.d/ieee80211/
$(INSTALL_DIR) $(1)/etc/hotplug.d/iface
$(INSTALL_DATA) ./files/99-modem-led $(1)/etc/hotplug.d/iface/
$(INSTALL_DIR) $(1)/etc/hotplug.d/button
$(INSTALL_DATA) ./files/50-battery-show $(1)/etc/hotplug.d/button/
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_DATA) ./files/battery-monitor.init $(1)/etc/init.d/battery-monitor
endef
$(eval $(call BuildPackage,ledcontrol))
+16
View File
@@ -0,0 +1,16 @@
#!/bin/sh
# /etc/hotplug.d/button/50-battery-show
[ "$BUTTON" = "power" ] || exit 0
[ "$ACTION" = "pressed" ] || exit 0
# Solo actuar si NO está cargando
charging=$(cat /sys/class/power_supply/pm8916-lbc-chgr/online 2>/dev/null || echo 0)
if [ "$charging" = "0" ]; then
# Enviar SIGUSR1 al daemon para mostrar batería
[ -f /var/run/battery-monitor.pid ] && {
kill -USR1 $(cat /var/run/battery-monitor.pid) 2>/dev/null
logger -t button-battery "SIGUSR1 sent to battery-monitor"
}
fi
+2
View File
@@ -4,10 +4,12 @@
case "$ACTION:$INTERFACE" in
ifup:modem)
ledcontrol wan red off 2>/dev/null || true
ledcontrol wan on
logger -t modem-led "Modem UP - Green LED ON"
;;
ifdown:modem)
ledcontrol wan red on 2>/dev/null || true
ledcontrol wan off
logger -t modem-led "Modem DOWN - Green LED OFF"
;;
@@ -0,0 +1,101 @@
#!/bin/sh /etc/rc.common
# /etc/init.d/battery-monitor
START=99
STOP=01
CHARGER_FILE="/sys/class/power_supply/pm8916-lbc-chgr/online"
BMS_PATH="/sys/class/power_supply/pm8916-bms-vm"
get_capacity() {
local voltage=$(cat $BMS_PATH/voltage_now 2>/dev/null)
local vmax=$(cat $BMS_PATH/voltage_max_design 2>/dev/null)
local vmin=$(cat $BMS_PATH/voltage_min_design 2>/dev/null)
if [ -n "$voltage" ] && [ -n "$vmax" ] && [ -n "$vmin" ]; then
awk -v v="$voltage" -v vmax="$vmax" -v vmin="$vmin" \
'BEGIN {pct = ((v - vmin) / (vmax - vmin)) * 100;
if (pct < 0) pct = 0;
if (pct > 100) pct = 100;
printf "%.0f", pct}'
else
echo "50"
fi
}
show_battery_temp() {
local capacity=$(get_capacity)
ledcontrol charging red off 2>/dev/null
ledcontrol charging green off 2>/dev/null
if [ "$capacity" -lt 20 ]; then
ledcontrol charging red on 2>/dev/null
elif [ "$capacity" -lt 50 ]; then
ledcontrol charging red on 2>/dev/null
ledcontrol charging green on 2>/dev/null
else
ledcontrol charging green on 2>/dev/null
fi
logger -t battery-monitor "SIGUSR1: Showing ${capacity}%"
sleep 2
update_led
}
update_led() {
local charging=$(cat $CHARGER_FILE 2>/dev/null || echo 0)
if [ "$charging" = "1" ]; then
local capacity=$(get_capacity)
ledcontrol charging red off 2>/dev/null
ledcontrol charging green off 2>/dev/null
if [ "$capacity" -ge 95 ]; then
ledcontrol charging green on 2>/dev/null
logger -t battery-monitor "Charging complete: ${capacity}%"
elif [ "$capacity" -ge 50 ]; then
ledcontrol charging red blink 2>/dev/null &
ledcontrol charging green blink 2>/dev/null &
logger -t battery-monitor "Charging: ${capacity}%"
else
ledcontrol charging red blink 2>/dev/null
logger -t battery-monitor "Charging low: ${capacity}%"
fi
else
ledcontrol charging red off 2>/dev/null
ledcontrol charging green off 2>/dev/null
fi
}
start() {
update_led
(
trap 'show_battery_temp' USR1
while true; do
inotifywait -qq -e modify $CHARGER_FILE 2>/dev/null
sleep 1
update_led
done
) &
echo $! > /var/run/battery-monitor.pid
}
stop() {
[ -f /var/run/battery-monitor.pid ] && {
kill $(cat /var/run/battery-monitor.pid) 2>/dev/null
rm -f /var/run/battery-monitor.pid
}
ledcontrol charging red blink 2>/dev/null
ledcontrol charging green blink 2>/dev/null
logger -t shutdown-led "BAT LED blinking amber - shutdown"
return 0
}
-87
View File
@@ -1,87 +0,0 @@
#!/bin/sh
# LED Control Utility for OpenWrt
# Usage: ledcontrol <color> <on|off|blink|blink_fast>
set -e
COLOR="$1"
ACTION="$2"
# LED base path
LED_BASE="/sys/class/leds"
# Find LED by color
find_led() {
local color="$1"
local led_path
# Search for LED containing the color in name
led_path=$(find "$LED_BASE" -maxdepth 1 -type l -iname "*:${color}:*" 2>/dev/null | head -n 1)
if [ -z "$led_path" ]; then
# Try without colons
led_path=$(find "$LED_BASE" -maxdepth 1 -type l -iname "*${color}*" 2>/dev/null | head -n 1)
fi
if [ -z "$led_path" ]; then
logger -t ledcontrol "LED color '$color' not found"
echo "[!] LED color '$color' not found" >&2
echo "[*] Available LEDs:" >&2
ls -1 "$LED_BASE" | sed 's/^/ /' >&2
return 1
fi
echo "$led_path"
}
# Set LED state
set_led() {
local led_path="$1"
local action="$2"
case "$action" in
on)
echo none > "$led_path/trigger"
echo 1 > "$led_path/brightness"
;;
off)
echo none > "$led_path/trigger"
echo 0 > "$led_path/brightness"
;;
blink)
echo timer > "$led_path/trigger"
echo 500 > "$led_path/delay_on"
echo 500 > "$led_path/delay_off"
;;
blink_fast)
echo timer > "$led_path/trigger"
echo 100 > "$led_path/delay_on"
echo 100 > "$led_path/delay_off"
;;
*)
logger -t ledcontrol "Invalid action: $action"
echo "[!] Invalid action: $action" >&2
echo "[*] Valid actions: on, off, blink, blink_fast" >&2
return 1
;;
esac
}
# Main
if [ -z "$COLOR" ] || [ -z "$ACTION" ]; then
echo "Usage: ledcontrol <color> <on|off|blink|blink_fast>" >&2
echo "" >&2
echo "Available LEDs:" >&2
ls -1 "$LED_BASE" 2>/dev/null | sed 's/^/ /' >&2
exit 1
fi
LED_PATH=$(find_led "$COLOR") || exit 1
LED_NAME=$(basename "$LED_PATH")
if set_led "$LED_PATH" "$ACTION"; then
logger -t ledcontrol "LED '$LED_NAME' set to '$ACTION'"
echo "[+] LED '$COLOR' set to '$ACTION'"
else
exit 1
fi
+136
View File
@@ -0,0 +1,136 @@
#!/bin/sh
# LED Control Utility for OpenWrt
# Usage: ledcontrol <function> [color] <on|off|blink|blink_fast>
# Examples:
# ledcontrol wan on (MiFi with green:wan)
# ledcontrol wlan on (MiFi with green:wlan)
# ledcontrol blue on (Dongle with blue LED)
# ledcontrol wan green on (Explicit color override)
set -e
# Parse arguments (support both 2 and 3 arg syntax)
if [ $# -eq 2 ]; then
# 2 args: <function_or_color> <action>
SEARCH_KEY="$1"
COLOR=""
ACTION="$2"
elif [ $# -eq 3 ]; then
# 3 args: <function> <color> <action>
SEARCH_KEY="$1"
COLOR="$2"
ACTION="$3"
else
echo "Usage: ledcontrol <function|color> <on|off|blink|blink_fast>" >&2
echo " or: ledcontrol <function> <color> <on|off|blink|blink_fast>" >&2
echo "" >&2
echo "Examples:" >&2
echo " ledcontrol wan on # Auto-detect color (green:wan or blue)" >&2
echo " ledcontrol wlan off # Auto-detect color (green:wlan or blue)" >&2
echo " ledcontrol blue blink # Specific color LED" >&2
echo " ledcontrol wan green on # Explicit function+color" >&2
echo "" >&2
echo "Available LEDs:" >&2
ls -1 /sys/class/leds 2>/dev/null | grep -v "^mmc" | sed 's/^/ /' >&2
exit 1
fi
LED_BASE="/sys/class/leds"
# Find LED with smart matching
find_led() {
local search="$1"
local color="$2"
local led_path
# Priority 1: Exact match with color prefix (green:wan, red:wlan)
if [ -n "$color" ]; then
led_path=$(find "$LED_BASE" -maxdepth 1 -type l -name "${color}:${search}" 2>/dev/null | head -n 1)
if [ -n "$led_path" ]; then
echo "$led_path"
return 0
fi
fi
# Priority 2: Function-based match (wan, wlan, charging)
# Prefer green for status, fallback to any color
for clr in green blue red amber; do
led_path=$(find "$LED_BASE" -maxdepth 1 -type l -name "${clr}:${search}" 2>/dev/null | head -n 1)
if [ -n "$led_path" ]; then
echo "$led_path"
return 0
fi
done
# Priority 3: Color-only match (blue, green, red)
led_path=$(find "$LED_BASE" -maxdepth 1 -type l -name "${search}" 2>/dev/null | head -n 1)
if [ -n "$led_path" ]; then
echo "$led_path"
return 0
fi
# Priority 4: Case-insensitive partial match
led_path=$(find "$LED_BASE" -maxdepth 1 -type l | grep -i "${search}" | grep -v "mmc" | head -n 1)
if [ -n "$led_path" ]; then
echo "$led_path"
return 0
fi
logger -t ledcontrol "LED '$search' not found"
echo "[!] LED '$search' not found" >&2
echo "[*] Available LEDs:" >&2
ls -1 "$LED_BASE" 2>/dev/null | grep -v "^mmc" | sed 's/^/ /' >&2
return 1
}
# Set LED state
set_led() {
local led_path="$1"
local action="$2"
case "$action" in
on)
echo none > "$led_path/trigger" 2>/dev/null || true
echo 1 > "$led_path/brightness"
;;
off)
echo none > "$led_path/trigger" 2>/dev/null || true
echo 0 > "$led_path/brightness"
;;
blink)
echo timer > "$led_path/trigger" 2>/dev/null || {
echo "[!] Blink not supported, setting ON" >&2
echo 1 > "$led_path/brightness"
return 0
}
echo 500 > "$led_path/delay_on" 2>/dev/null || true
echo 500 > "$led_path/delay_off" 2>/dev/null || true
;;
blink_fast)
echo timer > "$led_path/trigger" 2>/dev/null || {
echo "[!] Blink not supported, setting ON" >&2
echo 1 > "$led_path/brightness"
return 0
}
echo 100 > "$led_path/delay_on" 2>/dev/null || true
echo 100 > "$led_path/delay_off" 2>/dev/null || true
;;
*)
logger -t ledcontrol "Invalid action: $action"
echo "[!] Invalid action: $action" >&2
echo "[*] Valid actions: on, off, blink, blink_fast" >&2
return 1
;;
esac
}
# Main
LED_PATH=$(find_led "$SEARCH_KEY" "$COLOR") || exit 1
LED_NAME=$(basename "$LED_PATH")
if set_led "$LED_PATH" "$ACTION"; then
logger -t ledcontrol "LED '$LED_NAME' set to '$ACTION'"
echo "[+] LED '$LED_NAME' set to '$ACTION'"
else
exit 1
fi