Migrating from the hardware API
If you have code against the IHWAPI (sp209api_*, sp259api_*,
sp1000gapi_*), this page maps it onto the SDK.
Nothing forces you to move: the hardware API documentation stays online and existing integrations keep working. But the IHWAPI is frozen: it opens a device and hands you transitions, and that is all. Decoders, triggers, measurements, pattern generation, export and remote access are in the SDK only and will not be back-ported.
The workflow, side by side​
The IHWAPI's five steps, and what replaces them.
1. Create a handle and list devices​
The IHWAPI needs a handle per device family, and a device list you must free.
sp259api_handle handle;
sp259api_create_new_handle(&handle, SP259_MODEL);
sp259api_create_device_list(handle);
uint8_t count = sp259api_get_devices_count(handle);
device_descriptor_t descriptor;
sp259api_get_device_descriptor(handle, 0, &descriptor);
The SDK has one call, and the same one for every device family:
- Python
- NodeJS
- Rust
- C
with ScanaStudio.connect() as server:
for device in server.devices():
print(device.key, device.name, device.serial)
const server = await ScanaStudio.connect();
for (const device of await server.devices()) {
console.log(device.key, device.name, device.serial);
}
let server = ScanaStudio::connect(DEFAULT_URL).await?;
for device in server.devices().await? {
println!("{} {} {:?}", device.key, device.name, device.serial);
}
ss_server *server = ss_server_connect(NULL);
char *devices = ss_server_devices(server); /* JSON, every family at once */
printf("%s\n", devices);
ss_string_free(devices);
2. Open a device​
sp259api_device_open(handle, descriptor.serial_number);
/* or */
sp259api_device_open_first(handle);
Becomes opening a workspace on that device:
- Python
- NodeJS
- Rust
- C
workspace = server.create("hw:SP259-000123")
const workspace = await server.create('hw:SP259-000123');
let workspace = server.create("hw:SP259-000123").await?;
ss_workspace *workspace = ss_server_create(server, "hw:SP259-000123");
3. Configure and start a capture​
The IHWAPI fills a settings struct and a trigger description, then launches:
sp259api_settings_t settings;
sp259api_trigger_description_t trigger;
/* fill both in */
sp259api_launch_new_capture_simple_trigger(handle, &settings, &trigger);
while (!sp259api_get_capture_done_flag(handle)) { /* poll */ }
The SDK takes the settings as arguments and waits for you:
- Python
- NodeJS
- Rust
- C
last = workspace.capture.run(
samples=1_000_000,
sample_rate=25_000_000,
trigger=Trigger.rising(channel=0, position=0.1),
)
const last = await workspace.capture.run({
samples: 1_000_000,
sample_rate: 25_000_000,
trigger: Trigger.rising(0, { position: 0.1 }),
});
let last = workspace.capture().run(
&CaptureRequest::new(1_000_000, 25_000_000)
.trigger(Trigger::rising(0).at(0.1)),
Duration::from_secs(300),
).await?;
char *trigger = ss_trigger_edge(0, "rising", 0.1, NULL);
char request[192];
snprintf(request, sizeof request,
"{\"samples\": 1000000, \"sample_rate\": 25000000, \"trigger\": %s}",
trigger);
ss_string_free(trigger);
ss_capture_run(workspace, request, 300.0);
No polling loop. run() waits; start() returns at once and wait() blocks
later. The flags (get_capture_done_flag, get_ready_flag,
get_triggered_flag, get_config_done_flag) are replaced by capture.state,
capture.running and capture.trigger_count.
4. Retrieve the samples​
The IHWAPI keeps a per-channel iterator you reset and walk:
sp259api_trs_reset(handle, channel);
while (sp259api_trs_is_not_last(handle, channel)) {
sp259api_trs_t transition = sp259api_trs_get_next(handle, channel);
/* transition.sample_index, transition.value */
}
The SDK gives you the window you ask for, and pages it for you:
- Python
- NodeJS
- Rust
- C
for edge in workspace.data.transitions(channel=0):
edge.sample
edge.level
for await (const edge of workspace.data.transitions(0)) {
edge.sample;
edge.level;
}
for edge in workspace.data().transitions(0, 0, None).await? {
println!("{} -> {}", edge.sample, edge.level);
}
ss_edge *edges = malloc(sizeof(ss_edge) * ROOM);
ptrdiff_t n = ss_data_transitions(workspace, 0, 0, -1, edges, ROOM);
trs_before and trs_get_previous become level_at, next_edge and
previous_edge. See
Reading captured data.
Both APIs store transitions rather than samples. In both, the first record of a window is the level in force where the window starts, so its index may precede the start you asked for. If your IHWAPI code already handles that, it needs no change.
5. Close​
sp259api_device_close(handle);
sp259api_free_device_list(handle);
sp259api_free(handle);
Becomes:
- Python
- NodeJS
- Rust
- C
workspace.close() # the context manager closes the connection
workspace.close();
server.close();
workspace.close()?; // the connection ends with the value
ss_workspace_close(workspace);
ss_workspace_free(workspace);
ss_server_disconnect(server);
create, open and attach​
There are three ways to get a workspace:
| Call | Gives you |
|---|---|
server.create(device) | A new workspace on a device |
server.open(path) | A workspace from a .scana file |
server.attach(id) | One already running on the server |
create and open both take a stringIf you have pre-release code written against an earlier SDK, where
open(device) created a workspace on a device, that call still compiles and
now tries to load a file named se254. The failure is a file-not-found at
runtime, or silence if a file of that name happens to exist. Search your code
for open( and decide, per call, whether it should be create.
The C library has the same shape: ss_server_create(server, "se254") for a device,
ss_server_open(server, "/data/run.scana") for a file.
Concept mapping​
| IHWAPI | SDK |
|---|---|
A device handle (sp259api_handle) | A workspace, but see the note below |
One API per family (sp209api_*, sp259api_*, sp1000gapi_*) | One API for all of them |
sp259api_create_device_list + get_devices_count + get_device_descriptor | devices() |
device_open / device_open_first | server.create("hw:<serial>") |
launch_new_capture_simple_trigger | capture.start() / capture.run() |
get_capture_done_flag, get_ready_flag, get_triggered_flag | capture.state, capture.running, capture.trigger_count |
request_abort | capture.stop() |
get_available_samples | capture.last_sample |
get_trigger_position | The position you passed to the trigger builder |
trs_reset + trs_get_next + trs_is_not_last | data.transitions(channel) |
trs_before, trs_get_previous | data.level_at, data.previous_edge |
get_last_error | Raised exceptions, or ss_last_error() in C |
get_fpga_version, get_hw_version | workspace.device_info() |
device_close, free_device_list, free | workspace.close() and closing the client |
An IHWAPI handle lives in your process and dies with it. A workspace lives on the server and does not. Ending your program does not end a capture. That is what makes leave-and-rejoin possible, and it is also why a script that opens workspaces and never closes them leaves them running for as long as the server does.
What has no IHWAPI equivalent​
These have no IHWAPI counterpart:
- Protocol decoding: every ScanaStudio decoder, with packets, hex bytes and item rows.
- Triggers: pulse width, logic patterns, multi-step sequences, external input, A-then-B.
- Pattern generation: stimulate the board as well as watch it.
- Measurements: computed on the
server and saved with the
.scana. - Saving and exporting.
- Remote access: the instrument does not have to be on your machine.
- Python, NodeJS and Rust: the IHWAPI was C only.
Migrating incrementally​
You do not have to rewrite everything at once. The IHWAPI drives the USB device directly and the SDK drives a server, so they cannot share one device, but they can live in the same code base while you move test by test.
The usual order:
- Port the capture and sample reading first. It is a near-mechanical translation of the five steps above, and it is most of the code.
- Replace hand-written protocol parsing with a decoder.
- Replace hand-rolled timing arithmetic with measurements, if you want the numbers saved alongside the capture.
A physical device belongs to one workspace, and a workspace to one server. While the SDK's server holds a device, an IHWAPI program cannot open it, and the other way round. Migrate a bench wholesale rather than running both against the same analyser.