From eaad0684f237fb94e9dd0f17b5b231da38b6b40a Mon Sep 17 00:00:00 2001 From: Kurt Eckhardt Date: Sat, 20 Jan 2018 16:38:42 -0800 Subject: [PATCH] XBox360 Wireless controller Support for using the Microsoft XBox 360 wireless receiver for windows to be able to communicate with XBox 360 wireless controllers. In theory this should support up to 4 controllers. So far I have only tested with one as I only have one. Added a joystick only test that should support up to 4 joystick objects. --- USBHost_t36.h | 6 +- enumeration.cpp | 2 +- examples/Joystick/Joystick.ino | 195 ++++++++++++++++++++++++++++++ examples/Mouse/Mouse.ino | 1 + joystick.cpp | 213 ++++++++++++++++++++++++++++----- keywords.txt | 3 +- 6 files changed, 384 insertions(+), 36 deletions(-) create mode 100644 examples/Joystick/Joystick.ino diff --git a/USBHost_t36.h b/USBHost_t36.h index af4dadc..4ae2669 100644 --- a/USBHost_t36.h +++ b/USBHost_t36.h @@ -782,7 +782,7 @@ public: const uint8_t *manufacturer(); const uint8_t *product(); const uint8_t *serialNumber(); - operator bool() { return ((device != nullptr) || (mydevice != nullptr)); } // override as in both USBDriver and in USBHIDInput + operator bool() { return (((device != nullptr) || (mydevice != nullptr)) && connected_); } // override as in both USBDriver and in USBHIDInput bool available() { return joystickEvent; } void joystickDataClear(); @@ -798,7 +798,7 @@ public: // 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, 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} joytype_t; + typedef enum { UNKNOWN=0, PS3, PS4, XBOXONE, XBOX360} joytype_t; joytype_t joystickType = UNKNOWN; protected: // From USBDriver @@ -839,6 +839,7 @@ private: uint8_t rumble_rValue_ = 0; uint8_t rumble_timeout_ = 0; uint8_t leds_[3] = {0,0,0}; + uint8_t connected_ = 0; // what type of device if any is connected xbox 360... // Used by HID code @@ -854,6 +855,7 @@ private: Transfer_t mytransfers[7] __attribute__ ((aligned(32))); strbuf_t mystring_bufs[1]; + uint8_t rx_ep_ = 0; // remember which end point this object is... uint16_t rx_size_ = 0; uint16_t tx_size_ = 0; Pipe_t *rxpipe_; diff --git a/enumeration.cpp b/enumeration.cpp index d280706..0b49bf2 100644 --- a/enumeration.cpp +++ b/enumeration.cpp @@ -44,7 +44,7 @@ static USBDriver *available_drivers = NULL; // Static buffers used during enumeration. One a single USB device // may enumerate at once, because USB address zero is used, and // because this static buffer & state info can't be shared. -static uint8_t enumbuf[256] __attribute__ ((aligned(16))); +static uint8_t enumbuf[512] __attribute__ ((aligned(16))); static setup_t enumsetup __attribute__ ((aligned(16))); static uint16_t enumlen; diff --git a/examples/Joystick/Joystick.ino b/examples/Joystick/Joystick.ino new file mode 100644 index 0000000..0eb0327 --- /dev/null +++ b/examples/Joystick/Joystick.ino @@ -0,0 +1,195 @@ +// Simple test of USB Host Joystick +// +// This example is in the public domain + +#include "USBHost_t36.h" + +USBHost myusb; +USBHub hub1(myusb); +USBHIDParser hid1(myusb); +USBHIDParser hid2(myusb); +USBHIDParser hid3(myusb); +USBHIDParser hid4(myusb); +#define COUNT_JOYSTICKS 4 +JoystickController joysticks[COUNT_JOYSTICKS](myusb); +int user_axis[64]; +uint32_t buttons_prev = 0; + +USBDriver *drivers[] = {&hub1, &joysticks[0], &joysticks[1], &joysticks[2], &joysticks[3], &hid1, &hid2, &hid3, &hid4}; +#define CNT_DEVICES (sizeof(drivers)/sizeof(drivers[0])) +const char * driver_names[CNT_DEVICES] = {"Hub1", "joystick[0D]", "joystick[1D]", "joystick[2D]", "joystick[3D]", "HID1", "HID2", "HID3", "HID4"}; +bool driver_active[CNT_DEVICES] = {false, false, false, false}; + +// Lets also look at HID Input devices +USBHIDInput *hiddrivers[] = {&joysticks[0], &joysticks[1], &joysticks[2], &joysticks[3]}; +#define CNT_HIDDEVICES (sizeof(hiddrivers)/sizeof(hiddrivers[0])) +const char * hid_driver_names[CNT_DEVICES] = {"joystick[0H]", "joystick[1H]", "joystick[2H]", "joystick[3H]"}; +bool hid_driver_active[CNT_DEVICES] = {false}; +bool show_changed_only = false; + +uint8_t joystick_left_trigger_value[COUNT_JOYSTICKS] = {0}; +uint8_t joystick_right_trigger_value[COUNT_JOYSTICKS] = {0}; +uint64_t joystick_full_notify_mask = (uint64_t) - 1; + +//============================================================================= +// Setup +//============================================================================= +void setup() +{ + while (!Serial) ; // wait for Arduino Serial Monitor + Serial.println("\n\nUSB Host Joystick Testing"); + myusb.begin(); +} + + +//============================================================================= +// loop +//============================================================================= +void loop() +{ + myusb.Task(); + PrintDeviceListChanges(); + + if (Serial.available()) { + int ch = Serial.read(); // get the first char. + while (Serial.read() != -1) ; + if ((ch == 'b') || (ch == 'B')) { + Serial.println("Only notify on Basic Axis changes"); + for (int joystick_index = 0; joystick_index < COUNT_JOYSTICKS; joystick_index++) + joysticks[joystick_index].axisChangeNotifyMask(0x3ff); + } else if ((ch == 'f') || (ch == 'F')) { + Serial.println("Only notify on Full Axis changes"); + for (int joystick_index = 0; joystick_index < COUNT_JOYSTICKS; joystick_index++) + joysticks[joystick_index].axisChangeNotifyMask(joystick_full_notify_mask); + + } else { + if (show_changed_only) { + show_changed_only = false; + Serial.println("\n*** Show All fields mode ***"); + } else { + show_changed_only = true; + Serial.println("\n*** Show only changed fields mode ***"); + } + } + } + + for (int joystick_index = 0; joystick_index < COUNT_JOYSTICKS; joystick_index++) { + if (joysticks[joystick_index].available()) { + uint64_t axis_mask = joysticks[joystick_index].axisMask(); + uint64_t axis_changed_mask = joysticks[joystick_index].axisChangedMask(); + uint32_t buttons = joysticks[joystick_index].getButtons(); + Serial.printf("Joystick(%d): buttons = %x", joystick_index, buttons); + //Serial.printf(" AMasks: %x %x:%x", axis_mask, (uint32_t)(user_axis_mask >> 32), (uint32_t)(user_axis_mask & 0xffffffff)); + //Serial.printf(" M: %lx %lx", axis_mask, joysticks[joystick_index].axisChangedMask()); + if (show_changed_only) { + for (uint8_t i = 0; axis_changed_mask != 0; i++, axis_changed_mask >>= 1) { + if (axis_changed_mask & 1) { + Serial.printf(" %d:%d", i, joysticks[joystick_index].getAxis(i)); + } + } + + } else { + for (uint8_t i = 0; axis_mask != 0; i++, axis_mask >>= 1) { + if (axis_mask & 1) { + Serial.printf(" %d:%d", i, joysticks[joystick_index].getAxis(i)); + } + } + } + uint8_t ltv; + uint8_t rtv; + switch (joysticks[joystick_index].joystickType) { + default: + break; + case JoystickController::PS4: + ltv = joysticks[joystick_index].getAxis(3); + rtv = joysticks[joystick_index].getAxis(4); + if ((ltv != joystick_left_trigger_value[joystick_index]) || (rtv != joystick_right_trigger_value[joystick_index])) { + joystick_left_trigger_value[joystick_index] = ltv; + joystick_right_trigger_value[joystick_index] = rtv; + joysticks[joystick_index].setRumble(ltv, rtv); + } + break; + + case JoystickController::PS3: + ltv = joysticks[joystick_index].getAxis(18); + rtv = joysticks[joystick_index].getAxis(19); + if ((ltv != joystick_left_trigger_value[joystick_index]) || (rtv != joystick_right_trigger_value[joystick_index])) { + joystick_left_trigger_value[joystick_index] = ltv; + joystick_right_trigger_value[joystick_index] = rtv; + joysticks[joystick_index].setRumble(ltv, rtv, 50); + } + break; + + case JoystickController::XBOXONE: + case JoystickController::XBOX360: + ltv = joysticks[joystick_index].getAxis(4); + rtv = joysticks[joystick_index].getAxis(5); + if ((ltv != joystick_left_trigger_value[joystick_index]) || (rtv != joystick_right_trigger_value[joystick_index])) { + joystick_left_trigger_value[joystick_index] = ltv; + joystick_right_trigger_value[joystick_index] = rtv; + joysticks[joystick_index].setRumble(ltv, rtv); + Serial.printf(" Set Rumble %d %d", ltv, rtv); + } + break; + } + if (buttons != buttons_prev) { + if (joysticks[joystick_index].joystickType == JoystickController::PS3) { + joysticks[joystick_index].setLEDs((buttons >> 12) & 0xf); // try to get to TRI/CIR/X/SQuare + } else { + uint8_t lr = (buttons & 1) ? 0xff : 0; + uint8_t lg = (buttons & 2) ? 0xff : 0; + uint8_t lb = (buttons & 4) ? 0xff : 0; + joysticks[joystick_index].setLEDs(lr, lg, lb); + } + buttons_prev = buttons; + } + + Serial.println(); + joysticks[joystick_index].joystickDataClear(); + } + } + +} + +//============================================================================= +// Show when devices are added or removed +//============================================================================= +void PrintDeviceListChanges() { + for (uint8_t i = 0; i < CNT_DEVICES; i++) { + if (*drivers[i] != driver_active[i]) { + if (driver_active[i]) { + Serial.printf("*** Device %s - disconnected ***\n", driver_names[i]); + driver_active[i] = false; + } else { + Serial.printf("*** Device %s %x:%x - connected ***\n", driver_names[i], drivers[i]->idVendor(), drivers[i]->idProduct()); + driver_active[i] = true; + + const uint8_t *psz = drivers[i]->manufacturer(); + if (psz && *psz) Serial.printf(" manufacturer: %s\n", psz); + psz = drivers[i]->product(); + if (psz && *psz) Serial.printf(" product: %s\n", psz); + psz = drivers[i]->serialNumber(); + if (psz && *psz) Serial.printf(" Serial: %s\n", psz); + } + } + } + + for (uint8_t i = 0; i < CNT_HIDDEVICES; i++) { + if (*hiddrivers[i] != hid_driver_active[i]) { + if (hid_driver_active[i]) { + Serial.printf("*** HID Device %s - disconnected ***\n", hid_driver_names[i]); + hid_driver_active[i] = false; + } else { + Serial.printf("*** HID Device %s %x:%x - connected ***\n", hid_driver_names[i], hiddrivers[i]->idVendor(), hiddrivers[i]->idProduct()); + hid_driver_active[i] = true; + + const uint8_t *psz = hiddrivers[i]->manufacturer(); + if (psz && *psz) Serial.printf(" manufacturer: %s\n", psz); + psz = hiddrivers[i]->product(); + if (psz && *psz) Serial.printf(" product: %s\n", psz); + psz = hiddrivers[i]->serialNumber(); + if (psz && *psz) Serial.printf(" Serial: %s\n", psz); + } + } + } +} diff --git a/examples/Mouse/Mouse.ino b/examples/Mouse/Mouse.ino index d98d00c..71ac9d2 100644 --- a/examples/Mouse/Mouse.ino +++ b/examples/Mouse/Mouse.ino @@ -182,6 +182,7 @@ void loop() break; case JoystickController::XBOXONE: + case JoystickController::XBOX360: ltv = joystick1.getAxis(4); rtv = joystick1.getAxis(5); if ((ltv != joystick_left_trigger_value) || (rtv != joystick_right_trigger_value)) { diff --git a/joystick.cpp b/joystick.cpp index 04f1cc9..747c6c6 100644 --- a/joystick.cpp +++ b/joystick.cpp @@ -32,6 +32,7 @@ // doing other features. JoystickController::product_vendor_mapping_t JoystickController::pid_vid_mapping[] = { { 0x045e, 0x02ea, XBOXONE, false },{ 0x045e, 0x02dd, XBOXONE, false }, + { 0x045e, 0x0719, XBOX360, false}, { 0x054C, 0x0268, PS3, true}, { 0x054C, 0x05C4, PS4, true}, {0x054C, 0x09CC, PS4, true } }; @@ -135,6 +136,23 @@ bool JoystickController::setRumble(uint8_t lValue, uint8_t rValue, uint8_t timeo println("XBoxOne rumble transfer fail"); } return true; // + case XBOX360: + txbuf_[0] = 0x00; + txbuf_[1] = 0x01; + txbuf_[2] = 0x0F; + txbuf_[3] = 0xC0; + txbuf_[4] = 0x00; + txbuf_[5] = lValue; + txbuf_[6] = rValue; + txbuf_[7] = 0x00; + txbuf_[8] = 0x00; + txbuf_[9] = 0x00; + txbuf_[10] = 0x00; + txbuf_[11] = 0x00; + if (!queue_Data_Transfer(txpipe_, txbuf_, 12, this)) { + println("XBox360 rumble transfer fail"); + } + return true; } return false; } @@ -153,6 +171,27 @@ bool JoystickController::setLEDs(uint8_t lr, uint8_t lg, uint8_t lb) return transmitPS3UserFeedbackMsg(); case PS4: return transmitPS4UserFeedbackMsg(); + case XBOX360: + // 0: off, 1: all blink then return to before + // 2-5(TL, TR, BL, BR) - blink on then stay on + // 6-9() - On + // ... + txbuf_[1] = 0x00; + txbuf_[2] = 0x08; + txbuf_[3] = 0x40 + lr; + txbuf_[4] = 0x00; + txbuf_[5] = 0x00; + txbuf_[6] = 0x00; + txbuf_[7] = 0x00; + txbuf_[8] = 0x00; + txbuf_[9] = 0x00; + txbuf_[10] = 0x00; + txbuf_[11] = 0x00; + if (!queue_Data_Transfer(txpipe_, txbuf_, 12, this)) { + println("XBox360 set leds fail"); + } + return true; + case XBOXONE: default: return false; } @@ -213,11 +252,16 @@ hidclaim_t JoystickController::claim_collection(USBHIDParser *driver, Device_t * if (topusage != 0x10004 && topusage != 0x10005) return CLAIM_NO; // only claim from one physical device if (mydevice != NULL && dev != mydevice) return CLAIM_NO; + + // Also don't allow us to claim if it is used as a standard usb object (XBox...) + if (device != nullptr) return CLAIM_NO; + mydevice = dev; collections_claimed++; anychange = true; // always report values on first read driver_ = driver; // remember the driver. driver_->setTXBuffers(txbuf_, nullptr, sizeof(txbuf_)); + connected_ = true; // remember that hardware is actually connected... // Lets see if we know what type of joystick this is. That is, is it a PS3 or PS4 or ... joystickType = mapVIDPIDtoJoystickType(mydevice->idVendor, mydevice->idProduct, false); @@ -323,7 +367,7 @@ void JoystickController::hid_input_end() bool JoystickController::hid_process_out_data(const Transfer_t *transfer) { - Serial.printf("JoystickController::hid_process_out_data\n"); + //Serial.printf("JoystickController::hid_process_out_data\n"); return true; } @@ -339,14 +383,19 @@ void JoystickController::joystickDataClear() { // Example: XBox One controller. //***************************************************************************** -static uint8_t start_input[] = {0x05, 0x20, 0x00, 0x01, 0x00}; +static uint8_t xboxone_start_input[] = {0x05, 0x20, 0x00, 0x01, 0x00}; +static uint8_t xbox360w_inquire_present[] = {0x08, 0x00, 0x0F, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; bool JoystickController::claim(Device_t *dev, int type, const uint8_t *descriptors, uint32_t len) { println("JoystickController claim this=", (uint32_t)this, HEX); - // only claim at device level - if (type != 0) return false; + // Don't try to claim if it is used as USB device or HID device + if (mydevice != NULL) return false; + if (device != nullptr) return false; + + // Try claiming at the interface level. + if (type != 1) return false; print_hexbytes(descriptors, len); JoystickController::joytype_t jtype = mapVIDPIDtoJoystickType(dev->idVendor, dev->idProduct, true); @@ -354,21 +403,38 @@ bool JoystickController::claim(Device_t *dev, int type, const uint8_t *descripto if (jtype == UNKNOWN) return false; - // 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 9 30 1... + // XBOX One + // 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 9 30 1... // 09 04 00 00 02 FF 47 D0 00 07 05 02 03 40 00 04 07 05 82 03 40 00 04 09 04 01 00 00 FF 47 D0 00 // Lets do some verifications to make sure. + // XBOX 360 wireless... Has 8 interfaces. 4 joysticks (1, 3, 5, 7) and 4 headphones assume 2,4,6, 8... + // 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 81 00 14 22 00 01 13 81 1D 00 17 01 02 08 13 01 0C 00 0C 01 02 08 + + // 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 + if (len < 9+7+7) return false; + // Some common stuff for both XBoxs uint32_t count_end_points = descriptors[4]; if (count_end_points < 2) return false; if (descriptors[5] != 0xff) return false; // bInterfaceClass, 3 = HID - uint32_t rxep = 0; + rx_ep_ = 0; uint32_t txep = 0; + uint8_t rx_interval = 0; + uint8_t tx_interval = 0; rx_size_ = 0; tx_size_ = 0; uint32_t descriptor_index = 9; - while (count_end_points-- && ((rxep == 0) || txep == 0)) { + if (descriptors[descriptor_index+1] == 0x22) { + if (descriptors[descriptor_index] != 0x14) return false; // only support specific versions... + descriptor_index += descriptors[descriptor_index]; // XBox360w ignore this unknown setup... + } + while (count_end_points-- && ((rx_ep_ == 0) || txep == 0)) { if (descriptors[descriptor_index] != 7) return false; // length 7 if (descriptors[descriptor_index+1] != 5) return false; // ep desc if ((descriptors[descriptor_index+3] == 3) // Type 3... @@ -376,24 +442,26 @@ bool JoystickController::claim(Device_t *dev, int type, const uint8_t *descripto && (descriptors[descriptor_index+5] == 0)) { // have a bulk EP size if (descriptors[descriptor_index+2] & 0x80 ) { - rxep = descriptors[descriptor_index+2]; + rx_ep_ = descriptors[descriptor_index+2]; rx_size_ = descriptors[descriptor_index+4]; + rx_interval = descriptors[descriptor_index+6]; } else { txep = descriptors[descriptor_index+2]; tx_size_ = descriptors[descriptor_index+4]; + tx_interval = descriptors[descriptor_index+6]; } } descriptor_index += 7; // setup to look at next one... } - if ((rxep == 0) || (txep == 0)) return false; // did not find two end points. - print("JoystickController, rxep=", rxep & 15); + if ((rx_ep_ == 0) || (txep == 0)) return false; // did not find two end points. + print("JoystickController, rx_ep_=", rx_ep_ & 15); print("(", rx_size_); print("), txep=", txep); print("(", tx_size_); println(")"); - rxpipe_ = new_Pipe(dev, 2, rxep & 15, 1, rx_size_); + rxpipe_ = new_Pipe(dev, 3, rx_ep_ & 15, 1, rx_size_, rx_interval); if (!rxpipe_) return false; - txpipe_ = new_Pipe(dev, 2, txep, 0, tx_size_); + txpipe_ = new_Pipe(dev, 3, txep, 0, tx_size_, tx_interval); if (!txpipe_) { //free_Pipe(rxpipe_); return false; @@ -403,7 +471,13 @@ bool JoystickController::claim(Device_t *dev, int type, const uint8_t *descripto txpipe_->callback_function = tx_callback; - queue_Data_Transfer(txpipe_, start_input, sizeof(start_input), this); + if (jtype == XBOXONE) { + queue_Data_Transfer(txpipe_, xboxone_start_input, sizeof(xboxone_start_input), this); + connected_ = true; // remember that hardware is actually connected... + } else if (jtype == XBOX360) { + queue_Data_Transfer(txpipe_, xbox360w_inquire_present, sizeof(xbox360w_inquire_present), this); + connected_ = 0; // remember that hardware is actually connected... + } memset(axis, 0, sizeof(axis)); // clear out any data. joystickType = jtype; // remember we are an XBox One. return true; @@ -447,38 +521,113 @@ typedef struct { // dpad up, down left, right // lb, rb, left stick, right stick // Axis: - // lt, rt, lx, xy, rx, ry + // 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}; void JoystickController::rx_data(const Transfer_t *transfer) { -// print("JoystickController::rx_data: "); -// print_hexbytes((uint8_t*)transfer->buffer, transfer->length); - axis_mask_ = 0x3f; - axis_changed_mask_ = 0; // assume none for now - xbox1data20_t *xb1d = (xbox1data20_t *)transfer->buffer; - if ((xb1d->type == 0x20) && (transfer->length >= sizeof (xbox1data20_t))) { - // We have a data transfer. Lets see what is new... - if (xb1d->buttons != buttons) { - buttons = xb1d->buttons; - anychange = true; - } - for (uint8_t i = 0; i < sizeof (xbox_axis_order_mapping); i++) { - // The first two values were unsigned. - int axis_value = (i < 2)? (int)(uint16_t)xb1d->axis[i] : xb1d->axis[i]; - if (axis_value != axis[xbox_axis_order_mapping[i]]) { - axis[xbox_axis_order_mapping[i]] = axis_value; + print("JoystickController::rx_data: "); + print_hexbytes((uint8_t*)transfer->buffer, transfer->length); + + if (joystickType == XBOXONE) { + // Process XBOX One data + axis_mask_ = 0x3f; + axis_changed_mask_ = 0; // assume none for now + xbox1data20_t *xb1d = (xbox1data20_t *)transfer->buffer; + if ((xb1d->type == 0x20) && (transfer->length >= sizeof (xbox1data20_t))) { + // We have a data transfer. Lets see what is new... + if (xb1d->buttons != buttons) { + buttons = xb1d->buttons; anychange = true; } + for (uint8_t i = 0; i < sizeof (xbox_axis_order_mapping); i++) { + // The first two values were unsigned. + int axis_value = (i < 2)? (int)(uint16_t)xb1d->axis[i] : xb1d->axis[i]; + if (axis_value != axis[xbox_axis_order_mapping[i]]) { + axis[xbox_axis_order_mapping[i]] = axis_value; + axis_changed_mask_ |= (1 << xbox_axis_order_mapping[i]); + anychange = true; + } + } + joystickEvent = true; } - joystickEvent = true; - } + } else if (joystickType == XBOX360) { + // First byte appears to status - if the byte is 0x8 it is a connect or disconnect of the controller. + xbox360data_t *xb360d = (xbox360data_t *)transfer->buffer; + if (xb360d->state == 0x08) { + if (xb360d->id_or_type != connected_) { + connected_ = xb360d->id_or_type; // remember it... + if (connected_) { + println("XBox360w - Connected type:", connected_, HEX); + // rx_ep_ should be 1, 3, 5, 7 for the wireless convert to 2-5 on led + setLEDs(2+rx_ep_/2); // Right now hard coded to first joystick... + + } else { + println("XBox360w - disconnected"); + } + } + } else if((xb360d->id_or_type == 0x00) && (xb360d->controller_status & 0x1300)) { + // Controller status report - Maybe we should save away and allow the user access? + println("XBox360w - controllerStatus: ", xb360d->controller_status, HEX); + } else if(xb360d->id_or_type == 0x01) { // Lets only process report 1. + //const uint8_t *pbuffer = (uint8_t*)transfer->buffer; + //for (uint8_t i = 0; i < transfer->length; i++) Serial.printf("%02x ", pbuffer[i]); + //Serial.printf("\n"); + + if (buttons != xb360d->buttons) { + buttons = xb360d->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] != 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; + } + } queue_Data_Transfer(rxpipe_, rxbuf_, rx_size_, this); } diff --git a/keywords.txt b/keywords.txt index 8cbfb19..25f2630 100644 --- a/keywords.txt +++ b/keywords.txt @@ -9,7 +9,7 @@ USBSerial KEYWORD1 AntPlus KEYWORD1 JoystickController KEYWORD1 RawHIDController KEYWORD1 - +BluetoothController KEYWORD1 # Common Functions Task KEYWORD2 idVendor KEYWORD2 @@ -90,6 +90,7 @@ joystickType KEYWORD2 PS3 LITERAL1 PS4 LITERAL1 XBOXONE LITERAL1 +XBOX360 LITERAL1 # USBSerial USBHOST_SERIAL_7E1 LITERAL1