Simple Peripherals¶
Note
This guide describes how to access peripherals using the Linux 5.2 kernel. Earlier versions of Linux used on the Librem 5 development board expose some peripherals to user space differently.
The Librem 5 development board has a number of peripherals that allow applications to interact with users and the outside world in a simple way. This guide covers these I/O peripherals and describes how to use them.
Peripherals that handle input are typically readable by any user but some that allow output, such as LEDs, can only be written by the root user.
Finding Device Files¶
Some of the peripherals are accessed via device files in the /dev/input
directory. One way to determine which device file is used to access a
particular peripheral is to open a console on the development board and run the
evtest
tool:
sudo evtest
This should produce a list of devices to monitor, like the following, though the paths to these files may change from one version of the kernel to the next:
/dev/input/event0: gpio-keys
/dev/input/event1: bd718xx-pwrkey
/dev/input/event2: 30370000.snvs:snvs-powerkey
/dev/input/event3: gpio-vibrator
/dev/input/event4: Goodix Capacitive TouchScreen
Press Ctrl-C to exit the tool unless you want to monitor a device. Make a note of the device file that corresponds to the peripheral you want to access.
Light Emitting Diodes (LEDs)¶
Only one of the LEDs can be controlled by applications. This red diode is
mapped to the /sys/class/leds/LED 1
directory in the file system and its
state can be changed by writing to the /sys/class/leds/LED 1/brightness
file, as in this shell command:
echo 255 > /sys/class/leds/LED\ 1/brightness
Using the default system configuration, writing a value of 0 to the file will
switch the LED off. Writing a value from 1 to 255 will switch it on. Reading
from the file returns the value previously used to set the brightness of the
LED. The maximum brightness can be read from the
/sys/class/leds/LED 1/max_brightness
file:
cat /sys/class/leds/LED\ 1/max_brightness
The LED can also be controlled using the python-periphery library:
leds.py
#!/usr/bin/env python3
import periphery
# Obtain an object for the LED.
led = periphery.LED("LED 1")
# Read the current brightness.
brightness = led.read()
# Switch the LED on.
led.write(1)
# Switch the LED off.
led.write(0)
The lack of control over the brightness of the LED is because it is driven by a Pulse Width Modulator (PWM) that it shares with the haptic motor, and the default kernel device tree configures the motor to use the PWM. If a different device tree is used with the kernel, this behavior can be adjusted.
Haptic Motor¶
The haptic motor is treated as an input device that provides force feedback
effects. Use the evtest
tool as described earlier to find the path to the
device file that is used to access the motor.
Test that the device is working by running the fftest
tool that is provided
as part of the joystick
Debian package, passing the path to the device file
that corresponds to the motor:
fftest <device file>
Another way to control the motor is to use the python-evdev package:
haptic.py
#!/usr/bin/env python3
import evdev
import sys
import time
# Obtain an object for the motor.
for path in evdev.list_devices():
device = evdev.InputDevice(path)
if evdev.ecodes.EV_FF in device.capabilities():
break
else:
sys.stderr.write('Failed to find the haptic motor.\n')
sys.exit(1)
# Define a rumble effect.
rumble = evdev.ff.Rumble(strong_magnitude=0xff, weak_magnitude=0xffff)
# Create an effect type and duration.
effect_type = evdev.ff.EffectType(ff_rumble_effect=rumble)
duration = 1000
# Create the effect itself.
effect = evdev.ff.Effect(evdev.ecodes.FF_RUMBLE, -1, 0,
evdev.ff.Trigger(0, 0),
evdev.ff.Replay(duration, 0),
effect_type)
# Upload the effect to the device and obtain an ID.
effect_id = device.upload_effect(effect)
# Write the event to the device to play the effect just once.
device.write(evdev.ecodes.EV_FF, effect_id, 1)
time.sleep(duration / 1000.0)
# Erase the effect once we are finished with it.
device.erase_effect(effect_id)
The haptic motor shares a PWM with the red LED. In the device tree used by the default kernel the PWM is used to control the amplitude of the haptic motor, restricting the state of the LED to being either on or off. If a different device tree is used with the kernel, this behavior can be adjusted.
More information about the different parameters used for force feedback effect, see the Force feedback for Linux documentation.
Push Buttons¶
User input from the volume up, volume down and power push buttons can be read.
Events from these buttons are delivered to device files that can be found using
the evtest
tool as described earlier. Events from the volume buttons are
delivered to a separate device file to those from the power button.
Events can also be read using the python-evdev package:
buttons.py
#!/usr/bin/env python3
import evdev
import select
import sys
VOLUME_DOWN = 114
VOLUME_UP = 115
POWER = 116
# Obtain objects for the input devices.
devices = []
for path in evdev.list_devices():
device = evdev.InputDevice(path)
if evdev.ecodes.EV_KEY in device.capabilities():
devices.append(device)
if not devices:
sys.stderr.write('Failed to find any key input devices.\n')
sys.exit(1)
fds = dict([(device.fd, device) for device in devices])
while True:
# Wait for an event.
r, w, x = select.select(fds.keys(), [], [])
# Read the events for the device.
for fd in r:
device = fds[fd]
for event in device.read():
pressed = {0: "released", 1: "pressed"}[event.value]
if event.code == VOLUME_UP:
print("volume up", pressed)
elif event.code == VOLUME_DOWN:
print("volume down", pressed)
elif event.code == POWER:
print("power", pressed)
The python-evdev tutorial shows several ways of handling events that can be applied to various situations, using different techniques to read the event queue.
Headphone Connection¶
Note
This section requires revision.
Input events are generated when a headphone jack is inserted into or removed
from the headphone socket. These events are delivered to the
/dev/input/event0
file together with push button events. As with the
buttons, the evtest
command can be used to examine the events:
sudo evtest /dev/input/event0
This will listen for headphone connection events and write them in human-readable form to the console.
Events can also be read using the python-evdev package:
headphones.py
#!/usr/bin/env python3
import evdev
import select
HEADPHONE_CONNECT = 211
# Obtain an object for the input device.
device = evdev.InputDevice('/dev/input/event0')
while True:
# Wait for an event.
r, w, x = select.select([device.fd], [], [])
# Read the events for the device.
for event in device.read():
if event.code == HEADPHONE_CONNECT:
connected = {0: "connected", 1: "disconnected"}[event.value]
print("headphones", connected)
It may be necessary to combine reading of headphone connection events with those from the push buttons, even if they are handled separately.