USIO: Support up to 4 players for Tekken Tag Tournament 2 Pair Play mode

This commit is contained in:
brian218 2023-09-06 23:10:30 +08:00 committed by Megamouse
parent 52495c17d6
commit 009d8e13da
3 changed files with 62 additions and 46 deletions

View File

@ -186,7 +186,7 @@ void usb_device_usio::translate_input_taiko()
std::lock_guard lock(pad::g_pad_mutex); std::lock_guard lock(pad::g_pad_mutex);
const auto handler = pad::get_current_handler(); const auto handler = pad::get_current_handler();
std::vector<u8> input_buf(96); std::vector<u8> input_buf(0x60);
constexpr le_t<u16> c_hit = 0x1800; constexpr le_t<u16> c_hit = 0x1800;
le_t<u16> digital_input = 0; le_t<u16> digital_input = 0;
@ -204,6 +204,7 @@ void usb_device_usio::translate_input_taiko()
} }
const usz offset = player * 8ULL; const usz offset = player * 8ULL;
auto& status = m_io_status[0];
const auto& cfg = ::at32(g_cfg_usio.players, pad_number); const auto& cfg = ::at32(g_cfg_usio.players, pad_number);
cfg->handle_input(pad, false, [&](usio_btn btn, u16 /*value*/, bool pressed) cfg->handle_input(pad, false, [&](usio_btn btn, u16 /*value*/, bool pressed)
@ -212,15 +213,15 @@ void usb_device_usio::translate_input_taiko()
{ {
case usio_btn::test: case usio_btn::test:
if (player != 0) break; if (player != 0) break;
if (pressed && !test_key_pressed) // Solve the need to hold the Test key if (pressed && !status.test_key_pressed) // Solve the need to hold the Test key
test_on = !test_on; status.test_on = !status.test_on;
test_key_pressed = pressed; status.test_key_pressed = pressed;
break; break;
case usio_btn::coin: case usio_btn::coin:
if (player != 0) break; if (player != 0) break;
if (pressed && !coin_key_pressed) // Ensure only one coin is inserted each time the Coin key is pressed if (pressed && !status.coin_key_pressed) // Ensure only one coin is inserted each time the Coin key is pressed
coin_counter++; status.coin_counter++;
coin_key_pressed = pressed; status.coin_key_pressed = pressed;
break; break;
case usio_btn::service: case usio_btn::service:
if (player == 0 && pressed) if (player == 0 && pressed)
@ -258,14 +259,16 @@ void usb_device_usio::translate_input_taiko()
break; break;
} }
}); });
if (player == 0 && status.test_on)
digital_input |= 0x80;
}; };
for (usz i = 0; i < g_cfg_usio.players.size(); i++) for (usz i = 0; i < g_cfg_usio.players.size(); i++)
translate_from_pad(i, i); translate_from_pad(i, i);
digital_input |= test_on ? 0x80 : 0x00;
std::memcpy(input_buf.data(), &digital_input, sizeof(u16)); std::memcpy(input_buf.data(), &digital_input, sizeof(u16));
std::memcpy(input_buf.data() + 16, &coin_counter, sizeof(u16)); std::memcpy(input_buf.data() + 16, &m_io_status[0].coin_counter, sizeof(u16));
response = std::move(input_buf); response = std::move(input_buf);
} }
@ -275,8 +278,8 @@ void usb_device_usio::translate_input_tekken()
std::lock_guard lock(pad::g_pad_mutex); std::lock_guard lock(pad::g_pad_mutex);
const auto handler = pad::get_current_handler(); const auto handler = pad::get_current_handler();
std::vector<u8> input_buf(256); std::vector<u8> input_buf(0x180);
le_t<u64> digital_input = 0; le_t<u64> digital_input[2]{};
le_t<u16> digital_input_lm = 0; le_t<u16> digital_input_lm = 0;
auto translate_from_pad = [&](usz pad_number, usz player) auto translate_from_pad = [&](usz pad_number, usz player)
@ -292,7 +295,9 @@ void usb_device_usio::translate_input_tekken()
return; return;
} }
const usz shift = player * 24ULL; const usz shift = (player % 2) * 24ULL;
auto& status = m_io_status[player / 2];
auto& input = digital_input[player / 2];
const auto& cfg = ::at32(g_cfg_usio.players, pad_number); const auto& cfg = ::at32(g_cfg_usio.players, pad_number);
cfg->handle_input(pad, false, [&](usio_btn btn, u16 /*value*/, bool pressed) cfg->handle_input(pad, false, [&](usio_btn btn, u16 /*value*/, bool pressed)
@ -300,27 +305,27 @@ void usb_device_usio::translate_input_tekken()
switch (btn) switch (btn)
{ {
case usio_btn::test: case usio_btn::test:
if (player != 0) if (player % 2 != 0)
break; break;
if (pressed && !test_key_pressed) // Solve the need to hold the Test button if (pressed && !status.test_key_pressed) // Solve the need to hold the Test button
test_on = !test_on; status.test_on = !status.test_on;
test_key_pressed = pressed; status.test_key_pressed = pressed;
break; break;
case usio_btn::coin: case usio_btn::coin:
if (player != 0) if (player % 2 != 0)
break; break;
if (pressed && !coin_key_pressed) // Ensure only one coin is inserted each time the Coin button is pressed if (pressed && !status.coin_key_pressed) // Ensure only one coin is inserted each time the Coin button is pressed
coin_counter++; status.coin_counter++;
coin_key_pressed = pressed; status.coin_key_pressed = pressed;
break; break;
case usio_btn::service: case usio_btn::service:
if (player == 0 && pressed) if (player % 2 == 0 && pressed)
digital_input |= 0x4000; input |= 0x4000;
break; break;
case usio_btn::enter: case usio_btn::enter:
if (pressed) if (pressed)
{ {
digital_input |= 0x800000ULL << shift; input |= 0x800000ULL << shift;
if (player == 0) if (player == 0)
digital_input_lm |= 0x800; digital_input_lm |= 0x800;
} }
@ -328,7 +333,7 @@ void usb_device_usio::translate_input_tekken()
case usio_btn::up: case usio_btn::up:
if (pressed) if (pressed)
{ {
digital_input |= 0x200000ULL << shift; input |= 0x200000ULL << shift;
if (player == 0) if (player == 0)
digital_input_lm |= 0x200; digital_input_lm |= 0x200;
} }
@ -336,7 +341,7 @@ void usb_device_usio::translate_input_tekken()
case usio_btn::down: case usio_btn::down:
if (pressed) if (pressed)
{ {
digital_input |= 0x100000ULL << shift; input |= 0x100000ULL << shift;
if (player == 0) if (player == 0)
digital_input_lm |= 0x400; digital_input_lm |= 0x400;
} }
@ -344,7 +349,7 @@ void usb_device_usio::translate_input_tekken()
case usio_btn::left: case usio_btn::left:
if (pressed) if (pressed)
{ {
digital_input |= 0x80000ULL << shift; input |= 0x80000ULL << shift;
if (player == 0) if (player == 0)
digital_input_lm |= 0x2000; digital_input_lm |= 0x2000;
} }
@ -352,7 +357,7 @@ void usb_device_usio::translate_input_tekken()
case usio_btn::right: case usio_btn::right:
if (pressed) if (pressed)
{ {
digital_input |= 0x40000ULL << shift; input |= 0x40000ULL << shift;
if (player == 0) if (player == 0)
digital_input_lm |= 0x4000; digital_input_lm |= 0x4000;
} }
@ -360,47 +365,52 @@ void usb_device_usio::translate_input_tekken()
case usio_btn::tekken_button1: case usio_btn::tekken_button1:
if (pressed) if (pressed)
{ {
digital_input |= 0x20000ULL << shift; input |= 0x20000ULL << shift;
if (player == 0) if (player == 0)
digital_input_lm |= 0x100; digital_input_lm |= 0x100;
} }
break; break;
case usio_btn::tekken_button2: case usio_btn::tekken_button2:
if (pressed) if (pressed)
digital_input |= 0x10000ULL << shift; input |= 0x10000ULL << shift;
break; break;
case usio_btn::tekken_button3: case usio_btn::tekken_button3:
if (pressed) if (pressed)
digital_input |= 0x40000000ULL << shift; input |= 0x40000000ULL << shift;
break; break;
case usio_btn::tekken_button4: case usio_btn::tekken_button4:
if (pressed) if (pressed)
digital_input |= 0x20000000ULL << shift; input |= 0x20000000ULL << shift;
break; break;
case usio_btn::tekken_button5: case usio_btn::tekken_button5:
if (pressed) if (pressed)
digital_input |= 0x80000000ULL << shift; input |= 0x80000000ULL << shift;
break; break;
default: default:
break; break;
} }
}); });
if (player % 2 == 0 && status.test_on)
{
input |= 0x80;
if (player == 0)
digital_input_lm |= 0x1000;
}
}; };
for (usz i = 0; i < g_cfg_usio.players.size(); i++) for (usz i = 0; i < g_cfg_usio.players.size(); i++)
translate_from_pad(i, i); translate_from_pad(i, i);
if (test_on) for (usz i = 0; i < 2; i++)
{ {
digital_input |= 0x80; std::memcpy(input_buf.data() - i * 0x80 + 0x100, &digital_input[i], sizeof(u64));
digital_input_lm |= 0x1000; std::memcpy(input_buf.data() - i * 0x80 + 0x100 + 0x10, &m_io_status[i].coin_counter, sizeof(u16));
} }
std::memcpy(input_buf.data() + 128, &digital_input, sizeof(u64));
std::memcpy(input_buf.data() + 128 + 16, &coin_counter, sizeof(u16));
std::memcpy(input_buf.data(), &digital_input_lm, sizeof(u16)); std::memcpy(input_buf.data(), &digital_input_lm, sizeof(u16));
input_buf[2] = 0b00010000; // DIP Switches, 8 in total input_buf[2] = 0b00010000; // DIP switches, 8 in total
response = std::move(input_buf); response = std::move(input_buf);
} }
@ -489,7 +499,7 @@ void usb_device_usio::usio_read(u8 channel, u16 reg, u16 size)
// Get Buffer, rarely gives a reply on real HW // Get Buffer, rarely gives a reply on real HW
// First U16 seems to be a timestamp of sort // First U16 seems to be a timestamp of sort
// Purpose seems related to connectivity check // Purpose seems related to connectivity check
response = {0x7E, 0xE4, 0x00, 0x00, 0x74, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; response = {0x7E, 0xE4, 0x00, 0x00, 0x74, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
break; break;
} }
case 0x0080: case 0x0080:
@ -522,7 +532,7 @@ void usb_device_usio::usio_read(u8 channel, u16 reg, u16 size)
// Seems to contain a few extra bytes of info in addition to the firmware string // Seems to contain a few extra bytes of info in addition to the firmware string
// Firmware // Firmware
// "NBGI.;USIO01;Ver1.00;JPN,Multipurpose with PPG." // "NBGI.;USIO01;Ver1.00;JPN,Multipurpose with PPG."
constexpr std::array<u8, 0x100> info {0x4E, 0x42, 0x47, 0x49, 0x2E, 0x3B, 0x55, 0x53, 0x49, 0x4F, 0x30, 0x31, 0x3B, 0x56, 0x65, 0x72, 0x31, 0x2E, 0x30, 0x30, 0x3B, 0x4A, 0x50, 0x4E, 0x2C, 0x4D, 0x75, 0x6C, 0x74, 0x69, 0x70, 0x75, 0x72, 0x70, 0x6F, 0x73, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x50, 0x50, 0x47, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4E, 0x42, 0x47, 0x49, 0x2E, 0x3B, 0x55, 0x53, 0x49, 0x4F, 0x30, 0x31, 0x3B, 0x56, 0x65, 0x72, 0x31, 0x2E, 0x30, 0x30, 0x3B, 0x4A, 0x50, 0x4E, 0x2C, 0x4D, 0x75, 0x6C, 0x74, 0x69, 0x70, 0x75, 0x72, 0x70, 0x6F, 0x73, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x50, 0x50, 0x47, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x13, 0x00, 0x30, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x02, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x75, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; constexpr std::array<u8, 0x180> info {0x4E, 0x42, 0x47, 0x49, 0x2E, 0x3B, 0x55, 0x53, 0x49, 0x4F, 0x30, 0x31, 0x3B, 0x56, 0x65, 0x72, 0x31, 0x2E, 0x30, 0x30, 0x3B, 0x4A, 0x50, 0x4E, 0x2C, 0x4D, 0x75, 0x6C, 0x74, 0x69, 0x70, 0x75, 0x72, 0x70, 0x6F, 0x73, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x50, 0x50, 0x47, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4E, 0x42, 0x47, 0x49, 0x31, 0x3B, 0x55, 0x53, 0x49, 0x4F, 0x30, 0x31, 0x3B, 0x56, 0x65, 0x72, 0x31, 0x2E, 0x30, 0x30, 0x3B, 0x4A, 0x50, 0x4E, 0x2C, 0x4D, 0x75, 0x6C, 0x74, 0x69, 0x70, 0x75, 0x72, 0x70, 0x6F, 0x73, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x50, 0x50, 0x47, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x13, 0x00, 0x30, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x02, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x75, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4E, 0x42, 0x47, 0x49, 0x32, 0x3B, 0x55, 0x53, 0x49, 0x4F, 0x30, 0x31, 0x3B, 0x56, 0x65, 0x72, 0x31, 0x2E, 0x30, 0x30, 0x3B, 0x4A, 0x50, 0x4E, 0x2C, 0x4D, 0x75, 0x6C, 0x74, 0x69, 0x70, 0x75, 0x72, 0x70, 0x6F, 0x73, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x50, 0x50, 0x47, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x13, 0x00, 0x30, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x02, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x75, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
response = {info.begin() + (reg - 0x1800), info.end()}; response = {info.begin() + (reg - 0x1800), info.end()};
break; break;
} }

