Skip to content

Commit 54c29c1

Browse files
committed
gpiod v2 support
1 parent 4535fdb commit 54c29c1

File tree

5 files changed

+237
-59
lines changed

5 files changed

+237
-59
lines changed

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: 11 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,7 @@ struct audio_s {
330331

331332
int ptt_invert; /* Invert the output. */
332333
int ptt_invert2; /* Invert the secondary output. */
334+
gpio_num_t gpio_num; /* Handle from libgpiod. Valid only when ptt_method is PTT_METHOD_GPIOD. */
333335

334336
#ifdef USE_HAMLIB
335337

src/gpio_common.c

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
#include <gpiod.h>
2+
#include <stdio.h>
3+
#include <unistd.h>
4+
5+
#include <errno.h>
6+
#include <string.h>
7+
8+
#include "gpio_common.h"
9+
10+
#define GPIO_MAX_LINES 32
11+
#define GPIO_CONSUMER "FLDIGI"
12+
13+
//Types
14+
typedef struct gpio_common {
15+
struct gpiod_line_request *request;
16+
unsigned int offset;
17+
bool used;
18+
} gpio_common_t;
19+
20+
// local variables
21+
22+
static gpio_common_t gpio[GPIO_MAX_LINES];
23+
24+
void gpio_common_init(void) {
25+
fprintf(stderr, "Initializing GPIO common structure\n");
26+
for (gpio_num_t i = 0; i < GPIO_MAX_LINES; i++) {
27+
gpio[i].used = false;
28+
}
29+
}
30+
31+
32+
gpio_num_t gpio_common_open_line(const char *chip_name, unsigned int line, bool active_low) {
33+
gpio_num_t gpio_num;
34+
int ret;
35+
36+
struct gpiod_request_config *req_cfg = NULL;
37+
struct gpiod_line_settings *settings;
38+
struct gpiod_line_config *line_cfg;
39+
struct gpiod_chip *chip;
40+
41+
gpio_num = GPIO_COMMON_UNKNOWN;
42+
43+
if (chip_name == NULL) {
44+
fprintf(stderr, "No chip name supplied.\n");
45+
goto out;
46+
}
47+
48+
fprintf(stderr, "Opening GPIO line %d on chip %s\n", line, chip_name);
49+
50+
// Get a free slot
51+
for (gpio_num_t i = 0; i < GPIO_MAX_LINES; i++) {
52+
if (gpio[i].used == false) {
53+
gpio_num = i;
54+
break;
55+
}
56+
}
57+
58+
if (gpio_num == GPIO_COMMON_UNKNOWN) {
59+
fprintf(stderr, "Too many GPIOs open.\n");
60+
goto out;
61+
}
62+
63+
chip = gpiod_chip_open(chip_name);
64+
65+
if (chip == NULL) {
66+
fprintf(stderr, "Failed to open GPIO chip %s\n", chip_name);
67+
gpio_num = GPIO_COMMON_UNKNOWN;
68+
goto out;
69+
}
70+
71+
settings = gpiod_line_settings_new();
72+
73+
if (settings == NULL) {
74+
fprintf(stderr, "Unable to allocate memory for line settings \n");
75+
gpio_num = GPIO_COMMON_UNKNOWN;
76+
goto close_chip;
77+
}
78+
79+
gpiod_line_settings_set_direction(settings,
80+
GPIOD_LINE_DIRECTION_OUTPUT);
81+
gpiod_line_settings_set_output_value(settings, 0);
82+
gpiod_line_settings_set_active_low(settings, active_low);
83+
84+
line_cfg = gpiod_line_config_new();
85+
86+
if (!line_cfg) {
87+
gpio_num = GPIO_COMMON_UNKNOWN;
88+
goto free_settings;
89+
}
90+
91+
ret = gpiod_line_config_add_line_settings(line_cfg, &line, 1,
92+
settings);
93+
if (ret < 0) {
94+
fprintf(stderr, "Failed to add line settings\n");
95+
gpio_num = GPIO_COMMON_UNKNOWN;
96+
goto free_line_config;
97+
}
98+
99+
req_cfg = gpiod_request_config_new();
100+
if (!req_cfg) {
101+
goto free_line_config;
102+
}
103+
104+
gpiod_request_config_set_consumer(req_cfg, "FLDIGI");
105+
106+
gpio[gpio_num].request = gpiod_chip_request_lines(chip, req_cfg, line_cfg);
107+
108+
if (gpio[gpio_num].request == NULL) {
109+
fprintf(stderr, "Failed to request GPIO line %d\n", gpio_num);
110+
gpio_num = GPIO_COMMON_UNKNOWN;
111+
goto free_line_config;
112+
} else {
113+
gpio[gpio_num].used = true;
114+
gpio[gpio_num].offset = line;
115+
}
116+
117+
free_line_config:
118+
gpiod_line_config_free(line_cfg);
119+
120+
free_settings:
121+
gpiod_line_settings_free(settings);
122+
123+
close_chip:
124+
gpiod_chip_close(chip);
125+
126+
127+
out:
128+
129+
return gpio_num;
130+
}
131+
132+
133+
int gpio_common_release_line(gpio_num_t gpio_num) {
134+
if (gpio_num >= GPIO_MAX_LINES) {
135+
return -1;
136+
}
137+
138+
if (gpio[gpio_num].request != NULL) {
139+
gpiod_line_request_release(gpio[gpio_num].request);
140+
gpio[gpio_num].request = NULL;
141+
}
142+
143+
return 0;
144+
}
145+
146+
147+
int gpio_common_set(gpio_num_t gpio_num, bool val) {
148+
if (gpio_num >= GPIO_MAX_LINES || gpio[gpio_num].request == NULL) {
149+
return -1;
150+
}
151+
uint16_t gpiod_val;
152+
153+
if (val) {
154+
gpiod_val = GPIOD_LINE_VALUE_ACTIVE;
155+
} else {
156+
gpiod_val = GPIOD_LINE_VALUE_INACTIVE;
157+
}
158+
159+
160+
int ret = gpiod_line_request_set_value(gpio[gpio_num].request, gpio[gpio_num].offset, gpiod_val);
161+
if (ret < 0) {
162+
fprintf(stderr, "Error setting line\n");
163+
return -1;
164+
}
165+
return 0;
166+
}
167+
168+
169+
int gpio_common_close(void) {
170+
171+
for (gpio_num_t i = 0; i < GPIO_MAX_LINES; i++) {
172+
gpio_common_release_line(i);
173+
}
174+
175+
return 0;
176+
}

src/gpio_common.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#ifdef __cplusplus
2+
extern "C" {
3+
#endif
4+
5+
#include <gpiod.h>
6+
#include <stdint.h>
7+
8+
9+
10+
typedef uint16_t gpio_num_t;
11+
#define GPIO_COMMON_UNKNOWN UINT16_MAX
12+
#define GPIO_COMMON_OK 0
13+
#define GPIO_COMMON_ERR -1
14+
15+
16+
// Public functions
17+
18+
void gpio_common_init(void);
19+
gpio_num_t gpio_common_open_line(const char *chip_name, unsigned int line, bool active_low);
20+
int gpio_common_close(void);
21+
int gpio_common_set(gpio_num_t gpio_num, bool val);
22+
23+
#ifdef __cplusplus
24+
}
25+
#endif

0 commit comments

Comments
 (0)