Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ list(APPEND direwolf_SOURCES
dwgpsnmea.c
dwgpsd.c
mheard.c
gpio_common.c
)

if(LINUX)
Expand Down
20 changes: 11 additions & 9 deletions src/audio.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*
* Purpose: Interface to audio device commonly called a "sound card"
* for historical reasons.
*
*
*---------------------------------------------------------------*/


Expand All @@ -19,13 +19,14 @@
#include "direwolf.h" /* for MAX_RADIO_CHANS and MAX_TOTAL_CHANS used throughout the application. */
#include "ax25_pad.h" /* for AX25_MAX_ADDR_LEN */
#include "version.h"

#include "gpio_common.h"


/*
* PTT control.
* PTT control.
*/

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


typedef enum sanity_e { SANITY_APRS, SANITY_AX25, SANITY_NONE } sanity_t;


struct audio_s {

Expand Down Expand Up @@ -276,7 +277,7 @@ struct audio_s {


/* Additional properties for transmit. */

/* Originally we had control outputs only for PTT. */
/* In version 1.2, we generalize this to allow others such as DCD. */
/* In version 1.4 we add CON for connected to another station. */
Expand All @@ -288,8 +289,8 @@ struct audio_s {
#define OCTYPE_CON 2

#define NUM_OCTYPES 3 /* number of values above. i.e. last value +1. */
struct {

struct {

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

Expand All @@ -304,7 +305,7 @@ struct audio_s {
/* have a name like /dev/hidraw1 for Linux or */
/* \\?\hid#vid_0d8c&pid_0008&mi_03#8&39d3555&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030} */
/* for Windows. Largest observed was 95 but add some extra to be safe. */

ptt_line_t ptt_line; /* Control line when using serial port. PTT_LINE_RTS, PTT_LINE_DTR. */
ptt_line_t ptt_line2; /* Optional second one: PTT_LINE_NONE when not used. */

Expand All @@ -330,6 +331,7 @@ struct audio_s {

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

#ifdef USE_HAMLIB

Expand Down
179 changes: 179 additions & 0 deletions src/gpio_common.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
#include <gpiod.h>
#include <stdio.h>
#include <unistd.h>

#include <errno.h>
#include <string.h>

#include "gpio_common.h"

#define GPIO_MAX_LINES 32
#define GPIO_CONSUMER "DIREWOLF"

//Types
typedef struct gpio_common {
struct gpiod_line_request *request;
unsigned int offset;
bool used;
} gpio_common_t;

// local variables

static gpio_common_t gpio[GPIO_MAX_LINES];


// Function implementations

void gpio_common_init(void) {
fprintf(stderr, "Initializing GPIO common structure\n");
for (gpio_num_t i = 0; i < GPIO_MAX_LINES; i++) {
gpio[i].used = false;
}
}


gpio_num_t gpio_common_open_line(const char *chip_name, unsigned int line, bool active_low) {
gpio_num_t gpio_num;
int ret;

struct gpiod_request_config *req_cfg = NULL;
struct gpiod_line_settings *settings;
struct gpiod_line_config *line_cfg;
struct gpiod_chip *chip;

gpio_num = GPIO_COMMON_UNKNOWN;

if (chip_name == NULL) {
fprintf(stderr, "No chip name supplied.\n");
goto out;
}

fprintf(stderr, "Opening GPIO line %d on chip %s\n", line, chip_name);

// Get a free slot
for (gpio_num_t i = 0; i < GPIO_MAX_LINES; i++) {
if (gpio[i].used == false) {
gpio_num = i;
break;
}
}

if (gpio_num == GPIO_COMMON_UNKNOWN) {
fprintf(stderr, "Too many GPIOs open.\n");
goto out;
}

chip = gpiod_chip_open(chip_name);

if (chip == NULL) {
fprintf(stderr, "Failed to open GPIO chip %s\n", chip_name);
gpio_num = GPIO_COMMON_UNKNOWN;
goto out;
}

settings = gpiod_line_settings_new();

if (settings == NULL) {
fprintf(stderr, "Unable to allocate memory for line settings \n");
gpio_num = GPIO_COMMON_UNKNOWN;
goto close_chip;
}

gpiod_line_settings_set_direction(settings,
GPIOD_LINE_DIRECTION_OUTPUT);
gpiod_line_settings_set_output_value(settings, 0);
gpiod_line_settings_set_active_low(settings, active_low);

line_cfg = gpiod_line_config_new();

if (!line_cfg) {
gpio_num = GPIO_COMMON_UNKNOWN;
goto free_settings;
}

ret = gpiod_line_config_add_line_settings(line_cfg, &line, 1,
settings);
if (ret < 0) {
fprintf(stderr, "Failed to add line settings\n");
gpio_num = GPIO_COMMON_UNKNOWN;
goto free_line_config;
}

req_cfg = gpiod_request_config_new();
if (!req_cfg) {
goto free_line_config;
}

gpiod_request_config_set_consumer(req_cfg, "FLDIGI");

gpio[gpio_num].request = gpiod_chip_request_lines(chip, req_cfg, line_cfg);

if (gpio[gpio_num].request == NULL) {
fprintf(stderr, "Failed to request GPIO line %d\n", gpio_num);
gpio_num = GPIO_COMMON_UNKNOWN;
goto free_line_config;
} else {
gpio[gpio_num].used = true;
gpio[gpio_num].offset = line;
}

free_line_config:
gpiod_line_config_free(line_cfg);

free_settings:
gpiod_line_settings_free(settings);

close_chip:
gpiod_chip_close(chip);


out:

return gpio_num;
}


int gpio_common_release_line(gpio_num_t gpio_num) {
if (gpio_num >= GPIO_MAX_LINES) {
return GPIO_COMMON_ERR;
}

if (gpio[gpio_num].request != NULL) {
gpiod_line_request_release(gpio[gpio_num].request);
gpio[gpio_num].request = NULL;
}

return 0;
}


int gpio_common_set(gpio_num_t gpio_num, bool val) {
if (gpio_num >= GPIO_MAX_LINES || gpio[gpio_num].request == NULL) {
return GPIO_COMMON_ERR;
}
uint16_t gpiod_val;

if (val) {
gpiod_val = GPIOD_LINE_VALUE_ACTIVE;
} else {
gpiod_val = GPIOD_LINE_VALUE_INACTIVE;
}


int ret = gpiod_line_request_set_value(gpio[gpio_num].request, gpio[gpio_num].offset, gpiod_val);
if (ret < 0) {
fprintf(stderr, "Error setting line\n");
return GPIO_COMMON_ERR;
}
return 0;
}


int gpio_common_close(void) {

for (gpio_num_t i = 0; i < GPIO_MAX_LINES; i++) {
gpio_common_release_line(i);
}

return 0;
}
32 changes: 32 additions & 0 deletions src/gpio_common.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#ifndef GPIO_COMMON_H
#define GPIO_COMMON_H


#ifdef __cplusplus
extern "C" {
#endif

#include <gpiod.h>
#include <stdint.h>

// Types
typedef uint16_t gpio_num_t;

// Return values
#define GPIO_COMMON_UNKNOWN UINT16_MAX
#define GPIO_COMMON_OK 0
#define GPIO_COMMON_ERR -1


// Public functions

void gpio_common_init(void);
gpio_num_t gpio_common_open_line(const char *chip_name, unsigned int line, bool active_low);
int gpio_common_close(void);
int gpio_common_set(gpio_num_t gpio_num, bool val);

#ifdef __cplusplus
}
#endif

#endif // GPIO_COMMON_H
Loading