mirror of
https://github.com/RPCS3/rpcs3.git
synced 2026-03-11 16:05:23 +01:00
Wiimote to GunCon3: IR healthchecks to determine connection state
This commit is contained in:
parent
81bc25d3b4
commit
da55ae917f
|
|
@ -48,7 +48,7 @@ bool wiimote_device::open(hid_device_info* info)
|
|||
if (initialize_ir())
|
||||
{
|
||||
m_state.connected = true;
|
||||
m_last_update = std::chrono::steady_clock::now();
|
||||
m_last_ir_check = std::chrono::steady_clock::now();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -69,22 +69,23 @@ void wiimote_device::close()
|
|||
m_serial.clear();
|
||||
}
|
||||
|
||||
bool wiimote_device::write_reg(u32 addr, const std::vector<u8>& data)
|
||||
{
|
||||
u8 buf[22] = {0};
|
||||
buf[0] = 0x16; // Write register
|
||||
buf[1] = 0x06; // Register Space + Request Acknowledgement
|
||||
buf[2] = (addr >> 16) & 0xFF;
|
||||
buf[3] = (addr >> 8) & 0xFF;
|
||||
buf[4] = addr & 0xFF;
|
||||
buf[5] = static_cast<u8>(data.size());
|
||||
std::copy(data.begin(), data.end(), &buf[6]);
|
||||
if (hid_write(m_handle, buf, sizeof(buf)) < 0) return false;
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wiimote_device::initialize_ir()
|
||||
{
|
||||
auto write_reg = [&](u32 addr, const std::vector<u8>& data) {
|
||||
u8 buf[22] = {0};
|
||||
buf[0] = 0x16; // Write register
|
||||
buf[1] = 0x06; // Register Space + Request Acknowledgement
|
||||
buf[2] = (addr >> 16) & 0xFF;
|
||||
buf[3] = (addr >> 8) & 0xFF;
|
||||
buf[4] = addr & 0xFF;
|
||||
buf[5] = static_cast<u8>(data.size());
|
||||
std::copy(data.begin(), data.end(), &buf[6]);
|
||||
if (hid_write(m_handle, buf, sizeof(buf)) < 0) return false;
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
return true;
|
||||
};
|
||||
|
||||
// 1. Enable IR logic / Pixel Clock (Requesting Acknowledgement for stability)
|
||||
u8 ir_on1[] = { 0x13, 0x06 };
|
||||
hid_write(m_handle, ir_on1, 2);
|
||||
|
|
@ -114,19 +115,53 @@ bool wiimote_device::initialize_ir()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool wiimote_device::verify_ir_health()
|
||||
{
|
||||
if (!m_handle) return false;
|
||||
|
||||
// Request device status to verify communication
|
||||
u8 status_req[] = { 0x15, 0x00 };
|
||||
if (hid_write(m_handle, status_req, sizeof(status_req)) < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Try to read a response within reasonable time
|
||||
u8 buf[22];
|
||||
int res = hid_read_timeout(m_handle, buf, sizeof(buf), 100);
|
||||
|
||||
// If we got a response, device is alive. If timeout or error, it's dead.
|
||||
return res > 0;
|
||||
}
|
||||
|
||||
bool wiimote_device::update()
|
||||
{
|
||||
if (!m_handle) return false;
|
||||
|
||||
// Every 3 seconds, verify IR is still working
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
if (now - m_last_ir_check > std::chrono::seconds(3))
|
||||
{
|
||||
m_last_ir_check = now;
|
||||
if (!verify_ir_health())
|
||||
{
|
||||
// Device not responding - attempt to reinitialize IR
|
||||
if (!initialize_ir())
|
||||
{
|
||||
// Failed to reinitialize - close and mark disconnected
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u8 buf[22];
|
||||
int res;
|
||||
bool received = false;
|
||||
|
||||
// Fully drain the buffer until empty to ensure we have the most recent data.
|
||||
// This avoids getting stuck behind a backlog of old reports (e.g. from before IR was enabled).
|
||||
while ((res = hid_read_timeout(m_handle, buf, sizeof(buf), 0)) > 0)
|
||||
{
|
||||
received = true;
|
||||
// All data reports (0x30-0x3F) carry buttons in the same location (first 2 bytes).
|
||||
// We mask out accelerometer LSBs (bits 5,6 of both bytes).
|
||||
if ((buf[0] & 0xF0) == 0x30)
|
||||
|
|
@ -156,19 +191,12 @@ bool wiimote_device::update()
|
|||
// hid_read_timeout returns -1 on error (e.g. device disconnected).
|
||||
if (res < 0)
|
||||
{
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (received)
|
||||
{
|
||||
m_last_update = std::chrono::steady_clock::now();
|
||||
}
|
||||
else if (std::chrono::steady_clock::now() - m_last_update > std::chrono::seconds(2))
|
||||
{
|
||||
// No data for 2 seconds. Likely disconnected or powered off.
|
||||
close();
|
||||
return false;
|
||||
// Device error - try to recover once before giving up
|
||||
if (!initialize_ir())
|
||||
{
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -78,9 +78,11 @@ private:
|
|||
std::string m_path;
|
||||
std::wstring m_serial;
|
||||
wiimote_state m_state;
|
||||
std::chrono::steady_clock::time_point m_last_update;
|
||||
std::chrono::steady_clock::time_point m_last_ir_check;
|
||||
|
||||
bool initialize_ir();
|
||||
bool verify_ir_health();
|
||||
bool write_reg(u32 addr, const std::vector<u8>& data);
|
||||
};
|
||||
|
||||
class wiimote_manager
|
||||
|
|
|
|||
|
|
@ -12,11 +12,12 @@ wiimote_settings_dialog::wiimote_settings_dialog(QWidget* parent)
|
|||
{
|
||||
ui->setupUi(this);
|
||||
update_list();
|
||||
connect(ui->scanButton, &QPushButton::clicked, this, [this] { update_list(); });
|
||||
connect(ui->restoreDefaultsButton, &QPushButton::clicked, this, &wiimote_settings_dialog::restore_defaults);
|
||||
|
||||
// Timer updates both state AND device list (auto-refresh)
|
||||
QTimer* timer = new QTimer(this);
|
||||
connect(timer, &QTimer::timeout, this, &wiimote_settings_dialog::update_state);
|
||||
connect(timer, &QTimer::timeout, this, &wiimote_settings_dialog::update_list);
|
||||
timer->start(50);
|
||||
|
||||
populate_mappings();
|
||||
|
|
@ -229,28 +230,57 @@ void wiimote_settings_dialog::update_state()
|
|||
|
||||
void wiimote_settings_dialog::update_list()
|
||||
{
|
||||
ui->wiimoteList->clear();
|
||||
auto* wm = wiimote_manager::get_instance();
|
||||
if (!wm)
|
||||
{
|
||||
ui->wiimoteList->addItem(tr("Wiimote Manager not initialized."));
|
||||
if (ui->wiimoteList->count() != 1 || ui->wiimoteList->item(0)->text() != tr("Wiimote Manager not initialized."))
|
||||
{
|
||||
ui->wiimoteList->clear();
|
||||
ui->wiimoteList->addItem(tr("Wiimote Manager not initialized."));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
size_t count = wm->get_device_count();
|
||||
if (count == 0)
|
||||
auto states = wm->get_states();
|
||||
|
||||
// Only update if the list content actually changed (avoid flicker)
|
||||
if (static_cast<size_t>(ui->wiimoteList->count()) != states.size())
|
||||
{
|
||||
ui->wiimoteList->addItem(tr("No Wiimotes found."));
|
||||
}
|
||||
else
|
||||
{
|
||||
auto states = wm->get_states();
|
||||
int current_row = ui->wiimoteList->currentRow();
|
||||
ui->wiimoteList->clear();
|
||||
|
||||
for (size_t i = 0; i < states.size(); i++)
|
||||
{
|
||||
QString label = tr("Wiimote #%1").arg(i + 1);
|
||||
if (!states[i].connected) label += " (" + tr("Disconnected") + ")";
|
||||
ui->wiimoteList->addItem(label);
|
||||
}
|
||||
ui->wiimoteList->setCurrentRow(0);
|
||||
|
||||
if (current_row >= 0 && current_row < ui->wiimoteList->count())
|
||||
{
|
||||
ui->wiimoteList->setCurrentRow(current_row);
|
||||
}
|
||||
else if (ui->wiimoteList->count() > 0)
|
||||
{
|
||||
ui->wiimoteList->setCurrentRow(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Just update connection status labels without clearing
|
||||
for (size_t i = 0; i < states.size(); i++)
|
||||
{
|
||||
QString label = tr("Wiimote #%1").arg(i + 1);
|
||||
if (!states[i].connected) label += " (" + tr("Disconnected") + ")";
|
||||
|
||||
if (static_cast<int>(i) < ui->wiimoteList->count())
|
||||
{
|
||||
QListWidgetItem* item = ui->wiimoteList->item(static_cast<int>(i));
|
||||
if (item && item->text() != label)
|
||||
{
|
||||
item->setText(label);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -206,13 +206,6 @@
|
|||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="scanButton">
|
||||
<property name="text">
|
||||
<string>Refresh Scan</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="restoreDefaultsButton">
|
||||
<property name="text">
|
||||
|
|
|
|||
Loading…
Reference in a new issue