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
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]
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) }
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 - Use
sequence()to run many reads, writes and waits in one request; see GPIO command sequences