Skip to main content

GPIO API Reference

The GPIO (General Purpose Input/Output) API provides access to 32 programmable I/O pins that can be configured for digital or analog operations. Each pin supports voltages from -25V to +25V for inputs and 0 to 24V for outputs.

Accessing GPIO​

const gpio = tester.gpio;

GPIO Module Methods​

reset()​

Resets all GPIO pins to their default configuration.

await tester.gpio.reset();

Returns: Promise<void> / None / Result<(), At1000Error>


digital(io)​

Access a specific GPIO pin for digital operations.

const pin = tester.gpio.digital(0);

Parameters:

  • io (number / int / usize): GPIO pin number (0-31)

Returns: DigitalIO instance / Result<DigitalIo, At1000Error> in Rust


analog(io)​

Access a specific GPIO pin for analog operations.

const pin = tester.gpio.analog(0);

Parameters:

  • io (number / int / usize): GPIO pin number (0-31)

Returns: AnalogIO instance / Result<AnalogIo, At1000Error> in Rust


pwm(io)​

Access a PWM-capable pin. IO 17 and 21 measure, IO 18 and 22 generate. See PWM measurement and generation.

const pwm = tester.gpio.pwm(18);

Parameters:

  • io (number / int / usize): GPIO pin number. Only 17, 18, 21 and 22 support PWM; the device rejects the others when the handle is used.

Returns: PwmIO instance / Result<PwmIo, At1000Error> in Rust


hold()​

Holds (freezes) the current state of all GPIO pins. This allows buffering multiple write commands before applying them simultaneously.

await tester.gpio.hold();

Returns: Promise<SyncConfiguration> / SyncConfiguration / Result<SyncConfiguration, At1000Error> - Configuration with action: "hold"

note

Prevents external changes to GPIO states until release() is called. Digital and analog writes issued between hold() and release() are buffered on the device and applied together on release.


release()​

Releases the outputs, applying all buffered writes simultaneously. Releasing also switches the device to sync-slave mode: its outputs then follow the SYNC-IN line, so an external master's hold freezes them (see Output synchronization).

await tester.gpio.release();

Returns: Promise<SyncConfiguration> / SyncConfiguration / Result<SyncConfiguration, At1000Error> - Configuration with action: "release"


read_config(io)​

Reads back the current configuration of a specific I/O pin.

const config = await tester.gpio.read_config(0);

Parameters:

  • io (number / int / usize): GPIO pin number (0-31)

Returns: Promise<GpioConfiguration> / GpioConfiguration / Result<GpioConfiguration, At1000Error> - The pin's current configuration


read_sync()​

Reads the current synchronization hold state. Returns { hold_state: "held" } while outputs are frozen and { hold_state: "released" } otherwise.

const state = await tester.gpio.read_sync();

Returns: Promise<SyncState> / SyncState / Result<SyncState, At1000Error> - The current synchronization hold state

Type: SyncState = { hold_state: "held" | "released" }


sequence()​

Creates a builder for a list of GPIO commands the device runs back to back in one request. See GPIO command sequences for the guide and GpioSequence below for every method.

const sequence = tester.gpio.sequence();

Returns: GpioSequence / GpioSequence / GpioSequence - An empty builder, which talks to the device only on run()

note

The builder is immutable in JavaScript and Python: every call returns a new builder and leaves the receiver alone. In Rust it is consuming: every call takes self and returns Result<Self, At1000Error>, so a whole chain composes with ?.


DigitalIO Class​

Input thresholds may be equal or in either order. If both input-state comparisons match, the low-threshold comparison takes precedence and reads false. A partial REST PATCH retains omitted thresholds. The typed SDK configure_input method requires both vil and vih.

configure_input(config)​

Configures the pin as a digital input with custom thresholds.

await pin.configure_input({
vil: 0.8, // Input low threshold
vih: 2.0 // Input high threshold
});

Parameters:

  • config (PartialDigitalInputConfiguration / &DigitalInputConfig):
    • vil (number / float / f64, required): Voltage input low threshold ([-25, 25] V, inclusive)
    • vih (number / float / f64, required): Voltage input high threshold ([-25, 25] V, inclusive)

