mirror of
https://github.com/koreader/koreader
synced 2024-11-11 19:11:14 +00:00
9bf19d1bb3
* UIManager: Support more specialized update modes for corner-cases: * A2, which we'll use for the VirtualKeyboards keys (they'd... inadvertently switched to UI with the highlight refactor). * NO_MERGE variants of ui & partial (for sunxi). Use `[ui]` in ReaderHighlight's popup, because of a Sage kernel bug that could otherwise make it translucent, sometimes completely so (*sigh*). * UIManager: Assorted code cleanups & simplifications. * Logger & dbg: Unify logging style, and code cleanups. * SDL: Unbreak suspend/resume outside of the emulator (fix #9567). * NetworkMgr: Cache the network status, and allow it to be queried. (Used by AutoSuspend to avoid repeatedly poking the system when computing the standby schedule delay). * OneTimeMigration: Don't forget about `NETWORK_PROXY` & `STARDICT_DATA_DIR` when migrating `defaults.persistent.lua` (fix #9573) * WakeupMgr: Workaround an apparent limitation of the RTC found on i.MX5 Kobo devices, where setting a wakealarm further than UINT16_MAX seconds in the future would apparently overflow and wraparound... (fix #8039, many thanks to @yfede for the extensive deep-dive and for actually accurately pinpointing the issue!). * Kobo: Handle standby transitions at full CPU clock speeds, in order to limit the latency hit. * UIManager: Properly quit on reboot & exit. This ensures our exit code is preserved, as we exit on our own terms (instead of being killed by the init system). This is important on platforms where exit codes are semantically meaningful (e.g., Kobo). * UIManager: Speaking of reboot & exit, make sure the Screensaver shows in all circumstances (e.g., autoshutdown, re: #9542)), and that there aren't any extraneous refreshes triggered. (Additionally, fix a minor regression since #9448 about tracking this very transient state on Kobo & Cervantes). * Kindle: ID the upcoming Scribe. * Bump base (https://github.com/koreader/koreader-base/pull/1524)
333 lines
10 KiB
Lua
333 lines
10 KiB
Lua
local Generic = require("device/generic/device")
|
|
local logger = require("logger")
|
|
|
|
local function yes() return true end
|
|
local function no() return false end
|
|
|
|
local function getProductId()
|
|
local ntxinfo_pcb = io.popen("/usr/bin/ntxinfo /dev/mmcblk0 | grep pcb | cut -d ':' -f2", "r")
|
|
if not ntxinfo_pcb then return 0 end
|
|
local product_id = ntxinfo_pcb:read("*number") or 0
|
|
ntxinfo_pcb:close()
|
|
return product_id
|
|
end
|
|
|
|
local function isConnected()
|
|
-- read carrier state from sysfs (for eth0)
|
|
local file = io.open("/sys/class/net/eth0/carrier", "rb")
|
|
|
|
-- file exists while Wi-Fi module is loaded.
|
|
if not file then return 0 end
|
|
|
|
-- 0 means not connected, 1 connected
|
|
local out = file:read("*number")
|
|
file:close()
|
|
|
|
return out or 0
|
|
end
|
|
|
|
local function isMassStorageSupported()
|
|
-- we rely on 3rd party package for that. It should be installed as part of KOReader prerequisites,
|
|
local safemode_version = io.open("/usr/share/safemode/version", "rb")
|
|
if not safemode_version then return false end
|
|
safemode_version:close()
|
|
return true
|
|
end
|
|
|
|
local Cervantes = Generic:new{
|
|
model = "Cervantes",
|
|
isCervantes = yes,
|
|
isAlwaysPortrait = yes,
|
|
isTouchDevice = yes,
|
|
touch_legacy = true, -- SingleTouch input events
|
|
touch_switch_xy = true,
|
|
touch_mirrored_x = true,
|
|
hasOTAUpdates = yes,
|
|
hasFastWifiStatusQuery = yes,
|
|
hasKeys = yes,
|
|
hasWifiManager = yes,
|
|
canReboot = yes,
|
|
canPowerOff = yes,
|
|
canSuspend = yes,
|
|
home_dir = "/mnt/public",
|
|
|
|
-- do we support usb mass storage?
|
|
canToggleMassStorage = function() return isMassStorageSupported() end,
|
|
|
|
-- all devices, except the original Cervantes Touch, have frontlight
|
|
hasFrontlight = yes,
|
|
|
|
-- currently only Cervantes 4 has coloured frontlight
|
|
hasNaturalLight = no,
|
|
hasNaturalLightMixer = no,
|
|
|
|
-- HW inversion is generally safe on Cervantes, except on a few boards/kernels
|
|
canHWInvert = yes,
|
|
}
|
|
-- Cervantes Touch
|
|
local CervantesTouch = Cervantes:new{
|
|
model = "CervantesTouch",
|
|
display_dpi = 167,
|
|
hasFrontlight = no,
|
|
hasMultitouch = no,
|
|
}
|
|
-- Cervantes TouchLight / Fnac Touch Plus
|
|
local CervantesTouchLight = Cervantes:new{
|
|
model = "CervantesTouchLight",
|
|
display_dpi = 167,
|
|
hasMultitouch = no,
|
|
}
|
|
-- Cervantes 2013 / Fnac Touch Light
|
|
local Cervantes2013 = Cervantes:new{
|
|
model = "Cervantes2013",
|
|
display_dpi = 212,
|
|
hasMultitouch = no,
|
|
--- @fixme: Possibly requires canHWInvert = no, as it seems to be based on a similar board as the Kobo Aura...
|
|
}
|
|
-- Cervantes 3 / Fnac Touch Light 2
|
|
local Cervantes3 = Cervantes:new{
|
|
model = "Cervantes3",
|
|
display_dpi = 300,
|
|
hasMultitouch = no,
|
|
}
|
|
-- Cervantes 4
|
|
local Cervantes4 = Cervantes:new{
|
|
model = "Cervantes4",
|
|
display_dpi = 300,
|
|
hasNaturalLight = yes,
|
|
frontlight_settings = {
|
|
frontlight_white = "/sys/class/backlight/mxc_msp430_fl.0/brightness",
|
|
frontlight_mixer = "/sys/class/backlight/lm3630a_led/color",
|
|
nl_min = 0,
|
|
nl_max = 10,
|
|
nl_inverted = true,
|
|
},
|
|
}
|
|
|
|
-- input events
|
|
function Cervantes:initEventAdjustHooks()
|
|
if self.touch_switch_xy then
|
|
self.input:registerEventAdjustHook(self.input.adjustTouchSwitchXY)
|
|
end
|
|
|
|
if self.touch_mirrored_x then
|
|
self.input:registerEventAdjustHook(
|
|
self.input.adjustTouchMirrorX,
|
|
(self.screen:getWidth() - 1)
|
|
)
|
|
end
|
|
|
|
if self.touch_legacy then
|
|
self.input.handleTouchEv = self.input.handleTouchEvLegacy
|
|
end
|
|
end
|
|
|
|
function Cervantes:init()
|
|
self.screen = require("ffi/framebuffer_mxcfb"):new{device = self, debug = logger.dbg, is_always_portrait = self.isAlwaysPortrait()}
|
|
|
|
-- Automagically set this so we never have to remember to do it manually ;p
|
|
if self:hasNaturalLight() and self.frontlight_settings and self.frontlight_settings.frontlight_mixer then
|
|
self.hasNaturalLightMixer = yes
|
|
end
|
|
|
|
self.powerd = require("device/cervantes/powerd"):new{device = self}
|
|
self.input = require("device/input"):new{
|
|
device = self,
|
|
event_map = {
|
|
[61] = "Home",
|
|
[116] = "Power",
|
|
}
|
|
}
|
|
self.input.open("/dev/input/event0") -- Keys
|
|
self.input.open("/dev/input/event1") -- touchscreen
|
|
self.input.open("fake_events") -- usb events
|
|
self:initEventAdjustHooks()
|
|
Generic.init(self)
|
|
end
|
|
|
|
function Cervantes:setDateTime(year, month, day, hour, min, sec)
|
|
if hour == nil or min == nil then return true end
|
|
local command
|
|
if year and month and day then
|
|
command = string.format("date -s '%d-%d-%d %d:%d:%d'", year, month, day, hour, min, sec)
|
|
else
|
|
command = string.format("date -s '%d:%d'",hour, min)
|
|
end
|
|
if os.execute(command) == 0 then
|
|
os.execute('hwclock -u -w')
|
|
return true
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
function Cervantes:saveSettings()
|
|
self.powerd:saveSettings()
|
|
end
|
|
|
|
-- wireless
|
|
function Cervantes:initNetworkManager(NetworkMgr)
|
|
function NetworkMgr:turnOffWifi(complete_callback)
|
|
logger.info("Cervantes: disabling Wi-Fi")
|
|
self:releaseIP()
|
|
os.execute("./disable-wifi.sh")
|
|
if complete_callback then
|
|
complete_callback()
|
|
end
|
|
end
|
|
function NetworkMgr:turnOnWifi(complete_callback)
|
|
logger.info("Cervantes: enabling Wi-Fi")
|
|
os.execute("./enable-wifi.sh")
|
|
self:reconnectOrShowNetworkMenu(complete_callback)
|
|
end
|
|
function NetworkMgr:getNetworkInterfaceName()
|
|
return "eth0"
|
|
end
|
|
NetworkMgr:setWirelessBackend("wpa_supplicant", {ctrl_interface = "/var/run/wpa_supplicant/eth0"})
|
|
function NetworkMgr:obtainIP()
|
|
os.execute("./obtain-ip.sh")
|
|
end
|
|
function NetworkMgr:releaseIP()
|
|
os.execute("./release-ip.sh")
|
|
end
|
|
function NetworkMgr:restoreWifiAsync()
|
|
os.execute("./restore-wifi-async.sh")
|
|
end
|
|
function NetworkMgr:isWifiOn()
|
|
return 1 == isConnected()
|
|
end
|
|
end
|
|
|
|
-- screensaver
|
|
function Cervantes:supportsScreensaver()
|
|
return true
|
|
end
|
|
function Cervantes:intoScreenSaver()
|
|
local Screensaver = require("ui/screensaver")
|
|
if self.screen_saver_mode == false then
|
|
Screensaver:setup()
|
|
Screensaver:show()
|
|
end
|
|
self.powerd:beforeSuspend()
|
|
self.screen_saver_mode = true
|
|
end
|
|
function Cervantes:outofScreenSaver()
|
|
if self.screen_saver_mode == true then
|
|
local Screensaver = require("ui/screensaver")
|
|
Screensaver:close()
|
|
local UIManager = require("ui/uimanager")
|
|
UIManager:nextTick(function() UIManager:setDirty("all", "full") end)
|
|
end
|
|
self.powerd:afterResume()
|
|
self.screen_saver_mode = false
|
|
end
|
|
|
|
-- power functions: suspend, resume, reboot, poweroff
|
|
function Cervantes:suspend()
|
|
os.execute("./suspend.sh")
|
|
end
|
|
function Cervantes:resume()
|
|
os.execute("./resume.sh")
|
|
end
|
|
function Cervantes:reboot()
|
|
os.execute("sleep 1 && reboot &")
|
|
end
|
|
function Cervantes:powerOff()
|
|
os.execute("sleep 1 && halt &")
|
|
end
|
|
|
|
-- This method is the same as the one in kobo/device.lua except the sleep cover part.
|
|
function Cervantes:setEventHandlers(UIManager)
|
|
-- We do not want auto suspend procedure to waste battery during
|
|
-- suspend. So let's unschedule it when suspending, and restart it after
|
|
-- resume. Done via the plugin's onSuspend/onResume handlers.
|
|
UIManager.event_handlers.Suspend = function()
|
|
self:_beforeSuspend()
|
|
self:onPowerEvent("Suspend")
|
|
end
|
|
UIManager.event_handlers.Resume = function()
|
|
-- MONOTONIC doesn't tick during suspend,
|
|
-- invalidate the last battery capacity pull time so that we get up to date data immediately.
|
|
self:getPowerDevice():invalidateCapacityCache()
|
|
|
|
self:onPowerEvent("Resume")
|
|
self:_afterResume()
|
|
end
|
|
UIManager.event_handlers.PowerPress = function()
|
|
-- Always schedule power off.
|
|
-- Press the power button for 2+ seconds to shutdown directly from suspend.
|
|
UIManager:scheduleIn(2, UIManager.poweroff_action)
|
|
end
|
|
UIManager.event_handlers.PowerRelease = function()
|
|
if not UIManager._entered_poweroff_stage then
|
|
UIManager:unschedule(UIManager.poweroff_action)
|
|
-- resume if we were suspended
|
|
if self.screen_saver_mode then
|
|
UIManager.event_handlers.Resume()
|
|
else
|
|
UIManager.event_handlers.Suspend()
|
|
end
|
|
end
|
|
end
|
|
UIManager.event_handlers.Light = function()
|
|
self:getPowerDevice():toggleFrontlight()
|
|
end
|
|
-- USB plug events with a power-only charger
|
|
UIManager.event_handlers.Charging = function()
|
|
self:_beforeCharging()
|
|
-- NOTE: Plug/unplug events will wake the device up, which is why we put it back to sleep.
|
|
if self.screen_saver_mode then
|
|
UIManager.event_handlers.Suspend()
|
|
end
|
|
end
|
|
UIManager.event_handlers.NotCharging = function()
|
|
-- We need to put the device into suspension, other things need to be done before it.
|
|
self:usbPlugOut()
|
|
self:_afterNotCharging()
|
|
if self.screen_saver_mode then
|
|
UIManager.event_handlers.Suspend()
|
|
end
|
|
end
|
|
-- USB plug events with a data-aware host
|
|
UIManager.event_handlers.UsbPlugIn = function()
|
|
self:_beforeCharging()
|
|
-- NOTE: Plug/unplug events will wake the device up, which is why we put it back to sleep.
|
|
if self.screen_saver_mode then
|
|
UIManager.event_handlers.Suspend()
|
|
else
|
|
-- Potentially start an USBMS session
|
|
local MassStorage = require("ui/elements/mass_storage")
|
|
MassStorage:start()
|
|
end
|
|
end
|
|
UIManager.event_handlers.UsbPlugOut = function()
|
|
-- We need to put the device into suspension, other things need to be done before it.
|
|
self:usbPlugOut()
|
|
self:_afterNotCharging()
|
|
if self.screen_saver_mode then
|
|
UIManager.event_handlers.Suspend()
|
|
else
|
|
-- Potentially dismiss the USBMS ConfirmBox
|
|
local MassStorage = require("ui/elements/mass_storage")
|
|
MassStorage:dismiss()
|
|
end
|
|
end
|
|
end
|
|
|
|
-------------- device probe ------------
|
|
local product_id = getProductId()
|
|
|
|
if product_id == 22 then
|
|
return CervantesTouch
|
|
elseif product_id == 23 then
|
|
return CervantesTouchLight
|
|
elseif product_id == 33 then
|
|
return Cervantes2013
|
|
elseif product_id == 51 then
|
|
return Cervantes3
|
|
elseif product_id == 68 then
|
|
return Cervantes4
|
|
else
|
|
error("unrecognized Cervantes: board id " .. product_id)
|
|
end
|