numworks移植记录:2.下载 NumWorks 代码并分析目录结构

2 阅读5分钟

下载 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's architecture

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 颜色)、KDPointKDRect 等基本类型和绘图函数。
  • src/ 下的实现,如 framebuffer.cppfont.cpp 等。移植时需要确保 Kandinsky 的像素操作能正确映射到 ESP32-S3 的 LCD 驱动上。
3.3 poincare/

Poincaré 是数学引擎,功能强大且复杂。它负责解析用户输入的数学表达式(如 sin(π/2))、化简、求值(包括符号计算和数值计算),并生成结果。目录结构:

  • include/poincare.hsrc/ 下的众多源文件,实现了表达式节点(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.happs/window.h 等),并调用 Kandinsky 和 Poincaré 实现功能。移植时,这些应用代码通常无需修改,只要底层接口正确即可运行。

3.9 build/output/

编译过程中生成的中间文件和最终固件。默认情况下,make 会在 build 目录下生成对象文件,最终固件输出到 output 目录。

3.10 其他目录
  • haussmann/:构建辅助脚本,如生成版本信息、打包资源等。
  • tests/:单元测试。
  • docs/:文档。

4. 移植重点关注哪些模块?

从底层到上层,我们需要依次关注:

  1. Ion:这是与硬件交互的直接层。必须为 ESP32-S3 实现所有 Ion 接口:显示、按键、存储、定时器、电源等。可以利用 ESP-IDF 提供的驱动(如 SPI LCD、GPIO 按键、NVS 分区)来适配。
  2. 链接脚本和内存布局:NumWorks 假设特定的内存区域(如用于 Poincaré 内存池的静态缓冲区),需要调整链接脚本(或使用 C++ 静态分配)以适应 ESP32-S3 的 SRAM 布局。
  3. 第三方库:确保 gmpmpfr 等能在 ESP32-S3 上编译通过,可能需要调整编译选项或使用 ESP-IDF 的组件版本。
  4. 启动代码:替换原有的启动文件,使用 ESP-IDF 的启动流程,同时保证 C++ 全局构造和析构正确执行。
  5. MicroPython 集成:如果希望保留 Python 功能,需要将 MicroPython 移植层适配到 ESP-IDF,并连接到键盘和显示。

5. 总结

NumWorks 代码结构清晰,模块分离度较好。通过理解每个目录的作用,我们可以有目标地进行移植工作。在接下来的文章中,我们将逐步深入每个模块,介绍具体的适配方法和遇到的问题。下一章,我们将从最底层的 Ion 开始,逐步点亮屏幕、读取按键。敬请期待!