Skip to content

Commit e9c2b2b

Browse files
committed
beta
1 parent 761df24 commit e9c2b2b

File tree

408 files changed

+110831
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

408 files changed

+110831
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.vscode
2+
build

CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# The following lines of boilerplate have to be in your project's
2+
# CMakeLists in this exact order for cmake to work correctly
3+
cmake_minimum_required(VERSION 3.5)
4+
5+
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
6+
project(nodemcujs)

README.md

Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
# nodemcujs
2+
3+
> 目前处于开发阶段,还有很多需要做
4+
5+
### A real JavaScript based interactive firmware for ESP32.
6+
7+
nodemcujs 是一个在 ESP32 芯片上的 JavaScript 运行时。不同于 NodeMcu,这是在 ESP32 芯片上运行了一个真正的 JavaScript 虚拟机。在 ESP32 上编写 JavaScript 就和编写 NodeJS 程序一样。并且提供了一个 32MBit 的片上虚拟文件系统,你可以编写模块化的应用,然后使用 require() 导入模块。甚至直接将你的兼容 NodeJS 模块运行在 ESP32 上,而无需做任何改动。
8+
9+
# 文档 | Documentation
10+
11+
website: http://nodemcujs.timor.tech
12+
13+
github: https://github.com/nodemcujs/nodemcujs-doc
14+
15+
这是 nodemcujs 的网站,所有文档和最新信息将会发布在这里。也可以通过 fork 项目贡献文章。文档还在不断完善中。
16+
17+
# 特性
18+
19+
- 串口命令行交互
20+
- 使用开源 JerryScript,内存开销小,开源社区支持
21+
- 完整 ES5, 部分 ES6 语法支持
22+
- 虚拟文件系统
23+
- 遵循 CMD 模块规范
24+
- 使用官方 ESP_IDF 工程,集成硬件驱动
25+
- 纯 C 开发,编写 addon 方便
26+
27+
# Todo
28+
29+
- [ ] require 相对路径支持
30+
- [ ] 内置模块
31+
- [ ] 错误处理和调试
32+
- [ ] 桥接驱动
33+
- [ ] 完善文档
34+
- [ ] 更多。。。
35+
36+
# hello world
37+
38+
```js
39+
var foo = require('/spiffs/foo.js')
40+
41+
setInterval(() => {
42+
console.log('hello nodemcujs!')
43+
}, 1000)
44+
45+
foo();
46+
```
47+
48+
# 快速开始
49+
50+
快速在本地环境构建出可执行的固件并烧写到 ESP32 芯片上。
51+
52+
## 1. 开发环境搭建
53+
54+
项目使用 CMake `cmake_minimum_required (VERSION 2.8.12)` 构建。
55+
56+
我在 MacOS 10.13、Ubuntu 18.04.2 LTS、Windows 10 中已验证构建通过,你可以选择适合自己的开发环境。
57+
58+
在 Windows 中环境设置比较麻烦,请仔细参照官方文档进行环境安装,我多数在 Ubuntu 下进行开发测试。
59+
60+
### 1.1 设置工具链
61+
62+
按照官方文档进行编译工具链的安装。
63+
64+
- Windows: https://docs.espressif.com/projects/esp-idf/zh_CN/v3.2-rc/get-started/windows-setup.html
65+
- Linux: https://docs.espressif.com/projects/esp-idf/zh_CN/v3.2-rc/get-started/linux-setup.html
66+
- MaxOS: https://docs.espressif.com/projects/esp-idf/zh_CN/v3.2-rc/get-started/macos-setup.html
67+
68+
### 1.2 获取 ESP-IDF (V3.2-RC)
69+
70+
参照官方文档进行安装。注意本项目使用的是 V3.2-RC 版本。
71+
72+
ESP-IDF(V3.2-RC): https://docs.espressif.com/projects/esp-idf/zh_CN/v3.2-rc/get-started/index.html#esp-idf
73+
74+
你也可以在没有安装 git 的环境中下载源码包: https://github.com/espressif/esp-idf/releases/download/v3.2/esp-idf-v3.2.zip
75+
76+
## 2. 获取 nodemcujs 源码
77+
78+
```bash
79+
$ git clone git@github.com:nodemcujs/nodemcujs-firmware.git
80+
```
81+
82+
项目已经内置了 JerryScript 并修改了一些 CMakeLists.txt 以使得它可以在 ESP-IDF 中构建。
83+
84+
## 3. 编译固件
85+
86+
```bash
87+
$ cd nodemcujs-firmware
88+
```
89+
90+
创建 build 文件夹,为了编译后的临时文件不影响源码目录。
91+
92+
```bash
93+
$ mkdir build
94+
$ cd build
95+
```
96+
97+
使用 Cmake 构建
98+
99+
```bash
100+
cmake ../
101+
```
102+
103+
配置构建参数。大多数情况下使用默认参数就可以,这里一般只需要配置好串口和波特率。
104+
105+
```bash
106+
$ make menuconfig
107+
```
108+
109+
> 注意: 项目使用了自定义的分区表。详情可以查看分区表文件 [partitions.csv][partitions.csv]
110+
111+
最后进行编译固件。
112+
113+
```bash
114+
make
115+
```
116+
117+
## 4. 烧录固件
118+
119+
如果编译成功,会生成 3 个文件:
120+
121+
1. nodemcujs.bin (可执行 app)
122+
2. bootloader/bootloader.bin (引导)
123+
3. partition_table/partition_table.bin (分区表)
124+
125+
使用下面的命令进行固件的烧录。
126+
127+
```bash
128+
make flash
129+
```
130+
131+
如果你看到控制台输出如下信息,并一直停留,那么你需要手动让 ESP32 芯片进入下载模式。
132+
133+
```bash
134+
esptool.py --chip esp32 -b 460800 write_flash --flash_mode dio --flash_size detect --flash_freq 80m 0x1000 bootloader/bootloader.bin 0x8000 partition_table/partition-table.bin 0x10000 nodemcujs.bin
135+
esptool.py v2.6
136+
Found 3 serial ports
137+
Serial port /dev/ttyUSB0
138+
Connecting........___........___
139+
```
140+
141+
等待烧录完成,重启 ESP32 就可以了。你可以使用 ESPlorer 连接上 ESP32,输入 JavaScript 和它进行交互了。
142+
143+
## 5. 手动烧录固件
144+
145+
对于没有或者不方便安装 ESP-IDF 工程的用户,可以使用烧录工具进行烧录已经构建好的固件。
146+
147+
我们推荐使用 [esptool.py][esptool] 工具进行烧录。可以从 [release][release-github] 页面下载已经构建好的固件。
148+
149+
```bash
150+
$ python esptool.py --chip esp32 -p /dev/ttyUSB0 -b 460800 write_flash --flash_mode dio --flash_size detect --flash_freq 80m 0x1000 bootloader.bin 0x8000 partition-table.bin 0x10000 nodemcujs.bin
151+
```
152+
153+
这里有几点需要说明:
154+
155+
> -b 参数表示下载固件时使用的波特率,如果出现烧录失败等问题,请尝试降低波特率为 115200 或者 9600。这可能是劣质的串口芯片造成的。
156+
>
157+
> -p 参数表示 ESP32 芯片在你电脑上的串口设备,请替换为实际的值或者端口号。在 Windows 上的可能值为 COM3。
158+
>
159+
> 0x1000 和 0x8000,以及 0x10000 使用的是默认值。
160+
>
161+
> 第一次烧录需要这 3 个文件,以后烧录只需要一个 nodemcujs.bin 文件就行了。
162+
163+
## 6. 制作文件镜像
164+
165+
nodemcujs 使用 [spiffs][spiffs] 作为默认文件系统,容量大约为 `2.7MB`,所以文件的总大小不能超出此范围。关于为什么容量只有 2.7MB,请参考 [partitions.csv][partitions.csv]
166+
167+
我们建议将要烧录到 flash 存储的文件放到 `spiffs` 文件夹内,未来的构建系统中,我们将会自动构建 flash 镜像并随固件一起烧录。文件系统也是默认以 `/spiffs` 为前缀的。
168+
169+
我们使用 [mkspiffs][mkspiffs] 来制作镜像。这是 C++ 工程,首先你要编译它,得到可执行文件 `mkspiffs`
170+
171+
```bash
172+
$ mkspiffs -c spiffs -b 4096 -p 256 -s 0x2F0000 spiffs.bin
173+
```
174+
175+
上面的命令会将 `spiffs` 文件夹内的全部文件打包成镜像,并且在当前目录生成 `spiffs.bin` 文件。
176+
177+
这里有几点需要注意:
178+
179+
> -s 0x2F0000 是 nodemcujs 所使用的大小,至少在目前你不能大于此值。除非你自己定义分区表。
180+
181+
## 7. 烧录文件到 flash 芯片
182+
183+
nodemcujs 会在启动时检查分区,如果无法挂载 `storage` 分区,则会`自动格式化 storage` 分区并挂载。
184+
185+
你可以将你的 JavaScript 应用或者任何文件烧录到 ESP32 上,nodemcujs 会在启动时自动加载 `/spiffs/index.js` 文件,所以这可能是自动启动应用的一个好主意。
186+
187+
```bash
188+
python esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 115200 write_flash -z 0x10000 spiffs.bin
189+
```
190+
191+
使用上面的命令将文件镜像烧录到 flash 中。
192+
193+
有几点需要注意:
194+
195+
> 一旦你烧录文件镜像,则原来的分区会被覆盖掉,请知道你自己在做什么。
196+
>
197+
> -z 0x10000 是目前 nodemcujs 默认分区表参数,至少在目前你不能小于此值,否则 app 程序可能会被覆盖。
198+
199+
# License
200+
201+
[MIT][MIT]
202+
203+
204+
205+
206+
[esptool]: https://github.com/espressif/esptool
207+
[release-github]: https://github.com/nodemcujs/nodemcujs-firmware/releases
208+
[partitions.csv]: ./partitions.csv
209+
[mkspiffs]: https://github.com/igrr/mkspiffs
210+
[spiffs]: https://docs.espressif.com/projects/esp-idf/zh_CN/v3.2-rc/api-reference/storage/spiffs.html
211+
[MIT]: [./LICENSE]
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
cmake_minimum_required (VERSION 2.8.12)
2+
3+
set(COMPONENT_ADD_INCLUDEDIRS include)
4+
set(COMPONENT_SRCDIRS .)
5+
6+
set(COMPONENT_REQUIRES "jerry-core" "jerry-ext")
7+
8+
register_component()

components/jerry-console/component.mk

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#
2+
# "main" pseudo-component makefile.
3+
#
4+
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
5+

components/jerry-console/console.c

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
#include "include/console.h"
2+
3+
#include <stdio.h>
4+
5+
#include "freertos/FreeRTOS.h"
6+
7+
#include "jerryscript.h"
8+
#include "jerryscript-ext/handler.h"
9+
10+
static void print_value(const jerry_value_t value)
11+
{
12+
if (jerry_value_is_undefined(value))
13+
{
14+
printf("undefined");
15+
}
16+
else if (jerry_value_is_null(value))
17+
{
18+
printf("null");
19+
}
20+
else if (jerry_value_is_boolean(value))
21+
{
22+
if (jerry_get_boolean_value(value))
23+
{
24+
printf("true");
25+
}
26+
else
27+
{
28+
printf("false");
29+
}
30+
}
31+
/* Float value */
32+
else if (jerry_value_is_number(value))
33+
{
34+
printf("%.0f", jerry_get_number_value(value));
35+
}
36+
/* String value */
37+
else if (jerry_value_is_string(value))
38+
{
39+
/* Determining required buffer size */
40+
jerry_size_t req_sz = jerry_get_string_size(value);
41+
jerry_char_t str_buf_p[req_sz + 1];
42+
43+
jerry_string_to_char_buffer(value, str_buf_p, req_sz);
44+
str_buf_p[req_sz] = '\0';
45+
46+
printf("%s", (const char *)str_buf_p);
47+
}
48+
/* Object reference */
49+
else if (jerry_value_is_object(value))
50+
{
51+
printf("[object]");
52+
}
53+
}
54+
55+
static jerry_value_t log_handler(const jerry_value_t func_value, /**< function object */
56+
const jerry_value_t this_value, /**< this arg */
57+
const jerry_value_t args[], /**< function arguments */
58+
const jerry_length_t args_cnt) /**< number of function arguments */
59+
{
60+
if (args_cnt == 0)
61+
{
62+
return jerry_create_undefined();
63+
}
64+
uint32_t argIndex = 0;
65+
if (!jerry_value_is_string(args[0]))
66+
{
67+
while (argIndex < args_cnt)
68+
{
69+
print_value(args[argIndex]);
70+
if (argIndex != args_cnt - 1)
71+
{
72+
printf(" ");
73+
}
74+
argIndex++;
75+
}
76+
printf("\n");
77+
return jerry_create_undefined();
78+
}
79+
jerry_size_t len = jerry_get_string_size(args[0]);
80+
jerry_char_t format[len];
81+
jerry_string_to_char_buffer(args[0], format, len);
82+
argIndex++;
83+
84+
uint32_t end = 0;
85+
double num = 0;
86+
jerry_size_t substrLen = 0;
87+
jerry_char_t *substr;
88+
89+
while (end < len)
90+
{
91+
if (argIndex >= args_cnt)
92+
{
93+
printf("%c", format[end]);
94+
end++;
95+
continue;
96+
}
97+
if (format[end] != '%')
98+
{
99+
printf("%c", format[end]);
100+
end++;
101+
continue;
102+
}
103+
switch (format[end + 1])
104+
{
105+
case 's':
106+
substrLen = jerry_get_string_size(args[argIndex]);
107+
substr = (jerry_char_t *) malloc(substrLen + 1);
108+
jerry_string_to_char_buffer(args[argIndex], substr, substrLen);
109+
substr[substrLen] = '\0';
110+
printf("%s", substr);
111+
free(substr);
112+
end+= 2;
113+
argIndex++;
114+
break;
115+
case 'd':
116+
num = jerry_get_number_value(args[argIndex]);
117+
printf("%.0f", num);
118+
end+= 2;
119+
argIndex++;
120+
break;
121+
default:
122+
printf("%c", format[end]);
123+
end++;
124+
break;
125+
}
126+
}
127+
if (len > 0)
128+
{
129+
printf("\n");
130+
}
131+
return jerry_create_undefined();
132+
}
133+
134+
void module_console_init()
135+
{
136+
137+
jerry_value_t global = jerry_get_global_object();
138+
139+
jerry_value_t module_name = jerry_create_string((const jerry_char_t *)"console");
140+
jerry_value_t console = jerry_create_object();
141+
142+
jerry_value_t prop_name = jerry_create_string((const jerry_char_t *)"log");
143+
jerry_value_t value = jerry_create_external_function(log_handler);
144+
jerry_release_value(jerry_set_property(console, prop_name, value));
145+
jerry_release_value(prop_name);
146+
jerry_release_value(value);
147+
148+
jerry_release_value(jerry_set_property(global, module_name, console));
149+
jerry_release_value(console);
150+
jerry_release_value(module_name);
151+
jerry_release_value(global);
152+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#ifndef MODULE_CONSOLE_H
2+
#define MODULE_CONSOLE_H
3+
4+
void module_console_init();
5+
6+
#endif

0 commit comments

Comments
 (0)