From 3c9321be39de4250e6406c273e1e86fb286997e4 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Tue, 3 Nov 2026 09:00:04 -0800
Subject: [PATCH] Use the default calibration if we can't load IMU calibration
for Nintendo Switch controllers
Fixes https://github.com/libsdl-org/SDL/issues/16237
---
src/joystick/hidapi/SDL_hidapi_switch.c | 39 ++++++++++++++++---------
1 file changed, 26 insertions(+), 13 deletions(-)
diff --git a/src/joystick/hidapi/SDL_hidapi_switch.c b/src/joystick/hidapi/SDL_hidapi_switch.c
index f272a37e0a74f..dff750fc48b5a 100644
--- a/src/joystick/hidapi/SDL_hidapi_switch.c
+++ b/src/joystick/hidapi/SDL_hidapi_switch.c
@@ -1093,6 +1093,7 @@ static void LoadStickCalibration(SDL_DriverSwitch_Context *ctx)
static bool LoadIMUCalibration(SDL_DriverSwitch_Context *ctx)
{
+ bool have_imu_cal = false;
SwitchSubcommandInputPacket_t *reply = NULL;
// Read Calibration Info
@@ -1144,22 +1145,32 @@ static bool LoadIMUCalibration(SDL_DriverSwitch_Context *ctx)
}
}
- // Gyro zero-rate offset
- ctx->m_IMUScaleData.sGyroOffsetX = sGyroRawX;
- ctx->m_IMUScaleData.sGyroOffsetY = sGyroRawY;
- ctx->m_IMUScaleData.sGyroOffsetZ = sGyroRawZ;
+ if (sAccelSensCoeffX != sAccelRawX &&
+ sAccelSensCoeffY != sAccelRawY &&
+ sAccelSensCoeffZ != sAccelRawZ &&
+ sGyroSensCoeffX != sGyroRawX &&
+ sGyroSensCoeffY != sGyroRawY &&
+ sGyroSensCoeffZ != sGyroRawZ) {
+ // Gyro zero-rate offset
+ ctx->m_IMUScaleData.sGyroOffsetX = sGyroRawX;
+ ctx->m_IMUScaleData.sGyroOffsetY = sGyroRawY;
+ ctx->m_IMUScaleData.sGyroOffsetZ = sGyroRawZ;
- // Accelerometer scale
- ctx->m_IMUScaleData.fAccelScaleX = SWITCH_ACCEL_SCALE_MULT / ((float)sAccelSensCoeffX - (float)sAccelRawX) * SDL_STANDARD_GRAVITY;
- ctx->m_IMUScaleData.fAccelScaleY = SWITCH_ACCEL_SCALE_MULT / ((float)sAccelSensCoeffY - (float)sAccelRawY) * SDL_STANDARD_GRAVITY;
- ctx->m_IMUScaleData.fAccelScaleZ = SWITCH_ACCEL_SCALE_MULT / ((float)sAccelSensCoeffZ - (float)sAccelRawZ) * SDL_STANDARD_GRAVITY;
+ // Accelerometer scale
+ ctx->m_IMUScaleData.fAccelScaleX = SWITCH_ACCEL_SCALE_MULT / ((float)sAccelSensCoeffX - (float)sAccelRawX) * SDL_STANDARD_GRAVITY;
+ ctx->m_IMUScaleData.fAccelScaleY = SWITCH_ACCEL_SCALE_MULT / ((float)sAccelSensCoeffY - (float)sAccelRawY) * SDL_STANDARD_GRAVITY;
+ ctx->m_IMUScaleData.fAccelScaleZ = SWITCH_ACCEL_SCALE_MULT / ((float)sAccelSensCoeffZ - (float)sAccelRawZ) * SDL_STANDARD_GRAVITY;
- // Gyro scale
- ctx->m_IMUScaleData.fGyroScaleX = SWITCH_GYRO_SCALE_MULT / ((float)sGyroSensCoeffX - (float)sGyroRawX) * SDL_PI_F / 180.0f;
- ctx->m_IMUScaleData.fGyroScaleY = SWITCH_GYRO_SCALE_MULT / ((float)sGyroSensCoeffY - (float)sGyroRawY) * SDL_PI_F / 180.0f;
- ctx->m_IMUScaleData.fGyroScaleZ = SWITCH_GYRO_SCALE_MULT / ((float)sGyroSensCoeffZ - (float)sGyroRawZ) * SDL_PI_F / 180.0f;
+ // Gyro scale
+ ctx->m_IMUScaleData.fGyroScaleX = SWITCH_GYRO_SCALE_MULT / ((float)sGyroSensCoeffX - (float)sGyroRawX) * SDL_PI_F / 180.0f;
+ ctx->m_IMUScaleData.fGyroScaleY = SWITCH_GYRO_SCALE_MULT / ((float)sGyroSensCoeffY - (float)sGyroRawY) * SDL_PI_F / 180.0f;
+ ctx->m_IMUScaleData.fGyroScaleZ = SWITCH_GYRO_SCALE_MULT / ((float)sGyroSensCoeffZ - (float)sGyroRawZ) * SDL_PI_F / 180.0f;
- } else {
+ have_imu_cal = true;
+ }
+ }
+
+ if (!have_imu_cal) {
// Use default values
const float accelScale = SDL_STANDARD_GRAVITY / SWITCH_ACCEL_SCALE;
const float gyroScale = SDL_PI_F / 180.0f / SWITCH_GYRO_SCALE;
@@ -1176,6 +1187,8 @@ static bool LoadIMUCalibration(SDL_DriverSwitch_Context *ctx)
ctx->m_IMUScaleData.sGyroOffsetY = 0;
ctx->m_IMUScaleData.sGyroOffsetZ = 0;
}
+
+ // FIXME: Should we read two reports and verify that gyro values are coming through?
return true;
}