Triggers
A trigger says what arms the capture. Build one with the Trigger helpers and
hand it to capture.start() or capture.run().
Every builder takes the same two extras:
| Extra | Meaning |
|---|---|
position | The share of the acquisition kept before the trigger, 0.0 to 0.9. 0.1 keeps 10 % of history behind the event. |
mode | single captures once and stops. normal re-arms after every trigger until you stop the capture. |
immediate​
No trigger: sampling starts as soon as the device is armed.
- Python
- NodeJS
- Rust
- C
from ikalogic_scanastudio import Trigger
Trigger.immediate()
import { Trigger } from '@ikalogic/scanastudio';
Trigger.immediate();
use scanastudio_client::Trigger;
Trigger::immediate()
/* Leave `trigger` out of the request and sampling starts at once. */
ss_capture_run(workspace, "{\"samples\": 1000000, \"sample_rate\": 25000000}", 300.0);
/* Or say so explicitly: */
char *trigger = ss_trigger_immediate();
/* ... drop it into the request under "trigger", then ss_string_free(trigger); */
rising and falling​
An edge on one channel.
- Python
- NodeJS
- Rust
- C
Trigger.rising(channel=0, position=0.1, mode="single")
Trigger.falling(channel=3)
Trigger.rising(0, { position: 0.1, mode: 'single' });
Trigger.falling(3); // a high-to-low edge on channel 3
use scanastudio_client::{Trigger, TriggerExt, Mode};
Trigger::rising(0).at(0.1).mode(Mode::Single)
Trigger::falling(3) // a high-to-low edge on channel 3
/* A falling edge on channel 3, keeping 10 % of the capture before it. */
char *trigger = ss_trigger_edge(3, "falling", 0.1, "single");
char request[256];
snprintf(request, sizeof request,
"{\"samples\": %lld, \"sample_rate\": %llu, \"trigger\": %s}",
(long long)samples, (unsigned long long)rate, trigger);
ss_string_free(trigger);
/* Arm and wait in one call, or ss_capture_start to arm and return. */
ss_capture_run(workspace, request, 300.0);
ss_trigger_* buildersEach one returns the trigger object as JSON, to drop into the request that
ss_capture_run and ss_capture_start take. They are the C equivalent of the
Trigger helpers in the other SDKs. Free the string with ss_string_free once
you have built the request. position is 0.0–0.9; mode is "single" or
"normal", and NULL means "single".
position and mode are not arguments in Rust: they are .at() and .mode()
from the TriggerExt trait, which must be in scope. .at() clamps to 0.0–0.9;
the other SDKs raise instead.
logic​
Fires on any logic change across a set of channels: a bus transaction starting, rather than one wire moving.
- Python
- NodeJS
- Rust
- C
Trigger.logic([0, 1, 2, 3], position=0.2)
// Any logic change across these four channels.
Trigger.logic([0, 1, 2, 3], { position: 0.2 });
// Any logic change across these four channels.
Trigger::logic([0u16, 1, 2, 3]).at(0.2)
/* Any logic change across these four channels. */
uint16_t channels[] = { 0, 1, 2, 3 };
char *trigger = ss_trigger_logic(channels, 4, 0.2, NULL);
/* ... build the request, then ss_string_free(trigger); */
pulse​
A pulse on one channel, optionally bounded in width. This is how you catch a glitch: ask for a pulse shorter than anything legitimate.
- Python
- NodeJS
- Rust
- C
# A high pulse (0-1-0) shorter than 50 ns — a runt.
Trigger.pulse(channel=2, polarity="high", max_width=50e-9, position=0.5)
# A low pulse (1-0-1) at least 1 ms long — a bus held down.
Trigger.pulse(channel=2, polarity="low", min_width=1e-3)
// A high pulse (0-1-0) shorter than 50 ns — a runt.
Trigger.pulse(2, { polarity: 'high', max_width: 50e-9, position: 0.5 });
// A low pulse (1-0-1) at least 1 ms long — a bus held down.
Trigger.pulse(2, { polarity: 'low', min_width: 1e-3 });
// A high pulse (0-1-0) shorter than 50 ns — a runt.
Trigger::pulse(2, "high", None, Some(50e-9)).at(0.5)
// A low pulse (1-0-1) at least 1 ms long — a bus held down.
Trigger::pulse(2, "low", Some(1e-3), None)
/* A high pulse (0-1-0) shorter than 50 ns — a runt.
A negative width leaves that end unconstrained. */
char *runt = ss_trigger_pulse(2, "high", -1.0, 50e-9, 0.5, NULL);
/* A low pulse (1-0-1) at least 1 ms long — a bus held down. */
char *stuck = ss_trigger_pulse(2, "low", 1e-3, -1.0, 0.0, NULL);
Parameters:
polarity—highfor a 0‑1‑0 pulse,lowfor 1‑0‑1.min_width,max_width— in seconds. Leaving one out leaves that side unconstrained.
steps​
A multi-step pattern: a sequence of per-channel cells, each with its own timing window. This is the most selective trigger the hardware offers.
Each step is a list of cells, one per channel:
| Cell | Meaning |
|---|---|
x | Ignore this channel. |
0 / 1 | The channel must be at this level. |
r / f | The channel must show this edge. |
- Python
- NodeJS
- Rust
- C
from ikalogic_scanastudio import Trigger, step
# A falling edge on ch0 while ch1 is high, then 1-10 us later ch0 rises again.
Trigger.steps([
step(["f", "1"]),
step(["r", "x"], t_min=1e-6, t_max=10e-6),
], position=0.3)
import { Trigger, step } from '@ikalogic/scanastudio';
// A falling edge on ch0 while ch1 is high, then 1-10 us later ch0 rises again.
Trigger.steps([
step(['f', '1']),
step(['r', 'x'], { t_min: 1e-6, t_max: 10e-6 }),
], { position: 0.3 });
use scanastudio_client::{step, Trigger, TriggerExt};
// A falling edge on ch0 while ch1 is high, then 1-10 us later ch0 rises again.
Trigger::steps(vec![
step(vec!["f".into(), "1".into()], None, None),
step(vec!["r".into(), "x".into()], Some(1e-6), Some(10e-6)),
]).at(0.3)
/* A falling edge on ch0 while ch1 is high, then 1-10 us later ch0 rises. */
char *trigger = ss_trigger_steps(
"[{\"cells\": [\"f\", \"1\"], \"t_min\": null, \"t_max\": null},"
" {\"cells\": [\"r\", \"x\"], \"t_min\": 1e-6, \"t_max\": 10e-6}]",
0.3, NULL);
A cell is "x" to ignore the channel, "0" or "1" to match a level, and
"r" or "f" to match an edge. The timings are in seconds.
external​
The device's external trigger input, for arming off something outside the signals you are watching.
- Python
- NodeJS
- Rust
- C
Trigger.external(edge="rising", impedance="100k", position=0.1)
// The device's external trigger input, not one of the signal channels.
Trigger.external({ edge: 'rising', impedance: '100k', position: 0.1 });
// The device's external trigger input, not one of the signal channels.
Trigger::external("rising", "100k").at(0.1)
/* The device's external trigger input, not one of the signal channels. */
char *trigger = ss_trigger_external("rising", "100k", 0.1, NULL);
Parameters: edge is rising or falling; impedance is 100k for the
high-impedance input or 50ohm for the terminated one. Python and NodeJS
default it to 100k; Rust and C take it as a required argument.
sequence​
Combines two triggers into one condition.
| Order | Fires when |
|---|---|
a_then_b | B, but only after A has happened. |
b_then_a | A, but only after B has happened. |
a_or_b | Either one. |
a_and_b | Both, in any order. |
- Python
- NodeJS
- Rust
- C
# A chip-select falling, then a clock edge.
Trigger.sequence(
Trigger.falling(channel=0),
Trigger.rising(channel=1),
order="a_then_b",
position=0.2,
)
// A chip-select falling, then a clock edge.
Trigger.sequence(
Trigger.falling(0),
Trigger.rising(1),
{ order: 'a_then_b', position: 0.2 },
);
// A chip-select falling, then a clock edge.
Trigger::sequence(Trigger::falling(0), Trigger::rising(1), "a_then_b").at(0.2)
/* A chip-select falling, then a clock edge. The position comes from the first. */
char *cs = ss_trigger_edge(0, "falling", 0.2, NULL);
char *clock = ss_trigger_edge(1, "rising", 0.0, NULL);
char *both = ss_trigger_sequence(cs, clock, "a_then_b");
ss_string_free(cs);
ss_string_free(clock);
/* ... build the request with `both`, then ss_string_free(both); */
order is "a_or_b", "a_then_b", "b_then_a" or "a_and_b".
Not every device offers every trigger. A definition the hardware cannot arm is
refused rather than silently downgraded: you get a Refused error with the
reason.