Skip to content

Commit 9f7cab8

Browse files
committed
feat: add ESP32-S31 Wi-Fi and Bluetooth targets
1 parent d2dc319 commit 9f7cab8

20 files changed

Lines changed: 843 additions & 27 deletions

.github/workflows/ci.yml

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ jobs:
2828
run: cargo test --all-targets
2929
working-directory: app
3030
- name: Test embedded host-function ABI
31-
run: cargo test --features esp32c3
31+
run: cargo test --features esp32c3,wifi,bluetooth
3232
working-directory: app
3333
- name: Test VMBC partition packer
3434
run: |
@@ -44,19 +44,27 @@ jobs:
4444
esp32:
4545
name: ESP32-C3 factory firmware
4646
runs-on: ubuntu-latest
47+
env:
48+
PLATFORMIO_CORE_DIR: /mnt/TEMP/platformio/core
49+
PIP_CACHE_DIR: /mnt/TEMP/platformio/pip-cache
4750
steps:
4851
- uses: actions/checkout@v4
4952
with:
5053
path: app
5154
- uses: dtolnay/rust-toolchain@1.94.1
5255
with:
5356
components: llvm-tools-preview
54-
targets: riscv32imc-unknown-none-elf
57+
targets: riscv32imc-unknown-none-elf,riscv32imafc-unknown-none-elf
5558
- uses: actions/setup-python@v5
5659
with:
57-
python-version: "3.12"
60+
python-version: "3.11"
5861
- name: Install PlatformIO
59-
run: python -m pip install platformio==6.1.19
62+
run: |
63+
sudo mkdir -p /mnt/TEMP
64+
sudo chown -R "$USER:$USER" /mnt/TEMP
65+
python -m venv /mnt/TEMP/platformio/venv
66+
/mnt/TEMP/platformio/venv/bin/pip install platformio==6.1.19
67+
echo /mnt/TEMP/platformio/venv/bin >> "$GITHUB_PATH"
6068
- name: Build complete firmware
6169
run: pio run
6270
working-directory: app
@@ -67,32 +75,48 @@ jobs:
6775
grep 'micro-rustscript:gpio=low' /tmp/arduino.log
6876
grep 'rss:status=0' /tmp/arduino.log
6977
working-directory: app
78+
- name: Install ESP-IDF preview toolchain under /mnt/TEMP
79+
run: |
80+
sudo mkdir -p /mnt/TEMP
81+
sudo chown -R "$USER:$USER" /mnt/TEMP
82+
ci/install-esp-idf-s31.sh
83+
working-directory: app
84+
- name: Build ESP32-S31 factory image
85+
run: pio run -e esp32s31
86+
working-directory: app
7087
- name: Verify firmware artifacts
7188
run: |
7289
test -s .pio/build/esp32-c3-devkitm-1/firmware.elf
7390
test -s .pio/build/esp32-c3-devkitm-1/firmware.bin
7491
test -s dist/micro-rustscript-esp32-c3.factory.bin
7592
test -s .pio/generated/rustscript.partition.bin
7693
test -s .pio/build/arduino/program
94+
test -s dist/micro-rustscript-esp32-s31.factory.bin
95+
test -s /mnt/TEMP/micro-rustscript-esp32s31/build/micro_rustscript_esp32s31.elf
96+
cp /mnt/TEMP/micro-rustscript-esp32s31/build/micro_rustscript_esp32s31.elf \
97+
dist/micro-rustscript-esp32-s31.elf
7798
nm -C .pio/build/esp32-c3-devkitm-1/firmware.elf | grep rustscript_run_vmbc
7899
nm -C .pio/build/esp32-c3-devkitm-1/firmware.elf | grep rustscript_dispatch_host
79-
grep 'rustscript.*0x0b0000.*0x010000' partitions.csv
100+
grep 'rustscript.*0x110000.*0x010000' partitions.csv
80101
stat --format='%n %s bytes' \
81102
.pio/build/esp32-c3-devkitm-1/firmware.elf \
82103
.pio/build/esp32-c3-devkitm-1/firmware.bin \
83104
dist/micro-rustscript-esp32-c3.factory.bin \
84105
.pio/generated/esp32-blinky.vmbc \
85106
.pio/generated/rustscript.partition.bin
86-
test "$(stat --format=%s dist/micro-rustscript-esp32-c3.factory.bin)" -lt 1000000
107+
test "$(stat --format=%s dist/micro-rustscript-esp32-c3.factory.bin)" -lt 1200000
87108
working-directory: app
88109
- uses: actions/upload-artifact@v4
89110
with:
90-
name: micro-rustscript-esp32-c3
111+
name: micro-rustscript-firmware
91112
path: |
92113
app/dist/micro-rustscript-esp32-c3.factory.bin
93114
app/.pio/build/esp32-c3-devkitm-1/firmware.elf
94115
app/.pio/generated/esp32-blinky.vmbc
95116
app/.pio/generated/rustscript.partition.bin
117+
app/.pio/build/arduino/program
118+
app/dist/micro-rustscript-esp32-s31.factory.bin
119+
app/dist/micro-rustscript-esp32-s31.elf
96120
app/scripts/flash_vmbc.py
97121
app/scripts/vmbc_image.py
98122
app/scripts/repl_vmbc.py

