Scripting guide
EMWaver scripts are local JavaScript programs. Scripts use .js files and can include JSX-style UI syntax for native panels, extensionless imports such as "emw-ui", and hardware modules such as emw-gpio, emw-spi, and emw-sampler.
How scripts run
- The app loads the visible runtime libraries from the bundled script assets.
- Imports are resolved from EMWaver modules such as
emw-ui,emw-jsx,emw-gpio, andemw-spi. - JSX-style syntax is transpiled into native EMWaver UI nodes.
- Your script renders a native panel with
render(<App />). - Callbacks such as
onTap,onChange, andonViewportChangehandle user events and then re-render.
Hardware calls are synchronous from the script authoring point of view: a GPIO, SPI, I2C, UART, ADC, PWM, or sampler call returns after the local app/board path responds or throws.
Minimal JSX script
import { JSX, render } from "emw-jsx";
import { Column, Text, Button } from "emw-ui";
let count = 0;
function increment() {
count += 1;
rerender();
}
function reset() {
count = 0;
rerender();
}
function App() {
return (
<Column padding={16} spacing={12}>
<Text font="title2" fontWeight="semibold">Hello</Text>
<Text>Count: {count}</Text>
<Button onTap={increment}>Increment</Button>
<Button onTap={reset}>Reset</Button>
</Column>
);
}
function rerender() {
render(<App />);
}
rerender();Script structure
- Imports: bring in the UI renderer, JSX factory, components, and hardware modules.
- State: keep state in normal JavaScript variables.
- Actions: callbacks mutate state, perform device work, then re-render.
- App component: returns a JSX-style tree made from EMWaver UI components.
- Render function: one small
render(<App />)wrapper updates the native panel.
Board-aware GPIO example
import { JSX, render } from "emw-jsx";
import { Column, Text, Button, Picker } from "emw-ui";
import { pin, gpio } from "emw-gpio";
function boardType() {
try { return device.boardType(); } catch (e) { return "stm32f042"; }
}
const board = boardType();
const options = board === "esp32s3"
? [{ label: "GPIO4", value: "4" }, { label: "GPIO37", value: "37" }]
: [{ label: "A0", value: "0" }, { label: "A1", value: "1" }];
let selected = options[0].value;
let high = false;
function target() {
const n = Number(selected);
return board === "esp32s3" ? pin({ gpio: n }) : pin({ port: "A", number: n });
}
function toggle() {
high = !high;
gpio.mode(target(), "output");
gpio.write(target(), high);
rerender();
}
function App() {
return (
<Column padding={16} spacing={12}>
<Text font="title2" fontWeight="semibold">GPIO</Text>
<Text font="caption">Detected: {board}</Text>
<Picker
style="menu"
selected={selected}
options={options}
onChange={(value) => { selected = String(value); rerender(); }}
/>
<Button onTap={toggle}>{high ? "Write LOW" : "Write HIGH"}</Button>
</Column>
);
}
function rerender() { render(<App />); }
rerender();Bundled modules
| Module | Exports | Use |
|---|---|---|
emw-jsx | JSX, h, render | JSX transform target and UI rendering. |
emw-ui | UI components | Native UI tree components such as Column, Button, and Plot. |
emw-gpio | pin, gpio | Pin encoding, GPIO mode/read/write. |
emw-spi | spi | SPI transfers with optional chip select. |
emw-i2c | i2c | I2C open/read/write/write-then-read flows. |
emw-uart | uart | UART open/read/write flows. |
emw-adc | adc | ADC pin/internal-source reads and resolution setting. |
emw-pwm | pwm | PWM writes and resolution setting. |
emw-fs | FS | App-local file helpers. |
emw-sampler | Sampler, SamplerSignals | Signal capture, buffers, replay, and saved signal access. |
Built-in scripts
The app bundles local examples as JavaScript source. They are both tools and reference implementations.
| Script | What it demonstrates |
|---|---|
hello.js | JSX/import smoke test with buttons and state. |
blink.js | Board-aware pin selection, timer-based output, GPIO module use. |
sampler.js | Signal capture, plot viewport callbacks, retransmit, local save/load. |
cc1101.js | CC1101 radio register control, presets, SPI transfers, logs, grids, cards, tiles. |
rfid.js | MFRC522 probe/UID/read/write workflows over SPI and GPIO reset/IRQ pins. |
rfm69.js | Profile-driven RFM69/RFM69HW radio control and RSSI/status UI. |
Timing
delay(500); // blocking sleep (ms)
sleep(100); // alias for delay
millis(); // milliseconds since the script engine started
const timer = every(1000, () => {
// periodic work; return false to stop, or call timer.stop()
rerender();
});
timer.stop();Use rendered panels for user interaction. Agent hardware automation should use named hardware primitives such as SPI transfers, GPIO reads/writes, analog reads, and module probes rather than screen-scraping UI state.
Next
- UI widgets for every JSX component and prop shape.
- Device API for GPIO, buses, sampler, files, and device info.
