mirror of
https://github.com/koreader/koreader.git
synced 2025-12-13 20:36:53 +01:00
Autosuspend: add autostandby (#8815)
Allows the device to go into standby (if available in `/sys/power/state`) to save power. Adds an entry in the device menu to tune the timeout for standby. (Shows total standby- and suspend-time in system statistics.)
This commit is contained in:
@@ -147,6 +147,11 @@ function ReaderCoptListener:onResume()
|
||||
self:headerRefresh()
|
||||
end
|
||||
|
||||
function ReaderCoptListener:onLeaveStandby()
|
||||
self:onResume()
|
||||
self:onOutOfScreenSaver()
|
||||
end
|
||||
|
||||
function ReaderCoptListener:onOutOfScreenSaver()
|
||||
if not self._delayed_screensaver then
|
||||
return
|
||||
@@ -159,6 +164,7 @@ end
|
||||
-- Unschedule on these events
|
||||
ReaderCoptListener.onCloseDocument = ReaderCoptListener.unscheduleHeaderRefresh
|
||||
ReaderCoptListener.onSuspend = ReaderCoptListener.unscheduleHeaderRefresh
|
||||
ReaderCoptListener.onEnterStandby = ReaderCoptListener.unscheduleHeaderRefresh
|
||||
|
||||
function ReaderCoptListener:setAndSave(setting, property, value)
|
||||
self.ui.document._document:setIntProperty(property, value)
|
||||
|
||||
@@ -2432,10 +2432,17 @@ function ReaderFooter:onOutOfScreenSaver()
|
||||
self:rescheduleFooterAutoRefreshIfNeeded()
|
||||
end
|
||||
|
||||
function ReaderFooter:onLeaveStandby()
|
||||
self:onResume()
|
||||
self:onOutOfScreenSaver()
|
||||
end
|
||||
|
||||
function ReaderFooter:onSuspend()
|
||||
self:unscheduleFooterAutoRefresh()
|
||||
end
|
||||
|
||||
ReaderFooter.onEnterStandby = ReaderFooter.onSuspend
|
||||
|
||||
function ReaderFooter:onCloseDocument()
|
||||
self:unscheduleFooterAutoRefresh()
|
||||
end
|
||||
|
||||
@@ -6,6 +6,7 @@ This module defines stubs for common methods.
|
||||
|
||||
local DataStorage = require("datastorage")
|
||||
local Geom = require("ui/geometry")
|
||||
local TimeVal = require("ui/timeval")
|
||||
local logger = require("logger")
|
||||
local util = require("util")
|
||||
local _ = require("gettext")
|
||||
@@ -67,6 +68,12 @@ local Device = {
|
||||
canUseWAL = yes, -- requires mmap'ed I/O on the target FS
|
||||
canRestart = yes,
|
||||
canSuspend = yes,
|
||||
canStandby = no,
|
||||
canPowerSaveWhileCharging = no,
|
||||
total_standby_tv = TimeVal.zero, -- total time spent in standby
|
||||
last_standby_tv = TimeVal.zero,
|
||||
total_suspend_tv = TimeVal.zero, -- total time spent in suspend
|
||||
last_suspend_tv = TimeVal.zero,
|
||||
canReboot = no,
|
||||
canPowerOff = no,
|
||||
canAssociateFileExtensions = no,
|
||||
@@ -238,7 +245,7 @@ end
|
||||
function Device:rescheduleSuspend()
|
||||
local UIManager = require("ui/uimanager")
|
||||
UIManager:unschedule(self.suspend)
|
||||
UIManager:scheduleIn(self.suspend_wait_timeout, self.suspend)
|
||||
UIManager:scheduleIn(self.suspend_wait_timeout, self.suspend, self)
|
||||
end
|
||||
|
||||
-- Only used on platforms where we handle suspend ourselves.
|
||||
@@ -430,6 +437,9 @@ function Device:saveSettings() end
|
||||
function Device:simulateSuspend() end
|
||||
function Device:simulateResume() end
|
||||
|
||||
-- Put device into standby, input devices (buttons, touchscreen ...) stay enabled
|
||||
function Device:standby(max_duration) end
|
||||
|
||||
--[[--
|
||||
Device specific method for performing haptic feedback.
|
||||
|
||||
|
||||
@@ -24,6 +24,36 @@ local function koboEnableWifi(toggle)
|
||||
end
|
||||
end
|
||||
|
||||
-- checks if standby is available on the device
|
||||
local function checkStandby()
|
||||
logger.dbg("Kobo: checking if standby is possible ...")
|
||||
local f = io.open("/sys/power/state")
|
||||
if not f then
|
||||
return no
|
||||
end
|
||||
local mode = f:read()
|
||||
logger.dbg("Kobo: available power states", mode)
|
||||
if mode:find("standby") then
|
||||
logger.dbg("Kobo: standby state allowed")
|
||||
return yes
|
||||
end
|
||||
logger.dbg("Kobo: standby state not allowed")
|
||||
return no
|
||||
end
|
||||
|
||||
local function writeToSys(val, file)
|
||||
local f = io.open(file, "we")
|
||||
if not f then
|
||||
logger.err("Cannot open:", file)
|
||||
return
|
||||
end
|
||||
local re, err_msg, err_code = f:write(val, "\n")
|
||||
if not re then
|
||||
logger.err("Error writing value to file:", val, file, err_msg, err_code)
|
||||
end
|
||||
f:close()
|
||||
return re
|
||||
end
|
||||
|
||||
local Kobo = Generic:new{
|
||||
model = "Kobo",
|
||||
@@ -32,9 +62,9 @@ local Kobo = Generic:new{
|
||||
hasOTAUpdates = yes,
|
||||
hasFastWifiStatusQuery = yes,
|
||||
hasWifiManager = yes,
|
||||
canStandby = no, -- will get updated by checkStandby()
|
||||
canReboot = yes,
|
||||
canPowerOff = yes,
|
||||
|
||||
-- most Kobos have X/Y switched for the touch screen
|
||||
touch_switch_xy = true,
|
||||
-- most Kobos have also mirrored X coordinates
|
||||
@@ -75,6 +105,8 @@ local Kobo = Generic:new{
|
||||
isSMP = no,
|
||||
-- Device supports "eclipse" waveform modes (i.e., optimized for nightmode).
|
||||
hasEclipseWfm = no,
|
||||
|
||||
unexpected_wakeup_count = 0
|
||||
}
|
||||
|
||||
-- Kobo Touch:
|
||||
@@ -517,6 +549,11 @@ function Kobo:init()
|
||||
|
||||
-- Only enable a single core on startup
|
||||
self:enableCPUCores(1)
|
||||
|
||||
self.canStandby = checkStandby()
|
||||
if self.canStandby() and (self:isMk7() or self:isSunxi()) then
|
||||
self.canPowerSaveWhileCharging = yes
|
||||
end
|
||||
end
|
||||
|
||||
function Kobo:setDateTime(year, month, day, hour, min, sec)
|
||||
@@ -684,8 +721,7 @@ local function getProductId()
|
||||
return product_id
|
||||
end
|
||||
|
||||
local unexpected_wakeup_count = 0
|
||||
local function check_unexpected_wakeup()
|
||||
function Kobo:checkUnexpectedWakeup()
|
||||
local UIManager = require("ui/uimanager")
|
||||
-- just in case other events like SleepCoverClosed also scheduled a suspend
|
||||
UIManager:unschedule(Kobo.suspend)
|
||||
@@ -700,11 +736,11 @@ local function check_unexpected_wakeup()
|
||||
logger.info("Kobo suspend: putting device back to sleep.")
|
||||
-- Most wakeup actions are linear, but we need some leeway for the
|
||||
-- poweroff action to send out close events to all requisite widgets.
|
||||
UIManager:scheduleIn(30, Kobo.suspend)
|
||||
UIManager:scheduleIn(30, Kobo.suspend, self)
|
||||
else
|
||||
logger.dbg("Kobo suspend: checking unexpected wakeup:",
|
||||
unexpected_wakeup_count)
|
||||
if unexpected_wakeup_count == 0 or unexpected_wakeup_count > 20 then
|
||||
self.unexpected_wakeup_count)
|
||||
if self.unexpected_wakeup_count == 0 or self.unexpected_wakeup_count > 20 then
|
||||
-- Don't put device back to sleep under the following two cases:
|
||||
-- 1. a resume event triggered Kobo:resume() function
|
||||
-- 2. trying to put device back to sleep more than 20 times after unexpected wakeup
|
||||
@@ -715,17 +751,42 @@ local function check_unexpected_wakeup()
|
||||
end
|
||||
|
||||
logger.err("Kobo suspend: putting device back to sleep. Unexpected wakeups:",
|
||||
unexpected_wakeup_count)
|
||||
Kobo.suspend()
|
||||
self.unexpected_wakeup_count)
|
||||
Kobo:suspend()
|
||||
end
|
||||
end
|
||||
|
||||
function Kobo:getUnexpectedWakeup() return unexpected_wakeup_count end
|
||||
function Kobo:getUnexpectedWakeup() return self.unexpected_wakeup_count end
|
||||
|
||||
--- The function to put the device into standby, with enabled touchscreen.
|
||||
-- max_duration ... maximum time for the next standby, can wake earlier (e.g. Tap, Button ...)
|
||||
function Kobo:standby(max_duration)
|
||||
-- just for wake up, dummy function
|
||||
local function dummy() end
|
||||
|
||||
if max_duration then
|
||||
self.wakeup_mgr:addTask(max_duration, dummy)
|
||||
end
|
||||
|
||||
local TimeVal = require("ui/timeval")
|
||||
local standby_time_tv = TimeVal:boottime_or_realtime_coarse()
|
||||
|
||||
local ret = writeToSys("standby", "/sys/power/state")
|
||||
|
||||
self.last_standby_tv = TimeVal:boottime_or_realtime_coarse() - standby_time_tv
|
||||
self.total_standby_tv = self.total_standby_tv + self.last_standby_tv
|
||||
|
||||
logger.info("Kobo suspend: asked the kernel to put subsystems to standby, ret:", ret)
|
||||
|
||||
if max_duration then
|
||||
self.wakeup_mgr:removeTask(nil, nil, dummy)
|
||||
end
|
||||
end
|
||||
|
||||
function Kobo:suspend()
|
||||
logger.info("Kobo suspend: going to sleep . . .")
|
||||
local UIManager = require("ui/uimanager")
|
||||
UIManager:unschedule(check_unexpected_wakeup)
|
||||
UIManager:unschedule(self.checkUnexpectedWakeup)
|
||||
local f, re, err_msg, err_code
|
||||
-- NOTE: Sleep as little as possible here, sleeping has a tendency to make
|
||||
-- everything mysteriously hang...
|
||||
@@ -762,17 +823,8 @@ function Kobo:suspend()
|
||||
-- NOTE: Sets gSleep_Mode_Suspend to 1. Used as a flag throughout the
|
||||
-- kernel to suspend/resume various subsystems
|
||||
-- cf. kernel/power/main.c @ L#207
|
||||
f = io.open("/sys/power/state-extended", "we")
|
||||
if not f then
|
||||
logger.err("Cannot open /sys/power/state-extended for writing!")
|
||||
return false
|
||||
end
|
||||
re, err_msg, err_code = f:write("1\n")
|
||||
f:close()
|
||||
logger.info("Kobo suspend: asked the kernel to put subsystems to sleep, ret:", re)
|
||||
if not re then
|
||||
logger.err('write error: ', err_msg, err_code)
|
||||
end
|
||||
local ret = writeToSys("1", "/sys/power/state-extended")
|
||||
logger.info("Kobo suspend: asked the kernel to put subsystems to sleep, ret:", ret)
|
||||
|
||||
util.sleep(2)
|
||||
logger.info("Kobo suspend: waited for 2s because of reasons...")
|
||||
@@ -813,15 +865,23 @@ function Kobo:suspend()
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local TimeVal = require("ui/timeval")
|
||||
local suspend_time_tv = TimeVal:boottime_or_realtime_coarse()
|
||||
|
||||
re, err_msg, err_code = f:write("mem\n")
|
||||
if not re then
|
||||
logger.err("write error: ", err_msg, err_code)
|
||||
end
|
||||
f:close()
|
||||
|
||||
-- NOTE: At this point, we *should* be in suspend to RAM, as such,
|
||||
-- execution should only resume on wakeup...
|
||||
|
||||
self.last_suspend_tv = TimeVal:boottime_or_realtime_coarse() - suspend_time_tv
|
||||
self.total_suspend_tv = self.total_suspend_tv + self.last_suspend_tv
|
||||
|
||||
logger.info("Kobo suspend: ZzZ ZzZ ZzZ? Write syscall returned: ", re)
|
||||
if not re then
|
||||
logger.err('write error: ', err_msg, err_code)
|
||||
end
|
||||
f:close()
|
||||
-- NOTE: Ideally, we'd need a way to warn the user that suspending
|
||||
-- gloriously failed at this point...
|
||||
-- We can safely assume that just from a non-zero return code, without
|
||||
@@ -849,44 +909,32 @@ function Kobo:suspend()
|
||||
-- things tidy and easier to follow
|
||||
|
||||
-- Kobo:resume() will reset unexpected_wakeup_count = 0 to signal an
|
||||
-- expected wakeup, which gets checked in check_unexpected_wakeup().
|
||||
unexpected_wakeup_count = unexpected_wakeup_count + 1
|
||||
-- expected wakeup, which gets checked in checkUnexpectedWakeup().
|
||||
self.unexpected_wakeup_count = self.unexpected_wakeup_count + 1
|
||||
-- assuming Kobo:resume() will be called in 15 seconds
|
||||
logger.dbg("Kobo suspend: scheduling unexpected wakeup guard")
|
||||
UIManager:scheduleIn(15, check_unexpected_wakeup)
|
||||
UIManager:scheduleIn(15, self.checkUnexpectedWakeup, self)
|
||||
end
|
||||
|
||||
function Kobo:resume()
|
||||
logger.info("Kobo resume: clean up after wakeup")
|
||||
-- reset unexpected_wakeup_count ASAP
|
||||
unexpected_wakeup_count = 0
|
||||
require("ui/uimanager"):unschedule(check_unexpected_wakeup)
|
||||
self.unexpected_wakeup_count = 0
|
||||
require("ui/uimanager"):unschedule(self.checkUnexpectedWakeup)
|
||||
|
||||
-- Now that we're up, unflag subsystems for suspend...
|
||||
-- NOTE: Sets gSleep_Mode_Suspend to 0. Used as a flag throughout the
|
||||
-- kernel to suspend/resume various subsystems
|
||||
-- cf. kernel/power/main.c @ L#207
|
||||
local f = io.open("/sys/power/state-extended", "we")
|
||||
if not f then
|
||||
logger.err("cannot open /sys/power/state-extended for writing!")
|
||||
return false
|
||||
end
|
||||
local re, err_msg, err_code = f:write("0\n")
|
||||
f:close()
|
||||
logger.info("Kobo resume: unflagged kernel subsystems for resume, ret:", re)
|
||||
if not re then
|
||||
logger.err('write error: ', err_msg, err_code)
|
||||
end
|
||||
|
||||
local ret = writeToSys("0", "/sys/power/state-extended")
|
||||
logger.info("Kobo resume: unflagged kernel subsystems for resume, ret:", ret)
|
||||
|
||||
-- HACK: wait a bit (0.1 sec) for the kernel to catch up
|
||||
util.usleep(100000)
|
||||
-- cf. #1862, I can reliably break IR touch input on resume...
|
||||
-- cf. also #1943 for the rationale behind applying this workaorund in every case...
|
||||
f = io.open("/sys/devices/virtual/input/input1/neocmd", "we")
|
||||
if f ~= nil then
|
||||
f:write("a\n")
|
||||
f:close()
|
||||
end
|
||||
writeToSys("a", "/sys/devices/virtual/input/input1/neocmd")
|
||||
|
||||
-- A full suspend may have toggled the LED off.
|
||||
self:setupChargingLED()
|
||||
|
||||
@@ -66,6 +66,7 @@ local Device = Generic:new{
|
||||
hasEinkScreen = no,
|
||||
hasSystemFonts = yes,
|
||||
canSuspend = no,
|
||||
canStandby = yes,
|
||||
startTextInput = SDL.startTextInput,
|
||||
stopTextInput = SDL.stopTextInput,
|
||||
canOpenLink = getLinkOpener,
|
||||
|
||||
@@ -1179,6 +1179,15 @@ function UIManager:broadcastEvent(event)
|
||||
end
|
||||
end
|
||||
|
||||
function UIManager:getNextTaskTimes(count)
|
||||
count = count or 1
|
||||
local times = {}
|
||||
for i = 1, math.min(count, #self._task_queue) do
|
||||
times[i] = UIManager._task_queue[i].time - TimeVal:now()
|
||||
end
|
||||
return times
|
||||
end
|
||||
|
||||
function UIManager:_checkTasks()
|
||||
self._now = TimeVal:now()
|
||||
local wait_until = nil
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
local _ = require("gettext")
|
||||
return {
|
||||
name = "autosuspend",
|
||||
fullname = _("Auto suspend"),
|
||||
description = _([[Suspends the device after a period of inactivity.]]),
|
||||
fullname = _("Auto power save"),
|
||||
description = _([["Puts the device into standby, suspend or power off after specified periods of inactivity."]]),
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ if not Device:isCervantes() and
|
||||
return { disabled = true, }
|
||||
end
|
||||
|
||||
local Event = require("ui/event")
|
||||
local NetworkMgr = require("ui/network/manager")
|
||||
local PluginShare = require("pluginshare")
|
||||
local TimeVal = require("ui/timeval")
|
||||
local UIManager = require("ui/uimanager")
|
||||
@@ -22,17 +24,23 @@ local T = require("ffi/util").template
|
||||
|
||||
local default_autoshutdown_timeout_seconds = 3*24*60*60 -- three days
|
||||
local default_auto_suspend_timeout_seconds = 15*60 -- 15 minutes
|
||||
local default_auto_standby_timeout_seconds = 4 -- 4 seconds; should be safe on Kobo/Sage
|
||||
|
||||
local AutoSuspend = WidgetContainer:new{
|
||||
name = "autosuspend",
|
||||
is_doc_only = false,
|
||||
autoshutdown_timeout_seconds = default_autoshutdown_timeout_seconds,
|
||||
auto_suspend_timeout_seconds = default_auto_suspend_timeout_seconds,
|
||||
auto_standby_timeout_seconds = default_auto_standby_timeout_seconds,
|
||||
last_action_tv = TimeVal.zero,
|
||||
standby_prevented = false,
|
||||
is_standby_scheduled = nil,
|
||||
task = nil,
|
||||
}
|
||||
|
||||
function AutoSuspend:_enabledStandby()
|
||||
return Device:canStandby() and self.auto_standby_timeout_seconds > 0
|
||||
end
|
||||
|
||||
function AutoSuspend:_enabled()
|
||||
return self.auto_suspend_timeout_seconds > 0
|
||||
end
|
||||
@@ -49,15 +57,13 @@ function AutoSuspend:_schedule(shutdown_only)
|
||||
|
||||
local delay_suspend, delay_shutdown
|
||||
|
||||
if PluginShare.pause_auto_suspend or Device.standby_prevented or Device.powerd:isCharging() then
|
||||
if PluginShare.pause_auto_suspend or Device.powerd:isCharging() then
|
||||
delay_suspend = self.auto_suspend_timeout_seconds
|
||||
delay_shutdown = self.autoshutdown_timeout_seconds
|
||||
else
|
||||
local now_tv = UIManager:getTime()
|
||||
delay_suspend = self.last_action_tv + TimeVal:new{ sec = self.auto_suspend_timeout_seconds, usec = 0 } - now_tv
|
||||
delay_suspend = delay_suspend:tonumber()
|
||||
delay_shutdown = self.last_action_tv + TimeVal:new{ sec = self.autoshutdown_timeout_seconds, usec = 0 } - now_tv
|
||||
delay_shutdown = delay_shutdown:tonumber()
|
||||
local now_tv = UIManager:getTime() + Device.total_standby_tv
|
||||
delay_suspend = (self.last_action_tv - now_tv):tonumber() + self.auto_suspend_timeout_seconds
|
||||
delay_shutdown = (self.last_action_tv - now_tv):tonumber() + self.autoshutdown_timeout_seconds
|
||||
end
|
||||
|
||||
-- Try to shutdown first, as we may have been woken up from suspend just for the sole purpose of doing that.
|
||||
@@ -88,9 +94,8 @@ end
|
||||
|
||||
function AutoSuspend:_start()
|
||||
if self:_enabled() or self:_enabledShutdown() then
|
||||
local now_tv = UIManager:getTime()
|
||||
logger.dbg("AutoSuspend: start at", now_tv:tonumber())
|
||||
self.last_action_tv = now_tv
|
||||
self.last_action_tv = UIManager:getTime() + Device.total_standby_tv
|
||||
logger.dbg("AutoSuspend: start at", self.last_action_tv:tonumber())
|
||||
self:_schedule()
|
||||
end
|
||||
end
|
||||
@@ -98,9 +103,8 @@ end
|
||||
-- Variant that only re-engages the shutdown timer for onUnexpectedWakeupLimit
|
||||
function AutoSuspend:_restart()
|
||||
if self:_enabledShutdown() then
|
||||
local now_tv = UIManager:getTime()
|
||||
logger.dbg("AutoSuspend: restart at", now_tv:tonumber())
|
||||
self.last_action_tv = now_tv
|
||||
self.last_action_tv = UIManager:getTime() + Device.total_standby_tv
|
||||
logger.dbg("AutoSuspend: restart at", self.last_action_tv:tonumber())
|
||||
self:_schedule(true)
|
||||
end
|
||||
end
|
||||
@@ -113,6 +117,9 @@ function AutoSuspend:init()
|
||||
self.auto_suspend_timeout_seconds = G_reader_settings:readSetting("auto_suspend_timeout_seconds",
|
||||
default_auto_suspend_timeout_seconds)
|
||||
|
||||
-- Disabled, until the user opts in.
|
||||
self.auto_standby_timeout_seconds = G_reader_settings:readSetting("auto_standby_timeout_seconds", -1)
|
||||
|
||||
UIManager.event_hook:registerWidget("InputEvent", self)
|
||||
-- We need an instance-specific function reference to schedule, because in some rare cases,
|
||||
-- we may instantiate a new plugin instance *before* tearing down the old one.
|
||||
@@ -120,6 +127,8 @@ function AutoSuspend:init()
|
||||
self:_schedule(shutdown_only)
|
||||
end
|
||||
self:_start()
|
||||
self:_reschedule_standby()
|
||||
|
||||
-- self.ui is nil in the testsuite
|
||||
if not self.ui or not self.ui.menu then return end
|
||||
self.ui.menu:registerToMainMenu(self)
|
||||
@@ -131,11 +140,55 @@ function AutoSuspend:onCloseWidget()
|
||||
if Device:isPocketBook() and not Device:canSuspend() then return end
|
||||
self:_unschedule()
|
||||
self.task = nil
|
||||
|
||||
self:_unschedule_standby()
|
||||
-- allowStandby is necessary, as we do a preventStandby on plugin start
|
||||
UIManager:allowStandby()
|
||||
end
|
||||
|
||||
function AutoSuspend:onInputEvent()
|
||||
logger.dbg("AutoSuspend: onInputEvent")
|
||||
self.last_action_tv = UIManager:getTime()
|
||||
self.last_action_tv = UIManager:getTime() + Device.total_standby_tv
|
||||
|
||||
self:_reschedule_standby()
|
||||
end
|
||||
|
||||
function AutoSuspend:_unschedule_standby()
|
||||
UIManager:unschedule(AutoSuspend.allowStandby)
|
||||
end
|
||||
|
||||
function AutoSuspend:_reschedule_standby(standby_timeout)
|
||||
if not Device:canStandby() then return end
|
||||
standby_timeout = standby_timeout or self.auto_standby_timeout_seconds
|
||||
self:_unschedule_standby()
|
||||
if standby_timeout < 1 then
|
||||
return
|
||||
end
|
||||
|
||||
self:preventStandby()
|
||||
logger.dbg("AutoSuspend: schedule autoStandby in", standby_timeout) -- xxx may be deleted later
|
||||
UIManager:scheduleIn(standby_timeout, self.allowStandby, self)
|
||||
end
|
||||
|
||||
function AutoSuspend:preventStandby()
|
||||
if self.is_standby_scheduled ~= false then
|
||||
self.is_standby_scheduled = false
|
||||
UIManager:preventStandby()
|
||||
end
|
||||
end
|
||||
|
||||
function AutoSuspend:allowStandby()
|
||||
if not self.is_standby_scheduled then
|
||||
self.is_standby_scheduled = true
|
||||
UIManager:allowStandby()
|
||||
|
||||
-- This is necessary for wakeup from standby, as the deadline for receiving input events
|
||||
-- is calculated from the time to the next scheduled function.
|
||||
-- Make sure this function comes soon, as the time for going to standby after a scheduled wakeup
|
||||
-- is prolonged by the given time. Any time between 0.500 and 0.001 seconds would go.
|
||||
-- Let's call it deadline_guard.
|
||||
UIManager:scheduleIn(0.100, function() end)
|
||||
end
|
||||
end
|
||||
|
||||
function AutoSuspend:onSuspend()
|
||||
@@ -143,6 +196,7 @@ function AutoSuspend:onSuspend()
|
||||
-- We do not want auto suspend procedure to waste battery during suspend. So let's unschedule it
|
||||
-- when suspending and restart it after resume.
|
||||
self:_unschedule()
|
||||
self:_unschedule_standby()
|
||||
if self:_enabledShutdown() and Device.wakeup_mgr then
|
||||
Device.wakeup_mgr:addTask(self.autoshutdown_timeout_seconds, UIManager.poweroff_action)
|
||||
end
|
||||
@@ -156,6 +210,11 @@ function AutoSuspend:onResume()
|
||||
-- Unschedule in case we tripped onUnexpectedWakeupLimit first...
|
||||
self:_unschedule()
|
||||
self:_start()
|
||||
self:_reschedule_standby()
|
||||
end
|
||||
|
||||
function AutoSuspend:onLeaveStandby()
|
||||
self:_reschedule_standby()
|
||||
end
|
||||
|
||||
function AutoSuspend:onUnexpectedWakeupLimit()
|
||||
@@ -164,16 +223,12 @@ function AutoSuspend:onUnexpectedWakeupLimit()
|
||||
self:_restart()
|
||||
end
|
||||
|
||||
function AutoSuspend:onAllowStandby()
|
||||
self.standby_prevented = false
|
||||
end
|
||||
|
||||
function AutoSuspend:onPreventStandby()
|
||||
self.standby_prevented = true
|
||||
end
|
||||
|
||||
-- time_scale:
|
||||
-- 2 ... display day:hour
|
||||
-- 1 ... display hour:min
|
||||
-- else ... display min:sec
|
||||
function AutoSuspend:setSuspendShutdownTimes(touchmenu_instance, title, info, setting,
|
||||
default_value, range, is_day_hour)
|
||||
default_value, range, time_scale)
|
||||
-- Attention if is_day_hour then time.hour stands for days and time.min for hours
|
||||
|
||||
local InfoMessage = require("ui/widget/infomessage")
|
||||
@@ -181,10 +236,23 @@ function AutoSuspend:setSuspendShutdownTimes(touchmenu_instance, title, info, se
|
||||
|
||||
local setting_val = self[setting] > 0 and self[setting] or default_value
|
||||
|
||||
local left_val = is_day_hour and math.floor(setting_val / (24*3600))
|
||||
or math.floor(setting_val / 3600)
|
||||
local right_val = is_day_hour and math.floor(setting_val / 3600) % 24
|
||||
or math.floor((setting_val / 60) % 60)
|
||||
local left_val
|
||||
if time_scale == 2 then
|
||||
left_val = math.floor(setting_val / (24*3600))
|
||||
elseif time_scale == 1 then
|
||||
left_val = math.floor(setting_val / 3600)
|
||||
else
|
||||
left_val = math.floor(setting_val / 60)
|
||||
end
|
||||
|
||||
local right_val
|
||||
if time_scale == 2 then
|
||||
right_val = math.floor(setting_val / 3600) % 24
|
||||
elseif time_scale == 1 then
|
||||
right_val = math.floor(setting_val / 60) % 60
|
||||
else
|
||||
right_val = math.floor(setting_val) % 60
|
||||
end
|
||||
local time_spinner
|
||||
time_spinner = DateTimeWidget:new {
|
||||
is_date = false,
|
||||
@@ -192,36 +260,57 @@ function AutoSuspend:setSuspendShutdownTimes(touchmenu_instance, title, info, se
|
||||
min = right_val,
|
||||
hour_hold_step = 5,
|
||||
min_hold_step = 10,
|
||||
hour_max = is_day_hour and math.floor(range[2] / (24*3600)) or math.floor(range[2] / 3600),
|
||||
min_max = is_day_hour and 23 or 59,
|
||||
hour_max = (time_scale == 2 and math.floor(range[2] / (24*3600)))
|
||||
or (time_scale == 1 and math.floor(range[2] / 3600))
|
||||
or math.floor(range[2] / 60),
|
||||
min_max = (time_scale == 2 and 23) or 59,
|
||||
ok_text = _("Set timeout"),
|
||||
title_text = title,
|
||||
info_text = info,
|
||||
callback = function(time)
|
||||
self[setting] = is_day_hour and (time.hour * 24 * 3600 + time.min * 3600)
|
||||
or (time.hour * 3600 + time.min * 60)
|
||||
if time_scale == 2 then
|
||||
self[setting] = (time.hour * 24 + time.min) * 3600
|
||||
elseif time_scale == 1 then
|
||||
self[setting] = time.hour * 3600 + time.min * 60
|
||||
else
|
||||
self[setting] = time.hour * 60 + time.min
|
||||
end
|
||||
self[setting] = Math.clamp(self[setting], range[1], range[2])
|
||||
G_reader_settings:saveSetting(setting, self[setting])
|
||||
self:_unschedule()
|
||||
self:_start()
|
||||
if touchmenu_instance then touchmenu_instance:updateItems() end
|
||||
local time_string = util.secondsToClockDuration("modern", self[setting], true, true, true)
|
||||
time_string = time_string:gsub("00m","")
|
||||
local time_string = util.secondsToClockDuration("modern", self[setting],
|
||||
time_scale == 2 or time_scale == 1, true, true)
|
||||
time_string = time_string:gsub("00m$", ""):gsub("^0+m", ""):gsub("^0", "")
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = T(_("%1: %2"), title, time_string),
|
||||
timeout = 3,
|
||||
})
|
||||
end,
|
||||
default_value = util.secondsToClockDuration("modern", default_value, true, true, true):gsub("00m$",""),
|
||||
default_value = util.secondsToClockDuration("modern", default_value,
|
||||
time_scale == 2 or time_scale == 1, true, true):gsub("00m$", ""):gsub("^00m:", ""),
|
||||
default_callback = function()
|
||||
local hour = is_day_hour and math.floor(default_value / (24*3600))
|
||||
or math.floor(default_value / 3600)
|
||||
local min = is_day_hour and math.floor(default_value / 3600) % 24
|
||||
or math.floor(default_value / 60) % 60
|
||||
local hour
|
||||
if time_scale == 2 then
|
||||
hour = math.floor(default_value / (24*3600))
|
||||
elseif time_scale == 1 then
|
||||
hour = math.floor(default_value / 3600)
|
||||
else
|
||||
hour = math.floor(default_value / 60)
|
||||
end
|
||||
local min
|
||||
if time_scale == 2 then
|
||||
min = math.floor(default_value / 3600) % 24
|
||||
elseif time_scale == 1 then
|
||||
min = math.floor(default_value / 60) % 60
|
||||
else
|
||||
min = math.floor(default_value % 60)
|
||||
end
|
||||
time_spinner:update(nil, hour, min)
|
||||
end,
|
||||
extra_text = _("Disable"),
|
||||
extra_callback = function(_self)
|
||||
extra_callback = function(this)
|
||||
self[setting] = -1 -- disable with a negative time/number
|
||||
G_reader_settings:saveSetting(setting, -1)
|
||||
self:_unschedule()
|
||||
@@ -230,7 +319,7 @@ function AutoSuspend:setSuspendShutdownTimes(touchmenu_instance, title, info, se
|
||||
text = T(_("%1: disabled"), title),
|
||||
timeout = 3,
|
||||
})
|
||||
_self:onClose()
|
||||
this:onClose()
|
||||
end,
|
||||
keep_shown_on_apply = true,
|
||||
}
|
||||
@@ -246,7 +335,7 @@ function AutoSuspend:addToMainMenu(menu_items)
|
||||
text_func = function()
|
||||
if self.auto_suspend_timeout_seconds and self.auto_suspend_timeout_seconds > 0 then
|
||||
local time_string = util.secondsToClockDuration("modern",
|
||||
self.auto_suspend_timeout_seconds, true, true, true):gsub("00m$","")
|
||||
self.auto_suspend_timeout_seconds, true, true, true):gsub("00m$", ""):gsub("^00m:", "")
|
||||
return T(_("Autosuspend timeout: %1"), time_string)
|
||||
else
|
||||
return _("Autosuspend timeout")
|
||||
@@ -260,36 +349,122 @@ function AutoSuspend:addToMainMenu(menu_items)
|
||||
self:setSuspendShutdownTimes(touchmenu_instance,
|
||||
_("Timeout for autosuspend"), _("Enter time in hours and minutes."),
|
||||
"auto_suspend_timeout_seconds", default_auto_suspend_timeout_seconds,
|
||||
{60, 24*3600}, false)
|
||||
end,
|
||||
}
|
||||
if not (Device:canPowerOff() or Device:isEmulator()) then return end
|
||||
menu_items.autoshutdown = {
|
||||
sorting_hint = "device",
|
||||
checked_func = function()
|
||||
return self:_enabledShutdown()
|
||||
end,
|
||||
text_func = function()
|
||||
if self.autoshutdown_timeout_seconds and self.autoshutdown_timeout_seconds > 0 then
|
||||
local time_string = util.secondsToClockDuration("modern",
|
||||
self.autoshutdown_timeout_seconds, true, true, true):gsub("00m$","")
|
||||
return T(_("Autoshutdown timeout: %1"), time_string)
|
||||
else
|
||||
return _("Autoshutdown timeout")
|
||||
end
|
||||
end,
|
||||
keep_menu_open = true,
|
||||
callback = function(touchmenu_instance)
|
||||
-- 5*60 sec (5') is the minimum and 28*24*3600 (28days) is the maximum shutdown time.
|
||||
-- Minimum time has to be big enough, to avoid start-stop death scenarious.
|
||||
-- Maximum more than four weeks seems a bit excessive if you want to enable authoshutdown,
|
||||
-- even if the battery can last up to three months.
|
||||
self:setSuspendShutdownTimes(touchmenu_instance,
|
||||
_("Timeout for autoshutdown"), _("Enter time in days and hours."),
|
||||
"autoshutdown_timeout_seconds", default_autoshutdown_timeout_seconds,
|
||||
{5*60, 28*24*3600}, true)
|
||||
{60, 24*3600}, 1)
|
||||
end,
|
||||
}
|
||||
if Device:canPowerOff() or Device:isEmulator() then
|
||||
menu_items.autoshutdown = {
|
||||
sorting_hint = "device",
|
||||
checked_func = function()
|
||||
return self:_enabledShutdown()
|
||||
end,
|
||||
text_func = function()
|
||||
if self.autoshutdown_timeout_seconds and self.autoshutdown_timeout_seconds > 0 then
|
||||
local time_string = util.secondsToClockDuration("modern", self.autoshutdown_timeout_seconds,
|
||||
true, true, true):gsub("00m$", ""):gsub("^00m:", "")
|
||||
return T(_("Autoshutdown timeout: %1"), time_string)
|
||||
else
|
||||
return _("Autoshutdown timeout")
|
||||
end
|
||||
end,
|
||||
keep_menu_open = true,
|
||||
callback = function(touchmenu_instance)
|
||||
-- 5*60 sec (5') is the minimum and 28*24*3600 (28days) is the maximum shutdown time.
|
||||
-- Minimum time has to be big enough, to avoid start-stop death scenarious.
|
||||
-- Maximum more than four weeks seems a bit excessive if you want to enable authoshutdown,
|
||||
-- even if the battery can last up to three months.
|
||||
self:setSuspendShutdownTimes(touchmenu_instance,
|
||||
_("Timeout for autoshutdown"), _("Enter time in days and hours."),
|
||||
"autoshutdown_timeout_seconds", default_autoshutdown_timeout_seconds,
|
||||
{5*60, 28*24*3600}, 2)
|
||||
end,
|
||||
}
|
||||
end
|
||||
if Device:canStandby() then
|
||||
local standby_help = _([[Standby puts the device into a power-saving state in which the screen is on and user input can be performed.
|
||||
|
||||
Standby can not be entered if Wi-Fi is on.
|
||||
|
||||
Upon user input, the device needs a certain amount of time to wake up. With some devices this period of time is not noticeable, with other devices it can be annoying.]])
|
||||
|
||||
menu_items.autostandby = {
|
||||
sorting_hint = "device",
|
||||
checked_func = function()
|
||||
return self:_enabledStandby()
|
||||
end,
|
||||
text_func = function()
|
||||
if self.auto_standby_timeout_seconds and self.auto_standby_timeout_seconds > 0 then
|
||||
local time_string = util.secondsToClockDuration("modern", self.auto_standby_timeout_seconds,
|
||||
false, true, true):gsub("00m$", ""):gsub("^0+m", ""):gsub("^0", "")
|
||||
return T(_("Autostandby timeout: %1"), time_string)
|
||||
else
|
||||
return _("Autostandby timeout")
|
||||
end
|
||||
end,
|
||||
help_text = standby_help,
|
||||
keep_menu_open = true,
|
||||
callback = function(touchmenu_instance)
|
||||
-- 5 sec is the minimum and 60*60 sec (15min) is the maximum standby time.
|
||||
-- We need a minimum time, so that scheduled function have a chance to execute.
|
||||
-- A standby time of 15 min seem excessive.
|
||||
-- But or battery testing it might give some sense.
|
||||
self:setSuspendShutdownTimes(touchmenu_instance,
|
||||
_("Timeout for autostandby"), _("Enter time in minutes and seconds."),
|
||||
"auto_standby_timeout_seconds", default_auto_standby_timeout_seconds,
|
||||
{3, 15*60}, 0)
|
||||
end,
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
-- KOReader is merely waiting for user input right now.
|
||||
-- UI signals us that standby is allowed at this very moment because nothing else goes on in the background.
|
||||
function AutoSuspend:onAllowStandby()
|
||||
logger.dbg("AutoSuspend: onAllowStandby")
|
||||
-- In case the OS frontend itself doesn't manage power state, we can do it on our own here.
|
||||
-- One should also configure wake-up pins and perhaps wake alarm,
|
||||
-- if we want to enter deeper sleep states later on from within standby.
|
||||
|
||||
-- Don't enter standby if wifi is on, as this my break reconnecting (at least on Kobo-Sage)
|
||||
if NetworkMgr:isWifiOn() then
|
||||
logger.dbg("AutoSuspend: WiFi is on, no standby")
|
||||
return
|
||||
end
|
||||
|
||||
-- Don't enter standby if device is charging and it is a non sunxi kobo
|
||||
if Device.powerd:isCharging() and not Device:canPowerSaveWhileCharging() then
|
||||
logger.dbg("AutoSuspend: charging, no standby")
|
||||
return
|
||||
end
|
||||
|
||||
if Device:canStandby() then
|
||||
local wake_in = math.huge
|
||||
-- The next scheduled function should be the deadline_guard
|
||||
-- Wake before the second next scheduled function executes (e.g. footer update, suspend ...)
|
||||
local scheduler_times = UIManager:getNextTaskTimes(2)
|
||||
if #scheduler_times == 2 then
|
||||
-- Wake up slightly after the formerly scheduled event, to avoid resheduling the same function
|
||||
-- after a fraction of a second again (e.g. don't draw footer twice)
|
||||
wake_in = math.floor(scheduler_times[2]:tonumber()) + 1
|
||||
end
|
||||
|
||||
if wake_in > 3 then -- don't go into standby, if scheduled wake is in less than 3 secs
|
||||
UIManager:broadcastEvent(Event:new("EnterStandby"))
|
||||
logger.dbg("AutoSuspend: going to standby and wake in " .. wake_in .. "s zZzzZzZzzzzZZZzZZZz")
|
||||
|
||||
-- This is for the Kobo Sage/Elipsa for now, as these are the only with useStandby.
|
||||
-- Other devices may be added
|
||||
Device:standby(wake_in)
|
||||
|
||||
logger.dbg("AutoSuspend: leaving standby after " .. Device.last_standby_tv:tonumber() .. " s")
|
||||
|
||||
UIManager:broadcastEvent(Event:new("LeaveStandby"))
|
||||
self:_unschedule() -- unschedule suspend and shutdown as the realtime clock has ticked
|
||||
self:_schedule() -- reschedule suspend and shutdown with the new time
|
||||
end
|
||||
-- Don't do a `self:_reschedule_standby()` here, as this will interfere with suspend.
|
||||
-- Better to to it in onLeaveStandby.
|
||||
end
|
||||
end
|
||||
|
||||
return AutoSuspend
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
local Device = require("device")
|
||||
local Event = require("ui/event")
|
||||
local PluginShare = require("pluginshare")
|
||||
local TimeVal = require("ui/timeval")
|
||||
@@ -34,20 +35,24 @@ function AutoTurn:_schedule()
|
||||
if UIManager:getTopWidget() == "ReaderUI" then
|
||||
logger.dbg("AutoTurn: go to next page")
|
||||
self.ui:handleEvent(Event:new("GotoViewRel", self.autoturn_distance))
|
||||
self.last_action_tv = UIManager:getTime()
|
||||
end
|
||||
logger.dbg("AutoTurn: schedule in", self.autoturn_sec)
|
||||
UIManager:scheduleIn(self.autoturn_sec, self.task)
|
||||
self.scheduled = true
|
||||
else
|
||||
logger.dbg("AutoTurn: schedule in", delay)
|
||||
UIManager:scheduleIn(delay, self.task)
|
||||
self.scheduled = true
|
||||
end
|
||||
end
|
||||
|
||||
function AutoTurn:_unschedule()
|
||||
PluginShare.pause_auto_suspend = false
|
||||
if self.task then
|
||||
if self.scheduled then
|
||||
logger.dbg("AutoTurn: unschedule")
|
||||
UIManager:unschedule(self.task)
|
||||
self.scheduled = false
|
||||
end
|
||||
end
|
||||
|
||||
@@ -79,8 +84,8 @@ end
|
||||
|
||||
function AutoTurn:init()
|
||||
UIManager.event_hook:registerWidget("InputEvent", self)
|
||||
self.autoturn_sec = G_reader_settings:readSetting("autoturn_timeout_seconds") or 0
|
||||
self.autoturn_distance = G_reader_settings:readSetting("autoturn_distance") or 1
|
||||
self.autoturn_sec = G_reader_settings:readSetting("autoturn_timeout_seconds", 0)
|
||||
self.autoturn_distance = G_reader_settings:readSetting("autoturn_distance", 1)
|
||||
self.enabled = G_reader_settings:isTrue("autoturn_enabled")
|
||||
self.ui.menu:registerToMainMenu(self)
|
||||
self.task = function()
|
||||
@@ -105,6 +110,10 @@ function AutoTurn:onInputEvent()
|
||||
self.last_action_tv = UIManager:getTime()
|
||||
end
|
||||
|
||||
function AutoTurn:onEnterStandby()
|
||||
self:_unschedule()
|
||||
end
|
||||
|
||||
-- We do not want autoturn to turn pages during the suspend process.
|
||||
-- Unschedule it and restart after resume.
|
||||
function AutoTurn:onSuspend()
|
||||
@@ -112,7 +121,17 @@ function AutoTurn:onSuspend()
|
||||
self:_unschedule()
|
||||
end
|
||||
|
||||
function AutoTurn:onResume()
|
||||
function AutoTurn:_onLeaveStandby()
|
||||
self.last_action_tv = self.last_action_tv - Device.last_standby_tv
|
||||
|
||||
-- We messed with last_action_tv, so a complete reschedule has to be done.
|
||||
if self:_enabled() then
|
||||
self:_unschedule()
|
||||
self:_schedule()
|
||||
end
|
||||
end
|
||||
|
||||
function AutoTurn:_onResume()
|
||||
logger.dbg("AutoTurn: onResume")
|
||||
self:_start()
|
||||
end
|
||||
@@ -139,7 +158,10 @@ function AutoTurn:addToMainMenu(menu_items)
|
||||
G_reader_settings:makeFalse("autoturn_enabled")
|
||||
self:_unschedule()
|
||||
menu:updateItems()
|
||||
self.onResume = nil
|
||||
self.onLeaveStandby = nil
|
||||
end,
|
||||
ok_always_enabled = true,
|
||||
callback = function(autoturn_spin)
|
||||
self.autoturn_sec = autoturn_spin.value
|
||||
G_reader_settings:saveSetting("autoturn_timeout_seconds", autoturn_spin.value)
|
||||
@@ -148,6 +170,8 @@ function AutoTurn:addToMainMenu(menu_items)
|
||||
self:_unschedule()
|
||||
self:_start()
|
||||
menu:updateItems()
|
||||
self.onResume = self._onResume
|
||||
self.onLeaveStandby = self._onLeaveStandby
|
||||
end,
|
||||
}
|
||||
UIManager:show(autoturn_spin)
|
||||
|
||||
@@ -5,7 +5,6 @@ Plugin for setting screen warmth based on the sun position and/or a time schedul
|
||||
--]]--
|
||||
|
||||
local Device = require("device")
|
||||
|
||||
local ConfirmBox = require("ui/widget/confirmbox")
|
||||
local DateTimeWidget = require("ui/widget/datetimewidget")
|
||||
local DoubleSpinWidget = require("/ui/widget/doublespinwidget")
|
||||
@@ -21,6 +20,7 @@ local SunTime = require("suntime")
|
||||
local TextWidget = require("ui/widget/textwidget")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local WidgetContainer = require("ui/widget/container/widgetcontainer")
|
||||
local logger = require("logger")
|
||||
local _ = require("gettext")
|
||||
local T = FFIUtil.template
|
||||
local Screen = require("device").screen
|
||||
@@ -119,6 +119,7 @@ end
|
||||
function AutoWarmth:onResume()
|
||||
if self.activate == 0 then return end
|
||||
|
||||
logger.dbg("AutoWarmth: onResume/onLeaveStandby")
|
||||
local resume_date = os.date("*t")
|
||||
|
||||
-- check if resume and suspend are done on the same day
|
||||
@@ -131,6 +132,8 @@ function AutoWarmth:onResume()
|
||||
end
|
||||
end
|
||||
|
||||
AutoWarmth.onLeaveStandby = AutoWarmth.onResume
|
||||
|
||||
-- wrapper for unscheduling, so that only our setWarmth gets unscheduled
|
||||
function AutoWarmth.setWarmth(val)
|
||||
if val then
|
||||
@@ -147,6 +150,7 @@ function AutoWarmth.setWarmth(val)
|
||||
end
|
||||
|
||||
function AutoWarmth:scheduleMidnightUpdate()
|
||||
logger.dbg("AutoWarmth: scheduleMidnightUpdate")
|
||||
-- first unschedule all old functions
|
||||
UIManager:unschedule(self.scheduleMidnightUpdate) -- when called from menu or resume
|
||||
|
||||
@@ -249,7 +253,11 @@ function AutoWarmth:scheduleMidnightUpdate()
|
||||
self:scheduleWarmthChanges(now)
|
||||
end
|
||||
|
||||
--- @todo: As we have standby now, don't do the scheduling of the whole schedule,
|
||||
-- but only the next warmth value plus an additional scheduleWarmthChanges
|
||||
-- This would safe a bit of energy, but not really much.
|
||||
function AutoWarmth:scheduleWarmthChanges(time)
|
||||
logger.dbg("AutoWarmth: scheduleWarmthChanges")
|
||||
for i = 1, #self.sched_funcs do -- loop not essential, as unschedule unschedules all functions at once
|
||||
if not UIManager:unschedule(self.sched_funcs[i][1]) then
|
||||
break
|
||||
|
||||
@@ -44,8 +44,16 @@ function SystemStat:appendCounters()
|
||||
if self.resume_sec then
|
||||
self:put({_(" Last resume time"), os.date("%c", self.resume_sec)})
|
||||
end
|
||||
self:put({_(" Up hours"),
|
||||
string.format("%.2f", os.difftime(os.time(), self.start_sec) / 60 / 60)})
|
||||
self:put({_(" Up time"),
|
||||
util.secondsToClockDuration("", os.difftime(os.time(), self.start_sec), false, true, true)})
|
||||
if Device:canSuspend() then
|
||||
self:put({_(" Time in suspend"),
|
||||
util.secondsToClockDuration("", Device.total_suspend_tv:tonumber(), false, true, true)})
|
||||
end
|
||||
if Device:canStandby() then
|
||||
self:put({_(" Time in standby"),
|
||||
util.secondsToClockDuration("", Device.total_standby_tv:tonumber(), false, true, true)})
|
||||
end
|
||||
self:put({_("Counters"), ""})
|
||||
self:put({_(" wake-ups"), self.wakeup_count})
|
||||
-- @translators The number of "sleeps", that is the number of times the device has entered standby. This could also be translated as a rendition of a phrase like "entered sleep".
|
||||
|
||||
@@ -15,10 +15,12 @@ local MockTime = {
|
||||
original_tv_monotonic = nil,
|
||||
original_tv_monotonic_coarse = nil,
|
||||
original_tv_boottime = nil,
|
||||
original_tv_boottime_or_realtime_coarse = nil,
|
||||
original_tv_now = nil,
|
||||
monotonic = 0,
|
||||
realtime = 0,
|
||||
boottime = 0,
|
||||
boottime_or_realtime_coarse = 0,
|
||||
}
|
||||
|
||||
function MockTime:install()
|
||||
@@ -47,6 +49,10 @@ function MockTime:install()
|
||||
self.original_tv_boottime = TimeVal.boottime
|
||||
assert(self.original_tv_boottime ~= nil)
|
||||
end
|
||||
if self.original_tv_boottime_or_realtime_coarse == nil then
|
||||
self.original_tv_boottime_or_realtime_coarse = TimeVal.boottime_or_realtime_coarse
|
||||
assert(self.original_tv_boottime_or_realtime_coarse ~= nil)
|
||||
end
|
||||
if self.original_tv_now == nil then
|
||||
self.original_tv_now = TimeVal.now
|
||||
assert(self.original_tv_now ~= nil)
|
||||
@@ -86,6 +92,10 @@ function MockTime:install()
|
||||
logger.dbg("MockTime:TimeVal.boottime: ", self.boottime)
|
||||
return TimeVal:new{ sec = self.boottime }
|
||||
end
|
||||
TimeVal.boottime_or_realtime_coarse = function()
|
||||
logger.dbg("MockTime:TimeVal.boottime: ", self.boottime_or_realtime_coarse)
|
||||
return TimeVal:new{ sec = self.boottime_or_realtime_coarse }
|
||||
end
|
||||
TimeVal.now = function()
|
||||
logger.dbg("MockTime:TimeVal.now: ", self.monotonic)
|
||||
return TimeVal:new{ sec = self.monotonic }
|
||||
@@ -113,6 +123,9 @@ function MockTime:uninstall()
|
||||
if self.original_tv_boottime ~= nil then
|
||||
TimeVal.boottime = self.original_tv_boottime
|
||||
end
|
||||
if self.original_tv_boottime_or_realtime_coarse ~= nil then
|
||||
TimeVal.boottime_or_realtime_coarse = self.original_tv_boottime_or_realtime_coarse
|
||||
end
|
||||
if self.original_tv_now ~= nil then
|
||||
TimeVal.now = self.original_tv_now
|
||||
end
|
||||
@@ -178,6 +191,26 @@ function MockTime:increase_boottime(value)
|
||||
return true
|
||||
end
|
||||
|
||||
function MockTime:set_boottime_or_realtime_coarse(value)
|
||||
assert(self ~= nil)
|
||||
if type(value) ~= "number" then
|
||||
return false
|
||||
end
|
||||
self.boottime_or_realtime_coarse = math.floor(value)
|
||||
logger.dbg("MockTime:set_boottime ", self.boottime_or_realtime_coarse)
|
||||
return true
|
||||
end
|
||||
|
||||
function MockTime:increase_boottime_or_realtime_coarse(value)
|
||||
assert(self ~= nil)
|
||||
if type(value) ~= "number" then
|
||||
return false
|
||||
end
|
||||
self.boottime_or_realtime_coarse = math.floor(self.boottime_or_realtime_coarse + value)
|
||||
logger.dbg("MockTime:increase_boottime ", self.boottime_or_realtime_coarse)
|
||||
return true
|
||||
end
|
||||
|
||||
function MockTime:set(value)
|
||||
assert(self ~= nil)
|
||||
if type(value) ~= "number" then
|
||||
@@ -189,6 +222,8 @@ function MockTime:set(value)
|
||||
logger.dbg("MockTime:set (monotonic) ", self.monotonic)
|
||||
self.boottime = math.floor(value)
|
||||
logger.dbg("MockTime:set (boottime) ", self.boottime)
|
||||
self.boottime_or_realtime_coarse = math.floor(value)
|
||||
logger.dbg("MockTime:set (boottime) ", self.boottime_or_realtime_coarse)
|
||||
return true
|
||||
end
|
||||
|
||||
@@ -203,6 +238,8 @@ function MockTime:increase(value)
|
||||
logger.dbg("MockTime:increase (monotonic) ", self.monotonic)
|
||||
self.boottime = math.floor(self.boottime + value)
|
||||
logger.dbg("MockTime:increase (boottime) ", self.boottime)
|
||||
self.boottime_or_realtime_coarse = math.floor(self.boottime_or_realtime_coarse + value)
|
||||
logger.dbg("MockTime:increase (boottime) ", self.boottime_or_realtime_coarse)
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user