Skip to content

Commit

Permalink
nsyshid: Emulate Skylander Portal
Browse files Browse the repository at this point in the history
  • Loading branch information
deReeperJosh committed Sep 20, 2023
1 parent 1d39855 commit 68e7612
Show file tree
Hide file tree
Showing 16 changed files with 1,336 additions and 48 deletions.
2 changes: 2 additions & 0 deletions src/Cafe/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,8 @@ add_library(CemuCafe
OS/libs/nsyshid/BackendLibusb.h
OS/libs/nsyshid/BackendWindowsHID.cpp
OS/libs/nsyshid/BackendWindowsHID.h
OS/libs/nsyshid/Skylander.cpp
OS/libs/nsyshid/Skylander.h
OS/libs/nsyskbd/nsyskbd.cpp
OS/libs/nsyskbd/nsyskbd.h
OS/libs/nsysnet/nsysnet.cpp
Expand Down
39 changes: 36 additions & 3 deletions src/Cafe/OS/libs/nsyshid/Backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,34 @@ namespace nsyshid
/* +0x12 */ uint16be maxPacketSizeTX;
} HID_t;

struct TransferCommand
{
bool isFake;
sint32 expectedTimeMillis;
};

struct ReadMessage : TransferCommand
{
uint8* data;
sint32 length;
sint32 bytesRead;
};

struct WriteMessage : TransferCommand
{
uint8* data;
sint32 length;
sint32 bytesWritten;
};

struct ReportMessage : TransferCommand
{
uint8* reportData;
sint32 length;
uint8* originalData;
sint32 originalLength;
};

static_assert(offsetof(HID_t, vendorId) == 0x8, "");
static_assert(offsetof(HID_t, productId) == 0xA, "");
static_assert(offsetof(HID_t, ifIndex) == 0xC, "");
Expand Down Expand Up @@ -69,7 +97,7 @@ namespace nsyshid
ErrorTimeout,
};

virtual ReadResult Read(uint8* data, sint32 length, sint32& bytesRead) = 0;
virtual ReadResult Read(ReadMessage* message) = 0;

enum class WriteResult
{
Expand All @@ -78,7 +106,7 @@ namespace nsyshid
ErrorTimeout,
};

virtual WriteResult Write(uint8* data, sint32 length, sint32& bytesWritten) = 0;
virtual WriteResult Write(WriteMessage* message) = 0;

virtual bool GetDescriptor(uint8 descType,
uint8 descIndex,
Expand All @@ -88,7 +116,7 @@ namespace nsyshid

virtual bool SetProtocol(uint32 ifIndef, uint32 protocol) = 0;

virtual bool SetReport(uint8* reportData, sint32 length, uint8* originalData, sint32 originalLength) = 0;
virtual bool SetReport(ReportMessage* message) = 0;
};

class Backend {
Expand All @@ -113,6 +141,11 @@ namespace nsyshid

virtual bool IsInitialisedOk() = 0;

// Found Devices
bool m_foundSkylander = false;
bool m_foundInfinity = false;
bool m_foundDimensions = false;

protected:
// try to attach a device - only works if this backend is attached
bool AttachDevice(const std::shared_ptr<Device>& device);
Expand Down
46 changes: 29 additions & 17 deletions src/Cafe/OS/libs/nsyshid/BackendLibusb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,8 +243,21 @@ namespace nsyshid::backend::libusb
}
if (desc.idVendor == 0x0e6f && desc.idProduct == 0x0241)
{
m_foundDimensions = true;
cemuLog_logDebug(LogType::Force,
"nsyshid::BackendLibusb::CheckAndCreateDevice(): lego dimensions portal detected");
"nsyshid::BackendLibusb::CheckAndCreateDevice(): Lego Dimensions toypad detected");
}
if (desc.idVendor == 0x1430 && desc.idProduct == 0x0150)
{
m_foundSkylander = true;
cemuLog_logDebug(LogType::Force,
"nsyshid::BackendLibusb::CheckAndCreateDevice(): Skylander portal detected");
}
if (desc.idVendor == 0x0e6f && desc.idProduct == 0x0129)
{
m_foundInfinity = true;
cemuLog_logDebug(LogType::Force,
"nsyshid::BackendLibusb::CheckAndCreateDevice(): Infinity Base detected");
}
auto device = std::make_shared<DeviceLibusb>(m_ctx,
desc.idVendor,
Expand Down Expand Up @@ -471,7 +484,7 @@ namespace nsyshid::backend::libusb
return m_libusbHandle != nullptr && m_handleInUseCounter >= 0;
}

