Using HAL from TestStand
This skill assumes you already know how to author sequences with ts-cli (see
the ts-seq-authoring skill): adapters, TS.SData, the call list, parameters.
Here you only learn what is specific to HAL.
The only entry point
Use the facade assembly B101.Hal.dll ($HAL in the examples), and nothing
else. The ATE Framework installer leaves it at the framework root:
C:\Program Files\B101\AteFramework\B101.Hal.dll (64-bit station)
C:\Program Files (x86)\B101\AteFramework\B101.Hal.dll (32-bit station)
Point TS.SData.AssemblyPath at that file. A bare B101.Hal.dll also resolves
when TestStand finds it on its search path. The native B101.Hal.Runtime.dll
sits next to the facade in the same folder; the facade cannot start without it,
so never point at a copy that is missing it.
- Do not reference
B101.Hal.Core.dll as a step assembly: it only holds
interfaces and is an implementation detail.
- Do not reference, name or import the
B101.Hal.Wrappers types.
- The only usable API is the
Hal class and its instance: create it with
new Hal() and use what that instance exposes (its interface
implementations and their methods).
Pick the facade that matches the installed TestStand: the net8 one for
TestStand 2023 or newer (2025, 2026), and the net48/ one for TestStand 2022
and older.
Sequence shape
Create the Hal instance once and reuse it for the whole sequence.
- First step:
Calls[0] is the constructor B101.Hal.Hal; store the result in
an object reference variable (Locals.Hal here).
- Every later step:
Calls[0] is Use Existing Object bound to Locals.Hal,
then Calls[1] is the method of the interface implementation you need.
# The instance variable is created once.
ts-cli add-prop --file "$SEQ" --sequence MainSequence \
--path Hal --type reference
# First step: create the instance and keep it.
ts-cli set-prop --file "$SEQ" --step-id "$ID" \
--path TS.SData.AssemblyPath --text "$HAL"
ts-cli set-prop --file "$SEQ" --step-id "$ID" \
--path TS.SData.ClassName --text "B101.Hal.Hal"
ts-cli set-prop --file "$SEQ" --step-id "$ID" \
--path TS.SData.Calls[0].MemberName --text "Hal"
ts-cli set-prop --file "$SEQ" --step-id "$ID" \
--path TS.SData.Calls[0].MemberType --number 4
ts-cli set-prop --file "$SEQ" --step-id "$ID" \
--path "TS.SData.Calls[0].Params[0].Name" --text "Return Value"
ts-cli set-prop --file "$SEQ" --step-id "$ID" \
--path "TS.SData.Calls[0].Params[0].ArgVal" --text "Locals.Hal"
ts-cli set-prop --file "$SEQ" --step-id "$ID" \
--path "TS.SData.Calls[0].Params[0].TypeName" --text "B101.Hal.Hal"
# Later step: use the existing instance.
ts-cli set-prop --file "$SEQ" --step-id "$ID" \
--path TS.SData.AssemblyPath --text "$HAL"
ts-cli set-prop --file "$SEQ" --step-id "$ID" \
--path TS.SData.Calls[0].MemberName --text "Use Existing Object"
ts-cli set-prop --file "$SEQ" --step-id "$ID" \
--path TS.SData.Calls[0].MemberType --number 6
ts-cli set-prop --file "$SEQ" --step-id "$ID" \
--path "TS.SData.Calls[0].Params[0].Name" --text "Existing Object"
ts-cli set-prop --file "$SEQ" --step-id "$ID" \
--path "TS.SData.Calls[0].Params[0].ArgVal" --text "Locals.Hal"
ts-cli set-prop --file "$SEQ" --step-id "$ID" \
--path "TS.SData.Calls[0].Params[0].TypeName" --text "B101.Hal.Hal"
Never store an instrument in a variable: keep only the Hal instance and reach
the instrument from it inside each operation step.
Reaching an instrument operation
An instrument cannot be instantiated or stored on its own. The only shape is
one step per operation that, from the Hal instance, calls the instrument
method and immediately the action on what it returns:
Calls[0] = Use Existing Object on Locals.Hal.
Calls[1] = the instrument method that returns the implementation
(PowerSupply("PSU1")).
Calls[2] = the action on that implementation (SetVoltage(...)).
So SetVoltage is never called on a stored power supply: it always follows its
PowerSupply(...) call inside the same step.
The module class (TS.SData.ClassName) is always B101.Hal.Hal, the
root of everything. Every call also carries its own ClassName: B101.Hal.Hal
on the calls that go through the HAL instance, and the instrument interface
(B101.Hal.Core.Interfaces.IPowerSupply, ...) on the call that runs the
action. The object a call receives or returns carries that type in TypeName.
Interfaces exposed by the instance
IInstrument (SCPI base): Connect, Disconnect, Write, Query.
IPowerSupply: SetVoltage, SetCurrentLimit, SetOVP, SetOCP, Enable,
Disable, IsOutputEnabled, MeasureVoltage, MeasureCurrent, Reset.
IDMM: ConfigureFunction, Measure, AutoZero, SetNplc.
ISwitch: Close, Open, OpenAll, IsClosed.
IMux (extends ISwitch): ConfigureChannel, AutoZero.
IMatrix: Connect, Disconnect, ConnectMultiple, DisconnectAll,
IsConnected.
IOscilloscope: ConfigureChannel, SetTimebase, Run, Single,
FetchWaveform, Measure.
IProgrammer: Connect, Flash, Verify, Erase, Reset.
ISerialComm: Configure, Open, Read, Write, SendReceive.
Method arguments become step parameters (see ts-seq-authoring). Enums such as
DmmFunction are passed as their numeric or string value.
Rules
- Only
B101.Hal.dll and the Hal instance; never B101.Hal.Core, never
wrappers.
- The module class is always
B101.Hal.Hal; instrument calls use the instrument
interface as their call class.
- Create
Hal once and reuse the instance; do not construct it per step.
- Never instantiate or store an instrument: each operation step calls the
instrument method and then its action, in that order.
- Names are the unspaced .NET identifiers, not display names.
- Authoring only: this skill never runs sequences, deploys or touches hardware.
1---2name: hal3description: Drive instruments through the B101 HAL from NI TestStand .NET steps: power supplies, DMMs, switches, muxes, matrices, oscilloscopes, programmers and serial ports. Use when a sequence must call HAL instead of talking to hardware directly. Assumes the ts-seq-authoring skill (ts-cli) is already known; this skill only adds what is HAL-specific.4---56# Using HAL from TestStand78This skill assumes you already know how to author sequences with `ts-cli` (see9the `ts-seq-authoring` skill): adapters, `TS.SData`, the call list, parameters.10Here you only learn what is specific to HAL.1112## The only entry point1314Use the facade assembly **`B101.Hal.dll`** (`$HAL` in the examples), and nothing15else. The ATE Framework installer leaves it at the framework root:1617```text18C:\Program Files\B101\AteFramework\B101.Hal.dll (64-bit station)19C:\Program Files (x86)\B101\AteFramework\B101.Hal.dll (32-bit station)20```2122Point `TS.SData.AssemblyPath` at that file. A bare `B101.Hal.dll` also resolves23when TestStand finds it on its search path. The native `B101.Hal.Runtime.dll`24sits next to the facade in the same folder; the facade cannot start without it,25so never point at a copy that is missing it.2627- Do **not** reference `B101.Hal.Core.dll` as a step assembly: it only holds28 interfaces and is an implementation detail.29- Do **not** reference, name or import the `B101.Hal.Wrappers` types.30- The only usable API is the **`Hal` class and its instance**: create it with31 `new Hal()` and use what that instance exposes (its interface32 implementations and their methods).3334Pick the facade that matches the installed TestStand: the `net8` one for35TestStand 2023 or newer (2025, 2026), and the `net48/` one for TestStand 202236and older.3738## Sequence shape3940Create the `Hal` instance **once** and reuse it for the whole sequence.4142- First step: `Calls[0]` is the constructor `B101.Hal.Hal`; store the result in43 an object reference variable (`Locals.Hal` here).44- Every later step: `Calls[0]` is `Use Existing Object` bound to `Locals.Hal`,45 then `Calls[1]` is the method of the interface implementation you need.4647```bash48# The instance variable is created once.49ts-cli add-prop --file "$SEQ" --sequence MainSequence \50 --path Hal --type reference5152# First step: create the instance and keep it.53ts-cli set-prop --file "$SEQ" --step-id "$ID" \54 --path TS.SData.AssemblyPath --text "$HAL"55ts-cli set-prop --file "$SEQ" --step-id "$ID" \56 --path TS.SData.ClassName --text "B101.Hal.Hal"57ts-cli set-prop --file "$SEQ" --step-id "$ID" \58 --path TS.SData.Calls[0].MemberName --text "Hal"59ts-cli set-prop --file "$SEQ" --step-id "$ID" \60 --path TS.SData.Calls[0].MemberType --number 461ts-cli set-prop --file "$SEQ" --step-id "$ID" \62 --path "TS.SData.Calls[0].Params[0].Name" --text "Return Value"63ts-cli set-prop --file "$SEQ" --step-id "$ID" \64 --path "TS.SData.Calls[0].Params[0].ArgVal" --text "Locals.Hal"65ts-cli set-prop --file "$SEQ" --step-id "$ID" \66 --path "TS.SData.Calls[0].Params[0].TypeName" --text "B101.Hal.Hal"6768# Later step: use the existing instance.69ts-cli set-prop --file "$SEQ" --step-id "$ID" \70 --path TS.SData.AssemblyPath --text "$HAL"71ts-cli set-prop --file "$SEQ" --step-id "$ID" \72 --path TS.SData.Calls[0].MemberName --text "Use Existing Object"73ts-cli set-prop --file "$SEQ" --step-id "$ID" \74 --path TS.SData.Calls[0].MemberType --number 675ts-cli set-prop --file "$SEQ" --step-id "$ID" \76 --path "TS.SData.Calls[0].Params[0].Name" --text "Existing Object"77ts-cli set-prop --file "$SEQ" --step-id "$ID" \78 --path "TS.SData.Calls[0].Params[0].ArgVal" --text "Locals.Hal"79ts-cli set-prop --file "$SEQ" --step-id "$ID" \80 --path "TS.SData.Calls[0].Params[0].TypeName" --text "B101.Hal.Hal"81```8283Never store an instrument in a variable: keep only the `Hal` instance and reach84the instrument from it inside each operation step.8586## Reaching an instrument operation8788An instrument cannot be instantiated or stored on its own. The only shape is89one step per operation that, from the `Hal` instance, calls the instrument90method and immediately the action on what it returns:9192- `Calls[0]` = `Use Existing Object` on `Locals.Hal`.93- `Calls[1]` = the instrument method that returns the implementation94 (`PowerSupply("PSU1")`).95- `Calls[2]` = the action on that implementation (`SetVoltage(...)`).9697So `SetVoltage` is never called on a stored power supply: it always follows its98`PowerSupply(...)` call inside the same step.99100The **module class** (`TS.SData.ClassName`) is always **`B101.Hal.Hal`**, the101root of everything. Every call also carries its own `ClassName`: `B101.Hal.Hal`102on the calls that go through the HAL instance, and the **instrument interface**103(`B101.Hal.Core.Interfaces.IPowerSupply`, ...) on the call that runs the104action. The object a call receives or returns carries that type in `TypeName`.105106## Interfaces exposed by the instance107108- `IInstrument` (SCPI base): `Connect`, `Disconnect`, `Write`, `Query`.109- `IPowerSupply`: `SetVoltage`, `SetCurrentLimit`, `SetOVP`, `SetOCP`, `Enable`,110 `Disable`, `IsOutputEnabled`, `MeasureVoltage`, `MeasureCurrent`, `Reset`.111- `IDMM`: `ConfigureFunction`, `Measure`, `AutoZero`, `SetNplc`.112- `ISwitch`: `Close`, `Open`, `OpenAll`, `IsClosed`.113- `IMux` (extends `ISwitch`): `ConfigureChannel`, `AutoZero`.114- `IMatrix`: `Connect`, `Disconnect`, `ConnectMultiple`, `DisconnectAll`,115 `IsConnected`.116- `IOscilloscope`: `ConfigureChannel`, `SetTimebase`, `Run`, `Single`,117 `FetchWaveform`, `Measure`.118- `IProgrammer`: `Connect`, `Flash`, `Verify`, `Erase`, `Reset`.119- `ISerialComm`: `Configure`, `Open`, `Read`, `Write`, `SendReceive`.120121Method arguments become step parameters (see `ts-seq-authoring`). Enums such as122`DmmFunction` are passed as their numeric or string value.123124## Rules125126- Only `B101.Hal.dll` and the `Hal` instance; never `B101.Hal.Core`, never127 wrappers.128- The module class is always `B101.Hal.Hal`; instrument calls use the instrument129 interface as their call class.130- Create `Hal` once and reuse the instance; do not construct it per step.131- Never instantiate or store an instrument: each operation step calls the132 instrument method and then its action, in that order.133- Names are the unspaced .NET identifiers, not display names.134- Authoring only: this skill never runs sequences, deploys or touches hardware.