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
Closed
6 changes: 6 additions & 0 deletions audio.h
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down
24 changes: 24 additions & 0 deletions config.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
49 changes: 48 additions & 1 deletion hdlc_rec.c
Original file line number Diff line number Diff line change
Expand Up @@ -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. */

Expand Down Expand Up @@ -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)
Expand All @@ -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;
Expand Down Expand Up @@ -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 */

Expand Down
190 changes: 103 additions & 87 deletions ptt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
}

Expand All @@ -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);
}

Expand All @@ -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);
}

Expand All @@ -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
Expand Down