.github/workflows/release-esp32.yml

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: ESP32 firmware release
1+
name: Firmware release
22

33
on:
44
push:
@@ -11,47 +11,67 @@ permissions:
1111
jobs:
1212
release:
1313
runs-on: ubuntu-latest
14+
env:
15+
PLATFORMIO_CORE_DIR: /mnt/TEMP/platformio/core
16+
PIP_CACHE_DIR: /mnt/TEMP/platformio/pip-cache
1417
steps:
1518
- uses: actions/checkout@v4
1619
with:
1720
path: app
1821
- uses: dtolnay/rust-toolchain@1.94.1
1922
with:
2023
components: llvm-tools-preview
21-
targets: riscv32imc-unknown-none-elf
24+
targets: riscv32imc-unknown-none-elf,riscv32imafc-unknown-none-elf
2225
- uses: actions/setup-python@v5
2326
with:
24-
python-version: "3.12"
27+
python-version: "3.11"
2528
- name: Install build tools
26-
run: python -m pip install platformio==6.1.19
27-
- name: Build factory image
28-
run: pio run
29+
run: |
30+
sudo mkdir -p /mnt/TEMP
31+
sudo chown -R "$USER:$USER" /mnt/TEMP
32+
python -m venv /mnt/TEMP/platformio/venv
33+
/mnt/TEMP/platformio/venv/bin/pip install platformio==6.1.19
34+
echo /mnt/TEMP/platformio/venv/bin >> "$GITHUB_PATH"
35+
- name: Install ESP-IDF preview toolchain under /mnt/TEMP
36+
run: |
37+
sudo mkdir -p /mnt/TEMP
38+
sudo chown -R "$USER:$USER" /mnt/TEMP
39+
ci/install-esp-idf-s31.sh
40+
working-directory: app
41+
- name: Build all release targets
42+
run: pio run -e esp32-c3-devkitm-1 -e arduino -e esp32s31
2943
working-directory: app
3044
- name: Prepare release assets
3145
run: |
3246
cp .pio/build/esp32-c3-devkitm-1/firmware.elf dist/micro-rustscript-esp32-c3.elf
47+
cp .pio/build/arduino/program dist/micro-rustscript-arduino
48+
cp /mnt/TEMP/micro-rustscript-esp32s31/build/micro_rustscript_esp32s31.elf dist/micro-rustscript-esp32-s31.elf
3349
cp .pio/generated/esp32-blinky.vmbc dist/esp32-blinky.vmbc
3450
cp .pio/generated/rustscript.partition.bin dist/rustscript.partition.bin
3551
cp scripts/flash_vmbc.py scripts/vmbc_image.py scripts/repl_vmbc.py partitions.csv dist/
3652
cd dist
37-
sha256sum micro-rustscript-esp32-c3.factory.bin micro-rustscript-esp32-c3.elf esp32-blinky.vmbc rustscript.partition.bin flash_vmbc.py vmbc_image.py repl_vmbc.py partitions.csv > SHA256SUMS
53+
sha256sum micro-rustscript-esp32-c3.factory.bin micro-rustscript-esp32-c3.elf micro-rustscript-arduino micro-rustscript-esp32-s31.factory.bin micro-rustscript-esp32-s31.elf esp32-blinky.vmbc rustscript.partition.bin flash_vmbc.py vmbc_image.py repl_vmbc.py partitions.csv > SHA256SUMS
3854
working-directory: app
3955
- name: Publish GitHub Release
4056
uses: softprops/action-gh-release@v2
4157
with:
42-
name: micro-rustscript ESP32-C3 ${{ github.ref_name }}
58+
name: micro-rustscript firmware ${{ github.ref_name }}
4359
generate_release_notes: true
4460
body: |
45-
Directly flashable ESP32-C3-DevKitM-1 image with namespaced GPIO, I2C, MCU, and serial framework APIs. Startup checks SD, then the dedicated VMBC partition, then opens the serial VMBC REPL.
61+
Release images for ESP32-C3-DevKitM-1, Arduino host, and ESP32-S31. Supported ESP targets include optional ESP-IDF Wi-Fi and Bluetooth LE controller APIs.
4662
4763
Flash at offset `0x0`:
4864
```bash
4965
python -m esptool --chip esp32c3 erase_flash
5066
python -m esptool --chip esp32c3 write_flash 0x0 micro-rustscript-esp32-c3.factory.bin
67+
python -m esptool --chip esp32s31 write_flash 0x0 micro-rustscript-esp32-s31.factory.bin
5168
```
5269
files: |
5370
app/dist/micro-rustscript-esp32-c3.factory.bin
5471
app/dist/micro-rustscript-esp32-c3.elf
72+
app/dist/micro-rustscript-arduino
73+
app/dist/micro-rustscript-esp32-s31.factory.bin
74+
app/dist/micro-rustscript-esp32-s31.elf
5575
app/dist/esp32-blinky.vmbc
5676
app/dist/rustscript.partition.bin
5777
app/dist/flash_vmbc.py

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ required-features = ["host"]
1919
default = ["host"]
2020
host = ["dep:vm", "vm/runtime"]
2121
esp32c3 = ["dep:pd_vm_nostd"]
22+
esp32s31 = ["dep:pd_vm_nostd"]
2223
arduino = ["dep:pd_vm_nostd"]
24+
wifi = []
25+
bluetooth = []
2326