Device::ReadResult DeviceLibusb::Read(uint8* data, sint32 length, sint32& bytesRead)
Device::ReadResult DeviceLibusb::Read(ReadMessage* message)
{
auto handleLock = AquireHandleLock();
if (!handleLock->IsValid())
Expand All @@ -488,8 +501,8 @@ namespace nsyshid::backend::libusb
{
ret = libusb_bulk_transfer(handleLock->GetHandle(),
this->m_libusbEndpointIn,
data,
length,
message->data,
message->length,
&actualLength,
timeout);
}
Expand All @@ -500,8 +513,8 @@ namespace nsyshid::backend::libusb
// success
cemuLog_logDebug(LogType::Force, "nsyshid::DeviceLibusb::read(): read {} of {} bytes",
actualLength,
length);
bytesRead = actualLength;
message->length);
message->bytesRead = actualLength;
return ReadResult::Success;
}
cemuLog_logDebug(LogType::Force,
Expand All @@ -510,7 +523,7 @@ namespace nsyshid::backend::libusb
return ReadResult::Error;
}

Device::WriteResult DeviceLibusb::Write(uint8* data, sint32 length, sint32& bytesWritten)
Device::WriteResult DeviceLibusb::Write(WriteMessage* message)
{
auto handleLock = AquireHandleLock();
if (!handleLock->IsValid())
Expand All @@ -520,23 +533,23 @@ namespace nsyshid::backend::libusb
return WriteResult::Error;
}

bytesWritten = 0;
message->bytesWritten = 0;
int actualLength = 0;
int ret = libusb_bulk_transfer(handleLock->GetHandle(),
this->m_libusbEndpointOut,
data,
length,
message->data,
message->length,
&actualLength,
0);

if (ret == 0)
{
// success
bytesWritten = actualLength;
message->bytesWritten = actualLength;
cemuLog_logDebug(LogType::Force,
"nsyshid::DeviceLibusb::write(): wrote {} of {} bytes",
bytesWritten,
length);
message->bytesWritten,
message->length);
return WriteResult::Success;
}
cemuLog_logDebug(LogType::Force,
Expand Down Expand Up @@ -713,8 +726,7 @@ namespace nsyshid::backend::libusb
return true;
}

bool DeviceLibusb::SetReport(uint8* reportData, sint32 length, uint8* originalData,
sint32 originalLength)
bool DeviceLibusb::SetReport(ReportMessage* message)
{
auto handleLock = AquireHandleLock();
if (!handleLock->IsValid())
Expand All @@ -731,8 +743,8 @@ namespace nsyshid::backend::libusb
bRequest,
wValue,
wIndex,
reportData,
length,
message->reportData,
message->length,
timeout);
#endif

Expand Down
6 changes: 3 additions & 3 deletions src/Cafe/OS/libs/nsyshid/BackendLibusb.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ namespace nsyshid::backend::libusb

bool IsOpened() override;

ReadResult Read(uint8* data, sint32 length, sint32& bytesRead) override;
ReadResult Read(ReadMessage* message) override;

WriteResult Write(uint8* data, sint32 length, sint32& bytesWritten) override;
WriteResult Write(WriteMessage* message) override;

bool GetDescriptor(uint8 descType,
uint8 descIndex,
Expand All @@ -75,7 +75,7 @@ namespace nsyshid::backend::libusb

bool SetProtocol(uint32 ifIndex, uint32 protocol) override;

bool SetReport(uint8* reportData, sint32 length, uint8* originalData, sint32 originalLength) override;
bool SetReport(ReportMessage* message) override;

uint8 m_libusbBusNumber;
uint8 m_libusbDeviceAddress;
Expand Down
40 changes: 29 additions & 11 deletions src/Cafe/OS/libs/nsyshid/BackendWindowsHID.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,24 @@ namespace nsyshid::backend::windows
if (HidD_GetAttributes(hDevice, &hidAttr) == FALSE)
return nullptr;

if (hidAttr.VendorID == 0x0e6f && hidAttr.ProductID == 0x0241)
{
m_foundDimensions = true;
cemuLog_logDebug(LogType::Force,
"nsyshid::BackendLibusb::CheckAndCreateDevice(): Lego Dimensions toypad detected");
}
if (hidAttr.VendorID == 0x1430 && hidAttr.ProductID == 0x0150)
{
m_foundSkylander = true;
cemuLog_logDebug(LogType::Force,
"nsyshid::BackendLibusb::CheckAndCreateDevice(): Skylander portal detected");
}
if (hidAttr.VendorID == 0x0e6f && hidAttr.ProductID == 0x0129)
{
m_foundInfinity = true;
cemuLog_logDebug(LogType::Force,
"nsyshid::BackendLibusb::CheckAndCreateDevice(): Infinity Base detected");
}
auto device = std::make_shared<DeviceWindowsHID>(hidAttr.VendorID,
hidAttr.ProductID,
1,
Expand Down Expand Up @@ -196,20 +214,20 @@ namespace nsyshid::backend::windows
return m_hFile != INVALID_HANDLE_VALUE;
}

Device::ReadResult DeviceWindowsHID::Read(uint8* data, sint32 length, sint32& bytesRead)
Device::ReadResult DeviceWindowsHID::Read(ReadMessage* message)
{
bytesRead = 0;
DWORD bt;
OVERLAPPED ovlp = {0};
ovlp.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

uint8* tempBuffer = (uint8*)malloc(length + 1);
uint8* tempBuffer = (uint8*)malloc(message->length + 1);
sint32 transferLength = 0; // minus report byte

_debugPrintHex("HID_READ_BEFORE", data, length);
_debugPrintHex("HID_READ_BEFORE", message->data, message->length);

cemuLog_logDebug(LogType::Force, "HidRead Begin (Length 0x{:08x})", length);
BOOL readResult = ReadFile(this->m_hFile, tempBuffer, length + 1, &bt, &ovlp);
cemuLog_logDebug(LogType::Force, "HidRead Begin (Length 0x{:08x})", message->length);
BOOL readResult = ReadFile(this->m_hFile, tempBuffer, message->length + 1, &bt, &ovlp);
if (readResult != FALSE)
{
// sometimes we get the result immediately
Expand Down Expand Up @@ -247,7 +265,7 @@ namespace nsyshid::backend::windows
ReadResult result = ReadResult::Success;
if (bt != 0)
{
memcpy(data, tempBuffer + 1, transferLength);
memcpy(message->data, tempBuffer + 1, transferLength);
sint32 hidReadLength = transferLength;

char debugOutput[1024] = {0};
Expand All @@ -270,15 +288,15 @@ namespace nsyshid::backend::windows
return result;
}

Device::WriteResult DeviceWindowsHID::Write(uint8* data, sint32 length, sint32& bytesWritten)
Device::WriteResult DeviceWindowsHID::Write(WriteMessage* message)
{
bytesWritten = 0;
DWORD bt;
OVERLAPPED ovlp = {0};
ovlp.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

uint8* tempBuffer = (uint8*)malloc(length + 1);
memcpy(tempBuffer + 1, data, length);
memcpy(tempBuffer + 1, message->data, message->length);
tempBuffer[0] = 0; // report byte?

cemuLog_logDebug(LogType::Force, "HidWrite Begin (Length 0x{:08x})", length);
Expand Down Expand Up @@ -314,7 +332,7 @@ namespace nsyshid::backend::windows

if (bt != 0)
{
bytesWritten = length;
message->bytesWritten = message->length;
return WriteResult::Success;
}
return WriteResult::Error;
Expand Down Expand Up @@ -407,12 +425,12 @@ namespace nsyshid::backend::windows
return true;
}

bool DeviceWindowsHID::SetReport(uint8* reportData, sint32 length, uint8* originalData, sint32 originalLength)
bool DeviceWindowsHID::SetReport(ReportMessage* message)
{
sint32 retryCount = 0;
while (true)
{
BOOL r = HidD_SetOutputReport(this->m_hFile, reportData, length);
BOOL r = HidD_SetOutputReport(this->m_hFile, message->reportData, message->length);
if (r != FALSE)
break;
Sleep(20); // retry
Expand Down
6 changes: 3 additions & 3 deletions src/Cafe/OS/libs/nsyshid/BackendWindowsHID.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,15 @@ namespace nsyshid::backend::windows

bool IsOpened() override;

ReadResult Read(uint8* data, sint32 length, sint32& bytesRead) override;
ReadResult Read(ReadMessage* message) override;

WriteResult Write(uint8* data, sint32 length, sint32& bytesWritten) override;
WriteResult Write(WriteMessage* message) override;

bool GetDescriptor(uint8 descType, uint8 descIndex, uint8 lang, uint8* output, uint32 outputMaxLength) override;

bool SetProtocol(uint32 ifIndef, uint32 protocol) override;

bool SetReport(uint8* reportData, sint32 length, uint8* originalData, sint32 originalLength) override;
bool SetReport(ReportMessage* message) override;

private:
wchar_t* m_devicePath;
Expand Down
Loading

0 comments on commit 68e7612

Please sign in to comment.