Created
November 9, 2017 16:11
-
-
Save veryjos/7625dc0aa5ba6aaee6cd59ea017ccc21 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "Project_Combo.h" | |
#include "GCAdapter.h" | |
#define ADAPTER_VENDOR_ID 0x057e | |
#define ADAPTER_PRODUCT_ID 0x0337 | |
GCAdapter::GCAdapter() { | |
// Clear controller plugged states | |
for (int i = 0; i < 4; i++) { | |
controllers[i].connected = GCPadState::STATE_NONE; | |
controllers[i].portNum = i; | |
} | |
handle = nullptr; | |
// Init libusb | |
int ret = libusb_init(&libusb_context); | |
if (ret) | |
{ | |
UE_LOG(LogGCAdapter, Error, TEXT("Failed to init libusb")); | |
libusb_context = nullptr; | |
return; | |
} | |
else | |
{ | |
// Enumerate USB devices | |
libusb_device** deviceList; | |
ssize_t cnt = libusb_get_device_list(libusb_context, &deviceList); | |
// Find GC adapters | |
for (int i = 0; i < cnt; i++) | |
{ | |
libusb_device* device = deviceList[i]; | |
libusb_device_descriptor desc; | |
ret = libusb_get_device_descriptor(device, &desc); | |
// Skip over if the device can't be read | |
if (ret) | |
continue; | |
if (desc.idVendor == ADAPTER_VENDOR_ID && | |
desc.idProduct == ADAPTER_PRODUCT_ID) | |
{ | |
UE_LOG(LogGCAdapter, Log, TEXT("Found GC Adapter")); | |
uint8 bus = libusb_get_bus_number(device); | |
uint8 port = libusb_get_device_address(device); | |
ret = libusb_open(device, &handle); | |
if (ret) | |
{ | |
UE_LOG(LogGCAdapter, Warning, TEXT("Can't access GCAdapter device: Bus %03d Device %03d"), bus, port); | |
continue; | |
} | |
// Detach the kernel driver | |
if ((ret = libusb_kernel_driver_active(handle, 0)) == 1) | |
{ | |
if ((ret = libusb_detach_kernel_driver(handle, 0)) != 0 && ret != LIBUSB_ERROR_NOT_SUPPORTED) | |
{ | |
UE_LOG(LogGCAdapter, Error, TEXT("libusb_detach_kernel_driver failed, error: %d"), ret); | |
} | |
} | |
if (ret != 0 && ret != LIBUSB_ERROR_NOT_SUPPORTED) | |
{ | |
continue; | |
} | |
else if ((ret = libusb_claim_interface(handle, 0)) != 0) | |
{ | |
UE_LOG(LogGCAdapter, Error, TEXT("libusb_claim_interface failed, error: %d"), ret); | |
} | |
else | |
{ | |
UE_LOG(LogGCAdapter, Log, TEXT("Successfully opened GC device")); | |
LinkGCAdapter(device); | |
break; | |
} | |
} | |
} | |
libusb_free_device_list(deviceList, cnt); | |
} | |
} | |
GCAdapter::~GCAdapter() { | |
if (libusb_context) { | |
UE_LOG(LogGCAdapter, Log, TEXT("Shutting down libusb..")); | |
// Close the libusb device | |
if (handle) { | |
libusb_release_interface(handle, 0); | |
libusb_close(handle); | |
} | |
// Exit the libusb context | |
libusb_exit(libusb_context); | |
} | |
} | |
void GCAdapter::LinkGCAdapter(libusb_device* device) | |
{ | |
libusb_config_descriptor* config = nullptr; | |
libusb_get_config_descriptor(device, 0, &config); | |
for (uint8 ic = 0; ic < config->bNumInterfaces; ic++) | |
{ | |
const libusb_interface* interfaceContainer = &config->interface[ic]; | |
for (int i = 0; i < interfaceContainer->num_altsetting; i++) | |
{ | |
const libusb_interface_descriptor *interface = &interfaceContainer->altsetting[i]; | |
for (uint8 e = 0; e < interface->bNumEndpoints; e++) | |
{ | |
const libusb_endpoint_descriptor *endpoint = &interface->endpoint[e]; | |
if (endpoint->bEndpointAddress & LIBUSB_ENDPOINT_IN) | |
endpoint_in = endpoint->bEndpointAddress; | |
else | |
endpoint_out = endpoint->bEndpointAddress; | |
} | |
} | |
} | |
int tmp = 0; | |
// This packet starts comms with the GC controllers | |
unsigned char payload = 0x13; | |
libusb_interrupt_transfer(handle, endpoint_out, &payload, sizeof(payload), &tmp, 16); | |
UE_LOG(LogGCAdapter, Log, TEXT("Linking GCAdapter..")); | |
libusb_free_config_descriptor(config); | |
} | |
void GCAdapter::Read() | |
{ | |
if (!handle) | |
return; | |
int payloadSize; | |
libusb_interrupt_transfer(handle, endpoint_in, payload_in, sizeof(payload_in), &payloadSize, 16); | |
if (payloadSize != PAYLOAD_IN_SIZE) | |
{ | |
UE_LOG(LogGCAdapter, Warning, TEXT("Error reading payload from GCAdapter")); | |
} | |
else | |
{ | |
// Read all four controller states | |
for (int padNum = 0; padNum < 4; padNum++) | |
{ | |
GCPad& pad = GetPad(padNum); | |
uint8 type = payload_in[1 + (9 * padNum)] >> 4; | |
if (type != GCPadState::STATE_NONE && !pad.connected) | |
{ | |
UE_LOG(LogGCAdapter, Log, TEXT("New GC controller connected to port %d"), padNum); | |
m_justConnectedPads.push_back(&pad); | |
} | |
else if (type == GCPadState::STATE_NONE && pad.connected) | |
{ | |
UE_LOG(LogGCAdapter, Log, TEXT("GC controller disconnected from port %d"), padNum); | |
m_justDisconnectedPads.push_back(&pad); | |
} | |
pad.connected = (type != GCPadState::STATE_NONE); | |
if (pad.connected) | |
{ | |
// Clear pad button states | |
memset(&pad.buttons, 0, sizeof(pad.buttons)); | |
uint8 b1 = payload_in[1 + (9 * padNum) + 1]; | |
uint8 b2 = payload_in[1 + (9 * padNum) + 2]; | |
if (b1 & (1 << 0)) pad.buttons |= GCPAD_BUTTON_A; | |
if (b1 & (1 << 1)) pad.buttons |= GCPAD_BUTTON_B; | |
if (b1 & (1 << 2)) pad.buttons |= GCPAD_BUTTON_X; | |
if (b1 & (1 << 3)) pad.buttons |= GCPAD_BUTTON_Y; | |
if (b1 & (1 << 4)) pad.buttons |= GCPAD_BUTTON_LEFT; | |
if (b1 & (1 << 5)) pad.buttons |= GCPAD_BUTTON_RIGHT; | |
if (b1 & (1 << 6)) pad.buttons |= GCPAD_BUTTON_DOWN; | |
if (b1 & (1 << 7)) pad.buttons |= GCPAD_BUTTON_UP; | |
if (b2 & (1 << 0)) pad.buttons |= GCPAD_BUTTON_START; | |
if (b2 & (1 << 1)) pad.buttons |= GCPAD_BUTTON_Z; | |
if (b2 & (1 << 2)) pad.buttons |= GCPAD_BUTTON_DIGITAL_R; | |
if (b2 & (1 << 3)) pad.buttons |= GCPAD_BUTTON_DIGITAL_L; | |
pad.stickX = payload_in[1 + (9 * padNum) + 3]; | |
pad.stickY = payload_in[1 + (9 * padNum) + 4]; | |
pad.cStickX = payload_in[1 + (9 * padNum) + 5]; | |
pad.cStickY = payload_in[1 + (9 * padNum) + 6]; | |
pad.lTrigger = payload_in[1 + (9 * padNum) + 7]; | |
pad.rTrigger = payload_in[1 + (9 * padNum) + 8]; | |
// Calculate new button presses | |
pad.pressed = (pad.buttons ^ pad.oldButtons) & pad.buttons; | |
// Calculate new button releases | |
pad.released = (pad.buttons ^ pad.oldButtons) & pad.oldButtons; | |
pad.oldButtons = pad.buttons; | |
} | |
} | |
} | |
} | |
GCPad& GCAdapter::GetPad(uint8 pad) | |
{ | |
return controllers[pad]; | |
} | |
std::vector<GCPad*> GCAdapter::GetJustConnectedPads() | |
{ | |
return m_justConnectedPads; | |
} | |
std::vector<GCPad*> GCAdapter::GetJustDisconnectedPads() | |
{ | |
return m_justDisconnectedPads; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <cstdint> | |
#include "AllowWindowsPlatformTypes.h" | |
#include "libusb-1.0/libusb.h" | |
#include "HideWindowsPlatformTypes.h" | |
#include <vector> | |
#define PAYLOAD_IN_SIZE 37 | |
static const uint32_t GCPAD_BUTTON_A = (1 << 0); | |
static const uint32_t GCPAD_BUTTON_B = (1 << 1); | |
static const uint32_t GCPAD_BUTTON_X = (1 << 2); | |
static const uint32_t GCPAD_BUTTON_Y = (1 << 3); | |
static const uint32_t GCPAD_BUTTON_LEFT = (1 << 4); | |
static const uint32_t GCPAD_BUTTON_RIGHT = (1 << 5); | |
static const uint32_t GCPAD_BUTTON_DOWN = (1 << 6); | |
static const uint32_t GCPAD_BUTTON_UP = (1 << 7); | |
static const uint32_t GCPAD_BUTTON_START = (1 << 8); | |
static const uint32_t GCPAD_BUTTON_Z = (1 << 9); | |
static const uint32_t GCPAD_BUTTON_DIGITAL_L = (1 << 10); | |
static const uint32_t GCPAD_BUTTON_DIGITAL_R = (1 << 11); | |
enum GCPadState | |
{ | |
STATE_NONE, | |
STATE_WIRED, | |
STATE_WIRELESS | |
}; | |
struct GCPad { | |
bool connected; | |
uint8_t portNum; | |
uint32_t buttons; | |
uint32_t newButtons; | |
uint32_t oldButtons; | |
uint32_t pressed; | |
uint32_t released; | |
uint8_t stickX; | |
uint8_t stickY; | |
uint8_t cStickX; | |
uint8_t cStickY; | |
uint8_t lTrigger; | |
uint8_t rTrigger; | |
}; | |
class GCAdapter { | |
public: | |
GCAdapter(); | |
~GCAdapter(); | |
void Read(); | |
GCPad& GetPad(uint8_t padNum); | |
std::vector<GCPad*> GetJustConnectedPads(); | |
std::vector<GCPad*> GetJustDisconnectedPads(); | |
private: | |
void LinkGCAdapter(libusb_device* device); | |
GCPad controllers[4]; | |
uint8_t endpoint_in; | |
uint8_t endpoint_out; | |
uint8_t payload_in[PAYLOAD_IN_SIZE]; | |
libusb_device_handle* handle; | |
libusb_context* libusb_context; | |
std::vector<GCPad*> m_justConnectedPads; | |
std::vector<GCPad*> m_justDisconnectedPads; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment