一、FBInk帧缓冲绘图
FBInk 是 Kindle/Kobo 电子墨水屏帧缓冲绘图工具,可以直接在 eInk 屏幕输出文字、图片、进度条、局部刷屏、清屏,无需调用系统 UI。 版本:FBInk v1.24.0-161-gb7a8146
设备识别信息前置:
[FBInk] 检测到 Kindle Basic 2 (0KA -> 0x26A => Eanab Heisenberg)
[FBInk] 系统时钟频率:100 Hz
[FBInk] 屏幕DPI:167
[FBInk] 帧缓冲:600×800,8位色深,屏幕旋转 270°(逆时针)
[FBInk] 帧缓冲设备:mxc_epdc_fb,显存大小6537216字节,行宽608字节
[FBInk] 默认字体 16×16(基础8×8 IBM点阵字库)
[FBInk] 默认文本区域:37列 × 50行
[FBInk] 默认颜色:前景黑色,背景白色

1、 文本位置控制参数
基础语法:
fbink [参数] [文本内容...]
|----------|--------------|-------------------------------------|
| 参数 | 全称 | 说明 |
| -x NUM | --col | 起始列,默认 0;负数代表从屏幕右侧倒数;建议起始≥1 避免被边框遮挡 |
| -y NUM | --row | 起始行,默认 0;负数代表从屏幕底部倒数;建议起始≥1 |
| -X NUM | --hoffset | 水平像素偏移(叠加在行列之上,可正负) |
| -Y NUM | --voffset | 垂直像素偏移 |
| -m | --centered | 文本水平居中 |
| -M | --halfway | 垂直居中;此时 -y 的数值是相对于屏幕中线的偏移量 |
| -p | --padded | 两端填充空格,配合 -m 实现整行居中铺满 |
| -r | --rpadded | 右侧填充空格 |
2、 文本外观控制参数
|------------|----------------|----------------------------------------------------------------|
| 参数 | 全称 | 说明 |
| -h | --invert | 反转颜色:背景色写字、前景色做底色(黑底白字) |
| -f | --flash | 刷新区域启用黑屏全刷(eink 清除残影,耗电更高) |
| -c | --clear | 打印前全屏清屏 ;仅清屏建议改用 -k |
| -k | --cls | 清屏(可全屏 / 局部矩形),执行完成直接退出,优先级最高 |
| -W MODE | --waveform | 指定墨水刷新波形:A2,DU,GC16,GL16,AUTO ;Kindle 额外支持 REAGL、GC16_FAST 等 |
| -D | --dither | 硬件抖动(仅新设备支持) |
| -H | --nightmode | 硬件全局反色(和 -h 可叠加) |
| -b | --norefresh | 只写入帧缓冲,不触发屏幕刷新,适合批量绘图,最后统一刷新 |
| -w | --wait | 阻塞等待内核刷新完成再返回 |
| -S NUM | --size | 字体缩放倍数,自动 = 0,范围 1~45 |
| -F NAME | --font | 内置点阵字体:IBM、UNSCII、THIN、TEWI、ORP、TERMINUS 等 |
| -C COLOR | --color | 文字颜色:BLACK、GRAY1~GRAYE、WHITE |
| -B COLOR | --background | 文字底色 |
| -O | --bgless | 不绘制文字背景,只渲染文字轮廓 |
| -o | --overlay | 叠加模式,自动取底层像素反色(优先级高于 - O) |
| -T | --fgless | 不绘制前景文字 |
3、特殊绘图模式
-
进度条
-P NUM``fbink -P 35绘制全屏宽度 35% 进度条 -
活动加载条
-A NUM``fbink -A 80~16;负数自动循环动画 -
局部 / 全屏刷新
-s只触发屏幕刷新,不修改画面fbink -s top=20,left=10,width=500,height=600 -W GC16
-
图片显示
-g / -i支持 PNG/JPG/BMP;可缩放、对齐、软件抖动fbink -g file=/mnt/us/test.png,halign=CENTER,valign=MIDDLE
4、TrueType/OTF 矢量字体
可以调用 ttf 自定义字体(Kindle 内置 Caecilia),支持 Markdown 粗体 / 斜体
fbink -t regular=/usr/java/lib/fonts/Caecilia_LT_65_Medium.ttf,size=22,top=50 "自定义矢量文字"
5、输出调试与脚本参数
-q:静默,关闭硬件检测日志-v:详细日志-E:输出绘制区域坐标,方便 shell 脚本解析-e:输出设备环境变量,eval $(fbink -e)直接导入变量-d NUM:守护进程模式 ,启动 FIFO 管道/tmp/fbink-fifo,持续接收文本输出,适合仪表盘常驻刷新
6、常用命令示例
(适配 Kindle Basic2 600×800)
1. 基础文字输出
# 第10行、第2列输出文字
fbink -x 1 -y 10 "Hello Kindle!"
2. 居中、黑底白字
# 水平居中+垂直居中向上偏移5行、反色高亮
fbink -pmh -y -5 "System Information"
-m居中-p两端空格填充-h反转颜色-y -5距离底部向上 5 行
3. 全屏清屏后打印文字
fbink -c -m -M "Clear"
4. 局部矩形清屏(清空底部状态栏区域)
fbink -k top=720,left=0,width=600,height=80
5. 快速局部 GC16 刷新(不绘图,只消残影)
fbink -s top=700,left=0,width=600,height=100 -W GC16
6. 显示图片,屏幕居中
fbink -g file=/mnt/us/img.png,halign=CENTER,valign=MIDDLE
7. 启动守护进程(常驻仪表盘,推荐做动态面板)
# 最多容纳8行文本
PID=$(fbink -d 8)
# 向管道写入内容,屏幕实时更新
echo "CPU: 32% Battery:78%" > /tmp/fbink-fifo
# 关闭
kill $PID
8. 使用更大字体、更换内置字体
fbink -F TEWI -S 2 -m "Hello Kindle"
9. 无背景文字叠加(不覆盖原有画面)
fbink -O -x 2 -y 2 "Test..."
重要使用提示
- 多次连续绘图建议搭配
-b先写入缓冲区,最后一次不带-b统一刷新,减少墨水刷屏次数、减缓老化; -W A2快速刷新(残影重),GC16/GL16灰度高质量刷新;- 大量动态刷新尽量少用
-f(flash 黑屏全刷),频繁全刷损耗屏幕; - 多行文本文字直接写在同一个引号内,不要分成多个参数;多个参数配合
-c只会显示最后一行; - 坐标同时支持「绝对正数」和「负数反向计数」,很适合做自适应底部状态栏。
7、显示时间程序
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
static int fbink_exec(char *const argv[])
{
pid_t pid = fork();
if (pid < 0) {
perror("fork");
return -1;
}
if (pid == 0) {
execvp(argv[0], argv);
perror("execvp fbink");
_exit(127);
}
int status;
waitpid(pid, &status, 0);
if(WIFEXITED(status)){
return WEXITSTATUS(status);
}
return -1;
}
//局部区域白色擦除
static int fbink_local_clear(void)
{
char * const argv[] = {
"/usr/bin/fbink",
"-k", "top=400,left=0,width=600,height=15",
NULL
};
return fbink_exec(argv);
}
//屏幕居中输出文本
static int fbink_center_text(const char *text)
{
char * const argv[] = {
"/usr/bin/fbink",
"-m", "-M",
(char *)text,
NULL
};
return fbink_exec(argv);
}
int main(void)
{
char timestr[64];
time_t now;
struct tm *tm_ptr;
for(;;)
{
now = time(NULL);
tm_ptr = localtime(&now);
snprintf(timestr, sizeof(timestr),
"%04d/%02d/%02d %02d:%02d",
tm_ptr->tm_year + 1900,
tm_ptr->tm_mon + 1,
tm_ptr->tm_mday,
tm_ptr->tm_hour,
tm_ptr->tm_min);
printf("%s\n", timestr);
fbink_local_clear(); //局部擦除旧内容
fbink_center_text(timestr); //输出新时间
sleep(1);
}
return 0;
}
Linux 主机交叉编译:
arm-linux-gnueabi-gcc -march=armv7-a -mtune=cortex-a9 -msoft-float -mabi=aapcs-linux show-time.c -o show-time
上传程序:
scp ./show-time root@192.168.1.4:/mnt/us/gcc-test
kindle端运行:
#cd /mnt/us/gcc-test
#./show-time
二、kindle 触摸屏开发
1、触摸屏设备
设备节点确认
cat /proc/bus/input/devices
I: Bus=0000 Vendor=0000 Product=0000 Version=0000
N: Name="zforce2"
P: Phys=zforce2/input0
S: Sysfs=/devices/platform/zforce2.0/input/input0
U: Uniq=
H: Handlers=event0
B: PROP=2
B: EV=b
B: KEY=6420 0 0 0 0 0 0 0 0 0 0
B: ABS=2608000 0
Kindle 8 (PW3),触摸驱动是 zforce2 (不是 mtk‑tpd),触摸设备节点:/dev/input/event0。 zforce2 是多点触摸 MT protocol B ,使用 ABS_MT_POSITION_X / ABS_MT_POSITION_Y。
坐标说明(zforce2 PW3)
屏幕分辨率 600 × 800
ABS_MT_POSITION_X:0 ~ 600ABS_MT_POSITION_Y:0 ~ 800
和 FBInk 绘图坐标完全兼容,可以直接传给 fbink 的 -x``-y 参数。
⚠️ zforce2 的关键特性
- 没有 BTN_TOUCH 事件 ,依靠
ABS_MT_TRACKING_ID判断按下抬起:
-
tracking_id != -1→ 手指按下tracking_id == -1→ 手指抬起
- 设备节点固定
/dev/input/event0,来自你/proc/bus/input/devices的Handlers=event0。 - 程序打开 event0 后,系统原生触摸会失效(事件抢占),程序退出后恢复。
- 必须 root 权限打开
/dev/input/event0。
2、zforce2 触摸读取程序
逻辑:解析 Linux MT‑B 多点触摸协议,读取手指按下、抬起、X/Y 坐标。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/input.h>
#include <sys/types.h>
#include <sys/stat.h>
#define TOUCH_DEV "/dev/input/event0"
int main(void)
{
int fd;
struct input_event ev;
int x = -1, y = -1;
int touch_active = 0;
fd = open(TOUCH_DEV, O_RDONLY);
if (fd < 0) {
perror("open /dev/input/event0 failed (need root!)");
return EXIT_FAILURE;
}
printf("zforce2 touch reader. Tap screen, Ctrl+C exit.\n");
for (;;)
{
ssize_t n = read(fd, &ev, sizeof(struct input_event));
if (n != sizeof(struct input_event)) {
perror("read event");
continue;
}
switch (ev.type)
{
case EV_ABS:
// MT多点触摸坐标
if (ev.code == ABS_MT_POSITION_X) {
x = ev.value;
} else if (ev.code == ABS_MT_POSITION_Y) {
y = ev.value;
} else if (ev.code == ABS_MT_TRACKING_ID) {
/* tracking_id !=‑1:手指按下;==‑1:手指抬起 */
if(ev.value != -1) {
touch_active = 1;
printf("DOWN x=%d y=%d\n", x, y);
} else {
touch_active = 0;
printf("UP\n");
}
}
break;
case EV_SYN:
// SYN_REPORT 一次上报结束
break;
default:
break;
}
}
close(fd);
return 0;
}
Linux 主机交叉编译:
arm-linux-gnueabi-gcc -march=armv7-a -mtune=cortex-a9 -msoft-float -mabi=aapcs-linux touch-read.c -o touch-read
上传程序:
scp ./touch-read root@192.168.1.4:/mnt/us/gcc-test
kindle端运行:
#cd /mnt/us/gcc-test
#./touch-read
DOWN x=245 y=330
UP
DOWN x=410 y=520
UP
