1
27
2020
3

自制大上 Paperlike HD「驱动」

大上 Paperlike HD 使用有一段时间了,然而有一点我对其非常不满:它需要以 root 权限运行一个图形界面的程序。具体麻烦的地方是:

  • 图形界面的程序不方便使用 systemd 管理,那个窗口我得找个地方安放,并且在登出图形界面或者 Xorg 出问题时会随之关闭
  • 即使持续运行此程序,当几秒内不使用键盘或者鼠标的时候屏幕就会休眠。这导致我无法将此屏幕用于关注程序日志或者聊天工具的新消息。
  • 它持续不断地执行多个线程的任务(读取键盘事件、读取鼠标事件、通过 ioctl 与设备通讯),耗费了不少 CPU
  • 在屏幕尚未连接时,它的运行会导致内核不断输出日志「drm_dp_i2c_do_msg: 2 callbacks suppressed」

我曾多次想自己实现一个符合自己使用习惯的方案。

首先当然是 strace 上去啦。这会得到许多类似这样的消息:

ioctl(9</dev/i2c-1<char 89:1>>, _IOC(_IOC_NONE, 0x7, 0x7, 0), 0x7f47d8805b70) = 1
nanosleep({tv_sec=0, tv_nsec=100000000}, NULL) = 0
ioctl(9</dev/i2c-1<char 89:1>>, _IOC(_IOC_NONE, 0x7, 0x7, 0), 0x7f47d8805be0) = 1
nanosleep({tv_sec=0, tv_nsec=200000000},  <unfinished ...>

可以看到它在对 /dev/i2c-1 这个文件进行操作,但是具体内容是个指针,strace 看不到。

我尝试过使用大名鼎鼎的 IDA 的免费版本来分析其具体行为。但我对 IDA 并不熟悉,并且 IDA 只支持 Intel 语法的汇编,而我见的 AT&T 语法的比较多,Intel 的很多表示法我不太能看懂。

后来根据 ioctl 的请求参数找到这个文档,里边有这些 i2c 消息的结构体定义。于是想着先把 ioctl 的数据弄出来看看。一开始尝试用 gdb 去看那个地址的数据,但想到数据是变动的,再加上 gdb 查看太累了,就想起了通过 LD_PRELOAD 去 hook ioctl。

所以又要写 C 了?并没有呢!C 写起来那么不舒服,还是用 Rust 吧~然后搜了一下,还真有现成的用于写 LD_PRELOAD 库的 crate,比如我用的 redhook。不用自己去 dlopen,不用在各处写很多错误处理代码,很容易就写好了。代码链接

拿到了 ioctl 里用的消息,我不用理会它具体是什么意思,也没办法去猜测,自然是把它按大上提供的程序那个样子给发过去了。于是又一个 Rust 程序出来了。

一开始写的时候不小心往 unsafe 代码块里传了个悬空的指针,导致程序不工作,调试了好久,甚至我都把完整的整个流程给复刻了一遍。这要是用 C 写文本解析的逻辑可头疼了,不过 Rust 写起来就跟 Python 差不多的了~

至于那个 bug,是 Rust 语句中的临时对象(此例中是包含一个对象的数组)会在语句结束之后就释放导致的。有点坑,但也没什么好的办法。

程序运行起来之后就会保持 Paperlike HD 显示器可用,不会报错让装驱动,也不会过几秒就休眠了。我大幅降低了消息发送的频率(由差不多每秒三次改成了三秒才一次),再加上不需要读取键鼠输入,所以 CPU 占用也会大幅减少。另外内核也不会再打印「drm_dp_i2c_do_msg: 2 callbacks suppressed」的消息了,大概是因为消息频率降低了?重新连接显示器之后,和大上原版程序一样有概率出现显示器亮蓝灯、屏幕不工作的情况。拔插一下电源可解。

当然啦,如果有人要用这个程序的话,记得先确认一下你的 i2c 设备文件路径(去 lsof 大上原版程序就行)。另外,使用此程序后果自负,由此造成的任何设备损坏或者其它损失,我都不负责任的哦~

Category: 硬件 | Tags: 显示器 linux Rust E-ink 硬件
2
12
2018
22

大上 Paperlike HD 电子墨水屏开箱体验

刚听说就已心动,无奈当时并不支持 Linux。后来由于一些事情耽搁到现在,终于到手了~

开箱啦

显示器整体尺寸是31cm×27cm,其中显示屏尺寸不到26cm×21cm(请注意:手工测量有误差)。分辨率是2200x1650。也就是200dpi多,和我的 Kindle Paperwhite 一代差不多的。

显示器下方是两个纸盒,里边是Y形线(照片中没有)、简易支架(那根根子)、螺丝和仅几百M的驱动U盘。

附件

Y形线是附加了USB电源线的HDMI线。信号走HDMI,电源走USB,所以需要额外占用一个USB口。当然接充电器上也是可以的,只是在电脑边接个充电器更不方便。

工作时,USB端口的电流为30~50mA左右,并不像说明书上说的需要2A那么多,挺省电的。对比之下,我的罗技鼠标接收器也需要15mA左右的电流呢。

线都接上之后,屏幕会闪几下,然后就可以用了。只是每隔几分钟会弹出提示信息,要求安装并运行所谓的「驱动」。下图是默认的 floyd 模式:

未使用软件,显示的登录界面

为了更多的模式,以及最重要的,别显示那个提示信息,需要安装并运行大上提供的软件。

软件是为 Ubuntu 提供的,但是 Arch 下也可以使用。下载并解包,将得到的三个文件「PaperLikeHD」、「ResChange」、「DS.ico」放到/usr/local/sbin/下,然后sudo PaperLikeHD 运行,会弹出一个包含一列按钮的窗口。不给 root 权限是不行的,会什么也不做就退出。

但是这样还不够。我使用的时候它总是报告找不到显示器。客服不肯告诉我它到底使用什么机制检测的,所以我 strace 又反汇编看了一下,最后发现它在找 /dev/i2c-* 设备文件,而我的系统上没有它们。看了一下一堆以 i2c 开头的内核模块,最后发现只要加载 i2c-dev 模块就好了。大上的软件需要一些时间来检测,等一会儿它就会在终端打开出「setting...50」这样的文字,这时就好了。

在台灯下使用火狐发推

过程中我还专门启动到 Ubuntu live 系统里测试来着。后来才知道原来是自己的手速太快,软件还没检测到,其实等等就好 (╯‵□′)╯︵┻━┻

Ubuntu live

从图片中可以看到,floyd 模式的显示很粗糙。这是因为它实际上只有二阶灰阶,通过不同密度的点来近似不同的灰度。虽然显示有很严重的颗粒感,但是它响应飞快,常规打字操作时几乎感觉不到延迟,很适合写作和阅读文本。而真正的二阶灰阶模式 A2,只有黑白两色,虽然依旧反应快速,但是因为非黑即白,只能用来读纯文本,任何阴影或者灰色的字都不好处理。

16灰阶的 A16 模式,显示清晰、层次丰富,但是响应速度非常慢。也不是非常啦,除了屏幕大小外,无论显示效果还是响应速度都跟我的 Kindle 一样的。而与 Kindle 不同的是,它会在更新时将更新区域变黑再显示,造成闪烁。在此模式下使用鼠标非常非常费力,任何非静止的元素(比如火狐载入中的动画、时钟、光标移动)都挺分散注意力的。

以上都是所谓的「可变分辨率模式」。另外有个「固定1100x825模式」,也就是使用一半的分辨率。至于另一半去了哪里,看看它所支持的模式就能猜到了:

  • A5,也就是五灰阶。这是用四个墨滴来显示一个像素,每个墨滴只有黑与白两种状态。
  • A61,所谓的61灰阶。也是用四个墨滴来显示一个像素。不过每个墨滴竭尽所能有16种状态,也不知道大上是怎么组合出这61灰阶的。

也不知道大上为什么把这两种墨滴用法叫作「可变分辨率模式」和「固定1100x825模式」。哪里可变了,又哪里固定了呢?这两种模式切换时,会调用「ResChange」程序,它会影响当前的显示器布局,需要重新使用 xrandr 进行设置。

以下是各种模式显示这个灰阶测试网页的照片:

A2 模式:

A2 模式

A16 模式:

A16 模式

floyd 模式:

floyd 模式

A5 模式:

A5 模式

A61 模式:

A61 模式

半分辨率下,清晰度做出了很大的牺牲。以下是 A16 和 A61 模式显示 PaperLikeHD 软件自身界面的效果对比:

A16 A61

在 A2、A5、floyd 模式下,可以调节对比度,也就是墨滴到底显示为黑还是为白的值,以在显示不同的页面时都能将文本与背景良好区分开。

和 Kindle Paperwhite 不同的是,它没有背光。在晚上的时候,屏幕偏暗,附加一个台灯光源比较好。不过它的屏幕也不像 Kindle 那样偏黄。

这篇文章最终定稿,就是在 PaperLikeHD 上完成的,使用的是 floyd 模式。我个人觉得半分辨率的几个模式很鸡肋。目前觉得,写作用 floyd 模式,文本阅读使用 A2 模式,网页阅读使用 A16 模式,这样最好了~

floyd 模式还有个问题:在显示某些图片时(比如我的 Awesome 桌面壁纸),那些墨滴颗粒会不断地抖动,就像风在吹沙粒一样……

最后,这里是大上的官网链接

Category: 硬件 | Tags: linux 硬件 E-ink 显示器

Mastodon | Theme: Aeros 2.0 by TheBuckmaker.com