2
0
mirror of https://github.com/koreader/koreader synced 2024-11-16 06:12:56 +00:00

Kindle: enable WakeupMgr & RTC support

This is acomplished through listening for the wakeupFromSuspend
& readyToSuspend powerd events to set the RTC via lipc at the
correct time.
This commit is contained in:
yparitcher 2022-06-27 23:02:37 -04:00
parent 30e499d4a9
commit 926223c192
7 changed files with 169 additions and 10 deletions

2
base

@ -1 +1 @@
Subproject commit 9b8e1fc44dc4c4b08891d55e48fbf28db1f77799
Subproject commit d5b2e3798043630906251b99f9b79e1a59ab6099

View File

@ -243,6 +243,8 @@ function Input:init()
self.event_map[10011] = "UsbPlugOut"
self.event_map[10020] = "Charging"
self.event_map[10021] = "NotCharging"
self.event_map[10030] = "WakeupFromSuspend"
self.event_map[10031] = "ReadyToSuspend"
-- user custom event map
local custom_event_map_location = string.format(
@ -496,7 +498,8 @@ function Input:handleKeyBoardEv(ev)
-- fake events
if keycode == "IntoSS" or keycode == "OutOfSS"
or keycode == "UsbPlugIn" or keycode == "UsbPlugOut"
or keycode == "Charging" or keycode == "NotCharging" then
or keycode == "Charging" or keycode == "NotCharging"
or keycode == "WakeupFromSuspend" or keycode == "ReadyToSuspend" then
return keycode
end
@ -611,7 +614,8 @@ function Input:handlePowerManagementOnlyEv(ev)
-- Fake events
if keycode == "IntoSS" or keycode == "OutOfSS"
or keycode == "UsbPlugIn" or keycode == "UsbPlugOut"
or keycode == "Charging" or keycode == "NotCharging" then
or keycode == "Charging" or keycode == "NotCharging"
or keycode == "WakeupFromSuspend" or keycode == "ReadyToSuspend" then
return keycode
end

View File

@ -275,6 +275,14 @@ function Kindle:usbPlugOut()
self.charging_mode = false
end
function Kindle:wakeupFromSuspend()
self.powerd:wakeupFromSuspend()
end
function Kindle:readyToSuspend()
self.powerd:readyToSuspend()
end
function Kindle:ambientBrightnessLevel()
local haslipc, lipc = pcall(require, "liblipclua")
if not haslipc or lipc == nil then return 0 end

View File

@ -0,0 +1,62 @@
-- Mock RTC implementation backed by kindle's system powerd via lipc
local MockRTC = {
_wakeup_scheduled = false,
_wakeup_scheduled_epoch = nil,
}
-- This call always succeeds, errors will only happen at suspend time in
-- powerd:setRtcWakeup()
function MockRTC:setWakeupAlarm(epoch, enabled)
enabled = (enabled ~= nil) and enabled or true
if enabled then
self._wakeup_scheduled = true
self._wakeup_scheduled_epoch = epoch
else
self:unsetWakeupAlarm()
end
return true
end
function MockRTC:unsetWakeupAlarm()
self._wakeup_scheduled = false
self._wakeup_scheduled_epoch = nil
end
function MockRTC:getWakeupAlarmEpoch()
return self._wakeup_scheduled_epoch
end
--[[--
Checks if the alarm we set matches the current time.
--]]
function MockRTC:validateWakeupAlarmByProximity(task_alarm, proximity)
-- In principle alarm time and current time should match within a second,
-- but let's be absurdly generous and assume anything within 30 is a match.
-- In practice, suspend() schedules check_unexpected_wakeup 15s *after*
-- the actual wakeup, so we need to account for at least that much ;).
proximity = proximity or 30
-- We want everything in UTC time_t (i.e. a Posix epoch).
local now = os.time()
local alarm = self:getWakeupAlarmEpoch()
if not (alarm and task_alarm) then return end
-- Everything's in UTC, ask Lua to convert that to a human-readable format in the local timezone
print("validateWakeupAlarmByProximity:",
"\ntask @ " .. task_alarm .. os.date(" (%F %T %z)", task_alarm),
"\nlast set alarm @ " .. alarm .. os.date(" (%F %T %z)", alarm),
"\ncurrent time is " .. now .. os.date(" (%F %T %z)", now))
-- If our stored alarm and the provided task alarm don't match,
-- we're not talking about the same task.
if task_alarm and alarm ~= task_alarm then return end
local diff = now - alarm
if diff >= 0 and diff < proximity then return true end
end
function MockRTC:isWakeupAlarmScheduled()
return self._wakeup_scheduled
end
return MockRTC

