#c #c #linux #gpio #epoll
Вопрос:
Я использую epoll для идентификации нажатий кнопок на выводах GPIO (интерфейс кнопок).
Я использовал /sys/class/edge/gpio/gpioxx/edge, настроенный на «рост», потому что я просто хочу идентифицировать нажатия кнопок.
Я хочу, чтобы пользователь мог удерживать кнопку нажатой, чтобы что-то сделать в пользовательском интерфейсе (например, изменить громкость или что-то в этом роде). Для этого мне нужно определить, какое событие является событием «подъема» и событием «падения». Теперь, когда /edge/ установлен на оба, я действительно вижу два триггера в цикле epoll_wait. Проблема в том, что между ними нет никакой разницы.
У меня есть таймер, чтобы игнорировать события epoll в промежутке, потому что мои кнопки имеют эффект отскока, поэтому я обнаруживаю растущий край и жду X миллисекунд, потому что отскок приведет к тому, что 1 нажатие сработает пару раз. Это удобно устроено таким образом, что быстрые нажатия не регистрируют событие нажатия и выпуска, но событие нажатия и выпуска (длиннее промежутка в мс) регистрирует два.
Этот длинный фон предназначен только для того, чтобы обеспечить контекст для проблемы. В моем цикле epoll нет разницы между 2 быстрыми нажатиями и нажатием и удержанием. Два быстрых нажатия означали бы два события на подъеме. Длительное нажатие и удержание будет событием с восходящим и нисходящим краем. Я не могу в коде определить разницу.
Некоторый код включен для контекста.
u64 oldTime = getTime();
u64 newTime = getTime();
u64 gap = 0;
int n;
int epoll_fd = epoll_create(1);
if(epoll_fd == -1) {
perror("Unable to create the epoll: ");
}
int gpio1_fd = open("/sys/class/gpio/gpio1/value",O_RDONLY | O_NONBLOCK);
int gpio2_fd = open("/sys/class/gpio/gpio2/value",O_RDONLY | O_NONBLOCK);
int gpio3_fd = open("/sys/class/gpio/gpio3/value",O_RDONLY | O_NONBLOCK);
char buf = 0;
struct epoll_event event;
struct epoll_event *events;
events = (struct epoll_event *) calloc(MAXEVENTS, sizeof(event));
/** DO THIS FOR ALL 3 **/
struct epoll_event event;
event.data.fd = fd;
event.events = EPOLLPRI;
int ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, gpio1_fd, amp;event);
while (1) {
n = epoll_wait(epoll_fd, events, 10, 100);
for (int fd_index = 0; fd_index < n; fd_index ) {
int fd = events[fd_index].data.fd;
if(fd == gpio1_fd || fd == gpio2_fd || fd == gpio3_fd){
newTime = getMonotonicTime();
gap = newTime - oldTime;
if(gap <150){
printf("SHORT GAP, SKIP %llun", gap);
n = read(fd, amp;buf, 1);
oldTime = getTime();
continue;
} else {
printf("VALID GAP DETECTED: %llun", gap);
oldTime = getMonotonicTime();
if (fd == gpio1_fd) {
seek = lseek(gpio1_fd, 0, SEEK_SET);
printf("1");
read_and_send_gpios(1);
}
if (fd == gpio2_fd) {
seek = lseek(gpio2_fd, 0, SEEK_SET);
printf("2");
read_and_send_gpios(2);
}
if (fd == gpio3_fd) {
seek = lseek(gpio3_fd, 0, SEEK_SET);
printf("3");
read_and_send_gpios(3);
}
}
}
}
}
Комментарии:
1.
epoll
будет уведомляться только тогда, когда файл (или файлоподобное устройство, в данном случае) будет реагировать на какое-либо событие ввода-вывода. Я не знаком с использованиемepoll
для GPIO, но разве вы не можете просто прочитать значение в файле GPIO устройства, чтобы определить, установлен ли pin-код или нет?2. Боюсь, вам придется прочитать файл, чтобы узнать состояние пин-кода. К счастью
epoll
, он говорит вам, когда искать, иначе вы можете потратить много времени на проверку.3. Вы используете старый (устаревший) API GPIO. Есть пример в разделе инструменты/gpio ( github.com/torvalds/linux/blob/master/tools/gpio/… ), который показывает ваш вариант использования с новым api (он блокирует чтение, но расширение его до epoll должно быть простым)