mirror of
https://github.com/djhackersdev/bemanitools.git
synced 2026-08-28 19:34:02 -05:00
vigem-iidxio: Major refactoring incorporating features from Grim's branch
- 3 turntable modes: analog (raw), relative and button mapped - re-structure main to make it easier to maintain and less repetitive code
This commit is contained in:
@@ -20,12 +20,16 @@
|
||||
|
||||
#include "vigemstub/helper.h"
|
||||
|
||||
#define ANALOG_FIXED_SENSITIVITY 256
|
||||
#define JOYSTICKS_NUM 3
|
||||
#define TURNTABLE_NUM 2
|
||||
|
||||
static const uint8_t JOYSTICKS_NUM = 3;
|
||||
static uint8_t _tt_last_raw[TURNTABLE_NUM];
|
||||
static int32_t _tt_state_for_analog[TURNTABLE_NUM];
|
||||
static int16_t _tt_state_for_btn[TURNTABLE_NUM];
|
||||
|
||||
static int16_t _convert_analog_to_s16(uint8_t val)
|
||||
{
|
||||
// TT analog value is 8 bit, upscale to 16 bit
|
||||
return (int64_t) val * 256;
|
||||
}
|
||||
|
||||
@@ -88,6 +92,176 @@ static uint16_t _check_assign_key(uint16_t input, size_t idx_in, size_t bit_out)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t _handle_turntable_analog(
|
||||
const struct vigem_iidxio_config* config,
|
||||
uint8_t tt_cur,
|
||||
uint8_t tt_last,
|
||||
int32_t tt_state,
|
||||
XUSB_REPORT *pad_state)
|
||||
{
|
||||
int32_t state = tt_state;
|
||||
|
||||
if (config->tt.analog.relative) {
|
||||
state = _convert_relative_analog(
|
||||
tt_cur, tt_last, state, config->tt.analog.relative_sensitivity);
|
||||
|
||||
pad_state->sThumbLX = _filter_floor(state, config->tt.analog.relative_sensitivity / 2);
|
||||
} else {
|
||||
pad_state->sThumbLX = _convert_analog_to_s16(tt_cur);
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
static int16_t _handle_turntable_as_button(
|
||||
const struct vigem_iidxio_config* config,
|
||||
uint8_t tt_cur,
|
||||
uint8_t tt_last,
|
||||
int16_t tt_state,
|
||||
XUSB_REPORT *pad_state)
|
||||
{
|
||||
const uint8_t btn_inc = config->tt.button.debounce;
|
||||
const uint16_t btn_threshhold = btn_inc * config->tt.button.threshold;
|
||||
const uint16_t btn_max = btn_threshhold * 2;
|
||||
|
||||
int8_t delta = tt_cur - tt_last;
|
||||
int16_t state = tt_state;
|
||||
|
||||
if (config->tt.debug_output) {
|
||||
printf("delta_button %d, ", delta);
|
||||
}
|
||||
|
||||
// Update state according to delta, debounce and max values
|
||||
if (delta > 0 && state < btn_max) {
|
||||
state += btn_inc;
|
||||
} else if (delta < 0 && abs(state) < btn_max) {
|
||||
state -= btn_inc;
|
||||
}
|
||||
|
||||
// With each update, automatically counter the player's TT movement to turn the state
|
||||
// back to 0, e.g. player moves TT -> state += 20. with no additional movement, neutral state
|
||||
// (0) is back in 20 ticks
|
||||
if (state > 0) {
|
||||
state--;
|
||||
} else if (state < 0) {
|
||||
state++;
|
||||
}
|
||||
|
||||
if (state > btn_threshhold) {
|
||||
pad_state->wButtons |= XUSB_GAMEPAD_LEFT_THUMB;
|
||||
} else if (state < (int16_t) btn_threshhold * -1) {
|
||||
pad_state->wButtons |= XUSB_GAMEPAD_RIGHT_THUMB;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
static void _handle_turntable(
|
||||
const struct vigem_iidxio_config* config,
|
||||
uint8_t* tt,
|
||||
XUSB_REPORT *state)
|
||||
{
|
||||
for (uint8_t i = 0; i < TURNTABLE_NUM; i++) {
|
||||
if (config->tt.debug_output) {
|
||||
printf("TT (%d): last_raw %d, raw %d, ", i, _tt_last_raw[i], tt[i]);
|
||||
}
|
||||
|
||||
_tt_state_for_btn[i] = _handle_turntable_as_button(
|
||||
config, tt[i], _tt_last_raw[i], _tt_state_for_btn[i], &state[i]);
|
||||
|
||||
_tt_state_for_analog[i] = _handle_turntable_analog(
|
||||
config, tt[i], _tt_last_raw[i], _tt_state_for_analog[i], &state[i]);
|
||||
|
||||
_tt_last_raw[i] = tt[i];
|
||||
|
||||
if (config->tt.debug_output) {
|
||||
printf("state_btn %d, state_rel_analog %d\n",
|
||||
_tt_state_for_btn[i], _tt_state_for_analog[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void _handle_buttons_14keys(uint16_t keys, XUSB_REPORT *state)
|
||||
{
|
||||
state[0].wButtons |= _check_assign_key(
|
||||
keys, IIDX_IO_KEY_P1_1, XUSB_GAMEPAD_A);
|
||||
state[0].wButtons |= _check_assign_key(
|
||||
keys, IIDX_IO_KEY_P1_2, XUSB_GAMEPAD_B);
|
||||
state[0].wButtons |= _check_assign_key(
|
||||
keys, IIDX_IO_KEY_P1_3, XUSB_GAMEPAD_X);
|
||||
state[0].wButtons |= _check_assign_key(
|
||||
keys, IIDX_IO_KEY_P1_4, XUSB_GAMEPAD_Y);
|
||||
state[0].wButtons |= _check_assign_key(
|
||||
keys, IIDX_IO_KEY_P1_5, XUSB_GAMEPAD_LEFT_SHOULDER);
|
||||
state[0].wButtons |= _check_assign_key(
|
||||
keys, IIDX_IO_KEY_P1_6, XUSB_GAMEPAD_RIGHT_SHOULDER);
|
||||
state[0].wButtons |= _check_assign_key(
|
||||
keys, IIDX_IO_KEY_P1_7, XUSB_GAMEPAD_BACK);
|
||||
|
||||
state[1].wButtons |= _check_assign_key(
|
||||
keys, IIDX_IO_KEY_P2_1, XUSB_GAMEPAD_A);
|
||||
state[1].wButtons |= _check_assign_key(
|
||||
keys, IIDX_IO_KEY_P2_2, XUSB_GAMEPAD_B);
|
||||
state[1].wButtons |= _check_assign_key(
|
||||
keys, IIDX_IO_KEY_P2_3, XUSB_GAMEPAD_X);
|
||||
state[1].wButtons |= _check_assign_key(
|
||||
keys, IIDX_IO_KEY_P2_4, XUSB_GAMEPAD_Y);
|
||||
state[1].wButtons |= _check_assign_key(
|
||||
keys, IIDX_IO_KEY_P2_5, XUSB_GAMEPAD_LEFT_SHOULDER);
|
||||
state[1].wButtons |= _check_assign_key(
|
||||
keys, IIDX_IO_KEY_P2_6, XUSB_GAMEPAD_RIGHT_SHOULDER);
|
||||
state[1].wButtons |= _check_assign_key(
|
||||
keys, IIDX_IO_KEY_P2_7, XUSB_GAMEPAD_BACK);
|
||||
}
|
||||
|
||||
static void _handle_buttons_panel(uint8_t panel, XUSB_REPORT *state)
|
||||
{
|
||||
state[0].wButtons |= _check_assign_key(
|
||||
panel, IIDX_IO_PANEL_LIGHT_P1_START, XUSB_GAMEPAD_START);
|
||||
state[1].wButtons |= _check_assign_key(
|
||||
panel, IIDX_IO_PANEL_LIGHT_P2_START, XUSB_GAMEPAD_START);
|
||||
|
||||
state[2].wButtons |= _check_assign_key(
|
||||
panel, IIDX_IO_PANEL_LIGHT_VEFX, XUSB_GAMEPAD_B);
|
||||
state[2].wButtons |= _check_assign_key(
|
||||
panel, IIDX_IO_PANEL_LIGHT_EFFECT, XUSB_GAMEPAD_A);
|
||||
}
|
||||
|
||||
static void _handle_buttons_system(uint8_t system, XUSB_REPORT *state)
|
||||
{
|
||||
state[2].wButtons |= _check_assign_key(
|
||||
system, IIDX_IO_SYS_TEST, XUSB_GAMEPAD_X);
|
||||
state[2].wButtons |= _check_assign_key(
|
||||
system, IIDX_IO_SYS_SERVICE, XUSB_GAMEPAD_Y);
|
||||
state[2].wButtons |= _check_assign_key(
|
||||
system, IIDX_IO_SYS_COIN, XUSB_GAMEPAD_START);
|
||||
}
|
||||
|
||||
static void _all_lights_off()
|
||||
{
|
||||
iidx_io_ep1_set_deck_lights(0);
|
||||
iidx_io_ep1_set_panel_lights(0);
|
||||
iidx_io_ep1_set_top_lamps(0);
|
||||
iidx_io_ep1_set_top_neons(false);
|
||||
}
|
||||
|
||||
static void _all_lights_off_shutdown()
|
||||
{
|
||||
// Cleanup, turn all lights off
|
||||
_all_lights_off();
|
||||
|
||||
// Depending on the IO, pushing the state to the actual outputs, e.g. lights on/off
|
||||
// can be a bit finicky. Do a few times to "enforce" the state
|
||||
for (uint8_t i = 0; i < 3; i++) {
|
||||
iidx_io_ep1_send();
|
||||
// Required to handle iidxio-ezusb specific quirks with flushing 16seg text
|
||||
iidx_io_ep2_recv();
|
||||
iidx_io_ep3_write_16seg(" ");
|
||||
|
||||
Sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
log_to_writer(log_writer_stdout, NULL);
|
||||
@@ -141,122 +315,62 @@ int main(int argc, char **argv)
|
||||
|
||||
log_info("vigem init succeeded, beginning poll loop");
|
||||
|
||||
// Initial output state, turn all lights off
|
||||
iidx_io_ep1_set_deck_lights(0);
|
||||
iidx_io_ep1_set_panel_lights(0);
|
||||
iidx_io_ep1_set_top_lamps(0);
|
||||
iidx_io_ep1_set_top_neons(false);
|
||||
// Create clean output state
|
||||
_all_lights_off();
|
||||
|
||||
vigem_iidxio_cab_light_sequencer_init(config.cab_light_mode);
|
||||
vigem_iidxio_cab_light_sequencer_init(config.cab_light.light_mode);
|
||||
|
||||
if (config.text_16seg[0] != '\0') {
|
||||
vigem_iidxio_cab_16seg_sequencer_init(config.text_16seg, config.text_scroll_cycle_time_ms);
|
||||
if (config.cab_light.text_16seg[0] != '\0') {
|
||||
vigem_iidxio_cab_16seg_sequencer_init(
|
||||
config.cab_light.text_16seg, config.cab_light.text_scroll_cycle_time_ms);
|
||||
}
|
||||
|
||||
uint8_t turntable_buffered[2] = {0, 0};
|
||||
uint8_t turntable_last[2] = {0, 0};
|
||||
|
||||
while (loop) {
|
||||
for (uint8_t i = 0; i < JOYSTICKS_NUM; i++) {
|
||||
memset(&state[i], 0, sizeof(state[i]));
|
||||
}
|
||||
|
||||
if (!iidx_io_ep2_recv()) {
|
||||
log_warning("iidxio receiving failed");
|
||||
break;
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < JOYSTICKS_NUM; i++) {
|
||||
memset(&state[i], 0, sizeof(state[i]));
|
||||
}
|
||||
|
||||
// 14 keys
|
||||
// Keys/buttons
|
||||
|
||||
uint16_t keys = iidx_io_ep2_get_keys();
|
||||
|
||||
state[0].wButtons |= _check_assign_key(
|
||||
keys, IIDX_IO_KEY_P1_1, XUSB_GAMEPAD_A);
|
||||
state[0].wButtons |= _check_assign_key(
|
||||
keys, IIDX_IO_KEY_P1_2, XUSB_GAMEPAD_B);
|
||||
state[0].wButtons |= _check_assign_key(
|
||||
keys, IIDX_IO_KEY_P1_3, XUSB_GAMEPAD_X);
|
||||
state[0].wButtons |= _check_assign_key(
|
||||
keys, IIDX_IO_KEY_P1_4, XUSB_GAMEPAD_Y);
|
||||
state[0].wButtons |= _check_assign_key(
|
||||
keys, IIDX_IO_KEY_P1_5, XUSB_GAMEPAD_LEFT_SHOULDER);
|
||||
state[0].wButtons |= _check_assign_key(
|
||||
keys, IIDX_IO_KEY_P1_6, XUSB_GAMEPAD_RIGHT_SHOULDER);
|
||||
state[0].wButtons |= _check_assign_key(
|
||||
keys, IIDX_IO_KEY_P1_7, XUSB_GAMEPAD_BACK);
|
||||
|
||||
state[1].wButtons |= _check_assign_key(
|
||||
keys, IIDX_IO_KEY_P2_1, XUSB_GAMEPAD_A);
|
||||
state[1].wButtons |= _check_assign_key(
|
||||
keys, IIDX_IO_KEY_P2_2, XUSB_GAMEPAD_B);
|
||||
state[1].wButtons |= _check_assign_key(
|
||||
keys, IIDX_IO_KEY_P2_3, XUSB_GAMEPAD_X);
|
||||
state[1].wButtons |= _check_assign_key(
|
||||
keys, IIDX_IO_KEY_P2_4, XUSB_GAMEPAD_Y);
|
||||
state[1].wButtons |= _check_assign_key(
|
||||
keys, IIDX_IO_KEY_P2_5, XUSB_GAMEPAD_LEFT_SHOULDER);
|
||||
state[1].wButtons |= _check_assign_key(
|
||||
keys, IIDX_IO_KEY_P2_6, XUSB_GAMEPAD_RIGHT_SHOULDER);
|
||||
state[1].wButtons |= _check_assign_key(
|
||||
keys, IIDX_IO_KEY_P2_7, XUSB_GAMEPAD_BACK);
|
||||
|
||||
// Panel buttons
|
||||
uint8_t panel = iidx_io_ep2_get_panel();
|
||||
|
||||
state[0].wButtons |= _check_assign_key(
|
||||
panel, IIDX_IO_PANEL_LIGHT_P1_START, XUSB_GAMEPAD_START);
|
||||
state[1].wButtons |= _check_assign_key(
|
||||
panel, IIDX_IO_PANEL_LIGHT_P2_START, XUSB_GAMEPAD_START);
|
||||
|
||||
state[2].wButtons |= _check_assign_key(
|
||||
panel, IIDX_IO_PANEL_LIGHT_VEFX, XUSB_GAMEPAD_B);
|
||||
state[2].wButtons |= _check_assign_key(
|
||||
panel, IIDX_IO_PANEL_LIGHT_EFFECT, XUSB_GAMEPAD_A);
|
||||
|
||||
// System buttons
|
||||
uint8_t system = iidx_io_ep2_get_sys();
|
||||
|
||||
state[2].wButtons |= _check_assign_key(
|
||||
system, IIDX_IO_SYS_TEST, XUSB_GAMEPAD_X);
|
||||
state[2].wButtons |= _check_assign_key(
|
||||
system, IIDX_IO_SYS_SERVICE, XUSB_GAMEPAD_Y);
|
||||
state[2].wButtons |= _check_assign_key(
|
||||
system, IIDX_IO_SYS_COIN, XUSB_GAMEPAD_START);
|
||||
_handle_buttons_14keys(keys, state);
|
||||
_handle_buttons_panel(panel, state);
|
||||
_handle_buttons_system(system, state);
|
||||
|
||||
// Turntable
|
||||
uint8_t turntable[2];
|
||||
|
||||
turntable[0] = iidx_io_ep2_get_turntable(0);
|
||||
turntable[1] = iidx_io_ep2_get_turntable(1);
|
||||
|
||||
if (config.relative_analog) {
|
||||
turntable_buffered[0] = _convert_relative_analog(
|
||||
turntable[0], turntable_last[0], turntable_buffered[0], ANALOG_FIXED_SENSITIVITY);
|
||||
turntable_buffered[1] = _convert_relative_analog(
|
||||
turntable[1], turntable_last[1], turntable_buffered[1], ANALOG_FIXED_SENSITIVITY);
|
||||
uint8_t turntable[TURNTABLE_NUM];
|
||||
|
||||
state[0].sThumbLX = _filter_floor(turntable_buffered[0], ANALOG_FIXED_SENSITIVITY / 2);
|
||||
state[1].sThumbLX = _filter_floor(turntable_buffered[1], ANALOG_FIXED_SENSITIVITY / 2);
|
||||
|
||||
turntable_last[0] = turntable[0];
|
||||
turntable_last[1] = turntable[1];
|
||||
} else {
|
||||
state[0].sThumbLX = _convert_analog_to_s16(turntable[0]);
|
||||
state[1].sThumbLX = _convert_analog_to_s16(turntable[1]);
|
||||
for (uint8_t i = 0; i < TURNTABLE_NUM; i++) {
|
||||
turntable[i] = iidx_io_ep2_get_turntable(i);
|
||||
}
|
||||
|
||||
_handle_turntable(&config, turntable, state);
|
||||
|
||||
vigem_target_x360_update(client, pad[0], state[0]);
|
||||
vigem_target_x360_update(client, pad[1], state[1]);
|
||||
// Pad update
|
||||
|
||||
for (uint8_t i = 0; i < JOYSTICKS_NUM; i++) {
|
||||
vigem_target_x360_update(client, pad[i], state[i]);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Light related outputs
|
||||
|
||||
if (config.enable_keylight) {
|
||||
if (config.cab_light.enable_keylight) {
|
||||
iidx_io_ep1_set_deck_lights(keys);
|
||||
iidx_io_ep1_set_panel_lights(panel);
|
||||
}
|
||||
|
||||
if (config.cab_light_mode != LIGHT_SEQ_MODE_OFF) {
|
||||
if (config.cab_light.light_mode != LIGHT_SEQ_MODE_OFF) {
|
||||
bool neon;
|
||||
uint8_t spots;
|
||||
|
||||
@@ -274,10 +388,12 @@ int main(int argc, char **argv)
|
||||
iidx_io_ep1_set_top_lamps(spots);
|
||||
}
|
||||
|
||||
char buffer_16seg[9];
|
||||
if (config.cab_light.text_16seg[0] != '\0') {
|
||||
char buffer_16seg[9];
|
||||
|
||||
vigem_iidxio_cab_16seg_sequencer_update(buffer_16seg);
|
||||
iidx_io_ep3_write_16seg(buffer_16seg);
|
||||
vigem_iidxio_cab_16seg_sequencer_update(buffer_16seg);
|
||||
iidx_io_ep3_write_16seg(buffer_16seg);
|
||||
}
|
||||
|
||||
if (!iidx_io_ep1_send()) {
|
||||
log_warning("iidxio sending failed");
|
||||
@@ -290,22 +406,11 @@ int main(int argc, char **argv)
|
||||
loop = false;
|
||||
}
|
||||
|
||||
// avoid banging
|
||||
// Avoid CPU banging
|
||||
Sleep(1);
|
||||
}
|
||||
|
||||
// Cleanup, turn all lights off
|
||||
iidx_io_ep1_set_deck_lights(0);
|
||||
iidx_io_ep1_set_panel_lights(0);
|
||||
iidx_io_ep1_set_top_lamps(0);
|
||||
iidx_io_ep1_set_top_neons(false);
|
||||
|
||||
iidx_io_ep1_send();
|
||||
// Required to handle iidxio-ezusb specific quirks with flushing 16seg text
|
||||
iidx_io_ep2_recv();
|
||||
iidx_io_ep3_write_16seg(" ");
|
||||
|
||||
Sleep(10);
|
||||
_all_lights_off_shutdown();
|
||||
|
||||
for (uint8_t i = 0; i < JOYSTICKS_NUM; i++) {
|
||||
vigem_target_remove(client, pad[i]);
|
||||
|
||||
Reference in New Issue
Block a user