Add libgpiod support

This commit is contained in:
Vladimir K 2020-04-05 19:43:41 -07:00
parent e2b32d1d2a
commit 81d11c5e93
9 changed files with 149 additions and 8 deletions

2
.gitignore vendored
View File

@ -109,5 +109,5 @@ $RECYCLE.BIN/
*.dSYM *.dSYM
# cmake # cmake
build/ build*/
tmp/ tmp/

View File

@ -143,8 +143,8 @@ elseif(APPLE)
message(STATUS "RPATH support: ${CMAKE_MACOSX_RPATH}") message(STATUS "RPATH support: ${CMAKE_MACOSX_RPATH}")
elseif (WIN32) elseif (WIN32)
if(NOT VS2015 AND NOT VS2017) if(NOT VS2015 AND NOT VS2017 AND NOT VS2019)
message(FATAL_ERROR "You must use Microsoft Visual Studio 2015 or 2017 as compiler") message(FATAL_ERROR "You must use Microsoft Visual Studio 2015 | 2017 | 2019 as compiler")
endif() endif()
# compile with full multicore # compile with full multicore
@ -251,6 +251,14 @@ else()
set(HAMLIB_LIBRARIES "") set(HAMLIB_LIBRARIES "")
endif() endif()
find_package(gpiod)
if(GPIOD_FOUND)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DUSE_GPIOD")
else()
set(GPIOD_INCLUDE_DIRS "")
set(GPIOD_LIBRARIES "")
endif()
if(LINUX) if(LINUX)
find_package(ALSA REQUIRED) find_package(ALSA REQUIRED)
if(ALSA_FOUND) if(ALSA_FOUND)

View File

@ -5,7 +5,9 @@ elseif(NOT DEFINED C_GCC AND CMAKE_CXX_COMPILER_ID MATCHES "GNU")
set(C_GCC 1) set(C_GCC 1)
elseif(NOT DEFINED C_MSVC AND CMAKE_CXX_COMPILER_ID MATCHES "MSVC") elseif(NOT DEFINED C_MSVC AND CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
set(C_MSVC 1) set(C_MSVC 1)
if(MSVC_VERSION GREATER 1910 AND MSVC_VERSION LESS 1919) if(MSVC_VERSION GREATER 1919 AND MSVC_VERSION LESS 1926)
set(VS2019 ON)
elseif(MSVC_VERSION GREATER 1910 AND MSVC_VERSION LESS 1919)
set(VS2017 ON) set(VS2017 ON)
elseif(MSVC_VERSION GREATER 1899 AND MSVC_VERSION LESS 1910) elseif(MSVC_VERSION GREATER 1899 AND MSVC_VERSION LESS 1910)
set(VS2015 ON) set(VS2015 ON)

View File

@ -0,0 +1,23 @@
# - Try to find libgpiod
# Once done this will define
# GPIOD_FOUND - System has libgpiod
# GPIOD_INCLUDE_DIRS - The libgpiod include directories
# GPIOD_LIBRARIES - The libraries needed to use libgpiod
# GPIOD_DEFINITIONS - Compiler switches required for using libgpiod
find_package(PkgConfig)
pkg_check_modules(PC_GPIOD QUIET gpiod)
find_path(GPIOD_INCLUDE_DIR gpiod.h)
find_library(GPIOD_LIBRARY NAMES gpiod)
include(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set GPIOD_FOUND to TRUE
# if all listed variables are TRUE
find_package_handle_standard_args(gpiod DEFAULT_MSG
GPIOD_LIBRARY GPIOD_INCLUDE_DIR)
mark_as_advanced(GPIOD_INCLUDE_DIR GPIOD_LIBRARY)
set(GPIOD_LIBRARIES ${GPIOD_LIBRARY})
set(GPIOD_INCLUDE_DIRS ${GPIOD_INCLUDE_DIR})

View File

@ -8,6 +8,7 @@ include_directories(
${UDEV_INCLUDE_DIRS} ${UDEV_INCLUDE_DIRS}
${PORTAUDIO_INCLUDE_DIRS} ${PORTAUDIO_INCLUDE_DIRS}
${CUSTOM_GEOTRANZ_DIR} ${CUSTOM_GEOTRANZ_DIR}
${GPIOD_INCLUDE_DIRS}
) )
if(WIN32 OR CYGWIN) if(WIN32 OR CYGWIN)
@ -127,6 +128,7 @@ target_link_libraries(direwolf
${ALSA_LIBRARIES} ${ALSA_LIBRARIES}
${UDEV_LIBRARIES} ${UDEV_LIBRARIES}
${PORTAUDIO_LIBRARIES} ${PORTAUDIO_LIBRARIES}
${GPIOD_LIBRARIES}
) )
if(WIN32 OR CYGWIN) if(WIN32 OR CYGWIN)

View File

