mirror of https://github.com/encounter/SDL.git
Simplified Xbox One controller initialization state, and don't query for the serial number.
This commit is contained in:
parent
9fc4a4c92c
commit
7d92b14f46
|
@ -40,9 +40,8 @@
|
||||||
/* Define this if you want to log all packets from the controller */
|
/* Define this if you want to log all packets from the controller */
|
||||||
/*#define DEBUG_XBOX_PROTOCOL*/
|
/*#define DEBUG_XBOX_PROTOCOL*/
|
||||||
|
|
||||||
#define CONTROLLER_ANNOUNCE_TIMEOUT_MS 100
|
#define CONTROLLER_NEGOTIATION_TIMEOUT_MS 300
|
||||||
#define CONTROLLER_NEGOTIATION_TIMEOUT_MS 30
|
#define CONTROLLER_PREPARE_INPUT_TIMEOUT_MS 50
|
||||||
#define CONTROLLER_SERIAL_TIMEOUT_MS 100
|
|
||||||
|
|
||||||
|
|
||||||
/* Connect controller */
|
/* Connect controller */
|
||||||
|
@ -110,14 +109,10 @@ typedef enum {
|
||||||
} SDL_XboxOneWirelessProtocol;
|
} SDL_XboxOneWirelessProtocol;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
XBOX_ONE_INIT_STATE_WAITING_FOR_ANNOUNCE = 0,
|
XBOX_ONE_INIT_STATE_START_NEGOTIATING = 0,
|
||||||
XBOX_ONE_INIT_STATE_RECEIVED_ANNOUNCE = 1,
|
XBOX_ONE_INIT_STATE_NEGOTIATING = 1,
|
||||||
XBOX_ONE_INIT_STATE_START_NEGOTIATING = 2,
|
XBOX_ONE_INIT_STATE_PREPARE_INPUT = 2,
|
||||||
XBOX_ONE_INIT_STATE_NEGOTIATING = 3,
|
XBOX_ONE_INIT_STATE_COMPLETE = 3
|
||||||
XBOX_ONE_INIT_STATE_READY = 4,
|
|
||||||
XBOX_ONE_INIT_STATE_WAITING_FOR_SERIAL = 5,
|
|
||||||
XBOX_ONE_INIT_STATE_RECEIVED_SERIAL = 6,
|
|
||||||
XBOX_ONE_INIT_STATE_COMPLETE = 7
|
|
||||||
} SDL_XboxOneInitState;
|
} SDL_XboxOneInitState;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -127,7 +122,6 @@ typedef struct {
|
||||||
SDL_XboxOneWirelessProtocol wireless_protocol;
|
SDL_XboxOneWirelessProtocol wireless_protocol;
|
||||||
SDL_XboxOneInitState init_state;
|
SDL_XboxOneInitState init_state;
|
||||||
int init_packet;
|
int init_packet;
|
||||||
SDL_bool input_ready;
|
|
||||||
Uint32 start_time;
|
Uint32 start_time;
|
||||||
Uint8 sequence;
|
Uint8 sequence;
|
||||||
Uint32 send_time;
|
Uint32 send_time;
|
||||||
|
@ -149,7 +143,8 @@ IsBluetoothXboxOneController(Uint16 vendor_id, Uint16 product_id)
|
||||||
if (vendor_id == USB_VENDOR_MICROSOFT) {
|
if (vendor_id == USB_VENDOR_MICROSOFT) {
|
||||||
if (product_id == USB_PRODUCT_XBOX_ONE_S_REV1_BLUETOOTH ||
|
if (product_id == USB_PRODUCT_XBOX_ONE_S_REV1_BLUETOOTH ||
|
||||||
product_id == USB_PRODUCT_XBOX_ONE_S_REV2_BLUETOOTH ||
|
product_id == USB_PRODUCT_XBOX_ONE_S_REV2_BLUETOOTH ||
|
||||||
product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2_BLUETOOTH) {
|
product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2_BLUETOOTH ||
|
||||||
|
product_id == USB_PRODUCT_XBOX_ONE_SERIES_X_BLUETOOTH) {
|
||||||
return SDL_TRUE;
|
return SDL_TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -205,6 +200,7 @@ SendAckIfNeeded(SDL_HIDAPI_Device *device, Uint8 *data, int size)
|
||||||
#endif /* __WIN32__ */
|
#endif /* __WIN32__ */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
static SDL_bool
|
static SDL_bool
|
||||||
SendSerialRequest(SDL_HIDAPI_Device *device, SDL_DriverXboxOne_Context *ctx)
|
SendSerialRequest(SDL_HIDAPI_Device *device, SDL_DriverXboxOne_Context *ctx)
|
||||||
{
|
{
|
||||||
|
@ -212,7 +208,11 @@ SendSerialRequest(SDL_HIDAPI_Device *device, SDL_DriverXboxOne_Context *ctx)
|
||||||
|
|
||||||
ctx->send_time = SDL_GetTicks();
|
ctx->send_time = SDL_GetTicks();
|
||||||
|
|
||||||
/* Request the serial number */
|
/* Request the serial number
|
||||||
|
* Sending this should be done only after the negotiation is complete.
|
||||||
|
* It will cancel the announce packet if sent before that, and will be
|
||||||
|
* ignored if sent during the negotiation.
|
||||||
|
*/
|
||||||
if (SDL_HIDAPI_LockRumble() < 0 ||
|
if (SDL_HIDAPI_LockRumble() < 0 ||
|
||||||
SDL_HIDAPI_SendRumbleAndUnlock(device, serial_packet, sizeof(serial_packet)) != sizeof(serial_packet)) {
|
SDL_HIDAPI_SendRumbleAndUnlock(device, serial_packet, sizeof(serial_packet)) != sizeof(serial_packet)) {
|
||||||
SDL_SetError("Couldn't send serial packet");
|
SDL_SetError("Couldn't send serial packet");
|
||||||
|
@ -220,6 +220,17 @@ SendSerialRequest(SDL_HIDAPI_Device *device, SDL_DriverXboxOne_Context *ctx)
|
||||||
}
|
}
|
||||||
return SDL_TRUE;
|
return SDL_TRUE;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static SDL_bool
|
||||||
|
ControllerNeedsNegotiation(SDL_DriverXboxOne_Context *ctx)
|
||||||
|
{
|
||||||
|
if (ctx->vendor_id == USB_VENDOR_PDP && ctx->product_id == 0x0246) {
|
||||||
|
/* The PDP Rock Candy (PID 0x0246) doesn't send the announce packet on Linux for some reason */
|
||||||
|
return SDL_TRUE;
|
||||||
|
}
|
||||||
|
return SDL_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
static SDL_bool
|
static SDL_bool
|
||||||
SendControllerInit(SDL_HIDAPI_Device *device, SDL_DriverXboxOne_Context *ctx)
|
SendControllerInit(SDL_HIDAPI_Device *device, SDL_DriverXboxOne_Context *ctx)
|
||||||
|
@ -267,8 +278,8 @@ SendControllerInit(SDL_HIDAPI_Device *device, SDL_DriverXboxOne_Context *ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* All done with the negotiation! */
|
/* All done with the negotiation, prepare for input! */
|
||||||
SetInitState(ctx, XBOX_ONE_INIT_STATE_READY);
|
SetInitState(ctx, XBOX_ONE_INIT_STATE_PREPARE_INPUT);
|
||||||
|
|
||||||
return SDL_TRUE;
|
return SDL_TRUE;
|
||||||
}
|
}
|
||||||
|
@ -344,6 +355,14 @@ HIDAPI_DriverXboxOne_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joyst
|
||||||
ctx->has_paddles = ControllerHasPaddles(ctx->vendor_id, ctx->product_id);
|
ctx->has_paddles = ControllerHasPaddles(ctx->vendor_id, ctx->product_id);
|
||||||
ctx->has_trigger_rumble = ControllerHasTriggerRumble(ctx->vendor_id, ctx->product_id);
|
ctx->has_trigger_rumble = ControllerHasTriggerRumble(ctx->vendor_id, ctx->product_id);
|
||||||
ctx->has_share_button = ControllerHasShareButton(ctx->vendor_id, ctx->product_id);
|
ctx->has_share_button = ControllerHasShareButton(ctx->vendor_id, ctx->product_id);
|
||||||
|
|
||||||
|
/* Assume that the controller is correctly initialized when we start */
|
||||||
|
if (ControllerNeedsNegotiation(ctx)) {
|
||||||
|
ctx->init_state = XBOX_ONE_INIT_STATE_START_NEGOTIATING;
|
||||||
|
} else {
|
||||||
|
ctx->init_state = XBOX_ONE_INIT_STATE_COMPLETE;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_JOYSTICK
|
#ifdef DEBUG_JOYSTICK
|
||||||
SDL_Log("Controller version: %d (0x%.4x)\n", device->version, device->version);
|
SDL_Log("Controller version: %d (0x%.4x)\n", device->version, device->version);
|
||||||
#endif
|
#endif
|
||||||
|
@ -359,32 +378,6 @@ HIDAPI_DriverXboxOne_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joyst
|
||||||
joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
|
joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
|
||||||
joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
|
joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
|
||||||
|
|
||||||
#ifdef __WIN32__
|
|
||||||
ctx->init_state = XBOX_ONE_INIT_STATE_READY;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (ctx->bluetooth) {
|
|
||||||
ctx->init_state = XBOX_ONE_INIT_STATE_COMPLETE;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG_JOYSTICK
|
|
||||||
SDL_Log("Controller init state: %d\n", ctx->init_state);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Wait for initialization to complete */
|
|
||||||
while (ctx->init_state != XBOX_ONE_INIT_STATE_COMPLETE) {
|
|
||||||
SDL_Delay(1);
|
|
||||||
|
|
||||||
if (!HIDAPI_DriverXboxOne_UpdateJoystick(device, joystick)) {
|
|
||||||
HIDAPI_DriverXboxOne_CloseJoystick(device, joystick);
|
|
||||||
return SDL_FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ctx->input_ready = SDL_TRUE;
|
|
||||||
|
|
||||||
#ifdef DEBUG_JOYSTICK
|
|
||||||
SDL_Log("Controller initialization took %u ms\n", (SDL_GetTicks() - ctx->start_time));
|
|
||||||
#endif
|
|
||||||
return SDL_TRUE;
|
return SDL_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -888,26 +881,20 @@ HIDAPI_DriverXboxOne_UpdateInitState(SDL_HIDAPI_Device *device, SDL_DriverXboxOn
|
||||||
prev_state = ctx->init_state;
|
prev_state = ctx->init_state;
|
||||||
|
|
||||||
switch (ctx->init_state) {
|
switch (ctx->init_state) {
|
||||||
case XBOX_ONE_INIT_STATE_WAITING_FOR_ANNOUNCE:
|
|
||||||
if (SDL_TICKS_PASSED(SDL_GetTicks(), ctx->start_time + CONTROLLER_ANNOUNCE_TIMEOUT_MS)) {
|
|
||||||
/* We haven't heard anything, let's move on */
|
|
||||||
#ifdef DEBUG_JOYSTICK
|
|
||||||
SDL_Log("Waiting for announce timed out after %u ms\n", (SDL_GetTicks() - ctx->start_time));
|
|
||||||
#endif
|
|
||||||
SetInitState(ctx, XBOX_ONE_INIT_STATE_START_NEGOTIATING);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case XBOX_ONE_INIT_STATE_RECEIVED_ANNOUNCE:
|
|
||||||
SetInitState(ctx, XBOX_ONE_INIT_STATE_START_NEGOTIATING);
|
|
||||||
break;
|
|
||||||
case XBOX_ONE_INIT_STATE_START_NEGOTIATING:
|
case XBOX_ONE_INIT_STATE_START_NEGOTIATING:
|
||||||
|
#ifdef __WIN32__
|
||||||
|
/* The Windows driver is taking care of negotiation */
|
||||||
|
SetInitState(ctx, XBOX_ONE_INIT_STATE_COMPLETE);
|
||||||
|
#else
|
||||||
|
SetInitState(ctx, XBOX_ONE_INIT_STATE_NEGOTIATING);
|
||||||
ctx->init_packet = 0;
|
ctx->init_packet = 0;
|
||||||
if (!SendControllerInit(device, ctx)) {
|
if (!SendControllerInit(device, ctx)) {
|
||||||
return SDL_FALSE;
|
return SDL_FALSE;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
case XBOX_ONE_INIT_STATE_NEGOTIATING:
|
case XBOX_ONE_INIT_STATE_NEGOTIATING:
|
||||||
if (SDL_TICKS_PASSED(SDL_GetTicks(), ctx->send_time + CONTROLLER_ANNOUNCE_TIMEOUT_MS)) {
|
if (SDL_TICKS_PASSED(SDL_GetTicks(), ctx->send_time + CONTROLLER_NEGOTIATION_TIMEOUT_MS)) {
|
||||||
/* We haven't heard anything, let's move on */
|
/* We haven't heard anything, let's move on */
|
||||||
#ifdef DEBUG_JOYSTICK
|
#ifdef DEBUG_JOYSTICK
|
||||||
SDL_Log("Init sequence %d timed out after %u ms\n", ctx->init_packet, (SDL_GetTicks() - ctx->send_time));
|
SDL_Log("Init sequence %d timed out after %u ms\n", ctx->init_packet, (SDL_GetTicks() - ctx->send_time));
|
||||||
|
@ -918,28 +905,14 @@ HIDAPI_DriverXboxOne_UpdateInitState(SDL_HIDAPI_Device *device, SDL_DriverXboxOn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case XBOX_ONE_INIT_STATE_READY:
|
case XBOX_ONE_INIT_STATE_PREPARE_INPUT:
|
||||||
if (device->version >= 0x200) {
|
if (SDL_TICKS_PASSED(SDL_GetTicks(), ctx->send_time + CONTROLLER_PREPARE_INPUT_TIMEOUT_MS)) {
|
||||||
if (!SendSerialRequest(device, ctx)) {
|
|
||||||
return SDL_FALSE;
|
|
||||||
}
|
|
||||||
SetInitState(ctx, XBOX_ONE_INIT_STATE_WAITING_FOR_SERIAL);
|
|
||||||
} else {
|
|
||||||
SetInitState(ctx, XBOX_ONE_INIT_STATE_COMPLETE);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case XBOX_ONE_INIT_STATE_WAITING_FOR_SERIAL:
|
|
||||||
if (SDL_TICKS_PASSED(SDL_GetTicks(), ctx->send_time + CONTROLLER_SERIAL_TIMEOUT_MS)) {
|
|
||||||
/* We haven't heard anything, let's move on */
|
|
||||||
#ifdef DEBUG_JOYSTICK
|
#ifdef DEBUG_JOYSTICK
|
||||||
SDL_Log("Waiting for serial timed out after %u ms\n", (SDL_GetTicks() - ctx->send_time));
|
SDL_Log("Prepare input complete after %u ms\n", (SDL_GetTicks() - ctx->send_time));
|
||||||
#endif
|
#endif
|
||||||
SetInitState(ctx, XBOX_ONE_INIT_STATE_COMPLETE);
|
SetInitState(ctx, XBOX_ONE_INIT_STATE_COMPLETE);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case XBOX_ONE_INIT_STATE_RECEIVED_SERIAL:
|
|
||||||
SetInitState(ctx, XBOX_ONE_INIT_STATE_COMPLETE);
|
|
||||||
break;
|
|
||||||
case XBOX_ONE_INIT_STATE_COMPLETE:
|
case XBOX_ONE_INIT_STATE_COMPLETE:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1008,12 +981,15 @@ HIDAPI_DriverXboxOne_UpdateJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joy
|
||||||
is firmware version 5.5.2641.0, and product version 0x0505 = 1285
|
is firmware version 5.5.2641.0, and product version 0x0505 = 1285
|
||||||
then 8 bytes of unknown data
|
then 8 bytes of unknown data
|
||||||
*/
|
*/
|
||||||
SetInitState(ctx, XBOX_ONE_INIT_STATE_RECEIVED_ANNOUNCE);
|
#ifdef DEBUG_JOYSTICK
|
||||||
|
SDL_Log("Controller announce after %u ms\n", (SDL_GetTicks() - ctx->start_time));
|
||||||
|
#endif
|
||||||
|
SetInitState(ctx, XBOX_ONE_INIT_STATE_START_NEGOTIATING);
|
||||||
break;
|
break;
|
||||||
case 0x03:
|
case 0x03:
|
||||||
/* Controller heartbeat */
|
/* Controller heartbeat */
|
||||||
if (ctx->init_state < XBOX_ONE_INIT_STATE_READY) {
|
if (ctx->init_state < XBOX_ONE_INIT_STATE_COMPLETE) {
|
||||||
SetInitState(ctx, XBOX_ONE_INIT_STATE_READY);
|
SetInitState(ctx, XBOX_ONE_INIT_STATE_COMPLETE);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x04:
|
case 0x04:
|
||||||
|
@ -1037,19 +1013,19 @@ HIDAPI_DriverXboxOne_UpdateJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joy
|
||||||
*/
|
*/
|
||||||
if (size == 20 && data[3] == 0x10) {
|
if (size == 20 && data[3] == 0x10) {
|
||||||
HIDAPI_DriverXboxOne_HandleSerialIDPacket(joystick, ctx, data, size);
|
HIDAPI_DriverXboxOne_HandleSerialIDPacket(joystick, ctx, data, size);
|
||||||
|
|
||||||
if (ctx->init_state < XBOX_ONE_INIT_STATE_RECEIVED_SERIAL) {
|
|
||||||
SetInitState(ctx, XBOX_ONE_INIT_STATE_RECEIVED_SERIAL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x20:
|
case 0x20:
|
||||||
if (ctx->init_state < XBOX_ONE_INIT_STATE_READY) {
|
if (ctx->init_state < XBOX_ONE_INIT_STATE_COMPLETE) {
|
||||||
SetInitState(ctx, XBOX_ONE_INIT_STATE_READY);
|
SetInitState(ctx, XBOX_ONE_INIT_STATE_COMPLETE);
|
||||||
|
|
||||||
|
/* Ignore the first input, it may be spurious */
|
||||||
|
#ifdef DEBUG_JOYSTICK
|
||||||
|
SDL_Log("Controller ignoring spurious input\n");
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (ctx->input_ready) {
|
|
||||||
HIDAPI_DriverXboxOne_HandleStatePacket(joystick, device->dev, ctx, data, size);
|
HIDAPI_DriverXboxOne_HandleStatePacket(joystick, device->dev, ctx, data, size);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
#ifdef DEBUG_JOYSTICK
|
#ifdef DEBUG_JOYSTICK
|
||||||
|
|
Loading…
Reference in New Issue