Serial Device - Hot plug

The introduction of a containerized environment for daemon processes inside a URCapX changes the way it can access serial devices. The following section describes how serial devices work together with PolyScope X and how they can be implemented the intended way.

Conceptual Background and device ownership in URCapXs

  • We implement exclusive ownership of devices, so that only one URCapX is able to access a device at a time. This prevents different URCapXs from disturbing each other’s communication.

  • Devices are handled as “hot plug,” i.e., they are added and removed to URCapXs dynamically based on the device being added / removed on the host system or changes URCapX owner (in the case of ttyTool or possibly GUI-based assignment in the future).

  • We implement the URCapXs’ access rights as narrowly as possible, only allowing access to specific devices and during specific times.

API to URCapX containers / device ownership

  • Like on a normal Linux system, URCapX containers are expected to handle devices being added to or removed from the system (or more specifically to their container) at runtime.

  • URCapX containers always start (or restart) without any device access. Devices are subsequently mounted into the URCapX container if it is of a type that matches the device type in the manifest file, and one of the following conditions is met:

    • The device is attached to the host (and powered on), and the URCapX has previously “owned” the device.

    • The device is attached to the host (and powered on), and the device has no owner (i.e., no installed URCapX “owns” the device).

    • A new device is attached to the host.

  • A host system startup / reboot is indistinguishable from a URCapX start / restart with respect to devices.

  • URCapXs device ownership is based on physical devices, i.e., it will be given access to all device files of a physical device or none.

  • URCapX containers only have access to the device files, such as /dev/ttyUSB0 but not to the low-level device control in /sys/bus/usb/* for now.

Device add protocol

  • Devices are made accessible to URCapXs in the following events:

    • The device is physically added to the host.

    • System reboot.

    • URCapX restart.

    • Device access is moved from one URCapX to another via GUI (in the future).

  • The UR platform implements a rudimentary ownership model:

    • Only one URCapX can “own” a device.

    • When a new device is added or unclaimed devices are found during a system reboot or URCapX restart, they are offered to all potential URCapX owners (matching settings in the manifest.yaml file and not having rejected the device, yet) one-by-one until a URCapX takes ownership of the device.

    • If a URCapX “owns” a device, it is offered the device first upon the events named above.

  • Devices are made accessible to a URCapX through the following add-protocol:

    • All the physical device’s device files (“logical devices”) are created in the container’s /dev folder and the proper access permissions are set.

    • The /on_device_add hook executable is called in the URCapX’s container with a single JSON string as an argument. The JSON string (see specification below) contains information about the added device, the logical devices, etc.

      • /on_device_add is implemented by the URCapX. It should return quickly. It must return within a timeout period of 10 seconds or will be forcefully terminated. Giving a fairly generous timeout and already having the device mounted into the container gives the URCapX the possibility to communicate with the device to identify it.

      • /on_device_add is called regardless of previous ownership of the device.

    • Based on the return code of /on_device_add we decide whether the URCapX keeps the device and “owns” it in the future or not:

      • Return code 0 means the URCapX accepts the device and will be its exclusive owner in the future. The device will stay mounted in the URCapX’s container.

      • Return code not 0, or timeout is interpreted as the URCapX rejecting the device. The device will subsequently be removed from the container WITHOUT a call to the /on_device_remove hook. Afterward, the device is possibly offered to other URCapXs.

  • Note that in practice, the above means that:

    • From the URCapX’s point of view, there is no difference between any of the events with respect to device handling. Specifically, a system reboot and a URCapX restart are indistinguishable.

    • In the protocol, there is no difference between a new device and a previously owned device being added to a container. If such information is required, the URCapX is responsible for IDing the device and persistently storing information about previous ownership.

Device remove protocol

  • Device access is removed from URCapX containers in the following events:

    • The device is physically removed from the host.

    • Device access is removed via GUI (in the future).

  • The /on_device_remove hook executable is called in the URCapX’s container informing the URCapX about the removal of the device before the logical devices and permissions are removed. However, in cases where a device is physically removed, the communication to the device will likely fail BEFORE /on_device_remove is called.

  • /on_device_remove will be called with a single JSON string as an argument. The JSON string will have the same format as for the call to /on_device_add, however, the contained information naturally contains information about the removed device.

  • /on_device_remove is purely informative and will time out after 1 second.

Handling of ttyTool

  • ttyTool will in general be handled just like any other device, with the following exceptions:

    • Ownership of ttyTool will be allowed to change at program runtime to support tool-changer functionality in the future. It is planned that the set_tool_communication() URScript function will allow the user to switch the device ownership. Currently, the ownership is static.

    • Setting baud rate, parity, etc. through the device file is currently not supported and has to be done through set_tool_communication().

    • The device information like idVendor etc. does not represent the device that is actually attached to the tool-flange.

  • In case of ownership change, adding / removing ttyTool to a URCapX’s container will go through the standard device add / remove protocols. As noted above, setting communication settings such as baud rate is expected to happen through set_tool_communication()

Guaranteed and Non-guaranteed behavior

  • A device with a device file mounted in a URCapX at e.g. “/dev/ttyUSB0” is NOT guaranteed to be mounted at the same path again after a reboot. If unique identification of devices is required, URCapX must implement their own identification based on the information passed to the on_device_add hook.

  • The Reasoning behind this:

    • We want to keep the standard node names such as “/dev/ttyUSB0” or “/dev/video0”, as many libraries hardcode these names, especially when trying to access video streams.

    • We want to keep the device files consistent with the underlying device minor / major numbers (which are defined by the host system and the order of plugging in the devices). E.g. “/dev/ttyACM0” is always created for the device with major 166, minor 0 on a standard Linux system, as specified in https://www.kernel.org/doc/Documentation/admin-guide/devices.txt.

  • A URCapX is guaranteed to get a call to its on_device_add and on_device_remove if a device is added or removed (and the criteria for ownership at met).

  • A URCapX is guaranteed to have exclusive access to a device as long as it is accessible in the container.

  • Attached USB devices have proper, unique serial numbers (per vendor and product), i.e., the tuple of (idProduct, idVendor, serial number) must be unique.

URCapX hook JSON format

Note that the format can be extended in the future, so URCapXs should implement a way of parsing the JSON-payload that discards unknown fields to be future-proof. Example:

{
"idProduct": "23a3",
"idVendor": "067b",
"logicalDevices": [
    { "deviceNode": "/dev/ttyUSB0",
        "major": 188,
        "minor": 0
    },
    ...
],
"manufacturer": "Prolific Technology Inc.",
"product": "ATEN USB to Serial Bridge",
"serial": "DNCIb114J20",
"urDeviceType": "serial",
"urDeviceAPIVersion": "0.1"
}

Notes on the format:

  • Minimal information

  • We do not include information about whether the URCapX has been “owner” of this device before. If such information is needed, the URCapX needs to identify previously owned devices through a (idVendor, idProduct, serial) tuple.

  • Apart from urDeviceType, and urDeviceAPIVersion, device information are from the Linux device subsystem, see http://www.Linux-usb.org/usb.ids

  • LogicalDevice information follow https://www.kernel.org/doc/Documentation/admin-guide/devices.txt