mirror of
https://github.com/ndeadly/MissionControl
synced 2024-11-23 04:43:10 +00:00
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:
parent
d75cc58ac1
commit
bcc34cf5eb
13 changed files with 579 additions and 84 deletions
|
@ -83,68 +83,162 @@ namespace ams::mitm::btdrv {
|
|||
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) {
|
||||
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;
|
||||
|
||||
while (true) {
|
||||
if (realBuffer->readOffset == writeOffset)
|
||||
break;
|
||||
|
||||
// Read packet from real buffer
|
||||
realPacket = reinterpret_cast<BufferPacket *>(realBuffer->Read());
|
||||
// Get packet from real buffer
|
||||
//realPacket = reinterpret_cast<bluetooth::CircularBufferPacket *>(realBuffer->_read());
|
||||
realPacket = reinterpret_cast<bluetooth::CircularBufferPacket *>(&realBuffer->data[realBuffer->readOffset]);
|
||||
if (!realPacket)
|
||||
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
|
||||
/*
|
||||
controller = locateController(hos::GetVersion() < hos::Version_9_0_0 ? &realPacket->data.address : &realPacket->data.v2.address);
|
||||
if (!controller)
|
||||
//BTDRV_LOG_DATA(&realPacket->data, realPacket->header.size);
|
||||
//BTDRV_LOG_DATA(realPacket, realPacket->header.size + sizeof(bluetooth::CircularBufferPacketHeader));
|
||||
//BTDRV_LOG_FMT("fakeBuffer: [%d] writing %d bytes to data[%d]", realPacket->header.type, realPacket->header.size + sizeof(bluetooth::CircularBufferPacketHeader), fakeBuffer->writeOffset);
|
||||
|
||||
if (realPacket->header.type == 0xff) {
|
||||
//BTDRV_LOG_FMT("0xff packet received");
|
||||
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(inReport, outReport);
|
||||
|
||||
// Copy and correct packet header
|
||||
/*
|
||||
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;
|
||||
*/
|
||||
//BTDRV_LOG_DATA(g_fakeReportData, sizeof(g_fakeReportBuffer));
|
||||
|
||||
/*
|
||||
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) + sizeof(bluetooth::CircularBufferPacketHeader) <= fakeBuffer->GetWriteableSize()) {
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
/*
|
||||
os::LockSdkMutex(&realBuffer->mutex);
|
||||
// Write translated packet to fake buffer
|
||||
rc = fakeBuffer->_write(4, g_fakeReportData, sizeof(g_fakeReportBuffer));
|
||||
}
|
||||
}
|
||||
|
||||
u32 writeOffset = realBuffer->writeOffset;
|
||||
u32 readOffset = realBuffer->readOffset;
|
||||
s64 size = realBuffer->size;
|
||||
std::memcpy(&fakeBuffer->data[fakeBuffer->writeOffset], &realBuffer->data[readOffset], writeOffset-readOffset);
|
||||
realBuffer->readOffset = writeOffset;
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
fakeBuffer->_updateUtilization();
|
||||
}
|
||||
}
|
||||
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;
|
||||
fakeBuffer->size = realBuffer->size;
|
||||
*/
|
||||
rc = fakeBuffer->_write(realPacket->header.type, &realPacket->data, realPacket->header.size);
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
fakeBuffer->_updateUtilization();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
realBuffer->Free();
|
||||
}
|
||||
|
||||
return ams::ResultSuccess();
|
||||
|
@ -255,7 +349,7 @@ namespace ams::mitm::btdrv {
|
|||
|
||||
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) {
|
||||
case controller::ControllerType_Joycon:
|
||||
|
@ -337,12 +431,16 @@ namespace ams::mitm::btdrv {
|
|||
}
|
||||
|
||||
// Signal our forwarder events
|
||||
os::SignalSystemEvent(&g_btHidSystemEventFwd);
|
||||
|
||||
/*
|
||||
if (!g_redirectEvents || g_preparingForSleep) {
|
||||
os::SignalSystemEvent(&g_btHidSystemEventFwd);
|
||||
}
|
||||
else {
|
||||
os::SignalSystemEvent(&g_btHidSystemEventUser);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -354,7 +452,7 @@ namespace ams::mitm::btdrv {
|
|||
//BTDRV_LOG_FMT("hid report event fired");
|
||||
|
||||
// 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
|
||||
//os::SignalSystemEvent(&btHidReportSystemEventUser);
|
||||
|
@ -552,19 +650,15 @@ namespace ams::mitm::btdrv {
|
|||
|
||||
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) {
|
||||
/*
|
||||
Lookup controller type from address
|
||||
if (is_switch_controller) {
|
||||
//forward command as usual
|
||||
auto controller = locateController(&address);
|
||||
|
||||
if (!controller->isSwitchController()) {
|
||||
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(),
|
||||
|
@ -673,7 +767,7 @@ namespace ams::mitm::btdrv {
|
|||
g_realCircBuff = reinterpret_cast<bluetooth::CircularBuffer *>(shmemGetAddr(&g_realBtShmem));
|
||||
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(handle);
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ namespace controller {
|
|||
bool isSwitchController(void);
|
||||
|
||||
virtual Result initialize(void);
|
||||
virtual void convertReportFormat(HidReport *report) {};
|
||||
virtual void convertReportFormat(const HidReport *inReport, HidReport *outReport) {};
|
||||
|
||||
protected:
|
||||
BluetoothController(const BluetoothAddress *address, ControllerType type);
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
#include "dualshock4.hpp"
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
|
||||
#include "dualshock4.hpp"
|
||||
#include "../btdrv_mitm_logging.hpp"
|
||||
|
||||
|
||||
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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
#include "bluetoothcontroller.hpp"
|
||||
#include "switchcontroller.hpp"
|
||||
|
||||
|
||||
namespace controller {
|
||||
|
||||
|
@ -106,12 +108,14 @@ namespace controller {
|
|||
|
||||
Dualshock4Controller(const BluetoothAddress *address) : BluetoothController(address, ControllerType_Dualshock4) {};
|
||||
|
||||
void convertReportFormat(HidReport *report);
|
||||
Result initialize(void);
|
||||
|
||||
void convertReportFormat(const HidReport *inReport, HidReport *outReport);
|
||||
|
||||
private:
|
||||
void mapStickValues(JoystickPosition *dst, const Dualshock4StickData *src);
|
||||
void handleInputReport0x01(const Dualshock4ReportData *data);
|
||||
void handleInputReport0x11(const Dualshock4ReportData *data);
|
||||
void handleInputReport0x01(const Dualshock4ReportData *src, SwitchReportData *dst);
|
||||
void handleInputReport0x11(const Dualshock4ReportData *src, SwitchReportData *dst);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -3,15 +3,96 @@
|
|||
|
||||
namespace controller {
|
||||
|
||||
/*
|
||||
class SwitchController {
|
||||
|
||||
public:
|
||||
|
||||
private:
|
||||
|
||||
enum BatteryLevel {
|
||||
BatteryLevel_Empty,
|
||||
BatteryLevel_Critical,
|
||||
BatteryLevel_Low,
|
||||
BatteryLevel_Medium,
|
||||
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 {
|
||||
|
||||
|
@ -28,8 +109,8 @@ namespace controller {
|
|||
|
||||
public:
|
||||
static constexpr const HardwareID hardwareIds[] = {
|
||||
{0x057e, 2006}, // Official Joycon(L) Controller
|
||||
{0x057e, 2007}, // Official Joycon(R) Controller
|
||||
{0x057e, 0x2006}, // Official Joycon(L) Controller
|
||||
{0x057e, 0x2007}, // Official Joycon(R) Controller
|
||||
};
|
||||
|
||||
JoyconController(const BluetoothAddress *address) : BluetoothController(address, ControllerType_Joycon) {};
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
namespace controller {
|
||||
|
||||
Result WiiController::initialize(void) {
|
||||
BluetoothController::initialize();
|
||||
|
||||
BTDRV_LOG_FMT("WiiController::initialize");
|
||||
return setPlayerLeds(&m_address, WiiControllerLEDs_P1);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,23 @@ namespace controller {
|
|||
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 {
|
||||
|
||||
public:
|
||||
|
|
|
@ -2,6 +2,43 @@
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,8 +1,17 @@
|
|||
#pragma once
|
||||
#include "wiicontroller.hpp"
|
||||
#include "switchcontroller.hpp"
|
||||
|
||||
namespace controller {
|
||||
|
||||
union WiimoteReportData {
|
||||
struct {
|
||||
WiiButtonData buttons;
|
||||
uint8_t _unk;
|
||||
} report0x30;
|
||||
};
|
||||
|
||||
|
||||
class WiimoteController : public WiiController {
|
||||
|
||||
public:
|
||||
|
@ -12,8 +21,10 @@ namespace controller {
|
|||
|
||||
WiimoteController(const BluetoothAddress *address) : WiiController(address, ControllerType_Wiimote) {};
|
||||
|
||||
private:
|
||||
void convertReportFormat(const HidReport *inReport, HidReport *outReport);
|
||||
|
||||
private:
|
||||
void handleInputReport0x30(const WiimoteReportData *src, SwitchReportData *dst);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -7,9 +7,11 @@
|
|||
namespace controller {
|
||||
|
||||
Result WiiUProController::initialize(void) {
|
||||
BTDRV_LOG_FMT("WiiUProController::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(sendInit2(&m_address));
|
||||
R_TRY(setReportMode(&m_address, 0x34));
|
||||
|
@ -27,4 +29,63 @@ namespace controller {
|
|||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,8 +1,59 @@
|
|||
#pragma once
|
||||
#include "wiicontroller.hpp"
|
||||
#include "switchcontroller.hpp"
|
||||
|
||||
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 {
|
||||
|
||||
public:
|
||||
|
@ -12,12 +63,17 @@ namespace controller {
|
|||
|
||||
WiiUProController(const BluetoothAddress *address) : WiiController(address, ControllerType_WiiUPro) {};
|
||||
|
||||
void convertReportFormat(const HidReport *inReport, HidReport *outReport);
|
||||
|
||||
Result initialize(void);
|
||||
|
||||
private:
|
||||
Result sendInit1(const BluetoothAddress *address);
|
||||
Result sendInit2(const BluetoothAddress *address);
|
||||
|
||||
void handleInputReport0x20(const WiiUProReportData *src, SwitchReportData *dst);
|
||||
void handleInputReport0x34(const WiiUProReportData *src, SwitchReportData *dst);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
#include <cstring>
|
||||
#include <cmath>
|
||||
|
||||
#include "xboxone.hpp"
|
||||
|
||||
namespace controller {
|
||||
|
@ -8,16 +11,23 @@ namespace controller {
|
|||
|
||||
}
|
||||
|
||||
void XboxOneController::convertReportFormat(HidReport *report) {
|
||||
const XboxOneReportData *reportData = reinterpret_cast<const XboxOneReportData *>(&report->data);
|
||||
void XboxOneController::convertReportFormat(const HidReport *inReport, HidReport *outReport) {
|
||||
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:
|
||||
handleInputReport0x01(reportData);
|
||||
handleInputReport0x01(xboxData, switchData);
|
||||
break;
|
||||
|
||||
case 0x02:
|
||||
handleInputReport0x02(reportData);
|
||||
handleInputReport0x02(xboxData, switchData);
|
||||
break;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
#include "bluetoothcontroller.hpp"
|
||||
#include "switchcontroller.hpp"
|
||||
|
||||
namespace controller {
|
||||
|
||||
|
@ -61,12 +62,12 @@ namespace controller {
|
|||
|
||||
XboxOneController(const BluetoothAddress *address) : BluetoothController(address, ControllerType_XboxOne) {};
|
||||
|
||||
void convertReportFormat(HidReport *report);
|
||||
void convertReportFormat(const HidReport *inReport, HidReport *outReport);
|
||||
|
||||
private:
|
||||
void mapStickValues(JoystickPosition *dst, const XboxOneStickData *src);
|
||||
void handleInputReport0x01(const XboxOneReportData *data);
|
||||
void handleInputReport0x02(const XboxOneReportData *data);
|
||||
void handleInputReport0x01(const XboxOneReportData *src, SwitchReportData *dst);
|
||||
void handleInputReport0x02(const XboxOneReportData *src, SwitchReportData *dst);
|
||||
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue