threading rework to support rumble

This commit is contained in:
Denis 2023-11-25 21:03:05 +01:00
parent 0ca1c08158
commit 9f2e1e9de5
No known key found for this signature in database
GPG key ID: DD9B63F805CF5C03
7 changed files with 91 additions and 60 deletions

View file

@ -1,4 +1,5 @@
#include "input_dev.h"
#include "logic.h"
#include "message.h"
#include "queue.h"
#include "dev_iio.h"
@ -326,9 +327,7 @@ static void input_iio(
int open_sysfs_idx = -1;
for (;;) {
const uint32_t flags = in_dev->crtl_flags;
if (flags & INPUT_DEV_CTRL_FLAG_EXIT) {
in_dev->crtl_flags &= ~INPUT_DEV_CTRL_FLAG_EXIT;
if (logic_termination_requested(in_dev->logic)) {
break;
}
@ -435,9 +434,7 @@ static void input_udev(
int open_sysfs_idx = -1;
for (;;) {
const uint32_t flags = in_dev->crtl_flags;
if (flags & INPUT_DEV_CTRL_FLAG_EXIT) {
in_dev->crtl_flags &= ~INPUT_DEV_CTRL_FLAG_EXIT;
if (logic_termination_requested(in_dev->logic)) {
break;
}

View file

@ -7,8 +7,6 @@
#undef INCLUDE_INPUT_DEBUG
#undef IGNORE_INPUT_SCAN
#define INPUT_DEV_CTRL_FLAG_EXIT 0x00000001U
typedef uint32_t (*ev_input_filter_t)(struct input_event*, size_t*, uint32_t*, uint32_t*);
typedef enum input_dev_type {
@ -30,8 +28,6 @@ typedef struct input_dev {
const uinput_filters_t* ev_filters;
const iio_filters_t* iio_filters;
volatile uint32_t crtl_flags;
ev_input_filter_t ev_input_filter_fn;
logic_t *logic;

View file

@ -131,3 +131,11 @@ logic_begin_status_update_err:
void logic_end_status_update(logic_t *const logic) {
pthread_mutex_unlock(&logic->gamepad_mutex);
}
void logic_request_termination(logic_t *const logic) {
logic->flags |= LOGIC_FLAGS_TERMINATION_REQUESTED;
}
int logic_termination_requested(logic_t *const logic) {
return (logic->flags & LOGIC_FLAGS_TERMINATION_REQUESTED) != 0;
}

11
logic.h
View file

@ -46,8 +46,9 @@ typedef struct gamepad_status {
} gamepad_status_t;
#define LOGIC_FLAGS_VIRT_DS4_ENABLE 0x00000001U
#define LOGIC_FLAGS_PLATFORM_ENABLE 0x00000002U
#define LOGIC_FLAGS_VIRT_DS4_ENABLE 0x00000001U
#define LOGIC_FLAGS_PLATFORM_ENABLE 0x00000002U
#define LOGIC_FLAGS_TERMINATION_REQUESTED 0x80000000U
typedef enum gamepad_output {
GAMEPAD_OUTPUT_EVDEV = 0,
@ -71,7 +72,7 @@ typedef struct logic {
pthread_t virt_ds4_thread;
uint32_t flags;
volatile uint32_t flags;
// the mutex is not needed if only one thread is writing this and others are checking with equality
//pthread_mutex_t gamepad_output_mutex;
@ -92,3 +93,7 @@ int logic_copy_gamepad_status(logic_t *const logic, gamepad_status_t *const out)
int logic_begin_status_update(logic_t *const logic);
void logic_end_status_update(logic_t *const logic);
void logic_request_termination(logic_t *const logic);
int logic_termination_requested(logic_t *const logic);

29
main.c
View file

@ -10,7 +10,6 @@ logic_t global_logic;
static output_dev_t out_gamepadd_dev = {
.gamepad_fd = -1,
.imu_fd = -1,
.crtl_flags = 0x00000000U,
.logic = &global_logic,
};
@ -20,7 +19,6 @@ static iio_filters_t in_iio_filters = {
static input_dev_t in_iio_dev = {
.dev_type = input_dev_type_iio,
.crtl_flags = 0x00000000U,
.iio_filters = &in_iio_filters,
.logic = &global_logic,
//.input_filter_fn = input_filter_imu_identity,
@ -32,7 +30,6 @@ static uinput_filters_t in_asus_kb_1_filters = {
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,
.logic = &global_logic,
.ev_input_filter_fn = input_filter_asus_kb,
@ -44,7 +41,6 @@ static uinput_filters_t in_asus_kb_2_filters = {
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,
.logic = &global_logic,
.ev_input_filter_fn = input_filter_asus_kb,
@ -56,7 +52,6 @@ static uinput_filters_t in_asus_kb_3_filters = {
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,
.logic = &global_logic,
.ev_input_filter_fn = input_filter_asus_kb,
@ -68,25 +63,15 @@ static uinput_filters_t in_xbox_filters = {
static input_dev_t in_xbox_dev = {
.dev_type = input_dev_type_uinput,
.crtl_flags = 0x00000000U,
.ev_filters = &in_xbox_filters,
.logic = &global_logic,
.ev_input_filter_fn = input_filter_identity,
};
void request_termination(void) {
out_gamepadd_dev.crtl_flags |= OUTPUT_DEV_CTRL_FLAG_EXIT;
in_xbox_dev.crtl_flags |= INPUT_DEV_CTRL_FLAG_EXIT;
in_asus_kb_3_dev.crtl_flags |= INPUT_DEV_CTRL_FLAG_EXIT;
in_asus_kb_2_dev.crtl_flags |= INPUT_DEV_CTRL_FLAG_EXIT;
in_asus_kb_1_dev.crtl_flags |= INPUT_DEV_CTRL_FLAG_EXIT;
}
void sig_handler(int signo)
{
if (signo == SIGINT) {
request_termination();
logic_request_termination(&global_logic);
printf("received SIGINT\n");
}
}
@ -140,7 +125,7 @@ int main(int argc, char ** argv) {
if (gamepad_thread_creation != 0) {
fprintf(stderr, "Error creating gamepad output thread: %d\n", gamepad_thread_creation);
ret = -1;
request_termination();
logic_request_termination(&global_logic);
goto gamepad_thread_err;
}
@ -148,7 +133,7 @@ int main(int argc, char ** argv) {
if (xbox_thread_creation != 0) {
fprintf(stderr, "Error creating xbox input thread: %d\n", xbox_thread_creation);
ret = -1;
request_termination();
logic_request_termination(&global_logic);
goto xbox_drv_thread_err;
}
@ -156,7 +141,7 @@ int main(int argc, char ** argv) {
if (asus_kb_1_thread_creation != 0) {
fprintf(stderr, "Error creating asus keyboard (1) input thread: %d\n", asus_kb_1_thread_creation);
ret = -1;
request_termination();
logic_request_termination(&global_logic);
goto asus_kb_1_thread_err;
}
@ -164,7 +149,7 @@ int main(int argc, char ** argv) {
if (asus_kb_2_thread_creation != 0) {
fprintf(stderr, "Error creating asus keyboard (2) input thread: %d\n", asus_kb_2_thread_creation);
ret = -1;
request_termination();
logic_request_termination(&global_logic);
goto asus_kb_2_thread_err;
}
@ -172,7 +157,7 @@ int main(int argc, char ** argv) {
if (asus_kb_3_thread_creation != 0) {
fprintf(stderr, "Error creating asus keyboard (3) input thread: %d\n", asus_kb_3_thread_creation);
ret = -1;
request_termination();
logic_request_termination(&global_logic);
goto asus_kb_3_thread_err;
}
@ -180,7 +165,7 @@ int main(int argc, char ** argv) {
if (iio_thread_creation != 0) {
fprintf(stderr, "Error creating iio input thread: %d\n", asus_kb_3_thread_creation);
ret = -1;
request_termination();
logic_request_termination(&global_logic);
goto iio_thread_err;
}

View file

@ -806,7 +806,7 @@ static void handle_msg(output_dev_t *const out_dev, message_t *const msg) {
}
}
void *output_dev_thread_func(void *ptr) {
void *output_dev_rumble_thread_func(void* ptr) {
output_dev_t *const out_dev = (output_dev_t*)ptr;
struct timeval now = {0};
@ -820,6 +820,67 @@ void *output_dev_thread_func(void *ptr) {
pthread_mutex_lock(&out_dev->logic->gamepad_mutex);
uint64_t rumble_events_count = out_dev->logic->gamepad.rumble_events_count;
pthread_mutex_unlock(&out_dev->logic->gamepad_mutex);
// maximum number of ms that the gamepad can remain in a blocked status
const int timeout_ms = 10;
for (;;) {
// sleep for about 4ms: this is an aggressive polling for rumble.
usleep(4000);
// here transmit the rumble request to the input-device-handling components
pthread_mutex_lock(&out_dev->logic->gamepad_mutex);
// check if the gamepad has notified the presence of a rumble event
if (out_dev->logic->gamepad.rumble_events_count != rumble_events_count) {
struct timespec timeout;
if (clock_gettime(CLOCK_MONOTONIC, &timeout) == 0) {
timeout.tv_sec += timeout_ms / 1000;
timeout.tv_nsec += (timeout_ms % 1000) * 1000000;
int result = sem_timedwait(&out_dev->logic->rumble.sem_empty, &timeout);
if (result == 0) {
// translate the rumble to evdev
out_dev->logic->rumble.value = out_dev->logic->gamepad.motors_intensity[0] * 255;
// wake up the input thread that will propagate the rumble to raw devices.
sem_post(&out_dev->logic->rumble.sem_full);
// update the rumble events counter: this rumble event was handled
rumble_events_count = out_dev->logic->gamepad.rumble_events_count;
}
}
}
pthread_mutex_unlock(&out_dev->logic->gamepad_mutex);
if (logic_termination_requested(out_dev->logic)) {
break;
}
}
return NULL;
}
void *output_dev_thread_func(void *ptr) {
output_dev_t *const out_dev = (output_dev_t*)ptr;
struct timeval now = {0};
#if defined(INCLUDE_TIMESTAMP)
gettimeofday(&now, NULL);
__time_t secAtInit = now.tv_sec;
__time_t usecAtInit = now.tv_usec;
#endif
pthread_t rumble_thread;
const int rumble_thread_creation = pthread_create(&rumble_thread, NULL, output_dev_rumble_thread_func, ptr);
if (rumble_thread_creation != 0) {
fprintf(stderr, "Error creating the rumble thread: %d -- rumble will not work.\n", rumble_thread_creation);
}
for (;;) {
void *raw_ev;
const int pop_res = queue_pop_timeout(&out_dev->logic->input_queue, &raw_ev, 1000);
@ -835,29 +896,13 @@ void *output_dev_thread_func(void *ptr) {
fprintf(stderr, "Cannot read from input queue: %d\n", pop_res);
continue;
}
/*
// here transmit the rumble request to the input-device-handling components
pthread_mutex_lock(&out_dev->logic->gamepad_mutex);
// check if the gamepad has notified the presence of a rumble event
if (out_dev->logic->gamepad.rumble_events_count != rumble_events_count) {
sem_wait(&out_dev->logic->rumble.sem_empty);
// translate the rumble to evdev
out_dev->logic->rumble.value = out_dev->logic->gamepad.motors_intensity[0];
sem_post(&out_dev->logic->rumble.sem_full);
}
pthread_mutex_unlock(&out_dev->logic->gamepad_mutex);
const uint32_t flags = out_dev->crtl_flags;
if (flags & OUTPUT_DEV_CTRL_FLAG_EXIT) {
out_dev->crtl_flags &= ~OUTPUT_DEV_CTRL_FLAG_EXIT;
if (logic_termination_requested(out_dev->logic)) {
break;
}
*/
}
pthread_join(rumble_thread, NULL);
return NULL;
}

View file

@ -37,9 +37,6 @@
#define PHYS_STR "00:11:22:33:44:55"
#define OUTPUT_DEV_CTRL_FLAG_EXIT 0x00000001U
#define OUTPUT_DEV_CTRL_FLAG_DATA 0x00000002U
#define ACCEL_RANGE 512
#define GYRO_RANGE 2000 // max range is +/- 35 radian/s
@ -59,8 +56,6 @@ typedef struct output_dev {
int imu_fd;
int mouse_fd;
volatile uint32_t crtl_flags;
logic_t *logic;
} output_dev_t;