Skip to content

Commit 372dba4

Browse files
committed
docs: expand target and framework API reference
1 parent 9f7cab8 commit 372dba4

2 files changed

Lines changed: 241 additions & 59 deletions

File tree

README.md

Lines changed: 60 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22

33
[![rustscript-embedded on crates.io](https://img.shields.io/crates/v/rustscript-embedded.svg)](https://crates.io/crates/rustscript-embedded)
44

5-
A directly flashable RustScript runtime for ESP32-C3. One image contains the bootloader,
6-
partition table, Arduino-ESP32 runtime, `pd-vm-nostd`, framework host API, and a default VMBC
7-
script partition.
5+
A portable RustScript VMBC runtime with release targets for ESP32-C3, ESP32-S31 preview hardware,
6+
and a native Arduino API simulator. Each ESP factory image contains its bootloader, partition table,
7+
platform runtime, `pd-vm-nostd`, framework host bridge, and a default VMBC program.
88

9-
## Flash the complete image
9+
## Flash complete images
10+
11+
### ESP32-C3
1012

1113
Download `micro-rustscript-esp32-c3.factory.bin` from the latest GitHub Release and flash it at
1214
offset zero:
@@ -16,7 +18,7 @@ python -m esptool --chip esp32c3 erase_flash
1618
python -m esptool --chip esp32c3 write_flash 0x0 micro-rustscript-esp32-c3.factory.bin
1719
```
1820

19-
The boot order is fixed:
21+
The ESP32-C3 boot order is fixed:
2022

2123
1. `/rustscript/main.vmbc` on an SD card connected with CS on GPIO 7.
2224
2. The dedicated 64 KiB `rustscript` flash partition at `0x110000`.
@@ -26,18 +28,49 @@ An absent, unreadable, or missing SD script automatically falls through to the f
2628
The release factory image already contains `esp32-blinky.vmbc` in that partition.
2729
`RUSTSCRIPT_SD_CS` and `RUSTSCRIPT_SD_PATH` can be overridden with PlatformIO build flags.
2830

31+
### ESP32-S31 preview
32+
33+
Download `micro-rustscript-esp32-s31.factory.bin` and flash the merged image at offset zero:
34+
35+
```bash
36+
python -m esptool --chip esp32s31 write_flash 0x0 micro-rustscript-esp32-s31.factory.bin
37+
```
38+
39+
The S31 preview image currently embeds the default VMBC program into the application at build time.
40+
Its runtime does not yet implement the C3 SD-card lookup, replaceable flash VMBC partition, or serial
41+
VMBC REPL. The release also includes the S31 ELF for debugging.
42+
43+
## Targets and source layout
44+
45+
| PlatformIO environment | Purpose | Platform integration | Main source |
46+
|---|---|---|---|
47+
| `esp32-c3-devkitm-1` | Flashable ESP32-C3 firmware | Official PlatformIO board plus Arduino-ESP32 and selected ESP-IDF APIs | shared `firmware/` sources |
48+
| `esp32s31` | Flashable ESP32-S31 preview firmware | Pinned ESP-IDF master preview toolchain | `esp32s31/` CMake project |
49+
| `arduino` | Native host simulation of a small Arduino API subset | PlatformIO `native` plus `firmware/simulator/` | `firmware/arduino/main.cpp` |
50+
51+
Only ESP32-S31 has a top-level target directory because current PlatformIO releases do not provide
52+
an ESP32-S31 board definition or framework package. Its directory supplies the ESP-IDF project
53+
files that PlatformIO cannot generate: `CMakeLists.txt`, `sdkconfig.defaults`, partition layout, and
54+
the pure ESP-IDF application entry point. ESP32-C3 can use PlatformIO's standard
55+
`esp32-c3-devkitm-1` board and therefore shares the normal `firmware/` project. The `arduino` target
56+
is a native simulator rather than separate hardware; its target-specific source already lives under
57+
`firmware/arduino/` and reuses the simulator compatibility layer.
58+
59+
All three are still first-class PlatformIO and release targets. The directory shape reflects their
60+
different build systems, not a difference in release status.
61+
2962
## Framework API from RSS
3063

31-
Hardware functions are exposed through RSS modules, keeping board ABI names private. Import only the
32-
capabilities a script uses:
64+
Hardware functions are exposed through built-in RSS modules, keeping the C host ABI private. Import
65+
only the capabilities a script uses:
3366

3467
```rust
35-
use framework::gpio as gpio;
36-
use framework::i2c as i2c;
37-
use framework::mcu as mcu;
38-
use framework::serial as serial;
39-
use framework::wifi as wifi;
40-
use framework::bluetooth as bluetooth;
68+
use gpio;
69+
use i2c;
70+
use mcu;
71+
use serial;
72+
use wifi;
73+
use bluetooth;
4174

4275
let ok: bool = gpio::configure(8, 1);
4376
let written: bool = gpio::digital_write(8, true);
@@ -57,48 +90,14 @@ let address: string = wifi::local_ip();
5790
let ble_ready: bool = bluetooth::enable();
5891
```
5992

60-
### GPIO
61-
62-
| Function | Result |
63-
|---|---|
64-
| `gpio::configure(pin, mode)` | `bool`; modes: input `0`, output `1`, pull-up `2`, pull-down `3`, open-drain `4` |
65-
| `gpio::digital_write(pin, high)` | `bool` |
66-
| `gpio::digital_read(pin)` | `bool` |
67-
| `gpio::analog_read(pin)` | ADC value as `int` |
68-
| `gpio::pwm_write(pin, duty, frequency, resolution_bits)` | `bool`; six channels, 1–16 bits |
69-
70-
### I2C
71-
72-
| Function | Result |
73-
|---|---|
74-
| `i2c::open(sda, scl, frequency)` | `bool` |
75-
| `i2c::close()` | `null` |
76-
| `i2c::transmit(address, data)` | Wire status as `int` |
77-
| `i2c::transmit_register(address, register, data)` | Wire status as `int` |
78-
| `i2c::receive(address, length)` | Up to 255 bytes |
79-
| `i2c::receive_register(address, register, length)` | Up to 255 bytes |
80-
81-
### MCU and serial
82-
83-
`mcu` exports `delay_ms`, `delay_us`, `millis`, `micros`, `cpu_frequency_mhz`, `free_heap`,
84-
`flash_size`, `random`, `restart`, and `deep_sleep_us`. `serial` exports `write_line`, `available`,
85-
and `read_bytes`.
86-
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.
93+
API coverage is target-dependent. ESP32-C3 provides GPIO, ADC, PWM, I2C, MCU, serial, Wi-Fi, and BLE
94+
controller functions. ESP32-S31 currently provides digital GPIO, core MCU timing/status, serial
95+
output, Wi-Fi, and BLE controller functions. The Arduino host target provides a small GPIO,
96+
`delay_ms`, and serial-output simulation subset.
9897

99-
The private host ABI lives in `firmware/host_framework.cpp`; the public RSS modules live under
100-
`programs/framework/`. This keeps script-facing APIs namespaced while allowing the VM to dispatch a
101-
compact static function table.
98+
See **[Framework API reference](docs/framework-api.md)** for the complete support matrix, RSS
99+
signatures, argument limits, return behavior, asynchronous Wi-Fi semantics, BLE scope, and C host
100+
callback contract.
102101

103102
## Replace only the VMBC partition
104103

@@ -161,15 +160,17 @@ Outputs:
161160
.pio/build/esp32-c3-devkitm-1/firmware.elf
162161
.pio/build/esp32-c3-devkitm-1/firmware.bin
163162
.pio/build/arduino/program
163+
.pio/build/esp32s31/program
164164
.pio/generated/esp32-blinky.vmbc
165165
.pio/generated/rustscript.partition.bin
166166
dist/micro-rustscript-esp32-c3.factory.bin
167167
dist/micro-rustscript-esp32-s31.factory.bin
168+
/mnt/TEMP/micro-rustscript-esp32s31/build/micro_rustscript_esp32s31.elf
168169
```
169170

170-
The factory image merges the ESP32 boot components, application, and default script partition. The
171-
release includes the factory image, ELF, VMBC, packed script partition, flash helpers, partition CSV,
172-
and SHA-256 checksums.
171+
Each ESP factory image merges its bootloader, partition table, and application. The C3 factory image
172+
also includes the packed default script partition. The release includes both factory images, both
173+
ELFs, the Arduino host executable, VMBC assets and helpers for C3, and SHA-256 checksums.
173174

174175
The `esp32s31` target uses pinned ESP-IDF master preview support. ESP-IDF source, Python environment,
175176
toolchains, caches, Rust target artifacts, generated files, and build output are all kept under
@@ -179,9 +180,9 @@ The `arduino` environment links `pd-vm-nostd` through an Arduino-compatible GPIO
179180
and allocator bridge. It runs the bridge and compiled VMBC program on the host before a board is
180181
connected. A successful simulation ends with `rss:status=0`.
181182

182-
## ESP32 image size
183+
## ESP32-C3 image size
183184

184-
The ESP32 partition table uses a 1 MiB factory application slot and a 64 KiB VMBC slot. OTA data
185+
The ESP32-C3 partition table uses a 1 MiB factory application slot and a 64 KiB VMBC slot. OTA data
185186
and SPIFFS partitions are omitted because this image is flashed directly and script updates use the
186187
dedicated VMBC partition. With `wifi` and `bluetooth` enabled, the measured factory image is
187188
1,115,607 bytes, down from 2,164,183 bytes (48.45%), while retaining SD boot, the flash script,

docs/framework-api.md

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
# RustScript framework API
2+
3+
The VM calls platform functions through static host-import names such as `gpio::digital_write`.
4+
RSS programs import the built-in modules they use:
5+
6+
```rust
7+
use gpio;
8+
use mcu;
9+
use serial;
10+
use wifi;
11+
use bluetooth;
12+
13+
let ready: bool = gpio::configure(8, 1);
14+
let written: bool = gpio::digital_write(8, ready);
15+
mcu::delay_ms(100);
16+
serial::write_line("ready");
17+
```
18+
19+
The compiler knows the module declarations, while each firmware target decides which imports it can
20+
dispatch. Calling a function that is absent on the selected target fails host dispatch. Use the
21+
support matrix below when writing a portable program.
22+
23+
## Target support
24+
25+
| Module or function | ESP32-C3 | ESP32-S31 preview | Arduino host simulator |
26+
|---|:---:|:---:|:---:|
27+
| `gpio::configure` | yes | yes | yes |
28+
| `gpio::digital_write` | yes | yes | yes |
29+
| `gpio::digital_read` | yes | yes | yes |
30+
| `gpio::analog_read` | yes |||
31+
| `gpio::pwm_write` | yes |||
32+
| all `i2c` functions | yes |||
33+
| `mcu::delay_ms` | yes | yes | yes |
34+
| `mcu::millis`, `mcu::micros` | yes | yes ||
35+
| `mcu::free_heap`, `mcu::random` | yes | yes ||
36+
| `mcu::delay_us`, `mcu::cpu_frequency_mhz`, `mcu::flash_size` | yes |||
37+
| `mcu::restart`, `mcu::deep_sleep_us` | yes |||
38+
| `serial::write_line` | yes | yes | yes |
39+
| `serial::available`, `serial::read_bytes` | yes |||
40+
| all `wifi` functions | feature-gated | feature-gated ||
41+
| all `bluetooth` functions | feature-gated | feature-gated ||
42+
43+
The release ESP targets enable both `wifi` and `bluetooth`. They are independent Cargo and
44+
PlatformIO features. Removing one from `custom_rust_features` removes that module's host exports
45+
from the firmware. The Arduino host simulator never registers either module.
46+
47+
## Return and error behavior
48+
49+
The signatures below are RSS signatures. Argument type, arity, and range checks happen in the host
50+
bridge. A rejected call returns a host-dispatch error to the VM. A `bool` result reports whether the
51+
underlying platform operation was accepted. Calls documented as `null` are commands whose success
52+
is represented by normal completion.
53+
54+
## GPIO
55+
56+
```rust
57+
use gpio;
58+
59+
gpio::configure(pin: int, mode: int) -> bool
60+
gpio::digital_write(pin: int, high: bool) -> bool
61+
gpio::digital_read(pin: int) -> bool
62+
gpio::analog_read(pin: int) -> int
63+
gpio::pwm_write(pin: int, duty: int, frequency: int, resolution_bits: int) -> bool
64+
```
65+
66+
`pin` must be inside the SoC GPIO range. ESP32-C3 modes are `0` input, `1` output, `2` input
67+
pull-up, `3` input pull-down, and `4` open-drain output. ESP32-S31 currently accepts modes `0` and
68+
`1`. The simulator forwards the integer mode to its Arduino compatibility layer.
69+
70+
ESP32-C3 PWM supports six simultaneously assigned pins. Frequency is `1..40,000,000` Hz,
71+
resolution is `1..16` bits, and duty must fit the selected resolution.
72+
73+
## I2C
74+
75+
ESP32-C3 only:
76+
77+
```rust
78+
use i2c;
79+
80+
i2c::open(sda: int, scl: int, frequency: int) -> bool
81+
i2c::close() -> null
82+
i2c::transmit(address: int, data: bytes) -> int
83+
i2c::transmit_register(address: int, register: int, data: bytes) -> int
84+
i2c::receive(address: int, length: int) -> bytes
85+
i2c::receive_register(address: int, register: int, length: int) -> bytes
86+
```
87+
88+
Addresses must be 7-bit device addresses in `0x08..0x77`. Frequency must be
89+
`1,000..5,000,000` Hz. Register values are `0..255`; payloads and reads are limited to 255 bytes.
90+
Transmit functions return the Arduino Wire status code. A failed register-address phase returns an
91+
empty byte sequence.
92+
93+
## MCU
94+
95+
```rust
96+
use mcu;
97+
98+
mcu::delay_ms(duration: int) -> null
99+
mcu::delay_us(duration: int) -> null
100+
mcu::millis() -> int
101+
mcu::micros() -> int
102+
mcu::cpu_frequency_mhz() -> int
103+
mcu::free_heap() -> int
104+
mcu::flash_size() -> int
105+
mcu::random() -> int
106+
mcu::restart() -> null
107+
mcu::deep_sleep_us(duration: int) -> null
108+
```
109+
110+
On ESP32-C3, `delay_ms` accepts `0..60,000`, `delay_us` accepts `0..1,000,000`, and deep sleep
111+
accepts `1..86,400,000,000` microseconds. ESP32-S31 `delay_ms` accepts a non-negative 32-bit
112+
millisecond value. `millis` and `micros` are monotonic uptime counters. `restart` and
113+
`deep_sleep_us` do not return after the platform action succeeds.
114+
115+
## Serial
116+
117+
```rust
118+
use serial;
119+
120+
serial::write_line(value: string) -> null
121+
serial::available() -> int
122+
serial::read_bytes(maximum: int) -> bytes
123+
```
124+
125+
`write_line` appends a newline. ESP32-C3 input uses the 115200-baud primary serial port;
126+
`read_bytes` is non-blocking and returns at most 255 currently buffered bytes. ESP32-S31 and the
127+
simulator currently expose output only.
128+
129+
## Wi-Fi
130+
131+
Available on ESP targets when the `wifi` feature is enabled:
132+
133+
```rust
134+
use wifi;
135+
136+
wifi::connect(ssid: string, password: string) -> bool
137+
wifi::disconnect() -> bool
138+
wifi::is_connected() -> bool
139+
wifi::rssi() -> int
140+
wifi::local_ip() -> string
141+
```
142+
143+
SSID length is `1..32` bytes; password length is `0..64` bytes. An empty password requests an open
144+
network. `connect` initializes the ESP-IDF station stack and returns after ESP-IDF accepts or rejects
145+
the asynchronous connection request. Poll `is_connected` before using connection-dependent data.
146+
`rssi` returns `-127` when no access point is available. `local_ip` returns an empty string until a
147+
non-zero station address exists. `disconnect` returns `false` when Wi-Fi was never initialized or
148+
ESP-IDF rejects the request.
149+
150+
## Bluetooth LE controller
151+
152+
Available on ESP targets when the `bluetooth` feature is enabled:
153+
154+
```rust
155+
use bluetooth;
156+
157+
bluetooth::enable() -> bool
158+
bluetooth::disable() -> bool
159+
bluetooth::is_enabled() -> bool
160+
```
161+
162+
This API controls the ESP-IDF BLE controller lifecycle only. `enable` initializes the controller if
163+
needed and enables BLE mode. `disable` disables and deinitializes it. Both operations are idempotent.
164+
No GAP, GATT, advertising, scanning, pairing, or characteristic API is exposed yet.
165+
166+
## C host ABI
167+
168+
The Rust static library exports `rustscript_run_vmbc` and value types from
169+
`include/rustscript_embedded.h`. Platform bridges provide a callback with this logical contract:
170+
171+
```text
172+
(context, import_name_bytes, arguments, result) -> status
173+
```
174+
175+
A callback status of `-1` rejects the call, `0` completes a command with `null`, and `1` returns the
176+
value written to `result`. String and byte results reference bridge-owned storage and are consumed by
177+
the VM during the call. Platform implementations are located in:
178+
179+
- `firmware/host_framework.cpp` — ESP32-C3 Arduino/ESP-IDF bridge.
180+
- `esp32s31/main/main.cpp` — ESP32-S31 pure ESP-IDF bridge.
181+
- `firmware/arduino/main.cpp` — native Arduino compatibility simulator.

0 commit comments

Comments
 (0)