use a queue to send events to the output device
This commit is contained in:
parent
593b1fbb5e
commit
895b5abeb9
8 changed files with 118 additions and 59 deletions
4
Makefile
4
Makefile
|
|
@ -1,4 +1,4 @@
|
||||||
CFLAGS=-g -O0 -std=c11 -fPIE -pedantic -Wall # -Werror
|
CFLAGS= -g -O0 -D _DEFAULT_SOURCE -D_POSIX_C_SOURCE=200112L -std=c11 -fPIE -pedantic -Wall # -Werror
|
||||||
LDFLAGS=-lpthread -levdev
|
LDFLAGS=-lpthread -levdev
|
||||||
CC=gcc
|
CC=gcc
|
||||||
OBJECTS=main.o input_dev.o output_dev.o queue.o
|
OBJECTS=main.o input_dev.o output_dev.o queue.o
|
||||||
|
|
@ -15,4 +15,4 @@ depends:
|
||||||
$(CC) -MM $(OBJECTS:.o=.c) > depends
|
$(CC) -MM $(OBJECTS:.o=.c) > depends
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f ./$(TARGET) *.o depends
|
rm -f ./$(TARGET) *.o depends
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "rogue_enemy.h"
|
#include "queue.h"
|
||||||
|
|
||||||
#define INPUT_DEV_CTRL_FLAG_EXIT 0x00000001U
|
#define INPUT_DEV_CTRL_FLAG_EXIT 0x00000001U
|
||||||
|
|
||||||
|
|
@ -24,6 +24,8 @@ typedef struct input_dev {
|
||||||
const iio_filters_t* iio_filters;
|
const iio_filters_t* iio_filters;
|
||||||
|
|
||||||
volatile uint32_t crtl_flags;
|
volatile uint32_t crtl_flags;
|
||||||
|
|
||||||
|
queue_t *queue;
|
||||||
} input_dev_t;
|
} input_dev_t;
|
||||||
|
|
||||||
void *input_dev_thread_func(void *ptr);
|
void *input_dev_thread_func(void *ptr);
|
||||||
|
|
|
||||||
13
main.c
13
main.c
|
|
@ -3,8 +3,8 @@
|
||||||
#include "input_dev.h"
|
#include "input_dev.h"
|
||||||
#include "output_dev.h"
|
#include "output_dev.h"
|
||||||
|
|
||||||
ev_queue_t imu_ev;
|
queue_t imu_ev;
|
||||||
ev_queue_t gamepad_ev;
|
queue_t gamepad_ev;
|
||||||
|
|
||||||
static output_dev_t out_imu_dev = {
|
static output_dev_t out_imu_dev = {
|
||||||
.fd = -1,
|
.fd = -1,
|
||||||
|
|
@ -26,6 +26,7 @@ static input_dev_t in_asus_kb_1_dev = {
|
||||||
.dev_type = input_dev_type_uinput,
|
.dev_type = input_dev_type_uinput,
|
||||||
.crtl_flags = 0x00000000U,
|
.crtl_flags = 0x00000000U,
|
||||||
.ev_filters = &in_asus_kb_1_filters,
|
.ev_filters = &in_asus_kb_1_filters,
|
||||||
|
.queue = &gamepad_ev,
|
||||||
};
|
};
|
||||||
|
|
||||||
static uinput_filters_t in_asus_kb_2_filters = {
|
static uinput_filters_t in_asus_kb_2_filters = {
|
||||||
|
|
@ -36,6 +37,7 @@ static input_dev_t in_asus_kb_2_dev = {
|
||||||
.dev_type = input_dev_type_uinput,
|
.dev_type = input_dev_type_uinput,
|
||||||
.crtl_flags = 0x00000000U,
|
.crtl_flags = 0x00000000U,
|
||||||
.ev_filters = &in_asus_kb_2_filters,
|
.ev_filters = &in_asus_kb_2_filters,
|
||||||
|
.queue = &gamepad_ev,
|
||||||
};
|
};
|
||||||
|
|
||||||
static uinput_filters_t in_asus_kb_3_filters = {
|
static uinput_filters_t in_asus_kb_3_filters = {
|
||||||
|
|
@ -46,6 +48,7 @@ static input_dev_t in_asus_kb_3_dev = {
|
||||||
.dev_type = input_dev_type_uinput,
|
.dev_type = input_dev_type_uinput,
|
||||||
.crtl_flags = 0x00000000U,
|
.crtl_flags = 0x00000000U,
|
||||||
.ev_filters = &in_asus_kb_3_filters,
|
.ev_filters = &in_asus_kb_3_filters,
|
||||||
|
.queue = &gamepad_ev,
|
||||||
};
|
};
|
||||||
|
|
||||||
static uinput_filters_t in_xbox_filters = {
|
static uinput_filters_t in_xbox_filters = {
|
||||||
|
|
@ -56,6 +59,7 @@ static input_dev_t in_xbox_dev = {
|
||||||
.dev_type = input_dev_type_uinput,
|
.dev_type = input_dev_type_uinput,
|
||||||
.crtl_flags = 0x00000000U,
|
.crtl_flags = 0x00000000U,
|
||||||
.ev_filters = &in_xbox_filters,
|
.ev_filters = &in_xbox_filters,
|
||||||
|
.queue = &gamepad_ev,
|
||||||
};
|
};
|
||||||
|
|
||||||
void request_termination() {
|
void request_termination() {
|
||||||
|
|
@ -77,6 +81,9 @@ void sig_handler(int signo)
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char ** argv) {
|
int main(int argc, char ** argv) {
|
||||||
|
queue_init(&gamepad_ev, 32);
|
||||||
|
queue_init(&imu_ev, 32);
|
||||||
|
|
||||||
out_imu_dev.fd = create_output_dev("/dev/uinput", "Virtual IMU - ROGueENEMY", output_dev_imu);
|
out_imu_dev.fd = create_output_dev("/dev/uinput", "Virtual IMU - ROGueENEMY", output_dev_imu);
|
||||||
if (out_imu_dev.fd < 0) {
|
if (out_imu_dev.fd < 0) {
|
||||||
// TODO: free(imu_dev.events_list);
|
// TODO: free(imu_dev.events_list);
|
||||||
|
|
@ -94,11 +101,13 @@ int main(int argc, char ** argv) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
__sighandler_t sigint_hndl = signal(SIGINT, sig_handler);
|
__sighandler_t sigint_hndl = signal(SIGINT, sig_handler);
|
||||||
if (sigint_hndl == SIG_ERR) {
|
if (sigint_hndl == SIG_ERR) {
|
||||||
fprintf(stderr, "Error registering SIGINT handler\n");
|
fprintf(stderr, "Error registering SIGINT handler\n");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
|
|
||||||
12
output_dev.c
12
output_dev.c
|
|
@ -1,4 +1,5 @@
|
||||||
#include "output_dev.h"
|
#include "output_dev.h"
|
||||||
|
#include "queue.h"
|
||||||
|
|
||||||
int create_output_dev(const char* uinput_path, const char* name, output_dev_type_t type) {
|
int create_output_dev(const char* uinput_path, const char* name, output_dev_type_t type) {
|
||||||
int fd = open(uinput_path, O_WRONLY | O_NONBLOCK);
|
int fd = open(uinput_path, O_WRONLY | O_NONBLOCK);
|
||||||
|
|
@ -150,6 +151,17 @@ void *output_dev_thread_func(void *ptr) {
|
||||||
output_dev_t *out_dev = (output_dev_t*)ptr;
|
output_dev_t *out_dev = (output_dev_t*)ptr;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
void *raw_ev;
|
||||||
|
const int pop_res = queue_pop_timeout(out_dev->queue, &raw_ev, 1000);
|
||||||
|
if (pop_res == 0) {
|
||||||
|
// do stuff
|
||||||
|
} else if (pop_res == -1) {
|
||||||
|
// timed out read
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Cannot read from input queue: %d\n", pop_res);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const uint32_t flags = out_dev->crtl_flags;
|
const uint32_t flags = out_dev->crtl_flags;
|
||||||
if (flags & OUTPUT_DEV_CTRL_FLAG_EXIT) {
|
if (flags & OUTPUT_DEV_CTRL_FLAG_EXIT) {
|
||||||
out_dev->crtl_flags &= ~OUTPUT_DEV_CTRL_FLAG_EXIT;
|
out_dev->crtl_flags &= ~OUTPUT_DEV_CTRL_FLAG_EXIT;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "rogue_enemy.h"
|
|
||||||
#include "queue.h"
|
#include "queue.h"
|
||||||
|
|
||||||
#define OUTPUT_DEV_VENDOR_ID 0x4532
|
#define OUTPUT_DEV_VENDOR_ID 0x4532
|
||||||
|
|
@ -24,7 +23,7 @@ typedef struct output_dev {
|
||||||
|
|
||||||
volatile uint32_t crtl_flags;
|
volatile uint32_t crtl_flags;
|
||||||
|
|
||||||
ev_queue_t *queue;
|
queue_t *queue;
|
||||||
} output_dev_t;
|
} output_dev_t;
|
||||||
|
|
||||||
int create_output_dev(const char* uinput_path, const char* name, output_dev_type_t type);
|
int create_output_dev(const char* uinput_path, const char* name, output_dev_type_t type);
|
||||||
|
|
|
||||||
116
queue.c
116
queue.c
|
|
@ -1,67 +1,97 @@
|
||||||
#include "queue.h"
|
#include "queue.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
int queue_init(ev_queue_t* queue, key_t sem_key, size_t max_elements) {
|
int queue_init(queue_t* const q, size_t max_elements) {
|
||||||
queue->array_size = max_elements;
|
q->front = q->rear = -1;
|
||||||
queue->array = calloc(sizeof(void*), max_elements);
|
q->array_size = max_elements;
|
||||||
if (queue->array == NULL) {
|
q->array = calloc(sizeof(void*), max_elements);
|
||||||
|
if (q->array == NULL) {
|
||||||
perror("calloc");
|
perror("calloc");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int semid = semget(sem_key, 1, IPC_CREAT | 0666);
|
sem_init(&q->empty, 0, q->array_size);
|
||||||
if (semid < 0)
|
sem_init(&q->full, 0, 0);
|
||||||
{
|
sem_init(&q->mutex, 0, 1);
|
||||||
free(queue->array);
|
|
||||||
perror("semget");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (semctl(semid, 0, SETVAL, 1) < 0)
|
|
||||||
{
|
|
||||||
free(queue->array);
|
|
||||||
perror("semctl");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void queue_destroy(ev_queue_t* queue) {
|
void queue_destroy(queue_t* q) {
|
||||||
free(queue->array);
|
free(q->array);
|
||||||
queue->array = NULL;
|
q->array = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int queue_push(ev_queue_t* queue, void *in_item) {
|
int queue_push(queue_t* const q, void *in_item) {
|
||||||
struct sembuf sem_op;
|
sem_wait(&q->empty);
|
||||||
sem_op.sem_num = 0;
|
sem_wait(&q->mutex);
|
||||||
sem_op.sem_op = -1;
|
|
||||||
sem_op.sem_flg = 0;
|
|
||||||
semop(queue->sem_id, &sem_op, 1);
|
|
||||||
|
|
||||||
queue->array[queue->in] = in_item;
|
q->rear = (q->rear + 1) % q->array_size;
|
||||||
queue->in = (queue->in + 1) % queue->array_size;
|
q->array[q->rear] = in_item;
|
||||||
|
|
||||||
sem_op.sem_num = 0;
|
sem_post(&q->mutex);
|
||||||
sem_op.sem_op = 1;
|
sem_post(&q->full);
|
||||||
semop(queue->sem_id, &sem_op, 1);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int queue_pop(ev_queue_t* queue, void **out_item) {
|
int queue_pop(queue_t* const q, void **out_item) {
|
||||||
struct sembuf sem_op;
|
sem_wait(&q->full);
|
||||||
sem_op.sem_num = 0;
|
sem_wait(&q->mutex);
|
||||||
sem_op.sem_op = -1;
|
|
||||||
sem_op.sem_flg = 0;
|
|
||||||
semop(queue->sem_id, &sem_op, 1);
|
|
||||||
|
|
||||||
*out_item = queue->array[queue->out];
|
q->front = (q->front + 1) % q->array_size;
|
||||||
queue->out = (queue->out + 1) % queue->array_size;
|
*out_item = q->array[q->front];
|
||||||
|
|
||||||
sem_op.sem_num = 0;
|
sem_post(&q->mutex);
|
||||||
sem_op.sem_op = 1;
|
sem_post(&q->empty);
|
||||||
semop(queue->sem_id, &sem_op, 1);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int queue_push_timeout(queue_t* const q, void *in_item, int timeout_ms) {
|
||||||
|
struct timespec timeout;
|
||||||
|
if (clock_gettime(CLOCK_MONOTONIC, &timeout) == -1) {
|
||||||
|
// Handle clock_gettime error
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
timeout.tv_sec += timeout_ms / 1000;
|
||||||
|
timeout.tv_nsec += (timeout_ms % 1000) * 1000000;
|
||||||
|
|
||||||
|
int result = sem_timedwait(&q->empty, &timeout);
|
||||||
|
|
||||||
|
if (result == 0) {
|
||||||
|
sem_wait(&q->mutex);
|
||||||
|
|
||||||
|
q->rear = (q->rear + 1) % q->array_size;
|
||||||
|
q->array[q->rear] = in_item;
|
||||||
|
|
||||||
|
sem_post(&q->mutex);
|
||||||
|
sem_post(&q->full);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int queue_pop_timeout(queue_t* const q, void **out_item, int timeout_ms) {
|
||||||
|
struct timespec timeout;
|
||||||
|
if (clock_gettime(CLOCK_MONOTONIC, &timeout) == -1) {
|
||||||
|
// Handle clock_gettime error
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
timeout.tv_sec += timeout_ms / 1000;
|
||||||
|
timeout.tv_nsec += (timeout_ms % 1000) * 1000000;
|
||||||
|
|
||||||
|
int result = sem_timedwait(&q->full, &timeout);
|
||||||
|
|
||||||
|
if (result == 0) {
|
||||||
|
sem_wait(&q->mutex);
|
||||||
|
|
||||||
|
q->front = (q->front + 1) % q->array_size;
|
||||||
|
*out_item = q->array[q->front];
|
||||||
|
|
||||||
|
sem_post(&q->mutex);
|
||||||
|
sem_post(&q->empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
22
queue.h
22
queue.h
|
|
@ -2,20 +2,24 @@
|
||||||
|
|
||||||
#include "rogue_enemy.h"
|
#include "rogue_enemy.h"
|
||||||
|
|
||||||
typedef struct ev_queue {
|
typedef struct queue {
|
||||||
int sem_id;
|
sem_t empty, full, mutex;
|
||||||
|
|
||||||
size_t in;
|
ssize_t front;
|
||||||
size_t out;
|
ssize_t rear;
|
||||||
|
|
||||||
size_t array_size;
|
size_t array_size;
|
||||||
void** array;
|
void** array;
|
||||||
} ev_queue_t;
|
} queue_t;
|
||||||
|
|
||||||
int queue_init(ev_queue_t* queue, key_t sem_key, size_t max_elements);
|
int queue_init(queue_t* queue, size_t max_elements);
|
||||||
|
|
||||||
void queue_destroy(ev_queue_t* queue);
|
void queue_destroy(queue_t* queue);
|
||||||
|
|
||||||
int queue_push(ev_queue_t* queue, void *in_item);
|
int queue_push(queue_t* queue, void *in_item);
|
||||||
|
|
||||||
int queue_pop(ev_queue_t* queue, void **out_item);
|
int queue_push_timeout(queue_t* const q, void *in_item, int timeout_ms);
|
||||||
|
|
||||||
|
int queue_pop(queue_t* queue, void **out_item);
|
||||||
|
|
||||||
|
int queue_pop_timeout(queue_t* const q, void **out_item, int timeout_ms);
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <time.h>
|
||||||
#include <stdatomic.h>
|
#include <stdatomic.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
@ -18,6 +19,8 @@
|
||||||
#include <linux/uinput.h>
|
#include <linux/uinput.h>
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
|
|
||||||
|
#include <semaphore.h>
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
#include <libevdev-1.0/libevdev/libevdev.h>
|
#include <libevdev-1.0/libevdev/libevdev.h>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue