mirror of https://github.com/wb2osz/direwolf.git
Take advantage of new 'gpio' group and new /sys/class/gpio ownership in Raspbian Jessie.
Handle more complicated gpio naming for CubieBoard, etc.
This commit is contained in:
parent
dc292ffcc9
commit
58c2707f7d
Binary file not shown.
472
ptt.c
472
ptt.c
|
@ -1,7 +1,7 @@
|
||||||
//
|
//
|
||||||
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2011, 2013, 2014, 2015, 2016 John Langner, WB2OSZ
|
// Copyright (C) 2011, 2013, 2014, 2015, 2016, 2017 John Langner, WB2OSZ
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -48,6 +48,10 @@
|
||||||
*
|
*
|
||||||
* Version 1.4: The spare "future" indicator is now used when connected to another station.
|
* Version 1.4: The spare "future" indicator is now used when connected to another station.
|
||||||
*
|
*
|
||||||
|
* Take advantage of the new 'gpio' group and new /sys/class/gpio protections in Raspbian Jessie.
|
||||||
|
*
|
||||||
|
* Handle more complicated gpio node names for CubieBoard, etc.
|
||||||
|
*
|
||||||
* References: http://www.robbayer.com/files/serial-win.pdf
|
* References: http://www.robbayer.com/files/serial-win.pdf
|
||||||
*
|
*
|
||||||
* https://www.kernel.org/doc/Documentation/gpio.txt
|
* https://www.kernel.org/doc/Documentation/gpio.txt
|
||||||
|
@ -115,6 +119,8 @@
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <grp.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
|
||||||
#ifdef USE_HAMLIB
|
#ifdef USE_HAMLIB
|
||||||
#include <hamlib/rig.h>
|
#include <hamlib/rig.h>
|
||||||
|
@ -163,38 +169,254 @@ void ptt_set_debug(int debug)
|
||||||
ptt_debug_level = debug;
|
ptt_debug_level = debug;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------
|
/*-------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* Name: export_gpio
|
* Name: get_access_to_gpio
|
||||||
*
|
*
|
||||||
* Purpose: Tell the GPIO subsystem to export a GPIO line for
|
* Purpose: Try to get access to the GPIO device.
|
||||||
* us to use, and set the initial state of the GPIO.
|
|
||||||
*
|
*
|
||||||
* Inputs: gpio - GPIO line to export
|
* Inputs: path - Path to device node.
|
||||||
* invert: - Is the GPIO active low?
|
* /sys/class/gpio/export
|
||||||
* direction: - 0 for input, 1 for output
|
* /sys/class/gpio/unexport
|
||||||
|
* /sys/class/gpio/gpio??/direction
|
||||||
|
* /sys/class/gpio/gpio??/value
|
||||||
*
|
*
|
||||||
* Outputs: None.
|
* Description: First see if we have access thru the usual uid/gid/mode method.
|
||||||
|
* If that fails, we try a hack where we use "sudo chmod ..." to open up access.
|
||||||
|
* That requires that sudo be configured to work without a password.
|
||||||
|
* That's the case for 'pi' user in Raspbian but not not be for other boards / operating systems.
|
||||||
|
*
|
||||||
|
* Debug: Use the "-doo" command line option.
|
||||||
*
|
*
|
||||||
*------------------------------------------------------------------*/
|
*------------------------------------------------------------------*/
|
||||||
|
|
||||||
#ifndef __WIN32__
|
#ifndef __WIN32__
|
||||||
|
|
||||||
|
#define MAX_GROUPS 50
|
||||||
|
|
||||||
|
|
||||||
|
static void get_access_to_gpio (const char *path)
|
||||||
|
{
|
||||||
|
|
||||||
|
static int my_uid = -1;
|
||||||
|
static int my_gid = -1;
|
||||||
|
static gid_t my_groups[MAX_GROUPS];
|
||||||
|
static int num_groups = 0;
|
||||||
|
static int first_time = 1;
|
||||||
|
|
||||||
|
struct stat finfo;
|
||||||
|
int i;
|
||||||
|
char cmd[80];
|
||||||
|
int err;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Does path even exist?
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (stat(path, &finfo) < 0) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Can't get properties of %s.\n", path);
|
||||||
|
dw_printf ("This system is not configured with the GPIO user interface.\n");
|
||||||
|
dw_printf ("Use a different method for PTT control.\n");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (first_time) {
|
||||||
|
|
||||||
|
// No need to fetch same information each time. Cache it.
|
||||||
|
my_uid = geteuid();
|
||||||
|
my_gid = getegid();
|
||||||
|
num_groups = getgroups (MAX_GROUPS, my_groups);
|
||||||
|
|
||||||
|
if (num_groups < 0) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("getgroups() failed to get supplementary groups, errno=%d\n", errno);
|
||||||
|
num_groups = 0;
|
||||||
|
}
|
||||||
|
first_time = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ptt_debug_level >= 2) {
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf ("%s: uid=%d, gid=%d, mode=o%o\n", path, finfo.st_uid, finfo.st_gid, finfo.st_mode);
|
||||||
|
dw_printf ("my uid=%d, gid=%d, supplementary groups=", my_uid, my_gid);
|
||||||
|
for (i = 0; i < num_groups; i++) {
|
||||||
|
dw_printf (" %d", my_groups[i]);
|
||||||
|
}
|
||||||
|
dw_printf ("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Do we have permission to access it?
|
||||||
|
*
|
||||||
|
* On Debian 7 (Wheezy) we see this:
|
||||||
|
*
|
||||||
|
* $ ls -l /sys/class/gpio/export
|
||||||
|
* --w------- 1 root root 4096 Feb 27 12:31 /sys/class/gpio/export
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Only root can write to it.
|
||||||
|
* Our work-around is change the protection so that everyone can write.
|
||||||
|
* This requires that the current user can use sudo without a password.
|
||||||
|
* This has been the case for the predefined "pi" user but can be a problem
|
||||||
|
* when people add new user names.
|
||||||
|
* Other operating systems could have different default configurations.
|
||||||
|
*
|
||||||
|
* A better solution is available in Debian 8 (Jessie). The group is now "gpio"
|
||||||
|
* so anyone in that group can now write to it.
|
||||||
|
*
|
||||||
|
* $ ls -l /sys/class/gpio/export
|
||||||
|
* -rwxrwx--- 1 root gpio 4096 Mar 4 21:12 /sys/class/gpio/export
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* First see if we can access it by the usual file protection rules.
|
||||||
|
* If not, we will try the "sudo chmod go+rw ..." hack.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Do I have access?
|
||||||
|
* We could just try to open for write but this gives us more debugging information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ((my_uid == finfo.st_uid) && (finfo.st_mode & S_IWUSR)) { // user write 00200
|
||||||
|
if (ptt_debug_level >= 2) {
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf ("My uid matches and we have user write permission.\n");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((my_gid == finfo.st_gid) && (finfo.st_mode & S_IWGRP)) { // group write 00020
|
||||||
|
if (ptt_debug_level >= 2) {
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf ("My primary gid matches and we have group write permission.\n");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < num_groups; i++) {
|
||||||
|
if ((my_groups[i] == finfo.st_gid) && (finfo.st_mode & S_IWGRP)) { // group write 00020
|
||||||
|
if (ptt_debug_level >= 2) {
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf ("My supplemental group %d matches and we have group write permission.\n", my_groups[i]);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (finfo.st_mode & S_IWOTH) { // other write 00002
|
||||||
|
if (ptt_debug_level >= 2) {
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf ("We have other write permission.\n");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We don't have permission.
|
||||||
|
* Try a hack which requires that the user be set up to use sudo without a password.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (ptt_debug_level >= 2) {
|
||||||
|
text_color_set(DW_COLOR_ERROR); // debug message but different color so it stands out.
|
||||||
|
dw_printf ("Trying 'sudo chmod go+rw %s' hack.\n", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf (cmd, sizeof(cmd), "sudo chmod go+rw %s", path);
|
||||||
|
err = system (cmd);
|
||||||
|
(void)err; // suppress warning about not using result.
|
||||||
|
|
||||||
|
/*
|
||||||
|
* I don't trust status coming back from system() so we will check the mode again.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (stat(path, &finfo) < 0) {
|
||||||
|
/* 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");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Did we succeed in changing the protection? */
|
||||||
|
|
||||||
|
if ( (finfo.st_mode & 0266) != 0266) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("You don't have the necessary permission to access GPIO.\n");
|
||||||
|
dw_printf ("There are three different solutions: \n");
|
||||||
|
dw_printf (" 1. Run as root. (not recommended)\n");
|
||||||
|
dw_printf (" 2. If operating system has 'gpio' group, add your user id to it.\n");
|
||||||
|
dw_printf (" 3. Configure your user id for sudo without a password.\n");
|
||||||
|
dw_printf ("\n");
|
||||||
|
dw_printf ("Read the documentation and try -doo command line option for debugging details.\n");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* 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 number to export.
|
||||||
|
* invert: - Is the GPIO active low?
|
||||||
|
* direction: - 0 for input, 1 for output
|
||||||
|
*
|
||||||
|
* Outputs: gpio_name - See below.
|
||||||
|
*
|
||||||
|
*------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#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.
|
||||||
|
// 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)
|
void export_gpio(int gpio, int invert, int direction)
|
||||||
{
|
{
|
||||||
HANDLE fd;
|
HANDLE fd;
|
||||||
char stemp[80];
|
const char gpio_export_path[] = "/sys/class/gpio/export";
|
||||||
struct stat finfo;
|
char gpio_direction_path[80];
|
||||||
int err;
|
char stemp[16];
|
||||||
|
|
||||||
fd = open("/sys/class/gpio/export", O_WRONLY);
|
|
||||||
if (fd < 0) {
|
if (gpio < 0 || gpio >= MAX_GPIO_NUM) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("Permissions do not allow ordinary users to access GPIO.\n");
|
dw_printf ("GPIO line number %d is invalid. Must be in range of 0 to %d.\n", gpio, MAX_GPIO_NUM - 1);
|
||||||
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);
|
exit (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get_access_to_gpio (gpio_export_path);
|
||||||
|
|
||||||
|
fd = open(gpio_export_path, O_WRONLY);
|
||||||
|
if (fd < 0) {
|
||||||
|
// Not expected. Above should have obtained permission or exited.
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Permissions do not allow access to GPIO.\n");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
snprintf (stemp, sizeof(stemp), "%d", gpio);
|
snprintf (stemp, sizeof(stemp), "%d", gpio);
|
||||||
if (write (fd, stemp, strlen(stemp)) != strlen(stemp)) {
|
if (write (fd, stemp, strlen(stemp)) != strlen(stemp)) {
|
||||||
int e = errno;
|
int e = errno;
|
||||||
|
@ -202,7 +424,7 @@ void export_gpio(int gpio, int invert, int direction)
|
||||||
/* the device node already exists. */
|
/* the device node already exists. */
|
||||||
if (e != EBUSY) {
|
if (e != EBUSY) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("Error writing \"%s\" to /sys/class/gpio/export, errno=%d\n", stemp, e);
|
dw_printf ("Error writing \"%s\" to %s, errno=%d\n", stemp, gpio_export_path, e);
|
||||||
dw_printf ("%s\n", strerror(e));
|
dw_printf ("%s\n", strerror(e));
|
||||||
exit (1);
|
exit (1);
|
||||||
}
|
}
|
||||||
|
@ -210,62 +432,118 @@ void export_gpio(int gpio, int invert, int direction)
|
||||||
close (fd);
|
close (fd);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Idea for future:
|
* Added in release 1.4.
|
||||||
|
*
|
||||||
On the RPi, the device path for GPIO number XX is /sys/class/gpio/gpioXX.
|
* On the RPi, the device path for GPIO number XX is simply /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.
|
* 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://github.com/cubieplayer/Cubian/wiki/GPIO-Introduction
|
||||||
https://www.olimex.com/wiki/A20-OLinuXino-LIME#GPIO_under_Linux
|
*
|
||||||
|
* For another similar single board computer, we find the same thing:
|
||||||
How should we deal with this? Some possibilities:
|
* https://www.olimex.com/wiki/A20-OLinuXino-LIME#GPIO_under_Linux
|
||||||
|
*
|
||||||
(1) The user might explicitly mention the name in direwolf.conf.
|
* How should we deal with this? Some possibilities:
|
||||||
(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
|
* (1) The user might explicitly mention the name in direwolf.conf.
|
||||||
matching name. Suppose we wanted GPIO 61. First look for an exact
|
* (2) We might be able to find the names in some system device config file.
|
||||||
match to "gpio61". If that is not found, look for something
|
* (3) Get a directory listing of /sys/class/gpio then search for a
|
||||||
matching the pattern "gpio61_*".
|
* 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 are finally implementing the third choice.
|
||||||
* 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);
|
|
||||||
(void)err;
|
|
||||||
|
|
||||||
snprintf (stemp, sizeof(stemp), "/sys/class/gpio/gpio%d/value", gpio);
|
struct dirent **file_list;
|
||||||
|
int num_files;
|
||||||
|
int i;
|
||||||
|
int ok = 0;
|
||||||
|
|
||||||
if (stat(stemp, &finfo) < 0) {
|
if (ptt_debug_level >= 2) {
|
||||||
int e = errno;
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
text_color_set(DW_COLOR_ERROR);
|
dw_printf ("Contents of /sys/class/gpio:\n");
|
||||||
dw_printf ("Failed to get status for %s \n", stemp);
|
|
||||||
dw_printf ("%s\n", strerror(e));
|
|
||||||
exit (1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (geteuid() != 0) {
|
num_files = scandir ("/sys/class/gpio", &file_list, NULL, alphasort);
|
||||||
if ( ! (finfo.st_mode & S_IWOTH)) {
|
|
||||||
text_color_set(DW_COLOR_ERROR);
|
if (num_files < 0) {
|
||||||
dw_printf ("Permissions do not allow ordinary users to access GPIO.\n");
|
// Something went wrong. Fill in the simple expected name and keep going.
|
||||||
dw_printf ("Log in as root and type these commands:\n");
|
|
||||||
dw_printf (" chmod go+rw /sys/class/gpio/gpio%d/direction", gpio);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf (" chmod go+rw /sys/class/gpio/gpio%d/value", gpio);
|
dw_printf ("ERROR! Could not get directory listing for /sys/class/gpio\n");
|
||||||
exit (1);
|
|
||||||
|
snprintf (gpio_name[gpio], sizeof(gpio_name[gpio]), "gpio%d", gpio);
|
||||||
|
num_files = 0;
|
||||||
|
ok = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
if (ptt_debug_level >= 2) {
|
||||||
|
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
|
||||||
|
for (i = 0; i < num_files; i++) {
|
||||||
|
dw_printf("\t%s\n", file_list[i]->d_name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Look for exact name gpioNN
|
||||||
|
|
||||||
|
char lookfor[16];
|
||||||
|
snprintf (lookfor, sizeof(lookfor), "gpio%d", gpio);
|
||||||
|
|
||||||
|
for (i = 0; i < num_files && ! ok; i++) {
|
||||||
|
if (strcmp(lookfor, file_list[i]->d_name) == 0) {
|
||||||
|
strlcpy (gpio_name[gpio], file_list[i]->d_name, sizeof(gpio_name[gpio]));
|
||||||
|
ok = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not found, Look for gpioNN_*
|
||||||
|
|
||||||
|
snprintf (lookfor, sizeof(lookfor), "gpio%d_", gpio);
|
||||||
|
|
||||||
|
for (i = 0; i < num_files && ! ok; i++) {
|
||||||
|
if (strncmp(lookfor, file_list[i]->d_name, strlen(lookfor)) == 0) {
|
||||||
|
strlcpy (gpio_name[gpio], file_list[i]->d_name, sizeof(gpio_name[gpio]));
|
||||||
|
ok = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free the storage allocated by scandir().
|
||||||
|
|
||||||
|
for (i = 0; i < num_files; i++) {
|
||||||
|
free (file_list[i]);
|
||||||
|
}
|
||||||
|
free (file_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We should now have the corresponding node name.
|
||||||
|
*/
|
||||||
|
if (ok) {
|
||||||
|
|
||||||
|
if (ptt_debug_level >= 2) {
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf ("Path for gpio number %d is /sys/class/gpio/%s\n", gpio, gpio_name[gpio]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("ERROR! Could not find Path for gpio number %d.n", gpio);
|
||||||
|
exit (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set output direction and initial state
|
* Set output direction and initial state
|
||||||
*/
|
*/
|
||||||
|
|
||||||
snprintf (stemp, sizeof(stemp), "/sys/class/gpio/gpio%d/direction", gpio);
|
snprintf (gpio_direction_path, sizeof(gpio_direction_path), "/sys/class/gpio/%s/direction", gpio_name[gpio]);
|
||||||
fd = open(stemp, O_WRONLY);
|
get_access_to_gpio (gpio_direction_path);
|
||||||
|
|
||||||
|
fd = open(gpio_direction_path, O_WRONLY);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
int e = errno;
|
int e = errno;
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
@ -539,59 +817,11 @@ void ptt_init (struct audio_s *audio_config_p)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (using_gpio) {
|
if (using_gpio) {
|
||||||
|
get_access_to_gpio ("/sys/class/gpio/export");
|
||||||
|
|
||||||
struct stat finfo;
|
|
||||||
/*
|
|
||||||
* Normally the device nodes are set up for access
|
|
||||||
* only by root. Try to change it here so we don't
|
|
||||||
* burden user with another configuration step.
|
|
||||||
*
|
|
||||||
* Does /sys/class/gpio/export even exist?
|
|
||||||
*/
|
|
||||||
|
|
||||||
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");
|
|
||||||
exit (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Do we have permission to access it?
|
|
||||||
*
|
|
||||||
* pi@raspberrypi /sys/class/gpio $ ls -l
|
|
||||||
* total 0
|
|
||||||
* --w------- 1 root root 4096 Aug 20 07:59 export
|
|
||||||
* lrwxrwxrwx 1 root root 0 Aug 20 07:59 gpiochip0 -> ../../devices/virtual/gpio/gpiochip0
|
|
||||||
* --w------- 1 root root 4096 Aug 20 07:59 unexport
|
|
||||||
*/
|
|
||||||
if (geteuid() != 0) {
|
|
||||||
if ( ! (finfo.st_mode & S_IWOTH)) {
|
|
||||||
int err;
|
|
||||||
|
|
||||||
/* Try to change protection. */
|
|
||||||
err = system ("sudo chmod go+w /sys/class/gpio/export /sys/class/gpio/unexport");
|
|
||||||
(void)err;
|
|
||||||
|
|
||||||
if (stat("/sys/class/gpio/export", &finfo) < 0) {
|
|
||||||
/* 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");
|
|
||||||
exit (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Did we succeed in changing the protection? */
|
|
||||||
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 this command:\n");
|
|
||||||
dw_printf (" chmod go+w /sys/class/gpio/export /sys/class/gpio/unexport\n");
|
|
||||||
exit (1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We should now be able to create the device nodes for
|
* We should now be able to create the device nodes for
|
||||||
* the pins we want to use.
|
* the pins we want to use.
|
||||||
|
@ -892,11 +1122,14 @@ void ptt_set (int ot, int chan, int ptt_signal)
|
||||||
|
|
||||||
if (save_audio_config_p->achan[chan].octrl[ot].ptt_method == PTT_METHOD_GPIO) {
|
if (save_audio_config_p->achan[chan].octrl[ot].ptt_method == PTT_METHOD_GPIO) {
|
||||||
int fd;
|
int fd;
|
||||||
char stemp[80];
|
char gpio_value_path[80];
|
||||||
|
char stemp[16];
|
||||||
|
|
||||||
snprintf (stemp, sizeof(stemp), "/sys/class/gpio/gpio%d/value", save_audio_config_p->achan[chan].octrl[ot].ptt_gpio);
|
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]);
|
||||||
|
|
||||||
fd = open(stemp, O_WRONLY);
|
get_access_to_gpio (gpio_value_path);
|
||||||
|
|
||||||
|
fd = open(gpio_value_path, O_WRONLY);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
int e = errno;
|
int e = errno;
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
@ -1011,15 +1244,17 @@ int get_input (int it, int chan)
|
||||||
#else
|
#else
|
||||||
if (save_audio_config_p->achan[chan].ictrl[it].method == PTT_METHOD_GPIO) {
|
if (save_audio_config_p->achan[chan].ictrl[it].method == PTT_METHOD_GPIO) {
|
||||||
int fd;
|
int fd;
|
||||||
char stemp[80];
|
char gpio_value_path[80];
|
||||||
|
|
||||||
snprintf (stemp, sizeof(stemp), "/sys/class/gpio/gpio%d/value", save_audio_config_p->achan[chan].ictrl[it].gpio);
|
snprintf (gpio_value_path, sizeof(gpio_value_path), "/sys/class/gpio/%s/value", gpio_name[save_audio_config_p->achan[chan].ictrl[it].gpio]);
|
||||||
|
|
||||||
fd = open(stemp, O_RDONLY);
|
get_access_to_gpio (gpio_value_path);
|
||||||
|
|
||||||
|
fd = open(gpio_value_path, O_RDONLY);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
int e = errno;
|
int e = errno;
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("Error opening %s to check input.\n", stemp);
|
dw_printf ("Error opening %s to check input.\n", gpio_value_path);
|
||||||
dw_printf ("%s\n", strerror(e));
|
dw_printf ("%s\n", strerror(e));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -1033,6 +1268,7 @@ int get_input (int it, int chan)
|
||||||
}
|
}
|
||||||
close (fd);
|
close (fd);
|
||||||
|
|
||||||
|
vtemp[1] = '\0';
|
||||||
if (atoi(vtemp) != save_audio_config_p->achan[chan].ictrl[it].invert) {
|
if (atoi(vtemp) != save_audio_config_p->achan[chan].ictrl[it].invert) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue