下载 NumWorks 代码并分析目录结构
在开发环境搭建好之后,下一步就是获取 NumWorks 的源代码,并熟悉它的组织结构。NumWorks 是一款开源图形计算器,其代码托管在 GitHub 上,采用 C++ 编写,使用 Makefile 作为构建系统。理解代码布局是移植工作的基础,能帮助我们快速定位需要修改的部分。
1. 获取源代码
NumWorks 的官方仓库地址是:github.com/numworks/ep… 是 NumWorks 操作系统的名称)。你可以通过 Git 克隆到本地:
bash
git clone --recursive https://github.com/numworks/epsilon.git
--recursive 参数很重要,因为仓库中包含子模块(如第三方库),需要一并下载。克隆完成后,进入目录:
bash
cd epsilon
现在,让我们来探索这个庞大的代码库。
2. 代码仓库概览
Epsilon 是一个混合了 C、C++ 和少量汇编的项目,主要面向嵌入式系统(ARM Cortex-M4/M7 架构)。它的构建系统基于 Makefile,顶层 Makefile 负责调用各个子模块的编译。代码主要分为以下几个核心模块:
-
ion:硬件抽象层(HAL),提供对底层设备(显示、键盘、闪存、定时器等)的抽象接口。
-
kandinsky:2D 图形库,负责像素绘制、字体渲染等。
-
poincare:数学引擎,负责表达式解析、化简、求值和符号计算。
-
python:MicroPython 解释器集成,实现 Python 计算功能。
-
apps:内置应用程序(如计算器、函数绘图、表格等)。
-
escher:GUI图形控件库。
此外,还有一些辅助目录:build/(编译输出)、external_apps/(外部应用移植)、haussmann/(编译脚本)、liba/(c标准库)等。
3. 主要目录详解
3.1 ion/
这是整个移植工作的核心之一。Ion 提供了与硬件无关的接口,底层实现针对具体平台(如 STM32 系列)。它的结构如下:
include/ion:公共头文件,定义了 Ion 的 API,如:backlight.h:背光控制。console.h:串口控制台。crc.h:CRC32 计算。display.h:屏幕显示基础操作。events.h:按键事件。power.h:电源管理。storage.h:内部闪存存储。timing.h:延时和计时。usb.h:USB 通信。
src/:针对不同平台的实现,通常按芯片分类(如src/device/n0110是 N0110 型号的实现)。移植时需要为 ESP32-S3 添加一个新的实现目录,或者直接修改通用代码以适配 ESP-IDF。
3.2 kandinsky/
Kandinsky 是 NumWorks 的 2D 图形库,负责在屏幕上绘制点、线、矩形、字符等。它不依赖具体硬件,而是通过 Ion 的显示接口将像素数据推送到屏幕。主要文件:
kandinsky.h:主头文件,定义了KDColor(16 位 RGB565 颜色)、KDPoint、KDRect等基本类型和绘图函数。src/下的实现,如framebuffer.cpp、font.cpp等。移植时需要确保 Kandinsky 的像素操作能正确映射到 ESP32-S3 的 LCD 驱动上。
3.3 poincare/
Poincaré 是数学引擎,功能强大且复杂。它负责解析用户输入的数学表达式(如 sin(π/2))、化简、求值(包括符号计算和数值计算),并生成结果。目录结构:
-
include/poincare.h和src/下的众多源文件,实现了表达式节点(Expression 类层次结构)、简化规则、符号计算等。
3.4 python/
NumWorks 支持 MicroPython,使用户能用 Python 编程。这个目录包含 MicroPython 的定制版本,以及将 MicroPython 与 Poincaré 对接的胶水代码。主要子目录:
src/:MicroPython 核心源码(来自官方仓库的子模块)。port/:针对 NumWorks 平台的移植层,包括文件系统、硬件接口、模块注册等。ESP32-S3 本身已支持 MicroPython,但需要将其与 NumWorks 的 UI 和数学库集成。
3.5 apps/
应用程序目录,包含计算器的主界面和各种工具。每个应用是一个独立的模块,如:
apps/calculation/:主计算器应用。apps/graph/:函数绘图。apps/statistics/:统计表格。apps/settings/:设置界面。
这些应用共享一个事件驱动框架(apps/app.h、apps/window.h 等),并调用 Kandinsky 和 Poincaré 实现功能。移植时,这些应用代码通常无需修改,只要底层接口正确即可运行。
3.9 build/ 和 output/
编译过程中生成的中间文件和最终固件。默认情况下,make 会在 build 目录下生成对象文件,最终固件输出到 output 目录。
3.10 其他目录
haussmann/:构建辅助脚本,如生成版本信息、打包资源等。tests/:单元测试。docs/:文档。
4. 移植重点关注哪些模块?
从底层到上层,我们需要依次关注:
- Ion:这是与硬件交互的直接层。必须为 ESP32-S3 实现所有 Ion 接口:显示、按键、存储、定时器、电源等。可以利用 ESP-IDF 提供的驱动(如 SPI LCD、GPIO 按键、NVS 分区)来适配。
- 链接脚本和内存布局:NumWorks 假设特定的内存区域(如用于 Poincaré 内存池的静态缓冲区),需要调整链接脚本(或使用 C++ 静态分配)以适应 ESP32-S3 的 SRAM 布局。
- 第三方库:确保
gmp、mpfr等能在 ESP32-S3 上编译通过,可能需要调整编译选项或使用 ESP-IDF 的组件版本。 - 启动代码:替换原有的启动文件,使用 ESP-IDF 的启动流程,同时保证 C++ 全局构造和析构正确执行。
- MicroPython 集成:如果希望保留 Python 功能,需要将 MicroPython 移植层适配到 ESP-IDF,并连接到键盘和显示。
5. 总结
NumWorks 代码结构清晰,模块分离度较好。通过理解每个目录的作用,我们可以有目标地进行移植工作。在接下来的文章中,我们将逐步深入每个模块,介绍具体的适配方法和遇到的问题。下一章,我们将从最底层的 Ion 开始,逐步点亮屏幕、读取按键。敬请期待!