Skip to content

User Container

The user container setup is designed to support all the included hardware. A number of external devices will also be supported by the USB host controller. The initial support will be for audio, video, mass storage devices and Kvaser USB CAN devices.

Device information

Device information can be retrieved from the device tree under kvaser-parameters.

Examples:

# Read serial number
$ cat /proc/device-tree/kvaser-parameters/serial-number
1234

# Read EAN code
$ cat /proc/device-tree/kvaser-parameters/ean
73-30130-99999-9

USB Mass Storage Devices

Any FAT-formatted partition of a connected USB mass storage is automatically mounted under /host/mnt/<mountpoint>, where <mountpoint> is either the partition label, or if no label exists the device's USB iProduct string.

Note

Every partition on all connected devices must use unique labels (or have unique USB iProduct strings), otherwise the resulting behavior is undefined.

Multicolor LED Handling

The system groups red, green, and blue LEDs into multicolor LEDs using the LED class multicolor interface. This makes it convenient to manage each RGB LED as a single logical unit.

Examples:

# Check which color channels are available
$ cat /sys/class/leds/multi\:led1/multi_index
red green blue

# Set individual RGB values
$ echo 50 100 200 > /sys/class/leds/multi\:led1/multi_intensity

# Set overall brightness
$ echo 100 > /sys/class/leds/multi\:led1/brightness

Each multicolor LED "owns" the underlying color LEDs, meaning they cannot be controlled directly while bound.

If direct control of individual channels is needed, you can unbind the multicolor LED:

$ echo led1-multi > /sys/bus/platform/drivers/leds_group_multicolor/unbind
$ echo 50 > /sys/class/leds/green\:led1/brightness

Note

Unbinding disables grouped control, so RGB values can no longer be set together via the multicolor interface.

GPIO

The available GPIO pins can be found in gpiochip5 (/dev/gpiochip5). They can be accessed with libgpiod. If you are building your own custom container image you can add gpiod to the package list (see mkosi), otherwise see the build instructions for libgpiod.

To list all available GPIO lines and their properties:

$ gpioinfo

To monitor an input pin:

$ gpiomon NAME_OF_GPIO_LINE

Note

On distros with libgpiod older than v2.0, the libgpiod tools doesn't resolve GPIO line names. Use gpiochip name and offset instead i.e "$ gpiomon gpiochip5 0". Or resolve the name with gpiofind i.e "$ gpiomon $(gpiofind NAME_OF_GPIO_LINE)"

To set and get the value of gpio lines:

$ gpioset NAME_OF_GPIO_LINE=1
$ gpioget NAME_OF_GPIO_LINE

For further information and examples check the libgpiod documentation.

IMU

The available devices are an accelerometer, lsm6dso_accel, and a gyroscope, lsm6dso_gyro. Use iio_info to list available devices and their properties:

$ iio_info

libiio provides tools and utilities to interact with the IMU devices, there is a command line tool, libiio-util, there is also a C service library, libiio-dev. It is also possible to access the raw device, /dev/iio:deviceX and it's correponding sysfs attributes in /sys/bus/iio/devices/iio:deviceX, but the device numbers may change between boots and updates.

Polling mode

In polling mode the values of the device is read directly, this can be done using iio-attr from libiio-utils. Hardware timestamping is not supported in this mode.

Gyroscope example:

$ iio_attr -c lsm6dso_gyro anglvel_x raw

This would get the raw value for the x-axis of the gyroscope.

Accelerometer example:

$ iio_attr -c lsm6dso_accel accel_z raw
$ iio_attr -c lsm6dso_accel accel_z scale

The z-axis value can then be multiplied by the scale value and the result should be around 9.81 m/s^2, when the unit is lying flat on a table.

Buffer mode

In buffer mode iio_readdev is used to specify which channels to sample and iio_attr can be used to change device and channel attributes before hand, use iio_info to find the available attributes. Hardware timestamping is supported in this mode.

The sampling frequency can be adjusted to one of the available frequencies. When using smaller sampling frequencies the buffer needs to be adjusted to a smaller size to not run into buffer errors.

