Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ When the device is left idle it will enter light sleep. Light sleep turns the sc

After two minutes the device will go into deep sleep. The leds will turn completely off.

Settings > System > Shutdown timeout can optionally power off the device after a
configured period in deep sleep. The setting is Never by default.

---

## What about X feature?
Expand Down
1 change: 1 addition & 0 deletions makefile
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ ifeq ($(PLATFORM), h700)
# Limbo fix (AXP2202 needs an explicit software power-off)
cp ./workspace/$(PLATFORM)/poweroff_next/build/$(PLATFORM)/poweroff_next.elf ./build/SYSTEM/$(PLATFORM)/bin/poweroff_next
cp ./workspace/$(PLATFORM)/poweroff_next/build/$(PLATFORM)/reboot_next.elf ./build/SYSTEM/$(PLATFORM)/bin/reboot_next
cp ./workspace/$(PLATFORM)/poweroff_next/build/$(PLATFORM)/rtc_alarm.elf ./build/SYSTEM/$(PLATFORM)/bin/rtc_alarm
endif
ifneq (,$(filter $(PLATFORM),tg5040 tg5050 h700))
cp ./workspace/all/bootlogo/build/$(PLATFORM)/bootlogo.elf ./build/EXTRAS/Tools/$(PLATFORM)/Bootlogo.pak/
Expand Down
2 changes: 1 addition & 1 deletion skeleton/BASE/README.txt
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ ANBERNIC RG XX
----------------------------------------
Quicksave & auto-resume

NextUI will create a quicksave when powering off in-game. The next time you power on the device it will automatically resume from where you left off. A quicksave is created when powering off manually or automatically after a short sleep. On devices without a POWER button (eg. the Trimui Smart or M17) press the MENU button twice to put the device to sleep before flipping the POWER switch.
NextUI will create a quicksave when powering off in-game. The next time you power on the device it will automatically resume from where you left off. A quicksave is created when powering off manually or when the optional Shutdown timeout is reached in deep sleep. On devices without a POWER button (eg. the Trimui Smart or M17) press the MENU button twice to put the device to sleep before flipping the POWER switch.

----------------------------------------
Roms
Expand Down
119 changes: 118 additions & 1 deletion skeleton/SYSTEM/h700/bin/suspend
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,102 @@ sleep_retval=

asound_state_dir=/tmp/asound-suspend

shutdown_timeout_secs=${NEXTUI_SHUTDOWN_TIMEOUT_SECS:-0}
case "$shutdown_timeout_secs" in
''|*[!0-9]*) shutdown_timeout_secs=0 ;;
esac
rtc_dir=${NEXTUI_RTC_DIR:-}
rtc_device=${NEXTUI_RTC_DEVICE:-}
if [ -z "$rtc_dir" ] && [ -n "$rtc_device" ]; then
rtc_dir=/sys/class/rtc/${rtc_device##*/}
fi
if [ -z "$rtc_dir" ]; then
for rtc_candidate_dir in /sys/class/rtc/rtc*; do
[ -d "$rtc_candidate_dir" ] || continue
if [ "$(cat "$rtc_candidate_dir/name" 2>/dev/null)" = "sunxi-rtc" ]; then
rtc_dir=$rtc_candidate_dir
break
fi
done
fi
[ -n "$rtc_dir" ] || rtc_dir=/sys/class/rtc/rtc0
[ -n "$rtc_device" ] || rtc_device=/dev/${rtc_dir##*/}
rtc_since_epoch=$rtc_dir/since_epoch
rtc_wakeup=$rtc_dir/device/power/wakeup
rtc_name=$(cat "$rtc_dir/name" 2>/dev/null)
case "$rtc_name" in
sunxi-rtc) rtc_alarm_resolution=1 ;;
*) rtc_alarm_resolution=60 ;;
esac
if [ -n "${NEXTUI_RTC_RESOLUTION_SECONDS:-}" ]; then
rtc_alarm_resolution=$NEXTUI_RTC_RESOLUTION_SECONDS
fi
case "$rtc_alarm_resolution" in
''|*[!0-9]*|0) rtc_alarm_resolution=60 ;;
esac
rtc_alarm_tool=${NEXTUI_RTC_ALARM_TOOL:-$SYSTEM_PATH/bin/rtc_alarm}
shutdown_timeout_deadline=
shutdown_timeout_rtc_deadline=

arm_shutdown_timeout() {
[ "$shutdown_timeout_secs" -gt 0 ] || return 0
if [ ! -x "$rtc_alarm_tool" ]; then
>&2 echo "Shutdown timeout unavailable: $rtc_alarm_tool is not executable"
return 0
fi

rtc_wakeup_status=$(cat "$rtc_wakeup" 2>/dev/null)
>&2 echo "RTC wake source: name=${rtc_name:-unknown} device=$rtc_device wakeup=${rtc_wakeup_status:-unknown} resolution=${rtc_alarm_resolution}s"

rtc_now=$(cat "$rtc_since_epoch" 2>/dev/null)
case "$rtc_now" in
''|*[!0-9]*)
>&2 echo "Shutdown timeout unavailable: invalid RTC epoch '${rtc_now:-empty}'"
return 0
;;
esac

