Allow more flexible naming of GPIO pins. e.g. CubieBoard.

This commit is contained in:
WB2OSZ 2017-04-01 09:26:31 -04:00
parent b6254da203
commit 2fec597581
3 changed files with 97 additions and 59 deletions

34
audio.h
View File

@ -187,7 +187,7 @@ struct audio_s {
#define OCTYPE_DCD 1 #define OCTYPE_DCD 1
#define OCTYPE_CON 2 #define OCTYPE_CON 2
#define NUM_OCTYPES 4 /* number of values above. WHY IS THIS NOT 3? */ #define NUM_OCTYPES 3 /* number of values above. i.e. last value +1. */
struct { struct {
@ -199,8 +199,19 @@ struct audio_s {
ptt_line_t ptt_line; /* Control line when using serial port. PTT_LINE_RTS, PTT_LINE_DTR. */ ptt_line_t ptt_line; /* Control line when using serial port. PTT_LINE_RTS, PTT_LINE_DTR. */
ptt_line_t ptt_line2; /* Optional second one: PTT_LINE_NONE when not used. */ ptt_line_t ptt_line2; /* Optional second one: PTT_LINE_NONE when not used. */
int ptt_gpio; /* GPIO number. */ int out_gpio_num; /* GPIO number. Originally this was only for PTT. */
/* It is now more general. */
/* octrl array is indexed by PTT, DCD, or CONnected indicator. */
#define MAX_GPIO_NAME_LEN 16 // 12 would cover any case I've seen so this should be safe
char out_gpio_name[MAX_GPIO_NAME_LEN];
/* orginally, gpio number NN was assumed to simply */
/* have the name gpioNN but this turned out not to be */
/* the case for CubieBoard where it was longer. */
/* This is filled in by ptt_init so we don't have to */
/* recalculate it each time we access it. */
int ptt_lpt_bit; /* Bit number for parallel printer port. */ int ptt_lpt_bit; /* Bit number for parallel printer port. */
/* Bit 0 = pin 2, ..., bit 7 = pin 9. */ /* Bit 0 = pin 2, ..., bit 7 = pin 9. */
@ -214,13 +225,26 @@ struct audio_s {
} octrl[NUM_OCTYPES]; } octrl[NUM_OCTYPES];
/* Each channel can also have associated input lines. */
/* So far, we just have one for transmit inhibit. */
#define ICTYPE_TXINH 0 #define ICTYPE_TXINH 0
#define NUM_ICTYPES 1 #define NUM_ICTYPES 1 /* number of values above. i.e. last value +1. */
struct { struct {
ptt_method_t method; /* none, serial port, GPIO, LPT. */ ptt_method_t method; /* none, serial port, GPIO, LPT. */
int gpio; /* GPIO number */
int in_gpio_num; /* GPIO number */
char in_gpio_name[MAX_GPIO_NAME_LEN];
/* orginally, gpio number NN was assumed to simply */
/* have the name gpioNN but this turned out not to be */
/* the case for CubieBoard where it was longer. */
/* This is filled in by ptt_init so we don't have to */
/* recalculate it each time we access it. */
int invert; /* 1 = active low */ int invert; /* 1 = active low */
} ictrl[NUM_ICTYPES]; } ictrl[NUM_ICTYPES];

View File

@ -748,7 +748,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
p_audio_config->adev[0].defined = 1; p_audio_config->adev[0].defined = 1;
for (channel=0; channel<MAX_CHANS; channel++) { for (channel=0; channel<MAX_CHANS; channel++) {
int ot; int ot, it;
p_audio_config->achan[channel].valid = 0; /* One or both channels will be */ p_audio_config->achan[channel].valid = 0; /* One or both channels will be */
/* set to valid when corresponding */ /* set to valid when corresponding */
@ -773,12 +773,18 @@ void config_init (char *fname, struct audio_s *p_audio_config,
strlcpy (p_audio_config->achan[channel].octrl[ot].ptt_device, "", sizeof(p_audio_config->achan[channel].octrl[ot].ptt_device)); strlcpy (p_audio_config->achan[channel].octrl[ot].ptt_device, "", sizeof(p_audio_config->achan[channel].octrl[ot].ptt_device));
p_audio_config->achan[channel].octrl[ot].ptt_line = PTT_LINE_NONE; p_audio_config->achan[channel].octrl[ot].ptt_line = PTT_LINE_NONE;
p_audio_config->achan[channel].octrl[ot].ptt_line2 = PTT_LINE_NONE; p_audio_config->achan[channel].octrl[ot].ptt_line2 = PTT_LINE_NONE;
p_audio_config->achan[channel].octrl[ot].ptt_gpio = 0; p_audio_config->achan[channel].octrl[ot].out_gpio_num = 0;
p_audio_config->achan[channel].octrl[ot].ptt_lpt_bit = 0; p_audio_config->achan[channel].octrl[ot].ptt_lpt_bit = 0;
p_audio_config->achan[channel].octrl[ot].ptt_invert = 0; p_audio_config->achan[channel].octrl[ot].ptt_invert = 0;
p_audio_config->achan[channel].octrl[ot].ptt_invert2 = 0; p_audio_config->achan[channel].octrl[ot].ptt_invert2 = 0;
} }
for (it = 0; it < NUM_ICTYPES; it++) {
p_audio_config->achan[channel].ictrl[it].method = PTT_METHOD_NONE;
p_audio_config->achan[channel].ictrl[it].in_gpio_num = 0;
p_audio_config->achan[channel].ictrl[it].invert = 0;
}
p_audio_config->achan[channel].dwait = DEFAULT_DWAIT; p_audio_config->achan[channel].dwait = DEFAULT_DWAIT;
p_audio_config->achan[channel].slottime = DEFAULT_SLOTTIME; p_audio_config->achan[channel].slottime = DEFAULT_SLOTTIME;
p_audio_config->achan[channel].persist = DEFAULT_PERSIST; p_audio_config->achan[channel].persist = DEFAULT_PERSIST;
@ -1644,11 +1650,11 @@ void config_init (char *fname, struct audio_s *p_audio_config,
} }
if (*t == '-') { if (*t == '-') {
p_audio_config->achan[channel].octrl[ot].ptt_gpio = atoi(t+1); p_audio_config->achan[channel].octrl[ot].out_gpio_num = atoi(t+1);
p_audio_config->achan[channel].octrl[ot].ptt_invert = 1; p_audio_config->achan[channel].octrl[ot].ptt_invert = 1;
} }
else { else {
p_audio_config->achan[channel].octrl[ot].ptt_gpio = atoi(t); p_audio_config->achan[channel].octrl[ot].out_gpio_num = atoi(t);
p_audio_config->achan[channel].octrl[ot].ptt_invert = 0; p_audio_config->achan[channel].octrl[ot].ptt_invert = 0;
} }
p_audio_config->achan[channel].octrl[ot].ptt_method = PTT_METHOD_GPIO; p_audio_config->achan[channel].octrl[ot].ptt_method = PTT_METHOD_GPIO;
@ -1841,11 +1847,11 @@ void config_init (char *fname, struct audio_s *p_audio_config,
} }
if (*t == '-') { if (*t == '-') {
p_audio_config->achan[channel].ictrl[ICTYPE_TXINH].gpio = atoi(t+1); p_audio_config->achan[channel].ictrl[ICTYPE_TXINH].in_gpio_num = atoi(t+1);
p_audio_config->achan[channel].ictrl[ICTYPE_TXINH].invert = 1; p_audio_config->achan[channel].ictrl[ICTYPE_TXINH].invert = 1;
} }
else { else {
p_audio_config->achan[channel].ictrl[ICTYPE_TXINH].gpio = atoi(t); p_audio_config->achan[channel].ictrl[ICTYPE_TXINH].in_gpio_num = atoi(t);
p_audio_config->achan[channel].ictrl[ICTYPE_TXINH].invert = 0; p_audio_config->achan[channel].ictrl[ICTYPE_TXINH].invert = 0;
} }
p_audio_config->achan[channel].ictrl[ICTYPE_TXINH].method = PTT_METHOD_GPIO; p_audio_config->achan[channel].ictrl[ICTYPE_TXINH].method = PTT_METHOD_GPIO;

104
ptt.c
View File

@ -162,6 +162,8 @@ typedef int HANDLE;
#endif #endif
static struct audio_s *save_audio_config_p; /* Save config information for later use. */
static int ptt_debug_level = 0; static int ptt_debug_level = 0;
void ptt_set_debug(int debug) void ptt_set_debug(int debug)
@ -368,44 +370,44 @@ static void get_access_to_gpio (const char *path)
* Purpose: Tell the GPIO subsystem to export a GPIO line for * Purpose: Tell the GPIO subsystem to export a GPIO line for
* us to use, and set the initial state of the GPIO. * us to use, and set the initial state of the GPIO.
* *
* Inputs: gpio - GPIO line number to export. * Inputs: ch - Radio Channel.
* ot - Output type.
* invert: - Is the GPIO active low? * invert: - Is the GPIO active low?
* direction: - 0 for input, 1 for output * direction: - 0 for input, 1 for output
* *
* Outputs: gpio_name - See below. * Outputs: out_gpio_name - in the audio configuration structure.
* in_gpio_name
* *
*------------------------------------------------------------------*/ *------------------------------------------------------------------*/
#ifndef __WIN32__ #ifndef __WIN32__
#define MAX_GPIO_NUM 100 // 76 would handle any case I've seen.
#define MAX_GPIO_NAME_LEN 16 // 12 would handle any case I've seen.
// Raspberry Pi was easy. GPIO 24 has the name gpio24. void export_gpio(int ch, int ot, int invert, int direction)
// Others, such as the Cubieboard, take a little more effort.
// The name might be gpio24_ph11 meaning connector H, pin 11.
// When we "export" GPIO number, we will store the corresponding device name
// here for future use when we want to access it.
// I never saw any references to anything above gpio75 so we will take the easy
// way out and simply index into a fixed size array.
static char gpio_name[MAX_GPIO_NUM][MAX_GPIO_NAME_LEN];
void export_gpio(int gpio, int invert, int direction)
{ {
HANDLE fd; HANDLE fd;
const char gpio_export_path[] = "/sys/class/gpio/export"; const char gpio_export_path[] = "/sys/class/gpio/export";
char gpio_direction_path[80]; char gpio_direction_path[80];
char gpio_value_path[80];
char stemp[16]; char stemp[16];
int gpio_num;
char *gpio_name;
// Raspberry Pi was easy. GPIO 24 has the name gpio24.
// Others, such as the Cubieboard, take a little more effort.
// The name might be gpio24_ph11 meaning connector H, pin 11.
// When we "export" GPIO number, we will store the corresponding
// device name for future use when we want to access it.
if (gpio < 0 || gpio >= MAX_GPIO_NUM) { if (direction) {
text_color_set(DW_COLOR_ERROR); gpio_num = save_audio_config_p->achan[ch].octrl[ot].out_gpio_num;
dw_printf ("GPIO line number %d is invalid. Must be in range of 0 to %d.\n", gpio, MAX_GPIO_NUM - 1); gpio_name = save_audio_config_p->achan[ch].octrl[ot].out_gpio_name;
exit (1);
} }
else {
gpio_num = save_audio_config_p->achan[ch].ictrl[ot].in_gpio_num;
gpio_name = save_audio_config_p->achan[ch].ictrl[ot].in_gpio_name;
}
get_access_to_gpio (gpio_export_path); get_access_to_gpio (gpio_export_path);
@ -417,7 +419,7 @@ void export_gpio(int gpio, int invert, int direction)
exit (1); exit (1);
} }
snprintf (stemp, sizeof(stemp), "%d", gpio); snprintf (stemp, sizeof(stemp), "%d", gpio_num);
if (write (fd, stemp, strlen(stemp)) != strlen(stemp)) { if (write (fd, stemp, strlen(stemp)) != strlen(stemp)) {
int e = errno; int e = errno;
/* Ignore EBUSY error which seems to mean */ /* Ignore EBUSY error which seems to mean */
@ -473,7 +475,7 @@ void export_gpio(int gpio, int invert, int direction)
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("ERROR! Could not get directory listing for /sys/class/gpio\n"); dw_printf ("ERROR! Could not get directory listing for /sys/class/gpio\n");
snprintf (gpio_name[gpio], sizeof(gpio_name[gpio]), "gpio%d", gpio); snprintf (gpio_name, MAX_GPIO_NAME_LEN, "gpio%d", gpio_num);
num_files = 0; num_files = 0;
ok = 1; ok = 1;
} }
@ -491,22 +493,22 @@ void export_gpio(int gpio, int invert, int direction)
// Look for exact name gpioNN // Look for exact name gpioNN
char lookfor[16]; char lookfor[16];
snprintf (lookfor, sizeof(lookfor), "gpio%d", gpio); snprintf (lookfor, sizeof(lookfor), "gpio%d", gpio_num);
for (i = 0; i < num_files && ! ok; i++) { for (i = 0; i < num_files && ! ok; i++) {
if (strcmp(lookfor, file_list[i]->d_name) == 0) { if (strcmp(lookfor, file_list[i]->d_name) == 0) {
strlcpy (gpio_name[gpio], file_list[i]->d_name, sizeof(gpio_name[gpio])); strlcpy (gpio_name, file_list[i]->d_name, MAX_GPIO_NAME_LEN);
ok = 1; ok = 1;
} }
} }
// If not found, Look for gpioNN_* // If not found, Look for gpioNN_*
snprintf (lookfor, sizeof(lookfor), "gpio%d_", gpio); snprintf (lookfor, sizeof(lookfor), "gpio%d_", gpio_num);
for (i = 0; i < num_files && ! ok; i++) { for (i = 0; i < num_files && ! ok; i++) {
if (strncmp(lookfor, file_list[i]->d_name, strlen(lookfor)) == 0) { if (strncmp(lookfor, file_list[i]->d_name, strlen(lookfor)) == 0) {
strlcpy (gpio_name[gpio], file_list[i]->d_name, sizeof(gpio_name[gpio])); strlcpy (gpio_name, file_list[i]->d_name, MAX_GPIO_NAME_LEN);
ok = 1; ok = 1;
} }
} }
@ -526,13 +528,13 @@ void export_gpio(int gpio, int invert, int direction)
if (ptt_debug_level >= 2) { if (ptt_debug_level >= 2) {
text_color_set(DW_COLOR_DEBUG); text_color_set(DW_COLOR_DEBUG);
dw_printf ("Path for gpio number %d is /sys/class/gpio/%s\n", gpio, gpio_name[gpio]); dw_printf ("Path for gpio number %d is /sys/class/gpio/%s\n", gpio_num, gpio_name);
} }
} }
else { else {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("ERROR! Could not find Path for gpio number %d.n", gpio); dw_printf ("ERROR! Could not find Path for gpio number %d.n", gpio_num);
exit (1); exit (1);
} }
@ -540,7 +542,7 @@ void export_gpio(int gpio, int invert, int direction)
* Set output direction and initial state * Set output direction and initial state
*/ */
snprintf (gpio_direction_path, sizeof(gpio_direction_path), "/sys/class/gpio/%s/direction", gpio_name[gpio]); snprintf (gpio_direction_path, sizeof(gpio_direction_path), "/sys/class/gpio/%s/direction", gpio_name);
get_access_to_gpio (gpio_direction_path); get_access_to_gpio (gpio_direction_path);
fd = open(gpio_direction_path, O_WRONLY); fd = open(gpio_direction_path, O_WRONLY);
@ -572,6 +574,14 @@ void export_gpio(int gpio, int invert, int direction)
exit (1); exit (1);
} }
close (fd); close (fd);
/*
* Make sure that we have access to 'value'.
* Do it once here, rather than each time we want to use it.
*/
snprintf (gpio_value_path, sizeof(gpio_value_path), "/sys/class/gpio/%s/value", gpio_name);
get_access_to_gpio (gpio_value_path);
} }
#endif /* not __WIN32__ */ #endif /* not __WIN32__ */
@ -600,7 +610,7 @@ void export_gpio(int gpio, int invert, int direction)
* *
* ptt_line RTS or DTR when using serial port. * ptt_line RTS or DTR when using serial port.
* *
* ptt_gpio GPIO number. Only used for Linux. * out_gpio_num GPIO number. Only used for Linux.
* Valid only when ptt_method is PTT_METHOD_GPIO. * Valid only when ptt_method is PTT_METHOD_GPIO.
* *
* ptt_lpt_bit Bit number for parallel printer port. * ptt_lpt_bit Bit number for parallel printer port.
@ -623,7 +633,6 @@ void export_gpio(int gpio, int invert, int direction)
static struct audio_s *save_audio_config_p; /* Save config information for later use. */
static HANDLE ptt_fd[MAX_CHANS][NUM_OCTYPES]; static HANDLE ptt_fd[MAX_CHANS][NUM_OCTYPES];
/* Serial port handle or fd. */ /* Serial port handle or fd. */
@ -674,7 +683,7 @@ void ptt_init (struct audio_s *audio_config_p)
audio_config_p->achan[ch].octrl[ot].ptt_method, audio_config_p->achan[ch].octrl[ot].ptt_method,
audio_config_p->achan[ch].octrl[ot].ptt_device, audio_config_p->achan[ch].octrl[ot].ptt_device,
audio_config_p->achan[ch].octrl[ot].ptt_line, audio_config_p->achan[ch].octrl[ot].ptt_line,
audio_config_p->achan[ch].octrl[ot].ptt_gpio, audio_config_p->achan[ch].octrl[ot].out_gpio_num,
audio_config_p->achan[ch].octrl[ot].ptt_lpt_bit, audio_config_p->achan[ch].octrl[ot].ptt_lpt_bit,
audio_config_p->achan[ch].octrl[ot].ptt_invert); audio_config_p->achan[ch].octrl[ot].ptt_invert);
} }
@ -818,8 +827,6 @@ void ptt_init (struct audio_s *audio_config_p)
if (using_gpio) { if (using_gpio) {
get_access_to_gpio ("/sys/class/gpio/export"); get_access_to_gpio ("/sys/class/gpio/export");
} }
/* /*
@ -829,15 +836,18 @@ void ptt_init (struct audio_s *audio_config_p)
for (ch = 0; ch < MAX_CHANS; ch++) { for (ch = 0; ch < MAX_CHANS; ch++) {
if (save_audio_config_p->achan[ch].valid) { if (save_audio_config_p->achan[ch].valid) {
int ot;
int ot; // output control type, PTT, DCD, CON, ...
int it; // input control type
for (ot = 0; ot < NUM_OCTYPES; ot++) { for (ot = 0; ot < NUM_OCTYPES; ot++) {
if (audio_config_p->achan[ch].octrl[ot].ptt_method == PTT_METHOD_GPIO) { if (audio_config_p->achan[ch].octrl[ot].ptt_method == PTT_METHOD_GPIO) {
export_gpio(audio_config_p->achan[ch].octrl[ot].ptt_gpio, audio_config_p->achan[ch].octrl[ot].ptt_invert, 1); export_gpio(ch, ot, audio_config_p->achan[ch].octrl[ot].ptt_invert, 1);
} }
} }
for (ot = 0; ot < NUM_ICTYPES; ot++) { for (it = 0; it < NUM_ICTYPES; it++) {
if (audio_config_p->achan[ch].ictrl[ot].method == PTT_METHOD_GPIO) { if (audio_config_p->achan[ch].ictrl[it].method == PTT_METHOD_GPIO) {
export_gpio(audio_config_p->achan[ch].ictrl[ot].gpio, audio_config_p->achan[ch].ictrl[ot].invert, 0); export_gpio(ch, it, audio_config_p->achan[ch].ictrl[it].invert, 0);
} }
} }
} }
@ -1125,9 +1135,7 @@ void ptt_set (int ot, int chan, int ptt_signal)
char gpio_value_path[80]; char gpio_value_path[80];
char stemp[16]; char stemp[16];
snprintf (gpio_value_path, sizeof(gpio_value_path), "/sys/class/gpio/%s/value", gpio_name[save_audio_config_p->achan[chan].octrl[ot].ptt_gpio]); snprintf (gpio_value_path, sizeof(gpio_value_path), "/sys/class/gpio/%s/value", save_audio_config_p->achan[chan].octrl[ot].out_gpio_name);
get_access_to_gpio (gpio_value_path);
fd = open(gpio_value_path, O_WRONLY); fd = open(gpio_value_path, O_WRONLY);
if (fd < 0) { if (fd < 0) {
@ -1143,7 +1151,7 @@ void ptt_set (int ot, int chan, int ptt_signal)
if (write (fd, stemp, 1) != 1) { if (write (fd, stemp, 1) != 1) {
int e = errno; int e = errno;
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("Error setting GPIO %d for %s\n", save_audio_config_p->achan[chan].octrl[ot].ptt_gpio, otnames[ot]); dw_printf ("Error setting GPIO %d for %s\n", save_audio_config_p->achan[chan].octrl[ot].out_gpio_num, otnames[ot]);
dw_printf ("%s\n", strerror(e)); dw_printf ("%s\n", strerror(e));
} }
close (fd); close (fd);
@ -1246,7 +1254,7 @@ int get_input (int it, int chan)
int fd; int fd;
char gpio_value_path[80]; char gpio_value_path[80];
snprintf (gpio_value_path, sizeof(gpio_value_path), "/sys/class/gpio/%s/value", gpio_name[save_audio_config_p->achan[chan].ictrl[it].gpio]); snprintf (gpio_value_path, sizeof(gpio_value_path), "/sys/class/gpio/%s/value", save_audio_config_p->achan[chan].ictrl[it].in_gpio_name);
get_access_to_gpio (gpio_value_path); get_access_to_gpio (gpio_value_path);
@ -1263,7 +1271,7 @@ int get_input (int it, int chan)
if (read (fd, vtemp, 1) != 1) { if (read (fd, vtemp, 1) != 1) {
int e = errno; int e = errno;
text_color_set(DW_COLOR_ERROR); 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 ("Error getting GPIO %d value\n", save_audio_config_p->achan[chan].ictrl[it].in_gpio_num);
dw_printf ("%s\n", strerror(e)); dw_printf ("%s\n", strerror(e));
} }
close (fd); close (fd);
@ -1449,9 +1457,9 @@ main ()
my_audio_config.adev[0].num_channels = 1; my_audio_config.adev[0].num_channels = 1;
my_audio_config.valid[0] = 1; my_audio_config.valid[0] = 1;
my_audio_config.adev[0].octrl[OCTYPE_PTT].ptt_method = PTT_METHOD_GPIO; my_audio_config.adev[0].octrl[OCTYPE_PTT].ptt_method = PTT_METHOD_GPIO;
my_audio_config.adev[0].octrl[OCTYPE_PTT].ptt_gpio = 25; my_audio_config.adev[0].octrl[OCTYPE_PTT].out_gpio_num = 25;
dw_printf ("Try GPIO %d a few times...\n", my_audio_config.ptt_gpio[0]); dw_printf ("Try GPIO %d a few times...\n", my_audio_config.out_gpio_num[0]);
ptt_init (&my_audio_config); ptt_init (&my_audio_config);