diff --git a/Module.mk b/Module.mk index 546ab78..09a9658 100644 --- a/Module.mk +++ b/Module.mk @@ -183,6 +183,7 @@ include src/main/util/Module.mk include src/main/vefxio/Module.mk include src/main/vigem-iidxio/Module.mk include src/main/vigem-sdvxio/Module.mk +include src/main/vigem-ddrio/Module.mk include src/main/vigemstub/Module.mk include src/test/cconfig/Module.mk @@ -615,6 +616,18 @@ $(zipdir)/sdvx-hwio-x64.zip: \ $(V)echo ... $@ $(V)zip -j $@ $^ +$(zipdir)/ddr-hwio-x86.zip: \ + build/bin/indep-32/vigem-ddrio.exe \ + | $(zipdir)/ + $(V)echo ... $@ + $(V)zip -j $@ $^ + +$(zipdir)/ddr-hwio-x64.zip: \ + build/bin/indep-64/vigem-ddrio.exe \ + | $(zipdir)/ + $(V)echo ... $@ + $(V)zip -j $@ $^ + $(zipdir)/ddr-11.zip: \ build/bin/indep-32/inject.exe \ build/bin/avs2_803-32/ddrhook1.dll \ @@ -794,6 +807,8 @@ $(BUILDDIR)/bemanitools.zip: \ $(zipdir)/ddr-13.zip \ $(zipdir)/ddr-14-to-16.zip \ $(zipdir)/ddr-16-x64.zip \ + $(zipdir)/ddr-hwio-x86.zip \ + $(zipdir)/ddr-hwio-x64.zip \ $(zipdir)/doc.zip \ $(zipdir)/iidx-09-to-12.zip \ $(zipdir)/iidx-13.zip \ diff --git a/src/main/vigem-ddrio/Module.mk b/src/main/vigem-ddrio/Module.mk new file mode 100644 index 0000000..8aae8a2 --- /dev/null +++ b/src/main/vigem-ddrio/Module.mk @@ -0,0 +1,20 @@ +exes += vigem-ddrio + +deplibs_vigem-ddrio := \ + ViGEmClient \ + +cppflags_vigem-ddrio := \ + -I src/imports \ + +ldflags_vigem-ddrio := \ + -lsetupapi \ + +libs_vigem-ddrio := \ + cconfig \ + ddrio \ + util \ + vigemstub \ + +src_vigem-ddrio := \ + main.c \ + config-vigem-ddrio.c \ diff --git a/src/main/vigem-ddrio/config-vigem-ddrio.c b/src/main/vigem-ddrio/config-vigem-ddrio.c new file mode 100644 index 0000000..59e8251 --- /dev/null +++ b/src/main/vigem-ddrio/config-vigem-ddrio.c @@ -0,0 +1,63 @@ +#include "cconfig/cconfig-main.h" +#include "cconfig/cconfig-util.h" + +#include "vigem-ddrio/config-vigem-ddrio.h" + +#include "util/log.h" + +#define VIGEM_DDRIO_CONFIG_ENABLE_REACTIVE_LIGHT_KEY \ + "ddrio.enable_reactive_light" + +#define VIGEM_DDRIO_CONFIG_DEFAULT_ENABLE_REACTIVE_LIGHT_VALUE true + +static void vigem_ddrio_config_init(struct cconfig *config) +{ + cconfig_util_set_bool( + config, + VIGEM_DDRIO_CONFIG_ENABLE_REACTIVE_LIGHT_KEY, + VIGEM_DDRIO_CONFIG_DEFAULT_ENABLE_REACTIVE_LIGHT_VALUE, + "Enable reactive lights based on input."); +} + +static void vigem_ddrio_config_get( + struct vigem_ddrio_config *vigem_config, struct cconfig *config) +{ + if (!cconfig_util_get_bool( + config, + VIGEM_DDRIO_CONFIG_ENABLE_REACTIVE_LIGHT_KEY, + &vigem_config->enable_reactive_light, + VIGEM_DDRIO_CONFIG_DEFAULT_ENABLE_REACTIVE_LIGHT_VALUE)) { + log_warning( + "Invalid value for key '%s' specified, fallback " + "to default '%d'", + VIGEM_DDRIO_CONFIG_ENABLE_REACTIVE_LIGHT_KEY, + VIGEM_DDRIO_CONFIG_DEFAULT_ENABLE_REACTIVE_LIGHT_VALUE); + } +} + +bool get_vigem_ddrio_config(struct vigem_ddrio_config *config_out) +{ + struct cconfig *config; + + config = cconfig_init(); + + vigem_ddrio_config_init(config); + + if (!cconfig_main_config_init( + config, + "--config", + "vigem-ddrio.conf", + "--help", + "-h", + "vigem-ddrio", + CCONFIG_CMD_USAGE_OUT_STDOUT)) { + cconfig_finit(config); + return false; + } + + vigem_ddrio_config_get(config_out, config); + + cconfig_finit(config); + + return true; +} diff --git a/src/main/vigem-ddrio/config-vigem-ddrio.h b/src/main/vigem-ddrio/config-vigem-ddrio.h new file mode 100644 index 0000000..df00645 --- /dev/null +++ b/src/main/vigem-ddrio/config-vigem-ddrio.h @@ -0,0 +1,14 @@ +#ifndef VIGEM_DDRIO_CONFIG_H +#define VIGEM_DDRIO_CONFIG_H + +#include + +#include "cconfig/cconfig.h" + +struct vigem_ddrio_config { + bool enable_reactive_light; +}; + +bool get_vigem_ddrio_config(struct vigem_ddrio_config *config_out); + +#endif \ No newline at end of file diff --git a/src/main/vigem-ddrio/main.c b/src/main/vigem-ddrio/main.c new file mode 100644 index 0000000..62cc7b1 --- /dev/null +++ b/src/main/vigem-ddrio/main.c @@ -0,0 +1,244 @@ +#include +#include +#include +#include + +#include + +#include "ViGEm/Client.h" + +#include "bemanitools/ddrio.h" +#include "util/log.h" +#include "util/math.h" +#include "util/thread.h" +#include "vigemstub/helper.h" + +#include "vigem-ddrio/config-vigem-ddrio.h" + +#define NUM_PADS 2 + +bool check_key(uint32_t input, size_t idx_in) +{ + if ((input >> idx_in) & 1) { + return true; + } + + return false; +} + +uint32_t check_assign_key(uint32_t input, size_t idx_in, size_t bit_out) +{ + if (check_key(input, idx_in)) { + return bit_out; + } + + return 0; +} + +uint32_t check_assign_light(uint32_t input, size_t idx_in, size_t gpio_out) +{ + if (check_key(input, idx_in)) { + return 1 << gpio_out; + } + + return 0; +} + +void set_all_lights(bool on) +{ + ddr_io_set_lights_extio(on ? UINT32_MAX : 0); + ddr_io_set_lights_p3io(on ? UINT32_MAX : 0); + ddr_io_set_lights_hdxs_panel(on ? UINT32_MAX : 0); + + for (int i = 0; i < 4; i++) { + uint8_t val = on ? UINT8_MAX : 0; + ddr_io_set_lights_hdxs_rgb(i, val, val, val); + } +} + +void set_reactive_lights(uint32_t input_state) +{ + uint32_t new_extio_state = 0; + uint32_t new_p3io_state = 0; + uint32_t new_hdxs_state = 0; + + new_extio_state |= check_assign_light(input_state, DDR_P1_UP, LIGHT_P1_UP); + new_extio_state |= + check_assign_light(input_state, DDR_P1_DOWN, LIGHT_P1_DOWN); + new_extio_state |= + check_assign_light(input_state, DDR_P1_LEFT, LIGHT_P1_LEFT); + new_extio_state |= + check_assign_light(input_state, DDR_P1_RIGHT, LIGHT_P1_RIGHT); + + new_extio_state |= check_assign_light(input_state, DDR_P2_UP, LIGHT_P2_UP); + new_extio_state |= + check_assign_light(input_state, DDR_P2_DOWN, LIGHT_P2_DOWN); + new_extio_state |= + check_assign_light(input_state, DDR_P2_LEFT, LIGHT_P2_LEFT); + new_extio_state |= + check_assign_light(input_state, DDR_P2_RIGHT, LIGHT_P2_RIGHT); + + new_p3io_state |= + check_assign_light(input_state, DDR_P1_START, LIGHT_P1_MENU); + new_p3io_state |= + check_assign_light(input_state, DDR_P2_START, LIGHT_P2_MENU); + + new_hdxs_state |= + check_assign_light(input_state, DDR_P1_START, LIGHT_HD_P1_START); + new_hdxs_state |= + check_assign_light(input_state, DDR_P1_MENU_UP, LIGHT_HD_P1_UP_DOWN); + new_hdxs_state |= + check_assign_light(input_state, DDR_P1_MENU_DOWN, LIGHT_HD_P1_UP_DOWN); + new_hdxs_state |= check_assign_light( + input_state, DDR_P1_MENU_LEFT, LIGHT_HD_P1_LEFT_RIGHT); + new_hdxs_state |= check_assign_light( + input_state, DDR_P1_MENU_RIGHT, LIGHT_HD_P1_LEFT_RIGHT); + + new_hdxs_state |= + check_assign_light(input_state, DDR_P2_START, LIGHT_HD_P2_START); + new_hdxs_state |= + check_assign_light(input_state, DDR_P2_MENU_UP, LIGHT_HD_P2_UP_DOWN); + new_hdxs_state |= + check_assign_light(input_state, DDR_P2_MENU_DOWN, LIGHT_HD_P2_UP_DOWN); + new_hdxs_state |= check_assign_light( + input_state, DDR_P2_MENU_LEFT, LIGHT_HD_P2_LEFT_RIGHT); + new_hdxs_state |= check_assign_light( + input_state, DDR_P2_MENU_RIGHT, LIGHT_HD_P2_LEFT_RIGHT); + + ddr_io_set_lights_extio(new_extio_state); + ddr_io_set_lights_p3io(new_p3io_state); + ddr_io_set_lights_hdxs_panel(new_hdxs_state); +} + +int main(int argc, char **argv) +{ + log_to_writer(log_writer_stdout, NULL); + + struct vigem_ddrio_config config; + if (!get_vigem_ddrio_config(&config)) { + exit(EXIT_FAILURE); + } + + ddr_io_set_loggers( + log_impl_misc, log_impl_info, log_impl_warning, log_impl_fatal); + + if (!ddr_io_init(crt_thread_create, crt_thread_join, crt_thread_destroy)) { + log_warning("Initializing ddrio failed"); + return -1; + } + + // go ahead and turn lights off as some are on during boot. + set_all_lights(false); + + PVIGEM_CLIENT client = vigem_helper_setup(); + + if (!client) { + log_warning("client failed to connect failed"); + return -1; + } + + PVIGEM_TARGET pad[NUM_PADS]; + bool failed = false; + + for (uint8_t i = 0; i < NUM_PADS; i++) { + pad[i] = vigem_helper_add_pad(client); + + if (!pad[i]) { + log_warning("vigem_alloc pad %d failed", i); + failed = true; + } + } + + if (failed) { + ddr_io_fini(); + return -1; + } + + bool loop = true; + uint32_t pad_state = 0; + XUSB_REPORT state[NUM_PADS] = {0}; + + log_info("vigem init succeeded, beginning poll loop"); + + while (loop) { + pad_state = ddr_io_read_pad(); + + for (uint8_t i = 0; i < NUM_PADS; i++) { + memset(&state[i], 0, sizeof(state[i])); + } + + state[0].wButtons |= + check_assign_key(pad_state, DDR_TEST, XUSB_GAMEPAD_LEFT_THUMB); + state[0].wButtons |= + check_assign_key(pad_state, DDR_SERVICE, XUSB_GAMEPAD_RIGHT_THUMB); + state[0].wButtons |= + check_assign_key(pad_state, DDR_COIN, XUSB_GAMEPAD_BACK); + + // assign arrows to face buttons due to jumps / hat interpretation + state[0].wButtons |= + check_assign_key(pad_state, DDR_P1_UP, XUSB_GAMEPAD_Y); + state[0].wButtons |= + check_assign_key(pad_state, DDR_P1_DOWN, XUSB_GAMEPAD_A); + state[0].wButtons |= + check_assign_key(pad_state, DDR_P1_LEFT, XUSB_GAMEPAD_X); + state[0].wButtons |= + check_assign_key(pad_state, DDR_P1_RIGHT, XUSB_GAMEPAD_B); + + state[0].wButtons |= + check_assign_key(pad_state, DDR_P1_START, XUSB_GAMEPAD_START); + state[0].wButtons |= + check_assign_key(pad_state, DDR_P1_MENU_UP, XUSB_GAMEPAD_DPAD_UP); + state[0].wButtons |= check_assign_key( + pad_state, DDR_P1_MENU_DOWN, XUSB_GAMEPAD_DPAD_DOWN); + state[0].wButtons |= check_assign_key( + pad_state, DDR_P1_MENU_LEFT, XUSB_GAMEPAD_DPAD_LEFT); + state[0].wButtons |= check_assign_key( + pad_state, DDR_P1_MENU_RIGHT, XUSB_GAMEPAD_DPAD_RIGHT); + + state[1].wButtons |= + check_assign_key(pad_state, DDR_P2_UP, XUSB_GAMEPAD_Y); + state[1].wButtons |= + check_assign_key(pad_state, DDR_P2_DOWN, XUSB_GAMEPAD_A); + state[1].wButtons |= + check_assign_key(pad_state, DDR_P2_LEFT, XUSB_GAMEPAD_X); + state[1].wButtons |= + check_assign_key(pad_state, DDR_P2_RIGHT, XUSB_GAMEPAD_B); + + state[1].wButtons |= + check_assign_key(pad_state, DDR_P2_START, XUSB_GAMEPAD_START); + state[1].wButtons |= + check_assign_key(pad_state, DDR_P2_MENU_UP, XUSB_GAMEPAD_DPAD_UP); + state[1].wButtons |= check_assign_key( + pad_state, DDR_P2_MENU_DOWN, XUSB_GAMEPAD_DPAD_DOWN); + state[1].wButtons |= check_assign_key( + pad_state, DDR_P2_MENU_LEFT, XUSB_GAMEPAD_DPAD_LEFT); + state[1].wButtons |= check_assign_key( + pad_state, DDR_P2_MENU_RIGHT, XUSB_GAMEPAD_DPAD_RIGHT); + + for (uint8_t i = 0; i < NUM_PADS; i++) { + vigem_target_x360_update(client, pad[i], state[i]); + } + + if (config.enable_reactive_light) { + set_reactive_lights(pad_state); + } + + if (check_key(pad_state, DDR_TEST) && + check_key(pad_state, DDR_SERVICE)) { + loop = false; + } + + // avoid CPU banging + Sleep(1); + } + + for (uint8_t i = 0; i < NUM_PADS; i++) { + vigem_target_remove(client, pad[i]); + vigem_target_free(pad[i]); + } + + vigem_free(client); + ddr_io_fini(); + + return 0; +}