if ! shutdown_timeout_rtc_deadline=$(NEXTUI_RTC_DEVICE="$rtc_device" NEXTUI_RTC_WAKEUP="$rtc_wakeup" NEXTUI_RTC_RESOLUTION_SECONDS="$rtc_alarm_resolution" \
"$rtc_alarm_tool" arm "$shutdown_timeout_secs"); then
shutdown_timeout_rtc_deadline=
>&2 echo "Shutdown timeout unavailable: failed to replace RTC wake alarm"
return 0
fi

case "$shutdown_timeout_rtc_deadline" in
''|*[!0-9]*)
NEXTUI_RTC_DEVICE="$rtc_device" "$rtc_alarm_tool" clear || true
shutdown_timeout_rtc_deadline=
>&2 echo "Shutdown timeout unavailable: RTC helper returned an invalid deadline"
return 0
;;
esac

now=$(date +%s)
shutdown_timeout_deadline=$((now + shutdown_timeout_rtc_deadline - rtc_now))
>&2 echo "Shutdown timeout armed for $shutdown_timeout_secs seconds (RTC $rtc_now -> $shutdown_timeout_rtc_deadline)"
# Persist the armed deadline before an automatic wake and poweroff.
sync
}

clear_shutdown_timeout() {
[ -n "$shutdown_timeout_deadline" ] || return 0
if ! NEXTUI_RTC_DEVICE="$rtc_device" "$rtc_alarm_tool" clear; then
>&2 echo "Shutdown timeout warning: failed to clear RTC wake alarm after resume"
fi
}

shutdown_timeout_expired() {
[ -n "$shutdown_timeout_deadline" ] || return 1
rtc_now=$(cat "$rtc_since_epoch" 2>/dev/null)
case "$rtc_now" in
''|*[!0-9]*) ;;
*) [ "$rtc_now" -ge "$shutdown_timeout_rtc_deadline" ] && return 0 ;;
esac
now=$(date +%s)
[ "$now" -ge "$shutdown_timeout_deadline" ]
}

before() {
>&2 echo "Preparing for suspend..."
echo 0 > /sys/class/power_supply/axp2202-battery/work_led 2>/dev/null || true
Expand Down Expand Up @@ -82,6 +178,7 @@ after_async() {
}

before
arm_shutdown_timeout

hallkey=/sys/class/power_supply/axp2202-battery/hallkey
os_sleep=/sys/class/power_supply/axp2202-battery/os_sleep
Expand All @@ -99,7 +196,13 @@ while :; do
# it, but any non-zero value has the same effect.
# Non-SP kernels do not expose this attribute and already use the
# full USB-controller suspend path.
[ -w "$os_sleep" ] && printf '16' > "$os_sleep"
if [ -w "$os_sleep" ]; then
if printf '16' > "$os_sleep"; then
>&2 echo "Deep sleep policy: Super Standby (os_sleep=16)"
else
>&2 echo "Deep sleep policy warning: failed to enable Super Standby"
fi
fi

# Now issue suspend-to-ram command.
echo mem >/sys/power/state
Expand Down Expand Up @@ -131,6 +234,13 @@ while :; do
sleep 3
done

# An RTC timeout takes priority over the clamshell re-suspend loop so a
# closed device can power off without first lighting the display.
if [ $sleep_retval -eq 0 ] && shutdown_timeout_expired; then
sleep_retval=2
break
fi

# Clamshells: a pocketed power press wakes the kernel even with the
# lid shut. Only hand control back to the caller (which turns the
# screen on) once the lid is actually open; otherwise re-suspend.
Expand All @@ -144,6 +254,13 @@ while :; do
break
done

clear_shutdown_timeout
if [ $sleep_retval -eq 2 ]; then
>&2 echo "Shutdown timeout reached"
# Exit 2 is interpreted by PWR_deepSleep as a requested safe shutdown.
exit 2
fi

after_sync
after_async &

Expand Down
63 changes: 63 additions & 0 deletions skeleton/SYSTEM/tg5040/bin/suspend
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,60 @@ sleep_retval=

asound_state_dir=/tmp/asound-suspend

shutdown_timeout_secs=${NEXTUI_SHUTDOWN_TIMEOUT_SECS:-0}
case "$shutdown_timeout_secs" in
''|*[!0-9]*) shutdown_timeout_secs=0 ;;
esac
rtc_wakealarm=/sys/class/rtc/rtc0/wakealarm
shutdown_timeout_deadline=

rtc_alarm_available() {
if ! existing_alarm=$(cat "$rtc_wakealarm" 2>/dev/null); then
>&2 echo "Shutdown timeout unavailable: failed to read RTC wake alarm"
return 1
fi

case "$existing_alarm" in
'') return 0 ;;
*[!0-9]*)
>&2 echo "Shutdown timeout unavailable: invalid RTC wake alarm '$existing_alarm'"
return 1
;;
*)
>&2 echo "Shutdown timeout skipped: preserving existing RTC alarm $existing_alarm"
return 1
;;
esac
}

arm_shutdown_timeout() {
[ "$shutdown_timeout_secs" -gt 0 ] || return 0
if [ ! -w "$rtc_wakealarm" ]; then
>&2 echo "Shutdown timeout unavailable: RTC wake alarm is not writable"
return 0
fi
rtc_alarm_available || return 0

now=$(date +%s)
if printf '+%s\n' "$shutdown_timeout_secs" > "$rtc_wakealarm" 2>/dev/null; then
shutdown_timeout_deadline=$((now + shutdown_timeout_secs))
>&2 echo "Shutdown timeout armed for $shutdown_timeout_secs seconds"
else
>&2 echo "Shutdown timeout unavailable: failed to arm RTC wake alarm"
fi
}

clear_shutdown_timeout() {
[ -n "$shutdown_timeout_deadline" ] || return 0
printf '0\n' > "$rtc_wakealarm" 2>/dev/null || true
}

shutdown_timeout_expired() {
[ -n "$shutdown_timeout_deadline" ] || return 1
now=$(date +%s)
[ "$now" -ge "$shutdown_timeout_deadline" ]
}

before() {
>&2 echo "Preparing for suspend..."

Expand Down Expand Up @@ -59,6 +113,7 @@ after() {
}

before
arm_shutdown_timeout

>&2 echo "Suspending..."
sleep_max_tries=5
Expand Down Expand Up @@ -95,6 +150,14 @@ for i in $(seq 1 $sleep_max_tries); do
sleep 3
done

if shutdown_timeout_expired; then
clear_shutdown_timeout
>&2 echo "Shutdown timeout reached"
# Exit 2 is interpreted by PWR_deepSleep as a requested safe shutdown.
exit 2
fi
clear_shutdown_timeout

# Resume services in background to reduce UI latency
after &

Expand Down
63 changes: 63 additions & 0 deletions skeleton/SYSTEM/tg5050/bin/suspend
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,60 @@ sleep_retval=

asound_state_dir=/tmp/asound-suspend

shutdown_timeout_secs=${NEXTUI_SHUTDOWN_TIMEOUT_SECS:-0}
case "$shutdown_timeout_secs" in
''|*[!0-9]*) shutdown_timeout_secs=0 ;;
esac
rtc_wakealarm=/sys/class/rtc/rtc0/wakealarm
shutdown_timeout_deadline=

rtc_alarm_available() {
if ! existing_alarm=$(cat "$rtc_wakealarm" 2>/dev/null); then
>&2 echo "Shutdown timeout unavailable: failed to read RTC wake alarm"
return 1
fi

case "$existing_alarm" in
'') return 0 ;;
*[!0-9]*)
>&2 echo "Shutdown timeout unavailable: invalid RTC wake alarm '$existing_alarm'"
return 1
;;
*)
>&2 echo "Shutdown timeout skipped: preserving existing RTC alarm $existing_alarm"
return 1
;;
esac
}

arm_shutdown_timeout() {
[ "$shutdown_timeout_secs" -gt 0 ] || return 0
if [ ! -w "$rtc_wakealarm" ]; then
>&2 echo "Shutdown timeout unavailable: RTC wake alarm is not writable"
return 0
fi
rtc_alarm_available || return 0

now=$(date +%s)
if printf '+%s\n' "$shutdown_timeout_secs" > "$rtc_wakealarm" 2>/dev/null; then
shutdown_timeout_deadline=$((now + shutdown_timeout_secs))
>&2 echo "Shutdown timeout armed for $shutdown_timeout_secs seconds"
else
>&2 echo "Shutdown timeout unavailable: failed to arm RTC wake alarm"
fi
}

clear_shutdown_timeout() {
[ -n "$shutdown_timeout_deadline" ] || return 0
printf '0\n' > "$rtc_wakealarm" 2>/dev/null || true
}

shutdown_timeout_expired() {
[ -n "$shutdown_timeout_deadline" ] || return 1
now=$(date +%s)
[ "$now" -ge "$shutdown_timeout_deadline" ]
}

before() {
>&2 echo "Preparing for suspend..."

Expand Down Expand Up @@ -59,6 +113,7 @@ after() {
}

before
arm_shutdown_timeout

>&2 echo "Suspending..."
sleep_max_tries=5
Expand All @@ -77,6 +132,14 @@ for i in $(seq 1 $sleep_max_tries); do
sleep 3
done

if shutdown_timeout_expired; then
clear_shutdown_timeout
>&2 echo "Shutdown timeout reached"
# Exit 2 is interpreted by PWR_deepSleep as a requested safe shutdown.
exit 2
fi
clear_shutdown_timeout

# Resume services in background to reduce UI latency
after &

Expand Down
Loading