Может ли epoll определить разницу между «ростом» и «падением» на триггере edge?

#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 должно быть простым)