Skip to main content

Built-in functions

warning

These are the low-level native boundary — flat and C-shaped because that is what a bytecode VM calls efficiently. package:moth already wraps them in ordinary Dart — OutputPin(38).toggle() — and hardware.md is the layer you should write against. See ADR-009.

Every function below is available to any moth program without an import.

Built-ins are resolved when the program loads, not when they are called. If your board doesn't provide one, you get a clear failure at startup — "this program needs 'i2cPing', which this board does not provide" — instead of a crash halfway through.

Output

print(value)

Prints a number, boolean, string, list or null, followed by a newline. On a board this goes to the serial log.

Timing

delay(ms)

Waits for ms milliseconds. In the simulator this advances the virtual clock instantly unless you pass --real-time.

delayMicroseconds(us)

Busy-waits for us microseconds.

millis()int

Milliseconds since the program started.

micros()int

Microseconds since the program started.

Digital I/O

pinOutput(pin)

Configures pin as an output. Required before digitalWrite.

pinInput(pin) / pinInputPullup(pin)

Configures pin as an input, optionally with the internal pull-up resistor enabled. A pulled-up pin reads true when nothing is pulling it down — which is why buttons usually read false when pressed.

digitalWrite(pin, value)

Sets an output pin. value is a real bool, not 1/0.

digitalRead(pin)bool

Reads an input pin.

Analog I/O

analogRead(pin)int

Reads the ADC on pin. Returns −1 if that pin has no ADC. On ESP32 this is ADC1 one-shot at 12 dB attenuation.

analogWrite(pin, duty)

PWM output, duty from 0 to 255 — hardware LEDC on ESP32, at 5 kHz. The LEDC block gives moth six PWM channels, shared between analogWrite and tone, allocated per pin on first use; a seventh pin is ignored with a warning in the board log.

tone(pin, hz) / noTone(pin)

Square wave at hz on pin, and off again.

Random

randomSeed(n) / random(max)int

Returns a value in 0..max-1. The generator is deterministic for a given seed, so tests can assert on the sequence.

I2C

i2cBegin(sda, scl)

Starts the I2C bus on those pins. Call once before the others.

i2cPing(addr)bool

True if a device acknowledges at that 7-bit address. This is what an I2C scanner is built from.

i2cWriteReg(addr, reg, value)bool

Writes one byte to one register. False if the device didn't acknowledge.

i2cReadReg(addr, reg)int

Reads one byte from one register. Returns −1 if the device didn't answer — check for it rather than assuming success.

i2cReadBytes(addr, reg, n)List<int>

Reads n bytes from consecutive registers starting at reg, in a single transaction — which is what you want for a sensor that spreads one reading across several registers, because reading them one at a time can catch it mid-update. Returns an empty list if the device didn't answer: every byte in a result is a legal value, so there is no −1 to spare as a sentinel. n is clamped to 1..64.

i2cWriteBytes(addr, reg, bytes)bool

Writes a List<int> to consecutive registers starting at reg, each item truncated to a byte. False if the device didn't acknowledge.

UART

uartBegin(port, tx, rx, baud)

Opens a hardware serial port. Port 0 is usually the USB console — prefer 1 or 2.

uartWrite(port, byte)

Sends one byte.

uartAvailable(port)int

How many bytes are waiting.

uartRead(port)int

Reads one byte, or −1 if nothing is waiting.

Storage

Named integers that outlive the program: NVS flash on a board, memory in the simulator. Keys are 1 to 15 characters — NVS's own limit, not one invented here.

prefsGetInt(key, fallback)int

The value stored under key, or fallback when there is none. A key longer than 15 characters could never have been stored, so it reads back as fallback too rather than failing.

prefsSetInt(key, value)bool

Stores value. False if the key is invalid or the store is full — worth checking on the writes you care about, because afterwards a save that failed looks exactly like one that never happened.

Servo

servoAttach(pin)

Configures pin for 50Hz servo PWM. Call once before writing a pulse.

servoMicroseconds(pin, us)

The pulse width that positions the horn. Clamped to 500..2500, so a value from a knob can be fed in directly instead of grinding the servo against its stop. Two servo channels exist on ESP32; a third servoAttach is ignored with a warning in the board log.

A servo is never told an angle — it is told a pulse width and holds whatever that means to it. package:moth's Servo(pin).write(degrees) maps 0..180 onto 1000..2000us, which is a convention, not a measurement.

Display

The display natives are the backend contract — the flat, numeric boundary the widget layer in package:moth is built on. You will normally never call them: write widgets (Container, Text, Slider, …) and let runApp/pumpFrame drive this layer for you. They are listed here because "every function below is available" should stay true.

FunctionWhat it does
uiWidth() / uiHeight()display size in pixels
uiRoot()the root node, owned by the backend
uiCreate(kind)new node — 0 box, 1 label, 2 image, 3 slider, 4 switch, 5 arc
uiDestroy(node)frees a node
uiAttach(parent, child, index)inserts a child; index −1 appends
uiDetach(node)removes a node from its parent
uiSetNum(node, prop, value)sets a float property
uiSetInt(node, prop, value)sets an integer property — colours, enums
uiSetText(node, prop, text)sets a text property
uiAnimate(node, prop, from, to, ms, easing)starts a native animation; returns its id, 0 on failure
uiTick(dtMs)advances animations
uiCommit()lays out, paints, presents; true when the frame repainted
uiPoll()next event as node * 8 + kind, −1 when empty
uiEventValue()the value carried by the last polled event
uiFrameOf(node, which)a node's laid-out frame; which 0..3 = x, y, w, h
uiSafeArea(which)the always-visible rectangle — the inscribed square on a round panel

Writing your own helpers

Anything not listed here you can often just write in Dart. Arduino's map and constrain are macros in C; here they are ordinary functions:

int constrain(int v, int low, int high) {
if (v < low) return low;
if (v > high) return high;
return v;
}