mirror of https://github.com/koreader/koreader
[feat] Add support for BQ/Fnac devices (#4294)
Adds support for devices found in https://blog.bq.com/es/bq-ereaders-developers-program/. Tested on BQ Cervantes 4 (last BQ device from 2017). It adds a new touch input event handler (discussed in #4275) which should work on other single touch devices (ie: Kobo Touch, Mini, Glo, Aura HD) but wasn't tested. Includes base bump with: [feat] Add BQ/Fnac device support (https://github.com/koreader/koreader-base/pull/745)pull/4299/head v2018.11
parent
d1298ff8e5
commit
1e69fae7bc
@ -1 +1 @@
|
|||||||
Subproject commit 42bc013b62c8039d733513e00a92dd6c70d8b421
|
Subproject commit f13f1ce2ee42a64788ad80adb12d34197406b984
|
@ -0,0 +1,220 @@
|
|||||||
|
local Generic = require("device/generic/device")
|
||||||
|
local TimeVal = require("ui/timeval")
|
||||||
|
local logger = require("logger")
|
||||||
|
|
||||||
|
local function yes() return true 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 = tonumber(ntxinfo_pcb:read()) or 0
|
||||||
|
ntxinfo_pcb:close()
|
||||||
|
return product_id
|
||||||
|
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,
|
||||||
|
touch_probe_ev_epoch_time = true,
|
||||||
|
hasOTAUpdates = yes,
|
||||||
|
hasKeys = yes,
|
||||||
|
internal_storage_mount_point = "/mnt/public/",
|
||||||
|
}
|
||||||
|
-- Cervantes Touch
|
||||||
|
local CervantesTouch = Cervantes:new{
|
||||||
|
model = "Cervantes Touch",
|
||||||
|
display_dpi = 167,
|
||||||
|
}
|
||||||
|
-- Cervantes TouchLight / Fnac Touch Plus
|
||||||
|
local CervantesTouchLight = Cervantes:new{
|
||||||
|
model = "Cervantes TouchLight",
|
||||||
|
display_dpi = 167,
|
||||||
|
hasFrontlight = yes,
|
||||||
|
}
|
||||||
|
-- Cervantes 2013 / Fnac Touch Light
|
||||||
|
local Cervantes2013 = Cervantes:new{
|
||||||
|
model = "Cervantes 2013",
|
||||||
|
display_dpi = 212,
|
||||||
|
hasFrontlight = yes,
|
||||||
|
}
|
||||||
|
-- Cervantes 3 / Fnac Touch Light 2
|
||||||
|
local Cervantes3 = Cervantes:new{
|
||||||
|
model = "Cervantes 3",
|
||||||
|
display_dpi = 300,
|
||||||
|
hasFrontlight = yes,
|
||||||
|
}
|
||||||
|
-- Cervantes 4
|
||||||
|
local Cervantes4 = Cervantes:new{
|
||||||
|
model = "Cervantes 4",
|
||||||
|
display_dpi = 300,
|
||||||
|
hasFrontlight = yes,
|
||||||
|
hasNaturalLight = yes,
|
||||||
|
frontlight_settings = {
|
||||||
|
frontlight_white = "/sys/class/backlight/lm3630a_ledb",
|
||||||
|
frontlight_red = "/sys/class/backlight/lm3630a_leda",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
-- input events
|
||||||
|
local probeEvEpochTime
|
||||||
|
-- this function will update itself after the first touch event
|
||||||
|
probeEvEpochTime = function(self, ev)
|
||||||
|
local now = TimeVal:now()
|
||||||
|
-- This check should work as long as main UI loop is not blocked for more
|
||||||
|
-- than 10 minute before handling the first touch event.
|
||||||
|
if ev.time.sec <= now.sec - 600 then
|
||||||
|
-- time is seconds since boot, force it to epoch
|
||||||
|
probeEvEpochTime = function(_, _ev)
|
||||||
|
_ev.time = TimeVal:now()
|
||||||
|
end
|
||||||
|
ev.time = now
|
||||||
|
else
|
||||||
|
-- time is already epoch time, no need to do anything
|
||||||
|
probeEvEpochTime = function(_, _) end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
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()
|
||||||
|
)
|
||||||
|
end
|
||||||
|
if self.touch_probe_ev_epoch_time then
|
||||||
|
self.input:registerEventAdjustHook(function(_, ev)
|
||||||
|
probeEvEpochTime(_, ev)
|
||||||
|
end)
|
||||||
|
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}
|
||||||
|
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 WiFi")
|
||||||
|
os.execute("./disable-wifi.sh")
|
||||||
|
if complete_callback then
|
||||||
|
complete_callback()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function NetworkMgr:turnOnWifi(complete_callback)
|
||||||
|
logger.info("Cervantes: enabling WiFi")
|
||||||
|
os.execute("./enable-wifi.sh")
|
||||||
|
self:showNetworkMenu(complete_callback)
|
||||||
|
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 0 == os.execute("lsmod | grep -q 8189fs")
|
||||||
|
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: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("reboot")
|
||||||
|
end
|
||||||
|
function Cervantes:powerOff()
|
||||||
|
os.execute("halt")
|
||||||
|
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
|
@ -0,0 +1,210 @@
|
|||||||
|
local BasePowerD = require("device/generic/powerd")
|
||||||
|
local SysfsLight = require ("device/sysfs_light")
|
||||||
|
local PluginShare = require("pluginshare")
|
||||||
|
|
||||||
|
local battery_sysfs = "/sys/devices/platform/pmic_battery.1/power_supply/mc13892_bat/"
|
||||||
|
|
||||||
|
local CervantesPowerD = BasePowerD:new{
|
||||||
|
fl = nil,
|
||||||
|
fl_warmth = nil,
|
||||||
|
auto_warmth = false,
|
||||||
|
max_warmth_hour = 23,
|
||||||
|
|
||||||
|
fl_min = 0,
|
||||||
|
fl_max = 100,
|
||||||
|
capacity_file = battery_sysfs .. 'capacity',
|
||||||
|
status_file = battery_sysfs .. 'status'
|
||||||
|
}
|
||||||
|
|
||||||
|
function CervantesPowerD:_syncLightOnStart()
|
||||||
|
-- We can't read value from the OS or hardware.
|
||||||
|
-- Use last values stored in koreader settings.
|
||||||
|
local new_intensity = G_reader_settings:readSetting("frontlight_intensity") or nil
|
||||||
|
local is_frontlight_on = G_reader_settings:readSetting("is_frontlight_on") or nil
|
||||||
|
local new_warmth, auto_warmth = nil
|
||||||
|
|
||||||
|
if self.fl_warmth ~= nil then
|
||||||
|
new_warmth = G_reader_settings:readSetting("frontlight_warmth") or nil
|
||||||
|
auto_warmth = G_reader_settings:readSetting("frontlight_auto_warmth") or nil
|
||||||
|
end
|
||||||
|
|
||||||
|
if new_intensity ~= nil then
|
||||||
|
self.hw_intensity = new_intensity
|
||||||
|
end
|
||||||
|
|
||||||
|
if is_frontlight_on ~= nil then
|
||||||
|
self.initial_is_fl_on = is_frontlight_on
|
||||||
|
end
|
||||||
|
|
||||||
|
local max_warmth_hour =
|
||||||
|
G_reader_settings:readSetting("frontlight_max_warmth_hour")
|
||||||
|
if max_warmth_hour then
|
||||||
|
self.max_warmth_hour = max_warmth_hour
|
||||||
|
end
|
||||||
|
if auto_warmth then
|
||||||
|
self.auto_warmth = true
|
||||||
|
self:calculateAutoWarmth()
|
||||||
|
elseif new_warmth ~= nil then
|
||||||
|
self.fl_warmth = new_warmth
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.initial_is_fl_on == false and self.hw_intensity == 0 then
|
||||||
|
self.hw_intensity = 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function CervantesPowerD:init()
|
||||||
|
-- Default values in case self:_syncLightOnStart() does not find
|
||||||
|
-- any previously saved setting (and for unit tests where it will
|
||||||
|
-- not be called)
|
||||||
|
self.hw_intensity = 20
|
||||||
|
self.initial_is_fl_on = true
|
||||||
|
self.autowarmth_job_running = false
|
||||||
|
|
||||||
|
if self.device.hasFrontlight() then
|
||||||
|
if self.device.hasNaturalLight() then
|
||||||
|
local nl_config = G_reader_settings:readSetting("natural_light_config")
|
||||||
|
if nl_config then
|
||||||
|
for key,val in pairs(nl_config) do
|
||||||
|
self.device.frontlight_settings[key] = val
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self.fl = SysfsLight:new(self.device.frontlight_settings)
|
||||||
|
self.fl_warmth = 0
|
||||||
|
self:_syncLightOnStart()
|
||||||
|
else
|
||||||
|
local kobolight = require("ffi/kobolight")
|
||||||
|
local ok, light = pcall(kobolight.open)
|
||||||
|
if ok then
|
||||||
|
self.fl = light
|
||||||
|
self:_syncLightOnStart()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function CervantesPowerD:saveSettings()
|
||||||
|
if self.device.hasFrontlight() then
|
||||||
|
-- Store BasePowerD values into settings (and not our hw_intensity, so
|
||||||
|
-- that if frontlight was toggled off, we save and restore the previous
|
||||||
|
-- untoggled intensity and toggle state at next startup)
|
||||||
|
local cur_intensity = self.fl_intensity
|
||||||
|
local cur_is_fl_on = self.is_fl_on
|
||||||
|
local cur_warmth = self.fl_warmth
|
||||||
|
local cur_auto_warmth = self.auto_warmth
|
||||||
|
local cur_max_warmth_hour = self.max_warmth_hour
|
||||||
|
-- Save intensity to koreader settings
|
||||||
|
G_reader_settings:saveSetting("frontlight_intensity", cur_intensity)
|
||||||
|
G_reader_settings:saveSetting("is_frontlight_on", cur_is_fl_on)
|
||||||
|
if cur_warmth ~= nil then
|
||||||
|
G_reader_settings:saveSetting("frontlight_warmth", cur_warmth)
|
||||||
|
G_reader_settings:saveSetting("frontlight_auto_warmth", cur_auto_warmth)
|
||||||
|
G_reader_settings:saveSetting("frontlight_max_warmth_hour", cur_max_warmth_hour)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function CervantesPowerD:frontlightIntensityHW()
|
||||||
|
return self.hw_intensity
|
||||||
|
end
|
||||||
|
|
||||||
|
function CervantesPowerD:isFrontlightOnHW()
|
||||||
|
if self.initial_is_fl_on ~= nil then -- happens only once after init()
|
||||||
|
-- give initial state to BasePowerD, which will
|
||||||
|
-- reset our self.hw_intensity to 0 if self.initial_is_fl_on is false
|
||||||
|
local ret = self.initial_is_fl_on
|
||||||
|
self.initial_is_fl_on = nil
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
return self.hw_intensity > 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function CervantesPowerD:turnOffFrontlightHW()
|
||||||
|
self:_setIntensity(0) -- will call setIntensityHW(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
function CervantesPowerD:setIntensityHW(intensity)
|
||||||
|
if self.fl == nil then return end
|
||||||
|
if self.fl_warmth == nil then
|
||||||
|
self.fl:setBrightness(intensity)
|
||||||
|
else
|
||||||
|
self.fl:setNaturalBrightness(intensity, self.fl_warmth)
|
||||||
|
end
|
||||||
|
self.hw_intensity = intensity
|
||||||
|
-- Now that we have set intensity, we need to let BasePowerD
|
||||||
|
-- know about possibly changed frontlight state (if we came
|
||||||
|
-- from light toggled off to some intensity > 0).
|
||||||
|
self:_decideFrontlightState()
|
||||||
|
end
|
||||||
|
|
||||||
|
function CervantesPowerD:setWarmth(warmth)
|
||||||
|
if self.fl == nil then return end
|
||||||
|
if not warmth and self.auto_warmth then
|
||||||
|
self:calculateAutoWarmth()
|
||||||
|
end
|
||||||
|
self.fl_warmth = warmth or self.fl_warmth
|
||||||
|
self.fl:setWarmth(self.fl_warmth)
|
||||||
|
end
|
||||||
|
|
||||||
|
function CervantesPowerD:calculateAutoWarmth()
|
||||||
|
local current_time = os.date("%H") + os.date("%M")/60
|
||||||
|
local max_hour = self.max_warmth_hour
|
||||||
|
local diff_time = max_hour - current_time
|
||||||
|
if diff_time < 0 then
|
||||||
|
diff_time = diff_time + 24
|
||||||
|
end
|
||||||
|
if diff_time < 12 then
|
||||||
|
-- We are before bedtime. Use a slower progression over 5h.
|
||||||
|
self.fl_warmth = math.max(20 * (5 - diff_time), 0)
|
||||||
|
elseif diff_time > 22 then
|
||||||
|
-- Keep warmth at maximum for two hours after bedtime.
|
||||||
|
self.fl_warmth = 100
|
||||||
|
else
|
||||||
|
-- Between 2-4h after bedtime, return to zero.
|
||||||
|
self.fl_warmth = math.max(100 - 50 * (22 - diff_time), 0)
|
||||||
|
end
|
||||||
|
self.fl_warmth = math.floor(self.fl_warmth + 0.5)
|
||||||
|
|
||||||
|
-- Enable background job for setting Warmth, if not already done.
|
||||||
|
if not self.autowarmth_job_running then
|
||||||
|
table.insert(PluginShare.backgroundJobs, {
|
||||||
|
when = 180,
|
||||||
|
repeated = true,
|
||||||
|
executable = function()
|
||||||
|
if self.auto_warmth then
|
||||||
|
self:setWarmth()
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
self.autowarmth_job_running = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function CervantesPowerD:getCapacityHW()
|
||||||
|
return self:read_int_file(self.capacity_file)
|
||||||
|
end
|
||||||
|
|
||||||
|
function CervantesPowerD:isChargingHW()
|
||||||
|
return self:read_str_file(self.status_file) == "Charging\n"
|
||||||
|
end
|
||||||
|
|
||||||
|
function CervantesPowerD:beforeSuspend()
|
||||||
|
if self.fl == nil then return end
|
||||||
|
-- just turn off frontlight without remembering its state
|
||||||
|
self.fl:setBrightness(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
function CervantesPowerD:afterResume()
|
||||||
|
if self.fl == nil then return end
|
||||||
|
-- just re-set it to self.hw_intensity that we haven't change on Suspend
|
||||||
|
if self.fl_warmth == nil then
|
||||||
|
self.fl:setBrightness(self.hw_intensity)
|
||||||
|
else
|
||||||
|
if self.auto_warmth then
|
||||||
|
self:calculateAutoWarmth()
|
||||||
|
end
|
||||||
|
self.fl:setNaturalBrightness(self.hw_intensity, self.fl_warmth)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return CervantesPowerD
|
@ -0,0 +1,26 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
lsmod | grep -q g_file_storage || exit 1
|
||||||
|
|
||||||
|
modprobe -r g_file_storage
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
PCB_ID=$(/usr/bin/ntxinfo /dev/mmcblk0 | grep pcb | cut -d ":" -f2)
|
||||||
|
DISK=/dev/mmcblk
|
||||||
|
|
||||||
|
if [ "$PCB_ID" -eq 22 ] || [ "$PCB_ID" -eq 23 ]; then
|
||||||
|
PARTITION="${DISK}0p7"
|
||||||
|
else
|
||||||
|
PARTITION="${DISK}0p4"
|
||||||
|
fi
|
||||||
|
|
||||||
|
MOUNT_ARGS="noatime,nodiratime,shortname=mixed,utf8"
|
||||||
|
|
||||||
|
dosfsck -a -w "$PARTITION" >dosfsck.log 2>&1
|
||||||
|
|
||||||
|
mount -o "$MOUNT_ARGS" -t vfat "$PARTITION" /mnt/onboard
|
||||||
|
|
||||||
|
PARTITION=${DISK}1p1
|
||||||
|
|
||||||
|
[ -e "$PARTITION" ] && mount -o "$MOUNT_ARGS" -t vfat "$PARTITION" /mnt/sd
|
||||||
|
|
@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# disable wifi and remove all modules
|
||||||
|
killall udhcpc default-script wpa_supplicant 2>/dev/null
|
||||||
|
ifconfig eth0 down
|
||||||
|
|
||||||
|
if lsmod | grep -q 8189fs; then
|
||||||
|
modprobe -r 8189fs
|
||||||
|
fi
|
@ -0,0 +1,33 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# based on https://github.com/baskerville/plato/blob/master/scripts/usb-enable.sh
|
||||||
|
|
||||||
|
lsmod | grep -q g_file_storage && exit 1
|
||||||
|
|
||||||
|
PCB_ID=$(/usr/bin/ntxinfo /dev/mmcblk0 | grep pcb | cut -d ":" -f2)
|
||||||
|
DISK=/dev/mmcblk
|
||||||
|
|
||||||
|
if [ "$PCB_ID" -eq 22 ] || [ "$PCB_ID" -eq 23 ]; then
|
||||||
|
PRODUCT_ID=${PRODUCT_ID:-"0xAD78"}
|
||||||
|
PARTITIONS="${DISK}0p7"
|
||||||
|
else
|
||||||
|
PRODUCT_ID=${PRODUCT_ID:-"0xAD79"}
|
||||||
|
PARTITIONS="${DISK}0p4"
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ -e "${DISK}1p1" ] && PARTITIONS="${PARTITIONS},${DISK}1p1"
|
||||||
|
|
||||||
|
sync
|
||||||
|
echo 3 >/proc/sys/vm/drop_caches
|
||||||
|
|
||||||
|
for name in public sd; do
|
||||||
|
DIR=/mnt/"$name"
|
||||||
|
if grep -q "$DIR" /proc/mounts; then
|
||||||
|
umount "$DIR" || umount -l "$DIR"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
MODULE_PARAMETERS="vendor=0x2A47 product=${PRODUCT_ID} vendor_id=BQ product_id=Cervantes"
|
||||||
|
modprobe g_file_storage file="$PARTITIONS" stall=1 removable=1 "$MODULE_PARAMETERS"
|
||||||
|
|
||||||
|
sleep 1
|
@ -0,0 +1,18 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
WPA_SUPPLICANT_CONF="/mnt/private/koreader/wpa_supplicant.conf"
|
||||||
|
CTRL_INTERFACE="/var/run/wpa_supplicant"
|
||||||
|
|
||||||
|
# create a new configuration if neccesary.
|
||||||
|
if [ ! -f "$WPA_SUPPLICANT_CONF" ]; then
|
||||||
|
echo "ctrl_interface=DIR=${CTRL_INTERFACE}" >"$WPA_SUPPLICANT_CONF"
|
||||||
|
echo "update_config=1" >>"$WPA_SUPPLICANT_CONF"
|
||||||
|
sync
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! lsmod | grep -q 8189fs; then
|
||||||
|
modprobe 8189fs
|
||||||
|
sleep 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
ifconfig eth0 up && sleep 1
|
||||||
|
wpa_supplicant -B -D wext -i eth0 -s -O "$CTRL_INTERFACE" -c "$WPA_SUPPLICANT_CONF" 2>/dev/null
|
@ -0,0 +1,57 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Standalone KOReader application for BQ Cervantes
|
||||||
|
# this file is intended to replace /etc/rc.local on BQ developers firmware
|
||||||
|
|
||||||
|
# turn off the green flashing led.
|
||||||
|
echo "ch 4" >/sys/devices/platform/pmic_light.1/lit
|
||||||
|
echo "cur 0" >/sys/devices/platform/pmic_light.1/lit
|
||||||
|
echo "dc 0" >/sys/devices/platform/pmic_light.1/lit
|
||||||
|
|
||||||
|
# ensure we have a proper time.
|
||||||
|
if [ "$(date '+%Y')" -lt 2010 ]; then
|
||||||
|
echo "Fixing date before 2010"
|
||||||
|
date +%Y%m%d -s "20100101"
|
||||||
|
hwclock -w
|
||||||
|
fi
|
||||||
|
|
||||||
|
# assign public & private partition devices based on pcb.
|
||||||
|
PCB_ID=$(/usr/bin/ntxinfo /dev/mmcblk0 | grep pcb | cut -d ":" -f2)
|
||||||
|
if [ "$PCB_ID" -eq 22 ] || [ "$PCB_ID" -eq 23 ]; then
|
||||||
|
PRIVATE="/dev/mmcblk0p5"
|
||||||
|
PUBLIC="/dev/mmcblk0p7"
|
||||||
|
else
|
||||||
|
PRIVATE="/dev/mmcblk0p7"
|
||||||
|
PUBLIC="/dev/mmcblk0p4"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# mount internal partitions
|
||||||
|
mount $PRIVATE /mnt/private
|
||||||
|
mount $PUBLIC /mnt/public
|
||||||
|
|
||||||
|
# mount sdcard if present
|
||||||
|
if [ -b /dev/mmcblk1p1 ]; then
|
||||||
|
mount /dev/mmcblk1p1 /mnt/sd
|
||||||
|
fi
|
||||||
|
|
||||||
|
# remove wireless module since it wastes battery.
|
||||||
|
if lsmod | grep -q 8189fs; then
|
||||||
|
modprobe -r 8189fs
|
||||||
|
fi
|
||||||
|
|
||||||
|
# start usbnet using BQ scripts (192.168.4.1/24 w/ hardcoded MAC addr)
|
||||||
|
/usr/bin/usbup.sh
|
||||||
|
/usr/sbin/inetd
|
||||||
|
|
||||||
|
# check if KOReader script exists.
|
||||||
|
if [ -x /mnt/private/koreader/koreader.sh ]; then
|
||||||
|
# yada! KOReader is installed and ready to run.
|
||||||
|
while true; do
|
||||||
|
/mnt/private/koreader/koreader.sh
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
else
|
||||||
|
# nothing to do, leaving rc.local.
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
@ -0,0 +1,89 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
export LC_ALL="en_US.UTF-8"
|
||||||
|
|
||||||
|
# working directory of koreader
|
||||||
|
KOREADER_DIR="${0%/*}"
|
||||||
|
|
||||||
|
# we're always starting from our working directory
|
||||||
|
cd "${KOREADER_DIR}" || exit
|
||||||
|
|
||||||
|
# update to new version from OTA directory
|
||||||
|
ko_update_check() {
|
||||||
|
NEWUPDATE="${KOREADER_DIR}/ota/koreader.updated.tar"
|
||||||
|
INSTALLED="${KOREADER_DIR}/ota/koreader.installed.tar"
|
||||||
|
if [ -f "${NEWUPDATE}" ]; then
|
||||||
|
#./fbink -q -y -7 -pmh "Updating KOReader"
|
||||||
|
# NOTE: See frontend/ui/otamanager.lua for a few more details on how we squeeze a percentage out of tar's checkpoint feature
|
||||||
|
# NOTE: %B should always be 512 in our case, so let stat do part of the maths for us instead of using %s ;).
|
||||||
|
FILESIZE="$(stat -c %b "${NEWUPDATE}")"
|
||||||
|
BLOCKS="$((FILESIZE / 20))"
|
||||||
|
export CPOINTS="$((BLOCKS / 100))"
|
||||||
|
# shellcheck disable=SC2016
|
||||||
|
./tar xf "${NEWUPDATE}" --strip-components=1 --no-same-permissions --no-same-owner --checkpoint="${CPOINTS}" --checkpoint-action=exec='./fbink -q -y -6 -P $(($TAR_CHECKPOINT/$CPOINTS))'
|
||||||
|
fail=$?
|
||||||
|
# Cleanup behind us...
|
||||||
|
if [ "${fail}" -eq 0 ]; then
|
||||||
|
mv "${NEWUPDATE}" "${INSTALLED}"
|
||||||
|
# ./fbink -q -y -6 -pm "Update successful :)"
|
||||||
|
# ./fbink -q -y -5 -pm "KOReader will start momentarily . . ."
|
||||||
|
#else
|
||||||
|
# # Huh ho...
|
||||||
|
# ./fbink -q -y -6 -pmh "Update failed :("
|
||||||
|
# ./fbink -q -y -5 -pm "KOReader may fail to function properly!"
|
||||||
|
fi
|
||||||
|
rm -f "${NEWUPDATE}" # always purge newupdate in all cases to prevent update loop
|
||||||
|
unset BLOCKS CPOINTS
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# if no args were passed to the script, start the FM on public partition.
|
||||||
|
if [ "$#" -eq 0 ]; then
|
||||||
|
args="/mnt/public"
|
||||||
|
else
|
||||||
|
args="$*"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# NOTE: Keep doing an initial update check, in addition to one during the restart loop, so we can pickup potential updates of this very script...
|
||||||
|
ko_update_check
|
||||||
|
# If an update happened, and was successful, reexec
|
||||||
|
if [ -n "${fail}" ] && [ "${fail}" -eq 0 ]; then
|
||||||
|
# By now, we know we're in the right directory, and our script name is pretty much set in stone, so we can forgo using $0
|
||||||
|
exec ./koreader.sh "${args}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# load our own shared libraries if possible
|
||||||
|
export LD_LIBRARY_PATH="${KOREADER_DIR}/libs"
|
||||||
|
|
||||||
|
# export trained OCR data directory
|
||||||
|
export TESSDATA_PREFIX="data"
|
||||||
|
|
||||||
|
# export dict directory
|
||||||
|
export STARDICT_DATA_DIR="data/dict"
|
||||||
|
|
||||||
|
# we keep at most 500k worth of crash log
|
||||||
|
if [ -e crash.log ]; then
|
||||||
|
tail -c 500000 crash.log >crash.log.new
|
||||||
|
mv -f crash.log.new crash.log
|
||||||
|
fi
|
||||||
|
|
||||||
|
# check if QBookApp was started before us, then
|
||||||
|
# restart the application after leaving KOReader
|
||||||
|
export STANDALONE="true"
|
||||||
|
if pkill -0 QBookpp; then
|
||||||
|
STANDALONE="false"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${STANDALONE}" != "true" ]; then
|
||||||
|
stopapp.sh >/dev/null 2>&1
|
||||||
|
fi
|
||||||
|
|
||||||
|
RETURN_VALUE=85
|
||||||
|
while [ "${RETURN_VALUE}" -eq 85 ]; do
|
||||||
|
./reader.lua "${args}" >>crash.log 2>&1
|
||||||
|
RETURN_VALUE=$?
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "${STANDALONE}" != "true" ]; then
|
||||||
|
restart.sh >/dev/null 2>&1
|
||||||
|
fi
|
@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
./release-ip.sh
|
||||||
|
|
||||||
|
# Use udhcpc to obtain IP.
|
||||||
|
udhcpc -S -i eth0 -s /etc/udhcpc/default.script -t15 -T10 -A3 -b -q
|
@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Release IP and shutdown udhcpc.
|
||||||
|
pkill -9 -f '/bin/sh /etc/udhcpc/default.script'
|
||||||
|
ifconfig eth0 0.0.0.0
|
@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
RestoreWifi() {
|
||||||
|
echo "[$(date)] restore-wifi-async.sh: Restarting WiFi"
|
||||||
|
./enable-wifi.sh
|
||||||
|
./obtain-ip.sh
|
||||||
|
echo "[$(date)] restore-wifi-async.sh: Restarted WiFi"
|
||||||
|
}
|
||||||
|
|
||||||
|
RestoreWifi &
|
@ -0,0 +1,4 @@
|
|||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
echo 0 >/sys/power/state-extended
|
||||||
|
|
@ -0,0 +1,15 @@
|
|||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
# De-activate the touch screen.
|
||||||
|
echo 1 >/sys/power/state-extended
|
||||||
|
|
||||||
|
# Prevent the following error on the last line:
|
||||||
|
# *write error: Operation not permitted*.
|
||||||
|
sleep 2
|
||||||
|
|
||||||
|
# Synchronize the file system.
|
||||||
|
sync
|
||||||
|
|
||||||
|
# Suspend to RAM.
|
||||||
|
echo mem >/sys/power/state
|
||||||
|
|
Loading…
Reference in New Issue