Returns: Promise<DigitalInputConfiguration> / DigitalInputConfiguration / Result<GpioConfiguration, At1000Error> - Full configuration including mode and direction

Exceptions:

  • Throws validation error if vil or vih is outside the inclusive range [-25, 25] V

configure_output(config)​

Configures the pin as a digital output with custom voltage levels and thresholds.

await pin.configure_output({
value: true, // Initial state
vol: 0.0, // Output low voltage
voh: 3.3, // Output high voltage
vil: 0.8, // Optional input low threshold
vih: 2.0 // Optional input high threshold
});

Parameters:

  • config (PartialDigitalOutputConfiguration / &DigitalOutputConfig):
    • value (boolean | number / bool | int / bool, required): Initial output state (true/1 = high, false/0 = low)
    • vol (number / float / f64, required): Voltage output low level (0 to 24V)
    • voh (number / float / f64, required): Voltage output high level (0 to 24V)
    • vil (number / float / Option<f64>, optional): Voltage input low threshold ([-25, 25] V, inclusive)
    • vih (number / float / Option<f64>, optional): Voltage input high threshold ([-25, 25] V, inclusive)

Returns: Promise<DigitalOutputConfiguration> / DigitalOutputConfiguration / Result<GpioConfiguration, At1000Error> - Full configuration

Exceptions:

  • Throws validation error if vol or voh is outside the range [0, 24]
  • Throws validation error if vil or vih is outside the inclusive range [-25, 25] V
note

When vil and vih are omitted, they are automatically deduced from the given voh and vol parameters.


configure_open_drain(config)​

Configures the pin as an open-drain output (useful for I2C, 1-Wire, etc.).

await pin.configure_open_drain({
value: true,
vil: 0.8,
vih: 2.0
});

Parameters:

  • config (PartialOpenDrainConfiguration / &OpenDrainConfig):
    • value (boolean | number / bool | int / bool, required): Initial state (true = floating/high-Z, false = low)
    • vil (number / float / f64, required): Voltage input low threshold ([-25, 25] V, inclusive)
    • vih (number / float / f64, required): Voltage input high threshold ([-25, 25] V, inclusive)

Returns: Promise<OpenDrainConfiguration> / OpenDrainConfiguration / Result<GpioConfiguration, At1000Error> - Full configuration

Exceptions:

  • Throws validation error if vil or vih is outside the inclusive range [-25, 25] V

read()​

Reads the current logical state of the pin.

const state = await pin.read();
console.log("Pin is", state ? "HIGH" : "LOW");

Returns: Promise<boolean> / bool / Result<bool, At1000Error> - true for HIGH, false for LOW


write(value)​

Writes a logical value to the pin (must be configured as output).

await pin.write(true); // Set HIGH
await pin.write(false); // Set LOW
await pin.write(1); // Set HIGH (numeric)
await pin.write(0); // Set LOW (numeric)

Parameters:

  • value (boolean | number / bool | int / bool): Value to write (true/1 = HIGH, false/0 = LOW)

Returns: Promise<boolean> / bool / Result<bool, At1000Error> - The written value as boolean


AnalogIO Class​

configure_input()​

Configures the pin as an analog input for voltage measurement.

await pin.configure_input();

Returns: Promise<AnalogInputConfiguration> / AnalogInputConfiguration / Result<GpioConfiguration, At1000Error> - Configuration with mode "analog" and direction "input"


configure_output(value)​

Configures the pin as an analog output and sets the initial voltage.

await pin.configure_output(3.3); // Set to 3.3V

Parameters:

  • value (number / float / f64): Initial output voltage (0 to 24V)

Returns: Promise<AnalogOutputConfiguration> / AnalogOutputConfiguration / Result<GpioConfiguration, At1000Error> - Full configuration

Exceptions:

  • Throws validation error if value is outside the range [0, 24]

read()​

Reads the current analog voltage at the pin.

const voltage = await pin.read();
console.log("Voltage:", voltage, "V");

Returns: Promise<number> / float / Result<f64, At1000Error> - Measured voltage in volts


write(value)​

Sets the analog output voltage (must be configured as analog output).

await pin.write(3.3); // Set to 3.3V
await pin.write(5.0); // Set to 5.0V
await pin.write(12.5); // Set to 12.5V

Parameters:

  • value (number / float / f64): Voltage to output (0 to 24V)

Returns: Promise<number> / float / Result<f64, At1000Error> - The set voltage

Exceptions:

  • Throws validation error if value is outside the range [0, 24]

PwmIO Class​

PWM measurement on IO 17 and 21, square-wave generation on IO 18 and 22. Enabling PWM fails with CONFIGURATION_CONFLICT while I2C, SPI, UART or the other PWM pin of the same channel is enabled, and with UNSAFE_PIN_VOLTAGE if the pin reads below −0.5 V or above vcc + 0.5 V. Device errors surface as an ApiError carrying the code in JavaScript and Python, and as At1000Error::Api(err) with err.code in Rust. See PWM measurement and generation for the pin roles, channel sharing and timing details.

configure_input(options?)​

Enables PWM measurement on an input pin (IO 17 or 21).

const pwm = tester.gpio.pwm(17);
await pwm.configure_input({ vcc: 3.3 });

Parameters:

  • options (PwmInputOptions, optional / keyword arguments / &PwmInputConfig):
    • vcc (number / float / Option<f64>, optional): Highest voltage the pin accepts, [1.8, 3.3] V, inclusive. When omitted, the device keeps its current setting. The input thresholds stay at about 0.8–1.35 V whatever vcc is.

Returns: Promise<PwmConfig> / PwmConfig / Result<PwmConfig, At1000Error>

Exceptions:

  • Throws validation error if vcc is outside [1.8, 3.3] V
  • INVALID_VALUE if the pin is not a PWM input
  • CONFIGURATION_CONFLICT if the channel is in use
  • UNSAFE_PIN_VOLTAGE if the pin fails the voltage check

configure_output(options)​

Starts square-wave generation (about 50 % duty) on an output pin (IO 18 or 22). The device generates the closest frequency it can produce and returns it in frequency. Changing frequency or duration of a running output restarts it: the level shifter is off for about 100 ms, and duration counts from this call.

const pwm = tester.gpio.pwm(18);
const config = await pwm.configure_output({ frequency: 1000, vcc: 3.3, duration: 10 });
console.log(config.frequency); // frequency actually generated

Parameters:

  • options (PwmOutputOptions / keyword arguments / &PwmOutputConfig):
    • frequency (number / float / f64, required): Requested frequency in Hz, from 91.55 Hz to 7.5 MHz
    • vcc (number / float / Option<f64>, optional): High level driven on the pin, [1.8, 3.3] V, inclusive. When omitted, the device keeps its current setting.
    • duration (number / float / Option<f64>, optional): Run time in seconds, in (0, 86400]. When omitted, the output runs until it is disabled. duration is always sent, so omitting it clears a duration set by an earlier call.

Returns: Promise<PwmConfig> / PwmConfig / Result<PwmConfig, At1000Error> - with frequency set to the generated frequency

Exceptions:

  • Throws validation error if vcc or duration is out of range, or frequency is not a positive number
  • INVALID_VALUE if the pin is not a PWM output, or frequency is outside [91.55 Hz, 7.5 MHz]
  • CONFIGURATION_CONFLICT if the channel is in use
  • UNSAFE_PIN_VOLTAGE if the pin fails the voltage check

disable()​

Disables PWM on the pin. An output stops generating.

await pwm.disable();

Returns: Promise<PwmConfig> / PwmConfig / Result<PwmConfig, At1000Error>


read_config()​

Reads the PWM configuration of the pin. On an output whose timed run has ended, enabled is false.

const config = await pwm.read_config();

Returns: Promise<PwmConfig> / PwmConfig / Result<PwmConfig, At1000Error>


measure(options?)​

Runs one capture on an enabled input pin. The pin is sampled at 30 MHz. The capture runs until it holds at least one full cycle and 100 ms have passed, and ends on a rising edge; timeout ends it whatever the edges. The HTTP request timeout is extended automatically to timeout + 2 s.

const m = await pwm.measure({ timeout: 2 });
if (m.status === 'ok') {
console.log(m.frequency, m.duty_cycle);
}

Parameters:

  • options (PwmMeasureOptions, optional / keyword argument / Option<f64>):
    • timeout (number / float / f64, optional): Longest capture in seconds, [0.1, 60]. Default 5

Returns: Promise<PwmMeasurement> / PwmMeasurement / Result<PwmMeasurement, At1000Error>

Exceptions:

  • Throws validation error if timeout is outside [0.1, 60]
  • INVALID_VALUE if the pin is a PWM output
  • INVALID_CONFIGURATION if PWM is disabled on the pin
  • INTERNAL_ERROR (HTTP 500) if the AT1000 could not keep up with the capture. Retry the measurement
caution

Signals up to 5 MHz are measured accurately. Above about 6 MHz (pulses shorter than about 67 ns), the samples alias silently and the result is wrong without any error.


GpioSequence​

A sequence is a list of GPIO commands sent in one request. The device runs them back to back while holding the I/O subsystem, so no other I/O request interleaves, and answers with a single report. Every pin a sequence touches must already be configured, and every duration is in seconds.

Appending a command sends nothing: only run() talks to the device. repeat, delay, stable_for and expect are carried out on the device, so no network round trip separates two readings. GPIO command sequences walks through a complete example.

read(io, options?)​

Appends a read of one pin, or of several pins in the order given.

const report = await tester.gpio.sequence()
.read(0) // one pin, one reading
.read([0, 1, 2]).as('scan') // three pins, in the order given
.read(0, { repeat: 4, delay: 0.001 }).as('burst') // four readings, 1 ms apart
.read(1, { expect: true }).as('check') // assert every reading
.run();

Parameters:

  • io (number | number[] / int | list[int] / impl Into<SequencePins>): Pin, or distinct pins walked in the order given (0-31). Rust takes a usize or a Vec<usize>
  • options (GpioSequenceReadOptions / keyword arguments / ReadOptions, optional):
    • repeat (number / int / Option<u32>): Total number of readings of the whole pin list, an integer of at least 1, and 1 when omitted
    • delay (number / float / Option<f64>): Seconds between two passes of a repeated read, requires an effective repeat of at least 2
    • expect (boolean | { min, max } / bool | tuple[float, float] | SequenceBounds / Option<SequenceExpect>): Assertion checked on every reading: a level on a digital pin, inclusive voltage bounds on an analog one

Returns: GpioSequence / GpioSequence / Result<GpioSequence, At1000Error> - The sequence with the command appended

Exceptions:

  • Throws validation error if a pin is outside 0-31, the pin list is empty or lists a pin twice, repeat is 0, delay comes with an effective repeat below 2, or an expect bound is outside [-25, 25] V
note

A single pin read once reports its reading in the step's value. A pin list, or a repeat above 1, reports one entry per pin and pass in samples instead.


write(io, value)​

Appends a write of one pin, or of several pins in the order given.

const report = await tester.gpio.sequence()
.write(0, true) // one pin
.write([0, 1, 2], false) // one value on every listed pin
.write([0, 1, 2], [true, false, 2.5]) // one value per pin
.run();

Parameters:

  • io (number | number[] / int | list[int] / impl Into<SequencePins>): Pin, or distinct pins walked in the order given (0-31)
  • value (boolean | number | (boolean | number)[] / bool | float | Sequence[bool | float] / impl Into<SequenceValues>): One value applied to every listed pin, or one value per pin, in the order of the pin list. Rust takes a GpioValue or a Vec<GpioValue>

Returns: GpioSequence / GpioSequence / Result<GpioSequence, At1000Error> - The sequence with the command appended

Exceptions:

  • Throws validation error if a pin is outside 0-31, the pin list is empty or lists a pin twice, a value is not finite, or a list of values is not exactly as long as the pin list
note

Every value is read through its own pin's mode, exactly like a per-pin write, so one command may mix a level and a voltage. On a digital pin a number is a level (0 low, anything else high); on an analog pin it is a voltage in [0, 24] V and a boolean is rejected. A write of one pin reports what it applied in the step's value, a write of several pins one entry per pin in samples.


wait_voltage(io, options)​

Appends a wait for an analog pin to read inside given voltage bounds.

