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
|
||||
CC=gcc
|
||||
OBJECTS=main.o input_dev.o output_dev.o queue.o
|
||||
|
|
@ -15,4 +15,4 @@ depends:
|
|||
$(CC) -MM $(OBJECTS:.o=.c) > depends
|
||||
|
||||
clean:
|
||||
rm -f ./$(TARGET) *.o depends
|
||||
rm -f ./$(TARGET) *.o depends
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "rogue_enemy.h"
|
||||
#include "queue.h"
|
||||
|
||||
#define INPUT_DEV_CTRL_FLAG_EXIT 0x00000001U
|
||||
|
||||
|
|
@ -24,6 +24,8 @@ typedef struct input_dev {
|
|||
const iio_filters_t* iio_filters;
|
||||
|
||||
volatile uint32_t crtl_flags;
|
||||
|
||||
queue_t *queue;
|
||||
} input_dev_t;
|
||||
|
||||
void *input_dev_thread_func(void *ptr);
|
||||
|
|
|
|||
13
main.c
13
main.c
|
|
@ -3,8 +3,8 @@
|
|||
#include "input_dev.h"
|
||||
#include "output_dev.h"
|
||||
|
||||
ev_queue_t imu_ev;
|
||||
ev_queue_t gamepad_ev;
|
||||
queue_t imu_ev;
|
||||
queue_t gamepad_ev;
|
||||
|
||||
static output_dev_t out_imu_dev = {
|
||||
.fd = -1,
|
||||
|
|
@ -26,6 +26,7 @@ static input_dev_t in_asus_kb_1_dev = {
|
|||
.dev_type = input_dev_type_uinput,
|
||||
.crtl_flags = 0x00000000U,
|
||||
.ev_filters = &in_asus_kb_1_filters,
|
||||
.queue = &gamepad_ev,
|
||||
};
|
||||
|
||||
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,
|
||||
.crtl_flags = 0x00000000U,
|
||||
.ev_filters = &in_asus_kb_2_filters,
|
||||
.queue = &gamepad_ev,
|
||||
};
|
||||
|
||||
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,
|
||||
.crtl_flags = 0x00000000U,
|
||||
.ev_filters = &in_asus_kb_3_filters,
|
||||
.queue = &gamepad_ev,
|
||||
};
|
||||
|
||||
static uinput_filters_t in_xbox_filters = {
|
||||
|
|
@ -56,6 +59,7 @@ static input_dev_t in_xbox_dev = {
|
|||
.dev_type = input_dev_type_uinput,
|
||||
.crtl_flags = 0x00000000U,
|
||||
.ev_filters = &in_xbox_filters,
|
||||
.queue = &gamepad_ev,
|
||||
};
|
||||
|
||||
void request_termination() {
|
||||
|
|
@ -77,6 +81,9 @@ void sig_handler(int signo)
|
|||
}
|
||||
|
||||
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);
|
||||
if (out_imu_dev.fd < 0) {
|
||||
// TODO: free(imu_dev.events_list);
|
||||
|
|
@ -94,11 +101,13 @@ int main(int argc, char ** argv) {
|
|||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/*
|
||||
__sighandler_t sigint_hndl = signal(SIGINT, sig_handler);
|
||||
if (sigint_hndl == SIG_ERR) {
|
||||
fprintf(stderr, "Error registering SIGINT handler\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
*/
|
||||
|
||||
int ret = 0;
|
||||
|
||||
|
|
|
|||
12
output_dev.c
12
output_dev.c
|
|
@ -1,4 +1,5 @@
|
|||
#include "output_dev.h"
|
||||
#include "queue.h"
|
||||
|
||||
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);
|
||||
|
|
@ -150,6 +151,17 @@ void *output_dev_thread_func(void *ptr) {
|
|||
output_dev_t *out_dev = (output_dev_t*)ptr;
|
||||
|
||||
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;
|
||||
if (flags & OUTPUT_DEV_CTRL_FLAG_EXIT) {
|
||||
out_dev->crtl_flags &= ~OUTPUT_DEV_CTRL_FLAG_EXIT;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include "rogue_enemy.h"
|
||||
#include "queue.h"
|
||||
|
||||
#define OUTPUT_DEV_VENDOR_ID 0x4532
|
||||
|
|
@ -24,7 +23,7 @@ typedef struct output_dev {
|
|||
|
||||
volatile uint32_t crtl_flags;
|
||||
|
||||
ev_queue_t *queue;
|
||||
queue_t *queue;
|
||||
} output_dev_t;
|
||||
|
||||
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 <stdlib.h>
|
||||
|
||||
int queue_init(ev_queue_t* queue, key_t sem_key, size_t max_elements) {
|
||||
queue->array_size = max_elements;
|
||||
queue->array = calloc(sizeof(void*), max_elements);
|
||||
if (queue->array == NULL) {
|
||||
int queue_init(queue_t* const q, size_t max_elements) {
|
||||
q->front = q->rear = -1;
|
||||
q->array_size = max_elements;
|
||||
q->array = calloc(sizeof(void*), max_elements);
|
||||
if (q->array == NULL) {
|
||||
perror("calloc");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int semid = semget(sem_key, 1, IPC_CREAT | 0666);
|
||||
if (semid < 0)
|
||||
{
|
||||
free(queue->array);
|
||||
perror("semget");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (semctl(semid, 0, SETVAL, 1) < 0)
|
||||
{
|
||||
free(queue->array);
|
||||
perror("semctl");
|
||||
return 1;
|
||||
}
|
||||
sem_init(&q->empty, 0, q->array_size);
|
||||
sem_init(&q->full, 0, 0);
|
||||
sem_init(&q->mutex, 0, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void queue_destroy(ev_queue_t* queue) {
|
||||
free(queue->array);
|
||||
queue->array = NULL;
|
||||
void queue_destroy(queue_t* q) {
|
||||
free(q->array);
|
||||
q->array = NULL;
|
||||
}
|
||||
|
||||
int queue_push(ev_queue_t* queue, void *in_item) {
|
||||
struct sembuf sem_op;
|
||||
sem_op.sem_num = 0;
|
||||
sem_op.sem_op = -1;
|
||||
sem_op.sem_flg = 0;
|
||||
semop(queue->sem_id, &sem_op, 1);
|
||||
int queue_push(queue_t* const q, void *in_item) {
|
||||
sem_wait(&q->empty);
|
||||
sem_wait(&q->mutex);
|
||||
|
||||
queue->array[queue->in] = in_item;
|
||||
queue->in = (queue->in + 1) % queue->array_size;
|
||||
q->rear = (q->rear + 1) % q->array_size;
|
||||
q->array[q->rear] = in_item;
|
||||
|
||||
sem_op.sem_num = 0;
|
||||
sem_op.sem_op = 1;
|
||||
semop(queue->sem_id, &sem_op, 1);
|
||||
sem_post(&q->mutex);
|
||||
sem_post(&q->full);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int queue_pop(ev_queue_t* queue, void **out_item) {
|
||||
struct sembuf sem_op;
|
||||
sem_op.sem_num = 0;
|
||||
sem_op.sem_op = -1;
|
||||
sem_op.sem_flg = 0;
|
||||
semop(queue->sem_id, &sem_op, 1);
|
||||
int queue_pop(queue_t* const q, void **out_item) {
|
||||
sem_wait(&q->full);
|
||||
sem_wait(&q->mutex);
|
||||
|
||||
*out_item = queue->array[queue->out];
|
||||
queue->out = (queue->out + 1) % queue->array_size;
|
||||
q->front = (q->front + 1) % q->array_size;
|
||||
*out_item = q->array[q->front];
|
||||
|
||||
sem_op.sem_num = 0;
|
||||
sem_op.sem_op = 1;
|
||||
semop(queue->sem_id, &sem_op, 1);
|
||||
sem_post(&q->mutex);
|
||||
sem_post(&q->empty);
|
||||
|
||||
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"
|
||||
|
||||
typedef struct ev_queue {
|
||||
int sem_id;
|
||||
typedef struct queue {
|
||||
sem_t empty, full, mutex;
|
||||
|
||||
size_t in;
|
||||
size_t out;
|
||||
ssize_t front;
|
||||
ssize_t rear;
|
||||
|
||||
size_t array_size;
|
||||
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 <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
#include <stdatomic.h>
|
||||
#include <inttypes.h>
|
||||
#include <fcntl.h>
|
||||
|
|
@ -18,6 +19,8 @@
|
|||
#include <linux/uinput.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
#include <semaphore.h>
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include <libevdev-1.0/libevdev/libevdev.h>
|
||||
Loading…
Add table
Add a link
Reference in a new issue