Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GunCon 3 device emulation #15528

Merged
merged 4 commits into from
May 1, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions rpcs3/Emu/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ target_sources(rpcs3_emu PRIVATE
Io/camera_config.cpp
Io/GameTablet.cpp
Io/GHLtar.cpp
Io/GunCon3.cpp
Io/Infinity.cpp
Io/interception.cpp
Io/KeyboardHandler.cpp
Expand Down
24 changes: 18 additions & 6 deletions rpcs3/Emu/Cell/lv2/sys_usbd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "Emu/Io/Buzz.h"
#include "Emu/Io/buzz_config.h"
#include "Emu/Io/GameTablet.h"
#include "Emu/Io/GunCon3.h"
#include "Emu/Io/Turntable.h"
#include "Emu/Io/turntable_config.h"
#include "Emu/Io/RB3MidiKeyboard.h"
Expand Down Expand Up @@ -317,9 +318,9 @@ usb_handler_thread::usb_handler_thread()
}

// Top Shot Elite controllers
check_device(0x12BA, 0x04A0, 0x04A0, "RO Gun Controller");
check_device(0x12BA, 0x04A1, 0x04A1, "RO Gun Controller 2012");
check_device(0x12BA, 0x04B0, 0x04B0, "RO Fishing Rod");
check_device(0x12BA, 0x04A0, 0x04A0, "Top Shot Elite");
check_device(0x12BA, 0x04A1, 0x04A1, "Top Shot Fearmaster");
check_device(0x12BA, 0x04B0, 0x04B0, "Rapala Fishing Rod");

// GT5 Wheels&co
check_device(0x046D, 0xC283, 0xC29B, "lgFF_c283_c29b");
Expand All @@ -339,14 +340,14 @@ usb_handler_thread::usb_handler_thread()
check_device(0x054C, 0x0042, 0x0042, "buzzer2");
check_device(0x046D, 0xC220, 0xC220, "buzzer9");

// GCon3 Gun
check_device(0x0B9A, 0x0800, 0x0800, "guncon3");
// GunCon3 Gun
check_device(0x0B9A, 0x0800, 0x0800, "GunCon3");

// uDraw GameTablet
check_device(0x20D6, 0xCB17, 0xCB17, "uDraw GameTablet");

// DVB-T
check_device(0x1415, 0x0003, 0x0003, " PlayTV SCEH-0036");
check_device(0x1415, 0x0003, 0x0003, "PlayTV SCEH-0036");

// 0x0900: "H050 USJ(C) PCB rev00", 0x0910: "USIO PCB rev00"
if (check_device(0x0B9A, 0x0900, 0x0910, "PS3A-USJ"))
Expand Down Expand Up @@ -485,6 +486,17 @@ usb_handler_thread::usb_handler_thread()
sys_usbd.notice("Adding emulated uDraw GameTablet");
usb_devices.push_back(std::make_shared<usb_device_gametablet>(get_new_location()));
}

if (g_cfg.io.guncon3 != guncon3_handler::disabled)
{
sys_usbd.notice("Adding emulated GunCon3 (controller 1)");
usb_devices.push_back(std::make_shared<usb_device_guncon3>(0, get_new_location()));
}
if (g_cfg.io.guncon3 == guncon3_handler::two_controllers)
{
sys_usbd.notice("Adding emulated GunCon3 (controller 2)");
usb_devices.push_back(std::make_shared<usb_device_guncon3>(1, get_new_location()));
}
}

usb_handler_thread::~usb_handler_thread()
Expand Down
137 changes: 91 additions & 46 deletions rpcs3/Emu/Io/GameTablet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,60 @@

LOG_CHANNEL(gametablet_log);