View File

@ -1,4 +1,6 @@
local BasePowerD = require("device/generic/powerd")
local WakeupMgr = require("device/wakeupmgr")
local logger = require("logger")
-- liblipclua, see require below
local KindlePowerD = BasePowerD:new{
@ -19,6 +21,8 @@ function KindlePowerD:init()
if not self.device:canTurnFrontlightOff() then
self.fl_max = self.fl_max + 1
end
self:initWakeupMgr()
end
-- If we start with the light off (fl_intensity is fl_min), ensure a toggle will set it to the lowest "on" step,
@ -186,6 +190,71 @@ function KindlePowerD:toggleSuspend()
end
end
-- Kindle only allows setting the RTC via lipc during the ReadyToSuspend state
function KindlePowerD:setRtcWakeup(seconds_from_now)
if self.lipc_handle then
self.lipc_handle:set_int_property("com.lab126.powerd", "rtcWakeup", seconds_from_now)
end
end
-- Check the powerd state: are we still in screensaver mode.
function KindlePowerD:getPowerdState()
if self.lipc_handle then
return self.lipc_handle:get_string_property("com.lab126.powerd", "state")
end
end
function KindlePowerD:checkUnexpectedWakeup()
local state = self:getPowerdState()
logger.info("Powerd resume state:", state)
-- If we moved on to the active state,
-- then we were woken by user input not our alarm.
if state ~= "screenSaver" and state ~= "suspended" then return end
if self.device.wakeup_mgr:isWakeupAlarmScheduled() and self.device.wakeup_mgr:wakeupAction() then
logger.info("Kindle scheduled wakeup")
else
logger.info("Kindle unscheduled wakeup")
end
end
-- Dummy fuctions. They will be defined in initWakeupMgr
function KindlePowerD:wakeupFromSuspend() end
function KindlePowerD:readyToSuspend() end
-- Support WakeupMgr on Lipc & supportsScreensaver devices.
function KindlePowerD:initWakeupMgr()
if not self.device:supportsScreensaver() then return end
if self.lipc_handle == nil then return end
function KindlePowerD:wakeupFromSuspend()
logger.info("Kindle wakeupFromSuspend")
-- Give the device a few seconds to settle.
-- This filters out user input resumes -> device will resume to active
-- Also the Kindle stays in Ready to suspend for 10 seconds
-- so the alarm may fire 10 seconds early
local UIManager = require("ui/uimanager")
UIManager:scheduleIn(15, self.checkUnexpectedWakeup, self)
end
function KindlePowerD:readyToSuspend()
logger.info("Kindle readyToSuspend")
if self.device.wakeup_mgr:isWakeupAlarmScheduled() then
local now = os.time()
local alarm = self.device.wakeup_mgr:getWakeupAlarmEpoch()
if alarm > now then
-- Powerd / Lipc need seconds_from_now not epoch
self:setRtcWakeup(alarm - now)
else
-- wakeup time is in the past
self.device.wakeup_mgr:removeTasks(alarm)
end
end
end
self.device.wakeup_mgr = WakeupMgr:new{rtc = require("device/kindle/mockrtc")}
end
--- @fixme: This won't ever fire, as KindlePowerD is already a metatable on a plain table.
function KindlePowerD:__gc()
if self.lipc_handle then

View File

@ -22,6 +22,7 @@ WakeupMgr base class.
local WakeupMgr = {
dev_rtc = "/dev/rtc0", -- RTC device
_task_queue = {}, -- Table with epoch at which to schedule the task and the function to be scheduled.
rtc = RTC, -- The RTC implementation to use, defaults to the RTC module.
}
--[[--
@ -169,7 +170,7 @@ Set wakeup alarm.
Simple wrapper for @{ffi.rtc.setWakeupAlarm}.
--]]
function WakeupMgr:setWakeupAlarm(epoch, enabled)
return RTC:setWakeupAlarm(epoch, enabled)
return self.rtc:setWakeupAlarm(epoch, enabled)
end
--[[--
@ -178,7 +179,7 @@ Unset wakeup alarm.
Simple wrapper for @{ffi.rtc.unsetWakeupAlarm}.
--]]
function WakeupMgr:unsetWakeupAlarm()
return RTC:unsetWakeupAlarm()
return self.rtc:unsetWakeupAlarm()
end
--[[--
@ -187,13 +188,22 @@ Get wakealarm as set by us.
Simple wrapper for @{ffi.rtc.getWakeupAlarm}.
--]]
function WakeupMgr:getWakeupAlarm()
return RTC:getWakeupAlarm()
return self.rtc:getWakeupAlarm()
end
--[[--
Get wakealarm epoch as set by us.
Simple wrapper for @{ffi.rtc.getWakeupAlarmEpoch}.
--]]
function WakeupMgr:getWakeupAlarmEpoch()
return self.rtc:getWakeupAlarmEpoch()
end
--[[--
Get RTC wakealarm from system.
Simple wrapper for @{ffi.rtc.getWakeupAlarm}.
Simple wrapper for @{ffi.rtc.getWakeupAlarmSys}.
--]]
function WakeupMgr:getWakeupAlarmSys()
return RTC:getWakeupAlarmSys()
@ -207,7 +217,7 @@ Checks if we set the alarm.
Simple wrapper for @{ffi.rtc.validateWakeupAlarmByProximity}.
--]]
function WakeupMgr:validateWakeupAlarmByProximity(task_alarm_epoch, proximity)
return RTC:validateWakeupAlarmByProximity(task_alarm_epoch, proximity)
return self.rtc:validateWakeupAlarmByProximity(task_alarm_epoch, proximity)
end
--[[--
@ -216,10 +226,10 @@ Check if a wakeup is scheduled.
Simple wrapper for @{ffi.rtc.isWakeupAlarmScheduled}.
--]]
function WakeupMgr:isWakeupAlarmScheduled()
local wakeup_scheduled = RTC:isWakeupAlarmScheduled()
local wakeup_scheduled = self.rtc:isWakeupAlarmScheduled()
if wakeup_scheduled then
-- NOTE: This can't return nil given that we're behind an isWakeupAlarmScheduled check.
local alarm = RTC:getWakeupAlarmEpoch()
local alarm = self.rtc:getWakeupAlarmEpoch()
logger.dbg("WakeupMgr:isWakeupAlarmScheduled: An alarm is scheduled for " .. alarm .. os.date(" (%F %T %z)", alarm))
else
logger.dbg("WakeupMgr:isWakeupAlarmScheduled: No alarm is currently scheduled.")

View File

@ -239,6 +239,12 @@ function UIManager:init()
Device:usbPlugOut()
self:_afterNotCharging()
end
self.event_handlers["WakeupFromSuspend"] = function()
Device:wakeupFromSuspend()
end
self.event_handlers["ReadyToSuspend"] = function()
Device:readyToSuspend()
end
elseif Device:isRemarkable() then
self.event_handlers["Suspend"] = function()
self:_beforeSuspend()