Skip to content

Commit d5f7a6e

Browse files
authored
Feat/support rpi5 (#5)
* Updated version and added install target * Added fallback GPIO chip for RPi5 * From merge * Updated README * Fixed compiler errors.
1 parent 65615d2 commit d5f7a6e

File tree

5 files changed

+110
-36
lines changed

5 files changed

+110
-36
lines changed

README.md

Lines changed: 63 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,68 @@
22
This repository contains example code useful when using the WaveShare 8-channel relay module for the RaspberryPi.
33
The example code provided by WaveShare is mixed up and doesn't work correctly.
44

5+
# C++ Application
6+
7+
Included with this repository is a C++ application, which is now the recommended use of this repository!
8+
The C++ application uses libgpiod, which is bundled in this repository. Regardless of whether or not libgpiod is found on your system,
9+
the Makefile generator will always download the correct version of the library and link against it.
10+
11+
## Building the Application
12+
13+
Unlike in previous versions, the application has been refactored to use CMake as its Makefile generator and build system, instead of using raw compiler commands.
14+
Building the application is very easy nonetheless.
15+
16+
```sh
17+
# Ensure you're in the `cpp` directory!
18+
19+
# Create build directory
20+
mkdir -p build && cd build
21+
22+
# It doesn't really matter which platform you're on; because of the fallback logic, this should work on both RPi5 and older models
23+
24+
cmake .. [-Dchannelselect_RASPI5] # Add the value in brackets if you're planning on running on RPi5.
25+
26+
make -j$(($(nproc)-1)) # Build with nproc - 1
27+
```
28+
29+
## Usage
30+
31+
Using the app is fairly simple, and it provides a simple help text to get you started.
32+
Some examples are included below:
33+
34+
```
35+
waveshare_channel_select v1.1.0 - A simple application for controlling GPIO pins on modern Linux OSs on RasPi
36+
37+
Usage:
38+
waveshare_channel_select -h
39+
waveshare_channel_select -e -123 # enable channels 1, 2, and 3
40+
waveshare_channel_select -d -528 # disable channels 5, 2, and 8 and read the state of channel 7
41+
waveshare_channel_select -L # read the states of all channels
42+
43+
Troubleshooting:
44+
Permission denied? Is your user in the gpio group? # usermod -aG gpio <myuser>
45+
Library not found? Try installing lgpiod
46+
47+
Options:
48+
Channel selection:
49+
--channel1, -1 Channel 1
50+
--channel2, -2 Look, it's the same up until -8
51+
...
52+
--channel8, -8 I'm sure it's self-explanatory at this point
53+
--all, -a All channels
54+
55+
Channel options:
56+
--enable, -e Enable channel(s)
57+
--disable, -d Disable channel(s)
58+
--read, -r Read the channel state
59+
60+
General options:
61+
--list-all, -L List all channels and their current state
62+
63+
--help, -h Displays this text and exits
64+
--version, -v Displays the version information and exits
65+
```
66+
567
# Bash Script
668

769
Contained within this repository is a Bash script, which handles setting the GPIO pins, respective to the selected channel.
@@ -32,21 +94,4 @@ If the --help|-h arg is passed, the script will print the help text and exit.
3294

3395
# Print help menu
3496
./channel_select --help
35-
```
36-
37-
# C++ Application
38-
39-
Provided with this repository is a simple sample application written in C++, providing the same functionality as the Bash script.
40-
41-
## Building
42-
43-
```
44-
g++ -std=c++17 -o channel_select cpp/channel_select.cpp
45-
```
46-
47-
## Usage
48-
49-
The C++ example provides the same features/functionality and arguments as the Bash script.<br >
50-
They are virtually 1:1 ports of each other.
51-
52-
97+
```

cpp/CMakeLists.txt

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
cmake_minimum_required(VERSION 3.20)
22

3-
project(waveshare_channel_select LANGUAGES CXX VERSION 1.1.0)
3+
project(waveshare_channel_select LANGUAGES CXX VERSION 1.2.0)
44
set(CMAKE_CXX_STANDARD 20)
55
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
66

@@ -15,6 +15,14 @@ else()
1515
)
1616
endif()
1717

18+
if (DEFINED channelselect_RASPI5)
19+
set(DEFAULT_GPIOCHIP "gpiochip4")
20+
set(FALLBACK_GPIOCHIP "gpiochip0")
21+
else()
22+
set(DEFAULT_GPIOCHIP "gpiochip0")
23+
set(FALLBACK_GPIOCHIP "gpiochip4")
24+
endif()
25+
1826
add_compile_options(
1927
-Werror
2028
-Wall
@@ -43,4 +51,13 @@ target_link_libraries(
4351
gpiod::shared
4452
gpiodcxx::shared
4553
fmt
54+
)
55+
56+
###
57+
# Define install target
58+
# This will install the executable to /usr/local/bin
59+
###
60+
install(
61+
TARGETS channel_select
62+
DESTINATION ${CMAKE_INSTALL_BINDIR}
4663
)

cpp/channel_select.cpp

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,9 @@ using optsm_t = optional<StateModifier>;
8484
optsm_t stateModifierFromString(const string& optArg); //!< Converts an optarg value to a boolean
8585
int32_t parseArgs(int32_t argc, char** argv); //!< Parses arguments passed to the application
8686

87-
bool getChannelState(const int32_t channelId); //!< Gets the state of a given channel
87+
bool getChannelState(const int32_t channelId, const string& gpioDevice = GPIO_CHIP); //!< Gets the state of a given channel
8888
void listChannels(); //!< Lists all channels available with their state.
89-
void setChannel(const int32_t channelId, const StateModifier newState); //!< Sets the state of a given channel
89+
void setChannel(const int32_t channelId, const StateModifier newState, const string& gpioDevice = GPIO_CHIP); //!< Sets the state of a given channel
9090

9191
void printHelp(); //!< Prints the help text for the application
9292
void printVersion(); //!< Prints the version information for the application
@@ -197,12 +197,17 @@ int32_t parseArgs(int32_t argc, char** argv) {
197197
return 0;
198198
}
199199

200-
bool getChannelState(const int32_t channel) {
201-
auto gpioChip = gpiod::chip(string{GPIO_CHIP});
202-
auto lineSettings = gpiod::line_settings{};
203-
auto line = gpioChip.prepare_request().add_line_settings(gpioChip.get_line_offset_from_name(fmt::format("GPIO{0:d}", channel)), lineSettings).do_request();
200+
bool getChannelState(const int32_t channel, const string& gpioDevice/* = GPIO_CHIP*/) {
204201

205-
return static_cast<bool>(line.get_value(line.offsets()[0]));
202+
try {
203+
auto gpioChip = gpiod::chip(string{gpioDevice});
204+
auto lineSettings = gpiod::line_settings{};
205+
auto line = gpioChip.prepare_request().add_line_settings(gpioChip.get_line_offset_from_name(fmt::format("GPIO{0:d}", channel)), lineSettings).do_request();
206+
207+
return static_cast<bool>(line.get_value(line.offsets()[0]));
208+
} catch (const std::invalid_argument&) {
209+
return getChannelState(channel, FALLBACK_GPIO_CHIP);
210+
}
206211
}
207212

208213
optsm_t stateModifierFromString(const string& optArg) {
@@ -271,14 +276,19 @@ void printVersion() {
271276
fmt::print(R"({0:s} v{1:s} - A simple application for controlling GPIO pins on modern Linux OSs on RasPi)", APP_NAME, APP_VERS);
272277
}
273278

274-
void setChannel(const int32_t channel, const StateModifier newState) {
279+
void setChannel(const int32_t channel, const StateModifier newState, const string& gpioDevice/* = GPIO_CHIP*/) {
275280
const auto gpioLineName = fmt::format("GPIO{0:d}", CHANNELS[channel]);
276281

277-
auto gpioChip = gpiod::chip(string{GPIO_CHIP});
278-
auto lineSettings = gpiod::line_settings{};
279-
lineSettings.set_direction(gpiod::line::direction::OUTPUT);
280-
auto line = gpioChip.prepare_request().add_line_settings(gpioChip.get_line_offset_from_name(gpioLineName), lineSettings).do_request();
281-
282-
fmt::println("Attempting to set GPIO{0:d} {1:s}", CHANNELS[channel], newState == StateModifier::DISABLE ? "ON" : "OFF");
283-
line.set_value(line.offsets()[0], newState == StateModifier::DISABLE ? gpiod::line::value::INACTIVE : gpiod::line::value::ACTIVE);
282+
try {
283+
auto gpioChip = gpiod::chip(string{gpioDevice});
284+
auto lineSettings = gpiod::line_settings{};
285+
lineSettings.set_direction(gpiod::line::direction::OUTPUT);
286+
auto line = gpioChip.prepare_request().add_line_settings(gpioChip.get_line_offset_from_name(gpioLineName), lineSettings).do_request();
287+
288+
fmt::println("Attempting to set GPIO{0:d} {1:s}", CHANNELS[channel], newState == StateModifier::DISABLE ? "ON" : "OFF");
289+
line.set_value(line.offsets()[0], newState == StateModifier::DISABLE ? gpiod::line::value::INACTIVE : gpiod::line::value::ACTIVE);
290+
} catch (const std::invalid_argument&) {
291+
setChannel(channel, newState, FALLBACK_GPIO_CHIP);
292+
return;
293+
}
284294
}

cpp/channel_select.in.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,6 @@
1414
constexpr const char* APP_NAME = "@PROJECT_NAME@";
1515
constexpr const char* APP_VERS = "@PROJECT_VERSION@";
1616

17-
constexpr const char* GPIO_CHIP = "/dev/gpiochip0"; //!< This is the chip required for controlling the relay board
18-
17+
constexpr const char* GPIO_CHIP = "/dev/@DEFAULT_GPIOCHIP@"; //!< This is the chip required for controlling the relay board
18+
constexpr const char* FALLBACK_GPIO_CHIP = "/dev/@FALLBACK_GPIOCHIP@"; //!< This is the fallback chip required for controlling the relay board on a RaspberrFALLBACK
1919
#endif // CHANNEL_SELECT_HPP

cpp/cmake/add_libgpiod.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ ExternalProject_Add(
66
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/submodules/libgpiod
77
CONFIGURE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/submodules/libgpiod/autogen.sh --enable-bindings-cxx --prefix ${CMAKE_CURRENT_BINARY_DIR}/libgpiod/
88

9+
UPDATE_COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR}/submodules/libgpiod && autoupdate
10+
911
# BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/libgpiod
1012
BUILD_COMMAND make
1113
)

0 commit comments

Comments
 (0)