@ -28,7 +28,8 @@
enum ptt_method_e { enum ptt_method_e {
PTT_METHOD_NONE, /* VOX or no transmit. */ PTT_METHOD_NONE, /* VOX or no transmit. */
PTT_METHOD_SERIAL, /* Serial port RTS or DTR. */ PTT_METHOD_SERIAL, /* Serial port RTS or DTR. */
PTT_METHOD_GPIO, /* General purpose I/O, Linux only. */ PTT_METHOD_GPIO, /* General purpose I/O using sysfs, deprecated after 2020, Linux only. */
PTT_METHOD_GPIOD, /* General purpose I/O, using libgpiod, Linux only. */
PTT_METHOD_LPT, /* Parallel printer port, Linux only. */ PTT_METHOD_LPT, /* Parallel printer port, Linux only. */
PTT_METHOD_HAMLIB, /* HAMLib, Linux only. */ PTT_METHOD_HAMLIB, /* HAMLib, Linux only. */
PTT_METHOD_CM108 }; /* GPIO pin of CM108/CM119/etc. Linux only. */ PTT_METHOD_CM108 }; /* GPIO pin of CM108/CM119/etc. Linux only. */
@ -266,6 +267,7 @@ struct audio_s {
/* the case for CubieBoard where it was longer. */ /* the case for CubieBoard where it was longer. */
/* This is filled in by ptt_init so we don't have to */ /* This is filled in by ptt_init so we don't have to */
/* recalculate it each time we access it. */ /* recalculate it each time we access it. */
/* Also GPIO chip name for GPIOD method. Looks like 'gpiochip4' */
/* This could probably be collapsed into ptt_device instead of being separate. */ /* This could probably be collapsed into ptt_device instead of being separate. */

View File

@ -1743,6 +1743,43 @@ void config_init (char *fname, struct audio_s *p_audio_config,
} }
p_audio_config->achan[channel].octrl[ot].ptt_method = PTT_METHOD_GPIO; p_audio_config->achan[channel].octrl[ot].ptt_method = PTT_METHOD_GPIO;
#endif #endif
}
else if (strcasecmp(t, "GPIOD") == 0) {
#if __WIN32__
text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file line %d: %s with GPIOD is only available on Linux.\n", line, otname);
#else
#if defined(USE_GPIOD)
t = split(NULL,0);
if (t == NULL) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file line %d: Missing GPIO chip for %s.\n", line, otname);
continue;
}
strlcpy(p_audio_config->achan[channel].octrl[ot].out_gpio_name, t,
sizeof(p_audio_config->achan[channel].octrl[ot].out_gpio_name));
t = split(NULL,0);
if (t == NULL) {
text_color_set(DW_COLOR_ERROR);
dw_printf("Config file line %d: Missing GPIO number for %s.\n", line, otname);
continue;
}
if (*t == '-') {
p_audio_config->achan[channel].octrl[ot].out_gpio_num = atoi(t+1);
p_audio_config->achan[channel].octrl[ot].ptt_invert = 1;
}
else {
p_audio_config->achan[channel].octrl[ot].out_gpio_num = atoi(t);
p_audio_config->achan[channel].octrl[ot].ptt_invert = 0;
}
p_audio_config->achan[channel].octrl[ot].ptt_method = PTT_METHOD_GPIOD;
#else
text_color_set(DW_COLOR_ERROR);
dw_printf ("GPIOD is not supported.\n");
#endif /* USE_GPIOD*/
#endif /* __WIN32__ */
} }
else if (strcasecmp(t, "LPT") == 0) { else if (strcasecmp(t, "LPT") == 0) {

View File

@ -302,6 +302,9 @@ int main (int argc, char *argv[])
#endif #endif
#if defined(USE_CM108) #if defined(USE_CM108)
dw_printf (" cm108-ptt"); dw_printf (" cm108-ptt");
#endif
#if defined(USE_GPIOD)
dw_printf (" libgpiod");
#endif #endif
dw_printf ("\n"); dw_printf ("\n");
#endif #endif

View File

@ -166,6 +166,10 @@
#include "cm108.h" #include "cm108.h"
#endif #endif
#ifdef USE_GPIOD
#include <gpiod.h>
#endif
/* So we can have more common code for fd. */ /* So we can have more common code for fd. */
typedef int HANDLE; typedef int HANDLE;
#define INVALID_HANDLE_VALUE (-1) #define INVALID_HANDLE_VALUE (-1)
@ -623,6 +627,31 @@ void export_gpio(int ch, int ot, int invert, int direction)
get_access_to_gpio (gpio_value_path); get_access_to_gpio (gpio_value_path);
} }
#if defined(USE_GPIOD)
int gpiod_probe(const char *chip_name, int line_number)
{
struct gpiod_chip *chip;
chip = gpiod_chip_open_by_name(chip_name);
if (chip == NULL) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("Can't open GPIOD chip %s.\n", chip_name);
return -1;
}
struct gpiod_line *line;
line = gpiod_chip_get_line(chip, line_number);
if (line == NULL) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("Can't get GPIOD line %d.\n", line_number);
return -1;
}
if (ptt_debug_level >= 2) {
text_color_set(DW_COLOR_DEBUG);
dw_printf("GPIOD probe OK. Chip: %s line: %d\n", chip_name, line_number);
}
return 0;
}
#endif /* USE_GPIOD */
#endif /* not __WIN32__ */ #endif /* not __WIN32__ */
@ -639,7 +668,8 @@ void export_gpio(int ch, int ot, int invert, int direction)
* ptt_method Method for PTT signal. * ptt_method Method for PTT signal.
* PTT_METHOD_NONE - not configured. Could be using VOX. * PTT_METHOD_NONE - not configured. Could be using VOX.
* PTT_METHOD_SERIAL - serial (com) port. * PTT_METHOD_SERIAL - serial (com) port.
* PTT_METHOD_GPIO - general purpose I/O. * PTT_METHOD_GPIO - general purpose I/O (sysfs).
* PTT_METHOD_GPIOD - general purpose I/O (libgpiod).
* PTT_METHOD_LPT - Parallel printer port. * PTT_METHOD_LPT - Parallel printer port.
* PTT_METHOD_HAMLIB - HAMLib rig control. * PTT_METHOD_HAMLIB - HAMLib rig control.
* PTT_METHOD_CM108 - GPIO pins of CM108 etc. USB Audio. * PTT_METHOD_CM108 - GPIO pins of CM108 etc. USB Audio.
@ -718,12 +748,13 @@ void ptt_init (struct audio_s *audio_config_p)
if (ptt_debug_level >= 2) { if (ptt_debug_level >= 2) {
text_color_set(DW_COLOR_DEBUG); text_color_set(DW_COLOR_DEBUG);
dw_printf ("ch=%d, %s method=%d, device=%s, line=%d, gpio=%d, lpt_bit=%d, invert=%d\n", dw_printf ("ch=%d, %s method=%d, device=%s, line=%d, name=%s, gpio=%d, lpt_bit=%d, invert=%d\n",
ch, ch,
otnames[ot], otnames[ot],
audio_config_p->achan[ch].octrl[ot].ptt_method, audio_config_p->achan[ch].octrl[ot].ptt_method,
audio_config_p->achan[ch].octrl[ot].ptt_device, audio_config_p->achan[ch].octrl[ot].ptt_device,
audio_config_p->achan[ch].octrl[ot].ptt_line, audio_config_p->achan[ch].octrl[ot].ptt_line,
audio_config_p->achan[ch].octrl[ot].out_gpio_name,
audio_config_p->achan[ch].octrl[ot].out_gpio_num, audio_config_p->achan[ch].octrl[ot].out_gpio_num,
audio_config_p->achan[ch].octrl[ot].ptt_lpt_bit, audio_config_p->achan[ch].octrl[ot].ptt_lpt_bit,
audio_config_p->achan[ch].octrl[ot].ptt_invert); audio_config_p->achan[ch].octrl[ot].ptt_invert);
@ -869,7 +900,28 @@ void ptt_init (struct audio_s *audio_config_p)
if (using_gpio) { if (using_gpio) {
get_access_to_gpio ("/sys/class/gpio/export"); get_access_to_gpio ("/sys/class/gpio/export");
} }
#if defined(USE_GPIOD)
// GPIOD
for (ch = 0; ch < MAX_CHANS; ch++) {
if (save_audio_config_p->achan[ch].medium == MEDIUM_RADIO) {
for (int ot = 0; ot < NUM_OCTYPES; ot++) {
if (audio_config_p->achan[ch].octrl[ot].ptt_method == PTT_METHOD_GPIOD) {
const char *chip_name = audio_config_p->achan[ch].octrl[ot].out_gpio_name;
int line_number = audio_config_p->achan[ch].octrl[ot].out_gpio_num;
int rc = gpiod_probe(chip_name, line_number);
if (rc < 0) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("Disable PTT for channel %d\n", ch);
audio_config_p->achan[ch].octrl[ot].ptt_method = PTT_METHOD_NONE;
} else {
// Set initial state off ptt_set will invert output signal if appropriate.
ptt_set (ot, ch, 0);
}
}
}
}
}
#endif /* USE_GPIOD */
/* /*
* We should now be able to create the device nodes for * We should now be able to create the device nodes for
* the pins we want to use. * the pins we want to use.
@ -1226,6 +1278,18 @@ void ptt_set (int ot, int chan, int ptt_signal)
close (fd); close (fd);
} }
#if defined(USE_GPIOD)
if (save_audio_config_p->achan[chan].octrl[ot].ptt_method == PTT_METHOD_GPIOD) {
const char *chip = save_audio_config_p->achan[chan].octrl[ot].out_gpio_name;
int line = save_audio_config_p->achan[chan].octrl[ot].out_gpio_num;
int rc = gpiod_ctxless_set_value(chip, line, ptt, false, "direwolf", NULL, NULL);
if (ptt_debug_level >= 1) {
text_color_set(DW_COLOR_DEBUG);
dw_printf("PTT_METHOD_GPIOD chip: %s line: %d ptt: %d rc: %d\n", chip, line, ptt, rc);
}
}
#endif /* USE_GPIOD */
#endif #endif
/* /*