Skip to main content

GPIO Helpers

Drive general-purpose I/O pins from Lua. GPIO is served by two transports: the CH347 USB bridge and the unified Linux Peripherals transport (a /dev/gpiochipN on an embedded board such as a Raspberry Pi). It is driven only from Lua — there is no message-input form. Each helper builds a request message and sends it on the configured connection. All helpers return true once the request is queued, or raise a Lua runtime error on invalid parameters.

Pins are addressed by line number. On a CH347 that is the pin index 0–7. On the Linux transport it is the line offset on the configured gpiochip — on a Raspberry Pi those offsets are the BCM numbers (e.g. 25 for GPIO 25). A backend with a fixed pin count (the CH347) rejects out-of-range lines.

All helpers accept an optional trailing connection_id (default: 0) selecting the target connection, followed by an optional delay_ms that schedules the request delay_ms milliseconds in the future instead of sending it immediately (default: 0 — send now). This is handy for inserting settling time between operations, e.g. driving a pin high, then reading an input a few milliseconds later.

Request Functions​

gpio_write(line, level, connection_id, delay_ms) → boolean​

Drive a single line as an output to the given level. This is the convenient single-line form of gpio_set.

  • line (number) - Line number (required)
  • level (number|boolean) - Output level: 0/false = low, non-zero/true = high (required)
  • connection_id (number, optional) - Target connection (default: 0)
  • delay_ms (number, optional) - Delay delivery by this many milliseconds (default: 0)

gpio_set(ops, connection_id, delay_ms) → boolean​

Apply a batch of per-line updates at once. ops is a table (array) of entries, each a table with these fields:

  • line (number) - Line number (required)
  • output (boolean, optional) - true configures the line as an output (default), false as an input
  • level (boolean|number, optional) - For an output, the level to drive: true/non-zero = high (default false/low)

For example, gpio_set({ { line = 24, output = true, level = true }, { line = 25, output = false } }) drives line 24 high and configures line 25 as an input.

gpio_get(lines, connection_id, delay_ms) → boolean​

Read the level of one or more lines. lines is either a single line number or a table (array) of line numbers. The result arrives as an RX message in on_receive() (see below).

  • lines (number | table) - A line number, or an array of line numbers (required)
  • connection_id (number, optional) - Target connection (default: 0)
  • delay_ms (number, optional) - Delay delivery by this many milliseconds (default: 0)

Handling Responses​

Read results arrive as ordinary RX messages in on_receive(). Use message:get_metadata("gpio_op") to identify the result type. Set confirmations and errors are emitted as engine events, not RX messages.

gpio_op metadataMessage kindPayload
get_responseRXcount, then line:u32, value:u8 per line; each level also in gpio_line_<n>
set_responseeventgpio_set event; the applied batch is echoed in the payload
erroreventgpio_error event; the error value holds the message

In a get_response, the simplest way to read a line's level is the per-line metadata gpio_line_<n> — e.g. the level of line 25 is message:get_metadata("gpio_line_25"), which returns the integer 0 or 1.

local LED = 25   -- gpiochip line offset (BCM 25 on a Raspberry Pi)
local on = false

function on_timer(now_ms)
on = not on
gpio_write(LED, on)
end

Example: read a button on line 24​

local BTN = 24   -- wired as an input

function on_start()
gpio_set({ { line = BTN, output = false } }) -- configure as input
end

function on_timer(now_ms)
gpio_get(BTN) -- poll the line
end

function on_receive()
if message:get_metadata("gpio_op") ~= "get_response" then return false end

local pressed = message:get_metadata("gpio_line_" .. BTN) == 1
message:add_int_value("button", pressed and 1 or 0)
return true
end