diff --git a/headers/drivers/xbone/XBOneDescriptors.h b/headers/drivers/xbone/XBOneDescriptors.h index dae34a32f..99fa63fcf 100644 --- a/headers/drivers/xbone/XBOneDescriptors.h +++ b/headers/drivers/xbone/XBOneDescriptors.h @@ -60,7 +60,7 @@ typedef enum GIP_AUTH = 0x06, // Xbox One Authentication GIP_VIRTUAL_KEYCODE = 0x07, // XBox One Guide button pressed GIP_CMD_RUMBLE = 0x09, // Xbox One Rumble Command - GIP_CMD_WAKEUP = 0x0A, // Xbox One (Wake-up Maybe?) + GIP_CMD_LED_ON = 0x0A, // Xbox One (LED On) GIP_FINAL_AUTH = 0x1E, // Xbox One (Final auth?) GIP_INPUT_REPORT = 0x20, // Xbox One Input Report GIP_HID_REPORT = 0x21, // Xbox One HID Report @@ -109,6 +109,14 @@ typedef struct { uint8_t back : 1; // view } __attribute__((packed)) XboxOneInputHeader_Data_t; +typedef struct +{ + GipHeader_t Header; + uint8_t unk; + uint8_t mode; + uint8_t brightness; +} __attribute__((packed)) XboxOneLED_Data_t; + static const uint8_t xbone_device_qualifier[] = { 0x0A, // bLength diff --git a/headers/drivers/xbone/XBOneDriver.h b/headers/drivers/xbone/XBOneDriver.h index 2a568e5bb..1868c74e7 100644 --- a/headers/drivers/xbone/XBOneDriver.h +++ b/headers/drivers/xbone/XBOneDriver.h @@ -41,6 +41,7 @@ class XBOneDriver : public GPDriver { uint8_t virtual_keycode_sequence; bool xb1_guide_pressed; GPAuthDriver * authDriver; + uint8_t xbone_led_mode; }; #endif // _XBONE_DRIVER_H_ diff --git a/src/addons/neopicoleds.cpp b/src/addons/neopicoleds.cpp index fd9e65fd3..6571a05b7 100644 --- a/src/addons/neopicoleds.cpp +++ b/src/addons/neopicoleds.cpp @@ -116,6 +116,21 @@ PLEDAnimationState getXInputAnimationNEOPICO(uint16_t ledState) return animationState; } +PLEDAnimationState getXBoneAnimationNEOPICO(Gamepad * gamepad) +{ + PLEDAnimationState animationState = + { + .state = (PLED_STATE_LED1 | PLED_STATE_LED2 | PLED_STATE_LED3 | PLED_STATE_LED4), + .animation = PLED_ANIM_OFF + }; + + if ( gamepad->auxState.playerID.ledValue == 1 ) { + animationState.animation = PLED_ANIM_SOLID; + } + + return animationState; +} + PLEDAnimationState getPS3AnimationNEOPICO(uint16_t ledState) { const uint8_t ps3LEDs[10][4] = { @@ -226,6 +241,9 @@ void NeoPicoLEDAddon::process() case INPUT_MODE_PS5: animationState = getPS4AnimationNEOPICO(gamepad->auxState.playerID.ledBlinkOn, gamepad->auxState.playerID.ledBlinkOff); break; + case INPUT_MODE_XBONE: + animationState = getXBoneAnimationNEOPICO(gamepad); + break; default: break; } diff --git a/src/drivers/xbone/XBOneAuthUSBListener.cpp b/src/drivers/xbone/XBOneAuthUSBListener.cpp index 4ffade869..99b5801d0 100644 --- a/src/drivers/xbone/XBOneAuthUSBListener.cpp +++ b/src/drivers/xbone/XBOneAuthUSBListener.cpp @@ -15,6 +15,7 @@ static uint8_t xb1_power_on[] = {0x06, 0x62, 0x45, 0xb8, 0x77, 0x26, 0x2c, 0x55, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f}; static uint8_t xb1_power_on_single[] = {0x00}; static uint8_t xb1_rumble_on[] = {0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xeb}; +static uint8_t xb1_led_on[] = {0x00, 0x01, 0x14}; // 0x01 - LED on, 0x14 - Brightness // Report Queue for big report sizes from dongle #include @@ -124,6 +125,11 @@ void XBOneAuthUSBListener::report_received(uint8_t dev_addr, uint8_t instance, u outgoingXGIP.setData(xb1_power_on_single, sizeof(xb1_power_on_single)); queue_host_report((uint8_t*)outgoingXGIP.generatePacket(), outgoingXGIP.getPacketLength()); + outgoingXGIP.reset(); // LED On + outgoingXGIP.setAttributes(GIP_CMD_LED_ON, 1, 0, false, 0); // not internal function + outgoingXGIP.setData(xb1_led_on, sizeof(xb1_led_on)); + queue_host_report((uint8_t*)outgoingXGIP.generatePacket(), outgoingXGIP.getPacketLength()); + outgoingXGIP.reset(); // Rumble Support to enable dongle outgoingXGIP.setAttributes(GIP_CMD_RUMBLE, 1, 0, false, 0); // not internal function outgoingXGIP.setData(xb1_rumble_on, sizeof(xb1_rumble_on)); diff --git a/src/drivers/xbone/XBOneDriver.cpp b/src/drivers/xbone/XBOneDriver.cpp index e3c3c130d..e6904c632 100644 --- a/src/drivers/xbone/XBOneDriver.cpp +++ b/src/drivers/xbone/XBOneDriver.cpp @@ -3,6 +3,7 @@ #include "drivers/xbone/XBOneAuth.h" #include "peripheralmanager.h" +#include "storagemanager.h" #define XBONE_KEEPALIVE_TIMER 15000 @@ -87,6 +88,8 @@ static bool waiting_ack = false; static uint32_t waiting_ack_timeout=0; static uint32_t timer_wait_for_announce; static bool xbox_one_powered_on; +static uint8_t report_led_mode; +static uint8_t report_led_brightness; // Report Queue for big report sizes from dongle #include @@ -147,6 +150,7 @@ static void xbone_reset(uint8_t rhport) { (void)rhport; timer_wait_for_announce = to_ms_since_boot(get_absolute_time()); xbox_one_powered_on = false; + report_led_mode = 0; // 0 = OFF while(!report_queue.empty()) report_queue.pop(); @@ -271,8 +275,15 @@ bool xbone_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, outgoingXGIP->setAttributes(GIP_DEVICE_DESCRIPTOR, incomingXGIP->getSequence(), 1, 1, 0); outgoingXGIP->setData(xboxOneDescriptor, sizeof(xboxOneDescriptor)); xboneDriverState = XboxOneDriverState::SEND_DESCRIPTOR; - } else if ( command == GIP_POWER_MODE_DEVICE_CONFIG || command == GIP_CMD_WAKEUP || command == GIP_CMD_RUMBLE ) { + } else if ( command == GIP_POWER_MODE_DEVICE_CONFIG ) { + // Power Mode On! xbox_one_powered_on = true; + } else if ( command == GIP_CMD_LED_ON ) { + // Set all player LEDs to on + report_led_mode = incomingXGIP->getData()[1]; // 1 - turn LEDs on + report_led_brightness = incomingXGIP->getData()[2]; // 2 - brightness (ignored for now) + } else if ( command == GIP_CMD_RUMBLE ) { + // TO-DO } else if ( command == GIP_AUTH || command == GIP_FINAL_AUTH) { if (incomingXGIP->getDataLength() == 2 && memcmp(incomingXGIP->getData(), authReady, sizeof(authReady))==0 ) { xboxOneAuthData->authCompleted = true; @@ -339,11 +350,12 @@ void XBOneDriver::initialize() { xb1_guide_pressed = false; last_report_counter = 0; - incomingXGIP = new XGIPProtocol(); outgoingXGIP = new XGIPProtocol(); xboxOneAuthData = nullptr; + + xbone_led_mode = 0; } @@ -375,6 +387,14 @@ void XBOneDriver::process(Gamepad * gamepad) { // Perform update this->update(); + // Check if LEDs need to turn on + if ( xbone_led_mode != report_led_mode ) { + Gamepad * processedGamepad = Storage::getInstance().GetProcessedGamepad(); + processedGamepad->auxState.playerID.active = true; + processedGamepad->auxState.playerID.ledValue = report_led_mode; + processedGamepad->auxState.playerID.ledBlinkOn = report_led_brightness; + } + // No input until auth is ready if ( xboxOneAuthData->authCompleted == false ) { GIP_HEADER((&xboneReport), GIP_INPUT_REPORT, false, last_report_counter);