Skip to content
Permalink
main
Go to file
 
 
Cannot retrieve contributors at this time
146 lines (130 sloc) 4.07 KB
/*
* gpio.c
*
* keys and encoders
*/
#include <errno.h>
#include <fcntl.h>
#include <linux/input.h>
#include <pthread.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "events.h"
int key_fd;
pthread_t key_p;
int enc_fd[3];
pthread_t enc_p[3];
void *key_check(void *);
void *enc_check(void *);
// extern def
static int open_and_grab(const char *pathname, int flags) {
int fd;
int open_attempts = 0, ioctl_attempts = 0;
while (open_attempts < 200) {
fd = open(pathname, flags);
if (fd > 0) {
if (ioctl(fd, EVIOCGRAB, 1) == 0) {
ioctl(fd, EVIOCGRAB, (void *)0);
goto done;
}
ioctl_attempts++;
close(fd);
}
open_attempts++;
usleep(50000); // 50ms sleep * 200 = 10s fail after 10s
};
done:
if (open_attempts > 0) {
fprintf(stderr, "WARN open_and_grab GPIO '%s' required %d open attempts & %d ioctl attempts\n", pathname,
open_attempts, ioctl_attempts);
}
return fd;
}
void gpio_init() {
key_fd = open_and_grab("/dev/input/by-path/platform-keys-event", O_RDONLY); // Keys
if (key_fd > 0) {
if (pthread_create(&key_p, NULL, key_check, 0)) {
fprintf(stderr, "ERROR (keys) pthread error\n");
}
}
char *enc_filenames[3] = {"/dev/input/by-path/platform-soc:knob1-event",
"/dev/input/by-path/platform-soc:knob2-event",
"/dev/input/by-path/platform-soc:knob3-event"};
for (int i = 0; i < 3; i++) {
enc_fd[i] = open_and_grab(enc_filenames[i], O_RDONLY);
if (enc_fd[i] > 0) {
int *arg = malloc(sizeof(int));
*arg = i;
if (pthread_create(&enc_p[i], NULL, enc_check, arg)) {
fprintf(stderr, "ERROR (enc%d) pthread error\n", i);
}
}
}
}
void gpio_deinit() {
pthread_cancel(key_p);
pthread_cancel(enc_p[0]);
pthread_cancel(enc_p[1]);
pthread_cancel(enc_p[2]);
}
void *enc_check(void *x) {
int n = *((int *)x);
free(x);
int rd;
unsigned int i;
struct input_event event[64];
int dir[3] = {1, 1, 1};
clock_t now[3];
clock_t prev[3];
clock_t diff;
prev[0] = prev[1] = prev[2] = clock();
while (1) {
rd = read(enc_fd[n], event, sizeof(struct input_event) * 64);
if (rd < (int)sizeof(struct input_event)) {
fprintf(stderr, "ERROR (enc) read error\n");
}
for (i = 0; i < rd / sizeof(struct input_event); i++) {
if (event[i].type) { // make sure it's not EV_SYN == 0
now[i] = clock();
diff = now[i] - prev[i];
// fprintf(stderr, "%d\t%d\t%lu\n", n, event[i].value, diff);
prev[i] = now[i];
if (diff > 100) { // filter out glitches
if (dir[i] != event[i].value &&
diff > 500) { // only reverse direction if there is reasonable settling time
dir[i] = event[i].value;
}
union event_data *ev = event_data_new(EVENT_ENC);
ev->enc.n = n + 1;
ev->enc.delta = event[i].value;
event_post(ev);
}
}
}
}
}
void *key_check(void *x) {
(void)x;
int rd;
unsigned int i;
struct input_event event[64];
while (1) {
rd = read(key_fd, event, sizeof(struct input_event) * 64);
if (rd < (int)sizeof(struct input_event)) {
fprintf(stderr, "ERROR (key) read error\n");
}
for (i = 0; i < rd / sizeof(struct input_event); i++) {
if (event[i].type) { // make sure it's not EV_SYN == 0
// fprintf(stderr, "enc%d = %d\n", n, event[i].value);
union event_data *ev = event_data_new(EVENT_KEY);
ev->key.n = event[i].code;
ev->key.val = event[i].value;
event_post(ev);
}
}
}
}