diff --git a/app/meson.build b/app/meson.build index fc752e86..102a5c4f 100644 --- a/app/meson.build +++ b/app/meson.build @@ -35,6 +35,7 @@ src = [ 'src/hid/hid_gamepad.c', 'src/hid/hid_keyboard.c', 'src/hid/hid_mouse.c', + 'src/resampler/gamepad_resampler.c', 'src/trait/frame_source.c', 'src/trait/packet_source.c', 'src/uhid/gamepad_uhid.c', diff --git a/app/src/resampler/gamepad_resampler.c b/app/src/resampler/gamepad_resampler.c new file mode 100644 index 00000000..b1764922 --- /dev/null +++ b/app/src/resampler/gamepad_resampler.c @@ -0,0 +1,141 @@ +#include "gamepad_resampler.h" + +#include + +#include "input_events.h" +#include "util/log.h" + +/** Downcast gamepad processor to sc_gamepad_resampler */ +#define DOWNCAST(GP) \ + container_of(GP, struct sc_gamepad_resampler, gamepad_processor) + +static void +sc_gamepad_processor_slot_init(struct sc_gamepad_resampler_slot *slot, + uint32_t gamepad_id) { + assert(gamepad_id != SC_GAMEPAD_ID_INVALID); + slot->gamepad_id = gamepad_id; + slot->buttons = 0; + slot->axis_left_x = 0; + slot->axis_left_y = 0; + slot->axis_right_x = 0; + slot->axis_right_y = 0; + slot->axis_left_trigger = 0; + slot->axis_right_trigger = 0; +} + +static ssize_t +sc_gamepad_processor_slot_find(struct sc_gamepad_resampler *resampler, + uint32_t gamepad_id) { + for (size_t i = 0; i < SC_MAX_GAMEPADS; ++i) { + if (gamepad_id == resampler->slots[i].gamepad_id) { + // found + return i; + } + } + + return -1; +} + +static void +sc_gamepad_processor_process_gamepad_device(struct sc_gamepad_processor *gp, + const struct sc_gamepad_device_event *event) { + struct sc_gamepad_resampler *resampler = DOWNCAST(gp); + + if (event->type == SC_GAMEPAD_DEVICE_ADDED) { + + } else { + assert(event->type == SC_GAMEPAD_DEVICE_REMOVED); + } +} + +static void +sc_gamepad_processor_process_gamepad_axis(struct sc_gamepad_processor *gp, + const struct sc_gamepad_axis_event *event) { + struct sc_gamepad_resampler *resampler = DOWNCAST(gp); + +} + +static void +sc_gamepad_processor_process_gamepad_button(struct sc_gamepad_processor *gp, + const struct sc_gamepad_button_event *event) { + struct sc_gamepad_resampler *resampler = DOWNCAST(gp); + +} + +static void +sc_gamepad_resampler_trigger(void *userdata) { + struct sc_gamepad_resampler *resampler = userdata; + + sc_tick now = sc_tick_now(); + + for (size_t i = 0; i < SC_MAX_GAMEPADS; ++i) { + struct sc_gamepad_resampler_slot *slot = &resampler->slots[i]; + if (slot->gamepad_id != SC_GAMEPAD_ID_INVALID + && slot->deadline != SC_TICK_INVALID + && slot->deadline - now >= resampler->min_interval) { + + } + } +} + +static int +run_resampler(void *data) { + + return 0; +} + +bool +sc_gamepad_resampler_init(struct sc_gamepad_resampler *resampler, + struct sc_gamepad_processor *delegate, + sc_tick min_interval) { + bool ok = sc_mutex_init(&resampler->mutex); + if (!ok) { + return false; + } + + ok = sc_cond_init(&resampler->cond); + if (!ok) { + goto error_destroy_mutex; + } + + ok = sc_thread_create(&resampler->thread, run_resampler, "scrcpy-gp-rs", + resampler); + if (!ok) { + LOGE("Could not start gamepad resampler thread"); + goto error_destroy_cond; + } + + static const struct sc_gamepad_processor_ops ops = { + .process_gamepad_device = sc_gamepad_processor_process_gamepad_device, + .process_gamepad_axis = sc_gamepad_processor_process_gamepad_axis, + .process_gamepad_button = sc_gamepad_processor_process_gamepad_button, + }; + + resampler->gamepad_processor.ops = &ops; + + resampler->delegate = delegate; + resampler->min_interval = min_interval; + resampler->stopped = false; + + for (size_t i = 0; i < SC_MAX_GAMEPADS; ++i) { + resampler->slots[i].gamepad_id = SC_GAMEPAD_ID_INVALID; + } + + return true; + +error_destroy_mutex: + sc_mutex_destroy(&resampler->mutex); +error_destroy_cond: + sc_cond_destroy(&resampler->cond); + + return false; +} + +void +sc_gamepad_resampler_stop(struct sc_gamepad_resampler *resampler); + +void +sc_gamepad_resampler_join(struct sc_gamepad_resampler *resampler); + +void +sc_gamepad_resampler_destroy(struct sc_gamepad_resampler *resampler); diff --git a/app/src/resampler/gamepad_resampler.h b/app/src/resampler/gamepad_resampler.h new file mode 100644 index 00000000..52cf4686 --- /dev/null +++ b/app/src/resampler/gamepad_resampler.h @@ -0,0 +1,53 @@ +#ifndef SC_GAMEPAD_RESAMPLER_H +#define SC_GAMEPAD_RESAMPLER_H + +#include "common.h" + +#include + +#include "hid/hid_gamepad.h" // for SC_MAX_GAMEPADS +#include "trait/gamepad_processor.h" +#include "util/thread.h" +#include "util/tick.h" + +struct sc_gamepad_resampler_slot { + uint32_t gamepad_id; + sc_tick deadline; + uint32_t buttons; + uint16_t axis_left_x; + uint16_t axis_left_y; + uint16_t axis_right_x; + uint16_t axis_right_y; + uint16_t axis_left_trigger; + uint16_t axis_right_trigger; +}; + +struct sc_gamepad_resampler { + struct sc_gamepad_processor gamepad_processor; // gamepad processor trait + + struct sc_gamepad_processor *delegate; + sc_tick min_interval; + + sc_mutex mutex; + sc_cond cond; + sc_thread thread; + bool stopped; + + struct sc_gamepad_resampler_slot slots[SC_MAX_GAMEPADS]; +}; + +bool +sc_gamepad_resampler_init(struct sc_gamepad_resampler *resampler, + struct sc_gamepad_processor *delegate, + sc_tick min_interval); + +void +sc_gamepad_resampler_stop(struct sc_gamepad_resampler *resampler); + +void +sc_gamepad_resampler_join(struct sc_gamepad_resampler *resampler); + +void +sc_gamepad_resampler_destroy(struct sc_gamepad_resampler *resampler); + +#endif diff --git a/app/src/util/tick.h b/app/src/util/tick.h index 2d941f23..96299205 100644 --- a/app/src/util/tick.h +++ b/app/src/util/tick.h @@ -9,6 +9,8 @@ typedef int64_t sc_tick; #define PRItick PRIi64 #define SC_TICK_FREQ 1000000 // microsecond +#define SC_TICK_INVALID INT64_MIN + // To be adapted if SC_TICK_FREQ changes #define SC_TICK_TO_NS(tick) ((tick) * 1000) #define SC_TICK_TO_US(tick) (tick)