ds4: Cleanup

- Simplify helpers to read integers HID feature report buffers. They're
simple LE values.
- Improve calibration format detection by just checking the returned
values and not relying on bluetooth check. PS4 does not seem to do it
this way as it accepts 3rd party controllers with inverted format. The
only other request 0xA3 seems unrelated to device capabilities.
This commit is contained in:
kd-11 2019-12-04 00:24:37 +03:00 committed by kd-11
parent 6ae8fd0d34
commit d973835bef
2 changed files with 44 additions and 33 deletions

View File

@ -11,6 +11,7 @@ namespace
const u32 DS4_GYRO_RES_PER_DEG_S = 16; // technically this could be 1024, but keeping it at 16 keeps us within 16 bits of precision const u32 DS4_GYRO_RES_PER_DEG_S = 16; // technically this could be 1024, but keeping it at 16 keeps us within 16 bits of precision
const u32 DS4_FEATURE_REPORT_0x02_SIZE = 37; const u32 DS4_FEATURE_REPORT_0x02_SIZE = 37;
const u32 DS4_FEATURE_REPORT_0x05_SIZE = 41; const u32 DS4_FEATURE_REPORT_0x05_SIZE = 41;
const u32 DS4_FEATURE_REPORT_0x12_SIZE = 16;
const u32 DS4_FEATURE_REPORT_0x81_SIZE = 7; const u32 DS4_FEATURE_REPORT_0x81_SIZE = 7;
const u32 DS4_INPUT_REPORT_0x11_SIZE = 78; const u32 DS4_INPUT_REPORT_0x11_SIZE = 78;
const u32 DS4_OUTPUT_REPORT_0x05_SIZE = 32; const u32 DS4_OUTPUT_REPORT_0x05_SIZE = 32;
@ -64,14 +65,14 @@ namespace
return std::tuple<u16, u16>(Clamp0To255((outX + 1) * 127.f), Clamp0To255(((outY * -1) + 1) * 127.f)); return std::tuple<u16, u16>(Clamp0To255((outX + 1) * 127.f), Clamp0To255(((outY * -1) + 1) * 127.f));
}*/ }*/
inline s16 GetS16LEData(const u8* buf) inline s16 read_s16(const void* buf)
{ {
return (s16)(((u16)buf[0] << 0) + ((u16)buf[1] << 8)); return *reinterpret_cast<const s16*>(buf);
} }
inline u32 GetU32LEData(const u8* buf) inline u32 read_u32(const void* buf)
{ {
return (u32)(((u32)buf[0] << 0) + ((u32)buf[1] << 8) + ((u32)buf[2] << 16) + ((u32)buf[3] << 24)); return *reinterpret_cast<const u32*>(buf);
} }
} }
@ -384,7 +385,7 @@ bool ds4_pad_handler::GetCalibrationData(const std::shared_ptr<DS4Device>& ds4De
const u8 btHdr = 0xA3; const u8 btHdr = 0xA3;
const u32 crcHdr = CRCPP::CRC::Calculate(&btHdr, 1, crcTable); const u32 crcHdr = CRCPP::CRC::Calculate(&btHdr, 1, crcTable);
const u32 crcCalc = CRCPP::CRC::Calculate(buf.data(), (DS4_FEATURE_REPORT_0x05_SIZE - 4), crcTable, crcHdr); const u32 crcCalc = CRCPP::CRC::Calculate(buf.data(), (DS4_FEATURE_REPORT_0x05_SIZE - 4), crcTable, crcHdr);
const u32 crcReported = GetU32LEData(&buf[DS4_FEATURE_REPORT_0x05_SIZE - 4]); const u32 crcReported = read_u32(&buf[DS4_FEATURE_REPORT_0x05_SIZE - 4]);
if (crcCalc != crcReported) if (crcCalc != crcReported)
LOG_WARNING(HLE, "[DS4] Calibration CRC check failed! Will retry up to 3 times. Received 0x%x, Expected 0x%x", crcReported, crcCalc); LOG_WARNING(HLE, "[DS4] Calibration CRC check failed! Will retry up to 3 times. Received 0x%x, Expected 0x%x", crcReported, crcCalc);
else break; else break;
@ -402,31 +403,43 @@ bool ds4_pad_handler::GetCalibrationData(const std::shared_ptr<DS4Device>& ds4De
} }
} }
ds4Dev->calibData[DS4CalibIndex::PITCH].bias = GetS16LEData(&buf[1]); ds4Dev->calibData[DS4CalibIndex::PITCH].bias = read_s16(&buf[1]);
ds4Dev->calibData[DS4CalibIndex::YAW].bias = GetS16LEData(&buf[3]); ds4Dev->calibData[DS4CalibIndex::YAW].bias = read_s16(&buf[3]);
ds4Dev->calibData[DS4CalibIndex::ROLL].bias = GetS16LEData(&buf[5]); ds4Dev->calibData[DS4CalibIndex::ROLL].bias = read_s16(&buf[5]);
s16 pitchPlus, pitchNeg, rollPlus, rollNeg, yawPlus, yawNeg; s16 pitchPlus, pitchNeg, rollPlus, rollNeg, yawPlus, yawNeg;
if (ds4Dev->btCon || ds4Dev->unAuthentic)
// Check for calibration data format
// It's going to be either alternating +/- or +++---
if (read_s16(&buf[9]) < 0 && read_s16(&buf[7]) > 0)
{ {
pitchPlus = GetS16LEData(&buf[7]); // Wired mode for OEM controllers
yawPlus = GetS16LEData(&buf[9]); pitchPlus = read_s16(&buf[7]);
rollPlus = GetS16LEData(&buf[11]); pitchNeg = read_s16(&buf[9]);
pitchNeg = GetS16LEData(&buf[13]); yawPlus = read_s16(&buf[11]);
yawNeg = GetS16LEData(&buf[15]); yawNeg = read_s16(&buf[13]);
rollNeg = GetS16LEData(&buf[17]); rollPlus = read_s16(&buf[15]);
rollNeg = read_s16(&buf[17]);
} }
else else
{ {
pitchPlus = GetS16LEData(&buf[7]); // Bluetooth mode and wired mode for some 3rd party controllers
pitchNeg = GetS16LEData(&buf[9]); pitchPlus = read_s16(&buf[7]);
yawPlus = GetS16LEData(&buf[11]); yawPlus = read_s16(&buf[9]);
yawNeg = GetS16LEData(&buf[13]); rollPlus = read_s16(&buf[11]);
rollPlus = GetS16LEData(&buf[15]); pitchNeg = read_s16(&buf[13]);
rollNeg = GetS16LEData(&buf[17]); yawNeg = read_s16(&buf[15]);
rollNeg = read_s16(&buf[17]);
} }
const s32 gyroSpeedScale = GetS16LEData(&buf[19]) + GetS16LEData(&buf[21]); // Confirm correctness. Need confirmation with dongle with no active controller
if (pitchPlus <= 0 || yawPlus <= 0 || rollPlus <= 0 ||
pitchNeg >= 0 || yawNeg >= 0 || rollNeg >= 0)
{
return false;
}
const s32 gyroSpeedScale = read_s16(&buf[19]) + read_s16(&buf[21]);
ds4Dev->calibData[DS4CalibIndex::PITCH].sensNumer = gyroSpeedScale * DS4_GYRO_RES_PER_DEG_S; ds4Dev->calibData[DS4CalibIndex::PITCH].sensNumer = gyroSpeedScale * DS4_GYRO_RES_PER_DEG_S;
ds4Dev->calibData[DS4CalibIndex::PITCH].sensDenom = pitchPlus - pitchNeg; ds4Dev->calibData[DS4CalibIndex::PITCH].sensDenom = pitchPlus - pitchNeg;
@ -437,12 +450,12 @@ bool ds4_pad_handler::GetCalibrationData(const std::shared_ptr<DS4Device>& ds4De
ds4Dev->calibData[DS4CalibIndex::ROLL].sensNumer = gyroSpeedScale * DS4_GYRO_RES_PER_DEG_S; ds4Dev->calibData[DS4CalibIndex::ROLL].sensNumer = gyroSpeedScale * DS4_GYRO_RES_PER_DEG_S;
ds4Dev->calibData[DS4CalibIndex::ROLL].sensDenom = rollPlus - rollNeg; ds4Dev->calibData[DS4CalibIndex::ROLL].sensDenom = rollPlus - rollNeg;
const s16 accelXPlus = GetS16LEData(&buf[23]); const s16 accelXPlus = read_s16(&buf[23]);
const s16 accelXNeg = GetS16LEData(&buf[25]); const s16 accelXNeg = read_s16(&buf[25]);
const s16 accelYPlus = GetS16LEData(&buf[27]); const s16 accelYPlus = read_s16(&buf[27]);
const s16 accelYNeg = GetS16LEData(&buf[29]); const s16 accelYNeg = read_s16(&buf[29]);
const s16 accelZPlus = GetS16LEData(&buf[31]); const s16 accelZPlus = read_s16(&buf[31]);
const s16 accelZNeg = GetS16LEData(&buf[33]); const s16 accelZNeg = read_s16(&buf[33]);
const s32 accelXRange = accelXPlus - accelXNeg; const s32 accelXRange = accelXPlus - accelXNeg;
ds4Dev->calibData[DS4CalibIndex::X].bias = accelXPlus - accelXRange / 2; ds4Dev->calibData[DS4CalibIndex::X].bias = accelXPlus - accelXRange / 2;
@ -484,13 +497,12 @@ void ds4_pad_handler::CheckAddDevice(hid_device* hidDevice, hid_device_info* hid
if (length != DS4_FEATURE_REPORT_0x81_SIZE) if (length != DS4_FEATURE_REPORT_0x81_SIZE)
{ {
// Controller may not be genuine. These controllers do not have feature 0x81 implemented and calibration data is in bluetooth format even in USB mode! // Controller may not be genuine. These controllers do not have feature 0x81 implemented and calibration data is in bluetooth format even in USB mode!
ds4Dev->unAuthentic = true;
LOG_WARNING(HLE, "DS4 controller may not be genuine. Workaround enabled."); LOG_WARNING(HLE, "DS4 controller may not be genuine. Workaround enabled.");
// Read feature report 0x12 instead which is what the console uses. // Read feature report 0x12 instead which is what the console uses.
buf[0] = 0x12; buf[0] = 0x12;
buf[1] = 0; buf[1] = 0;
hid_get_feature_report(hidDevice, buf.data(), 16); hid_get_feature_report(hidDevice, buf.data(), DS4_FEATURE_REPORT_0x12_SIZE);
} }
serial = fmt::format("%x%x%x%x%x%x", buf[6], buf[5], buf[4], buf[3], buf[2], buf[1]); serial = fmt::format("%x%x%x%x%x%x", buf[6], buf[5], buf[4], buf[3], buf[2], buf[1]);
@ -696,7 +708,7 @@ ds4_pad_handler::DS4DataStatus ds4_pad_handler::GetRawData(const std::shared_ptr
const u8 btHdr = 0xA1; const u8 btHdr = 0xA1;
const u32 crcHdr = CRCPP::CRC::Calculate(&btHdr, 1, crcTable); const u32 crcHdr = CRCPP::CRC::Calculate(&btHdr, 1, crcTable);
const u32 crcCalc = CRCPP::CRC::Calculate(buf.data(), (DS4_INPUT_REPORT_0x11_SIZE - 4), crcTable, crcHdr); const u32 crcCalc = CRCPP::CRC::Calculate(buf.data(), (DS4_INPUT_REPORT_0x11_SIZE - 4), crcTable, crcHdr);
const u32 crcReported = GetU32LEData(&buf[DS4_INPUT_REPORT_0x11_SIZE - 4]); const u32 crcReported = read_u32(&buf[DS4_INPUT_REPORT_0x11_SIZE - 4]);
if (crcCalc != crcReported) if (crcCalc != crcReported)
{ {
LOG_WARNING(HLE, "[DS4] Data packet CRC check failed, ignoring! Received 0x%x, Expected 0x%x", crcReported, crcCalc); LOG_WARNING(HLE, "[DS4] Data packet CRC check failed, ignoring! Received 0x%x, Expected 0x%x", crcReported, crcCalc);
@ -724,7 +736,7 @@ ds4_pad_handler::DS4DataStatus ds4_pad_handler::GetRawData(const std::shared_ptr
int calibOffset = offset + DS4_INPUT_REPORT_GYRO_X_OFFSET; int calibOffset = offset + DS4_INPUT_REPORT_GYRO_X_OFFSET;
for (int i = 0; i < DS4CalibIndex::COUNT; ++i) for (int i = 0; i < DS4CalibIndex::COUNT; ++i)
{ {
const s16 rawValue = GetS16LEData(&buf[calibOffset]); const s16 rawValue = read_s16(&buf[calibOffset]);
const s16 calValue = ApplyCalibration(rawValue, device->calibData[i]); const s16 calValue = ApplyCalibration(rawValue, device->calibData[i]);
buf[calibOffset++] = ((u16)calValue >> 0) & 0xFF; buf[calibOffset++] = ((u16)calValue >> 0) & 0xFF;
buf[calibOffset++] = ((u16)calValue >> 8) & 0xFF; buf[calibOffset++] = ((u16)calValue >> 8) & 0xFF;

View File

@ -81,7 +81,6 @@ class ds4_pad_handler final : public PadHandlerBase
std::string path{ "" }; std::string path{ "" };
bool btCon{ false }; bool btCon{ false };
bool hasCalibData{ false }; bool hasCalibData{ false };
bool unAuthentic{ false };
std::array<DS4CalibData, DS4CalibIndex::COUNT> calibData{}; std::array<DS4CalibData, DS4CalibIndex::COUNT> calibData{};
bool newVibrateData{ true }; bool newVibrateData{ true };
u8 largeVibrate{ 0 }; u8 largeVibrate{ 0 };