From 5a6ecd790b496b83c5ec6e187058a167e5ab2080 Mon Sep 17 00:00:00 2001 From: Sorgelig Date: Thu, 21 Apr 2022 04:22:39 +0800 Subject: [PATCH] input: initial support for wheels. --- MiSTer.ini | 7 ++ cfg.cpp | 3 + cfg.h | 2 + input.cpp | 204 +++++++++++++++++++++++++++++++++++++++++++++-------- 4 files changed, 186 insertions(+), 30 deletions(-) diff --git a/MiSTer.ini b/MiSTer.ini index e55cc5e..4ca8d25 100644 --- a/MiSTer.ini +++ b/MiSTer.ini @@ -206,3 +206,10 @@ bt_reset_before_pair=0 ; ... ; [video=640x400@70.1] ; ... + +; Wheel centering force. Default is 50. +;wheel_force=50 + +; Wheel steeling angle range. Supported ranges depends on specific wheel model +; If not set then default (depending on driver) range is used +;wheel_range=200 diff --git a/cfg.cpp b/cfg.cpp index 46a3fdb..be62b2b 100644 --- a/cfg.cpp +++ b/cfg.cpp @@ -93,6 +93,8 @@ static const ini_var_t ini_vars[] = { "BT_RESET_BEFORE_PAIR", (void*)(&(cfg.bt_reset_before_pair)), UINT8, 0, 1 }, { "WAITMOUNT", (void*)(&(cfg.waitmount)), STRING, 0, sizeof(cfg.waitmount) - 1 }, { "RUMBLE", (void *)(&(cfg.rumble)), UINT8, 0, 1}, + { "WHEEL_FORCE", (void*)(&(cfg.wheel_force)), UINT8, 0, 100 }, + { "WHEEL_RANGE", (void*)(&(cfg.wheel_range)), UINT16, 0, 1000 }, }; static const int nvars = (int)(sizeof(ini_vars) / sizeof(ini_var_t)); @@ -371,6 +373,7 @@ void cfg_parse() cfg.browse_expand = 1; cfg.logo = 1; cfg.rumble = 1; + cfg.wheel_force = 50; has_video_sections = false; using_video_section = false; ini_parse(altcfg(), video_get_core_mode_name(1)); diff --git a/cfg.h b/cfg.h index 16ca733..7fb1a0f 100644 --- a/cfg.h +++ b/cfg.h @@ -70,6 +70,8 @@ typedef struct { char vfilter_scanlines_default[1023]; char shmask_default[1023]; uint8_t rumble; + uint8_t wheel_force; + uint16_t wheel_range; } cfg_t; extern cfg_t cfg; diff --git a/input.cpp b/input.cpp index 00836cc..a952b70 100644 --- a/input.cpp +++ b/input.cpp @@ -1119,7 +1119,8 @@ enum QUIRK QUIRK_VCS, QUIRK_JOYCON, QUIRK_LIGHTGUN_CRT, - QUIRK_LIGHTGUN + QUIRK_LIGHTGUN, + QUIRK_WHEEL, }; typedef struct @@ -1172,6 +1173,12 @@ typedef struct uint16_t last_rumble; ff_effect rumble_effect; + int8_t wh_steer; + int8_t wh_accel; + int8_t wh_break; + int8_t wh_clutch; + int8_t wh_combo; + int timeout; char mac[64]; @@ -2280,25 +2287,39 @@ static void input_cb(struct input_event *ev, struct input_absinfo *absinfo, int } if (!input[dev].mmap[SYS_BTN_OSD_KTGL + 2]) input[dev].mmap[SYS_BTN_OSD_KTGL + 2] = input[dev].mmap[SYS_BTN_OSD_KTGL + 1]; - if (input[dev].mmap[SYS_AXIS_X] == input[dev].mmap[SYS_AXIS1_X]) + if (input[dev].quirk == QUIRK_WHEEL) { - input[dev].stick_l[0] = SYS_AXIS1_X; - if((input[dev].mmap[SYS_AXIS2_X] >> 16) == 2) input[dev].stick_r[0] = SYS_AXIS2_X; + input[dev].mmap[SYS_AXIS_MX] = -1; + input[dev].mmap[SYS_AXIS_MY] = -1; + input[dev].mmap[SYS_AXIS_X] = -1; + input[dev].mmap[SYS_AXIS_Y] = -1; + input[dev].mmap[SYS_AXIS1_X] = -1; + input[dev].mmap[SYS_AXIS1_Y] = -1; + input[dev].mmap[SYS_AXIS2_X] = -1; + input[dev].mmap[SYS_AXIS2_Y] = -1; } - if (input[dev].mmap[SYS_AXIS_Y] == input[dev].mmap[SYS_AXIS1_Y]) + else { - input[dev].stick_l[1] = SYS_AXIS1_Y; - if ((input[dev].mmap[SYS_AXIS2_Y] >> 16) == 2) input[dev].stick_r[1] = SYS_AXIS2_Y; - } - if (input[dev].mmap[SYS_AXIS_X] == input[dev].mmap[SYS_AXIS2_X]) - { - input[dev].stick_l[0] = SYS_AXIS2_X; - if ((input[dev].mmap[SYS_AXIS1_X] >> 16) == 2) input[dev].stick_r[0] = SYS_AXIS1_X; - } - if (input[dev].mmap[SYS_AXIS_Y] == input[dev].mmap[SYS_AXIS2_Y]) - { - input[dev].stick_l[1] = SYS_AXIS2_Y; - if ((input[dev].mmap[SYS_AXIS1_Y] >> 16) == 2) input[dev].stick_r[1] = SYS_AXIS1_Y; + if (input[dev].mmap[SYS_AXIS_X] == input[dev].mmap[SYS_AXIS1_X]) + { + input[dev].stick_l[0] = SYS_AXIS1_X; + if ((input[dev].mmap[SYS_AXIS2_X] >> 16) == 2) input[dev].stick_r[0] = SYS_AXIS2_X; + } + if (input[dev].mmap[SYS_AXIS_Y] == input[dev].mmap[SYS_AXIS1_Y]) + { + input[dev].stick_l[1] = SYS_AXIS1_Y; + if ((input[dev].mmap[SYS_AXIS2_Y] >> 16) == 2) input[dev].stick_r[1] = SYS_AXIS2_Y; + } + if (input[dev].mmap[SYS_AXIS_X] == input[dev].mmap[SYS_AXIS2_X]) + { + input[dev].stick_l[0] = SYS_AXIS2_X; + if ((input[dev].mmap[SYS_AXIS1_X] >> 16) == 2) input[dev].stick_r[0] = SYS_AXIS1_X; + } + if (input[dev].mmap[SYS_AXIS_Y] == input[dev].mmap[SYS_AXIS2_Y]) + { + input[dev].stick_l[1] = SYS_AXIS2_Y; + if ((input[dev].mmap[SYS_AXIS1_Y] >> 16) == 2) input[dev].stick_r[1] = SYS_AXIS1_Y; + } } } input[dev].has_mmap++; @@ -2827,18 +2848,21 @@ static void input_cb(struct input_event *ev, struct input_absinfo *absinfo, int } } - if (input[dev].mmap[SYS_AXIS_X]) + if (input[dev].quirk != QUIRK_WHEEL) { - uint16_t key = KEY_EMU + ((uint16_t)input[dev].mmap[SYS_AXIS_X]*2); - if (ev->code == (key + 1)) joy_digital(0, 1 << 0, 0, ev->value, 0); - if (ev->code == key) joy_digital(0, 1 << 1, 0, ev->value, 1); - } + if (input[dev].mmap[SYS_AXIS_X]) + { + uint16_t key = KEY_EMU + ((uint16_t)input[dev].mmap[SYS_AXIS_X] * 2); + if (ev->code == (key + 1)) joy_digital(0, 1 << 0, 0, ev->value, 0); + if (ev->code == key) joy_digital(0, 1 << 1, 0, ev->value, 1); + } - if (input[dev].mmap[SYS_AXIS_Y]) - { - uint16_t key = KEY_EMU + ((uint16_t)input[dev].mmap[SYS_AXIS_Y]*2); - if (ev->code == (key + 1)) joy_digital(0, 1 << 2, 0, ev->value, 2); - if (ev->code == key) joy_digital(0, 1 << 3, 0, ev->value, 3); + if (input[dev].mmap[SYS_AXIS_Y]) + { + uint16_t key = KEY_EMU + ((uint16_t)input[dev].mmap[SYS_AXIS_Y] * 2); + if (ev->code == (key + 1)) joy_digital(0, 1 << 2, 0, ev->value, 2); + if (ev->code == key) joy_digital(0, 1 << 3, 0, ev->value, 3); + } } } } @@ -3065,7 +3089,7 @@ static void input_cb(struct input_event *ev, struct input_absinfo *absinfo, int // normalize to -range/2...+range/2 value = value - (absinfo->minimum + absinfo->maximum) / 2; - if (ev->code > 1 || !input[dev].lightgun) //lightgun has no dead zone + if (ev->code > 1 || (!input[dev].lightgun && input[dev].quirk != QUIRK_WHEEL)) //lightgun/wheel has no dead zone { // check the dead-zone and remove it from the range hrange -= dead; @@ -3103,7 +3127,38 @@ static void input_cb(struct input_event *ev, struct input_absinfo *absinfo, int // skip if joystick is undefined. if (!input[dev].num) break; - if (ev->code == 0 && input[dev].lightgun) + if (input[dev].quirk == QUIRK_WHEEL) + { + int wh_value = ((127 * (ev->value - absinfo->minimum)) / (absinfo->maximum - absinfo->minimum)) - 127; + + if (ev->code == input[dev].wh_steer) + { + joy_analog(input[dev].num, 0, value, 0); + } + else if (ev->code == input[dev].wh_accel) + { + joy_analog(input[dev].num, 1, wh_value, 0); + } + else if (ev->code == input[dev].wh_break) + { + joy_analog(input[dev].num, 1, wh_value, 1); + } + else if (ev->code == input[dev].wh_clutch) + { + joy_analog(input[dev].num, 0, wh_value, 1); + } + else if (ev->code == input[dev].wh_combo) + { + if (value < -1) joy_analog(input[dev].num, 1, value, 0); + else if (value > 1) joy_analog(input[dev].num, 1, -value, 1); + else + { + joy_analog(input[dev].num, 1, 0, 0); + joy_analog(input[dev].num, 1, 0, 0); + } + } + } + else if (ev->code == 0 && input[dev].lightgun) { joy_analog(input[dev].num, 0, value); } @@ -3948,6 +4003,75 @@ static void set_rumble(int dev, uint16_t rumble_val) } } +static void setup_wheels() +{ + static char path[1024]; + if (cfg.wheel_force > 100) cfg.wheel_force = 100; + + for (int i = 0; i < NUMDEV; i++) + { + if (pool[i].fd != -1 && input[i].quirk == QUIRK_WHEEL) + { + input[i].wh_steer = -1; + input[i].wh_accel = -1; + input[i].wh_break = -1; + input[i].wh_clutch = -1; + input[i].wh_combo = -1; + + if (input[i].vid == 0x046d) // logitech + { + struct input_event ie; + ie.type = EV_FF; + ie.code = FF_AUTOCENTER; + ie.value = 0xFFFFUL * cfg.wheel_force / 100; + write(pool[i].fd, &ie, sizeof(ie)); + if (cfg.wheel_range && input[i].sysfs[0]) + { + sprintf(path, "/sys%s", input[i].sysfs); + char *p = strstr(path, "/input/"); + if (p) + { + strcpy(p, "/range"); + FILE* f = fopen(path, "w"); + if (f) + { + fprintf(f, "%d", cfg.wheel_range); + fclose(f); + } + } + } + + input[i].wh_steer = 0; + + switch (input[i].pid) + { + case 0xc299: // LOGITECH_G25_WHEEL + case 0xc29b: // LOGITECH_G27_WHEEL + case 0xc24f: // LOGITECH_G29_WHEEL + input[i].wh_accel = 2; + input[i].wh_break = 5; + input[i].wh_clutch = 1; + break; + + case 0xc294: // LOGITECH_WHEEL + input[i].wh_combo = 1; + break; + + case 0xc298: // LOGITECH_DFP_WHEEL + input[i].wh_accel = 1; + input[i].wh_break = 5; + break; + + case 0xc29a: // LOGITECH_DFGT_WHEEL + input[i].wh_accel = 1; + input[i].wh_break = 2; + break; + } + } + } + } +} + int input_test(int getchar) { static char cur_leds = 0; @@ -4059,6 +4183,25 @@ int input_test(int getchar) } } + // Logitech Wheels + if (input[n].vid == 0x046d) + { + switch (input[n].pid) + { + case 0xc24f: // LOGITECH_G29_WHEEL + //case 0xc262: // LOGITECH_G920_WHEEL + case 0xc294: // LOGITECH_WHEEL + //case 0xc295: // LOGITECH_MOMO_WHEEL + case 0xc298: // LOGITECH_DFP_WHEEL + case 0xc299: // LOGITECH_G25_WHEEL + case 0xc29a: // LOGITECH_DFGT_WHEEL + case 0xc29b: // LOGITECH_G27_WHEEL + { + input[n].quirk = QUIRK_WHEEL; + } + } + } + // enable scroll wheel reading if (input[n].mouse) { @@ -4170,7 +4313,7 @@ int input_test(int getchar) { input[n].lightgun = 1; } - + //Namco Guncon via RetroZord adapter if (input[n].vid == 0x2341 && input[n].pid == 0x8036 && (strstr(uniq, "RZordPsGun") || strstr(input[n].name, "RZordPsGun"))) { @@ -4276,6 +4419,7 @@ int input_test(int getchar) mergedevs(); check_joycon(); + setup_wheels(); for (int i = 0; i < n; i++) { printf("opened %d(%2d): %s (%04x:%04x) %d \"%s\" \"%s\"\n", i, input[i].bind, input[i].devname, input[i].vid, input[i].pid, input[i].quirk, input[i].id, input[i].name);