Skip to content

Commit 81d11c5

Browse files
committed
Add libgpiod support
1 parent e2b32d1 commit 81d11c5

9 files changed

+149
-8
lines changed

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -109,5 +109,5 @@ $RECYCLE.BIN/
109109
*.dSYM
110110

111111
# cmake
112-
build/
112+
build*/
113113
tmp/

CMakeLists.txt

+10-2
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,8 @@ elseif(APPLE)
143143
message(STATUS "RPATH support: ${CMAKE_MACOSX_RPATH}")
144144

145145
elseif (WIN32)
146-
if(NOT VS2015 AND NOT VS2017)
147-
message(FATAL_ERROR "You must use Microsoft Visual Studio 2015 or 2017 as compiler")
146+
if(NOT VS2015 AND NOT VS2017 AND NOT VS2019)
147+
message(FATAL_ERROR "You must use Microsoft Visual Studio 2015 | 2017 | 2019 as compiler")
148148
endif()
149149

150150
# compile with full multicore
@@ -251,6 +251,14 @@ else()
251251
set(HAMLIB_LIBRARIES "")
252252
endif()
253253

254+
find_package(gpiod)
255+
if(GPIOD_FOUND)
256+
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DUSE_GPIOD")
257+
else()
258+
set(GPIOD_INCLUDE_DIRS "")
259+
set(GPIOD_LIBRARIES "")
260+
endif()
261+
254262
if(LINUX)
255263
find_package(ALSA REQUIRED)
256264
if(ALSA_FOUND)

cmake/modules/FindCompiler.cmake

