use a queue to send events to the output device

This commit is contained in:
Denis 2023-11-06 01:39:52 +01:00
parent 593b1fbb5e
commit 895b5abeb9
No known key found for this signature in database
GPG key ID: DD9B63F805CF5C03
8 changed files with 118 additions and 59 deletions

View file

@ -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

View file

@ -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
View file

@ -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;

View file

@ -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;

View file

@ -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
View file

@ -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
View file

@ -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);

View file

@ -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>