Skip to content

Support for GPIO TX inhibit line #11

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 11 commits into from
6 changes: 6 additions & 0 deletions audio.h
Original file line number Diff line number Diff line change
@@ -198,6 +198,12 @@ struct audio_s {

} octrl[NUM_OCTYPES];

struct {
int enabled;
int gpio;
int invert;
} txinh;

/* Transmit timing. */

int dwait; /* First wait extra time for receiver squelch. */
24 changes: 24 additions & 0 deletions config.c
Original file line number Diff line number Diff line change
@@ -1450,6 +1450,30 @@ void config_init (char *fname, struct audio_s *p_audio_config,

} /* end of PTT */

/*
* TXINH - Input for TX inhibit signal
*/

else if (strcasecmp(t, "TXINH") == 0) {
t = strtok (NULL, " ,\t\n\r");
if (t == NULL) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file line %d: Missing GPIO number for TXINH.\n",
line);
continue;
}

p_audio_config->achan[channel].txinh.enabled = 1;

if (*t == '-') {
p_audio_config->achan[channel].txinh.gpio = atoi(t+1);
p_audio_config->achan[channel].txinh.invert = 1;
}
else {
p_audio_config->achan[channel].txinh.gpio = atoi(t);
p_audio_config->achan[channel].txinh.invert = 0;
}
} /* end of TXINH */

/*
* DWAIT - Extra delay for receiver squelch.
49 changes: 48 additions & 1 deletion hdlc_rec.c
Original file line number Diff line number Diff line change
@@ -42,6 +42,15 @@
#include "demod_9600.h" /* for descramble() */
#include "ptt.h"

#if __WIN32__
#else
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#endif


//#define TEST 1 /* Define for unit testing. */

@@ -125,6 +134,8 @@ static void dcd_change (int chan, int subchan, int state);
*
***********************************************************************************/

static struct audio_s *save_audio_config_p;

static int was_init = 0;

void hdlc_rec_init (struct audio_s *pa)
@@ -137,6 +148,8 @@ void hdlc_rec_init (struct audio_s *pa)

assert (pa != NULL);

save_audio_config_p = pa;

for (j=0; j<MAX_CHANS; j++)
{
composite_dcd[j] = 0;
@@ -632,10 +645,44 @@ static void dcd_change (int chan, int subchan, int state)
int hdlc_rec_data_detect_any (int chan)
{
int subchan;
int busy = 0;

assert (chan >= 0 && chan < MAX_CHANS);

return (composite_dcd[chan] != 0);
if (composite_dcd[chan] != 0) busy = 1;

#if __WIN32__
#else

if (save_audio_config_p->achan[chan].txinh.enabled) {
int fd;
char stemp[80];

sprintf (stemp, "/sys/class/gpio/gpio%d/value", save_audio_config_p->achan[chan].txinh.gpio);

fd = open(stemp, O_RDONLY);
if (fd < 0) {
int e = errno;
text_color_set(DW_COLOR_ERROR);
dw_printf ("Error opening %s to check TXINH.\n", stemp);
dw_printf ("%s\n", strerror(e));
return (busy != 0);
}

char vtemp[2];
if (read (fd, vtemp, 1) != 1) {
int e = errno;
text_color_set(DW_COLOR_ERROR);
dw_printf ("Error getting GPIO %d value for TXINH\n", save_audio_config_p->achan[chan].txinh.gpio);
dw_printf ("%s\n", strerror(e));
}
close (fd);

if (atoi(vtemp) != save_audio_config_p->achan[chan].txinh.invert) busy = 1;
}
#endif

return (busy != 0);

} /* end hdlc_rec_data_detect_any */

190 changes: 103 additions & 87 deletions ptt.c
Original file line number Diff line number Diff line change
@@ -155,6 +155,102 @@ static HANDLE ptt_fd[MAX_CHANS][NUM_OCTYPES];

static char otnames[NUM_OCTYPES][8];

void export_gpio(int gpio, int invert, int direction)
{
HANDLE fd;
char stemp[80];
struct stat finfo;
int err;

fd = open("/sys/class/gpio/export", O_WRONLY);
if (fd < 0) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("Permissions do not allow ordinary users to access GPIO.\n");
dw_printf ("Log in as root and type this command:\n");
dw_printf (" chmod go+w /sys/class/gpio/export /sys/class/gpio/unexport\n");
exit (1);
}
sprintf (stemp, "%d", gpio);
if (write (fd, stemp, strlen(stemp)) != strlen(stemp)) {
int e = errno;
/* Ignore EBUSY error which seems to mean */
/* the device node already exists. */
if (e != EBUSY) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("Error writing \"%s\" to /sys/class/gpio/export, errno=%d\n", stemp, e);
dw_printf ("%s\n", strerror(e));
exit (1);
}
}
close (fd);

/*
* We will have the same permission problem if not root.
* We only care about "direction" and "value".
*/
sprintf (stemp, "sudo chmod go+rw /sys/class/gpio/gpio%d/direction", gpio);
err = system (stemp);
sprintf (stemp, "sudo chmod go+rw /sys/class/gpio/gpio%d/value", gpio);
err = system (stemp);

sprintf (stemp, "/sys/class/gpio/gpio%d/value", gpio);

if (stat(stemp, &finfo) < 0) {
int e = errno;
text_color_set(DW_COLOR_ERROR);
dw_printf ("Failed to get status for %s \n", stemp);
dw_printf ("%s\n", strerror(e));
exit (1);
}

if (geteuid() != 0) {
if ( ! (finfo.st_mode & S_IWOTH)) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("Permissions do not allow ordinary users to access GPIO.\n");
dw_printf ("Log in as root and type these commands:\n");
dw_printf (" chmod go+rw /sys/class/gpio/gpio%d/direction", gpio);
dw_printf (" chmod go+rw /sys/class/gpio/gpio%d/value", gpio);
exit (1);
}
}

/*
* Set direction and initial value.
*/

sprintf (stemp, "/sys/class/gpio/gpio%d/direction", gpio);
fd = open(stemp, O_WRONLY);
if (fd < 0) {
int e = errno;
text_color_set(DW_COLOR_ERROR);
dw_printf ("Error opening %s\n", stemp);
dw_printf ("%s\n", strerror(e));
exit (1);
}

char gpio_val[8];
if (direction) {
if (invert) {
strcpy (gpio_val, "high");
}
else {
strcpy (gpio_val, "low");
}
}
else {
strcpy (gpio_val, "in");
}

if (write (fd, gpio_val, strlen(gpio_val)) != strlen(gpio_val)) {
int e = errno;
text_color_set(DW_COLOR_ERROR);
dw_printf ("Error writing direction to %s\n", stemp);
dw_printf ("%s\n", strerror(e));
exit (1);
}
close (fd);
}

void ptt_init (struct audio_s *audio_config_p)
{
int ch;
@@ -326,6 +422,7 @@ void ptt_init (struct audio_s *audio_config_p)
using_gpio = 1;
}
}
if (audio_config_p->achan[ch].txinh.enabled) using_gpio = 1;
}
}

@@ -343,7 +440,7 @@ void ptt_init (struct audio_s *audio_config_p)
if (stat("/sys/class/gpio/export", &finfo) < 0) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("This system is not configured with the GPIO user interface.\n");
dw_printf ("Use a different method for PTT control.\n");
dw_printf ("Use a different method for PTT, DCD, or TXINH control.\n");
exit (1);
}

@@ -367,7 +464,7 @@ void ptt_init (struct audio_s *audio_config_p)
/* Unexpected because we could do it before. */
text_color_set(DW_COLOR_ERROR);
dw_printf ("This system is not configured with the GPIO user interface.\n");
dw_printf ("Use a different method for PTT control.\n");
dw_printf ("Use a different method for PTT, DCD, or TXINH control.\n");
exit (1);
}

@@ -392,93 +489,12 @@ void ptt_init (struct audio_s *audio_config_p)
int ot;
for (ot = 0; ot < NUM_OCTYPES; ot++) {
if (audio_config_p->achan[ch].octrl[ot].ptt_method == PTT_METHOD_GPIO) {
char stemp[80];
struct stat finfo;
int err;

fd = open("/sys/class/gpio/export", O_WRONLY);
if (fd < 0) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("Permissions do not allow ordinary users to access GPIO.\n");
dw_printf ("Log in as root and type this command:\n");
dw_printf (" chmod go+w /sys/class/gpio/export /sys/class/gpio/unexport\n");
exit (1);
}
sprintf (stemp, "%d", audio_config_p->achan[ch].octrl[ot].ptt_gpio);
if (write (fd, stemp, strlen(stemp)) != strlen(stemp)) {
int e = errno;
/* Ignore EBUSY error which seems to mean */
/* the device node already exists. */
if (e != EBUSY) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("Error writing \"%s\" to /sys/class/gpio/export, errno=%d\n", stemp, e);
dw_printf ("%s\n", strerror(e));
exit (1);
}
}
close (fd);

/*
* We will have the same permission problem if not root.
* We only care about "direction" and "value".
*/
sprintf (stemp, "sudo chmod go+rw /sys/class/gpio/gpio%d/direction", audio_config_p->achan[ch].octrl[ot].ptt_gpio);
err = system (stemp);
sprintf (stemp, "sudo chmod go+rw /sys/class/gpio/gpio%d/value", audio_config_p->achan[ch].octrl[ot].ptt_gpio);
err = system (stemp);

sprintf (stemp, "/sys/class/gpio/gpio%d/value", audio_config_p->achan[ch].octrl[ot].ptt_gpio);

if (stat(stemp, &finfo) < 0) {
int e = errno;
text_color_set(DW_COLOR_ERROR);
dw_printf ("Failed to get status for %s \n", stemp);
dw_printf ("%s\n", strerror(e));
exit (1);
}

if (geteuid() != 0) {
if ( ! (finfo.st_mode & S_IWOTH)) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("Permissions do not allow ordinary users to access GPIO.\n");
dw_printf ("Log in as root and type these commands:\n");
dw_printf (" chmod go+rw /sys/class/gpio/gpio%d/direction", audio_config_p->achan[ch].octrl[ot].ptt_gpio);
dw_printf (" chmod go+rw /sys/class/gpio/gpio%d/value", audio_config_p->achan[ch].octrl[ot].ptt_gpio);
exit (1);
}
}

/*
* Set output direction with initial state off.
*/

sprintf (stemp, "/sys/class/gpio/gpio%d/direction", audio_config_p->achan[ch].octrl[ot].ptt_gpio);
fd = open(stemp, O_WRONLY);
if (fd < 0) {
int e = errno;
text_color_set(DW_COLOR_ERROR);
dw_printf ("Error opening %s\n", stemp);
dw_printf ("%s\n", strerror(e));
exit (1);
}

char hilo[8];
if (audio_config_p->achan[ch].octrl[ot].ptt_invert) {
strcpy (hilo, "high");
}
else {
strcpy (hilo, "low");
}
if (write (fd, hilo, strlen(hilo)) != strlen(hilo)) {
int e = errno;
text_color_set(DW_COLOR_ERROR);
dw_printf ("Error writing initial state to %s\n", stemp);
dw_printf ("%s\n", strerror(e));
exit (1);
}
close (fd);
export_gpio(audio_config_p->achan[ch].octrl[ot].ptt_gpio, audio_config_p->achan[ch].octrl[ot].ptt_invert, 1);
}
}
if (audio_config_p->achan[ch].txinh.enabled) {
export_gpio(audio_config_p->achan[ch].txinh.gpio, audio_config_p->achan[ch].txinh.invert, 0);
}
}
}
#endif