#pragma pack(push, 1)
struct GameTablet_data
{
uint8_t btn_square : 1;
uint8_t btn_cross : 1;
uint8_t btn_circle : 1;
uint8_t btn_triangle : 1;
uint8_t : 4;

uint8_t btn_select : 1;
uint8_t btn_start : 1;
uint8_t : 2;
uint8_t btn_ps: 1;
uint8_t : 3;

uint8_t dpad;
uint8_t stick_lx; // 0x80
uint8_t stick_ly; // 0x80
uint8_t stick_rx; // 0x80
uint8_t stick_ry; // 0x80

uint8_t : 8;
uint8_t : 8;
uint8_t : 8;
uint8_t : 8;
uint8_t pen;
uint8_t : 8;
uint8_t pressure;
uint8_t : 8;
uint8_t pos_x_hi;
uint8_t pos_y_hi;
uint8_t pos_x_lo;
uint8_t pos_y_lo;

uint16_t accel_x;
uint16_t accel_y;
uint16_t accel_z;
uint16_t unk; // 0x0200
};
#pragma pack(pop)

enum
{
Dpad_North,
Dpad_NE,
Dpad_East,
Dpad_SE,
Dpad_South,
Dpad_SW,
Dpad_West,
Dpad_NW,
Dpad_None = 0x0f
};

