Skip to content

Commit

Permalink
Add player LED support for Xbox One
Browse files Browse the repository at this point in the history
  • Loading branch information
arntsonl committed Sep 29, 2024
1 parent ad31775 commit 9544ce0
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 3 deletions.
10 changes: 9 additions & 1 deletion headers/drivers/xbone/XBOneDescriptors.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions headers/drivers/xbone/XBOneDriver.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_
18 changes: 18 additions & 0 deletions src/addons/neopicoleds.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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] = {
Expand Down Expand Up @@ -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;
}
Expand Down
6 changes: 6 additions & 0 deletions src/drivers/xbone/XBOneAuthUSBListener.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <queue>
Expand Down Expand Up @@ -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));
Expand Down
24 changes: 22 additions & 2 deletions src/drivers/xbone/XBOneDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "drivers/xbone/XBOneAuth.h"
#include "peripheralmanager.h"
#include "storagemanager.h"

#define XBONE_KEEPALIVE_TIMER 15000

Expand Down Expand Up @@ -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 <queue>
Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}


Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 9544ce0

Please sign in to comment.