WiimoteReal: hidapi: Add support for the Balance Board

A name change isn't enough for the DolphinBar; we have to actually
query the Wiimote to know if the Wiimote is a Balance Board.
This commit is contained in:
Léo Lam 2016-08-04 20:19:34 +02:00
parent d9a9e34994
commit 132ca8d02c
3 changed files with 77 additions and 7 deletions

View File

@ -70,17 +70,17 @@ void WiimoteScannerHidapi::FindWiimotes(std::vector<Wiimote*>& wiimotes, Wiimote
if (!is_wiimote || s_known_paths.count(device->path) != 0 || !IsDeviceUsable(device->path))
continue;
const bool is_balance_board = IsBalanceBoardName(name);
NOTICE_LOG(WIIMOTE, "Found %s at %s: %ls %ls (%04hx:%04hx)",
is_balance_board ? "balance board" : "Wiimote", device->path,
device->manufacturer_string, device->product_string, device->vendor_id,
device->product_id);
Wiimote* wiimote = new WiimoteHidapi(device->path);
auto* wiimote = new WiimoteHidapi(device->path);
const bool is_balance_board = IsBalanceBoardName(name) || wiimote->IsBalanceBoard();
if (is_balance_board)
board = wiimote;
else
wiimotes.push_back(wiimote);
NOTICE_LOG(WIIMOTE, "Found %s at %s: %ls %ls (%04hx:%04hx)",
is_balance_board ? "balance board" : "Wiimote", device->path,
device->manufacturer_string, device->product_string, device->vendor_id,
device->product_id);
}
hid_free_enumeration(list);
}
@ -98,6 +98,9 @@ WiimoteHidapi::~WiimoteHidapi()
bool WiimoteHidapi::ConnectInternal()
{
if (m_handle != nullptr)
return true;
m_handle = hid_open_path(m_device_path.c_str());
if (m_handle == nullptr)
{

View File

@ -242,6 +242,71 @@ bool Wiimote::Write()
return ret != 0;
}
bool Wiimote::IsBalanceBoard()
{
if (!ConnectInternal())
return false;
// Initialise the extension by writing 0x55 to 0xa400f0, then writing 0x00 to 0xa400fb.
static const u8 init_extension_rpt1[MAX_PAYLOAD] = {
WM_SET_REPORT | WM_BT_OUTPUT, WM_WRITE_DATA, 0x04, 0xa4, 0x00, 0xf0, 0x01, 0x55};
static const u8 init_extension_rpt2[MAX_PAYLOAD] = {
WM_SET_REPORT | WM_BT_OUTPUT, WM_WRITE_DATA, 0x04, 0xa4, 0x00, 0xfb, 0x01, 0x00};
static const u8 status_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_REQUEST_STATUS, 0};
if (!IOWrite(init_extension_rpt1, sizeof(init_extension_rpt1)) ||
!IOWrite(init_extension_rpt2, sizeof(init_extension_rpt2)))
{
ERROR_LOG(WIIMOTE, "IsBalanceBoard(): Failed to initialise extension.");
return false;
}
int ret = IOWrite(status_report, sizeof(status_report));
u8 buf[MAX_PAYLOAD];
while (ret != 0)
{
ret = IORead(buf);
if (ret == -1)
continue;
switch (buf[1])
{
case WM_STATUS_REPORT:
{
const auto* status = reinterpret_cast<wm_status_report*>(&buf[2]);
// A Balance Board has a Balance Board extension.
if (!status->extension)
return false;
// Read two bytes from 0xa400fe to identify the extension.
static const u8 identify_ext_rpt[] = {
WM_SET_REPORT | WM_BT_OUTPUT, WM_READ_DATA, 0x04, 0xa4, 0x00, 0xfe, 0x02, 0x00};
ret = IOWrite(identify_ext_rpt, sizeof(identify_ext_rpt));
break;
}
case WM_READ_DATA_REPLY:
{
const auto* reply = reinterpret_cast<wm_read_data_reply*>(&buf[2]);
if (Common::swap16(reply->address) != 0x00fe)
{
ERROR_LOG(WIIMOTE, "IsBalanceBoard(): Received unexpected data reply for address %X",
Common::swap16(reply->address));
return false;
}
// A Balance Board ext can be identified by checking for 0x0402.
return reply->data[0] == 0x04 && reply->data[1] == 0x02;
}
case WM_ACK_DATA:
{
const auto* ack = reinterpret_cast<wm_acknowledge*>(&buf[2]);
if (ack->reportID == WM_READ_DATA && ack->errorID != 0x00)
{
WARN_LOG(WIIMOTE, "Failed to read from 0xa400fe, assuming Wiimote is not a Balance Board.");
return false;
}
}
}
}
return false;
}
static bool IsDataReport(const Report& rpt)
{
return rpt.size() >= 2 && rpt[1] >= WM_REPORT_CORE;

View File

@ -41,6 +41,8 @@ public:
void Read();
bool Write();
bool IsBalanceBoard();
void StartThread();
void StopThread();