+3-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ elseif(NOT DEFINED C_GCC AND CMAKE_CXX_COMPILER_ID MATCHES "GNU")
55
set(C_GCC 1)
66
elseif(NOT DEFINED C_MSVC AND CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
77
set(C_MSVC 1)
8-
if(MSVC_VERSION GREATER 1910 AND MSVC_VERSION LESS 1919)
8+
if(MSVC_VERSION GREATER 1919 AND MSVC_VERSION LESS 1926)
9+
set(VS2019 ON)
10+
elseif(MSVC_VERSION GREATER 1910 AND MSVC_VERSION LESS 1919)
911
set(VS2017 ON)
1012
elseif(MSVC_VERSION GREATER 1899 AND MSVC_VERSION LESS 1910)
1113
set(VS2015 ON)

cmake/modules/Findgpiod.cmake

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# - Try to find libgpiod
2+
# Once done this will define
3+
# GPIOD_FOUND - System has libgpiod
4+
# GPIOD_INCLUDE_DIRS - The libgpiod include directories
5+
# GPIOD_LIBRARIES - The libraries needed to use libgpiod
6+
# GPIOD_DEFINITIONS - Compiler switches required for using libgpiod
7+
8+
find_package(PkgConfig)
9+
pkg_check_modules(PC_GPIOD QUIET gpiod)
10+
11+
find_path(GPIOD_INCLUDE_DIR gpiod.h)
12+
find_library(GPIOD_LIBRARY NAMES gpiod)
13+
14+
include(FindPackageHandleStandardArgs)
15+
# handle the QUIETLY and REQUIRED arguments and set GPIOD_FOUND to TRUE
16+
# if all listed variables are TRUE
17+
find_package_handle_standard_args(gpiod DEFAULT_MSG
18+
GPIOD_LIBRARY GPIOD_INCLUDE_DIR)
19+
20+
mark_as_advanced(GPIOD_INCLUDE_DIR GPIOD_LIBRARY)
21+
22+
set(GPIOD_LIBRARIES ${GPIOD_LIBRARY})
23+
set(GPIOD_INCLUDE_DIRS ${GPIOD_INCLUDE_DIR})

src/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ include_directories(
88
${UDEV_INCLUDE_DIRS}
99
${PORTAUDIO_INCLUDE_DIRS}
1010
${CUSTOM_GEOTRANZ_DIR}
11+
${GPIOD_INCLUDE_DIRS}
1112
)
1213

1314
if(WIN32 OR CYGWIN)
@@ -127,6 +128,7 @@ target_link_libraries(direwolf
127128
${ALSA_LIBRARIES}
128129
${UDEV_LIBRARIES}
129130
${PORTAUDIO_LIBRARIES}
131+
${GPIOD_LIBRARIES}
130132
)
131133

132134
if(WIN32 OR CYGWIN)

src/audio.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@
2828
enum ptt_method_e {
2929
PTT_METHOD_NONE, /* VOX or no transmit. */
3030
PTT_METHOD_SERIAL, /* Serial port RTS or DTR. */
31-
PTT_METHOD_GPIO, /* General purpose I/O, Linux only. */
31+
PTT_METHOD_GPIO, /* General purpose I/O using sysfs, deprecated after 2020, Linux only. */
32+
PTT_METHOD_GPIOD, /* General purpose I/O, using libgpiod, Linux only. */
3233
PTT_METHOD_LPT, /* Parallel printer port, Linux only. */
3334
PTT_METHOD_HAMLIB, /* HAMLib, Linux only. */
3435
PTT_METHOD_CM108 }; /* GPIO pin of CM108/CM119/etc. Linux only. */
@@ -266,6 +267,7 @@ struct audio_s {
266267
/* the case for CubieBoard where it was longer. */
267268
/* This is filled in by ptt_init so we don't have to */
268269
/* recalculate it each time we access it. */
270+
/* Also GPIO chip name for GPIOD method. Looks like 'gpiochip4' */
269271

270272
/* This could probably be collapsed into ptt_device instead of being separate. */
271273

src/config.c

+37
Original file line numberDiff line numberDiff line change
@@ -1743,6 +1743,43 @@ void config_init (char *fname, struct audio_s *p_audio_config,
17431743
}
17441744
p_audio_config->achan[channel].octrl[ot].ptt_method = PTT_METHOD_GPIO;
17451745
#endif
1746+
}
1747+
else if (strcasecmp(t, "GPIOD") == 0) {
1748+
#if __WIN32__
1749+
text_color_set(DW_COLOR_ERROR);
1750+
dw_printf ("Config file line %d: %s with GPIOD is only available on Linux.\n", line, otname);
1751+
#else
1752+
#if defined(USE_GPIOD)
1753+
t = split(NULL,0);
1754+
if (t == NULL) {
1755+
text_color_set(DW_COLOR_ERROR);
1756+
dw_printf ("Config file line %d: Missing GPIO chip for %s.\n", line, otname);
1757+
continue;
1758+
}
1759+
strlcpy(p_audio_config->achan[channel].octrl[ot].out_gpio_name, t,
1760+
sizeof(p_audio_config->achan[channel].octrl[ot].out_gpio_name));
1761+
1762+
t = split(NULL,0);
1763+
if (t == NULL) {
1764+
text_color_set(DW_COLOR_ERROR);
1765+
dw_printf("Config file line %d: Missing GPIO number for %s.\n", line, otname);
1766+
continue;
1767+
}
1768+
1769+
if (*t == '-') {
1770+
p_audio_config->achan[channel].octrl[ot].out_gpio_num = atoi(t+1);
1771+
p_audio_config->achan[channel].octrl[ot].ptt_invert = 1;
1772+
}
1773+
else {
1774+
p_audio_config->achan[channel].octrl[ot].out_gpio_num = atoi(t);
1775+
p_audio_config->achan[channel].octrl[ot].ptt_invert = 0;
1776+
}
1777+
p_audio_config->achan[channel].octrl[ot].ptt_method = PTT_METHOD_GPIOD;
1778+
#else
1779+
text_color_set(DW_COLOR_ERROR);
1780+
dw_printf ("GPIOD is not supported.\n");
1781+
#endif /* USE_GPIOD*/
1782+
#endif /* __WIN32__ */
17461783
}
17471784
else if (strcasecmp(t, "LPT") == 0) {
17481785

src/direwolf.c

+3
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,9 @@ int main (int argc, char *argv[])
302302
#endif
303303
#if defined(USE_CM108)
304304
dw_printf (" cm108-ptt");
305+
#endif
306+
#if defined(USE_GPIOD)
307+
dw_printf (" libgpiod");
305308
#endif
306309
dw_printf ("\n");
307310
#endif

src/ptt.c

+67-3
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,10 @@
166166
#include "cm108.h"
167167
#endif
168168

169+
#ifdef USE_GPIOD
170+
#include <gpiod.h>
171+
#endif
172+
169173
/* So we can have more common code for fd. */
170174
typedef int HANDLE;
171175
#define INVALID_HANDLE_VALUE (-1)
@@ -623,6 +627,31 @@ void export_gpio(int ch, int ot, int invert, int direction)
623627
get_access_to_gpio (gpio_value_path);
624628
}
625629

630+
#if defined(USE_GPIOD)
631+
int gpiod_probe(const char *chip_name, int line_number)
632+
{
633+
struct gpiod_chip *chip;
634+
chip = gpiod_chip_open_by_name(chip_name);
635+
if (chip == NULL) {
636+
text_color_set(DW_COLOR_ERROR);
637+
dw_printf ("Can't open GPIOD chip %s.\n", chip_name);
638+
return -1;
639+
}
640+
641+
struct gpiod_line *line;
642+
line = gpiod_chip_get_line(chip, line_number);
643+
if (line == NULL) {
644+
text_color_set(DW_COLOR_ERROR);
645+
dw_printf ("Can't get GPIOD line %d.\n", line_number);
646+
return -1;
647+
}
648+
if (ptt_debug_level >= 2) {
649+
text_color_set(DW_COLOR_DEBUG);
650+
dw_printf("GPIOD probe OK. Chip: %s line: %d\n", chip_name, line_number);
651+
}
652+
return 0;
653+
}
654+
#endif /* USE_GPIOD */
626655
#endif /* not __WIN32__ */
627656

628657

@@ -639,7 +668,8 @@ void export_gpio(int ch, int ot, int invert, int direction)
639668
* ptt_method Method for PTT signal.
640669
* PTT_METHOD_NONE - not configured. Could be using VOX.
641670
* PTT_METHOD_SERIAL - serial (com) port.
642-
* PTT_METHOD_GPIO - general purpose I/O.
671+
* PTT_METHOD_GPIO - general purpose I/O (sysfs).
672+
* PTT_METHOD_GPIOD - general purpose I/O (libgpiod).
643673
* PTT_METHOD_LPT - Parallel printer port.
644674
* PTT_METHOD_HAMLIB - HAMLib rig control.
645675
* PTT_METHOD_CM108 - GPIO pins of CM108 etc. USB Audio.
@@ -718,12 +748,13 @@ void ptt_init (struct audio_s *audio_config_p)
718748
if (ptt_debug_level >= 2) {
719749

720750
text_color_set(DW_COLOR_DEBUG);
721-
dw_printf ("ch=%d, %s method=%d, device=%s, line=%d, gpio=%d, lpt_bit=%d, invert=%d\n",
751+
dw_printf ("ch=%d, %s method=%d, device=%s, line=%d, name=%s, gpio=%d, lpt_bit=%d, invert=%d\n",
722752
ch,
723753
otnames[ot],
724754
audio_config_p->achan[ch].octrl[ot].ptt_method,
725755
audio_config_p->achan[ch].octrl[ot].ptt_device,
726756
audio_config_p->achan[ch].octrl[ot].ptt_line,
757+
audio_config_p->achan[ch].octrl[ot].out_gpio_name,
727758
audio_config_p->achan[ch].octrl[ot].out_gpio_num,
728759
audio_config_p->achan[ch].octrl[ot].ptt_lpt_bit,
729760
audio_config_p->achan[ch].octrl[ot].ptt_invert);
@@ -869,7 +900,28 @@ void ptt_init (struct audio_s *audio_config_p)
869900
if (using_gpio) {
870901
get_access_to_gpio ("/sys/class/gpio/export");
871902
}
872-
903+
#if defined(USE_GPIOD)
904+
// GPIOD
905+
for (ch = 0; ch < MAX_CHANS; ch++) {
906+
if (save_audio_config_p->achan[ch].medium == MEDIUM_RADIO) {
907+
for (int ot = 0; ot < NUM_OCTYPES; ot++) {
908+
if (audio_config_p->achan[ch].octrl[ot].ptt_method == PTT_METHOD_GPIOD) {
909+
const char *chip_name = audio_config_p->achan[ch].octrl[ot].out_gpio_name;
910+
int line_number = audio_config_p->achan[ch].octrl[ot].out_gpio_num;
911+
int rc = gpiod_probe(chip_name, line_number);
912+
if (rc < 0) {
913+
text_color_set(DW_COLOR_ERROR);
914+
dw_printf ("Disable PTT for channel %d\n", ch);
915+
audio_config_p->achan[ch].octrl[ot].ptt_method = PTT_METHOD_NONE;
916+
} else {
917+
// Set initial state off ptt_set will invert output signal if appropriate.
918+
ptt_set (ot, ch, 0);
919+
}
920+
}
921+
}
922+
}
923+
}
924+
#endif /* USE_GPIOD */
873925
/*
874926
* We should now be able to create the device nodes for
875927
* the pins we want to use.
@@ -1226,6 +1278,18 @@ void ptt_set (int ot, int chan, int ptt_signal)
12261278
close (fd);
12271279

12281280
}
1281+
1282+
#if defined(USE_GPIOD)
1283+
if (save_audio_config_p->achan[chan].octrl[ot].ptt_method == PTT_METHOD_GPIOD) {
1284+
const char *chip = save_audio_config_p->achan[chan].octrl[ot].out_gpio_name;
1285+
int line = save_audio_config_p->achan[chan].octrl[ot].out_gpio_num;
1286+
int rc = gpiod_ctxless_set_value(chip, line, ptt, false, "direwolf", NULL, NULL);
1287+
if (ptt_debug_level >= 1) {
1288+
text_color_set(DW_COLOR_DEBUG);
1289+
dw_printf("PTT_METHOD_GPIOD chip: %s line: %d ptt: %d rc: %d\n", chip, line, ptt, rc);
1290+
}
1291+
}
1292+
#endif /* USE_GPIOD */
12291293
#endif
12301294

12311295
/*

0 commit comments

Comments
 (0)