You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
koreader/frontend/device/remarkable/device.lua

276 lines
8.7 KiB
Lua

local Generic = require("device/generic/device") -- <= look at this file!
local PluginShare = require("pluginshare")
local logger = require("logger")
local time = require("ui/time")
local ffi = require("ffi")
local C = ffi.C
require("ffi/linux_input_h")
local function yes() return true end
local function no() return false end
-- returns isRm2, device_model
local function getModel()
local f = io.open("/sys/devices/soc0/machine")
if not f then
error("missing sysfs entry for a remarkable")
end
local model = f:read("*line")
f:close()
return model == "reMarkable 2.0", model
end
-- Resolutions from libremarkable src/framebuffer/common.rs
local screen_width = 1404 -- unscaled_size_check: ignore
local screen_height = 1872 -- unscaled_size_check: ignore
local wacom_width = 15725 -- unscaled_size_check: ignore
local wacom_height = 20967 -- unscaled_size_check: ignore
local wacom_scale_x = screen_width / wacom_width
local wacom_scale_y = screen_height / wacom_height
local isRm2, rm_model = getModel()
Clarify our OOP semantics across the codebase (#9586) Basically: * Use `extend` for class definitions * Use `new` for object instantiations That includes some minor code cleanups along the way: * Updated `Widget`'s docs to make the semantics clearer. * Removed `should_restrict_JIT` (it's been dead code since https://github.com/koreader/android-luajit-launcher/pull/283) * Minor refactoring of LuaSettings/LuaData/LuaDefaults/DocSettings to behave (mostly, they are instantiated via `open` instead of `new`) like everything else and handle inheritance properly (i.e., DocSettings is now a proper LuaSettings subclass). * Default to `WidgetContainer` instead of `InputContainer` for stuff that doesn't actually setup key/gesture events. * Ditto for explicit `*Listener` only classes, make sure they're based on `EventListener` instead of something uselessly fancier. * Unless absolutely necessary, do not store references in class objects, ever; only values. Instead, always store references in instances, to avoid both sneaky inheritance issues, and sneaky GC pinning of stale references. * ReaderUI: Fix one such issue with its `active_widgets` array, with critical implications, as it essentially pinned *all* of ReaderUI's modules, including their reference to the `Document` instance (i.e., that was a big-ass leak). * Terminal: Make sure the shell is killed on plugin teardown. * InputText: Fix Home/End/Del physical keys to behave sensibly. * InputContainer/WidgetContainer: If necessary, compute self.dimen at paintTo time (previously, only InputContainers did, which might have had something to do with random widgets unconcerned about input using it as a baseclass instead of WidgetContainer...). * OverlapGroup: Compute self.dimen at *init* time, because for some reason it needs to do that, but do it directly in OverlapGroup instead of going through a weird WidgetContainer method that it was the sole user of. * ReaderCropping: Under no circumstances should a Document instance member (here, self.bbox) risk being `nil`ed! * Kobo: Minor code cleanups.
2 years ago
local Remarkable = Generic:extend{
isRemarkable = yes,
model = rm_model,
hasKeys = yes,
needsScreenRefreshAfterResume = no,
hasOTAUpdates = yes,
canReboot = yes,
canPowerOff = yes,
canSuspend = yes,
isTouchDevice = yes,
hasFrontlight = no,
hasSystemFonts = yes,
display_dpi = 226,
-- Despite the SoC supporting it, it's finicky in practice (#6772)
canHWInvert = no,
home_dir = "/home/root",
}
Clarify our OOP semantics across the codebase (#9586) Basically: * Use `extend` for class definitions * Use `new` for object instantiations That includes some minor code cleanups along the way: * Updated `Widget`'s docs to make the semantics clearer. * Removed `should_restrict_JIT` (it's been dead code since https://github.com/koreader/android-luajit-launcher/pull/283) * Minor refactoring of LuaSettings/LuaData/LuaDefaults/DocSettings to behave (mostly, they are instantiated via `open` instead of `new`) like everything else and handle inheritance properly (i.e., DocSettings is now a proper LuaSettings subclass). * Default to `WidgetContainer` instead of `InputContainer` for stuff that doesn't actually setup key/gesture events. * Ditto for explicit `*Listener` only classes, make sure they're based on `EventListener` instead of something uselessly fancier. * Unless absolutely necessary, do not store references in class objects, ever; only values. Instead, always store references in instances, to avoid both sneaky inheritance issues, and sneaky GC pinning of stale references. * ReaderUI: Fix one such issue with its `active_widgets` array, with critical implications, as it essentially pinned *all* of ReaderUI's modules, including their reference to the `Document` instance (i.e., that was a big-ass leak). * Terminal: Make sure the shell is killed on plugin teardown. * InputText: Fix Home/End/Del physical keys to behave sensibly. * InputContainer/WidgetContainer: If necessary, compute self.dimen at paintTo time (previously, only InputContainers did, which might have had something to do with random widgets unconcerned about input using it as a baseclass instead of WidgetContainer...). * OverlapGroup: Compute self.dimen at *init* time, because for some reason it needs to do that, but do it directly in OverlapGroup instead of going through a weird WidgetContainer method that it was the sole user of. * ReaderCropping: Under no circumstances should a Document instance member (here, self.bbox) risk being `nil`ed! * Kobo: Minor code cleanups.
2 years ago
local Remarkable1 = Remarkable:extend{
mt_width = 767, -- unscaled_size_check: ignore
mt_height = 1023, -- unscaled_size_check: ignore
input_wacom = "/dev/input/event0",
input_ts = "/dev/input/event1",
input_buttons = "/dev/input/event2",
battery_path = "/sys/class/power_supply/bq27441-0/capacity",
status_path = "/sys/class/power_supply/bq27441-0/status",
}
function Remarkable1:adjustTouchEvent(ev, by)
if ev.type == C.EV_ABS then
-- Mirror X and Y and scale up both X & Y as touch input is different res from
-- display
if ev.code == C.ABS_MT_POSITION_X then
ev.value = (Remarkable1.mt_width - ev.value) * by.mt_scale_x
end
if ev.code == C.ABS_MT_POSITION_Y then
ev.value = (Remarkable1.mt_height - ev.value) * by.mt_scale_y
end
end
end
Clarify our OOP semantics across the codebase (#9586) Basically: * Use `extend` for class definitions * Use `new` for object instantiations That includes some minor code cleanups along the way: * Updated `Widget`'s docs to make the semantics clearer. * Removed `should_restrict_JIT` (it's been dead code since https://github.com/koreader/android-luajit-launcher/pull/283) * Minor refactoring of LuaSettings/LuaData/LuaDefaults/DocSettings to behave (mostly, they are instantiated via `open` instead of `new`) like everything else and handle inheritance properly (i.e., DocSettings is now a proper LuaSettings subclass). * Default to `WidgetContainer` instead of `InputContainer` for stuff that doesn't actually setup key/gesture events. * Ditto for explicit `*Listener` only classes, make sure they're based on `EventListener` instead of something uselessly fancier. * Unless absolutely necessary, do not store references in class objects, ever; only values. Instead, always store references in instances, to avoid both sneaky inheritance issues, and sneaky GC pinning of stale references. * ReaderUI: Fix one such issue with its `active_widgets` array, with critical implications, as it essentially pinned *all* of ReaderUI's modules, including their reference to the `Document` instance (i.e., that was a big-ass leak). * Terminal: Make sure the shell is killed on plugin teardown. * InputText: Fix Home/End/Del physical keys to behave sensibly. * InputContainer/WidgetContainer: If necessary, compute self.dimen at paintTo time (previously, only InputContainers did, which might have had something to do with random widgets unconcerned about input using it as a baseclass instead of WidgetContainer...). * OverlapGroup: Compute self.dimen at *init* time, because for some reason it needs to do that, but do it directly in OverlapGroup instead of going through a weird WidgetContainer method that it was the sole user of. * ReaderCropping: Under no circumstances should a Document instance member (here, self.bbox) risk being `nil`ed! * Kobo: Minor code cleanups.
2 years ago
local Remarkable2 = Remarkable:extend{
mt_width = 1403, -- unscaled_size_check: ignore
mt_height = 1871, -- unscaled_size_check: ignore
input_wacom = "/dev/input/event1",
input_ts = "/dev/input/event2",
input_buttons = "/dev/input/event0",
battery_path = "/sys/class/power_supply/max77818_battery/capacity",
status_path = "/sys/class/power_supply/max77818-charger/status",
}
function Remarkable2:adjustTouchEvent(ev, by)
if ev.type == C.EV_ABS then
-- Mirror Y and scale up both X & Y as touch input is different res from
-- display
if ev.code == C.ABS_MT_POSITION_X then
ev.value = (ev.value) * by.mt_scale_x
end
if ev.code == C.ABS_MT_POSITION_Y then
ev.value = (Remarkable2.mt_height - ev.value) * by.mt_scale_y
end
end
-- Wacom uses CLOCK_REALTIME, but the Touchscreen spits out frozen timestamps.
-- Inject CLOCK_MONOTONIC timestamps at the end of every input frame in order to have consistent gesture detection across input devices.
-- c.f., #7536
if ev.type == C.EV_SYN and ev.code == C.SYN_REPORT then
local sec, usec = time.split_s_us(time.now())
ev.time = {
sec = sec,
usec = usec
}
end
end
local adjustAbsEvt = function(self, ev)
if ev.type == C.EV_ABS then
if ev.code == C.ABS_X then
ev.code = C.ABS_Y
ev.value = (wacom_height - ev.value) * wacom_scale_y
elseif ev.code == C.ABS_Y then
ev.code = C.ABS_X
ev.value = ev.value * wacom_scale_x
end
end
end
function Remarkable:init()
local oxide_running = os.execute("systemctl is-active --quiet tarnish") == 0
logger.info(string.format("Oxide running?: %s", oxide_running))
-- experiment
-- logger.info("PPID:")
-- local parent_process = os.execute("echo $PPID")
-- os.execute("ps | grep $PPID")
-- logger.info(string.format("parent proccess is oxide?: %s", parent_process_is_oxide))
self.screen = require("ffi/framebuffer_mxcfb"):new{device = self, debug = logger.dbg}
self.powerd = require("device/remarkable/powerd"):new{
device = self,
capacity_file = self.battery_path,
status_file = self.status_path,
}
local event_map = require("device/remarkable/event_map")
-- If we are launched while Oxide is running, remove Power from the event map
if oxide_running then
event_map[116] = nil
end
self.input = require("device/input"):new{
device = self,
event_map = require("device/remarkable/event_map"),
wacom_protocol = true,
}
self.input.open(self.input_wacom) -- Wacom
self.input.open(self.input_ts) -- Touchscreen
self.input.open(self.input_buttons) -- Buttons
local scalex = screen_width / self.mt_width
local scaley = screen_height / self.mt_height
self.input:registerEventAdjustHook(adjustAbsEvt)
self.input:registerEventAdjustHook(self.adjustTouchEvent, {mt_scale_x=scalex, mt_scale_y=scaley})
-- USB plug/unplug, battery charge/not charging are generated as fake events
self.input.open("fake_events")
local rotation_mode = self.screen.DEVICE_ROTATED_UPRIGHT
self.screen.native_rotation_mode = rotation_mode
self.screen.cur_rotation_mode = rotation_mode
if oxide_running then
-- Disable autosuspend on this device
PluginShare.pause_auto_suspend = true
end
Generic.init(self)
end
function Remarkable:supportsScreensaver() return true end
function Remarkable:initNetworkManager(NetworkMgr)
function NetworkMgr:turnOnWifi(complete_callback)
os.execute("./enable-wifi.sh")
self:reconnectOrShowNetworkMenu(function()
self:connectivityCheck(1, complete_callback)
end)
end
function NetworkMgr:turnOffWifi(complete_callback)
os.execute("./disable-wifi.sh")
if complete_callback then
complete_callback()
end
end
function NetworkMgr:getNetworkInterfaceName()
return "wlan0"
end
NetworkMgr:setWirelessBackend("wpa_supplicant", {ctrl_interface = "/var/run/wpa_supplicant/wlan0"})
NetworkMgr.isWifiOn = function()
return NetworkMgr:isConnected()
end
end
function Remarkable: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("timedatectl set-time '%d-%d-%d %d:%d:%d'", year, month, day, hour, min, sec)
else
command = string.format("timedatectl set-time '%d:%d'",hour, min)
end
return os.execute(command) == 0
end
function Remarkable:resume()
end
function Remarkable:suspend()
os.execute("./disable-wifi.sh")
os.execute("systemctl suspend")
end
function Remarkable:powerOff()
os.execute("systemctl poweroff")
end
function Remarkable:reboot()
os.execute("systemctl reboot")
end
logger.info(string.format("Starting %s", rm_model))
function Remarkable:getDefaultCoverPath()
return "/usr/share/remarkable/poweroff.png"
end
function Remarkable:setEventHandlers(UIManager)
Assorted bag'o tweaks & fixes (#9569) * 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)
2 years ago
UIManager.event_handlers.Suspend = function()
self:_beforeSuspend()
self:onPowerEvent("Suspend")
end
Assorted bag'o tweaks & fixes (#9569) * 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)
2 years ago
UIManager.event_handlers.Resume = function()
self:onPowerEvent("Resume")
self:_afterResume()
end
Assorted bag'o tweaks & fixes (#9569) * 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)
2 years ago
UIManager.event_handlers.PowerPress = function()
UIManager:scheduleIn(2, UIManager.poweroff_action)
end
Assorted bag'o tweaks & fixes (#9569) * 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)
2 years ago
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
if self.screen_saver_lock then
logger.dbg("Pressed power while awake in screen saver mode, going back to suspend...")
self:_beforeSuspend()
self.powerd:beforeSuspend() -- this won't be run by onPowerEvent because we're in screen_saver_mode
self:onPowerEvent("Suspend")
else
UIManager.event_handlers.Resume()
end
else
Assorted bag'o tweaks & fixes (#9569) * 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)
2 years ago
UIManager.event_handlers.Suspend()
end
end
end
end
if isRm2 then
if not os.getenv("RM2FB_SHIM") then
error("reMarkable2 requires RM2FB to work (https://github.com/ddvk/remarkable2-framebuffer)")
end
return Remarkable2
else
return Remarkable1
end