From 9783682d0edab58a9049ee039258abafb2256b8d Mon Sep 17 00:00:00 2001 From: jingle_xie Date: Mon, 30 Mar 2026 09:30:37 +0800 Subject: [PATCH] Update readme.md --- epdiy-epub/README.md | 256 +++++++++++++++++++++++-------------------- 1 file changed, 135 insertions(+), 121 deletions(-) diff --git a/epdiy-epub/README.md b/epdiy-epub/README.md index 88ced50..e8ca766 100644 --- a/epdiy-epub/README.md +++ b/epdiy-epub/README.md @@ -25,14 +25,17 @@ - `SELECTING_EPUB`:书库页面 - `SELECTING_TABLE_CONTENTS`:目录页面 - `READING_EPUB`:阅读页面 -- `SETTINGS_PAGE`:设置页面 -- `WELCOME_PAGE`:欢迎页面 +- `READING_SETTINGS`:阅读设置页面(字体/字号/字重/行距/边距) +- `SETTINGS_PAGE`:功能设置页面 +- `WELCOME_PAGE`:欢迎页面(超时熄屏) - `LOW_POWER_PAGE`:低电量页面 - `CHARGING_PAGE`:充电页面 - `SHUTDOWN_PAGE`:关机页面 默认开机进入 `MAIN_PAGE`。 +--- + ### 主页面 主页面包含 3 个入口: @@ -43,40 +46,80 @@ 说明: -- “继续阅读”基于本次运行期间最近一次成功进入阅读的书籍索引。 -- 若当前无可用记录,则显示“无阅读记录”。 +- "继续阅读"基于本次运行期间最近一次成功进入阅读的书籍索引,并自动恢复到上次所在章节。 +- 若当前无可用记录,则显示"无阅读记录"。 + +--- -### 设置页面 +### 功能设置页面 支持以下设置项: 1. 触控开关(同步触控硬件上电/下电) 2. 超时策略:`5分钟 / 10分钟 / 30分钟 / 1小时 / 不关机` 3. 全刷周期:`5次 / 10次 / 20次 / 每次(0)` -4. 确认保存并返回主页面 +4. 阅读设置:进入阅读设置子页面,见下节 +5. 确认保存并返回主页面 + +--- + +### 阅读设置页面 + +通过"功能设置 → 阅读设置"或"阅读页覆盖操作层 → 设置"进入,支持调节以下参数: + +| 设置项 | 可选值 | +|--------|--------| +| 字体 | Default(内置)及 TF 卡 `/fonts` 目录中所有 `.ttf` / `.otf` 文件 | +| 字号 | 24 / 28 / 32 / 36 / 40 / 44 / 48 px | +| 字重 | 正常 / 中粗 / 粗体| +| 行距 | 1.0x / 1.2x / 1.4x / 1.6x / 1.8x / 2.0x | +| 边距 | 5 / 8 / 11 / 14 / 17 / 20 px | +| 保存退出 | 确认后应用并持久化到 TF 卡 `/settings.cfg` | + +操作方式:`UP` / `DOWN` 切换设置项;`SELECT` 循环切换当前项的值;光标停在"保存退出"时 `SELECT` 保存并退出。 + +**持久化**:设置以 `key=value` 文本格式保存于 TF 卡 `/settings.cfg`,下次开机自动加载;若指定字体文件不可用,自动回退到内置默认字体。 + +--- + +### 动态字体加载 + +将 `.ttf` 或 `.otf` 字体文件放入 TF 卡的 `/fonts` 目录,开机后将自动被检测并出现在阅读设置的字体列表中(最多支持 64 个外部字体)。 + +- `Default`:编译时内置的 FreeType 字体(DroidSansFallback,存放于 Flash XIP)。 +- 外部字体:FreeType 直接从 TF 卡文件读取。 + +--- ### 阅读页覆盖操作层 在阅读页触发 `UPGLIDE`(上滑/映射动作)可呼出覆盖操作层,支持: -- 中心功能在“触控开关”与“全刷周期”间切换 +- 中心功能在"触控开关"与"全刷周期"间切换 - 跳页步进:`-5 / -1 / +1 / +5` - 确认跳转到目标页 - 进入目录页 - 返回书库 +- **进入阅读设置**(新增,可直接从阅读页调整字体/字号/行距/边距,退出后自动恢复到当前阅读位置) + +--- ### 书库页与目录页 -- 书库页:每页 4 项,底部支持“上一页 / 主页面 / 下一页”。 -- 目录页:每页 6 项,底部支持“上一页 / 书库 / 下一页”。 -- 触控采用“先选中再确认”机制以降低误触。 +阅读流程:**书库页 → 目录页 → 阅读页**。在书库页选中书籍后,将先进入目录页,再由目录页选择章节跳入阅读。 + +- 书库页:每页 4 项,底部支持"上一页 / 主页面 / 下一页"。 +- 目录页:每页 6 项,底部支持"上一页 / 书库 / 下一页"。 +- 触控采用"先选中再确认"机制以降低误触。 + +--- ### 电量与低功耗 -- 页面顶部显示电量与充电状态。 +- 页面顶部显示电量与充电状态(闪电图标);电量满时(≥98%)自动清除充电图标。 - 低电量进入 `LOW_POWER_PAGE` 并抑制普通用户操作。 -- 充电状态变化可触发页面刷新。 -- 用户无操作达到设置超时后进入 `WELCOME_PAGE`。 +- 充电状态变化可触发页面刷新(仅在百分比或充电状态真正变化时刷屏,避免无效刷新)。 +- 用户无操作达到设置超时后进入 `WELCOME_PAGE`(类似熄屏)。 - 主循环默认 5 小时无交互进入 `SHUTDOWN_PAGE`(常量 `TIMEOUT_SHUTDOWN_TIME`)。 --- @@ -88,7 +131,6 @@ - 将开发板与墨水屏通过对应连接器连接,注意排线方向。 - `SF32-OED-EPD_V1.1` 与 `SF32-OED-EPD_V1.2` 可共用 `sf32-oed-epd_base` 软件板级配置。 - ### 编译与烧录 进入 `epdiy-epub/project` 后执行: @@ -105,8 +147,7 @@ build_sf32-oed-epd_v11_hcpu\uart_download.bat 按脚本提示输入串口号。 -参考: -[SiFli 官方编译/烧录文档](https://docs.sifli.com/projects/sdk/latest/sf32lb52x/quickstart/build.html) +参考:[SiFli 官方编译/烧录文档](https://docs.sifli.com/projects/sdk/latest/sf32lb52x/quickstart/build.html) ### menuconfig @@ -114,6 +155,7 @@ build_sf32-oed-epd_v11_hcpu\uart_download.bat scons --board=sf32-oed-epd_v11 --board_search_path=.. --menuconfig ``` +--- ## 操作说明 @@ -121,50 +163,64 @@ scons --board=sf32-oed-epd_v11 --board_search_path=.. --menuconfig - `UP`:上移 / 上一项 / 向前翻页 - `DOWN`:下移 / 下一项 / 向后翻页 -- `SELECT`:确认 / 进入 +- `SELECT`:确认 / 进入 / 循环切换值 - `UPGLIDE`:阅读页呼出覆盖操作层 ### 触控操作 - 主页面:点击左右区域切换选项,点击中间区域确认。 -- 书库页:点击书籍项选中,再次点击确认打开。 -- 目录页:点击目录项选中,再次点击确认跳转。 -- 阅读页:左右区域翻页;上滑呼出覆盖层;覆盖层内执行跳页/目录/返回书库。 +- 书库页:点击书籍项选中,再次点击确认,进入目录页。 +- 目录页:点击目录项选中,再次点击确认跳转阅读。 +- 阅读页:左右区域翻页;上滑呼出覆盖层;覆盖层内执行跳页/目录/返回书库/进入阅读设置。 +- 阅读设置页:点击设置项选中并切换值,点击"保存退出"保存。 --- ## 目录结构 -``` -│ -├──disk # 内置flash,存放少量EPUB电子书文件 -├──lib # 存放项目依赖的第三方库或自定义基础库 -│ ├──epdiy # EPD驱动核心库 -│ ├──Epub # EPUB 解析专用库,负责解析 EPUB 格式文件(解压、读取目录、解析内容结构、提取文本 / 图片等),是阅读器功能基础。 -│ │ ├──EpubList # EPUB 文件管理模块 -│ │ ├──Renderer # 渲染器模块,将 EPUB 解析后的内容(文本、图片)转换为电子书可显示的格式 -│ │ ├──RubbishHtmlParser # HTML 解析模块,以 XHTML 格式存储,此模块负责解析 HTML 结构,提取文本、图片、样式 -│ │ ├──ZipFile # 补充解压逻辑(配合 miniz),处理 EPUB 压缩包内的 HTML 及资源文件 -│ ├──Fonts # 存放字体数据文件,储字符的像素映射 -│ ├──Images # 图片处理模块,负责加载、解码 -│ ├──miniz-2.2.0 # 轻量级 ZIP 解压库,处理 EPUB 压缩包 -│ ├──png # PNG 图像解码库,为 PNGHelper 提供底层解码能力。 -│ └──tjpgd3 # JPEG 图像解码库,为 JPEGHelper 提供底层解码能力。 -| -├──project # 编译脚本为项目编译、调试、部署提供工具链支持 -| -├──sf32-oed-epd_v11和sf32-oed-epd_v12 # `SF32-OED-EPD_V1.1`和`SF32-OED-EPD_V1.2`开发板公用的相关配置文件 -├──sf32-oed-epd_v12_spi # `SF32-OED-6'-EPD_V1.2`开发板搭配SPI墨水屏的相关配置文件 -| -├──src # 项目核心源码目录,实现阅读器业务逻辑 - ├──boards # 硬件板级
- │ ├──battery # 电池管理模块,包含电量检测 - │ ├──controls # 输入控制模块(如按键、触摸),处理用户交互(翻页、选菜单等) - │ └──display # 实现屏幕显示的最终输出,且可能针对不同屏幕型号做适配 - ├──epub_mem.c # 内存管理模块,为 EPUB 解析、渲染分配 / 释放内存,适配嵌入式设备内存限制。 - │ - └──main.cpp # 程序入口(main 函数),初始化硬件、加载库、启动阅读器主逻辑(如打开 EPUB 文件、进入阅读界面 ) ``` +│ +├── disk/ # 内置 Flash,存放少量 EPUB 电子书文件 +├── lib/ # 第三方库与自定义基础库 +│ ├── epdiy/ # EPD 驱动核心库 +│ ├── Epub/ # EPUB 解析专用库 +│ │ ├── EpubList/ # EPUB 文件管理模块(含 tinyxml2) +│ │ ├── Renderer/ # 渲染器模块(帧缓冲、字体、图片合成) +│ │ ├── RubbishHtmlParser/ # XHTML 解析模块(TextBlock / ImageBlock) +│ │ └── ZipFile/ # 包内文件寻址(配合 miniz) +│ ├── Images/ # 内置图片数据(欢迎/低电量/充电/关机页) +│ ├── miniz-2.2.0/ # 轻量级 ZIP 解压库 +│ ├── png/PNGdec/ # PNG 解码库 +│ └── tjpgd3/ # JPEG 解码库 +│ +├── project/ # 编译脚本(SCons + Kconfig) +│ +├── sf32-oed-epd_base/ # V1.1 与 V1.2 公用板级配置 +├── sf32-oed-epd_v11/ # V1.1 板级配置 +├── sf32-oed-epd_v12/ # V1.2 板级配置 +├── sf32-oed-epd_v12_spi/ # V1.2 + SPI 墨水屏配置 +│ +├── scripts/ # 工具脚本(字体生成、图片转换) +│ +├── src/ # 核心业务逻辑 +│ ├── boards/ # 硬件抽象层 +│ │ ├── battery/ # 电池管理(ADC 采样 + 电量表) +│ │ ├── controls/ # 输入控制(按键 / 触控 / 动作语义) +│ │ ├── display_dbi/ # DBI 8-bit 并行墨水屏驱动 +│ │ ├── display_spi/ # SPI 墨水屏驱动 +│ │ └── touch/ # 触控芯片驱动(FT5446U / FT6336U / GT967) +│ ├── assets/ # 内置位图资源(C 数组) +│ ├── epub_mem.c # 嵌入式内存管理 +│ ├── epub_screen.cpp # 各页面绘制与事件处理 +│ ├── font_manager.c # 字体管理器(动态加载 TF 卡字体) +│ ├── reading_settings.cpp # 阅读设置页面(字体/字号/字重/行距/边距 + 持久化) +│ ├── UIRegionsManager.cpp # 触控区域管理(动态注册与命中检测) +│ └── main.cpp # 程序入口(UI 状态机主循环) +│ +├── tools/ # 辅助工具(字体转换脚本) +└── waveform/ # 墨水屏波形文件及解码库 +``` + --- ## 二次开发 @@ -174,7 +230,11 @@ scons --board=sf32-oed-epd_v11 --board_search_path=.. --menuconfig - 少量样书:放入 `disk/`,随文件系统镜像打包。 - 大量书籍:建议使用 TF 卡。 -#### 添加新的屏幕屏驱 +### 添加外部字体 + +将 `.ttf` 或 `.otf` 文件直接复制到 TF 卡的 `/fonts` 目录,重启后即可在"阅读设置 → 字体"中选用。 + +### 添加新的屏幕驱动 1. 复制已有屏驱配置文件并改名(建议以 `src/boards/display_dbi/epd_configs_opm060d.c` 为模板,按新屏型号命名)。 2. 根据屏幕波形文档,将波形数据转换为数组,例如: @@ -182,12 +242,11 @@ scons --board=sf32-oed-epd_v11 --board_search_path=.. --menuconfig - 局刷波形:`static const uint8_t xxx_wave_forms_partial[12][256] = {}` 3. 按屏驱文档修改关键函数(波形选择、LUT 转换、时序频率、VCOM)。 - * 3.1多温区波形选择(可选) +#### 3.1 多温区波形选择(可选) - 如果波形按温度分段,可组织为多组二维数组,通过温度选择对应波形: +如果波形按温度分段,可组织为多组二维数组,通过温度选择对应波形: ```c -// 定义波形表条目结构体 typedef struct { int min_temp; int max_temp; @@ -195,17 +254,13 @@ typedef struct { const uint8_t (*wave_table)[256]; } WaveTableEntry; -// 原始波形数据 -static const uint8_t te067xjhe_wave_full_0_5[45][256] = {}; -static const uint8_t te067xjhe_wave_full_5_10[45][256] = {}; -// ... +static const uint8_t te067xjhe_wave_full_0_5[45][256] = {}; +static const uint8_t te067xjhe_wave_full_5_10[45][256] = {}; static const uint8_t te067xjhe_wave_full_50_100[45][256] = {}; -// 全刷波形表 - 按温度区间组织 static const WaveTableEntry te067xjhe_wave_forms_full[] = { {0, 5, 45, &te067xjhe_wave_full_0_5[0]}, {5, 10, 45, &te067xjhe_wave_full_5_10[0]}, - // ... {50, 100, 45, &te067xjhe_wave_full_50_100[0]}, }; @@ -213,71 +268,54 @@ static const uint8_t *p_current_wave_from = NULL; uint32_t epd_wave_table_get_frames(int temperature, EpdDrawMode mode) { - const WaveTableEntry *wave_table; - size_t table_size; + const WaveTableEntry *wave_table = te067xjhe_wave_forms_full; + size_t table_size = sizeof(te067xjhe_wave_forms_full) / sizeof(WaveTableEntry); - wave_table = te067xjhe_wave_forms_full; - table_size = sizeof(te067xjhe_wave_forms_full) / sizeof(WaveTableEntry); - - // 查找与温度匹配的区间 for (size_t i = 0; i < table_size; i++) { if (temperature >= wave_table[i].min_temp && temperature < wave_table[i].max_temp) { p_current_wave_from = (const uint8_t *)(*wave_table[i].wave_table); return wave_table[i].frame_count; } } - - // 默认回退到第一组 p_current_wave_from = (const uint8_t *)(*wave_table[0].wave_table); return wave_table[0].frame_count; } ``` -* 3.2波形转换为 32 位 Epic LUT - - 将当前帧的 8 位波形转换为硬件使用的 32 位 LUT 值: +#### 3.2 波形转换为 32 位 Epic LUT ```c void epd_wave_table_fill_lut(uint32_t *p_epic_lut, uint32_t frame_num) { - // 每帧波形长度为 256 字节 const uint8_t *p_frame_wave = p_current_wave_from + (frame_num * 256); - - // Convert the 8-bit waveforms to 32-bit epic LUT values for (uint16_t i = 0; i < 256; i++) p_epic_lut[i] = p_frame_wave[i] << 3; } ``` -* 3.3调整时序与频率参数 - - 按屏驱规格书配置 `SDCLK -> sclk_freq`、`frame clock -> fclk_freq` 及相关时序参数: +#### 3.3 调整时序与频率参数 ```c const EPD_TimingConfig *epd_get_timing_config(void) { static const EPD_TimingConfig timing_config = { - .sclk_freq = 24, // 像素时钟(列时钟),单位 MHz - .SDMODE = 0, // SD 模式选择 - .LSL = 0, // 行开始信号需要的 clock 数 - .LBL = 0, // 行起始的空 clock 数 - .LDL = LCD_HOR_RES_MAX / 4, // 有效数据 clock 数(2bit+8数据线,需除以4) - .LEL = 1, // 行结束空 clock 数 - - .fclk_freq = 83, // 行时钟,单位 KHz - .FSL = 1, // 起始行信号需要的 clock 数 - .FBL = 3, // 起始空行数量 - .FDL = LCD_VER_RES_MAX, // 有效数据行数 - .FEL = 5, // 结束空行数量 + .sclk_freq = 24, // 像素时钟,单位 MHz + .SDMODE = 0, + .LSL = 0, + .LBL = 0, + .LDL = LCD_HOR_RES_MAX / 4, // 有效数据 clock 数(2bit+8数据线,需除以4) + .LEL = 1, + .fclk_freq = 83, // 行时钟,单位 KHz + .FSL = 1, + .FBL = 3, + .FDL = LCD_VER_RES_MAX, + .FEL = 5, }; - return &timing_config; } ``` -* 3.4设置 VCOM 电压 - - 根据新屏规格书提供电子书显示所需参考电压: +#### 3.4 设置 VCOM 电压 ```c uint16_t epd_get_vcom_voltage(void) @@ -289,16 +327,14 @@ uint16_t epd_get_vcom_voltage(void) 4. 在 `project/Kconfig.proj` 中新增屏幕宏与 `menuconfig` 选项,并将新配置文件加入编译条件。 #### 板子必须补充的 `Kconfig.proj` 配置 -* 以`sf32-oed-epd_v12`板子为例 -* 如果你新增了一个屏驱并希望在 `sf32-oed-epd_v12` 上可选可编译,`project/Kconfig.proj` 需要同步添加。建议按以下顺序处理: -1. 在 `choice "Custom LCD driver"` 下新增你的屏幕选项(建议命名带 `V12`,便于和 `V11` 区分)。 +以 `sf32-oed-epd_v12` 为例,新增屏驱后按以下顺序修改: + +1. 在 `choice "Custom LCD driver"` 下新增屏幕选项(建议命名带 `V12`)。 2. 在该选项中 `select` 对应触控驱动、EPD 类型宏和总线宏(一般为 `BSP_LCDC_USING_EPD_8BIT`)。 3. 在 `LCD_HOR_RES_MAX` / `LCD_VER_RES_MAX` / `LCD_DPI` 中补上新屏默认值。 4. 若希望 v12 默认选中新屏,在 `choice` 的 `default ... if BSP_USING_BOARD_SF32_OED_EPD_V12` 中切换为新宏。 -示例(按你的新屏替换宏名与参数): - ```kconfig choice prompt "Custom LCD driver" @@ -324,37 +360,15 @@ config LCD_DPI default 300 if LCD_USING_EPD_YOUR_PANEL_V12 ``` -完成后建议执行一次: +完成后建议执行一次以确认新屏选项可见并选中: ```bash menuconfig --board=sf32-oed-epd_v12 --board_search_path=.. ``` -确认新屏选项可见并选中,然后再进行编译。 +参考:[SiFli 屏幕模块适配说明](https://wiki.sifli.com/tools/%E5%B1%8F%E5%B9%95%E8%B0%83%E8%AF%95/%E6%B7%BB%E5%8A%A0%E5%B1%8F%E5%B9%95%E6%A8%A1%E7%BB%84%EF%BC%883%20%E5%A4%96%E7%BD%AE%EF%BC%89.html) -参考: -[SiFli 屏幕模块适配说明](https://wiki.sifli.com/tools/%E5%B1%8F%E5%B9%95%E8%B0%83%E8%AF%95/%E6%B7%BB%E5%8A%A0%E5%B1%8F%E5%B9%95%E6%A8%A1%E7%BB%84%EF%BC%883%20%E5%A4%96%E7%BD%AE%EF%BC%89.html) -### 3) 字体生成 - -可先生成 Unicode 区间,再由 TTF 生成字库头文件。 - -生成区间示例: - -```bash -python3 get_intervals_from_font.py abc.ttf > interval.h -python3 generate_gb2312_L1_intervals.py -``` - -生成字体示例: - -```bash -python3 fontconvert.py regular_font 15 abc.ttf > ../lib/Fonts/regular_font.h -``` - -注意:Unicode 区间必须按从小到大排序,否则字符检索会异常。 - ---- ## 致谢