# Get the available frequencies of the device
$ iio_attr -d lsm6dso_accel sampling_frequency_available
# Set the desired frequency
$ iio_attr -d lsm6dso_accel sampling_frequency 26

Example:

$ iio_readdev -b 1 -s 4 lsm6dso_gyro anglvel_x anglvel_y anglvel_z timestamp > data.dat

The example would write four samples of the angle velocity in the x-, y- and z-axises, as well as the timestamp, to data.dat.

The output is binary data. hexdump can be used for inspecting the samples.

$ hexdump -d data.dat

GPS/GNSS

The GPS device can be found at /dev/gnss0, to monitor geo-location data gpsd can be used. gpsd supplies many different tools to interface with the GNSS receiver, below are some quick examples, to see the full extent check the documentation.

To enable the GNSS device the default configuration need to be edited. Edit the file /etc/defult/gpsd and change the settings to match what is given below:

GPSD_OPTIONS="-n"
DEVICES="/dev/gnss0"

cgps is a terminal client for gpsd and can be used to view data from the GNSS device:

$ cgps

gpsmon can be used to monitor the packets coming from the device and how the packets are displayed can be configured. The full extend can be seen in the documentation.

There is also a C service library, libgps, which enables communication with the daemon. Information and examples can be found here.

Systemd-journal

For support and debugging, the systemd-journal of the host system is available inside the container at /host/journal. Access it with journalctl:

$ journalctl --directory=/host/journal

To make it easier to handle both the host and container journals they can be combined into one.

$ journalctl -i /host/journal/<machine-id>/system.journal -i /var/log/journal/<machine-id>/system.journal

Note

The path to the container systemd-journal directory can change depending on the configuration.

If the system does not need to be restarted frequently the host journal can be symlinked to the containers systemd-journal directory using:

$ ln -s /host/journal/<machine-id> /var/log/journal/

Note

The machine-id of the host is randomized on each boot so the symlink will break when the system is turned off. A systemd service can be setup to handle the symlink on boot, see the mkosi chapter for more details.

Then use the merge flag in journalctl to combine the two journals.

$ journalctl -m

Note

If the containers systemd-journal is configured to be persistent the entries for the host system will occur towards the bottom of the journal since the host systemd-journal is not persistent.

Workarounds

The following table shows some limitations when running in a container and the workarounds.

Regulatory domain control from container

Normally, changing the wireless regulatory domain is restricted to users with CAP_NET_ADMIN in the initial (root) user namespace. This restriction prevents unprivileged containers from managing Wi-Fi region settings.

Workaround

A kernel patch has been applied to allow setting the regulatory domain from any user namespace, as long as the process has CAP_NET_ADMIN inside its namespace.

This makes the following now work from inside the container:

$ iw reg set SE

Warning

Because of this, only trusted code should be granted CAP_NET_ADMIN inside containers. Misuse could lead to regulatory violations or disrupt wireless behavior on the system.

System reboot and suspend

A reboot inside the user container will only restart the container. The container does not have the required privileges for controlling the system power state.

Workaround

Use the hostctl CLI to control host functions.

LED triggers

LED timer trigger control for delay_on/delay_off is created with wrong user/group id. The user/group id is changed by an udev script running in the host system.

Workaround

Add a short delay before accessing the trigger control:

echo timer > /sys/class/leds/\*/trigger
sleep 0.1
echo 100 > /sys/class/leds/\*/delay_on

System time

System time can not be set from the container.

Workaround

An ntpd service is running with privileges for setting system time. The status of the service can be checked with commands such as ntpstat or ntpq.

No udevd

In the user container there is no udev. Standard services containing device unit configurations wont work, i.e. Requires=sys-subsystem-net-devices-%i.device.

Workaround

Comment out the device dependency:

$ systemctl edit --full wpa_supplicant-nl80211@.service
$ systemctl cat wpa_supplicant-nl80211@.service
# /etc/systemd/system/wpa_supplicant-nl80211@.service
[Unit]
Description=WPA supplicant daemon (interface- and nl80211 driver-specific version)
#Requires=sys-subsystem-net-devices-%i.device
After=sys-subsystem-net-devices-%i.device
Before=network.target
Wants=network.target
...