resonance.api.core.dio

resonance.api.core.dio

DIOAccessor(conn)

Async interface for reading and writing BCS digital I/O channels.

Parameters:

Name Type Description Default
conn BCSServer

Active BCSz server connection.

required
Notes

Wraps BCSz digital I/O channels. read reads digital inputs; set writes digital outputs. The shutter channel ("Light Output", "Shutter Output", etc.) is the most common use case. Values are always coerced to bool.

Examples:

>>> state = await bl.dio.read("Shutter Output", "Light Output")
>>> print(state)
{'Shutter Output': True, 'Light Output': True}
>>> await bl.dio.set("Shutter Output", False)
>>> await bl.dio.set("Light Output", True)
>>> state = await bl.dio.read("Shutter Output", "Light Output")
>>> print(state)
{'Shutter Output': False, 'Light Output': True}
Source code in src/resonance/api/core/dio.py
def __init__(self, conn: BCSz.BCSServer) -> None:
    self._conn = conn

read(*channels) async

Read current state of one or more digital I/O channels.

Parameters:

Name Type Description Default
*channels str

One or more DIO channel names to read. Must be members of the DIO literal type.

()

Returns:

Type Description
dict[str, bool]

Mapping of channel name to its current boolean state.

Raises:

Type Description
KeyError

If any channel name is not a valid DIO channel.

Notes

Channels are read in a single BCSz get_di call. The response data field is coerced to bool for each channel.

Source code in src/resonance/api/core/dio.py
async def read(self, *channels: str) -> dict[str, bool]:
    """
    Read current state of one or more digital I/O channels.

    Parameters
    ----------
    *channels : str
        One or more DIO channel names to read. Must be members of the
        ``DIO`` literal type.

    Returns
    -------
    dict[str, bool]
        Mapping of channel name to its current boolean state.

    Raises
    ------
    KeyError
        If any channel name is not a valid DIO channel.

    Notes
    -----
    Channels are read in a single BCSz ``get_di`` call. The response
    ``data`` field is coerced to bool for each channel.
    """
    invalid = [c for c in channels if c not in _valid_channels]
    if invalid:
        raise KeyError(
            f"Unknown DIO channel(s): {invalid}. Valid channels: {list(_valid_channels)}"
        )

    response: dict = await self._conn.get_di(chans=list(channels))
    return {
        chan: bool(data) for chan, data in zip(response["chans"], response["data"])
    }

set(channel, value) async

Set a digital output channel to True (on) or False (off).

Parameters:

Name Type Description Default
channel str

DIO channel name to write. Must be a member of the DIO literal type.

required
value bool or int

Output value to set. Non-zero integers map to True, zero maps to False.

required

Returns:

Type Description
None

Raises:

Type Description
KeyError

If channel is not a valid DIO channel name.

ValueError

If value is not a bool or int (e.g. a float is passed).

ShutterError

If the BCSz set_do call raises an exception.

Notes

Value is coerced to bool: any non-zero int is True, 0 is False. Typical use is controlling the beamline shutter (e.g. channel="Light Output").

Source code in src/resonance/api/core/dio.py
async def set(self, channel: str, value: bool | int) -> None:
    """
    Set a digital output channel to True (on) or False (off).

    Parameters
    ----------
    channel : str
        DIO channel name to write. Must be a member of the ``DIO`` literal type.
    value : bool or int
        Output value to set. Non-zero integers map to True, zero maps to False.

    Returns
    -------
    None

    Raises
    ------
    KeyError
        If ``channel`` is not a valid DIO channel name.
    ValueError
        If ``value`` is not a bool or int (e.g. a float is passed).
    ShutterError
        If the BCSz ``set_do`` call raises an exception.

    Notes
    -----
    Value is coerced to bool: any non-zero int is True, 0 is False.
    Typical use is controlling the beamline shutter (e.g. channel="Light Output").
    """
    if channel not in _valid_channels:
        raise KeyError(
            f"Unknown DIO channel: {channel!r}. Valid channels: {list(_valid_channels)}"
        )

    if not isinstance(value, bool | int):
        raise ValueError(f"value must be bool or int, got {type(value).__name__!r}")

    bool_value = bool(value)

    try:
        await self._conn.set_do(chan=channel, value=bool_value)
    except Exception as exc:
        raise ShutterError(
            f"Failed to set DIO channel {channel!r} to {bool_value}: {exc}"
        ) from exc