From d973835bef74c5517de4b491a2afa8d865841df4 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Wed, 4 Dec 2019 00:24:37 +0300 Subject: [PATCH] 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. --- rpcs3/ds4_pad_handler.cpp | 76 ++++++++++++++++++++++----------------- rpcs3/ds4_pad_handler.h | 1 - 2 files changed, 44 insertions(+), 33 deletions(-) diff --git a/rpcs3/ds4_pad_handler.cpp b/rpcs3/ds4_pad_handler.cpp index 6893b71522..39299b817b 100644 --- a/rpcs3/ds4_pad_handler.cpp +++ b/rpcs3/ds4_pad_handler.cpp @@ -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_FEATURE_REPORT_0x02_SIZE = 37; 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_INPUT_REPORT_0x11_SIZE = 78; const u32 DS4_OUTPUT_REPORT_0x05_SIZE = 32; @@ -64,14 +65,14 @@ namespace return std::tuple(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(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(buf); } } @@ -384,7 +385,7 @@ bool ds4_pad_handler::GetCalibrationData(const std::shared_ptr& ds4De const u8 btHdr = 0xA3; 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 crcReported = GetU32LEData(&buf[DS4_FEATURE_REPORT_0x05_SIZE - 4]); + const u32 crcReported = read_u32(&buf[DS4_FEATURE_REPORT_0x05_SIZE - 4]); 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); else break; @@ -402,31 +403,43 @@ bool ds4_pad_handler::GetCalibrationData(const std::shared_ptr& ds4De } } - ds4Dev->calibData[DS4CalibIndex::PITCH].bias = GetS16LEData(&buf[1]); - ds4Dev->calibData[DS4CalibIndex::YAW].bias = GetS16LEData(&buf[3]); - ds4Dev->calibData[DS4CalibIndex::ROLL].bias = GetS16LEData(&buf[5]); + ds4Dev->calibData[DS4CalibIndex::PITCH].bias = read_s16(&buf[1]); + ds4Dev->calibData[DS4CalibIndex::YAW].bias = read_s16(&buf[3]); + ds4Dev->calibData[DS4CalibIndex::ROLL].bias = read_s16(&buf[5]); 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]); - yawPlus = GetS16LEData(&buf[9]); - rollPlus = GetS16LEData(&buf[11]); - pitchNeg = GetS16LEData(&buf[13]); - yawNeg = GetS16LEData(&buf[15]); - rollNeg = GetS16LEData(&buf[17]); + // Wired mode for OEM controllers + pitchPlus = read_s16(&buf[7]); + pitchNeg = read_s16(&buf[9]); + yawPlus = read_s16(&buf[11]); + yawNeg = read_s16(&buf[13]); + rollPlus = read_s16(&buf[15]); + rollNeg = read_s16(&buf[17]); } else { - pitchPlus = GetS16LEData(&buf[7]); - pitchNeg = GetS16LEData(&buf[9]); - yawPlus = GetS16LEData(&buf[11]); - yawNeg = GetS16LEData(&buf[13]); - rollPlus = GetS16LEData(&buf[15]); - rollNeg = GetS16LEData(&buf[17]); + // Bluetooth mode and wired mode for some 3rd party controllers + pitchPlus = read_s16(&buf[7]); + yawPlus = read_s16(&buf[9]); + rollPlus = read_s16(&buf[11]); + pitchNeg = read_s16(&buf[13]); + 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].sensDenom = pitchPlus - pitchNeg; @@ -437,12 +450,12 @@ bool ds4_pad_handler::GetCalibrationData(const std::shared_ptr& ds4De ds4Dev->calibData[DS4CalibIndex::ROLL].sensNumer = gyroSpeedScale * DS4_GYRO_RES_PER_DEG_S; ds4Dev->calibData[DS4CalibIndex::ROLL].sensDenom = rollPlus - rollNeg; - const s16 accelXPlus = GetS16LEData(&buf[23]); - const s16 accelXNeg = GetS16LEData(&buf[25]); - const s16 accelYPlus = GetS16LEData(&buf[27]); - const s16 accelYNeg = GetS16LEData(&buf[29]); - const s16 accelZPlus = GetS16LEData(&buf[31]); - const s16 accelZNeg = GetS16LEData(&buf[33]); + const s16 accelXPlus = read_s16(&buf[23]); + const s16 accelXNeg = read_s16(&buf[25]); + const s16 accelYPlus = read_s16(&buf[27]); + const s16 accelYNeg = read_s16(&buf[29]); + const s16 accelZPlus = read_s16(&buf[31]); + const s16 accelZNeg = read_s16(&buf[33]); const s32 accelXRange = accelXPlus - accelXNeg; 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) { // 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."); // Read feature report 0x12 instead which is what the console uses. buf[0] = 0x12; 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]); @@ -696,7 +708,7 @@ ds4_pad_handler::DS4DataStatus ds4_pad_handler::GetRawData(const std::shared_ptr const u8 btHdr = 0xA1; 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 crcReported = GetU32LEData(&buf[DS4_INPUT_REPORT_0x11_SIZE - 4]); + const u32 crcReported = read_u32(&buf[DS4_INPUT_REPORT_0x11_SIZE - 4]); if (crcCalc != crcReported) { 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; 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]); buf[calibOffset++] = ((u16)calValue >> 0) & 0xFF; buf[calibOffset++] = ((u16)calValue >> 8) & 0xFF; diff --git a/rpcs3/ds4_pad_handler.h b/rpcs3/ds4_pad_handler.h index 2ee140d8cb..c4b81b8c1a 100644 --- a/rpcs3/ds4_pad_handler.h +++ b/rpcs3/ds4_pad_handler.h @@ -81,7 +81,6 @@ class ds4_pad_handler final : public PadHandlerBase std::string path{ "" }; bool btCon{ false }; bool hasCalibData{ false }; - bool unAuthentic{ false }; std::array calibData{}; bool newVibrateData{ true }; u8 largeVibrate{ 0 };