usb_device_gametablet::usb_device_gametablet(const std::array<u8, 7>& location)
: usb_device_emulated(location)
{
Expand Down Expand Up @@ -114,38 +168,25 @@ void usb_device_gametablet::interrupt_transfer(u32 buf_size, u8* buf, u32 /*endp
// Interrupt transfers are slow (6ms, TODO accurate measurement)
transfer->expected_time = get_timestamp() + 6000;

std::memset(buf, 0, buf_size);

buf[0x02] = 0x0f; // dpad

buf[0x03] = 0x80;
buf[0x04] = 0x80;
buf[0x05] = 0x80;
buf[0x06] = 0x80;
GameTablet_data gt{};

buf[0x0d] = 0x72; // pressure
buf[0x0f] = 0x0f; // pos X
buf[0x10] = 0x0f; // pos Y
buf[0x11] = 0xff;
buf[0x12] = 0xff;

buf[0x13] = 0x01; // accel X
buf[0x14] = 0x02;
buf[0x15] = 0x00; // accel Y
buf[0x16] = 0x02;
buf[0x17] = 0xea; // accel Z
buf[0x18] = 0x01;

buf[0x1a] = 0x02;
gt.dpad = Dpad_None;
gt.stick_lx = gt.stick_ly = gt.stick_rx = gt.stick_ry = 0x80;
gt.pressure = 0x72;
gt.pos_x_hi = gt.pos_y_hi = 0x0f;
gt.pos_x_lo = gt.pos_y_lo = 0xff;
gt.accel_x = gt.accel_y = gt.accel_z = gt.unk = 0x0200;

if (!is_input_allowed())
{
std::memcpy(buf, &gt, sizeof(GameTablet_data));
Florin9doi marked this conversation as resolved.
Show resolved Hide resolved
return;
}

if (g_cfg.io.mouse != mouse_handler::basic)
if (g_cfg.io.mouse == mouse_handler::null)
{
gametablet_log.warning("GameTablet requires mouse_handler configured to basic");
gametablet_log.warning("GameTablet requires a Mouse Handler enabled");
std::memcpy(buf, &gt, sizeof(GameTablet_data));
return;
}

Expand All @@ -172,10 +213,10 @@ void usb_device_gametablet::interrupt_transfer(u32 buf_size, u8* buf, u32 /*endp
switch (button.m_outKeyCode)
{
case CELL_PAD_CTRL_SELECT:
buf[1] |= (1 << 0);
gt.btn_select |= 1;
break;
case CELL_PAD_CTRL_START:
buf[1] |= (1 << 1);
gt.btn_start |= 1;
break;
case CELL_PAD_CTRL_UP:
up = true;
Expand All @@ -198,19 +239,19 @@ void usb_device_gametablet::interrupt_transfer(u32 buf_size, u8* buf, u32 /*endp
switch (button.m_outKeyCode)
{
case CELL_PAD_CTRL_SQUARE:
buf[0] |= (1 << 0);
gt.btn_square |= 1;
break;
case CELL_PAD_CTRL_CROSS:
buf[0] |= (1 << 1);
gt.btn_cross |= 1;
break;
case CELL_PAD_CTRL_CIRCLE:
buf[0] |= (1 << 2);
gt.btn_circle |= 1;
break;
case CELL_PAD_CTRL_TRIANGLE:
buf[0] |= (1 << 3);
gt.btn_triangle |= 1;
break;
case CELL_PAD_CTRL_PS:
buf[1] |= (1 << 4);
gt.btn_ps |= 1;
break;
default:
break;
Expand All @@ -221,23 +262,23 @@ void usb_device_gametablet::interrupt_transfer(u32 buf_size, u8* buf, u32 /*endp
}

if (!up && !right && !down && !left)
buf[0x02] = 0x0f;
gt.dpad = Dpad_None;
else if (up && !left && !right)
buf[0x02] = 0x00;
gt.dpad = Dpad_North;
else if (up && right)
buf[0x02] = 0x01;
gt.dpad = Dpad_NE;
else if (right && !up && !down)
buf[0x02] = 0x02;
gt.dpad = Dpad_East;
else if (down && right)
buf[0x02] = 0x03;
gt.dpad = Dpad_SE;
else if (down && !left && !right)
buf[0x02] = 0x04;
gt.dpad = Dpad_South;
else if (down && left)
buf[0x02] = 0x05;
gt.dpad = Dpad_SW;
else if (left && !up && !down)
buf[0x02] = 0x06;
gt.dpad = Dpad_West;
else if (up && left)
buf[0x02] = 0x07;
gt.dpad = Dpad_NW;

auto& mouse_handler = g_fxo->get<MouseHandlerBase>();
std::lock_guard mouse_lock(mouse_handler.mutex);
Expand All @@ -247,12 +288,14 @@ void usb_device_gametablet::interrupt_transfer(u32 buf_size, u8* buf, u32 /*endp
constexpr u8 mouse_index = 0;
if (mouse_index >= mouse_handler.GetMice().size())
{
std::memcpy(buf, &gt, sizeof(GameTablet_data));
return;
}

const Mouse& mouse_data = ::at32(mouse_handler.GetMice(), mouse_index);
if (mouse_data.x_max <= 0 || mouse_data.y_max <= 0)
{
std::memcpy(buf, &gt, sizeof(GameTablet_data));
return;
}

Expand All @@ -266,10 +309,12 @@ void usb_device_gametablet::interrupt_transfer(u32 buf_size, u8* buf, u32 /*endp
noise_x ^= 0x1;
noise_y ^= 0x1;

buf[0x0b] = 0x40; // pen
buf[0x0d] = mouse_data.buttons & CELL_MOUSE_BUTTON_1 ? 0xbb : 0x72; // pressure
buf[0x0f] = static_cast<u8>(tablet_x_pos / 0x100);
buf[0x10] = static_cast<u8>(tablet_y_pos / 0x100);
buf[0x11] = static_cast<u8>(tablet_x_pos % 0x100);
buf[0x12] = static_cast<u8>(tablet_y_pos % 0x100);
gt.pen = 0x40;
gt.pressure = mouse_data.buttons & CELL_MOUSE_BUTTON_1 ? 0xbb : 0x72;
gt.pos_x_hi = static_cast<u8>(tablet_x_pos / 0x100);
gt.pos_y_hi = static_cast<u8>(tablet_y_pos / 0x100);
gt.pos_x_lo = static_cast<u8>(tablet_x_pos % 0x100);
gt.pos_y_lo = static_cast<u8>(tablet_y_pos % 0x100);

std::memcpy(buf, &gt, sizeof(GameTablet_data));
}