2015-08-18 22:43:30 +00:00
|
|
|
#include "boo/inputdev/DolphinSmashAdapter.hpp"
|
2015-04-22 21:48:23 +00:00
|
|
|
#include <stdio.h>
|
2015-04-24 00:24:15 +00:00
|
|
|
#include <string.h>
|
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
|
|
|
*/
|
|
|
|
|
2017-01-27 07:41:45 +00:00
|
|
|
DolphinSmashAdapter::DolphinSmashAdapter(DeviceToken* token) : DeviceBase(token) {}
|
2015-04-23 00:46:32 +00:00
|
|
|
|
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
|
|
|
|
2015-04-24 05:50:08 +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-02-11 04:20:41 +00:00
|
|
|
stateOut->m_leftStick[0] = int8_t(payload[3]);
|
|
|
|
stateOut->m_leftStick[1] = int8_t(payload[4]);
|
|
|
|
stateOut->m_rightStick[0] = int8_t(payload[5]);
|
|
|
|
stateOut->m_rightStick[1] = int8_t(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
|
|
|
|
2015-04-24 05:50:08 +00:00
|
|
|
return type;
|
2015-04-22 21:48:23 +00:00
|
|
|
}
|
2015-04-21 04:02:43 +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
|
|
|
{
|
2015-04-30 23:17:46 +00:00
|
|
|
uint8_t payload[37];
|
2015-05-10 07:02:18 +00:00
|
|
|
size_t recvSz = receiveUSBInterruptTransfer(payload, sizeof(payload));
|
2015-04-30 23:17:46 +00:00
|
|
|
if (recvSz != 37 || payload[0] != 0x21)
|
|
|
|
return;
|
2017-02-11 04:20:41 +00:00
|
|
|
|
2017-01-27 07:41:45 +00:00
|
|
|
// printf("RECEIVED DATA %zu %02X\n", recvSz, payload[0]);
|
2015-04-30 23:17:46 +00:00
|
|
|
|
|
|
|
if (!m_callback)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Parse controller states */
|
|
|
|
uint8_t* controller = &payload[1];
|
|
|
|
uint8_t rumbleMask = 0;
|
2017-02-11 04:20:41 +00:00
|
|
|
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;
|
2015-04-30 23:17:46 +00:00
|
|
|
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-01-27 07:41:45 +00:00
|
|
|
m_knownControllers |= 1 << i;
|
2015-04-30 23:17:46 +00:00
|
|
|
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)
|
2015-04-30 23:17:46 +00:00
|
|
|
m_callback->controllerUpdate(i, type, state);
|
2017-01-27 07:41:45 +00:00
|
|
|
rumbleMask |= rumble ? 1 << i : 0;
|
2015-04-30 23:17:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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));
|
2015-04-30 23:17:46 +00:00
|
|
|
m_rumbleState = rumbleReq;
|
2015-04-24 00:24:15 +00:00
|
|
|
}
|
2015-04-30 07:01:55 +00:00
|
|
|
}
|
|
|
|
|
2015-08-18 19:40:26 +00:00
|
|
|
void DolphinSmashAdapter::finalCycle()
|
2015-04-26 08:25:44 +00:00
|
|
|
{
|
2015-04-30 23:17:46 +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-30 07:01:55 +00:00
|
|
|
}
|
2015-04-26 08:25:44 +00:00
|
|
|
|
2015-08-18 19:40:26 +00:00
|
|
|
void DolphinSmashAdapter::deviceDisconnected()
|
2015-04-21 04:02:43 +00:00
|
|
|
{
|
2015-08-29 01:30:21 +00:00
|
|
|
if (!m_callback)
|
|
|
|
return;
|
2017-02-11 04:20:41 +00:00
|
|
|
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);
|
2015-08-29 01:30:21 +00:00
|
|
|
m_callback->controllerDisconnected(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static uint8_t pad_clampregion[8] = {30, 180, 15, 72, 40, 15, 59, 31};
|
|
|
|
|
|
|
|
static void pad_clampstick(int8_t& px, int8_t& py, int8_t max, int8_t xy, int8_t min)
|
|
|
|
{
|
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-01-27 07:41:45 +00:00
|
|
|
x = int8_t(xy * max * x / d);
|
|
|
|
y = int8_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-01-27 07:41:45 +00:00
|
|
|
x = int8_t(xy * max * x / d);
|
|
|
|
y = int8_t(xy * max * y / d);
|
2015-08-29 01:30:21 +00:00
|
|
|
}
|
|
|
|
}
|
2017-01-27 07:41:45 +00:00
|
|
|
|
|
|
|
px = int8_t(signX * x);
|
|
|
|
py = int8_t(signY * y);
|
2015-08-29 01:30:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void pad_clamptrigger(uint8_t& trigger)
|
|
|
|
{
|
|
|
|
uint8_t min, max;
|
|
|
|
|
|
|
|
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)
|
|
|
|
trigger = max - min;
|
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-02-11 04:20:41 +00:00
|
|
|
pad_clampstick(m_leftStick[0], m_leftStick[1], int8_t(pad_clampregion[3]), int8_t(pad_clampregion[4]), int8_t(pad_clampregion[2]));
|
|
|
|
pad_clampstick(m_rightStick[0], m_rightStick[1], int8_t(pad_clampregion[6]), int8_t(pad_clampregion[7]), int8_t(pad_clampregion[5]));
|
2015-08-29 01:30:21 +00:00
|
|
|
pad_clamptrigger(m_analogTriggers[0]);
|
|
|
|
pad_clamptrigger(m_analogTriggers[1]);
|
2015-04-21 04:02:43 +00:00
|
|
|
}
|
2015-04-29 10:24:39 +00:00
|
|
|
}
|