const report = await tester.gpio.sequence()
.wait_voltage(3, { min: 2.0, max: 3.0, timeout: 0.5 }).as('band')
.run();

Parameters:

  • io (number / int / usize): A single analog pin (0-31)
  • options (GpioSequenceWaitVoltageOptions / keyword arguments / WaitVoltageOptions):
    • min (number / float / Option<f64>): Lowest accepted voltage, [-25, 25] V. Alone, the wait completes when the pin reads at or above it
    • max (number / float / Option<f64>): Highest accepted voltage, [-25, 25] V. Alone, the wait completes when the pin reads at or below it
    • timeout (number / float / Option<f64>, optional): Seconds this wait may take, clamped to what is left of the sequence budget
    • stable_for (number / float / Option<f64>, optional): Seconds the condition must hold. Any sample that fails it restarts the window

Returns: GpioSequence / GpioSequence / Result<GpioSequence, At1000Error> - The sequence with the command appended

Exceptions:

  • Throws validation error if neither min nor max is given, min is above max, a bound is outside [-25, 25] V, or timeout or stable_for is not finite and greater than zero
note

Both bounds are inclusive, and together they describe a band. The semantics are level-based, not edge-based: a pin already inside the bounds completes the wait at once, unless stable_for first requires them to hold. The device reads the pin from polled ADC samples, so an excursion shorter than the interval between two samples is not observable. A wait that runs out of time fails the whole run with SEQUENCE_TIMED_OUT.


wait_level(io, level, options?)​

Appends a wait for a digital pin to read a level.

const report = await tester.gpio.sequence()
.wait_level(0, 'high', { stable_for: 0.02, timeout: 0.5 }).as('ready')
.run();

Parameters:

  • io (number / int / usize): A single digital pin (0-31)
  • level ('low' | 'high' | boolean / "low" | "high" | bool | SequenceLevel / impl Into<SequenceLevel>): Level to wait for, where true is high. Rust takes a bool or a SequenceLevel
  • options (GpioSequenceWaitOptions / keyword arguments / WaitLevelOptions, optional):
    • timeout (number / float / Option<f64>): Seconds this wait may take, clamped to what is left of the sequence budget
    • stable_for (number / float / Option<f64>): Seconds the level must hold. Any sample that fails it restarts the window

Returns: GpioSequence / GpioSequence / Result<GpioSequence, At1000Error> - The sequence with the command appended

Exceptions:

  • Throws validation error if the pin is outside 0-31, or timeout or stable_for is not finite and greater than zero
note

The level is resolved from the pin's configured vil and vih, from polled ADC samples, so a transition shorter than the sampling interval is not observable. A pin that already reads the level completes the wait at once, unless stable_for first requires it to hold.


delay(duration)​

Appends a pause the device takes between the surrounding commands.

const report = await tester.gpio.sequence()
.write(0, true)
.delay(0.01) // 10 ms, taken on the device
.write(0, false)
.run();

Parameters:

  • duration (number / float / f64): Pause in seconds, finite and greater than zero

Returns: GpioSequence / GpioSequence / Result<GpioSequence, At1000Error> - The sequence with the command appended


hold() / release()​

Appends a hold of the outputs, or a release that applies every write buffered since the hold. Same effect as gpio.hold() and gpio.release() (see Output synchronization), without one request each.

const report = await tester.gpio.sequence()
.hold() // freeze the outputs
.write([0, 1, 2], [true, true, false])
.release() // apply the three writes together
.run();

Parameters: None

Returns: GpioSequence / GpioSequence / Result<GpioSequence, At1000Error> - The sequence with the command appended

caution

A hold whose release never runs, because a later command stopped the run, leaves the outputs held. Call gpio.release() in your error path.


as(name) / as_(name)​

Names the command just appended, so its result can be read back by name. The method is as() in JavaScript and as_() in Python and Rust, and it adds no command of its own.

const report = await tester.gpio.sequence()
.read(0).as('initial')
.delay(0.01).as('pause')
.run();

console.log(report.named.initial.value, report.named.pause.elapsed);

Parameters:

  • name (string / str / impl Into<String>): Exact, case-sensitive name. Names stay in the SDK and never reach the device