View File

@ -21,11 +21,17 @@ private:
void usio_read(u8 channel, u16 reg, u16 size); void usio_read(u8 channel, u16 reg, u16 size);
private: private:
bool test_on = false;
bool test_key_pressed = false;
bool coin_key_pressed = false;
bool is_used = false; bool is_used = false;
le_t<u16> coin_counter = 0;
const std::string usio_backup_path = rpcs3::utils::get_hdd1_dir() + "/caches/usiobackup.bin"; const std::string usio_backup_path = rpcs3::utils::get_hdd1_dir() + "/caches/usiobackup.bin";
std::vector<u8> response; std::vector<u8> response;
struct io_status
{
bool test_on = false;
bool test_key_pressed = false;
bool coin_key_pressed = false;
le_t<u16> coin_counter = 0;
};
std::array<io_status, 2> m_io_status;
}; };

View File

@ -50,9 +50,9 @@ struct cfg_usio final : public emulated_pad_config<usio_btn>
cfg_pad_btn<usio_btn> tekken_button5{this, "Tekken Button 5", usio_btn::tekken_button5, pad_button::R1}; cfg_pad_btn<usio_btn> tekken_button5{this, "Tekken Button 5", usio_btn::tekken_button5, pad_button::R1};
}; };
struct cfg_usios final : public emulated_pads_config<cfg_usio, 2> struct cfg_usios final : public emulated_pads_config<cfg_usio, 4>
{ {
cfg_usios() : emulated_pads_config<cfg_usio, 2>("usio") {}; cfg_usios() : emulated_pads_config<cfg_usio, 4>("usio") {};
}; };
extern cfg_usios g_cfg_usio; extern cfg_usios g_cfg_usio;