Skip to content
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