mirror of
https://github.com/gdsports/USBHost_t36
synced 2024-12-21 23:08:55 -05:00
Add support for Xbox 360 USB controller
This commit is contained in:
parent
207ffd7682
commit
b1696901ce
@ -809,7 +809,7 @@ public:
|
|||||||
// setLEDs on PS4(RGB), PS3 simple LED setting (only uses lr)
|
// setLEDs on PS4(RGB), PS3 simple LED setting (only uses lr)
|
||||||
bool setLEDs(uint8_t lr, uint8_t lg=0, uint8_t lb=0); // sets Leds,
|
bool setLEDs(uint8_t lr, uint8_t lg=0, uint8_t lb=0); // sets Leds,
|
||||||
enum { STANDARD_AXIS_COUNT = 10, ADDITIONAL_AXIS_COUNT = 54, TOTAL_AXIS_COUNT = (STANDARD_AXIS_COUNT+ADDITIONAL_AXIS_COUNT) };
|
enum { STANDARD_AXIS_COUNT = 10, ADDITIONAL_AXIS_COUNT = 54, TOTAL_AXIS_COUNT = (STANDARD_AXIS_COUNT+ADDITIONAL_AXIS_COUNT) };
|
||||||
typedef enum { UNKNOWN=0, PS3, PS4, XBOXONE, XBOX360} joytype_t;
|
typedef enum { UNKNOWN=0, PS3, PS4, XBOXONE, XBOX360, XBOX360USB} joytype_t;
|
||||||
joytype_t joystickType = UNKNOWN;
|
joytype_t joystickType = UNKNOWN;
|
||||||
protected:
|
protected:
|
||||||
// From USBDriver
|
// From USBDriver
|
||||||
@ -827,8 +827,83 @@ protected:
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
// Class specific
|
// Class specific
|
||||||
|
/************************************************************/
|
||||||
|
// Interrupt-based Data Movement
|
||||||
|
// XBox one input data when type == 0x20
|
||||||
|
// Information came from several places on the web including:
|
||||||
|
// https://github.com/quantus/xbox-one-controller-protocol
|
||||||
|
/************************************************************/
|
||||||
|
typedef struct {
|
||||||
|
uint8_t type;
|
||||||
|
uint8_t const_0;
|
||||||
|
uint16_t id;
|
||||||
|
// From online references button order:
|
||||||
|
// sync, dummy, start, back, a, b, x, y
|
||||||
|
// dpad up, down left, right
|
||||||
|
// lb, rb, left stick, right stick
|
||||||
|
// Axis:
|
||||||
|
// lt, rt, lx, ly, rx, ry
|
||||||
|
//
|
||||||
|
uint16_t buttons;
|
||||||
|
int16_t axis[6];
|
||||||
|
} xbox1data20_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t buttons;
|
||||||
|
uint8_t lt;
|
||||||
|
uint8_t rt;
|
||||||
|
int16_t axis[4];
|
||||||
|
} xbox360controls_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t state;
|
||||||
|
uint8_t id_or_type;
|
||||||
|
uint16_t controller_status;
|
||||||
|
uint16_t unknown;
|
||||||
|
// From online references button order:
|
||||||
|
// sync, dummy, start, back, a, b, x, y
|
||||||
|
// dpad up, down left, right
|
||||||
|
// lb, rb, left stick, right stick
|
||||||
|
// Axis:
|
||||||
|
// lt, rt, lx, ly, rx, ry
|
||||||
|
//
|
||||||
|
xbox360controls_t controls;
|
||||||
|
} xbox360data_t;
|
||||||
|
|
||||||
|
/* Xbox 360 wired USB report
|
||||||
|
http://www.tattiebogle.net/index.php/ProjectRoot/Xbox360Controller/UsbInfo
|
||||||
|
|
||||||
|
Reports are type 0x00, and seem to be 20 bytes long:
|
||||||
|
|
||||||
|
0014ttttxxyyaaaaaaaabbbbbbbb000000000000
|
||||||
|
Where x is the left trigger, y is the right trigger, a is the left hat, b is the right hat and t is the buttons:
|
||||||
|
|
||||||
|
0x0001 Left shoulder
|
||||||
|
0x0002 Right shoulder
|
||||||
|
0x0004 XBox button
|
||||||
|
0x0008
|
||||||
|
0x0010 A
|
||||||
|
0x0020 B
|
||||||
|
0x0040 X
|
||||||
|
0x0080 Y
|
||||||
|
0x0100 D-pad up
|
||||||
|
0x0200 D-pad down
|
||||||
|
0x0400 D-pad left
|
||||||
|
0x0800 D-pad right
|
||||||
|
0x1000 Start
|
||||||
|
0x2000 Back
|
||||||
|
0x4000 Left hat button
|
||||||
|
0x8000 Right hat button
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint8_t rType;
|
||||||
|
uint8_t rLen;
|
||||||
|
xbox360controls_t controls;
|
||||||
|
} xbox360udata_t;
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
USBHIDParser *driver_ = nullptr;
|
USBHIDParser *driver_ = nullptr;
|
||||||
|
void extract_xbox360controls(const xbox360controls_t *cont);
|
||||||
joytype_t mapVIDPIDtoJoystickType(uint16_t idVendor, uint16_t idProduct, bool exclude_hid_devices);
|
joytype_t mapVIDPIDtoJoystickType(uint16_t idVendor, uint16_t idProduct, bool exclude_hid_devices);
|
||||||
bool transmitPS4UserFeedbackMsg();
|
bool transmitPS4UserFeedbackMsg();
|
||||||
bool transmitPS3UserFeedbackMsg();
|
bool transmitPS3UserFeedbackMsg();
|
||||||
|
@ -122,6 +122,7 @@ void loop()
|
|||||||
|
|
||||||
case JoystickController::XBOXONE:
|
case JoystickController::XBOXONE:
|
||||||
case JoystickController::XBOX360:
|
case JoystickController::XBOX360:
|
||||||
|
case JoystickController::XBOX360USB:
|
||||||
ltv = joysticks[joystick_index].getAxis(4);
|
ltv = joysticks[joystick_index].getAxis(4);
|
||||||
rtv = joysticks[joystick_index].getAxis(5);
|
rtv = joysticks[joystick_index].getAxis(5);
|
||||||
if ((ltv != joystick_left_trigger_value[joystick_index]) || (rtv != joystick_right_trigger_value[joystick_index])) {
|
if ((ltv != joystick_left_trigger_value[joystick_index]) || (rtv != joystick_right_trigger_value[joystick_index])) {
|
||||||
|
187
joystick.cpp
187
joystick.cpp
@ -33,6 +33,7 @@
|
|||||||
JoystickController::product_vendor_mapping_t JoystickController::pid_vid_mapping[] = {
|
JoystickController::product_vendor_mapping_t JoystickController::pid_vid_mapping[] = {
|
||||||
{ 0x045e, 0x02ea, XBOXONE, false },{ 0x045e, 0x02dd, XBOXONE, false },
|
{ 0x045e, 0x02ea, XBOXONE, false },{ 0x045e, 0x02dd, XBOXONE, false },
|
||||||
{ 0x045e, 0x0719, XBOX360, false},
|
{ 0x045e, 0x0719, XBOX360, false},
|
||||||
|
{ 0x045e, 0x028e, XBOX360USB, false},
|
||||||
{ 0x054C, 0x0268, PS3, true},
|
{ 0x054C, 0x0268, PS3, true},
|
||||||
{ 0x054C, 0x05C4, PS4, true}, {0x054C, 0x09CC, PS4, true }
|
{ 0x054C, 0x05C4, PS4, true}, {0x054C, 0x09CC, PS4, true }
|
||||||
};
|
};
|
||||||
@ -153,6 +154,19 @@ bool JoystickController::setRumble(uint8_t lValue, uint8_t rValue, uint8_t timeo
|
|||||||
println("XBox360 rumble transfer fail");
|
println("XBox360 rumble transfer fail");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
case XBOX360USB:
|
||||||
|
txbuf_[0] = 0x00;
|
||||||
|
txbuf_[1] = 0x08;
|
||||||
|
txbuf_[2] = 0x00;
|
||||||
|
txbuf_[3] = lValue;
|
||||||
|
txbuf_[4] = rValue;
|
||||||
|
txbuf_[5] = 0x00;
|
||||||
|
txbuf_[6] = 0x00;
|
||||||
|
txbuf_[7] = 0x00;
|
||||||
|
if (!queue_Data_Transfer(txpipe_, txbuf_, 8, this)) {
|
||||||
|
println("XBox360USB rumble transfer fail");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -191,6 +205,45 @@ bool JoystickController::setLEDs(uint8_t lr, uint8_t lg, uint8_t lb)
|
|||||||
println("XBox360 set leds fail");
|
println("XBox360 set leds fail");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
case XBOX360USB:
|
||||||
|
/* http://www.tattiebogle.net/index.php/ProjectRoot/Xbox360Controller/UsbInfo
|
||||||
|
|
||||||
|
Some control over the LEDs surrounding the XBox button is
|
||||||
|
provided, corresponding to the markings 1, 2, 3 and 4. This
|
||||||
|
is controlled using message type 0x01.
|
||||||
|
|
||||||
|
To select a new pattern for the LEDs, send a message of the following form:
|
||||||
|
|
||||||
|
0103xx
|
||||||
|
Where xx is the desired pattern:
|
||||||
|
|
||||||
|
0x00 All off
|
||||||
|
0x01 All blinking
|
||||||
|
0x02 1 flashes, then on
|
||||||
|
0x03 2 flashes, then on
|
||||||
|
0x04 3 flashes, then on
|
||||||
|
0x05 4 flashes, then on
|
||||||
|
0x06 1 on
|
||||||
|
0x07 2 on
|
||||||
|
0x08 3 on
|
||||||
|
0x09 4 on
|
||||||
|
0x0A Rotating (e.g. 1-2-4-3)
|
||||||
|
0x0B Blinking*
|
||||||
|
0x0C Slow blinking*
|
||||||
|
0x0D Alternating (e.g. 1+4-2+3), then back to previous*
|
||||||
|
* The previous setting will be used for these (all blinking, or 1, 2, 3 or 4 on).
|
||||||
|
|
||||||
|
At startup, the device seems to report 01030E. I believe
|
||||||
|
this to indicate that there are 14 options (e.g. 0 to D hex)
|
||||||
|
for the LEDs.
|
||||||
|
*/
|
||||||
|
txbuf_[0] = 0x01;
|
||||||
|
txbuf_[1] = 0x03;
|
||||||
|
txbuf_[2] = lr;
|
||||||
|
if (!queue_Data_Transfer(txpipe_, txbuf_, 3, this)) {
|
||||||
|
println("XBox360USB set leds fail");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
case XBOXONE:
|
case XBOXONE:
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
@ -417,11 +470,21 @@ bool JoystickController::claim(Device_t *dev, int type, const uint8_t *descripto
|
|||||||
// 29 30 1 2 3 4 5 6 7 8 9 40 41 42
|
// 29 30 1 2 3 4 5 6 7 8 9 40 41 42
|
||||||
// 07 05 81 03 20 00 01 07 05 01 03 20 00 08
|
// 07 05 81 03 20 00 01 07 05 01 03 20 00 08
|
||||||
|
|
||||||
|
// XBOX 360 wired USB... Has 4 interfaces and extra descriptors
|
||||||
|
// Shows data for #1 only...
|
||||||
|
// Also they have some unknown data type we need to ignore between interface and end points.
|
||||||
|
// 0 1 2 3 4 5 6 7 8 *9 10 1 2 3 4 5 6 7 8 9 20 1 2 3 4 5 *6 7 8
|
||||||
|
// 09 04 00 00 02 FF 5D 01 00 11 21 10 01 01 25 81 14 03 03 03 04 13 02 08 03 03 07 05 81
|
||||||
|
|
||||||
|
// 29 30 1 2 *3 4 5 6 7 8 9 40 41 42
|
||||||
|
// 03 20 00 04 07 05 02 03 20 00 08
|
||||||
|
|
||||||
if (len < 9+7+7) return false;
|
if (len < 9+7+7) return false;
|
||||||
|
|
||||||
// Some common stuff for both XBoxs
|
// Some common stuff for both XBoxs
|
||||||
uint32_t count_end_points = descriptors[4];
|
uint32_t count_end_points = descriptors[4];
|
||||||
if (count_end_points < 2) return false;
|
if (count_end_points < 2) return false;
|
||||||
|
if ((jtype == XBOX360USB) && (count_end_points != 2)) return false;
|
||||||
if (descriptors[5] != 0xff) return false; // bInterfaceClass, 3 = HID
|
if (descriptors[5] != 0xff) return false; // bInterfaceClass, 3 = HID
|
||||||
rx_ep_ = 0;
|
rx_ep_ = 0;
|
||||||
uint32_t txep = 0;
|
uint32_t txep = 0;
|
||||||
@ -434,6 +497,9 @@ bool JoystickController::claim(Device_t *dev, int type, const uint8_t *descripto
|
|||||||
if (descriptors[descriptor_index] != 0x14) return false; // only support specific versions...
|
if (descriptors[descriptor_index] != 0x14) return false; // only support specific versions...
|
||||||
descriptor_index += descriptors[descriptor_index]; // XBox360w ignore this unknown setup...
|
descriptor_index += descriptors[descriptor_index]; // XBox360w ignore this unknown setup...
|
||||||
}
|
}
|
||||||
|
else if (descriptors[descriptor_index+1] == 0x21) {
|
||||||
|
descriptor_index += descriptors[descriptor_index]; // XBox360USB skip this unknown setup...
|
||||||
|
}
|
||||||
while (count_end_points-- && ((rx_ep_ == 0) || txep == 0)) {
|
while (count_end_points-- && ((rx_ep_ == 0) || txep == 0)) {
|
||||||
if (descriptors[descriptor_index] != 7) return false; // length 7
|
if (descriptors[descriptor_index] != 7) return false; // length 7
|
||||||
if (descriptors[descriptor_index+1] != 5) return false; // ep desc
|
if (descriptors[descriptor_index+1] != 5) return false; // ep desc
|
||||||
@ -474,7 +540,7 @@ bool JoystickController::claim(Device_t *dev, int type, const uint8_t *descripto
|
|||||||
if (jtype == XBOXONE) {
|
if (jtype == XBOXONE) {
|
||||||
queue_Data_Transfer(txpipe_, xboxone_start_input, sizeof(xboxone_start_input), this);
|
queue_Data_Transfer(txpipe_, xboxone_start_input, sizeof(xboxone_start_input), this);
|
||||||
connected_ = true; // remember that hardware is actually connected...
|
connected_ = true; // remember that hardware is actually connected...
|
||||||
} else if (jtype == XBOX360) {
|
} else if ((jtype == XBOX360) || (jtype == XBOX360USB)) {
|
||||||
queue_Data_Transfer(txpipe_, xbox360w_inquire_present, sizeof(xbox360w_inquire_present), this);
|
queue_Data_Transfer(txpipe_, xbox360w_inquire_present, sizeof(xbox360w_inquire_present), this);
|
||||||
connected_ = 0; // remember that hardware is actually connected...
|
connected_ = 0; // remember that hardware is actually connected...
|
||||||
}
|
}
|
||||||
@ -506,47 +572,40 @@ void JoystickController::tx_callback(const Transfer_t *transfer)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/************************************************************/
|
|
||||||
// Interrupt-based Data Movement
|
|
||||||
// XBox one input data when type == 0x20
|
|
||||||
// Information came from several places on the web including:
|
|
||||||
// https://github.com/quantus/xbox-one-controller-protocol
|
|
||||||
/************************************************************/
|
|
||||||
typedef struct {
|
|
||||||
uint8_t type;
|
|
||||||
uint8_t const_0;
|
|
||||||
uint16_t id;
|
|
||||||
// From online references button order:
|
|
||||||
// sync, dummy, start, back, a, b, x, y
|
|
||||||
// dpad up, down left, right
|
|
||||||
// lb, rb, left stick, right stick
|
|
||||||
// Axis:
|
|
||||||
// lt, rt, lx, ly, rx, ry
|
|
||||||
//
|
|
||||||
uint16_t buttons;
|
|
||||||
int16_t axis[6];
|
|
||||||
} xbox1data20_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint8_t state;
|
|
||||||
uint8_t id_or_type;
|
|
||||||
uint16_t controller_status;
|
|
||||||
uint16_t unknown;
|
|
||||||
// From online references button order:
|
|
||||||
// sync, dummy, start, back, a, b, x, y
|
|
||||||
// dpad up, down left, right
|
|
||||||
// lb, rb, left stick, right stick
|
|
||||||
// Axis:
|
|
||||||
// lt, rt, lx, ly, rx, ry
|
|
||||||
//
|
|
||||||
uint16_t buttons;
|
|
||||||
uint8_t lt;
|
|
||||||
uint8_t rt;
|
|
||||||
int16_t axis[4];
|
|
||||||
} xbox360data_t;
|
|
||||||
|
|
||||||
static const uint8_t xbox_axis_order_mapping[] = {4, 5, 0, 1, 2, 3};
|
static const uint8_t xbox_axis_order_mapping[] = {4, 5, 0, 1, 2, 3};
|
||||||
|
|
||||||
|
void JoystickController::extract_xbox360controls(const xbox360controls_t *cont)
|
||||||
|
{
|
||||||
|
if (buttons != cont->buttons) {
|
||||||
|
buttons = cont->buttons;
|
||||||
|
anychange = true;
|
||||||
|
}
|
||||||
|
axis_mask_ = 0x3f;
|
||||||
|
axis_changed_mask_ = 0; // assume none for now
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < 4; i++) {
|
||||||
|
if (axis[i] != cont->axis[i]) {
|
||||||
|
axis[i] = cont->axis[i];
|
||||||
|
axis_changed_mask_ |= (1 << i);
|
||||||
|
anychange = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// the two triggers show up as 4 and 5
|
||||||
|
if (axis[4] != cont->lt) {
|
||||||
|
axis[4] = cont->lt;
|
||||||
|
axis_changed_mask_ |= (1 << 4);
|
||||||
|
anychange = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (axis[5] != cont->rt) {
|
||||||
|
axis[5] = cont->rt;
|
||||||
|
axis_changed_mask_ |= (1 << 5);
|
||||||
|
anychange = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (anychange) joystickEvent = true;
|
||||||
|
}
|
||||||
|
|
||||||
void JoystickController::rx_data(const Transfer_t *transfer)
|
void JoystickController::rx_data(const Transfer_t *transfer)
|
||||||
{
|
{
|
||||||
print("JoystickController::rx_data: ");
|
print("JoystickController::rx_data: ");
|
||||||
@ -591,41 +650,21 @@ void JoystickController::rx_data(const Transfer_t *transfer)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if((xb360d->id_or_type == 0x00) && (xb360d->controller_status & 0x1300)) {
|
} else if((xb360d->id_or_type == 0x00) && (xb360d->controller_status & 0x1300)) {
|
||||||
// Controller status report - Maybe we should save away and allow the user access?
|
// Controller status report - Maybe we should save away and allow the user access?
|
||||||
println("XBox360w - controllerStatus: ", xb360d->controller_status, HEX);
|
println("XBox360w - controllerStatus: ", xb360d->controller_status, HEX);
|
||||||
} else if(xb360d->id_or_type == 0x01) { // Lets only process report 1.
|
} else if(xb360d->id_or_type == 0x01) { // Lets only process report 1.
|
||||||
//const uint8_t *pbuffer = (uint8_t*)transfer->buffer;
|
//const uint8_t *pbuffer = (uint8_t*)transfer->buffer;
|
||||||
//for (uint8_t i = 0; i < transfer->length; i++) Serial.printf("%02x ", pbuffer[i]);
|
//for (uint8_t i = 0; i < transfer->length; i++) Serial.printf("%02x ", pbuffer[i]);
|
||||||
//Serial.printf("\n");
|
//Serial.printf("\n");
|
||||||
|
extract_xbox360controls(&xb360d->controls);
|
||||||
if (buttons != xb360d->buttons) {
|
}
|
||||||
buttons = xb360d->buttons;
|
} else if (joystickType == XBOX360USB) {
|
||||||
anychange = true;
|
xbox360udata_t *xb360ud = (xbox360udata_t *)transfer->buffer;
|
||||||
}
|
if ((xb360ud->rType == 0) && (xb360ud->rLen == 0x14)) {
|
||||||
axis_mask_ = 0x3f;
|
extract_xbox360controls(&xb360ud->controls);
|
||||||
axis_changed_mask_ = 0; // assume none for now
|
}
|
||||||
|
else {
|
||||||
for (uint8_t i = 0; i < 4; i++) {
|
Serial.printf("XBox360u - rType=0x%x rLen=0x%x\n", xb360ud->rType, xb360ud->rLen);
|
||||||
if (axis[i] != xb360d->axis[i]) {
|
|
||||||
axis[i] = xb360d->axis[i];
|
|
||||||
axis_changed_mask_ |= (1 << i);
|
|
||||||
anychange = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// the two triggers show up as 4 and 5
|
|
||||||
if (axis[4] != xb360d->lt) {
|
|
||||||
axis[4] = xb360d->lt;
|
|
||||||
axis_changed_mask_ |= (1 << 4);
|
|
||||||
anychange = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (axis[5] != xb360d->rt) {
|
|
||||||
axis[5] = xb360d->rt;
|
|
||||||
axis_changed_mask_ |= (1 << 5);
|
|
||||||
anychange = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (anychange) joystickEvent = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,6 +91,7 @@ PS3 LITERAL1
|
|||||||
PS4 LITERAL1
|
PS4 LITERAL1
|
||||||
XBOXONE LITERAL1
|
XBOXONE LITERAL1
|
||||||
XBOX360 LITERAL1
|
XBOX360 LITERAL1
|
||||||
|
XBOX360USB LITERAL1
|
||||||
|
|
||||||
# USBSerial
|
# USBSerial
|
||||||
USBHOST_SERIAL_7E1 LITERAL1
|
USBHOST_SERIAL_7E1 LITERAL1
|
||||||
|
Loading…
Reference in New Issue
Block a user