2427
[dependencies]
2528
pd_vm_nostd = { package = "pd-vm-nostd", git = "https://github.com/rustscript-lang/rustscript.git", rev = "ab04637a9b6192dd4f37b7e6abe4dde83f2fc710", version = "0.1.0", optional = true }

README.md

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ python -m esptool --chip esp32c3 write_flash 0x0 micro-rustscript-esp32-c3.facto
1919
The boot order is fixed:
2020

2121
1. `/rustscript/main.vmbc` on an SD card connected with CS on GPIO 7.
22-
2. The dedicated 64 KiB `rustscript` flash partition at `0x0b0000`.
22+
2. The dedicated 64 KiB `rustscript` flash partition at `0x110000`.
2323
3. The serial VMBC REPL at 115200 baud.
2424

2525
An absent, unreadable, or missing SD script automatically falls through to the flash partition.
@@ -36,6 +36,8 @@ use framework::gpio as gpio;
3636
use framework::i2c as i2c;
3737
use framework::mcu as mcu;
3838
use framework::serial as serial;
39+
use framework::wifi as wifi;
40+
use framework::bluetooth as bluetooth;
3941

4042
let ok: bool = gpio::configure(8, 1);
4143
let written: bool = gpio::digital_write(8, true);
@@ -49,6 +51,10 @@ i2c::close();
4951
mcu::delay_ms(100);
5052
let free_heap: int = mcu::free_heap();
5153
serial::write_line("ready");
54+
55+
let started: bool = wifi::connect("ssid", "password");
56+
let address: string = wifi::local_ip();
57+
let ble_ready: bool = bluetooth::enable();
5258
```
5359

5460
### GPIO
@@ -78,6 +84,18 @@ serial::write_line("ready");
7884
`flash_size`, `random`, `restart`, and `deep_sleep_us`. `serial` exports `write_line`, `available`,
7985
and `read_bytes`.
8086

87+
### Wi-Fi and Bluetooth LE
88+
89+
The `wifi` API exports `connect`, `disconnect`, `is_connected`, `rssi`, and `local_ip`. `connect`
90+
returns whether ESP-IDF accepted the asynchronous connection request; poll `is_connected` before
91+
using `rssi` or `local_ip`. The `bluetooth` API exports BLE-controller lifecycle operations:
92+
`enable`, `disable`, and `is_enabled`. Both use ESP-IDF APIs and are registered only on supported
93+
ESP targets.
94+
95+
`wifi` and `bluetooth` are independent Cargo/PlatformIO features. ESP release targets enable both
96+
by default through `custom_rust_features`; removing either feature also removes its ESP-IDF includes
97+
and RSS host exports. The host `arduino` target exports neither API.
98+
8199
The private host ABI lives in `firmware/host_framework.cpp`; the public RSS modules live under
82100
`programs/framework/`. This keeps script-facing APIs namespaced while allowing the VM to dispatch a
83101
compact static function table.
@@ -132,6 +150,8 @@ export PATH=/mnt/TEMP/platformio/bin:$PATH
132150

133151
pio run -e esp32-c3-devkitm-1
134152
pio run -e arduino
153+
ci/install-esp-idf-s31.sh
154+
pio run -e esp32s31
135155
.pio/build/arduino/program
136156
```
137157

@@ -144,19 +164,25 @@ Outputs:
144164
.pio/generated/esp32-blinky.vmbc
145165
.pio/generated/rustscript.partition.bin
146166
dist/micro-rustscript-esp32-c3.factory.bin
167+
dist/micro-rustscript-esp32-s31.factory.bin
147168
```
148169

149170
The factory image merges the ESP32 boot components, application, and default script partition. The
150171
release includes the factory image, ELF, VMBC, packed script partition, flash helpers, partition CSV,
151172
and SHA-256 checksums.
152173

174+
The `esp32s31` target uses pinned ESP-IDF master preview support. ESP-IDF source, Python environment,
175+
toolchains, caches, Rust target artifacts, generated files, and build output are all kept under
176+
`/mnt/TEMP`; only source and build configuration live in the repository.
177+
153178
The `arduino` environment links `pd-vm-nostd` through an Arduino-compatible GPIO, delay, serial,
154179
and allocator bridge. It runs the bridge and compiled VMBC program on the host before a board is
155180
connected. A successful simulation ends with `rss:status=0`.
156181

157182
## ESP32 image size
158183

159-
The ESP32 partition table uses a 640 KiB factory application slot and a 64 KiB VMBC slot. OTA data
184+
The ESP32 partition table uses a 1 MiB factory application slot and a 64 KiB VMBC slot. OTA data
160185
and SPIFFS partitions are omitted because this image is flashed directly and script updates use the
161-
dedicated VMBC partition. The measured factory image is 722,391 bytes, down from 2,164,183 bytes
162-
(66.62%), while retaining SD boot, the flash script, and the serial VMBC REPL.
186+
dedicated VMBC partition. With `wifi` and `bluetooth` enabled, the measured factory image is
187+
1,115,607 bytes, down from 2,164,183 bytes (48.45%), while retaining SD boot, the flash script,
188+
and the serial VMBC REPL.

ci/install-esp-idf-s31.sh

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
IDF_COMMIT=e88643bc619dff3c21b51705113bb488c9bc0990
5+
IDF_PATH=${ESP_IDF_PATH:-/mnt/TEMP/esp-idf}
6+
IDF_TOOLS_PATH=${IDF_TOOLS_PATH:-/mnt/TEMP/esp-idf-tools}
7+
8+
export IDF_TOOLS_PATH
9+
export GIT_CONFIG_GLOBAL=/dev/null
10+
unset IDF_PYTHON_ENV_PATH
11+
mkdir -p /mnt/TEMP "$IDF_TOOLS_PATH"
12+
13+
if [[ ! -d "$IDF_PATH/.git" ]]; then
14+
git clone --depth 1 --branch master \
15+
https://github.com/espressif/esp-idf.git "$IDF_PATH"
16+
fi
17+
18+
git -C "$IDF_PATH" fetch --depth 1 origin "$IDF_COMMIT"
19+
git -C "$IDF_PATH" checkout --detach "$IDF_COMMIT"
20+
for attempt in 1 2 3; do
21+
if git -C "$IDF_PATH" submodule update --init --recursive --depth 1; then
22+
break
23+
fi
24+
if [[ "$attempt" == 3 ]]; then
25+
exit 1
26+
fi
27+
sleep $((attempt * 5))
28+
done
29+
30+
"$IDF_PATH/install.sh" esp32s31
31+
printf 'ESP-IDF %s installed under %s\n' "$IDF_COMMIT" /mnt/TEMP

esp32s31/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
cmake_minimum_required(VERSION 3.16)
2+
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
3+
project(micro_rustscript_esp32s31)

esp32s31/main/CMakeLists.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
idf_component_register(
2+
SRCS "main.cpp"
3+
INCLUDE_DIRS "." "../../include" "$ENV{RUSTSCRIPT_GENERATED_DIR}"
4+
REQUIRES bt esp_driver_gpio esp_event esp_netif esp_timer esp_wifi nvs_flash spi_flash
5+
)
6+
7+
if(RUSTSCRIPT_FEATURE_WIFI)
8+
target_compile_definitions(${COMPONENT_LIB} PRIVATE RUSTSCRIPT_FEATURE_WIFI=1)
9+
endif()
10+
if(RUSTSCRIPT_FEATURE_BLUETOOTH)
11+
target_compile_definitions(${COMPONENT_LIB} PRIVATE RUSTSCRIPT_FEATURE_BLUETOOTH=1)
12+
endif()
13+
14+
add_prebuilt_library(rustscript_embedded "$ENV{RUSTSCRIPT_ARCHIVE}")
15+
target_link_libraries(${COMPONENT_LIB} PRIVATE rustscript_embedded)

0 commit comments

Comments
 (0)