From 64f9313f77e618f55cf725c7ab8ccaa09674bd2c Mon Sep 17 00:00:00 2001 From: Alex Swedenburg Date: Tue, 17 Nov 2015 09:27:31 -0700 Subject: [PATCH 1/4] TXINH config changes --- audio.h | 10 ++++++++++ config.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/audio.h b/audio.h index c493eef..046d62f 100644 --- a/audio.h +++ b/audio.h @@ -201,6 +201,16 @@ struct audio_s { } octrl[NUM_OCTYPES]; +#define ICTYPE_TXINH 0 + +#define NUM_ICTYPES 1 + + struct { + int enable; /* should we bother checking this input? */ + int gpio; /* GPIO number */ + int invert; /* 1 = active low */ + } ictrl[NUM_ICTYPES]; + /* Transmit timing. */ int dwait; /* First wait extra time for receiver squelch. */ diff --git a/config.c b/config.c index 72e60c9..c1f71d8 100644 --- a/config.c +++ b/config.c @@ -1598,6 +1598,52 @@ void config_init (char *fname, struct audio_s *p_audio_config, } /* end of PTT */ +/* + * INPUTS + * + * TXINH - TX holdoff input + * + * xxx GPIO [-]gpio-num (only type supported yet) + */ + + else if (strcasecmp(t, "TXINH") == 0) { + int it; + char itname[8]; + + it = ICTYPE_TXINH; + strlcpy (itname, "TXINH", sizeof(itname)); + + t = split(NULL,0); + if (t == NULL) { + text_color_set(DW_COLOR_ERROR); + dw_printf ("Config file line %d: Missing input type name for %s command.\n", line, itname); + continue; + } + + if (strcasecmp(t, "GPIO") == 0) { + +#if __WIN32__ + text_color_set(DW_COLOR_ERROR); + dw_printf ("Config file line %d: %s with GPIO is only available on Linux.\n", line, itname); +#else + t = split(NULL,0); + if (t == NULL) { + text_color_set(DW_COLOR_ERROR); + dw_printf ("Config file line %d: Missing GPIO number for %s.\n", line, itname); + continue; + } + + if (*t == '-') { + p_audio_config->achan[channel].ictrl[it].gpio = atoi(t+1); + p_audio_config->achan[channel].ictrl[it].invert = 1; + } + else { + p_audio_config->achan[channel].ictrl[it].gpio = atoi(t); + p_audio_config->achan[channel].ictrl[it].invert = 0; + } +#endif + } + } /* * DWAIT - Extra delay for receiver squelch. From ebacfea51773999bc89b36f08bfe650cde88ef6b Mon Sep 17 00:00:00 2001 From: Alex Swedenburg Date: Tue, 17 Nov 2015 10:06:58 -0700 Subject: [PATCH 2/4] PTT init changes for TXINH --- audio.h | 2 +- config.c | 1 + ptt.c | 225 +++++++++++++++++++++++++++++-------------------------- 3 files changed, 122 insertions(+), 106 deletions(-) diff --git a/audio.h b/audio.h index 046d62f..a84d196 100644 --- a/audio.h +++ b/audio.h @@ -206,7 +206,7 @@ struct audio_s { #define NUM_ICTYPES 1 struct { - int enable; /* should we bother checking this input? */ + ptt_method_t method; /* none, serial port, GPIO, LPT. */ int gpio; /* GPIO number */ int invert; /* 1 = active low */ } ictrl[NUM_ICTYPES]; diff --git a/config.c b/config.c index c1f71d8..11391a3 100644 --- a/config.c +++ b/config.c @@ -1641,6 +1641,7 @@ void config_init (char *fname, struct audio_s *p_audio_config, p_audio_config->achan[channel].ictrl[it].gpio = atoi(t); p_audio_config->achan[channel].ictrl[it].invert = 0; } + p_audio_config->achan[channel].ictrl[it].method = PTT_METHOD_GPIO; #endif } } diff --git a/ptt.c b/ptt.c index b76775a..693171f 100644 --- a/ptt.c +++ b/ptt.c @@ -147,6 +147,120 @@ void ptt_set_debug(int debug) ptt_debug_level = debug; } +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); + } + snprintf (stemp, sizeof(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); + +/* + Idea for future: + + On the RPi, the device path for GPIO number XX is /sys/class/gpio/gpioXX. + There was a report that it is different for the Cubieboard. For instance + GPIO 61 has gpio61_pi13 in the path. This indicates connector "i" pin 13. + + For another similar single board computer, we find the same thing: + https://www.olimex.com/wiki/A20-OLinuXino-LIME#GPIO_under_Linux + + How should we deal with this? Some possibilities: + + (1) The user might explicitly mention the name in direwolf.conf. + (2) We might be able to find the names in some system device config file. + (3) Get a directory listing of /sys/class/gpio then search for a + matching name. Suppose we wanted GPIO 61. First look for an exact + match to "gpio61". If that is not found, look for something + matching the pattern "gpio61_*". +*/ + +/* + * We will have the same permission problem if not root. + * We only care about "direction" and "value". + */ + snprintf (stemp, sizeof(stemp), "sudo chmod go+rw /sys/class/gpio/gpio%d/direction", gpio); + err = system (stemp); + snprintf (stemp, sizeof(stemp), "sudo chmod go+rw /sys/class/gpio/gpio%d/value", gpio); + err = system (stemp); + + snprintf (stemp, sizeof(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 output direction and initial state + */ + + snprintf (stemp, sizeof(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) { + strlcpy (gpio_val, "high", sizeof(gpio_val)); + } + else { + strlcpy (gpio_val, "low", sizeof(gpio_val)); + } + } + else { + strlcpy (gpio_val, "in", sizeof(gpio_val)); + } + if (write (fd, gpio_val, strlen(gpio_val)) != strlen(gpio_val)) { + 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); +} /*------------------------------------------------------------------- * @@ -368,6 +482,11 @@ void ptt_init (struct audio_s *audio_config_p) using_gpio = 1; } } + for (ot = 0; ot < NUM_ICTYPES; ot++) { + if (audio_config_p->achan[ch].ictrl[ot].method == PTT_METHOD_GPIO) { + using_gpio = 1; + } + } } } @@ -434,111 +553,7 @@ 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); - } - snprintf (stemp, sizeof(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); - -/* - Idea for future: - - On the RPi, the device path for GPIO number XX is /sys/class/gpio/gpioXX. - There was a report that it is different for the Cubieboard. For instance - GPIO 61 has gpio61_pi13 in the path. This indicates connector "i" pin 13. - - For another similar single board computer, we find the same thing: - https://www.olimex.com/wiki/A20-OLinuXino-LIME#GPIO_under_Linux - - How should we deal with this? Some possibilities: - - (1) The user might explicitly mention the name in direwolf.conf. - (2) We might be able to find the names in some system device config file. - (3) Get a directory listing of /sys/class/gpio then search for a - matching name. Suppose we wanted GPIO 61. First look for an exact - match to "gpio61". If that is not found, look for something - matching the pattern "gpio61_*". -*/ - -/* - * We will have the same permission problem if not root. - * We only care about "direction" and "value". - */ - snprintf (stemp, sizeof(stemp), "sudo chmod go+rw /sys/class/gpio/gpio%d/direction", audio_config_p->achan[ch].octrl[ot].ptt_gpio); - err = system (stemp); - snprintf (stemp, sizeof(stemp), "sudo chmod go+rw /sys/class/gpio/gpio%d/value", audio_config_p->achan[ch].octrl[ot].ptt_gpio); - err = system (stemp); - - snprintf (stemp, sizeof(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. - */ - - snprintf (stemp, sizeof(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) { - strlcpy (hilo, "high", sizeof(hilo)); - } - else { - strlcpy (hilo, "low", sizeof(hilo)); - } - 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); } } } From 979385a78ef44b0cef086ed7066bbccd5df32432 Mon Sep 17 00:00:00 2001 From: Alex Swedenburg Date: Tue, 17 Nov 2015 10:10:30 -0700 Subject: [PATCH 3/4] Export GPIO for inputs --- ptt.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ptt.c b/ptt.c index 693171f..78efc6f 100644 --- a/ptt.c +++ b/ptt.c @@ -556,6 +556,11 @@ void ptt_init (struct audio_s *audio_config_p) export_gpio(audio_config_p->achan[ch].octrl[ot].ptt_gpio, audio_config_p->achan[ch].octrl[ot].ptt_invert, 1); } } + for (ot = 0; ot < NUM_ICTYPES; ot++) { + if (audio_config_p->achan[ch].ictrl[ot].method == PTT_METHOD_GPIO) { + export_gpio(audio_config_p->achan[ch].ictrl[ot].gpio, audio_config_p->achan[ch].ictrl[ot].invert, 0); + } + } } } #endif From d9ca8cdc521e14b58469f589604aac33ce09b99b Mon Sep 17 00:00:00 2001 From: Alex Swedenburg Date: Tue, 17 Nov 2015 11:19:12 -0700 Subject: [PATCH 4/4] Implement TXINH --- atest.c | 4 +++ hdlc_rec.c | 6 ++++- ptt.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ ptt.h | 1 + 4 files changed, 85 insertions(+), 1 deletion(-) diff --git a/atest.c b/atest.c index c869698..aa48de7 100644 --- a/atest.c +++ b/atest.c @@ -679,6 +679,10 @@ void ptt_set (int ot, int chan, int ptt_signal) return; } +int get_input (int it, int chan) +{ + return -1; +} static void usage (void) { diff --git a/hdlc_rec.c b/hdlc_rec.c index 975c26c..98a3f90 100644 --- a/hdlc_rec.c +++ b/hdlc_rec.c @@ -634,9 +634,13 @@ void dcd_change (int chan, int subchan, int state) int hdlc_rec_data_detect_any (int chan) { + int busy = 0; + assert (chan >= 0 && chan < MAX_CHANS); - return (composite_dcd[chan] != 0); + if (composite_dcd[chan] != 0) busy = 1; + + if (get_input(ICTYPE_TXINH, chan) == 1) busy = 1; } /* end hdlc_rec_data_detect_any */ diff --git a/ptt.c b/ptt.c index 78efc6f..414c04b 100644 --- a/ptt.c +++ b/ptt.c @@ -147,6 +147,21 @@ void ptt_set_debug(int debug) ptt_debug_level = debug; } +/*------------------------------------------------------------------- + * + * Name: export_gpio + * + * Purpose: Tell the GPIO subsystem to export a GPIO line for + * us to use, and set the initial state of the GPIO. + * + * Inputs: gpio - GPIO line to export + * invert: - Is the GPIO active low? + * direction: - 0 for input, 1 for output + * + * Outputs: None. + * + *------------------------------------------------------------------*/ + void export_gpio(int gpio, int invert, int direction) { HANDLE fd; @@ -843,7 +858,67 @@ void ptt_set (int ot, int chan, int ptt_signal) } /* end ptt_set */ +/*------------------------------------------------------------------- + * + * Name: get_input + * + * Purpose: Read the value of an input line + * + * Inputs: it - Input type (ICTYPE_TCINH supported so far) + * chan - Audio channel number + * + * Outputs: 0 = inactive, 1 = active, -1 = error + * + * ------------------------------------------------------------------*/ +int get_input (int it, int chan) +{ + assert (it >= 0 && it < NUM_ICTYPES); + assert (chan >= 0 && chan < MAX_CHANS); + + if ( ! save_audio_config_p->achan[chan].valid) { + text_color_set(DW_COLOR_ERROR); + dw_printf ("Internal error, get_input ( %d, %d ), did not expect invalid channel.\n", it, chan); + return -1; + } + +#if __WIN32__ +#else + if (save_audio_config_p->achan[chan].ictrl[it].method == PTT_METHOD_GPIO) { + int fd; + char stemp[80]; + + snprintf (stemp, sizeof(stemp), "/sys/class/gpio/gpio%d/value", save_audio_config_p->achan[chan].ictrl[it].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 input.\n", stemp); + dw_printf ("%s\n", strerror(e)); + return -1; + } + + 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\n", save_audio_config_p->achan[chan].ictrl[it].gpio); + dw_printf ("%s\n", strerror(e)); + } + close (fd); + + if (atoi(vtemp) != save_audio_config_p->achan[chan].ictrl[it].invert) { + return 1; + } + else { + return 0; + } + } +#endif + + return -1; /* Method was none, or something went wrong */ +} /*------------------------------------------------------------------- * diff --git a/ptt.h b/ptt.h index 7e9f639..6e75253 100644 --- a/ptt.h +++ b/ptt.h @@ -15,6 +15,7 @@ void ptt_set (int octype, int chan, int ptt); void ptt_term (void); +int get_input (int it, int chan); #endif