Returns: GpioSequence / GpioSequence / Result<GpioSequence, At1000Error> - The same sequence, with the last command named

Exceptions:

  • Throws validation error if the name is empty, if the name is already used in this sequence, if the command just appended already has a name, or if no command has been appended yet

run(options?)​

Sends the appended commands and returns one result per command. The only method that reaches the device.

const report = await tester.gpio.sequence()
.read([0, 1, 2]).as('scan')
.run({ timeout: 10 });

console.log(report.elapsed, report.results.length);

Parameters:

  • options ({ timeout?: number } / timeout keyword argument / Option<f64>, optional):
    • timeout (number / float / Option<f64>): Time budget for the whole run in seconds, 30 when omitted. It bounds every command, including every pass of a repeated read, and a per-wait timeout is clamped to what is left of it

Returns: Promise<GpioSequenceReport> / SequenceReport / Result<SequenceReport, At1000Error> - One result per submitted command, in order

Exceptions:

  • Throws validation error if no command has been appended, or if timeout is not finite and greater than zero
  • A run that does not complete returns no report: a wait that ran out of time and an exhausted budget fail with SEQUENCE_TIMED_OUT, a failed read assertion with SEQUENCE_ASSERTION_FAILED, both naming the command that stopped the run (see Sequence errors)
caution

Writes that already ran stay applied when a run fails, and a hold without its release leaves the outputs held. Validation is different: the device checks the whole list before it runs anything, so a rejected sequence changes nothing.


Types​

DigitalInputConfiguration​

{
mode: "digital",
direction: "input",
vil: number, // [-25, 25] V, inclusive
vih: number // [-25, 25] V, inclusive
}

Rust: ikalogic_at1000::DigitalInputConfig

pub struct DigitalInputConfig {
pub vil: f64,
pub vih: f64,
}

DigitalOutputConfiguration​

{
mode: "digital",
direction: "output",
value: boolean,
vol: number, // 0 to 24V
voh: number, // 0 to 24V
vil: number, // [-25, 25] V, inclusive
vih: number // [-25, 25] V, inclusive
}

Rust: ikalogic_at1000::DigitalOutputConfig

pub struct DigitalOutputConfig {
pub value: bool,
pub vol: f64,
pub voh: f64,
pub vil: Option<f64>,
pub vih: Option<f64>,
}

OpenDrainConfiguration​

{
mode: "digital",
direction: "open_drain",
value: boolean,
vil: number, // [-25, 25] V, inclusive
vih: number // [-25, 25] V, inclusive
}

Rust: ikalogic_at1000::OpenDrainConfig

pub struct OpenDrainConfig {
pub value: bool,
pub vil: f64,
pub vih: f64,
}

AnalogInputConfiguration​

{
mode: "analog",
direction: "input"
}

Rust: no analog configuration struct. configure_input() takes no argument and returns GpioConfiguration.

AnalogOutputConfiguration​

{
mode: "analog",
direction: "output",
value?: number // 0 to 24V
}

Rust: no analog configuration struct. configure_output() takes the voltage as an f64 and returns GpioConfiguration.

GpioConfiguration​

What every configure call and read_config() return: in JavaScript and Python, one of the five configurations above.

DigitalInputConfiguration | DigitalOutputConfiguration | OpenDrainConfiguration
| AnalogInputConfiguration | AnalogOutputConfiguration

Rust: ikalogic_at1000::GpioConfiguration. The Rust SDK has no per-mode configuration type: configure_input, configure_output, configure_open_drain and read_config all return the same seven-field struct, whatever the pin's mode.

pub struct GpioConfiguration {
pub mode: GpioMode,
pub direction: GpioDirection,
pub value: GpioValue,
pub vil: f64,
pub vih: f64,
pub vol: f64,
pub voh: f64,
}

pub enum GpioMode { Analog, Digital }

pub enum GpioDirection { Input, Output, OpenDrain }

pub enum GpioValue { Digital(bool), Analog(f64) }

PwmConfig​

Returned by every PwmIO configure call, disable() and read_config(). Also the data of the gpio.pwm_config event.

