Use the asynchronous HIDAPI rumble code for Nintendo Switch Pro controllers
authorSam Lantinga <slouken@libsdl.org>
Fri, 07 Feb 2020 11:44:57 -0800
changeset 134915de509fd3a96
parent 13490 1d8cb0c5236b
child 13492 c0f435c3bf24
Use the asynchronous HIDAPI rumble code for Nintendo Switch Pro controllers
src/joystick/hidapi/SDL_hidapi_switch.c
     1.1 --- a/src/joystick/hidapi/SDL_hidapi_switch.c	Fri Feb 07 11:02:34 2020 -0800
     1.2 +++ b/src/joystick/hidapi/SDL_hidapi_switch.c	Fri Feb 07 11:44:57 2020 -0800
     1.3 @@ -31,9 +31,10 @@
     1.4  #include "SDL_timer.h"
     1.5  #include "SDL_joystick.h"
     1.6  #include "SDL_gamecontroller.h"
     1.7 +#include "../../SDL_hints_c.h"
     1.8  #include "../SDL_sysjoystick.h"
     1.9  #include "SDL_hidapijoystick_c.h"
    1.10 -#include "../../SDL_hints_c.h"
    1.11 +#include "SDL_hidapi_rumble.h"
    1.12  
    1.13  
    1.14  #ifdef SDL_JOYSTICK_HIDAPI_SWITCH
    1.15 @@ -192,7 +193,7 @@
    1.16  #pragma pack()
    1.17  
    1.18  typedef struct {
    1.19 -    hid_device *dev;
    1.20 +    SDL_HIDAPI_Device *device;
    1.21      SDL_bool m_bInputOnly;
    1.22      SDL_bool m_bHasHomeLED;
    1.23      SDL_bool m_bUsingBluetooth;
    1.24 @@ -200,6 +201,8 @@
    1.25      Uint8 m_nCommandNumber;
    1.26      SwitchCommonOutputPacket_t m_RumblePacket;
    1.27      Uint8 m_rgucReadBuffer[k_unSwitchMaxOutputPacketLength];
    1.28 +    SDL_bool m_bRumbleActive;
    1.29 +    Uint32 m_unRumbleRefresh;
    1.30  
    1.31      SwitchInputOnlyControllerStatePacket_t m_lastInputOnlyState;
    1.32      SwitchSimpleStatePacket_t m_lastSimpleState;
    1.33 @@ -254,12 +257,21 @@
    1.34  
    1.35  static int ReadInput(SDL_DriverSwitch_Context *ctx)
    1.36  {
    1.37 -    return hid_read_timeout(ctx->dev, ctx->m_rgucReadBuffer, sizeof(ctx->m_rgucReadBuffer), 0);
    1.38 +    /* Make sure we don't try to read at the same time a write is happening */
    1.39 +    if (SDL_AtomicGet(&ctx->device->rumble_pending) > 0) {
    1.40 +        return 0;
    1.41 +    }
    1.42 +
    1.43 +    return hid_read_timeout(ctx->device->dev, ctx->m_rgucReadBuffer, sizeof(ctx->m_rgucReadBuffer), 0);
    1.44  }
    1.45  
    1.46 -static int WriteOutput(SDL_DriverSwitch_Context *ctx, Uint8 *data, int size)
    1.47 +static int WriteOutput(SDL_DriverSwitch_Context *ctx, const Uint8 *data, int size)
    1.48  {
    1.49 -    return hid_write(ctx->dev, data, size);
    1.50 +    /* Use the rumble thread for general asynchronous writes */
    1.51 +    if (SDL_HIDAPI_LockRumble() < 0) {
    1.52 +        return -1;
    1.53 +    }
    1.54 +    return SDL_HIDAPI_SendRumbleAndUnlock(ctx->device, data, size);
    1.55  }
    1.56  
    1.57  static SwitchSubcommandInputPacket_t *ReadSubcommandReply(SDL_DriverSwitch_Context *ctx, ESwitchSubcommandIDs expectedID)
    1.58 @@ -430,6 +442,16 @@
    1.59      ctx->m_RumblePacket.ucPacketNumber = ctx->m_nCommandNumber;
    1.60      ctx->m_nCommandNumber = (ctx->m_nCommandNumber + 1) & 0xF;
    1.61  
    1.62 +    /* Refresh the rumble state periodically */
    1.63 +    if (ctx->m_bRumbleActive) {
    1.64 +        ctx->m_unRumbleRefresh = SDL_GetTicks() + 1000;
    1.65 +        if (!ctx->m_unRumbleRefresh) {
    1.66 +            ctx->m_unRumbleRefresh = 1;
    1.67 +        }
    1.68 +    } else {
    1.69 +        ctx->m_unRumbleRefresh = 0;
    1.70 +    }
    1.71 +
    1.72      return WritePacket(ctx, (Uint8 *)&ctx->m_RumblePacket, sizeof(ctx->m_RumblePacket));
    1.73  }
    1.74  
    1.75 @@ -650,9 +672,10 @@
    1.76          SDL_OutOfMemory();
    1.77          goto error;
    1.78      }
    1.79 +    ctx->device = device;
    1.80      device->context = ctx;
    1.81  
    1.82 -    device->dev = ctx->dev = hid_open_path(device->path, 0);
    1.83 +    device->dev = hid_open_path(device->path, 0);
    1.84      if (!device->dev) {
    1.85          SDL_SetError("Couldn't open %s", device->path);
    1.86          goto error;
    1.87 @@ -765,6 +788,8 @@
    1.88          SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[1]);
    1.89      }
    1.90  
    1.91 +    ctx->m_bRumbleActive = (low_frequency_rumble || high_frequency_rumble) ? SDL_TRUE : SDL_FALSE;
    1.92 +
    1.93      if (!WriteRumble(ctx)) {
    1.94          SDL_SetError("Couldn't send rumble packet");
    1.95          return -1;
    1.96 @@ -1065,6 +1090,11 @@
    1.97          }
    1.98      }
    1.99  
   1.100 +    if (ctx->m_bRumbleActive &&
   1.101 +        SDL_TICKS_PASSED(SDL_GetTicks(), ctx->m_unRumbleRefresh)) {
   1.102 +        WriteRumble(ctx);
   1.103 +    }
   1.104 +
   1.105      if (size < 0) {
   1.106          /* Read error, device is disconnected */
   1.107          HIDAPI_JoystickDisconnected(device, joystick->instance_id);