pw_digital_io_linux#
Digital I/O interface for Linux userspace
Unstable C++17
pw_digital_io_linux
implements the pw_digital_io interface
using the Linux userspace gpio-cdev interface.
Note
Currently only the v1 userspace ABI is supported (https://pwbug.dev/328268007).
API reference#
The following classes make up the public API:
LinuxDigitalIoChip
#
Represents an open handle to a GPIO chip (e.g. /dev/gpiochip0
).
This can be created using an existing file descriptor
(LinuxDigitalIoChip(fd)
) or by opening a given path
(LinuxDigitalIoChip::Open(path)
).
LinuxDigitalIn
#
Represents a single input line and implements DigitalIn
.
This is acquired by calling chip.GetInputLine()
with an appropriate
LinuxInputConfig
.
LinuxDigitalInInterrupt
#
Represents a single input line configured for interrupts and implements
DigitalInInterrupt
.
This is acquired by calling chip.GetInterruptLine()
with an appropriate
LinuxInputConfig
.
LinuxDigitalOut
#
Represents a single input line and implements DigitalOut
.
This is acquired by calling chip.GetOutputLine()
with an appropriate
LinuxOutputConfig
.
Warning
The Disable()
implementation only closes the GPIO handle file
descriptor, relying on the underlying GPIO driver / pinctrl to restore
the state of the line. This may or may not be implemented depending on
the GPIO driver.
Guides#
Example code to use GPIO pins:
Configure an input pin and get its state#
1#include "pw_digital_io/polarity.h"
2#include "pw_digital_io_linux/digital_io.h"
3#include "pw_log/log.h"
4#include "pw_status/try.h"
5
6using pw::digital_io::LinuxDigitalIoChip;
7using pw::digital_io::LinuxInputConfig;
8using pw::digital_io::Polarity;
9using pw::digital_io::State;
10
11pw::Status InputExample() {
12 // Open handle to chip.
13 PW_TRY_ASSIGN(auto chip, LinuxDigitalIoChip::Open("/dev/gpiochip0"));
14
15 // Configure input line.
16 LinuxInputConfig config(
17 /* gpio_index= */ 5,
18 /* gpio_polarity= */ Polarity::kActiveHigh);
19 PW_TRY_ASSIGN(auto input, chip.GetInputLine(config));
20 PW_TRY(input.Enable());
21
22 // Get the input pin state.
23 PW_TRY_ASSIGN(State pin_state, input.GetState());
24 PW_LOG_DEBUG("Pin state: %s",
25 pin_state == State::kActive ? "active" : "inactive");
26
27 return pw::OkStatus();
28}
Configure an output pin and set its state#
1#include "pw_digital_io/polarity.h"
2#include "pw_digital_io_linux/digital_io.h"
3#include "pw_status/try.h"
4
5using pw::digital_io::LinuxDigitalIoChip;
6using pw::digital_io::LinuxOutputConfig;
7using pw::digital_io::Polarity;
8using pw::digital_io::State;
9
10pw::Status OutputExample() {
11 // Open handle to chip.
12 PW_TRY_ASSIGN(auto chip, LinuxDigitalIoChip::Open("/dev/gpiochip0"));
13
14 // Configure output line.
15 // Set the polarity to active-low and default state to active.
16 LinuxOutputConfig config(
17 /* gpio_index= */ 4,
18 /* gpio_polarity= */ Polarity::kActiveLow,
19 /* gpio_default_state== */ State::kActive);
20 PW_TRY_ASSIGN(auto output, chip.GetOutputLine(config));
21
22 // Enable the output pin. This pulls the pin to ground since the
23 // polarity is kActiveLow and the default_state is kActive.
24 PW_TRY(output.Enable());
25
26 // Set the output pin to inactive.
27 // This pulls pin to Vdd since the polarity is kActiveLow.
28 PW_TRY(output.SetState(State::kInactive));
29
30 return pw::OkStatus();
31}
Configure an interrupt pin and handle events#
1#include <chrono>
2
3#include "pw_chrono/system_clock.h"
4#include "pw_digital_io_linux/digital_io.h"
5#include "pw_log/log.h"
6#include "pw_status/try.h"
7#include "pw_thread/sleep.h"
8#include "pw_thread/thread.h"
9#include "pw_thread_stl/options.h"
10
11using namespace std::chrono_literals;
12
13using pw::digital_io::InterruptTrigger;
14using pw::digital_io::LinuxDigitalIoChip;
15using pw::digital_io::LinuxGpioNotifier;
16using pw::digital_io::LinuxInputConfig;
17using pw::digital_io::Polarity;
18using pw::digital_io::State;
19
20pw::Status InterruptExample() {
21 // Open handle to chip.
22 PW_TRY_ASSIGN(auto chip, LinuxDigitalIoChip::Open("/dev/gpiochip0"));
23
24 // Create a notifier to deliver interrupts to the line.
25 PW_TRY_ASSIGN(auto notifier, LinuxGpioNotifier::Create());
26
27 // Configure input line.
28 LinuxInputConfig config(
29 /* gpio_index= */ 5,
30 /* gpio_polarity= */ Polarity::kActiveHigh);
31 PW_TRY_ASSIGN(auto input, chip.GetInterruptLine(config, notifier));
32
33 // Configure the interrupt handler.
34 auto handler = [](State state) {
35 PW_LOG_DEBUG("Interrupt handler fired with state=%s",
36 state == State::kActive ? "active" : "inactive");
37 };
38 PW_TRY(input.SetInterruptHandler(InterruptTrigger::kActivatingEdge, handler));
39 PW_TRY(input.EnableInterruptHandler());
40 PW_TRY(input.Enable());
41
42 // There are several different ways to deal with events:
43
44 // Option A: Wait once for events.
45 PW_TRY(notifier->WaitForEvents(0)); // Non-blocking.
46 PW_TRY(notifier->WaitForEvents(500)); // Block for 500 milliseconds.
47 PW_TRY(notifier->WaitForEvents(-1)); // Block indefinitely.
48
49 // Option B: Handle events synchronously, blocking forever.
50 notifier->Run();
51
52 // Option C: Handle events in a separate thread.
53 pw::Thread notifier_thread(pw::thread::stl::Options(), *notifier);
54 pw::this_thread::sleep_for(30s);
55 notifier->CancelWait();
56 notifier_thread.join();
57
58 return pw::OkStatus();
59}
Command-Line Interface#
This module also provides a tool also named pw_digital_io_linux
which
provides a basic command-line interface to the library. It provides the
following sub-commands:
get
#
Configure a GPIO line as an input and get its value.
Usage:
get [-i] CHIP LINE
Options:
-i
: Invert; configure as active-low.
Arguments:
CHIP
: gpiochip path (e.g./dev/gpiochip0
)LINE
: GPIO line number (e.g.1
)
set
#
Configure a GPIO line as an output and set its value.
Warning
After this process exits, the GPIO line could immediately return to its hardware-controlled default state (depending on the GPIO driver).
Usage:
set [-i] CHIP LINE VALUE
Options:
-i
: Invert; configure as active-low.
Arguments:
CHIP
: gpiochip path (e.g./dev/gpiochip0
)LINE
: GPIO line number (e.g.1
)VALUE
: the value to set (0
= inactive or1
= active)
watch
#
Configure a GPIO line as an input and watch for interrupt events.
By default, both rising and falling edges will trigger an event.
This can be changed via the -t
option.
Usage:
watch [-i] [{-ta,-tb,-td}] CHIP LINE
Options:
-i
: Invert; configure as active-low.-t
: Trigger for an interrupt:-ta
- activating edge-tb
- both edges (default)-td
- deactivating edge
Arguments:
CHIP
: gpiochip path (e.g./dev/gpiochip0
)LINE
: GPIO line number (e.g.1
)