-
-
Save ezdiy/a1e300bc05160032ea8390781f52abdd to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- Put this code into /applications/koreader/frontend/device/pocketbook/device.lua (replace file) | |
-- If you have older device, you'll also need to: | |
-- * https://github.com/ezdiy/inkview-compat/releases/download/v3/libinkview-compat.so | |
-- * Put the .so file into /applications/koreader/libs/libinkview-compat.so | |
local logger = require("logger") | |
local ffi = require("ffi") | |
local inkview = ffi.load("inkview") | |
local band = require("bit").band | |
local TimeVal = require("ui/timeval") | |
local util = require("util") | |
local Generic = require("device/generic/device") | |
local function yes() return true end | |
local function no() return false end | |
local PocketBook = Generic:new { | |
model = "PocketBook", | |
isPocketBook = yes, | |
isInBackGround = false, | |
hasOTAUpdates = yes, | |
hasWifiToggle = yes, | |
isTouchDevice = yes, | |
hasKeys = yes, | |
hasFrontlight = no, | |
canSuspend = no, | |
supportsScreensaver = no, | |
home_dir = "/mnt/ext1", | |
hasNaturalLightApi = no, | |
} | |
local EV_SYN = 0 | |
local EV_KEY = 1 | |
local EV_ABS = 3 | |
local EV_MSC = 4 | |
local SYN_REPORT = 0 | |
local SYN_CONFIG = 1 | |
local SYN_MT_REPORT = 2 | |
local ABS_X = 00 | |
local ABS_Y = 01 | |
local ABS_PRESSURE = 24 | |
local ABS_MT_SLOT = 47 | |
local ABS_MT_TOUCH_MAJOR = 48 | |
local ABS_MT_WIDTH_MAJOR = 50 | |
local ABS_MT_POSITION_X = 53 | |
local ABS_MT_POSITION_Y = 54 | |
local ABS_MT_TRACKING_ID = 57 | |
local ABS_MT_PRESSURE = 58 | |
local EVT_INIT = 21 | |
local EVT_EXIT = 22 | |
local EVT_SHOW = 23 | |
local EVT_REPAINT = 23 | |
local EVT_HIDE = 24 | |
local EVT_KEYDOWN = 25 | |
local EVT_KEYPRESS = 25 | |
local EVT_KEYUP = 26 | |
local EVT_KEYRELEASE = 26 | |
local EVT_KEYREPEAT = 28 | |
local EVT_POINTERUP = 29 | |
local EVT_POINTERDOWN = 30 | |
local EVT_POINTERMOVE = 31 | |
local EVT_ORIENTATION = 32 | |
local EVT_MTSYNC = 39 | |
local EVT_FOREGROUND = 151 | |
local EVT_BACKGROUND = 152 | |
local KEY_POWER = 0x01 | |
local KEY_DELETE = 0x08 | |
local KEY_OK = 0x0a | |
local KEY_UP = 0x11 | |
local KEY_DOWN = 0x12 | |
local KEY_LEFT = 0x13 | |
local KEY_RIGHT = 0x14 | |
local KEY_MINUS = 0x15 | |
local KEY_PLUS = 0x16 | |
local KEY_MENU = 0x17 | |
local KEY_PREV = 0x18 | |
local KEY_NEXT = 0x19 | |
local KEY_HOME = 0x1a | |
local KEY_BACK = 0x1b | |
local KEY_PREV2 = 0x1c | |
local KEY_NEXT2 = 0x1d | |
local KEY_COVEROPEN = 0x02 | |
local KEY_COVERCLOSE = 0x03 | |
local CONNECTED = 0xf00 | |
local NET_OK = 0 | |
local PANEL_DISABLED = 0 | |
ffi.cdef [[ | |
typedef int (*iv_handler)(int type, int par1, int par2); | |
void PrepareForLoop(iv_handler handler); | |
void ProcessEventLoop(); | |
void ClearOnExit(); | |
void OpenScreen(); | |
void iv_sleepmode(int on); | |
char *GetSoftwareVersion(void); | |
char *GetDeviceModel(void); | |
int GetFrontlightColor(void); | |
int QueryNetwork(); | |
int NetConnect(const char *name); | |
int NetDisconnect(); | |
typedef struct iv_mtinfo_s { | |
int active; | |
int x; | |
int y; | |
int pressure; | |
int rsv[4]; | |
} iv_mtinfo; | |
iv_mtinfo *GetTouchInfoI(int i); | |
void SetPanelType(int type); | |
int GetBatteryPower(); | |
]] | |
local compat, compat2 = inkview, inkview | |
if not pcall(function() _ = inkview.PrepareForLoop end) then | |
compat = ffi.load("inkview-compat") | |
compat2 = compat | |
logger.dbg("Switchin on compat, compat2") | |
elseif not pcall(function() _ = inkview.GetTouchInfoI end) then | |
compat2 = ffi.load("inkview-compat") | |
logger.dbg("Switchin on compat") | |
end | |
-------------------------------------------------------------------------- | |
-- FIXME: perhaps this should be made into a plugin and get proper UI at some point | |
local lastEvent = 0 | |
local suspendDelay | |
local function adaptiveSuspend() | |
local settings = G_reader_settings:readSetting("pocketbook_suspend") or { | |
enabled = true, -- if suspend is enabled at all | |
win = 1, -- count only events further apart than 1 second | |
ban = 2, -- initially, ban suspends for 2 seconds. | |
mul = 1.5, -- ban is multiplied by this each subsequent event | |
max = 30, -- events that happen further than 30 seconds since last one reset ban back to 1 | |
bat = 60, -- do adaptive suspend only if battery is above this. otherwise do aggressive suspend. | |
} | |
if not settings.enabled then | |
inkview.iv_sleepmode(0) | |
suspendDelay = 0 | |
return | |
end | |
if inkview.GetBatteryPower() < settings.bat then | |
inkview.iv_sleepmode(1) | |
suspendDelay = nil | |
return | |
end | |
local t = os.time() | |
-- too close event, just ignore it | |
if t < lastEvent + settings.win then | |
return | |
end | |
if t > lastEvent + settings.max then | |
logger.dbg("adaptive suspend event far into future, reset delay") | |
-- too far apart, so reset ban delay | |
suspendDelay = settings.ban | |
else | |
-- otherwise widen the delay ("adaptive"), but no further than max | |
suspendDelay = math.min(suspendDelay * settings.mul, settings.max) | |
end | |
lastEvent = t | |
logger.dbg("adaptive suspend new delay",suspendDelay) | |
-- disable suspend. will be re-enabled once suspendDelay expires | |
inkview.iv_sleepmode(0) | |
end | |
local eventq | |
local ts | |
local function genEmuEvent(t,c,v) | |
assert(ts, "need ts") | |
table.insert(eventq, { | |
type = tonumber(t), | |
code = tonumber(c), | |
value = tonumber(v) or v, | |
time = ts, | |
}) | |
end | |
-- this is more or less direct translation of pb_event_handler() | |
local nTouch = 0 | |
local function translateEvent(t, par1, par2) | |
if eventq == nil then | |
return 0 | |
end | |
logger.dbg("received event",t,par1,par2) | |
adaptiveSuspend() | |
ts = TimeVal:now() -- shared to lessen gc spam | |
if t == EVT_INIT then | |
logger.dbg("EVT_INIT") | |
inkview.SetPanelType(PANEL_DISABLED); | |
inkview.iv_sleepmode(0) | |
logger.dbg("SetPanelType(PANEL_DISABLED) done") | |
elseif t == EVT_POINTERDOWN then | |
nTouch = 1 | |
genEmuEvent(EV_ABS, ABS_MT_TRACKING_ID, 0) | |
genEmuEvent(EV_ABS, ABS_MT_POSITION_X, par1) | |
genEmuEvent(EV_ABS, ABS_MT_POSITION_Y, par2) | |
elseif t == EVT_MTSYNC then | |
if nTouch > 0 and par2 == 2 then | |
if ok then | |
nTouch = 2 | |
for i = 0, 1 do | |
genEmuEvent(EV_ABS, ABS_MT_SLOT, i); | |
genEmuEvent(EV_ABS, ABS_MT_TRACKING_ID, i); | |
local mt = compat2.GetTouchInfoI(i) | |
genEmuEvent(EV_ABS, ABS_MT_POSITION_X, mt.x) | |
genEmuEvent(EV_ABS, ABS_MT_POSITION_Y, mt.y) | |
genEmuEvent(EV_SYN, SYN_REPORT, 0) | |
end | |
end | |
elseif par2 == 0 then | |
for i = 0, 1 do | |
genEmuEvent(EV_ABS, ABS_MT_SLOT, i); | |
genEmuEvent(EV_ABS, ABS_MT_TRACKING_ID, -1); | |
genEmuEvent(EV_SYN, SYN_REPORT, 0) | |
end | |
else | |
genEmuEvent(EV_SYN, SYN_REPORT, 0) | |
end | |
elseif t == EVT_POINTERMOVE then | |
if nTouch == 1 then | |
genEmuEvent(EV_ABS, ABS_MT_POSITION_X, par1) | |
genEmuEvent(EV_ABS, ABS_MT_POSITION_Y, par2) | |
end | |
elseif t == EVT_POINTERUP then | |
if nTouch == 1 then | |
genEmuEvent(EV_ABS, ABS_MT_TRACKING_ID, -1) | |
end | |
nTouch = 0 | |
else | |
genEmuEvent(t, par1, par2) | |
end | |
return 1 | |
end | |
-- FIXME: Base device class shouldn't hardcode where input comes from - that's for the frontend, ie us, to decide. | |
-- Currently, generics brings forth ffi/input which awkwardly decides on its own under our nodes. This breaks owner | |
-- hierarchy resulting hacks like this whenever there's more than one driver for a given device. | |
local lastlog = 0 | |
package.loaded["ffi/input"] = { waitForEvent = function(t) | |
assert(eventq, "waitForEvent() invoked after device shutdown") | |
if #eventq > 0 then return table.remove(eventq, 1) end | |
local expire = TimeVal:new { usec = t } + TimeVal:now() | |
while expire > TimeVal:now() do | |
local canlog = false | |
if lastlog < os.time() then | |
lastlog = os.time() + 5 | |
canlog = true | |
end | |
if canlog then logger.dbg("ProcessEventLoop()") end | |
compat.ProcessEventLoop() | |
if canlog or #eventq > 0 then logger.dbg("ProcessEventLoop() end, eventq = ", #eventq) end | |
if #eventq > 0 then return table.remove(eventq, 1) end | |
end | |
if suspendDelay and suspendDelay > 0 and (lastEvent + suspendDelay < os.time()) then | |
-- suspend ban expired, so re-enable it | |
logger.dbg("iv_sleepmode(1)") | |
inkview.iv_sleepmode(1) | |
end | |
-- FIXME: This is a workaround for messy gesture detection timers in generic input and gesture module. | |
-- Really it should just accept nil result and perform exponential back off each time it sees subsequent nil. | |
-- Currently we're doing error() 1000 times every touch, which revs up the CPU scaling freq needlessly. | |
if t == 100 then | |
error("timed out") | |
end | |
return nil | |
end } | |
function PocketBook:exit() | |
self.screen:close() | |
-- no further waitForEvent() should be called by now | |
eventq = nil | |
logger.dbg("ClearOnExit()") | |
compat.ClearOnExit() | |
end | |
function PocketBook:init() | |
if not self:canUseCBB() or not self:canHWInvert() then | |
local dummy = require("ffi/posix_h") | |
local C = ffi.C | |
logger.info("Blacklisting the C BB on this device") | |
C.setenv("KO_NO_CBB", "true", 1) | |
G_reader_settings:saveSetting("dev_no_c_blitter", true) | |
end | |
logger.dbg("OpenScreen()") | |
inkview.OpenScreen() | |
logger.dbg("OpenScreen() done") | |
self.screen = require("ffi/framebuffer_mxcfb"):new{device = self, debug = logger.dbg} | |
local pd = require("device/pocketbook/powerd") | |
function pd:init() | |
-- powerd is broken trying to touch backlight APIs even if there's no device support | |
local color = self.device:hasNaturalLight() and inkview.GetFrontlightColor() or 0 | |
self.fl_warmth = color >= 0 and color or 0 | |
end | |
self.powerd = pd:new{device = self} | |
logger.dbg("powerd init done") | |
self.input = require("device/input"):new { | |
device = self, | |
event_map = { | |
[KEY_MENU] = "Menu", | |
[KEY_PREV] = "LPgBack", | |
[KEY_NEXT] = "LPgFwd", | |
[KEY_UP] = "Up", | |
[KEY_DOWN] = "Down", | |
[KEY_LEFT] = "Left", | |
[KEY_RIGHT] = "Right", | |
[KEY_OK] = "Press", | |
}, | |
handleMiscEv = function(this, ev) | |
if ev.code == EVT_HIDE or ev.code == EVT_BACKGROUND then | |
return "SaveState" | |
elseif ev.code == EVT_FOREGROUND then | |
require("ui/uimanager"):setDirty('all', 'partial') | |
return "Foreground" | |
end | |
end, | |
} | |
logger.dbg("PrepareForLoop()") | |
compat.PrepareForLoop(translateEvent) | |
logger.dbg("PrepareForLoop() done") | |
eventq = {} | |
self.input:registerEventAdjustHook(function(_input, ev) | |
if ev.type == EVT_KEYDOWN or ev.type == EVT_KEYUP then | |
ev.value = ev.type == EVT_KEYDOWN and 1 or 0 | |
ev.type = EV_KEY -- linux/input.h Key-Event | |
end | |
if ev.type == EVT_FOREGROUND or ev.type == EVT_BACKGROUND or ev.type == EVT_HIDE then | |
ev.code = ev.type | |
ev.type = EV_MSC | |
end | |
if ev.type == EVT_EXIT then | |
require("ui/uimanager"):broadcastEvent( | |
require("ui/event"):new("Close")) | |
end | |
end) | |
-- fix rotation for Color Lux device | |
if PocketBook:getDeviceModel() == "PocketBook Color Lux" then | |
self.screen.blitbuffer_rotation_mode = self.screen.ORIENTATION_PORTRAIT | |
self.screen.native_rotation_mode = self.screen.ORIENTATION_PORTRAIT | |
end | |
Generic.init(self) | |
end | |
function PocketBook:setDateTime(year, month, day, hour, min, sec) | |
if hour == nil or min == nil then return true end | |
local su = "/mnt/secure/su" | |
su = util.pathExists(su) and (su .. " ") or "" | |
local command | |
if year and month and day then | |
command = string.format(su .. "/bin/date -s '%d-%d-%d %d:%d:%d'", year, month, day, hour, min, sec) | |
else | |
command = string.format(su .. "/bin/date -s '%d:%d'",hour, min) | |
end | |
if os.execute(command) == 0 then | |
os.execute(su .. '/sbin/hwclock -u -w') | |
return true | |
else | |
return false | |
end | |
end | |
function PocketBook:initNetworkManager(NetworkMgr) | |
function NetworkMgr:turnOnWifi(complete_callback) | |
if inkview.NetConnect(nil) ~= NET_OK then | |
logger.info('NetConnect failed') | |
end | |
if complete_callback then | |
complete_callback() | |
end | |
end | |
function NetworkMgr:turnOffWifi(complete_callback) | |
inkview.NetDisconnect() | |
if complete_callback then | |
complete_callback() | |
end | |
end | |
function NetworkMgr:isWifiOn() | |
return band(inkview.QueryNetwork(), CONNECTED) ~= 0 | |
end | |
end | |
function PocketBook:getSoftwareVersion() | |
return ffi.string(inkview.GetSoftwareVersion()) | |
end | |
function PocketBook:getDeviceModel() | |
return ffi.string(inkview.GetDeviceModel()) | |
end | |
-------------------------------------------------------------------------- | |
-- PocketBook Mini (515) | |
local PocketBook515 = PocketBook:new{ | |
model = "PB515", | |
display_dpi = 200, | |
isTouchDevice = no, | |
hasFrontlight = no, | |
hasDPad = yes, | |
hasFewKeys = yes, | |
} | |
-- PocketBook 606 (606) | |
local PocketBook606 = PocketBook:new{ | |
model = "PB606", | |
display_dpi = 212, | |
isTouchDevice = no, | |
hasFrontlight = no, | |
hasDPad = yes, | |
hasFewKeys = yes, | |
} | |
-- PocketBook Basic (611) | |
local PocketBook611 = PocketBook:new{ | |
model = "PB611", | |
display_dpi = 167, | |
isTouchDevice = no, | |
hasFrontlight = no, | |
hasDPad = yes, | |
hasFewKeys = yes, | |
} | |
-- PocketBook Basic (613) | |
local PocketBook613 = PocketBook:new{ | |
model = "PB613B", | |
display_dpi = 167, | |
isTouchDevice = no, | |
hasWifiToggle = no, | |
hasFrontlight = no, | |
hasDPad = yes, | |
hasFewKeys = yes, | |
} | |
-- PocketBook Basic 2 / Basic 3 (614/614W) | |
local PocketBook614W = PocketBook:new{ | |
model = "PB614W", | |
display_dpi = 167, | |
isTouchDevice = no, | |
hasFrontlight = no, | |
hasDPad = yes, | |
hasFewKeys = yes, | |
} | |
-- PocketBook Basic Lux / 615 Plus (615/615W) | |
local PocketBook615 = PocketBook:new{ | |
model = "PBBLux", | |
display_dpi = 212, | |
isTouchDevice = no, | |
hasDPad = yes, | |
hasFewKeys = yes, | |
} | |
-- PocketBook Basic Lux 2 (616/616W) | |
local PocketBook616 = PocketBook:new{ | |
model = "PBBLux2", | |
display_dpi = 212, | |
isTouchDevice = no, | |
hasDPad = yes, | |
hasFewKeys = yes, | |
} | |
-- PocketBook Touch (622) | |
local PocketBook622 = PocketBook:new{ | |
model = "PBTouch", | |
display_dpi = 167, | |
hasFrontlight = no, | |
} | |
-- PocketBook Touch Lux (623) | |
local PocketBook623 = PocketBook:new{ | |
model = "PBTouchLux", | |
display_dpi = 212, | |
} | |
-- PocketBook Basic Touch (624) | |
local PocketBook624 = PocketBook:new{ | |
model = "PBBasicTouch", | |
display_dpi = 167, | |
hasFrontlight = no, | |
} | |
-- PocketBook Basic Touch 2 (625) | |
local PocketBook625 = PocketBook:new{ | |
model = "PBBasicTouch2", | |
display_dpi = 167, | |
hasFrontlight = no, | |
} | |
-- PocketBook Touch Lux 2 / Touch Lux 3 (626) | |
local PocketBook626 = PocketBook:new{ | |
model = "PBLux3", | |
display_dpi = 212, | |
} | |
-- PocketBook Touch Lux 4 (627) | |
local PocketBook627 = PocketBook:new{ | |
model = "PBLux4", | |
display_dpi = 212, | |
} | |
-- PocketBook Touch Lux 5 (628) | |
local PocketBook628 = PocketBook:new{ | |
model = "PBTouchLux5", | |
display_dpi = 212, | |
isAlwaysPortrait = yes, | |
hasNaturalLight = yes, | |
} | |
-- PocketBook Sense / Sense 2 (630) | |
local PocketBook630 = PocketBook:new{ | |
model = "PBSense", | |
display_dpi = 212, | |
} | |
-- PocketBook Touch HD / Touch HD 2 (631) | |
local PocketBook631 = PocketBook:new{ | |
model = "PBTouchHD", | |
display_dpi = 300, | |
-- see https://github.com/koreader/koreader/pull/6531#issuecomment-676629182 | |
hasNaturalLight = function() return inkview.GetFrontlightColor() >= 0 end, | |
} | |
-- PocketBook Touch HD Plus / Touch HD 3 (632) | |
local PocketBook632 = PocketBook:new{ | |
model = "PBTouchHDPlus", | |
display_dpi = 300, | |
isAlwaysPortrait = yes, | |
hasNaturalLight = yes, | |
} | |
-- PocketBook Color (633) | |
local PocketBook633 = PocketBook:new{ | |
model = "PBColor", | |
display_dpi = 300, | |
hasColorScreen = yes, | |
canUseCBB = no, -- 24bpp | |
isAlwaysPortrait = yes, | |
} | |
-- PocketBook Aqua (640) | |
local PocketBook640 = PocketBook:new{ | |
model = "PBAqua", | |
display_dpi = 167, | |
} | |
-- PocketBook Aqua 2 (641) | |
local PocketBook641 = PocketBook:new{ | |
model = "PBAqua2", | |
display_dpi = 212, | |
} | |
-- PocketBook Ultra (650) | |
local PocketBook650 = PocketBook:new{ | |
model = "PBUltra", | |
display_dpi = 212, | |
} | |
-- PocketBook InkPad 3 (740) | |
local PocketBook740 = PocketBook:new{ | |
model = "PBInkPad3", | |
display_dpi = 300, | |
isAlwaysPortrait = yes, | |
hasFrontLight = no, | |
} | |
-- PocketBook InkPad 3 Pro (740_2) | |
local PocketBook740_2 = PocketBook:new{ | |
model = "PBInkPad3Pro", | |
display_dpi = 300, | |
isAlwaysPortrait = yes, | |
hasFrontLight = no, | |
} | |
-- PocketBook Color Lux (801) | |
local PocketBookColorLux = PocketBook:new{ | |
model = "PBColorLux", | |
display_dpi = 125, | |
hasColorScreen = yes, | |
has3BytesWideFrameBuffer = yes, | |
canUseCBB = no, -- 24bpp | |
} | |
-- PocketBook InkPad / InkPad 2 (840) | |
local PocketBook840 = PocketBook:new{ | |
model = "PBInkPad", | |
display_dpi = 250, | |
} | |
-- PocketBook InkPad X (1040) | |
local PocketBook1040 = PocketBook:new{ | |
model = "PB1040", | |
display_dpi = 227, | |
isAlwaysPortrait = yes, | |
hasNaturalLight = yes, | |
} | |
logger.info('SoftwareVersion: ', PocketBook:getSoftwareVersion()) | |
local codename = PocketBook:getDeviceModel() | |
if codename == "PocketBook 515" then | |
return PocketBook515 | |
elseif codename == "PB606" or codename == "PocketBook 606" then | |
return PocketBook606 | |
elseif codename == "PocketBook 611" then | |
return PocketBook611 | |
elseif codename == "PocketBook 613" then | |
return PocketBook613 | |
elseif codename == "PocketBook 614" or codename == "PocketBook 614W" then | |
return PocketBook614W | |
elseif codename == "PB615" or codename == "PB615W" or | |
codename == "PocketBook 615" or codename == "PocketBook 615W" then | |
return PocketBook615 | |
elseif codename == "PB616" or codename == "PB616W" or | |
codename == "PocketBook 616" or codename == "PocketBook 616W" then | |
return PocketBook616 | |
elseif codename == "PocketBook 622" then | |
return PocketBook622 | |
elseif codename == "PocketBook 623" then | |
return PocketBook623 | |
elseif codename == "PocketBook 624" then | |
return PocketBook624 | |
elseif codename == "PB625" then | |
return PocketBook625 | |
elseif codename == "PB626" or codename == "PB626(2)-TL3" or | |
codename == "PocketBook 626" then | |
return PocketBook626 | |
elseif codename == "PB627" then | |
return PocketBook627 | |
elseif codename == "PB628" then | |
return PocketBook628 | |
elseif codename == "PocketBook 630" then | |
return PocketBook630 | |
elseif codename == "PB631" or codename == "PocketBook 631" then | |
return PocketBook631 | |
elseif codename == "PB632" then | |
return PocketBook632 | |
elseif codename == "PB633" then | |
return PocketBook633 | |
elseif codename == "PB640" or codename == "PocketBook 640" then | |
return PocketBook640 | |
elseif codename == "PB641" then | |
return PocketBook641 | |
elseif codename == "PB650" or codename == "PocketBook 650" then | |
return PocketBook650 | |
elseif codename == "PB740" then | |
return PocketBook740 | |
elseif codename == "PB740-2" then | |
return PocketBook740_2 | |
elseif codename == "PocketBook 840" then | |
return PocketBook840 | |
elseif codename == "PB1040" then | |
return PocketBook1040 | |
elseif codename == "PocketBook Color Lux" then | |
return PocketBookColorLux | |
else | |
error("unrecognized PocketBook model " .. codename) | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment