【Duktape】移植到单片机
Duktape 是一个可嵌入的 Javascript引擎,专注于可移植性和紧凑的占用空间。
Duktape 很容易集成到 C/C++ 项目中:添加 duktape.c、duktape.h 和 duk_config.h 三个文件到您的程序中,并使用 Duktape API 从 C 代码调用 ECMAScript 函数,反之亦然。
安装依赖
1 | sudo apt update |
下载源代码并解压
下载
1
wget https://duktape.org/duktape-2.6.0.tar.xz
解压
1
tar -xvJf duktape-2.6.0.tar.xz
编译运行命令行版本
编译
1
2cd duktape-2.6.0/
make -f Makefile.cmdline创建程序文件 fib.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15function fib(n) {
if (n == 0) { return 0; }
if (n == 1) { return 1; }
return fib(n-1) + fib(n-2);
}
function test() {
var res = [];
for (i = 0; i < 20; i++) {
res.push(fib(i));
}
print(res.join(' '));
}
test();运行脚本
1
./duk fib.js
应该输出了以下数据
1
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181
生成移植用的程序
安装 python2 运行环境
不太幸运,需要使用 python2 来运行脚本,包管理都已经不提供 pip2 了,只能从其他地方下载。
1
2
3
4
5sudo apt install -y python2
curl https://bootstrap.pypa.io/pip/2.7/get-pip.py --output get-pip.py
sudo python2 get-pip.py
sudo python2 -m pip install PyYAML创建配置文件 my_config.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15```
3. 生成自检程序
```bash
rm -rf /tmp/out
# 一般问题检查
python2 tools/configure.py --output-directory /tmp/out -DDUK_USE_ASSERTIONS -DDUK_USE_SELF_TESTS
ls /tmp/out
# 带有超时检查函数(可用于中断应用程序)
python2 tools/configure.py --output-directory /tmp/out --fixup-line='extern duk_bool_t duk_exec_timeout_check(void*);' --fixup-line='extern duk_double_t duk_get_now_date(void);' -DDUK_USE_INTERRUPT_COUNTER -DDUK_USE_EXEC_TIMEOUT_CHECK=duk_exec_timeout_check
# sudo mv /tmp/out /mnt/c/Users/szc31/Downloads/duk_out将 /tmp/out 里的 duktape.c、duktape.h 和 duk_config.h 添加到单片机的工程(GCC)中,然后在 main.c 中包含
duktape.h
头文件,修改单片机堆栈大小 >2k 以下是调用方式:需要单片机的工程标准库中有 malloc、realloc、free 函数。
1
2
3duk_context *ctx = duk_create_heap_default();
duk_eval_string(ctx, "a = 0;");
duk_destroy_heap(ctx);修复嵌入式设备中无法使用的时间问题和中断时间的使用
打开
duk_config.h
找到
#elif defined(DUK_F_UNIX)
下面的那个#else
修改
#else
里面的内容- 将
#define DUK_USE_DATE_NOW_TIME
和#define DUK_USE_DATE_TZO_GMTIME
注释掉 - 并在
#undef DUK_USE_DATE_PRS_STRPTIME
上面添加#undef DUK_USE_DATE_NOW_TIME
和#undef DUK_USE_DATE_TZO_GMTIME
- 注释掉
#include <time.h>
,这个头文件在本示例里用不到了
- 将
找到
#error no provider for DUK_USE_DATE_GET_NOW()
语句将其注释掉,并在其下面添加以下程序1
找到
#error no provider for DUK_USE_DATE_GET_LOCAL_TZOFFSET()
语句将其注释掉,并在其下面添加以下程序1
2// 默认时区偏移(秒)
在另外的源文件中,提供外部时间处理函数和周期检查函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
duk_double_t duk_get_now_date(void)
{
// 这里先返回一个固定时间测试 2021-08-04 09:33:24
return -1628040804062.0;
}
duk_bool_t duk_exec_timeout_check(void *udata) {
// 一般在执行好多指令后才会执行一次这个函数
// 因为作者写死了,所以只能去 duktape.c里找
// DUK_HTHREAD_INTCTR_DEFAULT 宏定义
// 修改后面的值可以提高本函数的调用频率
// 超时返回1,将触发异常
// 正常返回0
return 0;
}
添加 require 功能
这个 require 实际上是一个从磁盘上加载模块的功能,类似c语言的 include,不过是在运行时进行的。
在 duktape 中注册模块实际上是通过调用 Duktape.modSearch 来实现的,指定该属性的值到c语言中的加载函数即可实现模块的加载功能。
从 duktape-2.6.0\extras\module-duktape 中将 duk_module_duktape.c 和 duk_module_duktape.h 放到工程下。
代码如下
1 |
|
sys模块程序如下:
1 | var text = 'Hello world!'; |
示例调用如下:
1 | const sys = require('sys'); |
【Duktape】移植到单片机