boo/lib/inputdev/DolphinSmashAdapter.cpp

268 lines
7.4 KiB
C++
Raw Normal View History

2015-08-18 22:43:30 +00:00
#include "boo/inputdev/DolphinSmashAdapter.hpp"
2018-10-07 02:49:22 +00:00
#include "boo/inputdev/DeviceSignature.hpp"
2017-12-29 07:54:26 +00:00
#include <cstdio>
#include <cstring>
2015-04-22 21:48:23 +00:00
2015-04-29 10:24:39 +00:00
namespace boo
{
/*
* Reference: https://github.com/ToadKing/wii-u-gc-adapter/blob/master/wii-u-gc-adapter.c
2015-04-24 00:24:15 +00:00
*/
2018-10-07 02:49:22 +00:00
DolphinSmashAdapter::DolphinSmashAdapter(DeviceToken* token)
: TDeviceBase<IDolphinSmashAdapterCallback>(dev_typeid(DolphinSmashAdapter), token) {}
2017-01-27 07:41:45 +00:00
DolphinSmashAdapter::~DolphinSmashAdapter() {}
2015-04-24 00:24:15 +00:00
2015-04-29 10:24:39 +00:00
static inline EDolphinControllerType parseType(unsigned char status)
2015-04-24 00:24:15 +00:00
{
2017-01-27 07:41:45 +00:00
EDolphinControllerType type =
EDolphinControllerType(status) & (EDolphinControllerType::Normal | EDolphinControllerType::Wavebird);
2015-04-24 00:24:15 +00:00
switch (type)
{
2017-01-27 07:41:45 +00:00
case EDolphinControllerType::Normal:
case EDolphinControllerType::Wavebird:
return type;
default:
return EDolphinControllerType::None;
2015-04-24 00:24:15 +00:00
}
}
2017-01-27 07:41:45 +00:00
static inline EDolphinControllerType parseState(DolphinControllerState* stateOut, uint8_t* payload, bool& rumble)
2015-04-24 00:24:15 +00:00
{
2015-08-18 19:40:26 +00:00
memset(stateOut, 0, sizeof(DolphinControllerState));
2015-04-24 00:24:15 +00:00
unsigned char status = payload[0];
2015-04-29 10:24:39 +00:00
EDolphinControllerType type = parseType(status);
2017-01-27 07:41:45 +00:00
rumble = ((status & 0x04) != 0) ? true : false;
2017-01-27 07:41:45 +00:00
2015-04-24 00:24:15 +00:00
stateOut->m_btns = (uint16_t)payload[1] << 8 | (uint16_t)payload[2];
2017-01-27 07:41:45 +00:00
2017-12-20 06:04:11 +00:00
stateOut->m_leftStick[0] = payload[3];
stateOut->m_leftStick[1] = payload[4];
stateOut->m_rightStick[0] = payload[5];
stateOut->m_rightStick[1] = payload[6];
2015-04-24 00:24:15 +00:00
stateOut->m_analogTriggers[0] = payload[7];
stateOut->m_analogTriggers[1] = payload[8];
2017-01-27 07:41:45 +00:00
return type;
2015-04-22 21:48:23 +00:00
}
2015-08-18 19:40:26 +00:00
void DolphinSmashAdapter::initialCycle()
2015-05-04 04:28:07 +00:00
{
uint8_t handshakePayload[] = {0x13};
2015-05-10 07:02:18 +00:00
sendUSBInterruptTransfer(handshakePayload, sizeof(handshakePayload));
2015-05-04 04:28:07 +00:00
}
2015-08-18 19:40:26 +00:00
void DolphinSmashAdapter::transferCycle()
2015-04-24 00:24:15 +00:00
{
uint8_t payload[37];
2015-05-10 07:02:18 +00:00
size_t recvSz = receiveUSBInterruptTransfer(payload, sizeof(payload));
if (recvSz != 37 || payload[0] != 0x21)
return;
2017-01-27 07:41:45 +00:00
// printf("RECEIVED DATA %zu %02X\n", recvSz, payload[0]);
std::lock_guard<std::mutex> lk(m_callbackLock);
if (!m_callback)
return;
/* Parse controller states */
uint8_t* controller = &payload[1];
uint8_t rumbleMask = 0;
for (uint32_t i = 0; i < 4; i++, controller += 9)
2015-04-24 00:24:15 +00:00
{
2015-08-18 19:40:26 +00:00
DolphinControllerState state;
bool rumble = false;
EDolphinControllerType type = parseState(&state, controller, rumble);
2017-01-27 07:41:45 +00:00
if (type != EDolphinControllerType::None && !(m_knownControllers & 1 << i))
2015-04-24 00:24:15 +00:00
{
2017-12-20 06:04:11 +00:00
m_leftStickCal[0] = state.m_leftStick[0];
m_leftStickCal[1] = state.m_leftStick[1];
m_rightStickCal[0] = state.m_rightStick[0];
m_rightStickCal[1] = state.m_rightStick[1];
m_triggersCal[0] = state.m_analogTriggers[0];
m_triggersCal[1] = state.m_analogTriggers[1];
2017-01-27 07:41:45 +00:00
m_knownControllers |= 1 << i;
m_callback->controllerConnected(i, type);
2015-04-24 00:24:15 +00:00
}
2017-01-27 07:41:45 +00:00
else if (type == EDolphinControllerType::None && (m_knownControllers & 1 << i))
2015-04-24 00:24:15 +00:00
{
2017-01-27 07:41:45 +00:00
m_knownControllers &= ~(1 << i);
2015-08-29 01:30:21 +00:00
m_callback->controllerDisconnected(i);
2015-04-24 00:24:15 +00:00
}
2017-01-27 07:41:45 +00:00
if (m_knownControllers & 1 << i)
{
2017-12-20 06:04:11 +00:00
state.m_leftStick[0] = state.m_leftStick[0] - m_leftStickCal[0];
state.m_leftStick[1] = state.m_leftStick[1] - m_leftStickCal[1];
state.m_rightStick[0] = state.m_rightStick[0] - m_rightStickCal[0];
state.m_rightStick[1] = state.m_rightStick[1] - m_rightStickCal[1];
state.m_analogTriggers[0] = state.m_analogTriggers[0] - m_triggersCal[0];
state.m_analogTriggers[1] = state.m_analogTriggers[1] - m_triggersCal[1];
m_callback->controllerUpdate(i, type, state);
}
2017-01-27 07:41:45 +00:00
rumbleMask |= rumble ? 1 << i : 0;
}
/* Send rumble message (if needed) */
uint8_t rumbleReq = m_rumbleRequest & rumbleMask;
if (rumbleReq != m_rumbleState)
{
uint8_t rumbleMessage[5] = {0x11};
2017-01-27 07:41:45 +00:00
for (int i = 0; i < 4; ++i)
2015-08-29 01:30:21 +00:00
{
2017-01-27 07:41:45 +00:00
if (rumbleReq & 1 << i)
rumbleMessage[i + 1] = 1;
2015-08-29 01:30:21 +00:00
else if (m_hardStop[i])
2017-01-27 07:41:45 +00:00
rumbleMessage[i + 1] = 2;
2015-08-29 01:30:21 +00:00
else
2017-01-27 07:41:45 +00:00
rumbleMessage[i + 1] = 0;
2015-08-29 01:30:21 +00:00
}
2015-05-15 01:16:36 +00:00
2015-05-10 07:02:18 +00:00
sendUSBInterruptTransfer(rumbleMessage, sizeof(rumbleMessage));
m_rumbleState = rumbleReq;
2015-04-24 00:24:15 +00:00
}
}
2015-08-18 19:40:26 +00:00
void DolphinSmashAdapter::finalCycle()
2015-04-26 08:25:44 +00:00
{
uint8_t rumbleMessage[5] = {0x11, 0, 0, 0, 0};
2015-05-10 07:02:18 +00:00
sendUSBInterruptTransfer(rumbleMessage, sizeof(rumbleMessage));
}
2015-04-26 08:25:44 +00:00
2015-08-18 19:40:26 +00:00
void DolphinSmashAdapter::deviceDisconnected()
{
for (uint32_t i = 0; i < 4; i++)
2015-08-29 01:30:21 +00:00
{
2017-01-27 07:41:45 +00:00
if (m_knownControllers & 1 << i)
2015-08-29 01:30:21 +00:00
{
2017-01-27 07:41:45 +00:00
m_knownControllers &= ~(1 << i);
std::lock_guard<std::mutex> lk(m_callbackLock);
if (m_callback)
m_callback->controllerDisconnected(i);
2015-08-29 01:30:21 +00:00
}
}
}
/* The following code is derived from pad.c in libogc
*
* Copyright (C) 2004 - 2009
* Michael Wiedenbauer (shagkur)
* Dave Murphy (WinterMute)
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any
* damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any
* purpose, including commercial applications, and to alter it and
* redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you
* must not claim that you wrote the original software. If you use
* this software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source
* distribution.
*/
2017-12-20 06:04:11 +00:00
static int16_t pad_clampregion[8] = {30, 180, 15, 72, 40, 15, 59, 31};
2015-08-29 01:30:21 +00:00
2017-12-20 06:04:11 +00:00
static void pad_clampstick(int16_t& px, int16_t& py, int16_t max, int16_t xy, int16_t min)
2015-08-29 01:30:21 +00:00
{
2017-01-27 07:41:45 +00:00
int x = px;
int y = py;
int signX;
int signY;
int d;
2015-08-29 01:30:21 +00:00
2017-01-27 07:41:45 +00:00
if (x > 0)
{
2015-08-29 01:30:21 +00:00
signX = 1;
2017-01-27 07:41:45 +00:00
}
2015-08-29 01:30:21 +00:00
else
{
signX = -1;
x = -x;
}
2017-01-27 07:41:45 +00:00
if (y > 0)
{
2015-08-29 01:30:21 +00:00
signY = 1;
2017-01-27 07:41:45 +00:00
}
2015-08-29 01:30:21 +00:00
else
{
signY = -1;
y = -y;
}
if (x <= min)
x = 0;
else
x -= min;
if (y <= min)
2017-01-27 07:41:45 +00:00
{
2015-08-29 01:30:21 +00:00
y = 0;
2017-01-27 07:41:45 +00:00
}
2015-08-29 01:30:21 +00:00
else
2017-01-27 07:41:45 +00:00
{
2015-08-29 01:30:21 +00:00
y -= min;
2017-01-27 07:41:45 +00:00
}
2015-08-29 01:30:21 +00:00
2017-01-27 07:41:45 +00:00
if (x == 0 && y == 0)
2015-08-29 01:30:21 +00:00
{
2017-01-27 07:41:45 +00:00
px = py = 0;
return;
}
2015-08-29 01:30:21 +00:00
2017-01-27 07:41:45 +00:00
if (xy * y <= xy * x)
{
d = xy * x + (max - xy) * y;
if (xy * max < d)
2015-08-29 01:30:21 +00:00
{
2017-12-20 06:04:11 +00:00
x = int16_t(xy * max * x / d);
y = int16_t(xy * max * y / d);
2015-08-29 01:30:21 +00:00
}
2017-01-27 07:41:45 +00:00
}
else
{
d = xy * y + (max - xy) * x;
if (xy * max < d)
2015-08-29 01:30:21 +00:00
{
2017-12-20 06:04:11 +00:00
x = int16_t(xy * max * x / d);
y = int16_t(xy * max * y / d);
2015-08-29 01:30:21 +00:00
}
}
2017-01-27 07:41:45 +00:00
2017-12-20 06:04:11 +00:00
px = int16_t(signX * x);
py = int16_t(signY * y);
2015-08-29 01:30:21 +00:00
}
2017-12-20 06:04:11 +00:00
static void pad_clamptrigger(int16_t& trigger)
2015-08-29 01:30:21 +00:00
{
2017-12-20 06:04:11 +00:00
int16_t min, max;
2015-08-29 01:30:21 +00:00
min = pad_clampregion[0];
max = pad_clampregion[1];
if (min > trigger)
trigger = 0;
else
2017-01-27 07:41:45 +00:00
{
if (max < trigger)
2017-12-22 02:15:30 +00:00
trigger = max;
2015-08-29 01:30:21 +00:00
trigger -= min;
2017-01-27 07:41:45 +00:00
}
2015-08-29 01:30:21 +00:00
}
void DolphinControllerState::clamp()
{
2017-12-20 06:04:11 +00:00
pad_clampstick(m_leftStick[0], m_leftStick[1], pad_clampregion[3], pad_clampregion[4], pad_clampregion[2]);
pad_clampstick(m_rightStick[0], m_rightStick[1], pad_clampregion[6], pad_clampregion[7], pad_clampregion[5]);
2015-08-29 01:30:21 +00:00
pad_clamptrigger(m_analogTriggers[0]);
pad_clamptrigger(m_analogTriggers[1]);
}
2015-04-29 10:24:39 +00:00
}