btdrv-mitm: get fake bluetooth circular buffer working and translate incoming packets from non-switch controllers to switch input report 0x30

This commit is contained in:
ndeadly 2020-06-09 22:39:30 +02:00
parent d75cc58ac1
commit bcc34cf5eb
13 changed files with 579 additions and 84 deletions

View file

@ -83,68 +83,162 @@ namespace ams::mitm::btdrv {
return nullptr; return nullptr;
} }
// reimpl function from bluetooth module
/*
int g_packetCount = 0;
u64 hid_report_buffer_write(bluetooth::CircularBuffer *buffer, const void *data, size_t size, int type) {
if (!buffer->_unk3 || buffer->isInitialized())
return -1;
buffer->DiscardOldPackets(0x27, 100);
if (type == 4 && buffer->GetWriteableSize() <= ) {
++g_packetCount;
if (g_packetCount % 100 == 0) { // maybe inverse of this
//signal_hid_events();
}
return -1;
}
if (size > BLUETOOTH_CIRCBUFFER_SIZE)
return -1;
buffer->Write(type, data, size);
//signal_hid_events(); // Think this signals the hid report event
}
*/
u8 g_fakeReportBuffer[0x42] = {};
HidReportData *g_fakeReportData = reinterpret_cast<HidReportData *>(g_fakeReportBuffer);
Result TranslateHidReportPackets(bluetooth::CircularBuffer *realBuffer, bluetooth::CircularBuffer *fakeBuffer) { Result TranslateHidReportPackets(bluetooth::CircularBuffer *realBuffer, bluetooth::CircularBuffer *fakeBuffer) {
controller::BluetoothController *controller; controller::BluetoothController *controller;
BufferPacket *realPacket; bluetooth::CircularBufferPacket *realPacket;
//BufferPacket fakePacket; Result rc;
BTDRV_LOG_FMT("realBuffer: name: %s, roffs: %d, woffs: %d, capacity: %d, _unk3: %d, id: %d",
realBuffer->name,
realBuffer->readOffset,
realBuffer->writeOffset,
realBuffer->size,
realBuffer->_unk3,
realBuffer->id);
BTDRV_LOG_FMT("fakeBuffer: name: %s, roffs: %d, woffs: %d, capacity: %d, _unk3: %d, id: %d",
fakeBuffer->name,
fakeBuffer->readOffset,
fakeBuffer->writeOffset,
fakeBuffer->size,
fakeBuffer->_unk3,
fakeBuffer->id);
// Take snapshot of current write offset
u32 writeOffset = realBuffer->writeOffset; u32 writeOffset = realBuffer->writeOffset;
while (true) { while (true) {
if (realBuffer->readOffset == writeOffset) if (realBuffer->readOffset == writeOffset)
break; break;
// Read packet from real buffer // Get packet from real buffer
realPacket = reinterpret_cast<BufferPacket *>(realBuffer->Read()); //realPacket = reinterpret_cast<bluetooth::CircularBufferPacket *>(realBuffer->_read());
realPacket = reinterpret_cast<bluetooth::CircularBufferPacket *>(&realBuffer->data[realBuffer->readOffset]);
if (!realPacket) if (!realPacket)
break; break;
BTDRV_LOG_DATA(realPacket, realPacket->header.size + sizeof(bluetooth::CircularBufferPacketHeader)); // Move read pointer past current packet (I think this is what Free does)
if (realBuffer->readOffset != writeOffset) {
u32 newOffset = realBuffer->readOffset + realPacket->header.size + sizeof(bluetooth::CircularBufferPacketHeader);
if (newOffset >= BLUETOOTH_CIRCBUFFER_SIZE)
newOffset = 0;
fakeBuffer->_write(realPacket->header.type, &realPacket->data, realPacket->header.size); realBuffer->_setReadOffset(newOffset);
}
// Identify controller type from Bluetooth address //BTDRV_LOG_DATA(&realPacket->data, realPacket->header.size);
/* //BTDRV_LOG_DATA(realPacket, realPacket->header.size + sizeof(bluetooth::CircularBufferPacketHeader));
controller = locateController(hos::GetVersion() < hos::Version_9_0_0 ? &realPacket->data.address : &realPacket->data.v2.address); //BTDRV_LOG_FMT("fakeBuffer: [%d] writing %d bytes to data[%d]", realPacket->header.type, realPacket->header.size + sizeof(bluetooth::CircularBufferPacketHeader), fakeBuffer->writeOffset);
if (!controller)
if (realPacket->header.type == 0xff) {
//BTDRV_LOG_FMT("0xff packet received");
continue; continue;
*/ }
else if (realPacket->header.type == 4) {
controller = locateController(hos::GetVersion() < hos::Version_9_0_0 ? &realPacket->data.address : &realPacket->data.v2.address);
if (!controller) {
continue;
}
// Convert packet to standard Switch report format if (controller->isSwitchController()) {
// Write unmodified packet directly to fake buffer (_write call will add new timestamp)
if (realPacket->header.size + sizeof(bluetooth::CircularBufferPacketHeader) <= fakeBuffer->GetWriteableSize()) {
if (realPacket->header.size + 2*sizeof(bluetooth::CircularBufferPacketHeader) > BLUETOOTH_CIRCBUFFER_SIZE - fakeBuffer->writeOffset) {
fakeBuffer->_write(0xff, nullptr, (BLUETOOTH_CIRCBUFFER_SIZE - fakeBuffer->writeOffset) - sizeof(bluetooth::CircularBufferPacketHeader));
}
rc = fakeBuffer->_write(realPacket->header.type, &realPacket->data, realPacket->header.size);
}
}
else {
const HidReport *inReport;
HidReport *outReport;
// copy address and stuff over
if (ams::hos::GetVersion() < ams::hos::Version_10_0_0) {
g_fakeReportData->size = 0; // Todo: calculate size of report data
std::memcpy(&g_fakeReportData->address, &realPacket->data.address, sizeof(BluetoothAddress));
inReport = &realPacket->data.report;
outReport = &g_fakeReportData->report;
}
else {
std::memcpy(&g_fakeReportData->v2.address, &realPacket->data.v2.address, sizeof(BluetoothAddress));
inReport = &realPacket->data.v2.report;
outReport = &g_fakeReportData->v2.report;
}
auto switchData = reinterpret_cast<controller::SwitchReportData *>(&outReport->data);
switchData->report0x30.timer = os::ConvertToTimeSpan(realPacket->header.timestamp).GetMilliSeconds() & 0xff;
// Translate packet to switch pro format
//controller->convertReportFormat(hos::GetVersion() < hos::Version_9_0_0 ? &realPacket->data.report : &realPacket->data.v2.report); //controller->convertReportFormat(hos::GetVersion() < hos::Version_9_0_0 ? &realPacket->data.report : &realPacket->data.v2.report);
controller->convertReportFormat(inReport, outReport);
// Copy and correct packet header //BTDRV_LOG_DATA(g_fakeReportData, sizeof(g_fakeReportBuffer));
/*
std::memcpy(&fakePacket.header, &realPacket->header, sizeof(fakePacket.header));
fakePacket.header.size = 0; // Todo: size of switch report data
if (hos::GetVersion() < hos::Version_9_0_0)
fakePacket.data.size = fakePacket.header.size;
*/
/* if (sizeof(g_fakeReportBuffer) + sizeof(bluetooth::CircularBufferPacketHeader) <= fakeBuffer->GetWriteableSize()) {
std::memcpy(&fakePacket.header, &realPacket->header, sizeof(fakePacket.header));
std::memcpy(&fakePacket.data, &realPacket->data, sizeof(realPacket->header.size));
// Write to fake buffer
fakeBuffer->WritePacket(&fakePacket); //Probably need to use the real Write function
*/
if (sizeof(g_fakeReportBuffer) + 2*sizeof(bluetooth::CircularBufferPacketHeader) > BLUETOOTH_CIRCBUFFER_SIZE - fakeBuffer->writeOffset) {
fakeBuffer->_write(0xff, nullptr, (BLUETOOTH_CIRCBUFFER_SIZE - fakeBuffer->writeOffset) - sizeof(bluetooth::CircularBufferPacketHeader));
}
/* // Write translated packet to fake buffer
os::LockSdkMutex(&realBuffer->mutex); rc = fakeBuffer->_write(4, g_fakeReportData, sizeof(g_fakeReportBuffer));
}
}
u32 writeOffset = realBuffer->writeOffset; if (R_SUCCEEDED(rc)) {
u32 readOffset = realBuffer->readOffset; fakeBuffer->_updateUtilization();
s64 size = realBuffer->size; }
std::memcpy(&fakeBuffer->data[fakeBuffer->writeOffset], &realBuffer->data[readOffset], writeOffset-readOffset); }
realBuffer->readOffset = writeOffset; else {
BTDRV_LOG_FMT("unknown packet received");
if (realPacket->header.size + sizeof(bluetooth::CircularBufferPacketHeader) <= fakeBuffer->GetWriteableSize()) {
os::UnlockSdkMutex(&realBuffer->mutex); if (realPacket->header.size + 2*sizeof(bluetooth::CircularBufferPacketHeader) > BLUETOOTH_CIRCBUFFER_SIZE - fakeBuffer->writeOffset) {
fakeBuffer->_write(0xff, nullptr, (BLUETOOTH_CIRCBUFFER_SIZE - fakeBuffer->writeOffset) - sizeof(bluetooth::CircularBufferPacketHeader));
}
fakeBuffer->writeOffset = writeOffset; rc = fakeBuffer->_write(realPacket->header.type, &realPacket->data, realPacket->header.size);
fakeBuffer->size = realBuffer->size; if (R_SUCCEEDED(rc)) {
*/ fakeBuffer->_updateUtilization();
}
}
}
realBuffer->Free();
} }
return ams::ResultSuccess(); return ams::ResultSuccess();
@ -255,7 +349,7 @@ namespace ams::mitm::btdrv {
BTDRV_LOG_FMT(" vid/pid: %04x:%04x", device.vid, device.pid); BTDRV_LOG_FMT(" vid/pid: %04x:%04x", device.vid, device.pid);
controller::ControllerType type = identifyController(device.vid, device.pid); auto type = identifyController(device.vid, device.pid);
switch (type) { switch (type) {
case controller::ControllerType_Joycon: case controller::ControllerType_Joycon:
@ -337,12 +431,16 @@ namespace ams::mitm::btdrv {
} }
// Signal our forwarder events // Signal our forwarder events
os::SignalSystemEvent(&g_btHidSystemEventFwd);
/*
if (!g_redirectEvents || g_preparingForSleep) { if (!g_redirectEvents || g_preparingForSleep) {
os::SignalSystemEvent(&g_btHidSystemEventFwd); os::SignalSystemEvent(&g_btHidSystemEventFwd);
} }
else { else {
os::SignalSystemEvent(&g_btHidSystemEventUser); os::SignalSystemEvent(&g_btHidSystemEventUser);
} }
*/
} }
} }
@ -354,7 +452,7 @@ namespace ams::mitm::btdrv {
//BTDRV_LOG_FMT("hid report event fired"); //BTDRV_LOG_FMT("hid report event fired");
// Translate all new incoming packets from the real HID buffer to Switch Pro controller format // Translate all new incoming packets from the real HID buffer to Switch Pro controller format
//TranslateHidReportPackets(g_realCircBuff, g_fakeCircBuff); TranslateHidReportPackets(g_realCircBuff, g_fakeCircBuff);
// Signal our forwarder events // Signal our forwarder events
//os::SignalSystemEvent(&btHidReportSystemEventUser); //os::SignalSystemEvent(&btHidReportSystemEventUser);
@ -552,19 +650,15 @@ namespace ams::mitm::btdrv {
Result BtdrvMitmService::WriteHidData(BluetoothAddress address, const sf::InPointerBuffer &buffer) { Result BtdrvMitmService::WriteHidData(BluetoothAddress address, const sf::InPointerBuffer &buffer) {
BTDRV_LOG_FMT("btdrv-mitm: WriteHidData (caller: %s)", this->client_info.program_id == ncm::SystemProgramId::Hid ? "HID" : "other"); //BTDRV_LOG_FMT("btdrv-mitm: WriteHidData (caller: %s)", this->client_info.program_id == ncm::SystemProgramId::Hid ? "HID" : "other");
if (this->client_info.program_id == ncm::SystemProgramId::Hid) { if (this->client_info.program_id == ncm::SystemProgramId::Hid) {
/* auto controller = locateController(&address);
Lookup controller type from address
if (is_switch_controller) { if (!controller->isSwitchController()) {
//forward command as usual BTDRV_LOG_FMT("btdrv-mitm: WriteHidData - Non-Switch controller");
} }
else {
//check outgoing packet type
//convert to equivalent format of target controller
}
*/
} }
R_ABORT_UNLESS(btdrvWriteHidDataFwd(this->forward_service.get(), R_ABORT_UNLESS(btdrvWriteHidDataFwd(this->forward_service.get(),
@ -673,7 +767,7 @@ namespace ams::mitm::btdrv {
g_realCircBuff = reinterpret_cast<bluetooth::CircularBuffer *>(shmemGetAddr(&g_realBtShmem)); g_realCircBuff = reinterpret_cast<bluetooth::CircularBuffer *>(shmemGetAddr(&g_realBtShmem));
BTDRV_LOG_FMT("Real shmem @ 0x%p", (void *)g_realCircBuff); BTDRV_LOG_FMT("Real shmem @ 0x%p", (void *)g_realCircBuff);
// Return the handle of our fake shared memory to the called instead // Return the handle of our fake shared memory to the caller instead
out_handle.SetValue(g_fakeBtShmem.handle); out_handle.SetValue(g_fakeBtShmem.handle);
//out_handle.SetValue(handle); //out_handle.SetValue(handle);

View file

@ -27,7 +27,7 @@ namespace controller {
bool isSwitchController(void); bool isSwitchController(void);
virtual Result initialize(void); virtual Result initialize(void);
virtual void convertReportFormat(HidReport *report) {}; virtual void convertReportFormat(const HidReport *inReport, HidReport *outReport) {};
protected: protected:
BluetoothController(const BluetoothAddress *address, ControllerType type); BluetoothController(const BluetoothAddress *address, ControllerType type);

View file

@ -1,6 +1,9 @@
#include "dualshock4.hpp" #include <cstring>
#include <cmath> #include <cmath>
#include "dualshock4.hpp"
#include "../btdrv_mitm_logging.hpp"
namespace controller { namespace controller {
@ -10,8 +13,33 @@ namespace controller {
} }
void Dualshock4Controller::convertReportFormat(HidReport *report) { Result Dualshock4Controller::initialize(void) {
BTDRV_LOG_FMT("Dualshock4Controller::initialize");
return BluetoothController::initialize();
}
void Dualshock4Controller::convertReportFormat(const HidReport *inReport, HidReport *outReport) {
auto ds4Data = reinterpret_cast<const Dualshock4ReportData *>(&inReport->data);
auto switchData = reinterpret_cast<SwitchReportData *>(&outReport->data);
outReport->type = 0x31;
outReport->id = 0x30;
switchData->report0x30.conn_info = 0x0;
switchData->report0x30.battery = 0x8;
switch(inReport->id) {
case 0x01:
handleInputReport0x01(ds4Data, switchData);
break;
case 0x11:
handleInputReport0x11(ds4Data, switchData);
break;
default:
break;
}
} }
void Dualshock4Controller::mapStickValues(JoystickPosition *dst, const Dualshock4StickData *src) { void Dualshock4Controller::mapStickValues(JoystickPosition *dst, const Dualshock4StickData *src) {
@ -33,12 +61,76 @@ namespace controller {
*/ */
} }
void Dualshock4Controller::handleInputReport0x01(const Dualshock4ReportData *data) { void Dualshock4Controller::handleInputReport0x01(const Dualshock4ReportData *src, SwitchReportData *dst) {
dst->report0x30.buttons.dpad_down = (src->report0x01.buttons.dpad == Dualshock4DPad_S) ||
(src->report0x01.buttons.dpad == Dualshock4DPad_SE) ||
(src->report0x01.buttons.dpad == Dualshock4DPad_SW);
dst->report0x30.buttons.dpad_up = (src->report0x01.buttons.dpad == Dualshock4DPad_N) ||
(src->report0x01.buttons.dpad == Dualshock4DPad_NE) ||
(src->report0x01.buttons.dpad == Dualshock4DPad_NW);
dst->report0x30.buttons.dpad_right = (src->report0x01.buttons.dpad == Dualshock4DPad_E) ||
(src->report0x01.buttons.dpad == Dualshock4DPad_NE) ||
(src->report0x01.buttons.dpad == Dualshock4DPad_SE);
dst->report0x30.buttons.dpad_left = (src->report0x01.buttons.dpad == Dualshock4DPad_W) ||
(src->report0x01.buttons.dpad == Dualshock4DPad_NW) ||
(src->report0x01.buttons.dpad == Dualshock4DPad_SW);
dst->report0x30.buttons.A = src->report0x01.buttons.circle;
dst->report0x30.buttons.B = src->report0x01.buttons.cross;
dst->report0x30.buttons.X = src->report0x01.buttons.triangle;
dst->report0x30.buttons.Y = src->report0x01.buttons.square;
dst->report0x30.buttons.R = src->report0x01.buttons.R1;
dst->report0x30.buttons.ZR = src->report0x01.buttons.R2;
dst->report0x30.buttons.L = src->report0x01.buttons.L1;
dst->report0x30.buttons.ZL = src->report0x01.buttons.L2;
dst->report0x30.buttons.minus = src->report0x01.buttons.share;
dst->report0x30.buttons.plus = src->report0x01.buttons.options;
dst->report0x30.buttons.lstick_press = src->report0x01.buttons.L3;
dst->report0x30.buttons.rstick_press = src->report0x01.buttons.R3;
dst->report0x30.buttons.capture = src->report0x01.buttons.tpad;
dst->report0x30.buttons.home = src->report0x01.buttons.ps;
} }
void Dualshock4Controller::handleInputReport0x11(const Dualshock4ReportData *data) { void Dualshock4Controller::handleInputReport0x11(const Dualshock4ReportData *src, SwitchReportData *dst) {
dst->report0x30.buttons.dpad_down = (src->report0x11.buttons.dpad == Dualshock4DPad_S) ||
(src->report0x11.buttons.dpad == Dualshock4DPad_SE) ||
(src->report0x11.buttons.dpad == Dualshock4DPad_SW);
dst->report0x30.buttons.dpad_up = (src->report0x11.buttons.dpad == Dualshock4DPad_N) ||
(src->report0x11.buttons.dpad == Dualshock4DPad_NE) ||
(src->report0x11.buttons.dpad == Dualshock4DPad_NW);
dst->report0x30.buttons.dpad_right = (src->report0x11.buttons.dpad == Dualshock4DPad_E) ||
(src->report0x11.buttons.dpad == Dualshock4DPad_NE) ||
(src->report0x11.buttons.dpad == Dualshock4DPad_SE);
dst->report0x30.buttons.dpad_left = (src->report0x11.buttons.dpad == Dualshock4DPad_W) ||
(src->report0x11.buttons.dpad == Dualshock4DPad_NW) ||
(src->report0x11.buttons.dpad == Dualshock4DPad_SW);
dst->report0x30.buttons.A = src->report0x11.buttons.circle;
dst->report0x30.buttons.B = src->report0x11.buttons.cross;
dst->report0x30.buttons.X = src->report0x11.buttons.triangle;
dst->report0x30.buttons.Y = src->report0x11.buttons.square;
dst->report0x30.buttons.R = src->report0x11.buttons.R1;
dst->report0x30.buttons.ZR = src->report0x11.buttons.R2;
dst->report0x30.buttons.L = src->report0x11.buttons.L1;
dst->report0x30.buttons.ZL = src->report0x11.buttons.L2;
dst->report0x30.buttons.minus = src->report0x11.buttons.share;
dst->report0x30.buttons.plus = src->report0x11.buttons.options;
dst->report0x30.buttons.lstick_press = src->report0x11.buttons.L3;
dst->report0x30.buttons.rstick_press = src->report0x11.buttons.R3;
dst->report0x30.buttons.capture = src->report0x11.buttons.tpad;
dst->report0x30.buttons.home = src->report0x11.buttons.ps;
} }
} }

View file

@ -1,5 +1,7 @@
#pragma once #pragma once
#include "bluetoothcontroller.hpp" #include "bluetoothcontroller.hpp"
#include "switchcontroller.hpp"
namespace controller { namespace controller {
@ -106,12 +108,14 @@ namespace controller {
Dualshock4Controller(const BluetoothAddress *address) : BluetoothController(address, ControllerType_Dualshock4) {}; Dualshock4Controller(const BluetoothAddress *address) : BluetoothController(address, ControllerType_Dualshock4) {};
void convertReportFormat(HidReport *report); Result initialize(void);
void convertReportFormat(const HidReport *inReport, HidReport *outReport);
private: private:
void mapStickValues(JoystickPosition *dst, const Dualshock4StickData *src); void mapStickValues(JoystickPosition *dst, const Dualshock4StickData *src);
void handleInputReport0x01(const Dualshock4ReportData *data); void handleInputReport0x01(const Dualshock4ReportData *src, SwitchReportData *dst);
void handleInputReport0x11(const Dualshock4ReportData *data); void handleInputReport0x11(const Dualshock4ReportData *src, SwitchReportData *dst);
}; };
} }

View file

@ -3,15 +3,96 @@
namespace controller { namespace controller {
/* enum BatteryLevel {
class SwitchController { BatteryLevel_Empty,
BatteryLevel_Critical,
public: BatteryLevel_Low,
BatteryLevel_Medium,
private: BatteryLevel_Full
};
union SwitchStickData {
struct __attribute__ ((__packed__)) {
uint16_t x : 12;
uint16_t : 0;
uint8_t : 8;
};
struct __attribute__ ((__packed__)) {
uint8_t : 8;
uint16_t : 4;
uint16_t y : 12;
};
};
struct SwitchButtonData {
uint8_t Y : 1;
uint8_t X : 1;
uint8_t B : 1;
uint8_t A : 1;
uint8_t : 2; // SR, SL (Right Joy)
uint8_t R : 1;
uint8_t ZR : 1;
uint8_t minus : 1;
uint8_t plus : 1;
uint8_t rstick_press : 1;
uint8_t lstick_press : 1;
uint8_t home : 1;
uint8_t capture : 1;
uint8_t : 0;
uint8_t dpad_down : 1;
uint8_t dpad_up : 1;
uint8_t dpad_right : 1;
uint8_t dpad_left : 1;
uint8_t : 2; // SR, SL (Left Joy)
uint8_t L : 1;
uint8_t ZL : 1;
};
struct Switch6AxisData {
uint16_t accel_x;
uint16_t accel_y;
uint16_t accel_z;
uint16_t gyro_1;
uint16_t gyro_2;
uint16_t gyro_3;
};
union SwitchReportData {
struct {
uint8_t conn_info : 4;
uint8_t battery : 4;
uint8_t timer;
SwitchButtonData buttons;
SwitchStickData left_stick;
SwitchStickData right_stick;
uint8_t vibrator;
struct {
uint8_t ack;
uint8_t id;
uint8_t reply;
uint8_t data[0x22];
} subcmd;
} report0x21;
struct {
uint8_t timer;
uint8_t conn_info : 4;
uint8_t battery : 4;
SwitchButtonData buttons;
SwitchStickData left_stick;
SwitchStickData right_stick;
uint8_t vibrator;
Switch6AxisData imu_0ms;
Switch6AxisData imu_5ms;
Switch6AxisData imu_10ms;
} report0x30;
}; };
*/
class SwitchProController : public BluetoothController { class SwitchProController : public BluetoothController {
@ -28,8 +109,8 @@ namespace controller {
public: public:
static constexpr const HardwareID hardwareIds[] = { static constexpr const HardwareID hardwareIds[] = {
{0x057e, 2006}, // Official Joycon(L) Controller {0x057e, 0x2006}, // Official Joycon(L) Controller
{0x057e, 2007}, // Official Joycon(R) Controller {0x057e, 0x2007}, // Official Joycon(R) Controller
}; };
JoyconController(const BluetoothAddress *address) : BluetoothController(address, ControllerType_Joycon) {}; JoyconController(const BluetoothAddress *address) : BluetoothController(address, ControllerType_Joycon) {};

View file

@ -8,6 +8,8 @@
namespace controller { namespace controller {
Result WiiController::initialize(void) { Result WiiController::initialize(void) {
BluetoothController::initialize();
BTDRV_LOG_FMT("WiiController::initialize"); BTDRV_LOG_FMT("WiiController::initialize");
return setPlayerLeds(&m_address, WiiControllerLEDs_P1); return setPlayerLeds(&m_address, WiiControllerLEDs_P1);
} }

View file

@ -10,6 +10,23 @@ namespace controller {
WiiControllerLEDs_P4 = 0x80, WiiControllerLEDs_P4 = 0x80,
}; };
struct WiiButtonData {
uint8_t dpad_left : 1;
uint8_t dpad_right : 1;
uint8_t dpad_down : 1;
uint8_t dpad_up : 1;
uint8_t plus : 1;
uint8_t : 0;
uint8_t two : 1;
uint8_t one : 1;
uint8_t B : 1;
uint8_t A : 1;
uint8_t minus : 1;
uint8_t : 2;
uint8_t home : 1;
};
class WiiController : public BluetoothController { class WiiController : public BluetoothController {
public: public:

View file

@ -2,6 +2,43 @@
namespace controller { namespace controller {
void WiimoteController::convertReportFormat(const HidReport *inReport, HidReport *outReport) {
auto wiiData = reinterpret_cast<const WiimoteReportData *>(&inReport->data);
auto switchData = reinterpret_cast<SwitchReportData *>(&outReport->data);
outReport->type = 0x31;
outReport->id = 0x30;
switchData->report0x30.conn_info = 0x0;
switchData->report0x30.battery = 0x8;
switch(inReport->id) {
case 0x30:
handleInputReport0x30(wiiData, switchData);
break;
default:
break;
}
}
void WiimoteController::handleInputReport0x30(const WiimoteReportData *src, SwitchReportData *dst) {
dst->report0x30.buttons.dpad_down = src->report0x30.buttons.dpad_down;
dst->report0x30.buttons.dpad_up = src->report0x30.buttons.dpad_up;
dst->report0x30.buttons.dpad_right = src->report0x30.buttons.dpad_right;
dst->report0x30.buttons.dpad_left = src->report0x30.buttons.dpad_left;
dst->report0x30.buttons.A = src->report0x30.buttons.two;
dst->report0x30.buttons.B = src->report0x30.buttons.one;
dst->report0x30.buttons.R = src->report0x30.buttons.B;
dst->report0x30.buttons.L = src->report0x30.buttons.A;
dst->report0x30.buttons.minus = src->report0x30.buttons.minus;
dst->report0x30.buttons.plus = src->report0x30.buttons.plus;
dst->report0x30.buttons.home = src->report0x30.buttons.home;
}
} }

View file

@ -1,8 +1,17 @@
#pragma once #pragma once
#include "wiicontroller.hpp" #include "wiicontroller.hpp"
#include "switchcontroller.hpp"
namespace controller { namespace controller {
union WiimoteReportData {
struct {
WiiButtonData buttons;
uint8_t _unk;
} report0x30;
};
class WiimoteController : public WiiController { class WiimoteController : public WiiController {
public: public:
@ -12,8 +21,10 @@ namespace controller {
WiimoteController(const BluetoothAddress *address) : WiiController(address, ControllerType_Wiimote) {}; WiimoteController(const BluetoothAddress *address) : WiiController(address, ControllerType_Wiimote) {};
private: void convertReportFormat(const HidReport *inReport, HidReport *outReport);
private:
void handleInputReport0x30(const WiimoteReportData *src, SwitchReportData *dst);
}; };
} }

View file

@ -7,9 +7,11 @@
namespace controller { namespace controller {
Result WiiUProController::initialize(void) { Result WiiUProController::initialize(void) {
BTDRV_LOG_FMT("WiiUProController::initialize");
WiiController::initialize(); WiiController::initialize();
//setPlayerLeds(&m_address, WiiControllerLEDs_P1);
BTDRV_LOG_FMT("WiiUProController::initialize");
// This should actually probably be run in response to report 0x20
R_TRY(sendInit1(&m_address)); R_TRY(sendInit1(&m_address));
R_TRY(sendInit2(&m_address)); R_TRY(sendInit2(&m_address));
R_TRY(setReportMode(&m_address, 0x34)); R_TRY(setReportMode(&m_address, 0x34));
@ -27,4 +29,63 @@ namespace controller {
return writeMemory(address, 0x04a400fb, data, sizeof(data)); return writeMemory(address, 0x04a400fb, data, sizeof(data));
} }
void WiiUProController::convertReportFormat(const HidReport *inReport, HidReport *outReport) {
auto wiiUData = reinterpret_cast<const WiiUProReportData *>(&inReport->data);
auto switchData = reinterpret_cast<SwitchReportData *>(&outReport->data);
outReport->type = 0x31;
outReport->id = 0x30;
switchData->report0x30.conn_info = 0x0;
switchData->report0x30.battery = 0x8;
switch(inReport->id) {
case 0x20: //extension connected
handleInputReport0x20(wiiUData, switchData);
break;
case 0x22: // Acknowledgement
break;
case 0x32: // Buttons + Ext bytes
break;
case 0x34: // Buttons + Ext bytes
handleInputReport0x34(wiiUData, switchData);
break;
default:
break;
}
}
void WiiUProController::handleInputReport0x20(const WiiUProReportData *src, SwitchReportData *dst) {
}
void WiiUProController::handleInputReport0x34(const WiiUProReportData *src, SwitchReportData *dst) {
dst->report0x30.buttons.dpad_down = !src->report0x34.buttons.dpad_down;
dst->report0x30.buttons.dpad_up = !src->report0x34.buttons.dpad_up;
dst->report0x30.buttons.dpad_right = !src->report0x34.buttons.dpad_right;
dst->report0x30.buttons.dpad_left = !src->report0x34.buttons.dpad_left;
dst->report0x30.buttons.A = !src->report0x34.buttons.A;
dst->report0x30.buttons.B = !src->report0x34.buttons.B;
dst->report0x30.buttons.X = !src->report0x34.buttons.X;
dst->report0x30.buttons.Y = !src->report0x34.buttons.Y;
dst->report0x30.buttons.R = !src->report0x34.buttons.R;
dst->report0x30.buttons.ZR = !src->report0x34.buttons.ZR;
dst->report0x30.buttons.L = !src->report0x34.buttons.L;
dst->report0x30.buttons.ZL = !src->report0x34.buttons.ZL;
dst->report0x30.buttons.minus = !src->report0x34.buttons.minus;
dst->report0x30.buttons.plus = !src->report0x34.buttons.plus;
dst->report0x30.buttons.lstick_press = !src->report0x34.buttons.lstick_press;
dst->report0x30.buttons.rstick_press = !src->report0x34.buttons.rstick_press;
dst->report0x30.buttons.home = !src->report0x34.buttons.home;
}
} }

View file

@ -1,8 +1,59 @@
#pragma once #pragma once
#include "wiicontroller.hpp" #include "wiicontroller.hpp"
#include "switchcontroller.hpp"
namespace controller { namespace controller {
struct WiiUProButtonData {
uint8_t : 1;
uint8_t R : 1;
uint8_t plus : 1;
uint8_t home : 1;
uint8_t minus : 1;
uint8_t L : 1;
uint8_t dpad_down : 1;
uint8_t dpad_right : 1;
uint8_t dpad_up : 1;
uint8_t dpad_left : 1;
uint8_t ZR : 1;
uint8_t X : 1;
uint8_t A : 1;
uint8_t Y : 1;
uint8_t B : 1;
uint8_t ZL : 1;
uint8_t rstick_press : 1;
uint8_t lstick_press : 1;
uint8_t : 0;
};
union WiiUProReportData {
struct {
WiiButtonData core_buttons;
/*
uint8_t left_stick_x : 6;
uint8_t right_stick_x2 : 2;
uint8_t left_stick_y : 6;
uint8_t right_stick_x1 : 2;
uint8_t right_stick_x0 : 1;
uint8_t left_trigger_1 : 2;
uint8_t right_stick_y : 5;
uint8_t left_trigger_0 : 3;
uint8_t right_trigger : 5;
*/
uint16_t left_stick_x;
uint16_t right_stick_x;
uint16_t left_stick_y;
uint16_t right_stick_y;
WiiUProButtonData buttons;
} report0x34;
};
class WiiUProController : public WiiController { class WiiUProController : public WiiController {
public: public:
@ -12,12 +63,17 @@ namespace controller {
WiiUProController(const BluetoothAddress *address) : WiiController(address, ControllerType_WiiUPro) {}; WiiUProController(const BluetoothAddress *address) : WiiController(address, ControllerType_WiiUPro) {};
void convertReportFormat(const HidReport *inReport, HidReport *outReport);
Result initialize(void); Result initialize(void);
private: private:
Result sendInit1(const BluetoothAddress *address); Result sendInit1(const BluetoothAddress *address);
Result sendInit2(const BluetoothAddress *address); Result sendInit2(const BluetoothAddress *address);
void handleInputReport0x20(const WiiUProReportData *src, SwitchReportData *dst);
void handleInputReport0x34(const WiiUProReportData *src, SwitchReportData *dst);
}; };
} }

View file

@ -1,3 +1,6 @@
#include <cstring>
#include <cmath>
#include "xboxone.hpp" #include "xboxone.hpp"
namespace controller { namespace controller {
@ -8,16 +11,23 @@ namespace controller {
} }
void XboxOneController::convertReportFormat(HidReport *report) { void XboxOneController::convertReportFormat(const HidReport *inReport, HidReport *outReport) {
const XboxOneReportData *reportData = reinterpret_cast<const XboxOneReportData *>(&report->data); auto xboxData = reinterpret_cast<const XboxOneReportData *>(&inReport->data);
auto switchData = reinterpret_cast<SwitchReportData *>(&outReport->data);
switch(report->id) { outReport->type = 0x31;
outReport->id = 0x30;
switchData->report0x30.conn_info = 0x0;
switchData->report0x30.battery = 0x8;
switch(inReport->id) {
case 0x01: case 0x01:
handleInputReport0x01(reportData); handleInputReport0x01(xboxData, switchData);
break; break;
case 0x02: case 0x02:
handleInputReport0x02(reportData); handleInputReport0x02(xboxData, switchData);
break; break;
default: default:
@ -44,12 +54,41 @@ namespace controller {
*/ */
} }
void XboxOneController::handleInputReport0x01(const XboxOneReportData *data) { void XboxOneController::handleInputReport0x01(const XboxOneReportData *src, SwitchReportData *dst) {
dst->report0x30.buttons.dpad_down = (src->report0x01.buttons.dpad == XboxOneDPad_S) ||
(src->report0x01.buttons.dpad == XboxOneDPad_SE) ||
(src->report0x01.buttons.dpad == XboxOneDPad_SW);
dst->report0x30.buttons.dpad_up = (src->report0x01.buttons.dpad == XboxOneDPad_N) ||
(src->report0x01.buttons.dpad == XboxOneDPad_NE) ||
(src->report0x01.buttons.dpad == XboxOneDPad_NW);
dst->report0x30.buttons.dpad_right = (src->report0x01.buttons.dpad == XboxOneDPad_E) ||
(src->report0x01.buttons.dpad == XboxOneDPad_NE) ||
(src->report0x01.buttons.dpad == XboxOneDPad_SE);
dst->report0x30.buttons.dpad_left = (src->report0x01.buttons.dpad == XboxOneDPad_W) ||
(src->report0x01.buttons.dpad == XboxOneDPad_NW) ||
(src->report0x01.buttons.dpad == XboxOneDPad_SW);
dst->report0x30.buttons.A = src->report0x01.buttons.B;
dst->report0x30.buttons.B = src->report0x01.buttons.A;
dst->report0x30.buttons.X = src->report0x01.buttons.Y;
dst->report0x30.buttons.Y = src->report0x01.buttons.X;
dst->report0x30.buttons.R = src->report0x01.buttons.RB;
dst->report0x30.buttons.ZR = src->report0x01.right_trigger > 0;
dst->report0x30.buttons.L = src->report0x01.buttons.LB;
dst->report0x30.buttons.ZL = src->report0x01.left_trigger > 0;
dst->report0x30.buttons.minus = src->report0x01.buttons.view;
dst->report0x30.buttons.plus = src->report0x01.buttons.menu;
dst->report0x30.buttons.lstick_press = src->report0x01.buttons.lstick_press;
dst->report0x30.buttons.rstick_press = src->report0x01.buttons.rstick_press;
} }
void XboxOneController::handleInputReport0x02(const XboxOneReportData *data) { void XboxOneController::handleInputReport0x02(const XboxOneReportData *src, SwitchReportData *dst) {
dst->report0x30.buttons.home = src->report0x02.guide;
} }
} }

View file

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "bluetoothcontroller.hpp" #include "bluetoothcontroller.hpp"
#include "switchcontroller.hpp"
namespace controller { namespace controller {
@ -61,12 +62,12 @@ namespace controller {
XboxOneController(const BluetoothAddress *address) : BluetoothController(address, ControllerType_XboxOne) {}; XboxOneController(const BluetoothAddress *address) : BluetoothController(address, ControllerType_XboxOne) {};
void convertReportFormat(HidReport *report); void convertReportFormat(const HidReport *inReport, HidReport *outReport);
private: private:
void mapStickValues(JoystickPosition *dst, const XboxOneStickData *src); void mapStickValues(JoystickPosition *dst, const XboxOneStickData *src);
void handleInputReport0x01(const XboxOneReportData *data); void handleInputReport0x01(const XboxOneReportData *src, SwitchReportData *dst);
void handleInputReport0x02(const XboxOneReportData *data); void handleInputReport0x02(const XboxOneReportData *src, SwitchReportData *dst);
}; };