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​
- NodeJS
- Python
- Rust
const gpio = tester.gpio;
gpio = tester.gpio
let gpio = &tester.gpio;
GPIO Module Methods​
reset()​
Resets all GPIO pins to their default configuration.
- NodeJS
- Python
- Rust
await tester.gpio.reset();
tester.gpio.reset()
tester.gpio.reset()?;
Returns: Promise<void> / None / Result<(), At1000Error>
digital(io)​
Access a specific GPIO pin for digital operations.
- NodeJS
- Python
- Rust
const pin = tester.gpio.digital(0);
pin = tester.gpio.digital(0)
let 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.
- NodeJS
- Python
- Rust
const pin = tester.gpio.analog(0);
pin = tester.gpio.analog(0)
let 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.
- NodeJS
- Python
- Rust
const pwm = tester.gpio.pwm(18);
pwm = tester.gpio.pwm(18)
let 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.
- NodeJS
- Python
- Rust
await tester.gpio.hold();
tester.gpio.hold()
tester.gpio.hold()?;
Returns: Promise<SyncConfiguration> / SyncConfiguration / Result<SyncConfiguration, At1000Error> - Configuration with action: "hold"
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).
- NodeJS
- Python
- Rust
await tester.gpio.release();
tester.gpio.release()
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.
- NodeJS
- Python
- Rust
const config = await tester.gpio.read_config(0);
config = tester.gpio.read_config(0)
let config = 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.
- NodeJS
- Python
- Rust
const state = await tester.gpio.read_sync();
state = tester.gpio.read_sync()
let state = 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.
- NodeJS
- Python
- Rust
const sequence = tester.gpio.sequence();
sequence = tester.gpio.sequence()
let sequence = tester.gpio.sequence();
Returns: GpioSequence / GpioSequence / GpioSequence - An empty builder, which talks to the device only on run()
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.
- NodeJS
- Python
- Rust
await pin.configure_input({
vil: 0.8, // Input low threshold
vih: 2.0 // Input high threshold
});
pin.configure_input(vil=0.8, vih=2.0)
use ikalogic_at1000::DigitalInputConfig;
let pin = tester.gpio.digital(0)?;
pin.configure_input(&DigitalInputConfig {
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
vilorvihis outside the inclusive range [-25, 25] V
configure_output(config)​
Configures the pin as a digital output with custom voltage levels and thresholds.
- NodeJS
- Python
- Rust
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
});
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
)
use ikalogic_at1000::DigitalOutputConfig;
let pin = tester.gpio.digital(0)?;
pin.configure_output(&DigitalOutputConfig {
value: true, // Initial state
vol: 0.0, // Output low voltage
voh: 3.3, // Output high voltage
vil: Some(0.8), // Optional input low threshold
vih: Some(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
volorvohis outside the range [0, 24] - Throws validation error if
vilorvihis outside the inclusive range [-25, 25] V
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.).
- NodeJS
- Python
- Rust
await pin.configure_open_drain({
value: true,
vil: 0.8,
vih: 2.0
});
pin.configure_open_drain(
value=True,
vil=0.8,
vih=2.0
)
use ikalogic_at1000::OpenDrainConfig;
let pin = tester.gpio.digital(0)?;
pin.configure_open_drain(&OpenDrainConfig {
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
vilorvihis outside the inclusive range [-25, 25] V
read()​
Reads the current logical state of the pin.
- NodeJS
- Python
- Rust
const state = await pin.read();
console.log("Pin is", state ? "HIGH" : "LOW");
state = pin.read()
print("Pin is", "HIGH" if state else "LOW")
let pin = tester.gpio.digital(0)?;
let state = pin.read()?;
println!("Pin is {}", if state { "HIGH" } else { "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).
- NodeJS
- Python
- Rust
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)
pin.write(True) # Set HIGH
pin.write(False) # Set LOW
pin.write(1) # Set HIGH (numeric)
pin.write(0) # Set LOW (numeric)
let pin = tester.gpio.digital(0)?;
pin.write(true)?; // Set HIGH
pin.write(false)?; // Set LOW
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.
- NodeJS
- Python
- Rust
await pin.configure_input();
pin.configure_input()
let pin = tester.gpio.analog(0)?;
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.
- NodeJS
- Python
- Rust
await pin.configure_output(3.3); // Set to 3.3V
pin.configure_output(3.3) # Set to 3.3V
let pin = tester.gpio.analog(0)?;
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.
- NodeJS
- Python
- Rust
const voltage = await pin.read();
console.log("Voltage:", voltage, "V");
voltage = pin.read()
print(f"Voltage: {voltage} V")
let pin = tester.gpio.analog(0)?;
let voltage = pin.read()?;
println!("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).
- NodeJS
- Python
- Rust
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
pin.write(3.3) # Set to 3.3V
pin.write(5.0) # Set to 5.0V
pin.write(12.5) # Set to 12.5V
let pin = tester.gpio.analog(0)?;
pin.write(3.3)?; // Set to 3.3V
pin.write(5.0)?; // Set to 5.0V
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).
- NodeJS
- Python
- Rust
const pwm = tester.gpio.pwm(17);
await pwm.configure_input({ vcc: 3.3 });
pwm = tester.gpio.pwm(17)
pwm.configure_input(vcc=3.3)
use ikalogic_at1000::PwmInputConfig;
let pwm = tester.gpio.pwm(17)?;
pwm.configure_input(&PwmInputConfig { vcc: Some(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 whatevervccis.
Returns: Promise<PwmConfig> / PwmConfig / Result<PwmConfig, At1000Error>
Exceptions:
- Throws validation error if
vccis outside [1.8, 3.3] V INVALID_VALUEif the pin is not a PWM inputCONFIGURATION_CONFLICTif the channel is in useUNSAFE_PIN_VOLTAGEif 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.
- NodeJS
- Python
- Rust
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
pwm = tester.gpio.pwm(18)
config = pwm.configure_output(frequency=1000, vcc=3.3, duration=10)
print(config.frequency) # frequency actually generated
use ikalogic_at1000::PwmOutputConfig;
let pwm = tester.gpio.pwm(18)?;
let config = pwm.configure_output(&PwmOutputConfig {
frequency: 1000.0,
vcc: Some(3.3),
duration: Some(10.0),
})?;
println!("{:?}", 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 MHzvcc(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.durationis 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
vccordurationis out of range, orfrequencyis not a positive number INVALID_VALUEif the pin is not a PWM output, orfrequencyis outside [91.55 Hz, 7.5 MHz]CONFIGURATION_CONFLICTif the channel is in useUNSAFE_PIN_VOLTAGEif the pin fails the voltage check
disable()​
Disables PWM on the pin. An output stops generating.
- NodeJS
- Python
- Rust
await pwm.disable();
pwm.disable()
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.
- NodeJS
- Python
- Rust
const config = await pwm.read_config();
config = pwm.read_config()
let config = 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.
- NodeJS
- Python
- Rust
const m = await pwm.measure({ timeout: 2 });
if (m.status === 'ok') {
console.log(m.frequency, m.duty_cycle);
}
m = pwm.measure(timeout=2)
if m.status == "ok":
print(m.frequency, m.duty_cycle)
use ikalogic_at1000::PwmStatus;
let m = pwm.measure(Some(2.0))?;
if m.status == PwmStatus::Ok {
println!("{:?} {:?}", 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
timeoutis outside [0.1, 60] INVALID_VALUEif the pin is a PWM outputINVALID_CONFIGURATIONif PWM is disabled on the pinINTERNAL_ERROR(HTTP 500) if the AT1000 could not keep up with the capture. Retry the measurement
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.
- NodeJS
- Python
- Rust
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();
report = (
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()
)
use ikalogic_at1000::{ReadOptions, SequenceExpect};
let report = tester.gpio.sequence()
.read(0, ReadOptions::default())? // one pin, one reading
.read(vec![0, 1, 2], ReadOptions::default())?.as_("scan")? // three pins, in the order given
.read(0, ReadOptions { repeat: Some(4), delay: Some(0.001), ..Default::default() })?.as_("burst")? // four readings, 1 ms apart
.read(1, ReadOptions { expect: Some(SequenceExpect::Level(true)), ..Default::default() })?.as_("check")? // assert every reading
.run(None)?;
Parameters:
io(number | number[]/int | list[int]/impl Into<SequencePins>): Pin, or distinct pins walked in the order given (0-31). Rust takes ausizeor aVec<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 omitteddelay(number/float/Option<f64>): Seconds between two passes of a repeated read, requires an effectiverepeatof at least 2expect(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,
repeatis 0,delaycomes with an effectiverepeatbelow 2, or anexpectbound is outside [-25, 25] V
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.
- NodeJS
- Python
- Rust
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();
report = (
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()
)
use ikalogic_at1000::GpioValue;
let report = tester.gpio.sequence()
.write(0, GpioValue::Digital(true))? // one pin
.write(vec![0, 1, 2], GpioValue::Digital(false))? // one value on every listed pin
.write(
vec![0, 1, 2],
vec![GpioValue::Digital(true), GpioValue::Digital(false), GpioValue::Analog(2.5)],
)? // one value per pin
.run(None)?;
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 aGpioValueor aVec<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
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.
- NodeJS
- Python
- Rust
const report = await tester.gpio.sequence()
.wait_voltage(3, { min: 2.0, max: 3.0, timeout: 0.5 }).as('band')
.run();
report = (
tester.gpio.sequence()
.wait_voltage(3, min=2.0, max=3.0, timeout=0.5).as_("band")
.run()
)
use ikalogic_at1000::WaitVoltageOptions;
let report = tester.gpio.sequence()
.wait_voltage(3, WaitVoltageOptions { min: Some(2.0), max: Some(3.0), timeout: Some(0.5), ..Default::default() })?.as_("band")?
.run(None)?;
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 itmax(number/float/Option<f64>): Highest accepted voltage, [-25, 25] V. Alone, the wait completes when the pin reads at or below ittimeout(number/float/Option<f64>, optional): Seconds this wait may take, clamped to what is left of the sequence budgetstable_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
minnormaxis given,minis abovemax, a bound is outside [-25, 25] V, ortimeoutorstable_foris not finite and greater than zero
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.
- NodeJS
- Python
- Rust
const report = await tester.gpio.sequence()
.wait_level(0, 'high', { stable_for: 0.02, timeout: 0.5 }).as('ready')
.run();
report = (
tester.gpio.sequence()
.wait_level(0, "high", stable_for=0.02, timeout=0.5).as_("ready")
.run()
)
use ikalogic_at1000::WaitLevelOptions;
let report = tester.gpio.sequence()
.wait_level(0, true, WaitLevelOptions { stable_for: Some(0.02), timeout: Some(0.5) })?.as_("ready")?
.run(None)?;
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, wheretrueis high. Rust takes aboolor aSequenceLeveloptions(GpioSequenceWaitOptions/ keyword arguments /WaitLevelOptions, optional):timeout(number/float/Option<f64>): Seconds this wait may take, clamped to what is left of the sequence budgetstable_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
timeoutorstable_foris not finite and greater than zero
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.
- NodeJS
- Python
- Rust
const report = await tester.gpio.sequence()
.write(0, true)
.delay(0.01) // 10 ms, taken on the device
.write(0, false)
.run();
report = (
tester.gpio.sequence()
.write(0, True)
.delay(0.01) # 10 ms, taken on the device
.write(0, False)
.run()
)
use ikalogic_at1000::GpioValue;
let report = tester.gpio.sequence()
.write(0, GpioValue::Digital(true))?
.delay(0.01)? // 10 ms, taken on the device
.write(0, GpioValue::Digital(false))?
.run(None)?;
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.
- NodeJS
- Python
- Rust
const report = await tester.gpio.sequence()
.hold() // freeze the outputs
.write([0, 1, 2], [true, true, false])
.release() // apply the three writes together
.run();
report = (
tester.gpio.sequence()
.hold() # freeze the outputs
.write([0, 1, 2], [True, True, False])
.release() # apply the three writes together
.run()
)
use ikalogic_at1000::GpioValue;
let report = tester.gpio.sequence()
.hold()? // freeze the outputs
.write(
vec![0, 1, 2],
vec![GpioValue::Digital(true), GpioValue::Digital(true), GpioValue::Digital(false)],
)?
.release()? // apply the three writes together
.run(None)?;
Parameters: None
Returns: GpioSequence / GpioSequence / Result<GpioSequence, At1000Error> - The sequence with the command appended
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.
- NodeJS
- Python
- Rust
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);
report = (
tester.gpio.sequence()
.read(0).as_("initial")
.delay(0.01).as_("pause")
.run()
)
print(report.named["initial"].value, report.named["pause"].elapsed)
use ikalogic_at1000::{ReadOptions, SequenceNamedResult};
let report = tester.gpio.sequence()
.read(0, ReadOptions::default())?.as_("initial")?
.delay(0.01)?.as_("pause")?
.run(None)?;
if let Some(SequenceNamedResult::Scalar { value, .. }) = report.get("initial") {
println!("Initial reading: {value:?}");
}
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.
- NodeJS
- Python
- Rust
const report = await tester.gpio.sequence()
.read([0, 1, 2]).as('scan')
.run({ timeout: 10 });
console.log(report.elapsed, report.results.length);
report = tester.gpio.sequence().read([0, 1, 2]).as_("scan").run(timeout=10.0)
print(report.elapsed, len(report.results))
use ikalogic_at1000::ReadOptions;
let report = tester.gpio.sequence()
.read(vec![0, 1, 2], ReadOptions::default())?.as_("scan")?
.run(Some(10.0))?;
println!("{} commands in {} s", report.results().len(), report.elapsed);
Parameters:
options({ timeout?: number }/timeoutkeyword 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-waittimeoutis 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
timeoutis 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 failedreadassertion withSEQUENCE_ASSERTION_FAILED, both naming the command that stopped the run (see Sequence errors)
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​
code | HTTP | When it fires |
|---|---|---|
SEQUENCE_TIMED_OUT | 409 | A 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_FAILED | 409 | A reading did not satisfy a read's expect: Command 4 ('read'): pin 1 read false, which does not satisfy 'expect' |
INVALID_VALUE | 400 | A 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_VALUE | 400 | Sequence 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_CONFIGURATION | 400 | A 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_DESERIALIZATION | 400 | Malformed 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
booleanandnumber(0/1) are accepted - Analog readings provide precise voltage measurements
- Use
hold()andrelease()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