diff --git a/audio.h b/audio.h index 3f6017aa..2702b9dd 100644 --- a/audio.h +++ b/audio.h @@ -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. */ diff --git a/config.c b/config.c index d0ebee66..59fe26b9 100644 --- a/config.c +++ b/config.c @@ -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. diff --git a/hdlc_rec.c b/hdlc_rec.c index e645ee1b..407ec4cd 100644 --- a/hdlc_rec.c +++ b/hdlc_rec.c @@ -42,6 +42,15 @@ #include "demod_9600.h" /* for descramble() */ #include "ptt.h" +#if __WIN32__ +#else +#include +#include +#include +#include +#include +#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= 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 */ diff --git a/ptt.c b/ptt.c index f4129716..d3f120e1 100644 --- a/ptt.c +++ b/ptt.c @@ -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