diff --git a/CMakeLists.txt b/CMakeLists.txt index 515d8aa..d662d5f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,6 +17,7 @@ set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) add_executable(${ROGUE_EXECUTABLE_NAME} + dev_timer.c dev_evdev.c dev_iio.c dev_hidraw.c @@ -49,6 +50,7 @@ add_executable(${ALLINONE_EXECUTABLE_NAME} virt_mouse.c virt_kbd.c devices_status.c + dev_timer.c dev_evdev.c dev_iio.c dev_hidraw.c diff --git a/dev_in.c b/dev_in.c index c4104e1..141f113 100644 --- a/dev_in.c +++ b/dev_in.c @@ -5,6 +5,7 @@ #include "message.h" #include "dev_evdev.h" #include "dev_iio.h" +#include "dev_timer.h" #include @@ -13,6 +14,7 @@ typedef enum dev_in_type { DEV_IN_TYPE_HIDRAW, DEV_IN_TYPE_IIO, DEV_IN_TYPE_EV, + DEV_IN_TYPE_TIMER, } dev_in_type_t; typedef struct dev_in_iio { @@ -44,12 +46,29 @@ typedef struct dev_in_ev { struct ff_effect ff_effect; + ev_callbacks_t callbacks; + + void* user_data; + } dev_in_ev_t; +typedef struct dev_in_timer { + + dev_timer_t* timer; + + const char* name; + + timer_callbacks_t callbacks; + + void* user_data; + +} dev_in_timer_t; + typedef union dev_in_aggr { dev_in_ev_t evdev; dev_in_iio_t iio; dev_in_hidraw_t hidraw; + dev_in_timer_t timer; } dev_in_aggr_t; typedef struct dev_in { @@ -155,6 +174,23 @@ fill_message_from_evdev_err_completed: return res; } +static int timer_open_device( + const dev_in_settings_t *const in_settings, + const timer_filters_t *const in_filters, + dev_in_timer_t *const out_dev +) { + int res = dev_timer_open(in_filters, &out_dev->timer); + if (res != 0) { + fprintf(stderr, "Unable to open the timer device: %d\n", res); + goto timer_open_device_err; + } + + printf("Opened timer device: %s\n", in_filters->name); + +timer_open_device_err: + return res; +} + static int hidraw_open_device( const dev_in_settings_t *const in_settings, const hidraw_filters_t *const in_filters, @@ -270,6 +306,10 @@ static void hidraw_close_device(dev_in_hidraw_t *const out_hidraw) { dev_hidraw_close(out_hidraw->hidrawdev); } +static void timer_close_device(dev_in_timer_t *const out_hidraw) { + dev_timer_close(out_hidraw->timer); +} + static void handle_rumble_device(const dev_in_settings_t *const conf, dev_in_ev_t *const in_dev, const out_message_rumble_t *const in_rumble_msg) { if (!in_dev->has_rumble_support) { return; @@ -346,6 +386,25 @@ static void handle_leds(const dev_in_settings_t *const conf, dev_in_t *const in_ } } +static void handle_timeout( + const dev_in_settings_t *const conf, + dev_in_t *const in_devs, + size_t in_devs_count, + const char* name, + uint64_t expirations +) { + for (size_t i = 0; i < in_devs_count; ++i) { + if (in_devs[i].type == DEV_IN_TYPE_EV) { + in_devs[i].dev.hidraw.callbacks.timeout_callback( + conf, + name, + expirations, + in_devs[i].dev.evdev.user_data + ); + } + } +} + static int open_socket(struct sockaddr_un *serveraddr) { int res = -ENODEV; @@ -440,8 +499,11 @@ void* dev_in_thread_func(void *ptr) { &dev_in_data->input_dev_decl->dev[i]->filters.ev, &devices[i].dev.evdev ); + if (open_res == 0) { devices[i].type = DEV_IN_TYPE_EV; + devices[i].dev.evdev.user_data = dev_in_data->input_dev_decl->dev[i]->user_data; + devices[i].dev.evdev.callbacks = dev_in_data->input_dev_decl->dev[i]->map.ev_callbacks; // device is now connected, query it in select FD_SET(libevdev_get_fd(devices[i].dev.evdev.evdev), &read_fds); @@ -457,6 +519,9 @@ void* dev_in_thread_func(void *ptr) { if (open_res == 0) { devices[i].type = DEV_IN_TYPE_IIO; + + // device is now connected, query it in select + FD_SET(dev_iio_get_buffer_fd(devices[i].dev.iio.iiodev), &read_fds); } } else if (d_type == input_dev_type_hidraw) { fprintf(stderr, "Device (hidraw) %zu not found -- Attempt reconnection for device %x:%x\n", i, dev_in_data->input_dev_decl->dev[i]->filters.hidraw.pid, dev_in_data->input_dev_decl->dev[i]->filters.hidraw.vid); @@ -471,6 +536,27 @@ void* dev_in_thread_func(void *ptr) { devices[i].dev.hidraw.callbacks = dev_in_data->input_dev_decl->dev[i]->map.hidraw_callbacks; devices[i].dev.hidraw.user_data = dev_in_data->input_dev_decl->dev[i]->user_data; devices[i].type = DEV_IN_TYPE_HIDRAW; + + // device is now connected, query it in select + FD_SET(dev_hidraw_get_fd(devices[i].dev.hidraw.hidrawdev), &read_fds); + } + } else if (d_type == input_dev_type_timer) { + fprintf(stderr, "Device (timer) %zu not found -- Attempt to create it with name %s\n", i, dev_in_data->input_dev_decl->dev[i]->filters.timer.name); + + const int open_res = timer_open_device( + &dev_in_data->settings, + &dev_in_data->input_dev_decl->dev[i]->filters.timer, + &devices[i].dev.timer + ); + + if (open_res == 0) { + devices[i].dev.timer.callbacks = dev_in_data->input_dev_decl->dev[i]->map.timer_callbacks; + devices[i].dev.timer.user_data = dev_in_data->input_dev_decl->dev[i]->user_data; + devices[i].dev.timer.name = dev_in_data->input_dev_decl->dev[i]->filters.timer.name; + devices[i].type = DEV_IN_TYPE_TIMER; + + // device is now connected, query it in select + FD_SET(dev_timer_get_fd(devices[i].dev.timer.timer), &read_fds); } } } @@ -534,6 +620,8 @@ void* dev_in_thread_func(void *ptr) { fd = dev_iio_get_buffer_fd(devices[i].dev.iio.iiodev); } else if (devices[i].type == DEV_IN_TYPE_HIDRAW) { fd = dev_hidraw_get_fd(devices[i].dev.hidraw.hidrawdev); + } else if (devices[i].type == DEV_IN_TYPE_TIMER) { + fd = dev_timer_get_fd(devices[i].dev.timer.timer); } else { continue; } @@ -560,12 +648,12 @@ void* dev_in_thread_func(void *ptr) { continue; } - controller_msg_count = dev_in_data->input_dev_decl->dev[i]->map.ev_input_map_fn( + controller_msg_count = devices[i].dev.evdev.callbacks.input_map_fn( &dev_in_data->settings, &coll, &controller_msg[0], controller_msg_avail, - dev_in_data->input_dev_decl->dev[i]->user_data + devices[i].dev.evdev.user_data ); } else if (devices[i].type == DEV_IN_TYPE_IIO) { controller_msg_count = map_message_from_iio( @@ -573,6 +661,7 @@ void* dev_in_thread_func(void *ptr) { &controller_msg[0], controller_msg_avail ); + if (controller_msg_count < 0) { fprintf(stderr, "Error in reading iio buffer for device %zd: %d -- Will reconnect to the device\n", i, controller_msg_count); iio_close_device(&devices[i].dev.iio); @@ -580,19 +669,53 @@ void* dev_in_thread_func(void *ptr) { continue; } } else if (devices[i].type == DEV_IN_TYPE_HIDRAW) { - controller_msg_count = dev_in_data->input_dev_decl->dev[i]->map.hidraw_callbacks.map_callback( + controller_msg_count = devices[i].dev.hidraw.callbacks.map_callback( &dev_in_data->settings, - dev_hidraw_get_fd(devices[i].dev.hidraw.hidrawdev), + fd, &controller_msg[0], controller_msg_avail, - dev_in_data->input_dev_decl->dev[i]->user_data + devices[i].dev.hidraw.user_data ); + if (controller_msg_count < 0) { fprintf(stderr, "Error in performing operations for device %zd: %d -- Will reconnect to the device\n", i, controller_msg_count); hidraw_close_device(&devices[i].dev.hidraw); devices[i].type = DEV_IN_TYPE_NONE; continue; } + } else if (devices[i].type == DEV_IN_TYPE_TIMER) { + uint64_t expirations; + ssize_t num_read = read(fd, &expirations, sizeof(uint64_t)); + if (num_read != sizeof(uint64_t)) { + fprintf(stderr, "Error in reading expirations from timer device %zd: %d -- Will reconnect to the device\n", i, controller_msg_count); + timer_close_device(&devices[i].dev.timer); + devices[i].type = DEV_IN_TYPE_NONE; + continue; + } + + controller_msg_count = devices[i].dev.timer.callbacks.map_fn( + &dev_in_data->settings, + fd, + expirations, + &controller_msg[0], + controller_msg_avail, + devices[i].dev.timer.user_data + ); + + if (controller_msg_count < 0) { + fprintf(stderr, "Error in timer device %zd: %d -- Will reconnect to the device\n", i, controller_msg_count); + timer_close_device(&devices[i].dev.timer); + devices[i].type = DEV_IN_TYPE_NONE; + continue; + } + + handle_timeout( + &dev_in_data->settings, + devices, + max_devices, + devices[i].dev.timer.name, + expirations + ); } // send messages (if any) @@ -652,6 +775,9 @@ void* dev_in_thread_func(void *ptr) { } else if (devices[i].type == DEV_IN_TYPE_HIDRAW) { hidraw_close_device(&devices[i].dev.hidraw); devices[i].type = DEV_IN_TYPE_NONE; + } else if (devices[i].type == DEV_IN_TYPE_TIMER) { + timer_close_device(&devices[i].dev.timer); + devices[i].type = DEV_IN_TYPE_NONE; } } diff --git a/dev_timer.c b/dev_timer.c new file mode 100644 index 0000000..6c6e2e3 --- /dev/null +++ b/dev_timer.c @@ -0,0 +1,60 @@ +#include "dev_timer.h" + +int dev_timer_open( + const timer_filters_t *const in_filters, + dev_timer_t **const out_dev +) { + int res = -ENODEV; + + *out_dev = malloc(sizeof(dev_timer_t)); + if (*out_dev == NULL) { + res = -ENOMEM; + goto dev_timer_open_err; + } + + memset(*out_dev, 0, sizeof(dev_timer_t)); + + const int fd = timerfd_create(CLOCK_MONOTONIC, 0); + if (fd < 0) { + res = errno < 0 ? errno : -1 * errno; + if (res == 0) { + res = fd; + } + goto dev_timer_open_err; + } + + (*out_dev)->fd = fd; + (*out_dev)->timer_spec.it_value.tv_sec = in_filters->ticktime_ms / (__time_t)1000; + (*out_dev)->timer_spec.it_value.tv_nsec = (in_filters->ticktime_ms % (__syscall_slong_t)1000) * (__syscall_slong_t)1000000; + (*out_dev)->timer_spec.it_interval.tv_sec = in_filters->ticktime_ms / (__time_t)1000; + (*out_dev)->timer_spec.it_interval.tv_nsec = (in_filters->ticktime_ms % (__syscall_slong_t)1000) * (__syscall_slong_t)1000000; + + if (timerfd_settime((*out_dev)->fd, 0, &(*out_dev)->timer_spec, NULL) < 0) { + res = errno < 0 ? errno : -1 * errno; + if (res == 0) { + res = -EIO; + } + goto dev_timer_open_err; + } + + res = 0; + +dev_timer_open_err: + if (res != 0) { + if (fd > 0) { + close(fd); + } + + free(*out_dev); + } + + return res; +} + +void dev_timer_close(dev_timer_t *const inout_dev) { + close(inout_dev->fd); +} + +int dev_timer_get_fd(const dev_timer_t *const in_dev) { + return in_dev->fd; +} diff --git a/dev_timer.h b/dev_timer.h new file mode 100644 index 0000000..41c6ba5 --- /dev/null +++ b/dev_timer.h @@ -0,0 +1,18 @@ +#pragma once + +#include "input_dev.h" + +typedef struct dev_timer { + struct itimerspec timer_spec; + + int fd; +} dev_timer_t; + +int dev_timer_open( + const timer_filters_t *const in_filters, + dev_timer_t **const out_dev +); + +void dev_timer_close(dev_timer_t *const inout_dev); + +int dev_timer_get_fd(const dev_timer_t *const in_dev); diff --git a/input_dev.h b/input_dev.h index 377c689..c7cb973 100644 --- a/input_dev.h +++ b/input_dev.h @@ -18,12 +18,25 @@ typedef struct evdev_collected { * A function with this signature grapbs input_event data and sends to the pipe messages * constructed from that data. */ -typedef int (*ev_map)(const dev_in_settings_t *const conf, const evdev_collected_t *const e, in_message_t *const messages, size_t messages_len, void* user_data); +typedef int (*ev_map)( + const dev_in_settings_t *const conf, + const evdev_collected_t *const e, + in_message_t *const messages, + size_t messages_len, + void* user_data +); +typedef void (*ev_timer)( + const dev_in_settings_t *const conf, + const char* const timer_name, + uint64_t expired, + void* user_data +); typedef enum input_dev_type { input_dev_type_uinput, input_dev_type_iio, input_dev_type_hidraw, + input_dev_type_timer, } input_dev_type_t; typedef struct hidraw_filters { @@ -48,6 +61,7 @@ typedef struct hidraw_callbacks { hidraw_set_leds leds_callback; hidraw_rumble rumble_callback; hidraw_map map_callback; + ev_timer timeout_callback; } hidraw_callbacks_t; typedef struct iio_settings { @@ -55,6 +69,22 @@ typedef struct iio_settings { int8_t post_matrix[3][3]; } iio_settings_t; +typedef int (*timer_map)(const dev_in_settings_t *const conf, int timer_fd, uint64_t expirations, in_message_t *const messages, size_t messages_len, void* user_data); + +typedef struct timer_callbacks { + timer_map map_fn; +} timer_callbacks_t; + +typedef struct ev_callbacks { + ev_map input_map_fn; + ev_timer timeout_callback; +} ev_callbacks_t; + +typedef struct timer_filters { + char name[128]; + uint64_t ticktime_ms; +} timer_filters_t; + typedef struct input_dev { input_dev_type_t dev_type; @@ -62,14 +92,16 @@ typedef struct input_dev { uinput_filters_t ev; iio_filters_t iio; hidraw_filters_t hidraw; + timer_filters_t timer; } filters; void* user_data; union input_dev_map { iio_settings_t iio_settings; - ev_map ev_input_map_fn; + ev_callbacks_t ev_callbacks; hidraw_callbacks_t hidraw_callbacks; + timer_callbacks_t timer_callbacks; } map; } input_dev_t; diff --git a/legion_go.c b/legion_go.c index 6f15eb0..6d5c33e 100644 --- a/legion_go.c +++ b/legion_go.c @@ -11,7 +11,9 @@ static input_dev_t in_xbox_dev = { } }, .map = { - .ev_input_map_fn = xbox360_ev_map, + .ev_callbacks = { + .input_map_fn = xbox360_ev_map, + }, } }; diff --git a/rog_ally.c b/rog_ally.c index 1b808e0..59072a2 100644 --- a/rog_ally.c +++ b/rog_ally.c @@ -844,6 +844,15 @@ static input_dev_t in_iio_dev = { //.input_filter_fn = input_filter_imu_identity, }; +static void rc71l_timer_asus_kbd( + const dev_in_settings_t *const conf, + const char* const timer_name, + uint64_t expired, + void* user_data +) { + +} + static input_dev_t in_asus_kb_1_dev = { .dev_type = input_dev_type_uinput, .filters = { @@ -853,7 +862,10 @@ static input_dev_t in_asus_kb_1_dev = { }, .user_data = (void*)&asus_userdata, .map = { - .ev_input_map_fn = asus_kbd_ev_map, + .ev_callbacks = { + .input_map_fn = asus_kbd_ev_map, + .timeout_callback = rc71l_timer_asus_kbd, + }, } }; @@ -866,7 +878,10 @@ static input_dev_t in_asus_kb_2_dev = { }, .user_data = (void*)&asus_userdata, .map = { - .ev_input_map_fn = asus_kbd_ev_map, + .ev_callbacks = { + .input_map_fn = asus_kbd_ev_map, + .timeout_callback = rc71l_timer_asus_kbd, + }, } }; @@ -879,10 +894,22 @@ static input_dev_t in_asus_kb_3_dev = { }, .user_data = &asus_userdata, .map = { - .ev_input_map_fn = asus_kbd_ev_map, + .ev_callbacks = { + .input_map_fn = asus_kbd_ev_map, + .timeout_callback = rc71l_timer_asus_kbd, + }, } }; +static void rc71l_timer_xbox360( + const dev_in_settings_t *const conf, + const char* const timer_name, + uint64_t expired, + void* user_data +) { + +} + static input_dev_t in_xbox_dev = { .dev_type = input_dev_type_uinput, .filters = { @@ -891,7 +918,10 @@ static input_dev_t in_xbox_dev = { } }, .map = { - .ev_input_map_fn = xbox360_ev_map, + .ev_callbacks = { + .input_map_fn = xbox360_ev_map, + .timeout_callback = rc71l_timer_xbox360, + }, } }; @@ -989,6 +1019,26 @@ static int rc71l_platform_leds(const dev_in_settings_t *const conf, uint8_t r, u return 0; } +int rc71l_timer_map(const dev_in_settings_t *const conf, int timer_fd, uint64_t expirations, in_message_t *const messages, size_t messages_len, void* user_data) { + return 0; +} + +input_dev_t timer_dev = { + .dev_type = input_dev_type_timer, + .filters = { + .timer = { + .name = "RC71L_timer", + .ticktime_ms = 150, + } + }, + .user_data = NULL, + .map = { + .timer_callbacks = { + .map_fn = rc71l_timer_map, + } + } +}; + input_dev_composite_t rc71l_composite = { .dev = { &in_xbox_dev, @@ -997,8 +1047,9 @@ input_dev_composite_t rc71l_composite = { &in_asus_kb_2_dev, &in_asus_kb_3_dev, &nkey_dev, + &timer_dev, }, - .dev_count = 6, + .dev_count = 7, .init_fn = rc71l_platform_init, .deinit_fn = rc71l_platform_deinit, .leds_fn = rc71l_platform_leds, diff --git a/rogue_enemy.h b/rogue_enemy.h index 4d17389..00197be 100644 --- a/rogue_enemy.h +++ b/rogue_enemy.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include