{
enabled: boolean,
direction: "input" | "output",
vcc: number, // 1.8 to 3.3 V
frequency?: number, // outputs only: generated frequency in Hz
duration?: number // outputs only: run time in s requested at the last start; absent when running until disabled
}

Rust: ikalogic_at1000::PwmConfig

pub struct PwmConfig {
pub enabled: bool,
pub direction: PwmDirection,
pub vcc: f64,
pub frequency: Option<f64>,
pub duration: Option<f64>,
}

pub enum PwmDirection { Input, Output }

PwmInputOptions / PwmOutputOptions / PwmMeasureOptions​

JavaScript options of configure_input, configure_output and measure. Python takes the same fields as keyword arguments.

PwmInputOptions = { vcc?: number }
PwmOutputOptions = { frequency: number, vcc?: number, duration?: number }
PwmMeasureOptions = { timeout?: number }

Rust: ikalogic_at1000::PwmInputConfig and ikalogic_at1000::PwmOutputConfig. measure takes the timeout directly as Option<f64>.

pub struct PwmInputConfig {
pub vcc: Option<f64>,
}

pub struct PwmOutputConfig {
pub frequency: f64,
pub vcc: Option<f64>,
pub duration: Option<f64>,
}

PwmInputConfig implements Default. PwmOutputConfig does not, so every field is set explicitly.

PwmMeasurement​

Returned by measure(). A discriminated union on status; the statistics are present only when status is "ok" and cover whole cycles from the first to the last captured rising edge. Times are in seconds. In Python, status is typed PwmStatus = Literal["ok", "timeout"].

{
status: "ok" | "timeout",
level: boolean, // line level at the end of the capture
edges: number,
cycles: number,
duration: number, // captured time
// status "ok" only:
frequency: number, // Hz
duty_cycle: number, // %
period: number, period_min: number, period_max: number,
high_time: number, high_time_min: number, high_time_max: number,
low_time: number, low_time_min: number, low_time_max: number
}

Rust: ikalogic_at1000::PwmMeasurement. The statistics are Option<f64>, None on a timeout.

pub struct PwmMeasurement {
pub status: PwmStatus,
pub level: bool,
pub edges: u64,
pub cycles: u64,
pub duration: f64,
pub frequency: Option<f64>,
pub duty_cycle: Option<f64>,
pub period: Option<f64>,
pub period_min: Option<f64>,
pub period_max: Option<f64>,
pub high_time: Option<f64>,
pub high_time_min: Option<f64>,
pub high_time_max: Option<f64>,
pub low_time: Option<f64>,
pub low_time_min: Option<f64>,
pub low_time_max: Option<f64>,
}

pub enum PwmStatus { Ok, Timeout }

SyncState​

{ hold_state: "held" | "released" }

Rust: ikalogic_at1000::SyncState

pub struct SyncState {
pub hold_state: HoldState,
}

pub enum HoldState { Released, Held }

GpioSequenceStep​

{
op: "read" | "write" | "wait_voltage" | "wait_level" | "delay" | "hold" | "release",
io?: number | number[], // absent on delay, hold and release
value?: boolean | number, // a one-pin read that did not repeat, a one-pin write, or a wait
samples?: GpioSequenceSample[], // a pin list, or a read that repeated
elapsed: number // seconds from the sequence start to the end of this command
}

Python: SequenceStep

Rust: ikalogic_at1000::SequenceStep

pub struct SequenceStep {
pub op: SequenceOp,
pub io: Option<SequencePins>,
pub value: Option<GpioValue>,
pub samples: Option<Vec<SequenceSample>>,
pub elapsed: f64,
}

pub enum SequenceOp { Read, Write, WaitVoltage, WaitLevel, Delay, Hold, Release }

pub enum SequencePins { One(usize), Many(Vec<usize>) }

GpioSequenceSample​

{
io: number,
value: boolean | number,
elapsed: number // seconds from the sequence start to this entry
}

Python: SequenceSample

Rust: ikalogic_at1000::SequenceSample

pub struct SequenceSample {
pub io: usize,
pub value: GpioValue,
pub elapsed: f64,
}

GpioSequenceReport​

{
elapsed: number, // total duration of the run, in seconds
results: GpioSequenceStep[], // one entry per submitted command, in order
named: Record<string, GpioSequenceNamedResult>, // typed per name declared with as()
get(name: string): GpioSequenceNamedResult | undefined
}

Python: SequenceReport, read through report.results and report.named["name"].

Rust: ikalogic_at1000::SequenceReport

pub struct SequenceReport {
pub elapsed: f64,
// the results and the name associations are private
}

In Rust the results and the name associations are private, so a name stays bound to its command: read them through report.results(), which borrows a &[SequenceStep], and report.get(name), which returns an Option<SequenceNamedResult>.

GpioSequenceNamedResult​

// scalar: a one-pin read or write, and every wait
{ kind: "scalar", name: string, index: number, op: string, elapsed: number, io: number | number[], value: boolean | number }

// collection: a read over a pin list or with repeat > 1, and a multi-pin write
{ kind: "collection", name: string, index: number, op: string, elapsed: number, io: number | number[], samples: GpioSequenceSample[] }

// control: hold, release and delay
{ kind: "control", name: string, index: number, op: string, elapsed: number }

Python: SequenceNamedResult, a union of SequenceScalarResult, SequenceCollectionResult and SequenceControlResult discriminated on kind.

Rust: ikalogic_at1000::SequenceNamedResult, an enum whose variants borrow from the report.

pub enum SequenceNamedResult<'a> {
Scalar {
name: &'a str,
index: usize,
op: SequenceOp,
kind: SequenceResultKind,
io: &'a SequencePins,
elapsed: f64,
value: GpioValue,
},
Collection {
name: &'a str,
index: usize,
op: SequenceOp,
kind: SequenceResultKind,
io: &'a SequencePins,
elapsed: f64,
samples: SequenceSamples<'a>,
},
Control {
name: &'a str,
index: usize,
op: SequenceOp,
kind: SequenceResultKind,
elapsed: f64,
},
}

pub enum SequenceResultKind { Scalar, Collection, Control }

Sequence errors​

codeHTTPWhen it fires
SEQUENCE_TIMED_OUT409A wait exceeded its timeout, or what was left of the sequence budget: Command 3 ('wait_voltage'): pin 3 still reads 2.1000 V. The budget ran out before a command started: Command 7 ('read'): the sequence exhausted its 30 s budget
SEQUENCE_ASSERTION_FAILED409A reading did not satisfy a read's expect: Command 4 ('read'): pin 1 read false, which does not satisfy 'expect'
INVALID_VALUE400A field is missing, or the op does not accept it: Command 2 ('delay'): field 'io' is not accepted by 'delay'. Also an empty commands list, a pin listed twice, and a pin list where a wait requires a single pin
OUT_OF_RANGE_VALUE400Sequence of 70000 commands exceeds the maximum of 65536, Command 1 ('read'): field 'io' pin 40 is out of range [0; 31], or Field 'timeout' must be a finite duration greater than zero
INVALID_CONFIGURATION400A pin is not configured for the command: Command 0 ('write'): cannot write to pin 5, configured as input, or Command 1 ('wait_voltage'): pin 3 must be in 'analog' mode
JSON_DESERIALIZATION400Malformed JSON, an unknown field, or a field of the wrong type, rejected before the sequence is validated

The four 400 codes reject the whole sequence before anything runs. The two 409 codes stop a run part-way, and every write that already executed stays applied. A failure surfaces as an ApiError carrying that code in JavaScript and Python, and as At1000Error::Api(err) with err.code in Rust.


Notes​

  • All 32 pins support both digital and analog modes
  • Voltage range: -25 V to +25 V for measured inputs and digital thresholds, 0 to 24 V for outputs. Both ranges are inclusive.
  • Open-drain mode is ideal for protocols requiring external pull-ups (I2C, 1-Wire)
  • When writing digital values, both boolean and number (0/1) are accepted
  • Analog readings provide precise voltage measurements
  • Use hold() and release() for synchronized multi-pin operations
  • IO 17, 18, 21 and 22 also support PWM measurement and generation through pwm(io); see PWM measurement and generation
  • Use sequence() to run many reads, writes and waits in one request; see GPIO command sequences