This page shows how to list, read and write the physical inputs and outputs of a Staubli CS8 or CS9 controller with the SDK: digital, analog and the other I/O of the boards of the controller. No VAL 3 program is needed.

## List the I/O

`GetAllPhysicalIos()` returns every physical I/O of the controller, with its name, its type and its description.

**C# : IoList**
```csharp
using UnderAutomation.Staubli;
using UnderAutomation.Staubli.Soap.Data;

public class IoList
{
    static void Main()
    {
        var controller = new StaubliController();
        controller.Connect("192.168.0.254");

        /**/
        // Every physical I/O of the controller
        PhysicalIo[] ios = controller.Soap.GetAllPhysicalIos();

        foreach (PhysicalIo io in ios)
        {
            // TypeStr: din, dout, ain, serial...
            Console.WriteLine($"{io.Name} [{io.TypeStr}] {io.Description} lockable={io.Lockable}");
        }
        /**/

        controller.Disconnect();
    }
}
```

**Python : IoList**
```python
from underautomation.staubli.staubli_controller import StaubliController

controller = StaubliController()
controller.connect("192.168.0.254")

##
# Every physical I/O of the controller
ios = controller.soap.get_all_physical_ios()

for io in ios:
    # type_str: din, dout, ain, serial...
    print(f"{io.name} [{io.type_str}] {io.description} lockable={io.lockable}")
##

controller.disconnect()
```

**Matlab : IoList**
```matlab
NET.addAssembly(fullfile(pwd, 'net48', 'UnderAutomation.Staubli.dll'));
import UnderAutomation.Staubli.*

controller = StaubliController();
controller.Connect('192.168.0.254');

%%
% Every physical I/O of the controller
ios = controller.Soap.GetAllPhysicalIos();

% .NET arrays are indexed from 1 in Matlab
for i = 1:ios.Length
    io = ios(i);
    fprintf('%s [%s] %s\n', char(io.Name), char(io.TypeStr), char(io.Description));
end
%%

controller.Disconnect();
```

The name identifies the I/O in the read and write methods. It contains the board and the I/O, separated by a backslash, for example `BasicIO-1\%I0`. The boards depend on the configuration of each controller: read the names with `GetAllPhysicalIos()`, do not guess them. In C#, write the name as a verbatim string (`@"BasicIO-1\%I0"`), in Python as a raw string (`r"BasicIO-1\%I0"`).

`TypeStr` gives the type, for example `din` or `dout` for a digital input or output, `ain` for an analog input, `serial` for a serial line.

## Read I/O

`ReadIos(names)` reads several I/O in one request. It returns one `PhysicalIoState` per name, in the same order.

**C# : IoRead**
```csharp
using UnderAutomation.Staubli;
using UnderAutomation.Staubli.Soap.Data;

public class IoRead
{
    static void Main()
    {
        var controller = new StaubliController();
        controller.Connect("192.168.0.254");

        /**/
        // Names as returned by GetAllPhysicalIos
        string[] names = { @"BasicIO-1\%I0", @"BasicIO-1\%Q0" };

        // One state per name, in the same order
        PhysicalIoState[] states = controller.Soap.ReadIos(names);

        for (int i = 0; i < names.Length; i++)
        {
            PhysicalIoState state = states[i];

            // State tells if the name exists on this controller
            if (state.State != PhysicalIoEnumState.Defined)
            {
                Console.WriteLine($"{names[i]}: {state.State}");
                continue;
            }

            Console.WriteLine($"{names[i]} = {state.Value} locked={state.Locked} simulated={state.Simulated}");
        }
        /**/

        controller.Disconnect();
    }
}
```

**Python : IoRead**
```python
from underautomation.staubli.staubli_controller import StaubliController
from underautomation.staubli.soap.data.physical_io_enum_state import PhysicalIoEnumState

controller = StaubliController()
controller.connect("192.168.0.254")

##
# Names as returned by get_all_physical_ios
names = [r"BasicIO-1\%I0", r"BasicIO-1\%Q0"]

# One state per name, in the same order
states = controller.soap.read_ios(names)

for name, state in zip(names, states):
    # state tells if the name exists on this controller
    if state.state != PhysicalIoEnumState.Defined:
        print(f"{name}: {state.state.name}")
        continue

    print(f"{name} = {state.value} locked={state.locked} simulated={state.simulated}")
##

controller.disconnect()
```

**Matlab : IoRead**
```matlab
NET.addAssembly(fullfile(pwd, 'net48', 'UnderAutomation.Staubli.dll'));
import UnderAutomation.Staubli.*

controller = StaubliController();
controller.Connect('192.168.0.254');

%%
% Names as returned by GetAllPhysicalIos, in a .NET string array
names = NET.createArray('System.String', 2);
names(1) = 'BasicIO-1\%I0';
names(2) = 'BasicIO-1\%Q0';

% One state per name, in the same order
states = controller.Soap.ReadIos(names);

for i = 1:states.Length
    fprintf('%s = %g\n', char(names(i)), states(i).Value);
end
%%

controller.Disconnect();
```

- `State` is `Defined` when the name exists, `Undefined` or `InvalidName` otherwise. Test it before you use the value.
- `Value` is a number: `0` or `1` for a digital I/O.
- `Locked` and `Simulated` tell if the I/O is locked or simulated on the controller.

## Write I/O

`WriteIos(names, values)` writes several outputs in one request. The two arrays have the same length.

**C# : IoWrite**
```csharp
using UnderAutomation.Staubli;
using UnderAutomation.Staubli.Soap.Data;

public class IoWrite
{
    static void Main()
    {
        var controller = new StaubliController();
        controller.Connect("192.168.0.254");

        /**/
        string[] names = { @"BasicIO-1\%Q0", @"BasicIO-1\%Q1" };

        // One value per name. Digital outputs: 1 is on, 0 is off
        double[] values = { 1, 0 };

        PhysicalIoWriteResponse[] responses = controller.Soap.WriteIos(names, values);

        for (int i = 0; i < names.Length; i++)
        {
            if (!responses[i].Found)
                Console.WriteLine($"{names[i]}: unknown name");
            else if (!responses[i].Success)
                Console.WriteLine($"{names[i]}: write refused");
        }
        /**/

        controller.Disconnect();
    }
}
```

**Python : IoWrite**
```python
from underautomation.staubli.staubli_controller import StaubliController

controller = StaubliController()
controller.connect("192.168.0.254")

##
names = [r"BasicIO-1\%Q0", r"BasicIO-1\%Q1"]

# One value per name. Digital outputs: 1 is on, 0 is off
values = [1.0, 0.0]

responses = controller.soap.write_ios(names, values)

for name, response in zip(names, responses):
    if not response.found:
        print(f"{name}: unknown name")
    elif not response.success:
        print(f"{name}: write refused")
##

controller.disconnect()
```

**Matlab : IoWrite**
```matlab
NET.addAssembly(fullfile(pwd, 'net48', 'UnderAutomation.Staubli.dll'));
import UnderAutomation.Staubli.*

controller = StaubliController();
controller.Connect('192.168.0.254');

%%
names = NET.createArray('System.String', 2);
names(1) = 'BasicIO-1\%Q0';
names(2) = 'BasicIO-1\%Q1';

% One value per name. Digital outputs: 1 is on, 0 is off
values = [1, 0];

responses = controller.Soap.WriteIos(names, values);

for i = 1:responses.Length
    if ~responses(i).Found || ~responses(i).Success
        fprintf('%s: write refused\n', char(names(i)));
    end
end
%%

controller.Disconnect();
```

The answer has one `PhysicalIoWriteResponse` per name:

- `Found` is `false` when the name does not exist.
- `Success` is `false` when the controller refused the write, for example for an input.

## Try it in the demo application



## Reference

**Methods of SoapClientBase**
```csharp
// Get all the physical I/O values of the controller
PhysicalIo[] GetAllPhysicalIos();

// Read the state of specified physical I/Os
PhysicalIoState[] ReadIos(string[] ios);

// Write values to specified physical I/Os
PhysicalIoWriteResponse[] WriteIos(string[] ios, double[] values);
```

Every method also exists in an asynchronous version, with the same name followed by `Async` and an optional `CancellationToken`.

**Members of Soap.Data.PhysicalIo**
```csharp
public class PhysicalIo {
    public PhysicalIo()

    // Description of the physical I/O.
    public string Description { get; set; }

    public override bool Equals(object obj)

    public override int GetHashCode()

    // Indicates whether the physical I/O is lockable.
    public bool Lockable { get; set; }

    // Name of the physical I/O.
    public string Name { get; set; }

    public override string ToString()

    // Type of the physical I/O (e.g., din, dout, ain, serial, ...).
    public string TypeStr { get; set; }
}
```

**Members of Soap.Data.PhysicalIoState**
```csharp
public class PhysicalIoState {
    // Initializes a new instance of the <xref href="UnderAutomation.Staubli.Soap.Data.PhysicalIoState" data-throw-if-not-resolved="false"></xref> class.
    public PhysicalIoState()

    // I/O type-specific attributes (analog or digital).
    public PhysicalIoAttribute Attribute { get; set; }

    public override bool Equals(object obj)

    public override int GetHashCode()

    // Indicates whether the I/O is locked.
    public bool Locked { get; set; }

    // Indicates whether the I/O is in simulation mode.
    public bool Simulated { get; set; }

    // Definition state of the I/O.
    public PhysicalIoEnumState State { get; set; }

    public override string ToString()

    // Current numeric value of the I/O.
    public double Value { get; set; }
}
```

**Members of Soap.Data.PhysicalIoEnumState**
```csharp
public enum PhysicalIoEnumState {
    // The I/O is defined and available.
    Defined = 0

    // The I/O name is invalid.
    InvalidName = 2

    // The I/O is not defined.
    Undefined = 1
}
```

**Members of Soap.Data.PhysicalIoWriteResponse**
```csharp
public class PhysicalIoWriteResponse {
    // Initializes a new instance of the <xref href="UnderAutomation.Staubli.Soap.Data.PhysicalIoWriteResponse" data-throw-if-not-resolved="false"></xref> class.
    public PhysicalIoWriteResponse()

    public override bool Equals(object obj)

    // Indicates whether the specified I/O was found.
    public bool Found { get; set; }

    public override int GetHashCode()

    // Indicates whether the write operation succeeded.
    public bool Success { get; set; }

    public override string ToString()
}
```

**Members of Soap.Data.PhysicalIoAttribute**
```csharp
public class PhysicalIoAttribute {
    // Initializes a new instance of the <xref href="UnderAutomation.Staubli.Soap.Data.PhysicalIoAttribute" data-throw-if-not-resolved="false"></xref> class.
    public PhysicalIoAttribute()

    // Analog I/O specific attributes (null if digital).
    public PhysicalAioAttribute AioAttribute { get; set; }

    // Digital I/O specific attributes (null if analog).
    public PhysicalDioAttribute DioAttribute { get; set; }

    public override bool Equals(object obj)

    public override int GetHashCode()

    public override string ToString()
}
```