Skip to content

Commit dce46d4

Browse files
committed
Merge branch 'leventelist-gpiod_support2' into dev
2 parents 3cce46f + c202286 commit dce46d4

File tree

7 files changed

+335
-30
lines changed

7 files changed

+335
-30
lines changed

CHANGES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
- Include the direwolf icon in the Windows executable. Note: When building from source, environment variable RC must point to windres location.
1616

17+
- Added support for libgpiod version 2.
18+
1719
## Version 1.7 -- October 2023
1820

1921
### New Documentation:

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ list(APPEND direwolf_SOURCES
104104
dwgpsnmea.c
105105
dwgpsd.c
106106
mheard.c
107+
gpio_common.c
107108
)
108109

109110
if(LINUX)

src/audio.h

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*
66
* Purpose: Interface to audio device commonly called a "sound card"
77
* for historical reasons.
8-
*
8+
*
99
*---------------------------------------------------------------*/
1010

1111

@@ -19,13 +19,14 @@
1919
#include "direwolf.h" /* for MAX_RADIO_CHANS and MAX_TOTAL_CHANS used throughout the application. */
2020
#include "ax25_pad.h" /* for AX25_MAX_ADDR_LEN */
2121
#include "version.h"
22-
22+
#include "gpio_common.h"
23+
2324

2425
/*
25-
* PTT control.
26+
* PTT control.
2627
*/
2728

28-
enum ptt_method_e {
29+
enum ptt_method_e {
2930
PTT_METHOD_NONE, /* VOX or no transmit. */
3031
PTT_METHOD_SERIAL, /* Serial port RTS or DTR. */
3132
PTT_METHOD_GPIO, /* General purpose I/O using sysfs, deprecated after 2020, Linux only. */
@@ -63,7 +64,7 @@ enum medium_e { MEDIUM_NONE = 0, // Channel is not valid for use.
6364

6465

6566
typedef enum sanity_e { SANITY_APRS, SANITY_AX25, SANITY_NONE } sanity_t;
66-
67+
6768

6869
struct audio_s {
6970

@@ -276,7 +277,7 @@ struct audio_s {
276277

277278

278279
/* Additional properties for transmit. */
279-
280+
280281
/* Originally we had control outputs only for PTT. */
281282
/* In version 1.2, we generalize this to allow others such as DCD. */
282283
/* In version 1.4 we add CON for connected to another station. */
@@ -288,8 +289,8 @@ struct audio_s {
288289
#define OCTYPE_CON 2
289290

290291
#define NUM_OCTYPES 3 /* number of values above. i.e. last value +1. */
291-
292-
struct {
292+
293+
struct {
293294

294295
ptt_method_t ptt_method; /* none, serial port, GPIO, LPT, HAMLIB, CM108. */
295296

@@ -304,7 +305,7 @@ struct audio_s {
304305
/* have a name like /dev/hidraw1 for Linux or */
305306
/* \\?\hid#vid_0d8c&pid_0008&mi_03#8&39d3555&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030} */
306307
/* for Windows. Largest observed was 95 but add some extra to be safe. */
307-
308+
308309
ptt_line_t ptt_line; /* Control line when using serial port. PTT_LINE_RTS, PTT_LINE_DTR. */
309310
ptt_line_t ptt_line2; /* Optional second one: PTT_LINE_NONE when not used. */
310311

@@ -330,6 +331,11 @@ struct audio_s {
330331

331332
int ptt_invert; /* Invert the output. */
332333
int ptt_invert2; /* Invert the secondary output. */
334+
#if USE_GPIOD
335+
#if LIBGPIOD_VERSION_MAJOR >= 2
336+
gpio_num_t gpio_num; /* Handle from libgpiod. Valid only when ptt_method is PTT_METHOD_GPIOD. */
337+
#endif
338+
#endif
333339

334340
#ifdef USE_HAMLIB
335341

src/direwolf.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ int main (int argc, char *argv[])
305305
text_color_init(t_opt);
306306
text_color_set(DW_COLOR_INFO);
307307
//dw_printf ("Dire Wolf version %d.%d (%s) BETA TEST 7\n", MAJOR_VERSION, MINOR_VERSION, __DATE__);
308-
dw_printf ("Dire Wolf DEVELOPMENT version %d.%d %s (%s)\n", MAJOR_VERSION, MINOR_VERSION, "D", __DATE__);
308+
dw_printf ("Dire Wolf DEVELOPMENT version %d.%d %s (%s)\n", MAJOR_VERSION, MINOR_VERSION, "E", __DATE__);
309309
//dw_printf ("Dire Wolf version %d.%d\n", MAJOR_VERSION, MINOR_VERSION);
310310

311311

@@ -321,7 +321,9 @@ int main (int argc, char *argv[])
321321
dw_printf (" cm108-ptt");
322322
#endif
323323
#if defined(USE_GPIOD)
324-
dw_printf (" libgpiod");
324+
#define STRINGIFY(x) STRINGIFY2(x)
325+
#define STRINGIFY2(x) #x
326+
dw_printf (" libgpiod-%s", STRINGIFY(LIBGPIOD_VERSION));
325327
#endif
326328
#if (USE_AVAHI_CLIENT|USE_MACOS_DNSSD)
327329
dw_printf (" dns-sd");

src/gpio_common.c

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
/*------------------------------------------------------------------
2+
*
3+
* Module: gpio_common.c
4+
*
5+
* Purpose: The libgpiod API changed drastically between v1 and v2, as first seen
6+
* in Debian 13 Trixie.
7+
* It is not possible to have the same application code work with both.
8+
* It is necessary to have two sets of code and conditional compilation.
9+
*
10+
* Environment: Preprocessor symbols set by build system:
11+
* USE_GPIOD to include the gpiod code
12+
* LIBGPIOD_VERSION e.g. 1.2.3
13+
* LIBGPIOD_VERSION_MAJOR e.g. 1
14+
* LIBGPIOD_VERSION_MINOR e.g. 2
15+
*
16+
* Description: Eventually we would like to put all of the version differences
17+
* in here to avoid cluttering ptt.c more than it is already.
18+
* Currently this is all version 2 code which has no hope of
19+
* building with version 1 library.
20+
*
21+
*---------------------------------------------------------------*/
22+
23+
#if USE_GPIOD // Skip all of this if no GPIOD libary present
24+
25+
#if LIBGPIOD_VERSION_MAJOR >= 2 // Someday we might have v1 and v2 sections
26+
27+
#include "direwolf.h"
28+
29+
#include <gpiod.h>
30+
#include <stdio.h>
31+
#include <unistd.h>
32+
33+
#include <errno.h>
34+
#include <string.h>
35+
36+
#include "textcolor.h"
37+
38+
#include "gpio_common.h"
39+
40+
#define GPIO_MAX_LINES 32
41+
#define GPIO_CONSUMER "DIREWOLF"
42+
43+
//Types
44+
typedef struct gpio_common {
45+
struct gpiod_line_request *request;
46+
unsigned int offset;
47+
bool used;
48+
} gpio_common_t;
49+
50+
// local variables
51+
52+
static gpio_common_t gpio[GPIO_MAX_LINES];
53+
54+
55+
// Function implementations
56+
57+
void gpio_common_init(void) {
58+
text_color_set(DW_COLOR_DEBUG);
59+
dw_printf("Initializing GPIO common structure\n");
60+
for (gpio_num_t i = 0; i < GPIO_MAX_LINES; i++) {
61+
gpio[i].used = false;
62+
}
63+
}
64+
65+
66+
gpio_num_t gpio_common_open_line(const char *chip_name, unsigned int line, bool active_low) {
67+
gpio_num_t gpio_num;
68+
int ret;
69+
70+
struct gpiod_request_config *req_cfg = NULL;
71+
struct gpiod_line_settings *settings;
72+
struct gpiod_line_config *line_cfg;
73+
struct gpiod_chip *chip;
74+
75+
gpio_num = GPIO_COMMON_UNKNOWN;
76+
77+
if (chip_name == NULL) {
78+
text_color_set(DW_COLOR_ERROR);
79+
dw_printf("No chip name supplied.\n");
80+
goto out;
81+
}
82+
83+
text_color_set(DW_COLOR_DEBUG);
84+
dw_printf("Opening GPIO line %d on chip %s\n", line, chip_name);
85+
86+
// Get a free slot
87+
for (gpio_num_t i = 0; i < GPIO_MAX_LINES; i++) {
88+
if (gpio[i].used == false) {
89+
gpio_num = i;
90+
break;
91+
}
92+
}
93+
94+
if (gpio_num == GPIO_COMMON_UNKNOWN) {
95+
text_color_set(DW_COLOR_ERROR);
96+
dw_printf("Too many GPIOs open.\n");
97+
goto out;
98+
}
99+
100+
chip = gpiod_chip_open(chip_name);
101+
102+
if (chip == NULL) {
103+
text_color_set(DW_COLOR_ERROR);
104+
dw_printf("Failed to open GPIO chip %s\n", chip_name);
105+
gpio_num = GPIO_COMMON_UNKNOWN;
106+
goto out;
107+
}
108+
109+
settings = gpiod_line_settings_new();
110+
111+
if (settings == NULL) {
112+
text_color_set(DW_COLOR_ERROR);
113+
dw_printf("Unable to allocate memory for line settings \n");
114+
gpio_num = GPIO_COMMON_UNKNOWN;
115+
goto close_chip;
116+
}
117+
118+
gpiod_line_settings_set_direction(settings,
119+
GPIOD_LINE_DIRECTION_OUTPUT);
120+
gpiod_line_settings_set_output_value(settings, 0);
121+
gpiod_line_settings_set_active_low(settings, active_low);
122+
123+
line_cfg = gpiod_line_config_new();
124+
125+
if (!line_cfg) {
126+
gpio_num = GPIO_COMMON_UNKNOWN;
127+
goto free_settings;
128+
}
129+
130+
ret = gpiod_line_config_add_line_settings(line_cfg, &line, 1,
131+
settings);
132+
if (ret < 0) {
133+
text_color_set(DW_COLOR_ERROR);
134+
dw_printf("Failed to add line settings\n");
135+
gpio_num = GPIO_COMMON_UNKNOWN;
136+
goto free_line_config;
137+
}
138+
139+
req_cfg = gpiod_request_config_new();
140+
if (!req_cfg) {
141+
goto free_line_config;
142+
}
143+
144+
gpiod_request_config_set_consumer(req_cfg, GPIO_CONSUMER);
145+
146+
gpio[gpio_num].request = gpiod_chip_request_lines(chip, req_cfg, line_cfg);
147+
148+
if (gpio[gpio_num].request == NULL) {
149+
text_color_set(DW_COLOR_ERROR);
150+
dw_printf("Failed to request GPIO line %d\n", gpio_num);
151+
gpio_num = GPIO_COMMON_UNKNOWN;
152+
goto free_line_config;
153+
} else {
154+
gpio[gpio_num].used = true;
155+
gpio[gpio_num].offset = line;
156+
}
157+
158+
free_line_config:
159+
gpiod_line_config_free(line_cfg);
160+
161+
free_settings:
162+
gpiod_line_settings_free(settings);
163+
164+
close_chip:
165+
gpiod_chip_close(chip);
166+
167+
168+
out:
169+
170+
return gpio_num;
171+
}
172+
173+
174+
int gpio_common_release_line(gpio_num_t gpio_num) {
175+
if (gpio_num >= GPIO_MAX_LINES) {
176+
return GPIO_COMMON_ERR;
177+
}
178+
179+
if (gpio[gpio_num].request != NULL) {
180+
gpiod_line_request_release(gpio[gpio_num].request);
181+
gpio[gpio_num].request = NULL;
182+
}
183+
184+
return 0;
185+
}
186+
187+
188+
int gpio_common_set(gpio_num_t gpio_num, bool val) {
189+
if (gpio_num >= GPIO_MAX_LINES || gpio[gpio_num].request == NULL) {
190+
return GPIO_COMMON_ERR;
191+
}
192+
uint16_t gpiod_val;
193+
194+
if (val) {
195+
gpiod_val = GPIOD_LINE_VALUE_ACTIVE;
196+
} else {
197+
gpiod_val = GPIOD_LINE_VALUE_INACTIVE;
198+
}
199+
200+
201+
int ret = gpiod_line_request_set_value(gpio[gpio_num].request, gpio[gpio_num].offset, gpiod_val);
202+
if (ret < 0) {
203+
text_color_set(DW_COLOR_ERROR);
204+
dw_printf("Error setting line\n");
205+
return GPIO_COMMON_ERR;
206+
}
207+
return 0;
208+
}
209+
210+
211+
int gpio_common_close(void) {
212+
213+
for (gpio_num_t i = 0; i < GPIO_MAX_LINES; i++) {
214+
gpio_common_release_line(i);
215+
}
216+
217+
return 0;
218+
}
219+
220+
#endif // LIBGPIOD_VERSION_MAJOR >= 2
221+
222+
#endif // USE_GPIOD
223+
224+
// end gpio_common.c

src/gpio_common.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#ifndef GPIO_COMMON_H
2+
#define GPIO_COMMON_H
3+
4+
#if USE_GPIOD // Skip all if no libgpiod available
5+
6+
#if LIBGPIOD_VERSION_MAJOR >= 2 // Someday we might have v1 and v2 sections
7+
8+
#ifdef __cplusplus
9+
extern "C" {
10+
#endif
11+
12+
#include <gpiod.h>
13+
#include <stdint.h>
14+
15+
// Types
16+
typedef uint16_t gpio_num_t;
17+
18+
// Return values
19+
#define GPIO_COMMON_UNKNOWN UINT16_MAX
20+
#define GPIO_COMMON_OK 0
21+
#define GPIO_COMMON_ERR -1
22+
23+
24+
// Public functions
25+
26+
void gpio_common_init(void);
27+
gpio_num_t gpio_common_open_line(const char *chip_name, unsigned int line, bool active_low);
28+
int gpio_common_close(void);
29+
int gpio_common_set(gpio_num_t gpio_num, bool val);
30+
31+
#ifdef __cplusplus
32+
}
33+
#endif
34+
35+
#endif // LIBGPIOD_VERSION_MAJOR >= 2
36+
37+
#endif // USE_GPIOD
38+
39+
#endif // GPIO_COMMON_H

0 commit comments

Comments
 (0)