From 02b12cbe5259947a550610d1d0dd1d6b01f9a2c2 Mon Sep 17 00:00:00 2001 From: Megamouse Date: Sun, 1 Nov 2020 01:11:16 +0100 Subject: [PATCH 01/11] DS4: enumerate devices periodically --- rpcs3/Input/ds4_pad_handler.cpp | 164 +++++++++++++++++++------- rpcs3/Input/ds4_pad_handler.h | 8 +- rpcs3/Input/pad_thread.cpp | 2 +- rpcs3/rpcs3qt/pad_settings_dialog.cpp | 27 +++-- 4 files changed, 141 insertions(+), 60 deletions(-) diff --git a/rpcs3/Input/ds4_pad_handler.cpp b/rpcs3/Input/ds4_pad_handler.cpp index e81008fba3a3..bc17964f37a5 100644 --- a/rpcs3/Input/ds4_pad_handler.cpp +++ b/rpcs3/Input/ds4_pad_handler.cpp @@ -246,17 +246,12 @@ std::shared_ptr ds4_pad_handler::GetDS4Device(const if (!Init()) return nullptr; - usz pos = padId.find(m_name_string); - if (pos == umax) - return nullptr; - - std::string pad_serial = padId.substr(pos + 9); std::shared_ptr device = nullptr; - int i = 0; // Controllers 1-n in GUI + // Controllers 1-n in GUI for (auto& cur_control : controllers) { - if (pad_serial == std::to_string(++i) || pad_serial == cur_control.first) + if (padId == cur_control.first) { device = cur_control.second; break; @@ -524,11 +519,26 @@ bool ds4_pad_handler::GetCalibrationData(const std::shared_ptr& ds4De return true; } -void ds4_pad_handler::CheckAddDevice(hid_device* hidDevice, hid_device_info* hidDevInfo) +void ds4_pad_handler::CheckAddDevice(hid_device* hidDevice, std::string_view path, std::wstring_view wide_serial) { + std::shared_ptr ds4_dev; + + for (auto& controller : controllers) + { + if (!controller.second || !controller.second->hidDevice) + { + ds4_dev = controller.second; + break; + } + } + + if (!ds4_dev) + { + return; + } + std::string serial; - std::shared_ptr ds4Dev = std::make_shared(); - ds4Dev->hidDevice = hidDevice; + ds4_dev->hidDevice = hidDevice; // There isnt a nice 'portable' way with hidapi to detect bt vs wired as the pid/vid's are the same // Let's try getting 0x81 feature report, which should will return mac address on wired, and should error on bluetooth std::array buf{}; @@ -545,7 +555,7 @@ void ds4_pad_handler::CheckAddDevice(hid_device* hidDevice, hid_device_info* hid buf[1] = 0; if (hid_get_feature_report(hidDevice, buf.data(), DS4_FEATURE_REPORT_0x12_SIZE) == -1) { - ds4_log.error("CheckAddDevice: hid_get_feature_report 0x12 failed! Reason: %s", hid_error(ds4Dev->hidDevice)); + ds4_log.error("CheckAddDevice: hid_get_feature_report 0x12 failed! Reason: %s", hid_error(hidDevice)); } } @@ -553,13 +563,12 @@ void ds4_pad_handler::CheckAddDevice(hid_device* hidDevice, hid_device_info* hid } else { - ds4Dev->btCon = true; - std::wstring_view wideSerial(hidDevInfo->serial_number); - for (wchar_t ch : wideSerial) + ds4_dev->btCon = true; + for (wchar_t ch : wide_serial) serial += static_cast(ch); } - if (!GetCalibrationData(ds4Dev)) + if (!GetCalibrationData(ds4_dev)) { ds4_log.error("CheckAddDevice: GetCalibrationData failed!"); hid_close(hidDevice); @@ -573,17 +582,17 @@ void ds4_pad_handler::CheckAddDevice(hid_device* hidDevice, hid_device_info* hid return; } - ds4Dev->hasCalibData = true; - ds4Dev->path = hidDevInfo->path; + ds4_dev->hasCalibData = true; + ds4_dev->path = path; - controllers.emplace(serial, ds4Dev); + send_output_report(ds4_dev); } ds4_pad_handler::~ds4_pad_handler() { for (auto& controller : controllers) { - if (controller.second->hidDevice) + if (controller.second && controller.second->hidDevice) { // Disable blinking and vibration controller.second->smallVibrate = 0; @@ -603,7 +612,7 @@ ds4_pad_handler::~ds4_pad_handler() int ds4_pad_handler::send_output_report(const std::shared_ptr& device) { - if (!device) + if (!device || !device->hidDevice) return -2; auto config = device->config; @@ -656,39 +665,72 @@ int ds4_pad_handler::send_output_report(const std::shared_ptr& device } } -bool ds4_pad_handler::Init() +void ds4_pad_handler::enumerate_devices() { - if (is_init) - return true; + std::set device_paths; + std::map serials; - const int res = hid_init(); - if (res != 0) - fmt::throw_exception("hidapi-init error.threadproc"); + for (auto pid : ds4Pids) + { + hid_device_info* dev_info = hid_enumerate(DS4_VID, pid); + hid_device_info* head = dev_info; + while (dev_info) + { + ensure(dev_info->path != nullptr); + device_paths.insert(dev_info->path); + serials[dev_info->path] = dev_info->serial_number ? std::wstring_view(dev_info->serial_number) : std::wstring_view{}; + dev_info = dev_info->next; + } + hid_free_enumeration(head); + } + + if (m_last_enumerated_devices == device_paths) + { + return; + } + + m_last_enumerated_devices = device_paths; + + // Scrap devices that are not in the new list + for (auto it = controllers.begin(); it != controllers.end(); ++it) + { + if (it->second && !it->second->path.empty() && !device_paths.contains(it->second->path)) + { + hid_close(it->second->hidDevice); + pad_config* config = it->second->config; + it->second.reset(new DS4Device()); + it->second->config = config; + } + } - // get all the possible controllers at start bool warn_about_drivers = false; - for (auto pid : ds4Pids) + + // Find and add new devices + for (const auto& path : device_paths) { - hid_device_info* devInfo = hid_enumerate(DS4_VID, pid); - hid_device_info* head = devInfo; - while (devInfo) + // Check if we already have this controller + const auto it_found = std::find_if(controllers.cbegin(), controllers.cend(), [path](const auto& c) { return c.second && c.second->path == path; }); + + if (it_found == controllers.cend()) { - if (controllers.size() >= MAX_GAMEPADS) + // Check if we have at least one virtual controller left + const auto it_free = std::find_if(controllers.cbegin(), controllers.cend(), [](const auto& c) { return !c.second || !c.second->hidDevice; }); + if (it_free == controllers.cend()) + { break; + } - hid_device* dev = hid_open_path(devInfo->path); + hid_device* dev = hid_open_path(path.c_str()); if (dev) { - CheckAddDevice(dev, devInfo); + CheckAddDevice(dev, path, serials[path]); } else { ds4_log.error("hid_open_path failed! Reason: %s", hid_error(dev)); warn_about_drivers = true; } - devInfo = devInfo->next; } - hid_free_enumeration(head); } if (warn_about_drivers) @@ -698,19 +740,53 @@ bool ds4_pad_handler::Init() ds4_log.error("Check https://wiki.rpcs3.net/index.php?title=Help:Controller_Configuration for intructions on how to solve this issue"); #endif } - else if (controllers.empty()) + else { - ds4_log.warning("No controllers found!"); + const size_t count = std::count_if(controllers.cbegin(), controllers.cend(), [](const auto& c) { return c.second && c.second->hidDevice; }); + if (count > 0) + { + ds4_log.success("Controllers found: %d", count); + } + else + { + ds4_log.warning("No controllers found!"); + } } - else +} + +bool ds4_pad_handler::Init() +{ + if (is_init) + return true; + + const int res = hid_init(); + if (res != 0) + fmt::throw_exception("hidapi-init error.threadproc"); + + for (size_t i = 1; i <= MAX_GAMEPADS; i++) // Controllers 1-n in GUI { - ds4_log.success("Controllers found: %d", controllers.size()); + controllers.emplace(m_name_string + std::to_string(i), std::make_shared()); } + enumerate_devices(); + is_init = true; return true; } +void ds4_pad_handler::ThreadProc() +{ + const auto now = std::chrono::system_clock::now(); + const auto elapsed = std::chrono::duration_cast(now - m_last_enumeration).count(); + if (elapsed > 2000) + { + m_last_enumeration = now; + enumerate_devices(); + } + + PadHandlerBase::ThreadProc(); +} + std::vector ds4_pad_handler::ListDevices() { std::vector ds4_pads_list; @@ -718,9 +794,9 @@ std::vector ds4_pad_handler::ListDevices() if (!Init()) return ds4_pads_list; - for (usz i = 1; i <= controllers.size(); ++i) // Controllers 1-n in GUI + for (const auto& controller : controllers) // Controllers 1-n in GUI { - ds4_pads_list.emplace_back(m_name_string + std::to_string(i)); + ds4_pads_list.emplace_back(controller.first); } return ds4_pads_list; @@ -809,7 +885,7 @@ ds4_pad_handler::DS4DataStatus ds4_pad_handler::GetRawData(const std::shared_ptr std::shared_ptr ds4_pad_handler::get_device(const std::string& device) { std::shared_ptr ds4device = GetDS4Device(device); - if (ds4device == nullptr || ds4device->hidDevice == nullptr) + if (ds4device == nullptr) return nullptr; return ds4device; @@ -870,7 +946,7 @@ u32 ds4_pad_handler::get_battery_color(u8 battery_level, int brightness) PadHandlerBase::connection ds4_pad_handler::update_connection(const std::shared_ptr& device) { auto ds4_dev = std::static_pointer_cast(device); - if (!ds4_dev) + if (!ds4_dev || ds4_dev->path.empty()) return connection::disconnected; if (ds4_dev->hidDevice == nullptr) diff --git a/rpcs3/Input/ds4_pad_handler.h b/rpcs3/Input/ds4_pad_handler.h index ce479c974b03..6b28b060ccad 100644 --- a/rpcs3/Input/ds4_pad_handler.h +++ b/rpcs3/Input/ds4_pad_handler.h @@ -99,7 +99,7 @@ class ds4_pad_handler final : public PadHandlerBase const std::array ds4Pids = { { 0xBA0, 0x5C4, 0x09CC } }; // pseudo 'controller id' to keep track of unique controllers - std::unordered_map> controllers; + std::map> controllers; CRCPP::CRC::Table crcTable{ CRCPP::CRC::CRC_32() }; public: @@ -107,6 +107,7 @@ class ds4_pad_handler final : public PadHandlerBase ~ds4_pad_handler(); bool Init() override; + void ThreadProc() override; std::vector ListDevices() override; void SetPadData(const std::string& padId, u32 largeMotor, u32 smallMotor, s32 r, s32 g, s32 b, bool battery_led, u32 battery_led_brightness) override; @@ -116,6 +117,9 @@ class ds4_pad_handler final : public PadHandlerBase private: bool is_init = false; DS4DataStatus status; + std::chrono::system_clock::time_point m_last_enumeration; + std::set m_last_enumerated_devices; + void enumerate_devices(); u32 get_battery_color(u8 battery_level, int brightness); private: @@ -124,7 +128,7 @@ class ds4_pad_handler final : public PadHandlerBase DS4DataStatus GetRawData(const std::shared_ptr& ds4Device); // This function gets us usuable buffer from the rawbuffer of padData bool GetCalibrationData(const std::shared_ptr& ds4Device); - void CheckAddDevice(hid_device* hidDevice, hid_device_info* hidDevInfo); + void CheckAddDevice(hid_device* hidDevice, std::string_view path, std::wstring_view serial); int send_output_report(const std::shared_ptr& device); inline s16 ApplyCalibration(s32 rawValue, const DS4CalibData& calibData) { diff --git a/rpcs3/Input/pad_thread.cpp b/rpcs3/Input/pad_thread.cpp index f39b2259bc5e..a8f7e1afe782 100644 --- a/rpcs3/Input/pad_thread.cpp +++ b/rpcs3/Input/pad_thread.cpp @@ -104,7 +104,7 @@ void pad_thread::Init() const bool is_ldd_pad = pad_settings[i].ldd_handle == static_cast(i); const auto handler_type = is_ldd_pad ? pad_handler::null : g_cfg_input.player[i]->handler.get(); - if (handlers.count(handler_type) != 0) + if (handlers.contains(handler_type)) { cur_pad_handler = handlers[handler_type]; } diff --git a/rpcs3/rpcs3qt/pad_settings_dialog.cpp b/rpcs3/rpcs3qt/pad_settings_dialog.cpp index 591e5b506686..262f795f1fec 100644 --- a/rpcs3/rpcs3qt/pad_settings_dialog.cpp +++ b/rpcs3/rpcs3qt/pad_settings_dialog.cpp @@ -102,7 +102,7 @@ pad_settings_dialog::pad_settings_dialog(std::shared_ptr gui_setti connect(ui->chooseHandler, &QComboBox::currentTextChanged, this, &pad_settings_dialog::ChangeInputType); // Combobox: Devices - connect(ui->chooseDevice, QOverload::of(&QComboBox::currentIndexChanged), [this](int index) + connect(ui->chooseDevice, QOverload::of(&QComboBox::currentIndexChanged), this, [this](int index) { if (index < 0) { @@ -119,7 +119,7 @@ pad_settings_dialog::pad_settings_dialog(std::shared_ptr gui_setti }); // Combobox: Profiles - connect(ui->chooseProfile, &QComboBox::currentTextChanged, [this](const QString& prof) + connect(ui->chooseProfile, &QComboBox::currentTextChanged, this, [this](const QString& prof) { if (prof.isEmpty()) { @@ -136,7 +136,7 @@ pad_settings_dialog::pad_settings_dialog(std::shared_ptr gui_setti }); // Pushbutton: Add Profile - connect(ui->b_addProfile, &QAbstractButton::clicked, [this]() + connect(ui->b_addProfile, &QAbstractButton::clicked, this, [this]() { const int i = ui->tabWidget->currentIndex(); @@ -175,7 +175,7 @@ pad_settings_dialog::pad_settings_dialog(std::shared_ptr gui_setti ui->buttonBox->button(QDialogButtonBox::Reset)->setText(tr("Filter Noise")); - connect(ui->buttonBox, &QDialogButtonBox::clicked, [this](QAbstractButton* button) + connect(ui->buttonBox, &QDialogButtonBox::clicked, this, [this](QAbstractButton* button) { if (button == ui->buttonBox->button(QDialogButtonBox::Save)) { @@ -304,7 +304,7 @@ void pad_settings_dialog::InitButtons() connect(m_pad_buttons, &QButtonGroup::idClicked, this, &pad_settings_dialog::OnPadButtonClicked); - connect(&m_timer, &QTimer::timeout, [this]() + connect(&m_timer, &QTimer::timeout, this, [this]() { if (--m_seconds <= 0) { @@ -314,7 +314,7 @@ void pad_settings_dialog::InitButtons() m_pad_buttons->button(m_button_id)->setText(tr("[ Waiting %1 ]").arg(m_seconds)); }); - connect(ui->chb_vibration_large, &QCheckBox::clicked, [this](bool checked) + connect(ui->chb_vibration_large, &QCheckBox::clicked, this, [this](bool checked) { if (!checked) { @@ -330,7 +330,7 @@ void pad_settings_dialog::InitButtons() }); }); - connect(ui->chb_vibration_small, &QCheckBox::clicked, [this](bool checked) + connect(ui->chb_vibration_small, &QCheckBox::clicked, this, [this](bool checked) { if (!checked) { @@ -346,7 +346,7 @@ void pad_settings_dialog::InitButtons() }); }); - connect(ui->chb_vibration_switch, &QCheckBox::clicked, [this](bool checked) + connect(ui->chb_vibration_switch, &QCheckBox::clicked, this, [this](bool checked) { checked ? SetPadData(m_min_force, m_max_force) : SetPadData(m_max_force, m_min_force); @@ -363,18 +363,18 @@ void pad_settings_dialog::InitButtons() }); }); - connect(ui->slider_stick_left, &QSlider::valueChanged, [&](int value) + connect(ui->slider_stick_left, &QSlider::valueChanged, this, [&](int value) { RepaintPreviewLabel(ui->preview_stick_left, value, ui->slider_stick_left->size().width(), m_lx, m_ly, ui->squircle_left->value(), ui->stick_multi_left->value()); }); - connect(ui->slider_stick_right, &QSlider::valueChanged, [&](int value) + connect(ui->slider_stick_right, &QSlider::valueChanged, this, [&](int value) { RepaintPreviewLabel(ui->preview_stick_right, value, ui->slider_stick_right->size().width(), m_rx, m_ry, ui->squircle_right->value(), ui->stick_multi_right->value()); }); // Open LED settings - connect(ui->b_led_settings, &QPushButton::clicked, [this]() + connect(ui->b_led_settings, &QPushButton::clicked, this, [this]() { // Allow LED battery indication while the dialog is open m_handler->SetPadData(m_device_name, 0, 0, m_handler_cfg.colorR, m_handler_cfg.colorG, m_handler_cfg.colorB, m_handler_cfg.led_battery_indicator.get(), m_handler_cfg.led_battery_indicator_brightness); @@ -462,7 +462,7 @@ void pad_settings_dialog::InitButtons() }; // Use timer to get button input - connect(&m_timer_input, &QTimer::timeout, [this, callback, fail_callback]() + connect(&m_timer_input, &QTimer::timeout, this, [this, callback, fail_callback]() { const std::vector buttons = { @@ -475,7 +475,7 @@ void pad_settings_dialog::InitButtons() }); // Use timer to refresh pad connection status - connect(&m_timer_pad_refresh, &QTimer::timeout, [this]() + connect(&m_timer_pad_refresh, &QTimer::timeout, this, [this]() { for (int i = 0; i < ui->chooseDevice->count(); i++) { @@ -1193,6 +1193,7 @@ void pad_settings_dialog::ChangeInputType() // Get this player's current handler and it's currently available devices m_handler = GetHandler(g_cfg_input.player[player]->handler); + ensure(m_handler); const auto device_list = m_handler->ListDevices(); // Localized tooltips From 782a61dbbe7f8b22546442129e4c2ab7d7d3f54f Mon Sep 17 00:00:00 2001 From: Megamouse Date: Thu, 11 Feb 2021 22:13:21 +0100 Subject: [PATCH 02/11] DS4: inherit from hid_pad_handler --- rpcs3/CMakeLists.txt | 1 + rpcs3/Emu/Io/PadHandler.h | 3 +- rpcs3/Input/ds4_pad_handler.cpp | 295 +++++++------------------------- rpcs3/Input/ds4_pad_handler.h | 107 +++--------- rpcs3/Input/hid_pad_handler.cpp | 200 ++++++++++++++++++++++ rpcs3/Input/hid_pad_handler.h | 103 +++++++++++ rpcs3/rpcs3.vcxproj | 2 + rpcs3/rpcs3.vcxproj.filters | 6 + 8 files changed, 393 insertions(+), 324 deletions(-) create mode 100644 rpcs3/Input/hid_pad_handler.cpp create mode 100644 rpcs3/Input/hid_pad_handler.h diff --git a/rpcs3/CMakeLists.txt b/rpcs3/CMakeLists.txt index d165e935ace5..f8742d4f1315 100644 --- a/rpcs3/CMakeLists.txt +++ b/rpcs3/CMakeLists.txt @@ -60,6 +60,7 @@ set(RPCS3_SRC Input/ds4_pad_handler.cpp Input/dualsense_pad_handler.cpp Input/evdev_joystick_handler.cpp + Input/hid_pad_handler.cpp Input/keyboard_pad_handler.cpp Input/mm_joystick_handler.cpp Input/pad_thread.cpp diff --git a/rpcs3/Emu/Io/PadHandler.h b/rpcs3/Emu/Io/PadHandler.h index 081960287a61..4cf95af00ccd 100644 --- a/rpcs3/Emu/Io/PadHandler.h +++ b/rpcs3/Emu/Io/PadHandler.h @@ -12,8 +12,9 @@ #include #include -struct PadDevice +class PadDevice { +public: pad_config* config{ nullptr }; }; diff --git a/rpcs3/Input/ds4_pad_handler.cpp b/rpcs3/Input/ds4_pad_handler.cpp index bc17964f37a5..fad938739dfa 100644 --- a/rpcs3/Input/ds4_pad_handler.cpp +++ b/rpcs3/Input/ds4_pad_handler.cpp @@ -63,19 +63,10 @@ namespace return std::tuple(Clamp0To255((outX + 1) * 127.f), Clamp0To255(((outY * -1) + 1) * 127.f)); }*/ - - inline s16 read_s16(const void* buf) - { - return *reinterpret_cast(buf); - } - - inline u32 read_u32(const void* buf) - { - return *reinterpret_cast(buf); - } } -ds4_pad_handler::ds4_pad_handler() : PadHandlerBase(pad_handler::ds4) +ds4_pad_handler::ds4_pad_handler() + : hid_pad_handler(pad_handler::ds4, 0x054C, {0xBA0, 0x5C4, 0x09CC}) { // Unique names for the config files and our pad settings dialog button_list = @@ -189,7 +180,7 @@ void ds4_pad_handler::init_config(pad_config* cfg, const std::string& name) u32 ds4_pad_handler::get_battery_level(const std::string& padId) { - std::shared_ptr device = GetDS4Device(padId); + std::shared_ptr device = get_hid_device(padId); if (device == nullptr || device->hidDevice == nullptr) { return 0; @@ -199,7 +190,7 @@ u32 ds4_pad_handler::get_battery_level(const std::string& padId) void ds4_pad_handler::SetPadData(const std::string& padId, u32 largeMotor, u32 smallMotor, s32 r, s32 g, s32 b, bool battery_led, u32 battery_led_brightness) { - std::shared_ptr device = GetDS4Device(padId); + std::shared_ptr device = get_hid_device(padId); if (device == nullptr || device->hidDevice == nullptr) return; @@ -238,33 +229,13 @@ void ds4_pad_handler::SetPadData(const std::string& padId, u32 largeMotor, u32 s } // Start/Stop the engines :) - send_output_report(device); -} - -std::shared_ptr ds4_pad_handler::GetDS4Device(const std::string& padId) -{ - if (!Init()) - return nullptr; - - std::shared_ptr device = nullptr; - - // Controllers 1-n in GUI - for (auto& cur_control : controllers) - { - if (padId == cur_control.first) - { - device = cur_control.second; - break; - } - } - - return device; + send_output_report(device.get()); } std::unordered_map ds4_pad_handler::get_button_values(const std::shared_ptr& device) { std::unordered_map keyBuffer; - auto ds4_dev = std::static_pointer_cast(device); + DS4Device* ds4_dev = static_cast(device.get()); if (!ds4_dev) return keyBuffer; @@ -387,7 +358,7 @@ pad_preview_values ds4_pad_handler::get_preview_values(const std::unordered_map< }; } -bool ds4_pad_handler::GetCalibrationData(const std::shared_ptr& ds4Dev) +bool ds4_pad_handler::GetCalibrationData(DS4Device* ds4Dev) { if (!ds4Dev || !ds4Dev->hidDevice) { @@ -435,9 +406,9 @@ bool ds4_pad_handler::GetCalibrationData(const std::shared_ptr& ds4De } } - 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]); + ds4Dev->calibData[CalibIndex::PITCH].bias = read_s16(&buf[1]); + ds4Dev->calibData[CalibIndex::YAW].bias = read_s16(&buf[3]); + ds4Dev->calibData[CalibIndex::ROLL].bias = read_s16(&buf[5]); s16 pitchPlus, pitchNeg, rollPlus, rollNeg, yawPlus, yawNeg; @@ -474,14 +445,14 @@ bool ds4_pad_handler::GetCalibrationData(const std::shared_ptr& ds4De 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; + ds4Dev->calibData[CalibIndex::PITCH].sens_numer = gyroSpeedScale * DS4_GYRO_RES_PER_DEG_S; + ds4Dev->calibData[CalibIndex::PITCH].sens_denom = pitchPlus - pitchNeg; - ds4Dev->calibData[DS4CalibIndex::YAW].sensNumer = gyroSpeedScale * DS4_GYRO_RES_PER_DEG_S; - ds4Dev->calibData[DS4CalibIndex::YAW].sensDenom = yawPlus - yawNeg; + ds4Dev->calibData[CalibIndex::YAW].sens_numer = gyroSpeedScale * DS4_GYRO_RES_PER_DEG_S; + ds4Dev->calibData[CalibIndex::YAW].sens_denom = yawPlus - yawNeg; - ds4Dev->calibData[DS4CalibIndex::ROLL].sensNumer = gyroSpeedScale * DS4_GYRO_RES_PER_DEG_S; - ds4Dev->calibData[DS4CalibIndex::ROLL].sensDenom = rollPlus - rollNeg; + ds4Dev->calibData[CalibIndex::ROLL].sens_numer = gyroSpeedScale * DS4_GYRO_RES_PER_DEG_S; + ds4Dev->calibData[CalibIndex::ROLL].sens_denom = rollPlus - rollNeg; const s16 accelXPlus = read_s16(&buf[23]); const s16 accelXNeg = read_s16(&buf[25]); @@ -491,25 +462,25 @@ bool ds4_pad_handler::GetCalibrationData(const std::shared_ptr& ds4De const s16 accelZNeg = read_s16(&buf[33]); const s32 accelXRange = accelXPlus - accelXNeg; - ds4Dev->calibData[DS4CalibIndex::X].bias = accelXPlus - accelXRange / 2; - ds4Dev->calibData[DS4CalibIndex::X].sensNumer = 2 * DS4_ACC_RES_PER_G; - ds4Dev->calibData[DS4CalibIndex::X].sensDenom = accelXRange; + ds4Dev->calibData[CalibIndex::X].bias = accelXPlus - accelXRange / 2; + ds4Dev->calibData[CalibIndex::X].sens_numer = 2 * DS4_ACC_RES_PER_G; + ds4Dev->calibData[CalibIndex::X].sens_denom = accelXRange; const s32 accelYRange = accelYPlus - accelYNeg; - ds4Dev->calibData[DS4CalibIndex::Y].bias = accelYPlus - accelYRange / 2; - ds4Dev->calibData[DS4CalibIndex::Y].sensNumer = 2 * DS4_ACC_RES_PER_G; - ds4Dev->calibData[DS4CalibIndex::Y].sensDenom = accelYRange; + ds4Dev->calibData[CalibIndex::Y].bias = accelYPlus - accelYRange / 2; + ds4Dev->calibData[CalibIndex::Y].sens_numer = 2 * DS4_ACC_RES_PER_G; + ds4Dev->calibData[CalibIndex::Y].sens_denom = accelYRange; const s32 accelZRange = accelZPlus - accelZNeg; - ds4Dev->calibData[DS4CalibIndex::Z].bias = accelZPlus - accelZRange / 2; - ds4Dev->calibData[DS4CalibIndex::Z].sensNumer = 2 * DS4_ACC_RES_PER_G; - ds4Dev->calibData[DS4CalibIndex::Z].sensDenom = accelZRange; + ds4Dev->calibData[CalibIndex::Z].bias = accelZPlus - accelZRange / 2; + ds4Dev->calibData[CalibIndex::Z].sens_numer = 2 * DS4_ACC_RES_PER_G; + ds4Dev->calibData[CalibIndex::Z].sens_denom = accelZRange; // Make sure data 'looks' valid, dongle will report invalid calibration data with no controller connected for (const auto& data : ds4Dev->calibData) { - if (data.sensDenom == 0) + if (data.sens_denom == 0) { ds4_log.error("GetCalibrationData: Failure: sensDenom == 0"); return false; @@ -519,15 +490,20 @@ bool ds4_pad_handler::GetCalibrationData(const std::shared_ptr& ds4De return true; } -void ds4_pad_handler::CheckAddDevice(hid_device* hidDevice, std::string_view path, std::wstring_view wide_serial) +void ds4_pad_handler::check_add_device(hid_device* hidDevice, std::string_view path, std::wstring_view wide_serial) { - std::shared_ptr ds4_dev; + if (!hidDevice) + { + return; + } + + DS4Device* ds4_dev = nullptr; - for (auto& controller : controllers) + for (auto& controller : m_controllers) { if (!controller.second || !controller.second->hidDevice) { - ds4_dev = controller.second; + ds4_dev = controller.second.get(); break; } } @@ -539,6 +515,7 @@ void ds4_pad_handler::CheckAddDevice(hid_device* hidDevice, std::string_view pat std::string serial; ds4_dev->hidDevice = hidDevice; + // There isnt a nice 'portable' way with hidapi to detect bt vs wired as the pid/vid's are the same // Let's try getting 0x81 feature report, which should will return mac address on wired, and should error on bluetooth std::array buf{}; @@ -548,14 +525,14 @@ void ds4_pad_handler::CheckAddDevice(hid_device* hidDevice, std::string_view pat if (bytes_read != 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! - ds4_log.warning("CheckAddDevice: DS4 controller may not be genuine. Workaround enabled."); + ds4_log.warning("check_add_device: 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; if (hid_get_feature_report(hidDevice, buf.data(), DS4_FEATURE_REPORT_0x12_SIZE) == -1) { - ds4_log.error("CheckAddDevice: hid_get_feature_report 0x12 failed! Reason: %s", hid_error(hidDevice)); + ds4_log.error("check_add_device: hid_get_feature_report 0x12 failed! Reason: %s", hid_error(hidDevice)); } } @@ -570,14 +547,14 @@ void ds4_pad_handler::CheckAddDevice(hid_device* hidDevice, std::string_view pat if (!GetCalibrationData(ds4_dev)) { - ds4_log.error("CheckAddDevice: GetCalibrationData failed!"); + ds4_log.error("check_add_device: GetCalibrationData failed!"); hid_close(hidDevice); return; } if (hid_set_nonblocking(hidDevice, 1) == -1) { - ds4_log.error("CheckAddDevice: hid_set_nonblocking failed! Reason: %s", hid_error(hidDevice)); + ds4_log.error("check_add_device: hid_set_nonblocking failed! Reason: %s", hid_error(hidDevice)); hid_close(hidDevice); return; } @@ -590,7 +567,7 @@ void ds4_pad_handler::CheckAddDevice(hid_device* hidDevice, std::string_view pat ds4_pad_handler::~ds4_pad_handler() { - for (auto& controller : controllers) + for (auto& controller : m_controllers) { if (controller.second && controller.second->hidDevice) { @@ -599,18 +576,12 @@ ds4_pad_handler::~ds4_pad_handler() controller.second->largeVibrate = 0; controller.second->led_delay_on = 0; controller.second->led_delay_off = 0; - send_output_report(controller.second); - - hid_close(controller.second->hidDevice); + send_output_report(controller.second.get()); } } - if (hid_exit() != 0) - { - ds4_log.error("hid_exit failed!"); - } } -int ds4_pad_handler::send_output_report(const std::shared_ptr& device) +int ds4_pad_handler::send_output_report(DS4Device* device) { if (!device || !device->hidDevice) return -2; @@ -665,147 +636,10 @@ int ds4_pad_handler::send_output_report(const std::shared_ptr& device } } -void ds4_pad_handler::enumerate_devices() -{ - std::set device_paths; - std::map serials; - - for (auto pid : ds4Pids) - { - hid_device_info* dev_info = hid_enumerate(DS4_VID, pid); - hid_device_info* head = dev_info; - while (dev_info) - { - ensure(dev_info->path != nullptr); - device_paths.insert(dev_info->path); - serials[dev_info->path] = dev_info->serial_number ? std::wstring_view(dev_info->serial_number) : std::wstring_view{}; - dev_info = dev_info->next; - } - hid_free_enumeration(head); - } - - if (m_last_enumerated_devices == device_paths) - { - return; - } - - m_last_enumerated_devices = device_paths; - - // Scrap devices that are not in the new list - for (auto it = controllers.begin(); it != controllers.end(); ++it) - { - if (it->second && !it->second->path.empty() && !device_paths.contains(it->second->path)) - { - hid_close(it->second->hidDevice); - pad_config* config = it->second->config; - it->second.reset(new DS4Device()); - it->second->config = config; - } - } - - bool warn_about_drivers = false; - - // Find and add new devices - for (const auto& path : device_paths) - { - // Check if we already have this controller - const auto it_found = std::find_if(controllers.cbegin(), controllers.cend(), [path](const auto& c) { return c.second && c.second->path == path; }); - - if (it_found == controllers.cend()) - { - // Check if we have at least one virtual controller left - const auto it_free = std::find_if(controllers.cbegin(), controllers.cend(), [](const auto& c) { return !c.second || !c.second->hidDevice; }); - if (it_free == controllers.cend()) - { - break; - } - - hid_device* dev = hid_open_path(path.c_str()); - if (dev) - { - CheckAddDevice(dev, path, serials[path]); - } - else - { - ds4_log.error("hid_open_path failed! Reason: %s", hid_error(dev)); - warn_about_drivers = true; - } - } - } - - if (warn_about_drivers) - { - ds4_log.error("One or more DS4 pads were detected but couldn't be interacted with directly"); -#if defined(_WIN32) || defined(__linux__) - ds4_log.error("Check https://wiki.rpcs3.net/index.php?title=Help:Controller_Configuration for intructions on how to solve this issue"); -#endif - } - else - { - const size_t count = std::count_if(controllers.cbegin(), controllers.cend(), [](const auto& c) { return c.second && c.second->hidDevice; }); - if (count > 0) - { - ds4_log.success("Controllers found: %d", count); - } - else - { - ds4_log.warning("No controllers found!"); - } - } -} - -bool ds4_pad_handler::Init() -{ - if (is_init) - return true; - - const int res = hid_init(); - if (res != 0) - fmt::throw_exception("hidapi-init error.threadproc"); - - for (size_t i = 1; i <= MAX_GAMEPADS; i++) // Controllers 1-n in GUI - { - controllers.emplace(m_name_string + std::to_string(i), std::make_shared()); - } - - enumerate_devices(); - - is_init = true; - return true; -} - -void ds4_pad_handler::ThreadProc() +ds4_pad_handler::DataStatus ds4_pad_handler::GetRawData(DS4Device* device) { - const auto now = std::chrono::system_clock::now(); - const auto elapsed = std::chrono::duration_cast(now - m_last_enumeration).count(); - if (elapsed > 2000) - { - m_last_enumeration = now; - enumerate_devices(); - } - - PadHandlerBase::ThreadProc(); -} - -std::vector ds4_pad_handler::ListDevices() -{ - std::vector ds4_pads_list; - - if (!Init()) - return ds4_pads_list; - - for (const auto& controller : controllers) // Controllers 1-n in GUI - { - ds4_pads_list.emplace_back(controller.first); - } - - return ds4_pads_list; -} - -ds4_pad_handler::DS4DataStatus ds4_pad_handler::GetRawData(const std::shared_ptr& device) -{ - if (!device) - return DS4DataStatus::ReadError; + if (!device || !device->hidDevice) + return DataStatus::ReadError; std::array buf{}; @@ -813,12 +647,12 @@ ds4_pad_handler::DS4DataStatus ds4_pad_handler::GetRawData(const std::shared_ptr if (res == -1) { // looks like controller disconnected or read error - return DS4DataStatus::ReadError; + return DataStatus::ReadError; } // no data? keep going if (res == 0) - return DS4DataStatus::NoNewData; + return DataStatus::NoNewData; // bt controller sends this until 0x02 feature report is sent back (happens on controller init/restart) if (device->btCon && buf[0] == 0x1) @@ -830,7 +664,7 @@ ds4_pad_handler::DS4DataStatus ds4_pad_handler::GetRawData(const std::shared_ptr { ds4_log.error("GetRawData: hid_get_feature_report 0x2 failed! Reason: %s", hid_error(device->hidDevice)); } - return DS4DataStatus::NoNewData; + return DataStatus::NoNewData; } int offset = 0; @@ -846,7 +680,7 @@ ds4_pad_handler::DS4DataStatus ds4_pad_handler::GetRawData(const std::shared_ptr if (crcCalc != crcReported) { ds4_log.warning("Data packet CRC check failed, ignoring! Received 0x%x, Expected 0x%x", crcReported, crcCalc); - return DS4DataStatus::NoNewData; + return DataStatus::NoNewData; } } else if (!device->btCon && buf[0] == 0x01 && res == 64) @@ -859,7 +693,7 @@ ds4_pad_handler::DS4DataStatus ds4_pad_handler::GetRawData(const std::shared_ptr offset = 0; } else - return DS4DataStatus::NoNewData; + return DataStatus::NoNewData; const int battery_offset = offset + DS4_INPUT_REPORT_BATTERY_OFFSET; device->is_initialized = true; @@ -869,26 +703,17 @@ ds4_pad_handler::DS4DataStatus ds4_pad_handler::GetRawData(const std::shared_ptr if (device->hasCalibData) { int calibOffset = offset + DS4_INPUT_REPORT_GYRO_X_OFFSET; - for (int i = 0; i < DS4CalibIndex::COUNT; ++i) + for (int i = 0; i < CalibIndex::COUNT; ++i) { const s16 rawValue = read_s16(&buf[calibOffset]); - const s16 calValue = ApplyCalibration(rawValue, device->calibData[i]); + const s16 calValue = apply_calibration(rawValue, device->calibData[i]); buf[calibOffset++] = (static_cast(calValue) >> 0) & 0xFF; buf[calibOffset++] = (static_cast(calValue) >> 8) & 0xFF; } } memcpy(device->padData.data(), &buf[offset], 64); - return DS4DataStatus::NewData; -} - -std::shared_ptr ds4_pad_handler::get_device(const std::string& device) -{ - std::shared_ptr ds4device = GetDS4Device(device); - if (ds4device == nullptr) - return nullptr; - - return ds4device; + return DataStatus::NewData; } bool ds4_pad_handler::get_is_left_trigger(u64 keyCode) @@ -945,7 +770,7 @@ u32 ds4_pad_handler::get_battery_color(u8 battery_level, int brightness) PadHandlerBase::connection ds4_pad_handler::update_connection(const std::shared_ptr& device) { - auto ds4_dev = std::static_pointer_cast(device); + DS4Device* ds4_dev = static_cast(device.get()); if (!ds4_dev || ds4_dev->path.empty()) return connection::disconnected; @@ -970,9 +795,7 @@ PadHandlerBase::connection ds4_pad_handler::update_connection(const std::shared_ } } - status = GetRawData(ds4_dev); - - if (status == DS4DataStatus::ReadError) + if (GetRawData(ds4_dev) == DataStatus::ReadError) { // this also can mean disconnected, either way deal with it on next loop and reconnect hid_close(ds4_dev->hidDevice); @@ -986,7 +809,7 @@ PadHandlerBase::connection ds4_pad_handler::update_connection(const std::shared_ void ds4_pad_handler::get_extended_info(const std::shared_ptr& device, const std::shared_ptr& pad) { - auto ds4_device = std::static_pointer_cast(device); + DS4Device* ds4_device = static_cast(device.get()); if (!ds4_device || !pad) return; @@ -1024,8 +847,8 @@ void ds4_pad_handler::get_extended_info(const std::shared_ptr& device void ds4_pad_handler::apply_pad_data(const std::shared_ptr& device, const std::shared_ptr& pad) { - auto ds4_dev = std::static_pointer_cast(device); - if (!ds4_dev || !pad) + DS4Device* ds4_dev = static_cast(device.get()); + if (!ds4_dev || !ds4_dev->hidDevice || !pad) return; auto config = ds4_dev->config; diff --git a/rpcs3/Input/ds4_pad_handler.h b/rpcs3/Input/ds4_pad_handler.h index 6b28b060ccad..8ff9632f42c7 100644 --- a/rpcs3/Input/ds4_pad_handler.h +++ b/rpcs3/Input/ds4_pad_handler.h @@ -1,12 +1,25 @@ #pragma once -#include "Emu/Io/PadHandler.h" +#include "hid_pad_handler.h" #include "Utilities/CRC.h" -#include "hidapi.h" #include -class ds4_pad_handler final : public PadHandlerBase +class DS4Device : public HidDevice +{ +public: + bool btCon{false}; + bool hasCalibData{false}; + std::array calibData{}; + bool newVibrateData{true}; + std::array padData{}; + u8 batteryLevel{0}; + u8 last_battery_level{0}; + u8 cableState{0}; + bool is_initialized{false}; +}; + +class ds4_pad_handler final : public hid_pad_handler { // These are all the possible buttons on a standard DS4 controller // The touchpad is restricted to its button for now (or forever?) @@ -46,105 +59,25 @@ class ds4_pad_handler final : public PadHandlerBase KeyCodeCount }; - enum DS4CalibIndex - { - // gyro - PITCH = 0, - YAW, - ROLL, - - // accel - X, - Y, - Z, - COUNT - }; - - struct DS4CalibData - { - s16 bias; - s32 sensNumer; - s32 sensDenom; - }; - - enum class DS4DataStatus - { - NewData, - NoNewData, - ReadError, - }; - - struct DS4Device : public PadDevice - { - hid_device* hidDevice{ nullptr }; - std::string path{ "" }; - bool btCon{ false }; - bool hasCalibData{ false }; - std::array calibData{}; - bool newVibrateData{ true }; - u8 largeVibrate{ 0 }; - u8 smallVibrate{ 0 }; - std::array padData{}; - u8 batteryLevel{ 0 }; - u8 last_battery_level { 0 }; - u8 cableState{ 0 }; - u8 led_delay_on{ 0 }; - u8 led_delay_off{ 0 }; - bool is_initialized{ false }; - }; - - const u16 DS4_VID = 0x054C; - - // pid's of connected ds4 - const std::array ds4Pids = { { 0xBA0, 0x5C4, 0x09CC } }; - - // pseudo 'controller id' to keep track of unique controllers - std::map> controllers; - CRCPP::CRC::Table crcTable{ CRCPP::CRC::CRC_32() }; - public: ds4_pad_handler(); ~ds4_pad_handler(); - bool Init() override; - void ThreadProc() override; - - std::vector ListDevices() override; void SetPadData(const std::string& padId, u32 largeMotor, u32 smallMotor, s32 r, s32 g, s32 b, bool battery_led, u32 battery_led_brightness) override; u32 get_battery_level(const std::string& padId) override; void init_config(pad_config* cfg, const std::string& name) override; private: - bool is_init = false; - DS4DataStatus status; - std::chrono::system_clock::time_point m_last_enumeration; - std::set m_last_enumerated_devices; - void enumerate_devices(); u32 get_battery_color(u8 battery_level, int brightness); -private: - std::shared_ptr GetDS4Device(const std::string& padId); // Copies data into padData if status is NewData, otherwise buffer is untouched - DS4DataStatus GetRawData(const std::shared_ptr& ds4Device); + DataStatus GetRawData(DS4Device* ds4Device); // This function gets us usuable buffer from the rawbuffer of padData - bool GetCalibrationData(const std::shared_ptr& ds4Device); - void CheckAddDevice(hid_device* hidDevice, std::string_view path, std::wstring_view serial); - int send_output_report(const std::shared_ptr& device); - inline s16 ApplyCalibration(s32 rawValue, const DS4CalibData& calibData) - { - const s32 biased = rawValue - calibData.bias; - const s32 quot = calibData.sensNumer / calibData.sensDenom; - const s32 rem = calibData.sensNumer % calibData.sensDenom; - const s32 output = (quot * biased) + ((rem * biased) / calibData.sensDenom); + bool GetCalibrationData(DS4Device* ds4Device); + int send_output_report(DS4Device* device); - if (output > INT16_MAX) - return INT16_MAX; - else if (output < INT16_MIN) - return INT16_MIN; - else return static_cast(output); - } + void check_add_device(hid_device* hidDevice, std::string_view path, std::wstring_view serial); - std::shared_ptr get_device(const std::string& device) override; bool get_is_left_trigger(u64 keyCode) override; bool get_is_right_trigger(u64 keyCode) override; bool get_is_left_stick(u64 keyCode) override; diff --git a/rpcs3/Input/hid_pad_handler.cpp b/rpcs3/Input/hid_pad_handler.cpp new file mode 100644 index 000000000000..f624a3e413f3 --- /dev/null +++ b/rpcs3/Input/hid_pad_handler.cpp @@ -0,0 +1,200 @@ +#include "hid_pad_handler.h" +#include "ds4_pad_handler.h" +#include "util/logs.hpp" + +#include +#include + +LOG_CHANNEL(hid_log, "HID"); + +template +hid_pad_handler::hid_pad_handler(pad_handler type, u16 vid, std::vector pids) + : PadHandlerBase(type), m_vid(vid), m_pids(std::move(pids)) +{ +}; + +template +hid_pad_handler::~hid_pad_handler() +{ + for (auto& controller : m_controllers) + { + if (controller.second && controller.second->hidDevice) + { + hid_close(controller.second->hidDevice); + } + } + + if (hid_exit() != 0) + { + hid_log.error("hid_exit failed!"); + } +} + +template +bool hid_pad_handler::Init() +{ + if (m_is_init) + return true; + + const int res = hid_init(); + if (res != 0) + fmt::throw_exception("hidapi-init error.threadproc"); + + for (size_t i = 1; i <= MAX_GAMEPADS; i++) // Controllers 1-n in GUI + { + m_controllers.emplace(m_name_string + std::to_string(i), std::make_shared()); + } + + enumerate_devices(); + + m_is_init = true; + return true; +} + +template +void hid_pad_handler::ThreadProc() +{ + const auto now = std::chrono::system_clock::now(); + const auto elapsed = std::chrono::duration_cast(now - m_last_enumeration).count(); + if (elapsed > 2000) + { + m_last_enumeration = now; + enumerate_devices(); + } + + PadHandlerBase::ThreadProc(); +} + +template +std::vector hid_pad_handler::ListDevices() +{ + std::vector pads_list; + + if (!Init()) + return pads_list; + + for (const auto& controller : m_controllers) // Controllers 1-n in GUI + { + pads_list.emplace_back(controller.first); + } + + return pads_list; +} + +template +void hid_pad_handler::enumerate_devices() +{ + std::set device_paths; + std::map serials; + + for (const auto& pid : m_pids) + { + hid_device_info* dev_info = hid_enumerate(m_vid, pid); + hid_device_info* head = dev_info; + while (dev_info) + { + ensure(dev_info->path != nullptr); + device_paths.insert(dev_info->path); + serials[dev_info->path] = dev_info->serial_number ? std::wstring_view(dev_info->serial_number) : std::wstring_view{}; + dev_info = dev_info->next; + } + hid_free_enumeration(head); + } + + if (m_last_enumerated_devices == device_paths) + { + return; + } + + m_last_enumerated_devices = device_paths; + + // Scrap devices that are not in the new list + for (auto& controller : m_controllers) + { + if (controller.second && !controller.second->path.empty() && !device_paths.contains(controller.second->path)) + { + hid_close(controller.second->hidDevice); + pad_config* config = controller.second->config; + controller.second.reset(new Device()); + controller.second->config = config; + } + } + + bool warn_about_drivers = false; + + // Find and add new devices + for (const auto& path : device_paths) + { + // Check if we already have this controller + const auto it_found = std::find_if(m_controllers.cbegin(), m_controllers.cend(), [path](const auto& c) { return c.second && c.second->path == path; }); + + if (it_found == m_controllers.cend()) + { + // Check if we have at least one virtual controller left + const auto it_free = std::find_if(m_controllers.cbegin(), m_controllers.cend(), [](const auto& c) { return !c.second || !c.second->hidDevice; }); + if (it_free == m_controllers.cend()) + { + break; + } + + hid_device* dev = hid_open_path(path.c_str()); + if (dev) + { + check_add_device(dev, path, serials[path]); + } + else + { + hid_log.error("hid_open_path failed! Reason: %s", hid_error(dev)); + warn_about_drivers = true; + } + } + } + + if (warn_about_drivers) + { + hid_log.error("One or more pads were detected but couldn't be interacted with directly"); +#if defined(_WIN32) || defined(__linux__) + hid_log.error("Check https://wiki.rpcs3.net/index.php?title=Help:Controller_Configuration for intructions on how to solve this issue"); +#endif + } + else + { + const size_t count = std::count_if(m_controllers.cbegin(), m_controllers.cend(), [](const auto& c) { return c.second && c.second->hidDevice; }); + if (count > 0) + { + hid_log.success("Controllers found: %d", count); + } + else + { + hid_log.warning("No controllers found!"); + } + } +} + +template +std::shared_ptr hid_pad_handler::get_hid_device(const std::string& padId) +{ + if (!Init()) + return nullptr; + + std::shared_ptr device = nullptr; + + // Controllers 1-n in GUI + for (auto& cur_control : m_controllers) + { + if (padId == cur_control.first) + { + return cur_control.second; + } + } + + return nullptr; +} + +template +std::shared_ptr hid_pad_handler::get_device(const std::string& device) +{ + return get_hid_device(device); +} + +template class hid_pad_handler; diff --git a/rpcs3/Input/hid_pad_handler.h b/rpcs3/Input/hid_pad_handler.h new file mode 100644 index 000000000000..6af2535c38ad --- /dev/null +++ b/rpcs3/Input/hid_pad_handler.h @@ -0,0 +1,103 @@ +#pragma once + +#include "Emu/Io/PadHandler.h" +#include "Utilities/CRC.h" + +#include "hidapi.h" + +struct CalibData +{ + s16 bias; + s32 sens_numer; + s32 sens_denom; +}; + +enum CalibIndex +{ + // gyro + PITCH = 0, + YAW, + ROLL, + + // accel + X, + Y, + Z, + COUNT +}; + +class HidDevice : public PadDevice +{ +public: + hid_device* hidDevice{nullptr}; + std::string path{""}; + u8 largeVibrate{0}; + u8 smallVibrate{0}; + u8 led_delay_on{0}; + u8 led_delay_off{0}; +}; + +template +class hid_pad_handler : public PadHandlerBase +{ +public: + hid_pad_handler(pad_handler type, u16 vid, std::vector pids); + ~hid_pad_handler(); + + bool Init() override; + void ThreadProc() override; + std::vector ListDevices() override; + +protected: + enum class DataStatus + { + NewData, + NoNewData, + ReadError, + }; + + CRCPP::CRC::Table crcTable{CRCPP::CRC::CRC_32()}; + + u16 m_vid; + std::vector m_pids; + + // pseudo 'controller id' to keep track of unique controllers + std::map> m_controllers; + + bool m_is_init = false; + std::chrono::system_clock::time_point m_last_enumeration; + std::set m_last_enumerated_devices; + + void enumerate_devices(); + std::shared_ptr get_hid_device(const std::string& padId); + + virtual void check_add_device(hid_device* hidDevice, std::string_view path, std::wstring_view serial) = 0; + + inline s16 apply_calibration(s32 rawValue, const CalibData& calibData) + { + const s32 biased = rawValue - calibData.bias; + const s32 quot = calibData.sens_numer / calibData.sens_denom; + const s32 rem = calibData.sens_numer % calibData.sens_denom; + const s32 output = (quot * biased) + ((rem * biased) / calibData.sens_denom); + + if (output > INT16_MAX) + return INT16_MAX; + else if (output < INT16_MIN) + return INT16_MIN; + else + return static_cast(output); + } + + inline s16 read_s16(const void* buf) + { + return *reinterpret_cast(buf); + } + + inline u32 read_u32(const void* buf) + { + return *reinterpret_cast(buf); + } + +private: + std::shared_ptr get_device(const std::string& device) override; +}; diff --git a/rpcs3/rpcs3.vcxproj b/rpcs3/rpcs3.vcxproj index 461d95871185..97ee05b4af66 100644 --- a/rpcs3/rpcs3.vcxproj +++ b/rpcs3/rpcs3.vcxproj @@ -332,6 +332,7 @@ + @@ -1641,6 +1642,7 @@ + Moc%27ing gs_frame.h... diff --git a/rpcs3/rpcs3.vcxproj.filters b/rpcs3/rpcs3.vcxproj.filters index 1c72125b831e..a8c176877c5f 100644 --- a/rpcs3/rpcs3.vcxproj.filters +++ b/rpcs3/rpcs3.vcxproj.filters @@ -1105,6 +1105,9 @@ Generated Files\Debug - LLVM + + Io + @@ -1230,6 +1233,9 @@ Gui\misc dialogs + + Io + From 98f2cfd41ad1d94415f659db003ecfcafac6fedc Mon Sep 17 00:00:00 2001 From: Megamouse Date: Thu, 11 Feb 2021 23:27:33 +0100 Subject: [PATCH 03/11] DualSense: inherit from hid_pad_handler --- rpcs3/Input/ds4_pad_handler.cpp | 80 +++---- rpcs3/Input/ds4_pad_handler.h | 2 +- rpcs3/Input/dualsense_pad_handler.cpp | 290 +++++++++----------------- rpcs3/Input/dualsense_pad_handler.h | 117 +++-------- rpcs3/Input/hid_pad_handler.cpp | 2 + rpcs3/Input/hid_pad_handler.h | 6 +- 6 files changed, 181 insertions(+), 316 deletions(-) diff --git a/rpcs3/Input/ds4_pad_handler.cpp b/rpcs3/Input/ds4_pad_handler.cpp index fad938739dfa..021c4546fa4c 100644 --- a/rpcs3/Input/ds4_pad_handler.cpp +++ b/rpcs3/Input/ds4_pad_handler.cpp @@ -4,19 +4,24 @@ LOG_CHANNEL(ds4_log, "DS4"); +constexpr u16 DS4_VID = 0x054C; +constexpr u16 DS4_PID_0 = 0xBA0; +constexpr u16 DS4_PID_1 = 0x5C4; +constexpr u16 DS4_PID_2 = 0x09CC; + namespace { - const u32 DS4_ACC_RES_PER_G = 8192; - 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; - const u32 DS4_OUTPUT_REPORT_0x11_SIZE = 78; - const u32 DS4_INPUT_REPORT_GYRO_X_OFFSET = 13; - const u32 DS4_INPUT_REPORT_BATTERY_OFFSET = 30; + constexpr u32 DS4_ACC_RES_PER_G = 8192; + constexpr 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 + constexpr u32 DS4_FEATURE_REPORT_0x02_SIZE = 37; + constexpr u32 DS4_FEATURE_REPORT_0x05_SIZE = 41; + constexpr u32 DS4_FEATURE_REPORT_0x12_SIZE = 16; + constexpr u32 DS4_FEATURE_REPORT_0x81_SIZE = 7; + constexpr u32 DS4_INPUT_REPORT_0x11_SIZE = 78; + constexpr u32 DS4_OUTPUT_REPORT_0x05_SIZE = 32; + constexpr u32 DS4_OUTPUT_REPORT_0x11_SIZE = 78; + constexpr u32 DS4_INPUT_REPORT_GYRO_X_OFFSET = 13; + constexpr u32 DS4_INPUT_REPORT_BATTERY_OFFSET = 30; // This tries to convert axis to give us the max even in the corners, // this actually might work 'too' well, we end up actually getting diagonals of actual max/min, we need the corners still a bit rounded to match ds3 @@ -66,7 +71,7 @@ namespace } ds4_pad_handler::ds4_pad_handler() - : hid_pad_handler(pad_handler::ds4, 0x054C, {0xBA0, 0x5C4, 0x09CC}) + : hid_pad_handler(pad_handler::ds4, DS4_VID, {DS4_PID_0, DS4_PID_1, DS4_PID_2}) { // Unique names for the config files and our pad settings dialog button_list = @@ -195,8 +200,8 @@ void ds4_pad_handler::SetPadData(const std::string& padId, u32 largeMotor, u32 s return; // Set the device's motor speeds to our requested values 0-255 - device->largeVibrate = largeMotor; - device->smallVibrate = smallMotor; + device->large_motor = largeMotor; + device->small_motor = smallMotor; int index = 0; for (uint i = 0; i < MAX_GAMEPADS; i++) @@ -497,24 +502,25 @@ void ds4_pad_handler::check_add_device(hid_device* hidDevice, std::string_view p return; } - DS4Device* ds4_dev = nullptr; + DS4Device* device = nullptr; for (auto& controller : m_controllers) { - if (!controller.second || !controller.second->hidDevice) + ensure(controller.second); + + if (!controller.second->hidDevice) { - ds4_dev = controller.second.get(); + device = controller.second.get(); break; } } - if (!ds4_dev) + if (!device) { return; } std::string serial; - ds4_dev->hidDevice = hidDevice; // There isnt a nice 'portable' way with hidapi to detect bt vs wired as the pid/vid's are the same // Let's try getting 0x81 feature report, which should will return mac address on wired, and should error on bluetooth @@ -540,15 +546,18 @@ void ds4_pad_handler::check_add_device(hid_device* hidDevice, std::string_view p } else { - ds4_dev->btCon = true; + device->btCon = true; for (wchar_t ch : wide_serial) serial += static_cast(ch); } - if (!GetCalibrationData(ds4_dev)) + device->hidDevice = hidDevice; + + if (!GetCalibrationData(device)) { ds4_log.error("check_add_device: GetCalibrationData failed!"); hid_close(hidDevice); + device->hidDevice = nullptr; return; } @@ -556,13 +565,14 @@ void ds4_pad_handler::check_add_device(hid_device* hidDevice, std::string_view p { ds4_log.error("check_add_device: hid_set_nonblocking failed! Reason: %s", hid_error(hidDevice)); hid_close(hidDevice); + device->hidDevice = nullptr; return; } - ds4_dev->hasCalibData = true; - ds4_dev->path = path; + device->hasCalibData = true; + device->path = path; - send_output_report(ds4_dev); + send_output_report(device); } ds4_pad_handler::~ds4_pad_handler() @@ -572,8 +582,8 @@ ds4_pad_handler::~ds4_pad_handler() if (controller.second && controller.second->hidDevice) { // Disable blinking and vibration - controller.second->smallVibrate = 0; - controller.second->largeVibrate = 0; + controller.second->small_motor = 0; + controller.second->large_motor = 0; controller.second->led_delay_on = 0; controller.second->led_delay_off = 0; send_output_report(controller.second.get()); @@ -597,8 +607,8 @@ int ds4_pad_handler::send_output_report(DS4Device* device) outputBuf[0] = 0x11; outputBuf[1] = 0xC4; outputBuf[3] = 0x07; - outputBuf[6] = device->smallVibrate; - outputBuf[7] = device->largeVibrate; + outputBuf[6] = device->small_motor; + outputBuf[7] = device->large_motor; outputBuf[8] = config->colorR; // red outputBuf[9] = config->colorG; // green outputBuf[10] = config->colorB; // blue @@ -624,8 +634,8 @@ int ds4_pad_handler::send_output_report(DS4Device* device) { outputBuf[0] = 0x05; outputBuf[1] = 0x07; - outputBuf[4] = device->smallVibrate; - outputBuf[5] = device->largeVibrate; + outputBuf[4] = device->small_motor; + outputBuf[5] = device->large_motor; outputBuf[6] = config->colorR; // red outputBuf[7] = config->colorG; // green outputBuf[8] = config->colorB; // blue @@ -636,7 +646,7 @@ int ds4_pad_handler::send_output_report(DS4Device* device) } } -ds4_pad_handler::DataStatus ds4_pad_handler::GetRawData(DS4Device* device) +ds4_pad_handler::DataStatus ds4_pad_handler::get_data(DS4Device* device) { if (!device || !device->hidDevice) return DataStatus::ReadError; @@ -795,7 +805,7 @@ PadHandlerBase::connection ds4_pad_handler::update_connection(const std::shared_ } } - if (GetRawData(ds4_dev) == DataStatus::ReadError) + if (get_data(ds4_dev) == DataStatus::ReadError) { // this also can mean disconnected, either way deal with it on next loop and reconnect hid_close(ds4_dev->hidDevice); @@ -898,10 +908,10 @@ void ds4_pad_handler::apply_pad_data(const std::shared_ptr& device, c } } - ds4_dev->newVibrateData |= ds4_dev->largeVibrate != speed_large || ds4_dev->smallVibrate != speed_small || newBlinkData; + ds4_dev->newVibrateData |= ds4_dev->large_motor != speed_large || ds4_dev->small_motor != speed_small || newBlinkData; - ds4_dev->largeVibrate = speed_large; - ds4_dev->smallVibrate = speed_small; + ds4_dev->large_motor = speed_large; + ds4_dev->small_motor = speed_small; if (ds4_dev->newVibrateData && send_output_report(ds4_dev) >= 0) { diff --git a/rpcs3/Input/ds4_pad_handler.h b/rpcs3/Input/ds4_pad_handler.h index 8ff9632f42c7..2bf651fd53f0 100644 --- a/rpcs3/Input/ds4_pad_handler.h +++ b/rpcs3/Input/ds4_pad_handler.h @@ -71,7 +71,7 @@ class ds4_pad_handler final : public hid_pad_handler u32 get_battery_color(u8 battery_level, int brightness); // Copies data into padData if status is NewData, otherwise buffer is untouched - DataStatus GetRawData(DS4Device* ds4Device); + DataStatus get_data(DS4Device* ds4Device); // This function gets us usuable buffer from the rawbuffer of padData bool GetCalibrationData(DS4Device* ds4Device); int send_output_report(DS4Device* device); diff --git a/rpcs3/Input/dualsense_pad_handler.cpp b/rpcs3/Input/dualsense_pad_handler.cpp index bf0c94ba723d..d57c661ae71d 100644 --- a/rpcs3/Input/dualsense_pad_handler.cpp +++ b/rpcs3/Input/dualsense_pad_handler.cpp @@ -6,13 +6,16 @@ LOG_CHANNEL(dualsense_log, "DualSense"); namespace { - const u32 DUALSENSE_ACC_RES_PER_G = 8192; - const u32 DUALSENSE_GYRO_RES_PER_DEG_S = 1024; - const u32 DUALSENSE_CALIBRATION_REPORT_SIZE = 41; - const u32 DUALSENSE_BLUETOOTH_REPORT_SIZE = 78; - const u32 DUALSENSE_USB_REPORT_SIZE = 63; - const u32 DUALSENSE_COMMON_REPORT_SIZE = 47; - const u32 DUALSENSE_INPUT_REPORT_GYRO_X_OFFSET = 15; + constexpr u32 DUALSENSE_ACC_RES_PER_G = 8192; + constexpr u32 DUALSENSE_GYRO_RES_PER_DEG_S = 1024; + constexpr u32 DUALSENSE_CALIBRATION_REPORT_SIZE = 41; + constexpr u32 DUALSENSE_BLUETOOTH_REPORT_SIZE = 78; + constexpr u32 DUALSENSE_USB_REPORT_SIZE = 63; + constexpr u32 DUALSENSE_COMMON_REPORT_SIZE = 47; + constexpr u32 DUALSENSE_INPUT_REPORT_GYRO_X_OFFSET = 15; + + constexpr u16 DUALSENSE_VID = 0x054C; + constexpr u16 DUALSENSE_PID = 0x0CE6; enum { @@ -68,20 +71,10 @@ namespace static_assert(sizeof(struct output_report_common) == DUALSENSE_COMMON_REPORT_SIZE); static_assert(sizeof(struct output_report_bt) == DUALSENSE_BLUETOOTH_REPORT_SIZE); static_assert(sizeof(struct output_report_usb) == DUALSENSE_USB_REPORT_SIZE); - - inline s16 read_s16(const void* buf) - { - return *reinterpret_cast(buf); - } - - inline u32 read_u32(const void* buf) - { - return *reinterpret_cast(buf); - } } dualsense_pad_handler::dualsense_pad_handler() - : PadHandlerBase(pad_handler::dualsense) + : hid_pad_handler(pad_handler::dualsense, DUALSENSE_VID, {DUALSENSE_PID}) { // Unique names for the config files and our pad settings dialog button_list = @@ -138,11 +131,32 @@ dualsense_pad_handler::dualsense_pad_handler() m_thumb_threshold = thumb_max / 2; } -void dualsense_pad_handler::CheckAddDevice(hid_device * hidDevice, hid_device_info* hidDevInfo) +void dualsense_pad_handler::check_add_device(hid_device* hidDevice, std::string_view path, std::wstring_view wide_serial) { + if (!hidDevice) + { + return; + } + + DualSenseDevice* device = nullptr; + + for (auto& controller : m_controllers) + { + ensure(controller.second); + + if (!controller.second->hidDevice) + { + device = controller.second.get(); + break; + } + } + + if (!device) + { + return; + } + std::string serial; - std::shared_ptr dualsenseDev = std::make_shared(); - dualsenseDev->hidDevice = hidDevice; std::array buf{}; buf[0] = 0x09; @@ -153,78 +167,39 @@ void dualsense_pad_handler::CheckAddDevice(hid_device * hidDevice, hid_device_in if (hid_get_feature_report(hidDevice, buf.data(), 64) == 21) { serial = fmt::format("%x%x%x%x%x%x", buf[6], buf[5], buf[4], buf[3], buf[2], buf[1]); - dualsenseDev->dataMode = DualSenseDataMode::Enhanced; + device->dataMode = DualSenseDevice::DualSenseDataMode::Enhanced; } else { // We're probably on Bluetooth in this case, but for whatever reason the feature report failed. // This will give us a less capable fallback. - dualsenseDev->dataMode = DualSenseDataMode::Simple; - std::wstring_view wideSerial(hidDevInfo->serial_number); - for (wchar_t ch : wideSerial) + device->dataMode = DualSenseDevice::DualSenseDataMode::Simple; + for (wchar_t ch : wide_serial) serial += static_cast(ch); } - if (!get_calibration_data(dualsenseDev)) + device->hidDevice = hidDevice; + + if (!get_calibration_data(device)) { - dualsense_log.error("CheckAddDevice: get_calibration_data failed!"); + dualsense_log.error("check_add_device: get_calibration_data failed!"); hid_close(hidDevice); + device->hidDevice = nullptr; return; } if (hid_set_nonblocking(hidDevice, 1) == -1) { - dualsense_log.error("CheckAddDevice: hid_set_nonblocking failed! Reason: %s", hid_error(hidDevice)); + dualsense_log.error("check_add_device: hid_set_nonblocking failed! Reason: %s", hid_error(hidDevice)); hid_close(hidDevice); + device->hidDevice = nullptr; return; } - dualsenseDev->has_calib_data = true; - dualsenseDev->path = hidDevInfo->path; - controllers.emplace(serial, dualsenseDev); -} - -bool dualsense_pad_handler::Init() -{ - if (is_init) - return true; - - const int res = hid_init(); - if (res != 0) - fmt::throw_exception("hidapi-init error.threadproc"); - - hid_device_info* devInfo = hid_enumerate(DUALSENSE_VID, DUALSENSE_PID); - hid_device_info* head = devInfo; - - while (devInfo) - { - if (controllers.size() >= MAX_GAMEPADS) - break; - - hid_device* dev = hid_open_path(devInfo->path); - if (dev) - { - CheckAddDevice(dev, devInfo); - } - else - { - dualsense_log.error("hid_open_path failed! Reason: %s", hid_error(dev)); - } - devInfo = devInfo->next; - } - hid_free_enumeration(head); + device->has_calib_data = true; + device->path = path; - if (controllers.empty()) - { - dualsense_log.warning("No controllers found!"); - } - else - { - dualsense_log.success("Controllers found: %d", controllers.size()); - } - - is_init = true; - return true; + send_output_report(device); } void dualsense_pad_handler::init_config(pad_config* cfg, const std::string& name) @@ -283,30 +258,10 @@ void dualsense_pad_handler::init_config(pad_config* cfg, const std::string& name cfg->from_default(); } -std::vector dualsense_pad_handler::ListDevices() -{ - std::vector dualsense_pads_list; - - if (!Init()) - return dualsense_pads_list; - - for (usz i = 1; i < controllers.size(); ++i) - { - dualsense_pads_list.emplace_back(m_name_string + std::to_string(i)); - } - - for (auto& pad : dualsense_pads_list) - { - dualsense_log.success("%s", pad); - } - - return dualsense_pads_list; -} - -dualsense_pad_handler::DualSenseDataStatus dualsense_pad_handler::GetRawData(const std::shared_ptr& device) +dualsense_pad_handler::DataStatus dualsense_pad_handler::get_data(DualSenseDevice* device) { if (!device) - return DualSenseDataStatus::ReadError; + return DataStatus::ReadError; std::array buf{}; @@ -315,11 +270,11 @@ dualsense_pad_handler::DualSenseDataStatus dualsense_pad_handler::GetRawData(con if (res == -1) { // looks like controller disconnected or read error - return DualSenseDataStatus::ReadError; + return DataStatus::ReadError; } if (res == 0) - return DualSenseDataStatus::NoNewData; + return DataStatus::NoNewData; u8 offset = 0; switch (buf[0]) @@ -328,13 +283,13 @@ dualsense_pad_handler::DualSenseDataStatus dualsense_pad_handler::GetRawData(con { if (res == DUALSENSE_BLUETOOTH_REPORT_SIZE) { - device->dataMode = DualSenseDataMode::Simple; + device->dataMode = DualSenseDevice::DualSenseDataMode::Simple; device->btCon = true; offset = 1; } else { - device->dataMode = DualSenseDataMode::Enhanced; + device->dataMode = DualSenseDevice::DualSenseDataMode::Enhanced; device->btCon = false; offset = 1; } @@ -342,7 +297,7 @@ dualsense_pad_handler::DualSenseDataStatus dualsense_pad_handler::GetRawData(con } case 0x31: { - device->dataMode = DualSenseDataMode::Enhanced; + device->dataMode = DualSenseDevice::DualSenseDataMode::Enhanced; device->btCon = true; offset = 2; @@ -353,18 +308,18 @@ dualsense_pad_handler::DualSenseDataStatus dualsense_pad_handler::GetRawData(con if (crcCalc != crcReported) { dualsense_log.warning("Data packet CRC check failed, ignoring! Received 0x%x, Expected 0x%x", crcReported, crcCalc); - return DualSenseDataStatus::NoNewData; + return DataStatus::NoNewData; } break; } default: - return DualSenseDataStatus::NoNewData; + return DataStatus::NoNewData; } if (device->has_calib_data) { int calib_offset = offset + DUALSENSE_INPUT_REPORT_GYRO_X_OFFSET; - for (int i = 0; i < DualSenseCalibIndex::COUNT; ++i) + for (int i = 0; i < CalibIndex::COUNT; ++i) { const s16 raw_value = read_s16(&buf[calib_offset]); const s16 cal_value = apply_calibration(raw_value, device->calib_data[i]); @@ -374,10 +329,10 @@ dualsense_pad_handler::DualSenseDataStatus dualsense_pad_handler::GetRawData(con } memcpy(device->padData.data(), &buf[offset], 64); - return DualSenseDataStatus::NewData; + return DataStatus::NewData; } -bool dualsense_pad_handler::get_calibration_data(const std::shared_ptr& dualsense_device) +bool dualsense_pad_handler::get_calibration_data(DualSenseDevice* dualsense_device) { if (!dualsense_device || !dualsense_device->hidDevice) { @@ -426,9 +381,9 @@ bool dualsense_pad_handler::get_calibration_data(const std::shared_ptrcalib_data[DualSenseCalibIndex::PITCH].bias = read_s16(&buf[1]); - dualsense_device->calib_data[DualSenseCalibIndex::YAW].bias = read_s16(&buf[3]); - dualsense_device->calib_data[DualSenseCalibIndex::ROLL].bias = read_s16(&buf[5]); + dualsense_device->calib_data[CalibIndex::PITCH].bias = read_s16(&buf[1]); + dualsense_device->calib_data[CalibIndex::YAW].bias = read_s16(&buf[3]); + dualsense_device->calib_data[CalibIndex::ROLL].bias = read_s16(&buf[5]); s16 pitch_plus, pitch_minus, roll_plus, roll_minus, yaw_plus, yaw_minus; @@ -467,14 +422,14 @@ bool dualsense_pad_handler::get_calibration_data(const std::shared_ptrcalib_data[DualSenseCalibIndex::PITCH].sens_numer = gyro_speed_scale * DUALSENSE_GYRO_RES_PER_DEG_S; - dualsense_device->calib_data[DualSenseCalibIndex::PITCH].sens_denom = pitch_plus - pitch_minus; + dualsense_device->calib_data[CalibIndex::PITCH].sens_numer = gyro_speed_scale * DUALSENSE_GYRO_RES_PER_DEG_S; + dualsense_device->calib_data[CalibIndex::PITCH].sens_denom = pitch_plus - pitch_minus; - dualsense_device->calib_data[DualSenseCalibIndex::YAW].sens_numer = gyro_speed_scale * DUALSENSE_GYRO_RES_PER_DEG_S; - dualsense_device->calib_data[DualSenseCalibIndex::YAW].sens_denom = yaw_plus - yaw_minus; + dualsense_device->calib_data[CalibIndex::YAW].sens_numer = gyro_speed_scale * DUALSENSE_GYRO_RES_PER_DEG_S; + dualsense_device->calib_data[CalibIndex::YAW].sens_denom = yaw_plus - yaw_minus; - dualsense_device->calib_data[DualSenseCalibIndex::ROLL].sens_numer = gyro_speed_scale * DUALSENSE_GYRO_RES_PER_DEG_S; - dualsense_device->calib_data[DualSenseCalibIndex::ROLL].sens_denom = roll_plus - roll_minus; + dualsense_device->calib_data[CalibIndex::ROLL].sens_numer = gyro_speed_scale * DUALSENSE_GYRO_RES_PER_DEG_S; + dualsense_device->calib_data[CalibIndex::ROLL].sens_denom = roll_plus - roll_minus; const s16 accel_x_plus = read_s16(&buf[23]); const s16 accel_x_minus = read_s16(&buf[25]); @@ -487,17 +442,17 @@ bool dualsense_pad_handler::get_calibration_data(const std::shared_ptrcalib_data[DualSenseCalibIndex::X].bias = accel_x_plus - accel_x_range / 2; - dualsense_device->calib_data[DualSenseCalibIndex::X].sens_numer = 2 * DUALSENSE_ACC_RES_PER_G; - dualsense_device->calib_data[DualSenseCalibIndex::X].sens_denom = accel_x_range; + dualsense_device->calib_data[CalibIndex::X].bias = accel_x_plus - accel_x_range / 2; + dualsense_device->calib_data[CalibIndex::X].sens_numer = 2 * DUALSENSE_ACC_RES_PER_G; + dualsense_device->calib_data[CalibIndex::X].sens_denom = accel_x_range; - dualsense_device->calib_data[DualSenseCalibIndex::Y].bias = accel_y_plus - accel_y_range / 2; - dualsense_device->calib_data[DualSenseCalibIndex::Y].sens_numer = 2 * DUALSENSE_ACC_RES_PER_G; - dualsense_device->calib_data[DualSenseCalibIndex::Y].sens_denom = accel_y_range; + dualsense_device->calib_data[CalibIndex::Y].bias = accel_y_plus - accel_y_range / 2; + dualsense_device->calib_data[CalibIndex::Y].sens_numer = 2 * DUALSENSE_ACC_RES_PER_G; + dualsense_device->calib_data[CalibIndex::Y].sens_denom = accel_y_range; - dualsense_device->calib_data[DualSenseCalibIndex::Z].bias = accel_z_plus - accel_z_range / 2; - dualsense_device->calib_data[DualSenseCalibIndex::Z].sens_numer = 2 * DUALSENSE_ACC_RES_PER_G; - dualsense_device->calib_data[DualSenseCalibIndex::Z].sens_denom = accel_z_range; + dualsense_device->calib_data[CalibIndex::Z].bias = accel_z_plus - accel_z_range / 2; + dualsense_device->calib_data[CalibIndex::Z].sens_numer = 2 * DUALSENSE_ACC_RES_PER_G; + dualsense_device->calib_data[CalibIndex::Z].sens_denom = accel_z_range; // Make sure data 'looks' valid, dongle will report invalid calibration data with no controller connected @@ -553,8 +508,8 @@ bool dualsense_pad_handler::get_is_right_stick(u64 keyCode) PadHandlerBase::connection dualsense_pad_handler::update_connection(const std::shared_ptr& device) { - auto dualsense_dev = std::static_pointer_cast(device); - if (!dualsense_dev) + DualSenseDevice* dualsense_dev = static_cast(device.get()); + if (!dualsense_dev || dualsense_dev->path.empty()) return connection::disconnected; if (dualsense_dev->hidDevice == nullptr) @@ -578,8 +533,7 @@ PadHandlerBase::connection dualsense_pad_handler::update_connection(const std::s } } - status = GetRawData(dualsense_dev); - if (status == DualSenseDataStatus::ReadError) + if (get_data(dualsense_dev) == DataStatus::ReadError) { // this also can mean disconnected, either way deal with it on next loop and reconnect hid_close(dualsense_dev->hidDevice); @@ -593,7 +547,7 @@ PadHandlerBase::connection dualsense_pad_handler::update_connection(const std::s void dualsense_pad_handler::get_extended_info(const std::shared_ptr& device, const std::shared_ptr& pad) { - auto dualsense_device = std::static_pointer_cast(device); + DualSenseDevice* dualsense_device = static_cast(device.get()); if (!dualsense_device || !pad) return; @@ -631,13 +585,13 @@ void dualsense_pad_handler::get_extended_info(const std::shared_ptr& std::unordered_map dualsense_pad_handler::get_button_values(const std::shared_ptr& device) { std::unordered_map keyBuffer; - auto dualsense_dev = std::static_pointer_cast(device); + DualSenseDevice* dualsense_dev = static_cast(device.get()); if (!dualsense_dev) return keyBuffer; auto buf = dualsense_dev->padData; - if (dualsense_dev->dataMode == DualSenseDataMode::Simple) + if (dualsense_dev->dataMode == DualSenseDevice::DualSenseDataMode::Simple) { // Left Stick X Axis keyBuffer[DualSenseKeyCodes::LSXNeg] = Clamp0To255((127.5f - buf[0]) * 2.0f); @@ -860,63 +814,23 @@ pad_preview_values dualsense_pad_handler::get_preview_values(const std::unordere }; } -std::shared_ptr dualsense_pad_handler::GetDualSenseDevice(const std::string& padId) -{ - if (!Init()) - return nullptr; - - usz pos = padId.find(m_name_string); - if (pos == umax) - return nullptr; - - std::string pad_serial = padId.substr(pos + 15); - std::shared_ptr device = nullptr; - - int i = 0; // Controllers 1-n in GUI - for (auto& cur_control : controllers) - { - if (pad_serial == std::to_string(++i) || pad_serial == cur_control.first) - { - device = cur_control.second; - break; - } - } - - return device; -} - -std::shared_ptr dualsense_pad_handler::get_device(const std::string& device) -{ - std::shared_ptr dualsense_dev = GetDualSenseDevice(device); - if (dualsense_dev == nullptr || dualsense_dev->hidDevice == nullptr) - return nullptr; - - return dualsense_dev; -} - dualsense_pad_handler::~dualsense_pad_handler() { - for (auto& controller : controllers) + for (auto& controller : m_controllers) { - if (controller.second->hidDevice) + if (controller.second && controller.second->hidDevice) { // Disable vibration - controller.second->smallVibrate = 0; - controller.second->largeVibrate = 0; - send_output_report(controller.second); - - hid_close(controller.second->hidDevice); + controller.second->small_motor = 0; + controller.second->large_motor = 0; + send_output_report(controller.second.get()); } } - if (hid_exit() != 0) - { - dualsense_log.error("hid_exit failed!"); - } } -int dualsense_pad_handler::send_output_report(const std::shared_ptr& device) +int dualsense_pad_handler::send_output_report(DualSenseDevice* device) { - if (!device) + if (!device || !device->hidDevice) return -2; auto config = device->config; @@ -926,8 +840,8 @@ int dualsense_pad_handler::send_output_report(const std::shared_ptrlargeVibrate; - common.motor_right = device->smallVibrate; + common.motor_left = device->large_motor; + common.motor_right = device->small_motor; if (device->init_lightbar) { @@ -1003,8 +917,8 @@ int dualsense_pad_handler::send_output_report(const std::shared_ptr& device, const std::shared_ptr& pad) { - auto dualsense_dev = std::static_pointer_cast(device); - if (!dualsense_dev || !pad) + DualSenseDevice* dualsense_dev = static_cast(device.get()); + if (!dualsense_dev || !dualsense_dev->hidDevice || !pad) return; auto config = dualsense_dev->config; @@ -1016,10 +930,10 @@ void dualsense_pad_handler::apply_pad_data(const std::shared_ptr& dev const int speed_large = config->enable_vibration_motor_large ? pad->m_vibrateMotors[idx_l].m_value : vibration_min; const int speed_small = config->enable_vibration_motor_small ? pad->m_vibrateMotors[idx_s].m_value : vibration_min; - dualsense_dev->newVibrateData |= dualsense_dev->largeVibrate != speed_large || dualsense_dev->smallVibrate != speed_small; + dualsense_dev->newVibrateData |= dualsense_dev->large_motor != speed_large || dualsense_dev->small_motor != speed_small; - dualsense_dev->largeVibrate = speed_large; - dualsense_dev->smallVibrate = speed_small; + dualsense_dev->large_motor = speed_large; + dualsense_dev->small_motor = speed_small; if (dualsense_dev->newVibrateData) { @@ -1032,13 +946,13 @@ void dualsense_pad_handler::apply_pad_data(const std::shared_ptr& dev void dualsense_pad_handler::SetPadData(const std::string& padId, u32 largeMotor, u32 smallMotor, s32 r, s32 g, s32 b, bool /*battery_led*/, u32 /*battery_led_brightness*/) { - std::shared_ptr device = GetDualSenseDevice(padId); + std::shared_ptr device = get_hid_device(padId); if (device == nullptr || device->hidDevice == nullptr) return; // Set the device's motor speeds to our requested values 0-255 - device->largeVibrate = largeMotor; - device->smallVibrate = smallMotor; + device->large_motor = largeMotor; + device->small_motor = smallMotor; int index = 0; for (uint i = 0; i < MAX_GAMEPADS; i++) @@ -1065,5 +979,5 @@ void dualsense_pad_handler::SetPadData(const std::string& padId, u32 largeMotor, } // Start/Stop the engines :) - send_output_report(device); + send_output_report(device.get()); } diff --git a/rpcs3/Input/dualsense_pad_handler.h b/rpcs3/Input/dualsense_pad_handler.h index e061d409ecbd..028d8fa84aad 100644 --- a/rpcs3/Input/dualsense_pad_handler.h +++ b/rpcs3/Input/dualsense_pad_handler.h @@ -1,12 +1,32 @@ #pragma once -#include "Emu/Io/PadHandler.h" +#include "hid_pad_handler.h" #include "Utilities/CRC.h" -#include "hidapi.h" #include -class dualsense_pad_handler final : public PadHandlerBase +class DualSenseDevice : public HidDevice +{ +public: + enum class DualSenseDataMode + { + Simple, + Enhanced + }; + + bool btCon{false}; + u8 bt_sequence{0}; + bool has_calib_data{false}; + std::array calib_data{}; + DualSenseDataMode dataMode{DualSenseDataMode::Simple}; + std::array padData{}; + bool newVibrateData{true}; + bool init_lightbar{true}; + bool update_lightbar{true}; + bool update_player_leds{true}; +}; + +class dualsense_pad_handler final : public hid_pad_handler { enum DualSenseKeyCodes { @@ -43,102 +63,19 @@ class dualsense_pad_handler final : public PadHandlerBase KeyCodeCount }; - enum DualSenseCalibIndex - { - // gyro - PITCH = 0, - YAW, - ROLL, - - // accel - X, - Y, - Z, - COUNT - }; - - enum class DualSenseDataStatus - { - NewData, - NoNewData, - ReadError, - }; - - enum class DualSenseDataMode - { - Simple, - Enhanced - }; - - struct DualSenseCalibData - { - s16 bias; - s32 sens_numer; - s32 sens_denom; - }; - - struct DualSenseDevice : public PadDevice - { - hid_device* hidDevice{ nullptr }; - std::string path{ "" }; - bool btCon{ false }; - u8 bt_sequence{ 0 }; - bool has_calib_data{false}; - std::array calib_data{}; - DualSenseDataMode dataMode{ DualSenseDataMode::Simple }; - std::array padData{}; - bool newVibrateData{true}; - u8 largeVibrate{0}; - u8 smallVibrate{0}; - bool init_lightbar{true}; - bool update_lightbar{true}; - bool update_player_leds{true}; - }; - - const u16 DUALSENSE_VID = 0x054C; - const u16 DUALSENSE_PID = 0x0CE6; - - std::unordered_map> controllers; - CRCPP::CRC::Table crcTable{CRCPP::CRC::CRC_32()}; - public: dualsense_pad_handler(); ~dualsense_pad_handler(); - bool Init() override; - - std::vector ListDevices() override; void SetPadData(const std::string& padId, u32 largeMotor, u32 smallMotor, s32 r, s32 g, s32 b, bool battery_led, u32 battery_led_brightness) override; void init_config(pad_config* cfg, const std::string& name) override; private: - bool is_init = false; - DualSenseDataStatus status; - -private: - std::shared_ptr GetDualSenseDevice(const std::string& padId); - - DualSenseDataStatus GetRawData(const std::shared_ptr& dualsenseDevice); - bool get_calibration_data(const std::shared_ptr& dualsense_device); - - inline s16 apply_calibration(s32 rawValue, const DualSenseCalibData& calib_data) - { - const s32 biased = rawValue - calib_data.bias; - const s32 quot = calib_data.sens_numer / calib_data.sens_denom; - const s32 rem = calib_data.sens_numer % calib_data.sens_denom; - const s32 output = (quot * biased) + ((rem * biased) / calib_data.sens_denom); - - if (output > INT16_MAX) - return INT16_MAX; - else if (output < INT16_MIN) - return INT16_MIN; - else - return static_cast(output); - } + DataStatus get_data(DualSenseDevice* dualsenseDevice); + bool get_calibration_data(DualSenseDevice* dualsense_device); - void CheckAddDevice(hid_device* hidDevice, hid_device_info* hidDevInfo); - int send_output_report(const std::shared_ptr& device); - std::shared_ptr get_device(const std::string& device) override; + void check_add_device(hid_device* hidDevice, std::string_view path, std::wstring_view wide_serial); + int send_output_report(DualSenseDevice* device); bool get_is_left_trigger(u64 keyCode) override; bool get_is_right_trigger(u64 keyCode) override; bool get_is_left_stick(u64 keyCode) override; diff --git a/rpcs3/Input/hid_pad_handler.cpp b/rpcs3/Input/hid_pad_handler.cpp index f624a3e413f3..5d6153883e69 100644 --- a/rpcs3/Input/hid_pad_handler.cpp +++ b/rpcs3/Input/hid_pad_handler.cpp @@ -1,5 +1,6 @@ #include "hid_pad_handler.h" #include "ds4_pad_handler.h" +#include "dualsense_pad_handler.h" #include "util/logs.hpp" #include @@ -198,3 +199,4 @@ std::shared_ptr hid_pad_handler::get_device(const std::string } template class hid_pad_handler; +template class hid_pad_handler; diff --git a/rpcs3/Input/hid_pad_handler.h b/rpcs3/Input/hid_pad_handler.h index 6af2535c38ad..f81b2e2f57cf 100644 --- a/rpcs3/Input/hid_pad_handler.h +++ b/rpcs3/Input/hid_pad_handler.h @@ -31,8 +31,8 @@ class HidDevice : public PadDevice public: hid_device* hidDevice{nullptr}; std::string path{""}; - u8 largeVibrate{0}; - u8 smallVibrate{0}; + u8 large_motor{0}; + u8 small_motor{0}; u8 led_delay_on{0}; u8 led_delay_off{0}; }; @@ -72,6 +72,8 @@ class hid_pad_handler : public PadHandlerBase std::shared_ptr get_hid_device(const std::string& padId); virtual void check_add_device(hid_device* hidDevice, std::string_view path, std::wstring_view serial) = 0; + virtual int send_output_report(Device* device) = 0; + virtual DataStatus get_data(Device* device) = 0; inline s16 apply_calibration(s32 rawValue, const CalibData& calibData) { From b2ef3bedce173340e10757d8ca77033e8b76bb74 Mon Sep 17 00:00:00 2001 From: Megamouse Date: Fri, 12 Feb 2021 01:07:10 +0100 Subject: [PATCH 04/11] DS3: inherit from hid_pad_handler --- rpcs3/Input/ds3_pad_handler.cpp | 298 ++++++++++++-------------------- rpcs3/Input/ds3_pad_handler.h | 57 ++---- rpcs3/Input/hid_pad_handler.cpp | 2 + 3 files changed, 129 insertions(+), 228 deletions(-) diff --git a/rpcs3/Input/ds3_pad_handler.cpp b/rpcs3/Input/ds3_pad_handler.cpp index 8013b6f14b2e..d36af783ff25 100644 --- a/rpcs3/Input/ds3_pad_handler.cpp +++ b/rpcs3/Input/ds3_pad_handler.cpp @@ -4,7 +4,11 @@ LOG_CHANNEL(ds3_log, "DS3"); -ds3_pad_handler::ds3_pad_handler() : PadHandlerBase(pad_handler::ds3) +constexpr u16 DS3_VID = 0x054C; +constexpr u16 DS3_PID = 0x0268; + +ds3_pad_handler::ds3_pad_handler() + : hid_pad_handler(pad_handler::ds3, DS3_VID, {DS3_PID}) { button_list = { @@ -51,125 +55,22 @@ ds3_pad_handler::ds3_pad_handler() : PadHandlerBase(pad_handler::ds3) ds3_pad_handler::~ds3_pad_handler() { - for (auto& controller : controllers) + for (auto& controller : m_controllers) { - if (controller->handle) + if (controller.second && controller.second->hidDevice) { // Disable blinking and vibration - controller->large_motor = 0; - controller->small_motor = 0; - send_output_report(controller); - hid_close(controller->handle); + controller.second->large_motor = 0; + controller.second->small_motor = 0; + send_output_report(controller.second.get()); } } - hid_exit(); -} - -bool ds3_pad_handler::init_usb() -{ - if (hid_init() != 0) - { - ds3_log.fatal("Failed to init hidapi for the DS3 pad handler"); - return false; - } - return true; -} - -bool ds3_pad_handler::Init() -{ - if (is_init) - return true; - - if (!init_usb()) - return false; - - bool warn_about_drivers = false; - - // Uses libusb for windows as hidapi will never work with UsbHid driver for the ds3 and it won't work with WinUsb either(windows hid api needs the UsbHid in the driver stack as far as I can tell) - // For other os use hidapi and hope for the best! - hid_device_info* hid_info = hid_enumerate(DS3_VID, DS3_PID); - hid_device_info* head = hid_info; - while (hid_info) - { - hid_device *handle = hid_open_path(hid_info->path); - -#ifdef _WIN32 - u8 buf[0xFF]; - buf[0] = 0xF2; - bool got_report = false; - if (handle) - { - got_report = hid_get_feature_report(handle, buf, 0xFF) >= 0; - if (!got_report) - { - buf[0] = 0; - got_report = hid_get_feature_report(handle, buf, 0xFF) >= 0; - } - } - if (got_report) -#else - if(handle) -#endif - { - std::shared_ptr ds3dev = std::make_shared(); - ds3dev->device = hid_info->path; - ds3dev->handle = handle; -#ifdef _WIN32 - ds3dev->report_id = buf[0]; -#endif - controllers.emplace_back(ds3dev); - } - else - { - if (handle) - hid_close(handle); - - warn_about_drivers = true; - } - hid_info = hid_info->next; - } - - hid_free_enumeration(head); - - if (warn_about_drivers) - { - ds3_log.error("One or more DS3 pads were detected but couldn't be interacted with directly"); -#if defined(_WIN32) || defined(__linux__) - ds3_log.error("Check https://wiki.rpcs3.net/index.php?title=Help:Controller_Configuration for intructions on how to solve this issue"); -#endif - } - else if (controllers.empty()) - { - ds3_log.warning("No controllers found!"); - } - else - { - ds3_log.success("Controllers found: %d", controllers.size()); - } - - is_init = true; - return true; -} - -std::vector ds3_pad_handler::ListDevices() -{ - std::vector ds3_pads_list; - - if (!Init()) - return ds3_pads_list; - - for (usz i = 1; i <= controllers.size(); ++i) // Controllers 1-n in GUI - { - ds3_pads_list.emplace_back(m_name_string + std::to_string(i)); - } - - return ds3_pads_list; } void ds3_pad_handler::SetPadData(const std::string& padId, u32 largeMotor, u32 smallMotor, s32/* r*/, s32/* g*/, s32 /* b*/, bool /*battery_led*/, u32 /*battery_led_brightness*/) { - std::shared_ptr device = get_ds3_device(padId); - if (device == nullptr || device->handle == nullptr) + std::shared_ptr device = get_hid_device(padId); + if (device == nullptr || device->hidDevice == nullptr) return; // Set the device's motor speeds to our requested values 0-255 @@ -192,13 +93,13 @@ void ds3_pad_handler::SetPadData(const std::string& padId, u32 largeMotor, u32 s } // Start/Stop the engines :) - send_output_report(device); + send_output_report(device.get()); } -void ds3_pad_handler::send_output_report(const std::shared_ptr& ds3dev) +int ds3_pad_handler::send_output_report(ds3_device* ds3dev) { - if (!ds3dev) - return; + if (!ds3dev || !ds3dev->hidDevice) + return -2; #ifdef _WIN32 u8 report_buf[] = { @@ -223,23 +124,7 @@ void ds3_pad_handler::send_output_report(const std::shared_ptr& ds3d report_buf[5] = ds3dev->small_motor; #endif - hid_write(ds3dev->handle, report_buf, sizeof(report_buf)); -} - -std::shared_ptr ds3_pad_handler::get_ds3_device(const std::string& padId) -{ - if (!Init()) - return nullptr; - - const usz pos = padId.find(m_name_string); - if (pos == umax) - return nullptr; - - const int pad_number = std::stoi(padId.substr(pos + 9)); - if (pad_number > 0 && pad_number + 0u <= controllers.size()) - return controllers[static_cast(pad_number) - 1]; - - return nullptr; + return hid_write(ds3dev->hidDevice, report_buf, sizeof(report_buf)); } void ds3_pad_handler::init_config(pad_config* cfg, const std::string& name) @@ -293,18 +178,83 @@ void ds3_pad_handler::init_config(pad_config* cfg, const std::string& name) cfg->from_default(); } -ds3_pad_handler::DS3Status ds3_pad_handler::get_data(const std::shared_ptr& ds3dev) +void ds3_pad_handler::check_add_device(hid_device* hidDevice, std::string_view path, std::wstring_view wide_serial) +{ + if (!hidDevice) + { + return; + } + + ds3_device* device = nullptr; + + for (auto& controller : m_controllers) + { + ensure(controller.second); + + if (!controller.second->hidDevice) + { + device = controller.second.get(); + break; + } + } + + if (!device) + { + return; + } + + std::string serial; + + // Uses libusb for windows as hidapi will never work with UsbHid driver for the ds3 and it won't work with WinUsb either(windows hid api needs the UsbHid in the driver stack as far as I can tell) + // For other os use hidapi and hope for the best! +#ifdef _WIN32 + u8 buf[0xFF]; + buf[0] = 0xF2; + + bool got_report = hid_get_feature_report(hidDevice, buf, 0xFF) >= 0; + if (!got_report) + { + buf[0] = 0; + got_report = hid_get_feature_report(hidDevice, buf, 0xFF) >= 0; + } + if (!got_report) + { + hid_close(hidDevice); + return; + } +#endif + + { + for (wchar_t ch : wide_serial) + serial += static_cast(ch); + } + + if (hid_set_nonblocking(hidDevice, 1) == -1) + { + ds3_log.error("check_add_device: hid_set_nonblocking failed! Reason: %s", hid_error(hidDevice)); + hid_close(hidDevice); + return; + } + + device->report_id = buf[0]; + device->path = path; + device->hidDevice = hidDevice; + + send_output_report(device); +} + +ds3_pad_handler::DataStatus ds3_pad_handler::get_data(ds3_device* ds3dev) { if (!ds3dev) - return DS3Status::Disconnected; + return DataStatus::ReadError; auto& dbuf = ds3dev->buf; #ifdef _WIN32 dbuf[0] = ds3dev->report_id; - const int result = hid_get_feature_report(ds3dev->handle, dbuf, sizeof(dbuf)); + const int result = hid_get_feature_report(ds3dev->hidDevice, dbuf, sizeof(dbuf)); #else - const int result = hid_read(ds3dev->handle, dbuf, sizeof(dbuf)); + const int result = hid_read(ds3dev->hidDevice, dbuf, sizeof(dbuf)); #endif if (result > 0) @@ -315,27 +265,27 @@ ds3_pad_handler::DS3Status ds3_pad_handler::get_data(const std::shared_ptr ds3_pad_handler::get_button_values(const std::shared_ptr& device) { std::unordered_map key_buf; - auto dev = std::static_pointer_cast(device); + ds3_device* dev = static_cast(device.get()); if (!dev) return key_buf; @@ -400,7 +350,7 @@ pad_preview_values ds3_pad_handler::get_preview_values(const std::unordered_map< void ds3_pad_handler::get_extended_info(const std::shared_ptr& device, const std::shared_ptr& pad) { - auto ds3dev = std::static_pointer_cast(device); + ds3_device* ds3dev = static_cast(device.get()); if (!ds3dev || !pad) return; @@ -438,15 +388,6 @@ void ds3_pad_handler::get_extended_info(const std::shared_ptr& device //pad->m_sensors[3].m_value = polish_value(pad->m_sensors[3].m_value, 1, 1, 512, 512, 0, 1023); } -std::shared_ptr ds3_pad_handler::get_device(const std::string& device) -{ - std::shared_ptr ds3device = get_ds3_device(device); - if (ds3device == nullptr || ds3device->handle == nullptr) - return nullptr; - - return ds3device; -} - bool ds3_pad_handler::get_is_left_trigger(u64 keyCode) { return keyCode == DS3KeyCodes::L2; @@ -487,56 +428,43 @@ bool ds3_pad_handler::get_is_right_stick(u64 keyCode) PadHandlerBase::connection ds3_pad_handler::update_connection(const std::shared_ptr& device) { - auto dev = std::static_pointer_cast(device); - if (!dev) + ds3_device* dev = static_cast(device.get()); + if (!dev || dev->path.empty()) return connection::disconnected; - if (dev->handle == nullptr) + if (dev->hidDevice == nullptr) { - hid_device* devhandle = hid_open_path(dev->device.c_str()); - if (!devhandle) + hid_device* devhandle = hid_open_path(dev->path.c_str()); + if (devhandle) { - return connection::disconnected; + if (hid_set_nonblocking(devhandle, 1) == -1) + { + ds3_log.error("Reconnecting Device %s: hid_set_nonblocking failed with error %s", dev->path, hid_error(devhandle)); + } + dev->hidDevice = devhandle; } - - dev->handle = devhandle; - } - - switch (get_data(dev)) - { - case DS3Status::Disconnected: - { - if (dev->status == DS3Status::Connected) + else { - dev->status = DS3Status::Disconnected; - hid_close(dev->handle); - dev->handle = nullptr; + return connection::disconnected; } - return connection::disconnected; } - case DS3Status::Connected: + + if (get_data(dev) == DataStatus::ReadError) { - if (dev->status == DS3Status::Disconnected) - { - dev->status = DS3Status::Connected; - } + // this also can mean disconnected, either way deal with it on next loop and reconnect + hid_close(dev->hidDevice); + dev->hidDevice = nullptr; + return connection::no_data; } - case DS3Status::NewData: - { - return connection::connected; - } - default: - break; - } - return connection::disconnected; + return connection::connected; } void ds3_pad_handler::apply_pad_data(const std::shared_ptr& device, const std::shared_ptr& pad) { - auto dev = std::static_pointer_cast(device); - if (!dev || !pad) + ds3_device* dev = static_cast(device.get()); + if (!dev || !dev->hidDevice || !pad) return; if (dev->large_motor != pad->m_vibrateMotors[0].m_value || dev->small_motor != pad->m_vibrateMotors[1].m_value) diff --git a/rpcs3/Input/ds3_pad_handler.h b/rpcs3/Input/ds3_pad_handler.h index a727fe661c14..2430516e54b5 100644 --- a/rpcs3/Input/ds3_pad_handler.h +++ b/rpcs3/Input/ds3_pad_handler.h @@ -1,12 +1,19 @@ #pragma once -#include "Emu/Io/PadHandler.h" - -#include "hidapi.h" +#include "hid_pad_handler.h" #include -class ds3_pad_handler final : public PadHandlerBase +class ds3_device : public HidDevice +{ +public: + u8 buf[64]{0}; +#ifdef _WIN32 + u8 report_id = 0; +#endif +}; + +class ds3_pad_handler final : public hid_pad_handler { enum DS3KeyCodes { @@ -64,60 +71,24 @@ class ds3_pad_handler final : public PadHandlerBase DS3_ENDPOINT_IN = 0x81 }; - enum DS3Status : u8 - { - Disconnected, - Connected, - NewData - }; - - struct ds3_device : public PadDevice - { - std::string device = {}; - hid_device *handle = nullptr; - u8 buf[64]{ 0 }; - u8 large_motor = 0; - u8 small_motor = 0; - u8 status = DS3Status::Disconnected; -#ifdef _WIN32 - u8 report_id = 0; -#endif - }; - - const u16 DS3_VID = 0x054C; - const u16 DS3_PID = 0x0268; - #ifdef _WIN32 const u8 DS3_HID_OFFSET = 0x01; #else const u8 DS3_HID_OFFSET = 0x00; #endif - // pseudo 'controller id' to keep track of unique controllers - std::vector> controllers; - public: ds3_pad_handler(); ~ds3_pad_handler(); - bool Init() override; - - std::vector ListDevices() override; void SetPadData(const std::string& padId, u32 largeMotor, u32 smallMotor, s32 r, s32 g, s32 b, bool battery_led, u32 battery_led_brightness) override; void init_config(pad_config* cfg, const std::string& name) override; private: - std::shared_ptr get_ds3_device(const std::string& padId); - ds3_pad_handler::DS3Status get_data(const std::shared_ptr& ds3dev); - void send_output_report(const std::shared_ptr& ds3dev); - -private: - bool init_usb(); - -private: - bool is_init = false; + ds3_pad_handler::DataStatus get_data(ds3_device* ds3dev); + int send_output_report(ds3_device* ds3dev); + void check_add_device(hid_device* hidDevice, std::string_view path, std::wstring_view serial); - std::shared_ptr get_device(const std::string& device) override; bool get_is_left_trigger(u64 keyCode) override; bool get_is_right_trigger(u64 keyCode) override; bool get_is_left_stick(u64 keyCode) override; diff --git a/rpcs3/Input/hid_pad_handler.cpp b/rpcs3/Input/hid_pad_handler.cpp index 5d6153883e69..3b32d4677f78 100644 --- a/rpcs3/Input/hid_pad_handler.cpp +++ b/rpcs3/Input/hid_pad_handler.cpp @@ -1,4 +1,5 @@ #include "hid_pad_handler.h" +#include "ds3_pad_handler.h" #include "ds4_pad_handler.h" #include "dualsense_pad_handler.h" #include "util/logs.hpp" @@ -198,5 +199,6 @@ std::shared_ptr hid_pad_handler::get_device(const std::string return get_hid_device(device); } +template class hid_pad_handler; template class hid_pad_handler; template class hid_pad_handler; From e35acca63ea5739a89794ddf6349d219be092e90 Mon Sep 17 00:00:00 2001 From: Megamouse Date: Fri, 12 Feb 2021 01:44:39 +0100 Subject: [PATCH 05/11] Input: unify some more code --- rpcs3/Input/ds3_pad_handler.cpp | 50 +++++++++++++++++---------- rpcs3/Input/ds3_pad_handler.h | 1 - rpcs3/Input/ds4_pad_handler.cpp | 23 ++++++------ rpcs3/Input/ds4_pad_handler.h | 3 -- rpcs3/Input/dualsense_pad_handler.cpp | 10 +++--- rpcs3/Input/dualsense_pad_handler.h | 2 -- rpcs3/Input/hid_pad_handler.h | 2 ++ 7 files changed, 51 insertions(+), 40 deletions(-) diff --git a/rpcs3/Input/ds3_pad_handler.cpp b/rpcs3/Input/ds3_pad_handler.cpp index d36af783ff25..cdd1fc3fd764 100644 --- a/rpcs3/Input/ds3_pad_handler.cpp +++ b/rpcs3/Input/ds3_pad_handler.cpp @@ -248,28 +248,28 @@ ds3_pad_handler::DataStatus ds3_pad_handler::get_data(ds3_device* ds3dev) if (!ds3dev) return DataStatus::ReadError; - auto& dbuf = ds3dev->buf; + ds3dev->padData = {}; #ifdef _WIN32 - dbuf[0] = ds3dev->report_id; - const int result = hid_get_feature_report(ds3dev->hidDevice, dbuf, sizeof(dbuf)); + ds3dev->padData[0] = ds3dev->report_id; + const int result = hid_get_feature_report(ds3dev->hidDevice, ds3dev->padData.data(), 64); #else - const int result = hid_read(ds3dev->hidDevice, dbuf, sizeof(dbuf)); + const int result = hid_read(ds3dev->hidDevice, ds3dev->padData.data(), 64); #endif if (result > 0) { #ifdef _WIN32 - if (dbuf[0] == ds3dev->report_id) + if (ds3dev->padData[0] == ds3dev->report_id) #else - if (dbuf[0] == 0x01 && dbuf[1] != 0xFF) + if (ds3dev->padData[0] == 0x01 && ds3dev->padData[1] != 0xFF) #endif { return DataStatus::NewData; } else { - ds3_log.warning("Unknown packet received:0x%02x", dbuf[0]); + ds3_log.warning("Unknown packet received:0x%02x", ds3dev->padData[0]); return DataStatus::NoNewData; } } @@ -289,7 +289,7 @@ std::unordered_map ds3_pad_handler::get_button_values(const std::share if (!dev) return key_buf; - auto& dbuf = dev->buf; + auto& dbuf = dev->padData; const u8 lsx = dbuf[6 + DS3_HID_OFFSET]; const u8 lsy = dbuf[7 + DS3_HID_OFFSET]; @@ -358,14 +358,14 @@ void ds3_pad_handler::get_extended_info(const std::shared_ptr& device #ifdef _WIN32 // Official Sony Windows DS3 driver seems to do the same modification of this value as the ps3 - pad->m_sensors[0].m_value = *reinterpret_cast*>(&ds3dev->buf[41 + DS3_HID_OFFSET]); + pad->m_sensors[0].m_value = *reinterpret_cast*>(&ds3dev->padData[41 + DS3_HID_OFFSET]); #else // When getting raw values from the device this adjustement is needed - pad->m_sensors[0].m_value = 512 - (*reinterpret_cast*>(&ds3dev->buf[41]) - 512); + pad->m_sensors[0].m_value = 512 - (*reinterpret_cast*>(&ds3dev->padData[41]) - 512); #endif - pad->m_sensors[1].m_value = *reinterpret_cast*>(&ds3dev->buf[45 + DS3_HID_OFFSET]); - pad->m_sensors[2].m_value = *reinterpret_cast*>(&ds3dev->buf[43 + DS3_HID_OFFSET]); - pad->m_sensors[3].m_value = *reinterpret_cast*>(&ds3dev->buf[47 + DS3_HID_OFFSET]); + pad->m_sensors[1].m_value = *reinterpret_cast*>(&ds3dev->padData[45 + DS3_HID_OFFSET]); + pad->m_sensors[2].m_value = *reinterpret_cast*>(&ds3dev->padData[43 + DS3_HID_OFFSET]); + pad->m_sensors[3].m_value = *reinterpret_cast*>(&ds3dev->padData[47 + DS3_HID_OFFSET]); // Those are formulas used to adjust sensor values in sys_hid code but I couldn't find all the vars. //auto polish_value = [](s32 value, s32 dword_0x0, s32 dword_0x4, s32 dword_0x8, s32 dword_0xC, s32 dword_0x18, s32 dword_0x1C) -> u16 @@ -464,13 +464,27 @@ PadHandlerBase::connection ds3_pad_handler::update_connection(const std::shared_ void ds3_pad_handler::apply_pad_data(const std::shared_ptr& device, const std::shared_ptr& pad) { ds3_device* dev = static_cast(device.get()); - if (!dev || !dev->hidDevice || !pad) + if (!dev || !dev->hidDevice || !dev->config || !pad) return; - if (dev->large_motor != pad->m_vibrateMotors[0].m_value || dev->small_motor != pad->m_vibrateMotors[1].m_value) + pad_config* config = dev->config; + + const int idx_l = config->switch_vibration_motors ? 1 : 0; + const int idx_s = config->switch_vibration_motors ? 0 : 1; + + const int speed_large = config->enable_vibration_motor_large ? pad->m_vibrateMotors[idx_l].m_value : vibration_min; + const int speed_small = config->enable_vibration_motor_small ? pad->m_vibrateMotors[idx_s].m_value : vibration_min; + + dev->new_output_data |= dev->large_motor != speed_large || dev->small_motor != speed_small; + + dev->large_motor = speed_large; + dev->small_motor = speed_small; + + if (dev->new_output_data) { - dev->large_motor = static_cast(pad->m_vibrateMotors[0].m_value); - dev->small_motor = static_cast(pad->m_vibrateMotors[1].m_value); - send_output_report(dev); + if (send_output_report(dev) >= 0) + { + dev->new_output_data = false; + } } } diff --git a/rpcs3/Input/ds3_pad_handler.h b/rpcs3/Input/ds3_pad_handler.h index 2430516e54b5..604f154df39c 100644 --- a/rpcs3/Input/ds3_pad_handler.h +++ b/rpcs3/Input/ds3_pad_handler.h @@ -7,7 +7,6 @@ class ds3_device : public HidDevice { public: - u8 buf[64]{0}; #ifdef _WIN32 u8 report_id = 0; #endif diff --git a/rpcs3/Input/ds4_pad_handler.cpp b/rpcs3/Input/ds4_pad_handler.cpp index 021c4546fa4c..9d82f2a37a39 100644 --- a/rpcs3/Input/ds4_pad_handler.cpp +++ b/rpcs3/Input/ds4_pad_handler.cpp @@ -706,7 +706,6 @@ ds4_pad_handler::DataStatus ds4_pad_handler::get_data(DS4Device* device) return DataStatus::NoNewData; const int battery_offset = offset + DS4_INPUT_REPORT_BATTERY_OFFSET; - device->is_initialized = true; device->cableState = (buf[battery_offset] >> 4) & 0x01; device->batteryLevel = buf[battery_offset] & 0x0F; @@ -858,10 +857,10 @@ void ds4_pad_handler::get_extended_info(const std::shared_ptr& device void ds4_pad_handler::apply_pad_data(const std::shared_ptr& device, const std::shared_ptr& pad) { DS4Device* ds4_dev = static_cast(device.get()); - if (!ds4_dev || !ds4_dev->hidDevice || !pad) + if (!ds4_dev || !ds4_dev->hidDevice || !ds4_dev->config || !pad) return; - auto config = ds4_dev->config; + pad_config* config = ds4_dev->config; // Attempt to send rumble no matter what const int idx_l = config->switch_vibration_motors ? 1 : 0; @@ -874,8 +873,6 @@ void ds4_pad_handler::apply_pad_data(const std::shared_ptr& device, c const bool lowBattery = ds4_dev->batteryLevel < 2; const bool isBlinking = ds4_dev->led_delay_on > 0 || ds4_dev->led_delay_off > 0; - bool newBlinkData = false; - // Blink LED when battery is low if (config->led_low_battery_blink) { @@ -884,14 +881,14 @@ void ds4_pad_handler::apply_pad_data(const std::shared_ptr& device, c { ds4_dev->led_delay_on = 0; ds4_dev->led_delay_off = 0; - newBlinkData = true; + ds4_dev->new_output_data = true; } // we are now wireless and low on battery -> blink - if (!isBlinking && wireless && lowBattery) + else if (!isBlinking && wireless && lowBattery) { ds4_dev->led_delay_on = 100; ds4_dev->led_delay_off = 100; - newBlinkData = true; + ds4_dev->new_output_data = true; } } @@ -905,16 +902,20 @@ void ds4_pad_handler::apply_pad_data(const std::shared_ptr& device, c config->colorR.set(combined_color >> 8); config->colorG.set(combined_color & 0xff); config->colorB.set(0); + ds4_dev->new_output_data = true; } } - ds4_dev->newVibrateData |= ds4_dev->large_motor != speed_large || ds4_dev->small_motor != speed_small || newBlinkData; + ds4_dev->new_output_data |= ds4_dev->large_motor != speed_large || ds4_dev->small_motor != speed_small; ds4_dev->large_motor = speed_large; ds4_dev->small_motor = speed_small; - if (ds4_dev->newVibrateData && send_output_report(ds4_dev) >= 0) + if (ds4_dev->new_output_data) { - ds4_dev->newVibrateData = false; + if (send_output_report(ds4_dev) >= 0) + { + ds4_dev->new_output_data = false; + } } } diff --git a/rpcs3/Input/ds4_pad_handler.h b/rpcs3/Input/ds4_pad_handler.h index 2bf651fd53f0..7cde470cb31c 100644 --- a/rpcs3/Input/ds4_pad_handler.h +++ b/rpcs3/Input/ds4_pad_handler.h @@ -11,12 +11,9 @@ class DS4Device : public HidDevice bool btCon{false}; bool hasCalibData{false}; std::array calibData{}; - bool newVibrateData{true}; - std::array padData{}; u8 batteryLevel{0}; u8 last_battery_level{0}; u8 cableState{0}; - bool is_initialized{false}; }; class ds4_pad_handler final : public hid_pad_handler diff --git a/rpcs3/Input/dualsense_pad_handler.cpp b/rpcs3/Input/dualsense_pad_handler.cpp index d57c661ae71d..ad6053048a61 100644 --- a/rpcs3/Input/dualsense_pad_handler.cpp +++ b/rpcs3/Input/dualsense_pad_handler.cpp @@ -918,10 +918,10 @@ int dualsense_pad_handler::send_output_report(DualSenseDevice* device) void dualsense_pad_handler::apply_pad_data(const std::shared_ptr& device, const std::shared_ptr& pad) { DualSenseDevice* dualsense_dev = static_cast(device.get()); - if (!dualsense_dev || !dualsense_dev->hidDevice || !pad) + if (!dualsense_dev || !dualsense_dev->hidDevice || !dualsense_dev->config || !pad) return; - auto config = dualsense_dev->config; + pad_config* config = dualsense_dev->config; // Attempt to send rumble no matter what const int idx_l = config->switch_vibration_motors ? 1 : 0; @@ -930,16 +930,16 @@ void dualsense_pad_handler::apply_pad_data(const std::shared_ptr& dev const int speed_large = config->enable_vibration_motor_large ? pad->m_vibrateMotors[idx_l].m_value : vibration_min; const int speed_small = config->enable_vibration_motor_small ? pad->m_vibrateMotors[idx_s].m_value : vibration_min; - dualsense_dev->newVibrateData |= dualsense_dev->large_motor != speed_large || dualsense_dev->small_motor != speed_small; + dualsense_dev->new_output_data |= dualsense_dev->large_motor != speed_large || dualsense_dev->small_motor != speed_small; dualsense_dev->large_motor = speed_large; dualsense_dev->small_motor = speed_small; - if (dualsense_dev->newVibrateData) + if (dualsense_dev->new_output_data) { if (send_output_report(dualsense_dev) >= 0) { - dualsense_dev->newVibrateData = false; + dualsense_dev->new_output_data = false; } } } diff --git a/rpcs3/Input/dualsense_pad_handler.h b/rpcs3/Input/dualsense_pad_handler.h index 028d8fa84aad..549e4cab9ec1 100644 --- a/rpcs3/Input/dualsense_pad_handler.h +++ b/rpcs3/Input/dualsense_pad_handler.h @@ -19,8 +19,6 @@ class DualSenseDevice : public HidDevice bool has_calib_data{false}; std::array calib_data{}; DualSenseDataMode dataMode{DualSenseDataMode::Simple}; - std::array padData{}; - bool newVibrateData{true}; bool init_lightbar{true}; bool update_lightbar{true}; bool update_player_leds{true}; diff --git a/rpcs3/Input/hid_pad_handler.h b/rpcs3/Input/hid_pad_handler.h index f81b2e2f57cf..71b13351115d 100644 --- a/rpcs3/Input/hid_pad_handler.h +++ b/rpcs3/Input/hid_pad_handler.h @@ -31,6 +31,8 @@ class HidDevice : public PadDevice public: hid_device* hidDevice{nullptr}; std::string path{""}; + std::array padData{}; + bool new_output_data{true}; u8 large_motor{0}; u8 small_motor{0}; u8 led_delay_on{0}; From 5bfc124c8befa11dead2ceff1072218e13d9963a Mon Sep 17 00:00:00 2001 From: Megamouse Date: Fri, 12 Feb 2021 01:55:32 +0100 Subject: [PATCH 06/11] Input: replace a bunch of static_pointer_cast --- rpcs3/Input/evdev_joystick_handler.cpp | 12 ++++++------ rpcs3/Input/evdev_joystick_handler.h | 2 +- rpcs3/Input/hid_pad_handler.h | 9 +++------ rpcs3/Input/mm_joystick_handler.cpp | 8 ++++---- rpcs3/Input/xinput_pad_handler.cpp | 8 ++++---- 5 files changed, 18 insertions(+), 21 deletions(-) diff --git a/rpcs3/Input/evdev_joystick_handler.cpp b/rpcs3/Input/evdev_joystick_handler.cpp index 84296bb75323..fecd0672384c 100644 --- a/rpcs3/Input/evdev_joystick_handler.cpp +++ b/rpcs3/Input/evdev_joystick_handler.cpp @@ -136,7 +136,7 @@ std::string evdev_joystick_handler::get_device_name(const libevdev* dev) bool evdev_joystick_handler::update_device(const std::shared_ptr& device) { - auto evdev_device = std::static_pointer_cast(device); + EvdevDevice* evdev_device = static_cast(device.get()); if (!evdev_device) return false; @@ -193,7 +193,7 @@ void evdev_joystick_handler::Close() { for (auto& binding : bindings) { - auto evdev_device = std::static_pointer_cast(binding.first); + EvdevDevice* evdev_device = static_cast(binding.first.get()); if (evdev_device) { auto& dev = evdev_device->device; @@ -424,7 +424,7 @@ void evdev_joystick_handler::get_next_button_press(const std::string& padId, con // https://github.com/dolphin-emu/dolphin/blob/master/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp // https://github.com/reicast/reicast-emulator/blob/master/core/linux-dist/evdev.cpp // http://www.infradead.org/~mchehab/kernel_docs_pdf/linux-input.pdf -void evdev_joystick_handler::SetRumble(std::shared_ptr device, u16 large, u16 small) +void evdev_joystick_handler::SetRumble(EvdevDevice* device, u16 large, u16 small) { if (!device || !device->has_rumble || device->effect_id == -2) return; @@ -658,7 +658,7 @@ int evdev_joystick_handler::add_device(const std::string& device, const std::sha // It's a joystick. Now let's make sure we don't already have this one. if (std::any_of(bindings.begin(), bindings.end(), [&path](std::pair, std::shared_ptr> binding) { - const auto device = std::static_pointer_cast(binding.first); + EvdevDevice* device = static_cast(binding.first.get()); return device && path == device->path; })) { @@ -703,7 +703,7 @@ PadHandlerBase::connection evdev_joystick_handler::update_connection(const std:: if (!update_device(device)) return connection::disconnected; - auto evdev_device = std::static_pointer_cast(device); + EvdevDevice* evdev_device = static_cast(device.get()); if (!evdev_device || !evdev_device->device) return connection::disconnected; @@ -859,7 +859,7 @@ void evdev_joystick_handler::get_mapping(const std::shared_ptr& devic void evdev_joystick_handler::apply_pad_data(const std::shared_ptr& device, const std::shared_ptr& pad) { - auto evdev_device = std::static_pointer_cast(device); + EvdevDevice* evdev_device = static_cast(device.get()); if (!evdev_device) return; diff --git a/rpcs3/Input/evdev_joystick_handler.h b/rpcs3/Input/evdev_joystick_handler.h index 5e4aa77da6f1..0e92177239a8 100644 --- a/rpcs3/Input/evdev_joystick_handler.h +++ b/rpcs3/Input/evdev_joystick_handler.h @@ -374,7 +374,7 @@ class evdev_joystick_handler final : public PadHandlerBase int add_device(const std::string& device, const std::shared_ptr& pad, bool in_settings = false); int GetButtonInfo(const input_event& evt, const std::shared_ptr& device, int& button_code); std::unordered_map> GetButtonValues(const std::shared_ptr& device); - void SetRumble(std::shared_ptr device, u16 large, u16 small); + void SetRumble(EvdevDevice* device, u16 large, u16 small); // Search axis_orientations map for the direction by index, returns -1 if not found, 0 for positive and 1 for negative int FindAxisDirection(const std::unordered_map& map, int index); diff --git a/rpcs3/Input/hid_pad_handler.h b/rpcs3/Input/hid_pad_handler.h index 71b13351115d..2e849f3fa556 100644 --- a/rpcs3/Input/hid_pad_handler.h +++ b/rpcs3/Input/hid_pad_handler.h @@ -5,6 +5,8 @@ #include "hidapi.h" +#include + struct CalibData { s16 bias; @@ -84,12 +86,7 @@ class hid_pad_handler : public PadHandlerBase const s32 rem = calibData.sens_numer % calibData.sens_denom; const s32 output = (quot * biased) + ((rem * biased) / calibData.sens_denom); - if (output > INT16_MAX) - return INT16_MAX; - else if (output < INT16_MIN) - return INT16_MIN; - else - return static_cast(output); + return static_cast(std::clamp(output, INT16_MIN, INT16_MAX)); } inline s16 read_s16(const void* buf) diff --git a/rpcs3/Input/mm_joystick_handler.cpp b/rpcs3/Input/mm_joystick_handler.cpp index c10a3f2ab58d..d35208829ba9 100644 --- a/rpcs3/Input/mm_joystick_handler.cpp +++ b/rpcs3/Input/mm_joystick_handler.cpp @@ -125,7 +125,7 @@ std::array mm_joystick_handler::get_m { std::array mapping{ 0 }; - auto joy_device = std::static_pointer_cast(device); + MMJOYDevice* joy_device = static_cast(device.get()); if (!joy_device) return mapping; @@ -429,7 +429,7 @@ std::unordered_map mm_joystick_handler::GetButtonValues(const JOYINFOE std::unordered_map mm_joystick_handler::get_button_values(const std::shared_ptr& device) { - auto dev = std::static_pointer_cast(device); + MMJOYDevice* dev = static_cast(device.get()); if (!dev) return std::unordered_map(); return GetButtonValues(dev->device_info, dev->device_caps); @@ -508,14 +508,14 @@ bool mm_joystick_handler::get_is_right_stick(u64 keyCode) PadHandlerBase::connection mm_joystick_handler::update_connection(const std::shared_ptr& device) { - auto dev = std::static_pointer_cast(device); + MMJOYDevice* dev = static_cast(device.get()); if (!dev) return connection::disconnected; const auto old_status = dev->device_status; dev->device_status = joyGetPosEx(dev->device_id, &dev->device_info); - if (dev->device_status == JOYERR_NOERROR && (old_status == JOYERR_NOERROR || GetMMJOYDevice(dev->device_id, dev.get()))) + if (dev->device_status == JOYERR_NOERROR && (old_status == JOYERR_NOERROR || GetMMJOYDevice(dev->device_id, dev))) { return connection::connected; } diff --git a/rpcs3/Input/xinput_pad_handler.cpp b/rpcs3/Input/xinput_pad_handler.cpp index 2729316935a9..bec0aa5ca962 100644 --- a/rpcs3/Input/xinput_pad_handler.cpp +++ b/rpcs3/Input/xinput_pad_handler.cpp @@ -162,7 +162,7 @@ int xinput_pad_handler::GetDeviceNumber(const std::string& padId) std::unordered_map xinput_pad_handler::get_button_values(const std::shared_ptr& device) { PadButtonValues values; - auto dev = std::static_pointer_cast(device); + XInputDevice* dev = static_cast(device.get()); if (!dev || dev->state != ERROR_SUCCESS) // the state has to be aquired with update_connection before calling this function return values; @@ -426,7 +426,7 @@ bool xinput_pad_handler::get_is_right_stick(u64 keyCode) PadHandlerBase::connection xinput_pad_handler::update_connection(const std::shared_ptr& device) { - auto dev = std::static_pointer_cast(device); + XInputDevice* dev = static_cast(device.get()); if (!dev) return connection::disconnected; @@ -451,7 +451,7 @@ PadHandlerBase::connection xinput_pad_handler::update_connection(const std::shar void xinput_pad_handler::get_extended_info(const std::shared_ptr& device, const std::shared_ptr& pad) { - auto dev = std::static_pointer_cast(device); + XInputDevice* dev = static_cast(device.get()); if (!dev || !pad) return; @@ -478,7 +478,7 @@ void xinput_pad_handler::get_extended_info(const std::shared_ptr& dev void xinput_pad_handler::apply_pad_data(const std::shared_ptr& device, const std::shared_ptr& pad) { - auto dev = std::static_pointer_cast(device); + XInputDevice* dev = static_cast(device.get()); if (!dev || !pad) return; From 5eadae5023125ca927440df0927814cac64bf1da Mon Sep 17 00:00:00 2001 From: Megamouse Date: Fri, 12 Feb 2021 02:31:49 +0100 Subject: [PATCH 07/11] cellPad: minor optimization --- rpcs3/Emu/Cell/Modules/cellPad.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rpcs3/Emu/Cell/Modules/cellPad.cpp b/rpcs3/Emu/Cell/Modules/cellPad.cpp index d3692a64275e..303435f12d99 100644 --- a/rpcs3/Emu/Cell/Modules/cellPad.cpp +++ b/rpcs3/Emu/Cell/Modules/cellPad.cpp @@ -85,7 +85,7 @@ error_code cellPadEnd() return CELL_OK; } -void clear_pad_buffer(const std::shared_ptr pad) +void clear_pad_buffer(const std::shared_ptr& pad) { if (!pad) return; @@ -159,7 +159,6 @@ error_code cellPadGetData(u32 port_no, vm::ptr data) return CELL_PAD_ERROR_NO_DEVICE; const auto pad = pads[port_no]; - const auto setting = config->port_setting[port_no]; if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) return CELL_PAD_ERROR_NO_DEVICE; @@ -172,6 +171,7 @@ error_code cellPadGetData(u32 port_no, vm::ptr data) return CELL_OK; } + const auto setting = config->port_setting[port_no]; bool btnChanged = false; if (rinfo.ignore_input) From e540b9242548a5b005b55e8b12ccf8660a7a7a90 Mon Sep 17 00:00:00 2001 From: Megamouse Date: Fri, 12 Feb 2021 02:44:26 +0100 Subject: [PATCH 08/11] Input: fix build --- rpcs3/Input/ds3_pad_handler.cpp | 2 +- rpcs3/Input/ds3_pad_handler.h | 6 +++--- rpcs3/Input/ds4_pad_handler.h | 8 ++++---- rpcs3/Input/dualsense_pad_handler.h | 7 ++++--- rpcs3/Input/hid_pad_handler.cpp | 12 ++++++------ 5 files changed, 18 insertions(+), 17 deletions(-) diff --git a/rpcs3/Input/ds3_pad_handler.cpp b/rpcs3/Input/ds3_pad_handler.cpp index cdd1fc3fd764..32498364e7f0 100644 --- a/rpcs3/Input/ds3_pad_handler.cpp +++ b/rpcs3/Input/ds3_pad_handler.cpp @@ -222,6 +222,7 @@ void ds3_pad_handler::check_add_device(hid_device* hidDevice, std::string_view p hid_close(hidDevice); return; } + device->report_id = buf[0]; #endif { @@ -236,7 +237,6 @@ void ds3_pad_handler::check_add_device(hid_device* hidDevice, std::string_view p return; } - device->report_id = buf[0]; device->path = path; device->hidDevice = hidDevice; diff --git a/rpcs3/Input/ds3_pad_handler.h b/rpcs3/Input/ds3_pad_handler.h index 604f154df39c..c05f174fa102 100644 --- a/rpcs3/Input/ds3_pad_handler.h +++ b/rpcs3/Input/ds3_pad_handler.h @@ -84,9 +84,9 @@ class ds3_pad_handler final : public hid_pad_handler void init_config(pad_config* cfg, const std::string& name) override; private: - ds3_pad_handler::DataStatus get_data(ds3_device* ds3dev); - int send_output_report(ds3_device* ds3dev); - void check_add_device(hid_device* hidDevice, std::string_view path, std::wstring_view serial); + ds3_pad_handler::DataStatus get_data(ds3_device* ds3dev) override; + int send_output_report(ds3_device* ds3dev) override; + void check_add_device(hid_device* hidDevice, std::string_view path, std::wstring_view serial) override; bool get_is_left_trigger(u64 keyCode) override; bool get_is_right_trigger(u64 keyCode) override; diff --git a/rpcs3/Input/ds4_pad_handler.h b/rpcs3/Input/ds4_pad_handler.h index 7cde470cb31c..ea441fa7beea 100644 --- a/rpcs3/Input/ds4_pad_handler.h +++ b/rpcs3/Input/ds4_pad_handler.h @@ -67,13 +67,13 @@ class ds4_pad_handler final : public hid_pad_handler private: u32 get_battery_color(u8 battery_level, int brightness); - // Copies data into padData if status is NewData, otherwise buffer is untouched - DataStatus get_data(DS4Device* ds4Device); // This function gets us usuable buffer from the rawbuffer of padData bool GetCalibrationData(DS4Device* ds4Device); - int send_output_report(DS4Device* device); - void check_add_device(hid_device* hidDevice, std::string_view path, std::wstring_view serial); + // Copies data into padData if status is NewData, otherwise buffer is untouched + DataStatus get_data(DS4Device* ds4Device) override; + int send_output_report(DS4Device* device) override; + void check_add_device(hid_device* hidDevice, std::string_view path, std::wstring_view serial) override; bool get_is_left_trigger(u64 keyCode) override; bool get_is_right_trigger(u64 keyCode) override; diff --git a/rpcs3/Input/dualsense_pad_handler.h b/rpcs3/Input/dualsense_pad_handler.h index 549e4cab9ec1..e51c87b24de4 100644 --- a/rpcs3/Input/dualsense_pad_handler.h +++ b/rpcs3/Input/dualsense_pad_handler.h @@ -69,11 +69,12 @@ class dualsense_pad_handler final : public hid_pad_handler void init_config(pad_config* cfg, const std::string& name) override; private: - DataStatus get_data(DualSenseDevice* dualsenseDevice); bool get_calibration_data(DualSenseDevice* dualsense_device); - void check_add_device(hid_device* hidDevice, std::string_view path, std::wstring_view wide_serial); - int send_output_report(DualSenseDevice* device); + DataStatus get_data(DualSenseDevice* dualsenseDevice) override; + void check_add_device(hid_device* hidDevice, std::string_view path, std::wstring_view wide_serial) override; + int send_output_report(DualSenseDevice* device) override; + bool get_is_left_trigger(u64 keyCode) override; bool get_is_right_trigger(u64 keyCode) override; bool get_is_left_stick(u64 keyCode) override; diff --git a/rpcs3/Input/hid_pad_handler.cpp b/rpcs3/Input/hid_pad_handler.cpp index 3b32d4677f78..56b00d6ed12b 100644 --- a/rpcs3/Input/hid_pad_handler.cpp +++ b/rpcs3/Input/hid_pad_handler.cpp @@ -28,7 +28,7 @@ hid_pad_handler::~hid_pad_handler() if (hid_exit() != 0) { - hid_log.error("hid_exit failed!"); + hid_log.error("%s hid_exit failed!", m_type); } } @@ -40,7 +40,7 @@ bool hid_pad_handler::Init() const int res = hid_init(); if (res != 0) - fmt::throw_exception("hidapi-init error.threadproc"); + fmt::throw_exception("%s hidapi-init error.threadproc", m_type); for (size_t i = 1; i <= MAX_GAMEPADS; i++) // Controllers 1-n in GUI { @@ -146,7 +146,7 @@ void hid_pad_handler::enumerate_devices() } else { - hid_log.error("hid_open_path failed! Reason: %s", hid_error(dev)); + hid_log.error("%s hid_open_path failed! Reason: %s", m_type, hid_error(dev)); warn_about_drivers = true; } } @@ -154,7 +154,7 @@ void hid_pad_handler::enumerate_devices() if (warn_about_drivers) { - hid_log.error("One or more pads were detected but couldn't be interacted with directly"); + hid_log.error("One or more %s pads were detected but couldn't be interacted with directly", m_type); #if defined(_WIN32) || defined(__linux__) hid_log.error("Check https://wiki.rpcs3.net/index.php?title=Help:Controller_Configuration for intructions on how to solve this issue"); #endif @@ -164,11 +164,11 @@ void hid_pad_handler::enumerate_devices() const size_t count = std::count_if(m_controllers.cbegin(), m_controllers.cend(), [](const auto& c) { return c.second && c.second->hidDevice; }); if (count > 0) { - hid_log.success("Controllers found: %d", count); + hid_log.success("%s Controllers found: %d", m_type, count); } else { - hid_log.warning("No controllers found!"); + hid_log.warning("No %s controllers found!", m_type); } } } From 718c5712870472b20250ab15554d7a37072dd111 Mon Sep 17 00:00:00 2001 From: Megamouse Date: Fri, 12 Feb 2021 22:42:00 +0100 Subject: [PATCH 09/11] only call hid_exit when all hid_handlers are done --- rpcs3/Input/hid_pad_handler.cpp | 49 +++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/rpcs3/Input/hid_pad_handler.cpp b/rpcs3/Input/hid_pad_handler.cpp index 56b00d6ed12b..eff198a94c1f 100644 --- a/rpcs3/Input/hid_pad_handler.cpp +++ b/rpcs3/Input/hid_pad_handler.cpp @@ -9,10 +9,15 @@ LOG_CHANNEL(hid_log, "HID"); +static std::mutex s_hid_mutex; // hid_pad_handler is created by pad_thread and pad_settings_dialog +static u8 s_hid_instances{0}; + template hid_pad_handler::hid_pad_handler(pad_handler type, u16 vid, std::vector pids) : PadHandlerBase(type), m_vid(vid), m_pids(std::move(pids)) { + std::scoped_lock lock(s_hid_mutex); + ensure(s_hid_instances++ < 255); }; template @@ -26,9 +31,16 @@ hid_pad_handler::~hid_pad_handler() } } - if (hid_exit() != 0) + std::scoped_lock lock(s_hid_mutex); + ensure(s_hid_instances-- > 0); + if (s_hid_instances == 0) { - hid_log.error("%s hid_exit failed!", m_type); + // Call hid_exit after all hid_pad_handlers are finished + if (hid_exit() != 0) + { + hid_log.error("hid_exit failed!"); + } + hid_log.error("hid_exit !"); } } @@ -127,28 +139,23 @@ void hid_pad_handler::enumerate_devices() // Find and add new devices for (const auto& path : device_paths) { + // Check if we have at least one virtual controller left + if (std::none_of(m_controllers.cbegin(), m_controllers.cend(), [](const auto& c) { return !c.second || !c.second->hidDevice; })) + break; + // Check if we already have this controller - const auto it_found = std::find_if(m_controllers.cbegin(), m_controllers.cend(), [path](const auto& c) { return c.second && c.second->path == path; }); + if (std::any_of(m_controllers.cbegin(), m_controllers.cend(), [&path](const auto& c) { return c.second && c.second->path == path; })) + continue; - if (it_found == m_controllers.cend()) + hid_device* dev = hid_open_path(path.c_str()); + if (dev) + { + check_add_device(dev, path, serials[path]); + } + else { - // Check if we have at least one virtual controller left - const auto it_free = std::find_if(m_controllers.cbegin(), m_controllers.cend(), [](const auto& c) { return !c.second || !c.second->hidDevice; }); - if (it_free == m_controllers.cend()) - { - break; - } - - hid_device* dev = hid_open_path(path.c_str()); - if (dev) - { - check_add_device(dev, path, serials[path]); - } - else - { - hid_log.error("%s hid_open_path failed! Reason: %s", m_type, hid_error(dev)); - warn_about_drivers = true; - } + hid_log.error("%s hid_open_path failed! Reason: %s", m_type, hid_error(dev)); + warn_about_drivers = true; } } From ef207bf5cd4fe7237a69acf2788b13704e85bdca Mon Sep 17 00:00:00 2001 From: Megamouse Date: Sat, 13 Feb 2021 01:25:39 +0100 Subject: [PATCH 10/11] hid: log more info when adding a device And minor format changes --- rpcs3/Input/ds3_pad_handler.cpp | 7 ++ rpcs3/Input/ds4_pad_handler.cpp | 98 ++++++++++++++------------- rpcs3/Input/ds4_pad_handler.h | 10 +-- rpcs3/Input/dualsense_pad_handler.cpp | 43 +++++++++--- rpcs3/Input/dualsense_pad_handler.h | 4 +- rpcs3/Input/hid_pad_handler.cpp | 1 - 6 files changed, 96 insertions(+), 67 deletions(-) diff --git a/rpcs3/Input/ds3_pad_handler.cpp b/rpcs3/Input/ds3_pad_handler.cpp index 32498364e7f0..9235b92d9f5b 100644 --- a/rpcs3/Input/ds3_pad_handler.cpp +++ b/rpcs3/Input/ds3_pad_handler.cpp @@ -219,6 +219,7 @@ void ds3_pad_handler::check_add_device(hid_device* hidDevice, std::string_view p } if (!got_report) { + ds3_log.error("check_add_device: hid_get_feature_report failed! Reason: %s", hid_error(hidDevice)); hid_close(hidDevice); return; } @@ -241,6 +242,12 @@ void ds3_pad_handler::check_add_device(hid_device* hidDevice, std::string_view p device->hidDevice = hidDevice; send_output_report(device); + +#ifdef _WIN32 + ds3_log.notice("Added device: report_id=%d, serial='%s', path='%s'", device->report_id, serial, device->path); +#else + ds3_log.notice("Added device: serial='%s', path='%s'", serial, device->path); +#endif } ds3_pad_handler::DataStatus ds3_pad_handler::get_data(ds3_device* ds3dev) diff --git a/rpcs3/Input/ds4_pad_handler.cpp b/rpcs3/Input/ds4_pad_handler.cpp index 9d82f2a37a39..3ca1ecd03612 100644 --- a/rpcs3/Input/ds4_pad_handler.cpp +++ b/rpcs3/Input/ds4_pad_handler.cpp @@ -190,7 +190,7 @@ u32 ds4_pad_handler::get_battery_level(const std::string& padId) { return 0; } - return std::min(device->batteryLevel * 10, 100); + return std::min(device->battery_level * 10, 100); } void ds4_pad_handler::SetPadData(const std::string& padId, u32 largeMotor, u32 smallMotor, s32 r, s32 g, s32 b, bool battery_led, u32 battery_led_brightness) @@ -221,7 +221,7 @@ void ds4_pad_handler::SetPadData(const std::string& padId, u32 largeMotor, u32 s // Set new LED color if (battery_led) { - const u32 combined_color = get_battery_color(device->batteryLevel, battery_led_brightness); + const u32 combined_color = get_battery_color(device->battery_level, battery_led_brightness); device->config->colorR.set(combined_color >> 8); device->config->colorG.set(combined_color & 0xff); device->config->colorB.set(0); @@ -372,7 +372,7 @@ bool ds4_pad_handler::GetCalibrationData(DS4Device* ds4Dev) } std::array buf; - if (ds4Dev->btCon) + if (ds4Dev->bt_controller) { for (int tries = 0; tries < 3; ++tries) { @@ -411,9 +411,9 @@ bool ds4_pad_handler::GetCalibrationData(DS4Device* ds4Dev) } } - ds4Dev->calibData[CalibIndex::PITCH].bias = read_s16(&buf[1]); - ds4Dev->calibData[CalibIndex::YAW].bias = read_s16(&buf[3]); - ds4Dev->calibData[CalibIndex::ROLL].bias = read_s16(&buf[5]); + ds4Dev->calib_data[CalibIndex::PITCH].bias = read_s16(&buf[1]); + ds4Dev->calib_data[CalibIndex::YAW].bias = read_s16(&buf[3]); + ds4Dev->calib_data[CalibIndex::ROLL].bias = read_s16(&buf[5]); s16 pitchPlus, pitchNeg, rollPlus, rollNeg, yawPlus, yawNeg; @@ -450,14 +450,14 @@ bool ds4_pad_handler::GetCalibrationData(DS4Device* ds4Dev) const s32 gyroSpeedScale = read_s16(&buf[19]) + read_s16(&buf[21]); - ds4Dev->calibData[CalibIndex::PITCH].sens_numer = gyroSpeedScale * DS4_GYRO_RES_PER_DEG_S; - ds4Dev->calibData[CalibIndex::PITCH].sens_denom = pitchPlus - pitchNeg; + ds4Dev->calib_data[CalibIndex::PITCH].sens_numer = gyroSpeedScale * DS4_GYRO_RES_PER_DEG_S; + ds4Dev->calib_data[CalibIndex::PITCH].sens_denom = pitchPlus - pitchNeg; - ds4Dev->calibData[CalibIndex::YAW].sens_numer = gyroSpeedScale * DS4_GYRO_RES_PER_DEG_S; - ds4Dev->calibData[CalibIndex::YAW].sens_denom = yawPlus - yawNeg; + ds4Dev->calib_data[CalibIndex::YAW].sens_numer = gyroSpeedScale * DS4_GYRO_RES_PER_DEG_S; + ds4Dev->calib_data[CalibIndex::YAW].sens_denom = yawPlus - yawNeg; - ds4Dev->calibData[CalibIndex::ROLL].sens_numer = gyroSpeedScale * DS4_GYRO_RES_PER_DEG_S; - ds4Dev->calibData[CalibIndex::ROLL].sens_denom = rollPlus - rollNeg; + ds4Dev->calib_data[CalibIndex::ROLL].sens_numer = gyroSpeedScale * DS4_GYRO_RES_PER_DEG_S; + ds4Dev->calib_data[CalibIndex::ROLL].sens_denom = rollPlus - rollNeg; const s16 accelXPlus = read_s16(&buf[23]); const s16 accelXNeg = read_s16(&buf[25]); @@ -467,27 +467,27 @@ bool ds4_pad_handler::GetCalibrationData(DS4Device* ds4Dev) const s16 accelZNeg = read_s16(&buf[33]); const s32 accelXRange = accelXPlus - accelXNeg; - ds4Dev->calibData[CalibIndex::X].bias = accelXPlus - accelXRange / 2; - ds4Dev->calibData[CalibIndex::X].sens_numer = 2 * DS4_ACC_RES_PER_G; - ds4Dev->calibData[CalibIndex::X].sens_denom = accelXRange; + ds4Dev->calib_data[CalibIndex::X].bias = accelXPlus - accelXRange / 2; + ds4Dev->calib_data[CalibIndex::X].sens_numer = 2 * DS4_ACC_RES_PER_G; + ds4Dev->calib_data[CalibIndex::X].sens_denom = accelXRange; const s32 accelYRange = accelYPlus - accelYNeg; - ds4Dev->calibData[CalibIndex::Y].bias = accelYPlus - accelYRange / 2; - ds4Dev->calibData[CalibIndex::Y].sens_numer = 2 * DS4_ACC_RES_PER_G; - ds4Dev->calibData[CalibIndex::Y].sens_denom = accelYRange; + ds4Dev->calib_data[CalibIndex::Y].bias = accelYPlus - accelYRange / 2; + ds4Dev->calib_data[CalibIndex::Y].sens_numer = 2 * DS4_ACC_RES_PER_G; + ds4Dev->calib_data[CalibIndex::Y].sens_denom = accelYRange; const s32 accelZRange = accelZPlus - accelZNeg; - ds4Dev->calibData[CalibIndex::Z].bias = accelZPlus - accelZRange / 2; - ds4Dev->calibData[CalibIndex::Z].sens_numer = 2 * DS4_ACC_RES_PER_G; - ds4Dev->calibData[CalibIndex::Z].sens_denom = accelZRange; + ds4Dev->calib_data[CalibIndex::Z].bias = accelZPlus - accelZRange / 2; + ds4Dev->calib_data[CalibIndex::Z].sens_numer = 2 * DS4_ACC_RES_PER_G; + ds4Dev->calib_data[CalibIndex::Z].sens_denom = accelZRange; // Make sure data 'looks' valid, dongle will report invalid calibration data with no controller connected - for (const auto& data : ds4Dev->calibData) + for (const auto& data : ds4Dev->calib_data) { if (data.sens_denom == 0) { - ds4_log.error("GetCalibrationData: Failure: sensDenom == 0"); + ds4_log.error("GetCalibrationData: Failure: sens_denom == 0"); return false; } } @@ -546,7 +546,7 @@ void ds4_pad_handler::check_add_device(hid_device* hidDevice, std::string_view p } else { - device->btCon = true; + device->bt_controller = true; for (wchar_t ch : wide_serial) serial += static_cast(ch); } @@ -569,10 +569,12 @@ void ds4_pad_handler::check_add_device(hid_device* hidDevice, std::string_view p return; } - device->hasCalibData = true; - device->path = path; + device->has_calib_data = true; + device->path = path; send_output_report(device); + + ds4_log.notice("Added device: bluetooth=%d, serial='%s', path='%s'", device->bt_controller, serial, device->path); } ds4_pad_handler::~ds4_pad_handler() @@ -602,7 +604,7 @@ int ds4_pad_handler::send_output_report(DS4Device* device) std::array outputBuf{0}; // write rumble state - if (device->btCon) + if (device->bt_controller) { outputBuf[0] = 0x11; outputBuf[1] = 0xC4; @@ -653,7 +655,7 @@ ds4_pad_handler::DataStatus ds4_pad_handler::get_data(DS4Device* device) std::array buf{}; - const int res = hid_read(device->hidDevice, buf.data(), device->btCon ? 78 : 64); + const int res = hid_read(device->hidDevice, buf.data(), device->bt_controller ? 78 : 64); if (res == -1) { // looks like controller disconnected or read error @@ -665,7 +667,7 @@ ds4_pad_handler::DataStatus ds4_pad_handler::get_data(DS4Device* device) return DataStatus::NoNewData; // bt controller sends this until 0x02 feature report is sent back (happens on controller init/restart) - if (device->btCon && buf[0] == 0x1) + if (device->bt_controller && buf[0] == 0x1) { // tells controller to send 0x11 reports std::array buf_error{}; @@ -679,7 +681,7 @@ ds4_pad_handler::DataStatus ds4_pad_handler::get_data(DS4Device* device) int offset = 0; // check report and set offset - if (device->btCon && buf[0] == 0x11 && res == 78) + if (device->bt_controller && buf[0] == 0x11 && res == 78) { offset = 2; @@ -693,12 +695,12 @@ ds4_pad_handler::DataStatus ds4_pad_handler::get_data(DS4Device* device) return DataStatus::NoNewData; } } - else if (!device->btCon && buf[0] == 0x01 && res == 64) + else if (!device->bt_controller && buf[0] == 0x01 && res == 64) { // Ds4 Dongle uses this bit to actually report whether a controller is connected const bool connected = (buf[31] & 0x04) ? false : true; - if (connected && !device->hasCalibData) - device->hasCalibData = GetCalibrationData(device); + if (connected && !device->has_calib_data) + device->has_calib_data = GetCalibrationData(device); offset = 0; } @@ -706,16 +708,16 @@ ds4_pad_handler::DataStatus ds4_pad_handler::get_data(DS4Device* device) return DataStatus::NoNewData; const int battery_offset = offset + DS4_INPUT_REPORT_BATTERY_OFFSET; - device->cableState = (buf[battery_offset] >> 4) & 0x01; - device->batteryLevel = buf[battery_offset] & 0x0F; + device->cable_state = (buf[battery_offset] >> 4) & 0x01; + device->battery_level = buf[battery_offset] & 0x0F; - if (device->hasCalibData) + if (device->has_calib_data) { int calibOffset = offset + DS4_INPUT_REPORT_GYRO_X_OFFSET; for (int i = 0; i < CalibIndex::COUNT; ++i) { const s16 rawValue = read_s16(&buf[calibOffset]); - const s16 calValue = apply_calibration(rawValue, device->calibData[i]); + const s16 calValue = apply_calibration(rawValue, device->calib_data[i]); buf[calibOffset++] = (static_cast(calValue) >> 0) & 0xFF; buf[calibOffset++] = (static_cast(calValue) >> 8) & 0xFF; } @@ -794,8 +796,8 @@ PadHandlerBase::connection ds4_pad_handler::update_connection(const std::shared_ ds4_log.error("Reconnecting Device %s: hid_set_nonblocking failed with error %s", ds4_dev->path, hid_error(dev)); } ds4_dev->hidDevice = dev; - if (!ds4_dev->hasCalibData) - ds4_dev->hasCalibData = GetCalibrationData(ds4_dev); + if (!ds4_dev->has_calib_data) + ds4_dev->has_calib_data = GetCalibrationData(ds4_dev); } else { @@ -824,8 +826,8 @@ void ds4_pad_handler::get_extended_info(const std::shared_ptr& device auto buf = ds4_device->padData; - pad->m_battery_level = ds4_device->batteryLevel; - pad->m_cable_state = ds4_device->cableState; + pad->m_battery_level = ds4_device->battery_level; + pad->m_cable_state = ds4_device->cable_state; // these values come already calibrated, all we need to do is convert to ds3 range @@ -864,14 +866,14 @@ void ds4_pad_handler::apply_pad_data(const std::shared_ptr& device, c // Attempt to send rumble no matter what const int idx_l = config->switch_vibration_motors ? 1 : 0; - const int idx_s = config->switch_vibration_motors ? 0 : 1; + const int idx_s = config->switch_vibration_motors ? 0 : 1; const int speed_large = config->enable_vibration_motor_large ? pad->m_vibrateMotors[idx_l].m_value : vibration_min; - const int speed_small = config->enable_vibration_motor_small ? pad->m_vibrateMotors[idx_s].m_value : vibration_min; + const int speed_small = config->enable_vibration_motor_small ? pad->m_vibrateMotors[idx_s].m_value : vibration_min; - const bool wireless = ds4_dev->cableState < 1; - const bool lowBattery = ds4_dev->batteryLevel < 2; - const bool isBlinking = ds4_dev->led_delay_on > 0 || ds4_dev->led_delay_off > 0; + const bool wireless = ds4_dev->cable_state < 1; + const bool lowBattery = ds4_dev->battery_level < 2; + const bool isBlinking = ds4_dev->led_delay_on > 0 || ds4_dev->led_delay_off > 0; // Blink LED when battery is low if (config->led_low_battery_blink) @@ -896,9 +898,9 @@ void ds4_pad_handler::apply_pad_data(const std::shared_ptr& device, c if (config->led_battery_indicator) { // This makes sure that the LED color doesn't update every 1ms. DS4 only reports battery level in 10% increments - if (ds4_dev->last_battery_level != ds4_dev->batteryLevel) + if (ds4_dev->last_battery_level != ds4_dev->battery_level) { - const u32 combined_color = get_battery_color(ds4_dev->batteryLevel, config->led_battery_indicator_brightness); + const u32 combined_color = get_battery_color(ds4_dev->battery_level, config->led_battery_indicator_brightness); config->colorR.set(combined_color >> 8); config->colorG.set(combined_color & 0xff); config->colorB.set(0); diff --git a/rpcs3/Input/ds4_pad_handler.h b/rpcs3/Input/ds4_pad_handler.h index ea441fa7beea..633a9438a865 100644 --- a/rpcs3/Input/ds4_pad_handler.h +++ b/rpcs3/Input/ds4_pad_handler.h @@ -8,12 +8,12 @@ class DS4Device : public HidDevice { public: - bool btCon{false}; - bool hasCalibData{false}; - std::array calibData{}; - u8 batteryLevel{0}; + bool bt_controller{false}; + bool has_calib_data{false}; + std::array calib_data{}; + u8 battery_level{0}; u8 last_battery_level{0}; - u8 cableState{0}; + u8 cable_state{0}; }; class ds4_pad_handler final : public hid_pad_handler diff --git a/rpcs3/Input/dualsense_pad_handler.cpp b/rpcs3/Input/dualsense_pad_handler.cpp index ad6053048a61..db4dcda401cf 100644 --- a/rpcs3/Input/dualsense_pad_handler.cpp +++ b/rpcs3/Input/dualsense_pad_handler.cpp @@ -4,6 +4,21 @@ LOG_CHANNEL(dualsense_log, "DualSense"); +template <> +void fmt_class_string::format(std::string& out, u64 arg) +{ + format_enum(out, arg, [](auto mode) + { + switch (mode) + { + case DualSenseDevice::DualSenseDataMode::Simple: return "Simple"; + case DualSenseDevice::DualSenseDataMode::Enhanced: return "Enhanced"; + } + + return unknown; + }); +} + namespace { constexpr u32 DUALSENSE_ACC_RES_PER_G = 8192; @@ -167,13 +182,13 @@ void dualsense_pad_handler::check_add_device(hid_device* hidDevice, std::string_ if (hid_get_feature_report(hidDevice, buf.data(), 64) == 21) { serial = fmt::format("%x%x%x%x%x%x", buf[6], buf[5], buf[4], buf[3], buf[2], buf[1]); - device->dataMode = DualSenseDevice::DualSenseDataMode::Enhanced; + device->data_mode = DualSenseDevice::DualSenseDataMode::Enhanced; } else { // We're probably on Bluetooth in this case, but for whatever reason the feature report failed. // This will give us a less capable fallback. - device->dataMode = DualSenseDevice::DualSenseDataMode::Simple; + device->data_mode = DualSenseDevice::DualSenseDataMode::Simple; for (wchar_t ch : wide_serial) serial += static_cast(ch); } @@ -199,7 +214,13 @@ void dualsense_pad_handler::check_add_device(hid_device* hidDevice, std::string_ device->has_calib_data = true; device->path = path; + // Activate send_output_report(device); + + // Get bluetooth information + get_data(device); + + dualsense_log.notice("Added device: bluetooth=%d, data_mode=%s, serial='%s', path='%s'", device->bt_controller, device->data_mode, serial, device->path); } void dualsense_pad_handler::init_config(pad_config* cfg, const std::string& name) @@ -283,22 +304,22 @@ dualsense_pad_handler::DataStatus dualsense_pad_handler::get_data(DualSenseDevic { if (res == DUALSENSE_BLUETOOTH_REPORT_SIZE) { - device->dataMode = DualSenseDevice::DualSenseDataMode::Simple; - device->btCon = true; + device->data_mode = DualSenseDevice::DualSenseDataMode::Simple; + device->bt_controller = true; offset = 1; } else { - device->dataMode = DualSenseDevice::DualSenseDataMode::Enhanced; - device->btCon = false; + device->data_mode = DualSenseDevice::DualSenseDataMode::Enhanced; + device->bt_controller = false; offset = 1; } break; } case 0x31: { - device->dataMode = DualSenseDevice::DualSenseDataMode::Enhanced; - device->btCon = true; + device->data_mode = DualSenseDevice::DualSenseDataMode::Enhanced; + device->bt_controller = true; offset = 2; const u8 btHdr = 0xA1; @@ -341,7 +362,7 @@ bool dualsense_pad_handler::get_calibration_data(DualSenseDevice* dualsense_devi } std::array buf; - if (dualsense_device->btCon) + if (dualsense_device->bt_controller) { for (int tries = 0; tries < 3; ++tries) { @@ -591,7 +612,7 @@ std::unordered_map dualsense_pad_handler::get_button_values(const std: auto buf = dualsense_dev->padData; - if (dualsense_dev->dataMode == DualSenseDevice::DualSenseDataMode::Simple) + if (dualsense_dev->data_mode == DualSenseDevice::DualSenseDataMode::Simple) { // Left Stick X Axis keyBuffer[DualSenseKeyCodes::LSXNeg] = Clamp0To255((127.5f - buf[0]) * 2.0f); @@ -883,7 +904,7 @@ int dualsense_pad_handler::send_output_report(DualSenseDevice* device) } } - if (device->btCon) + if (device->bt_controller) { const u8 seq_tag = (device->bt_sequence << 4) | 0x0; if (++device->bt_sequence >= 16) device->bt_sequence = 0; diff --git a/rpcs3/Input/dualsense_pad_handler.h b/rpcs3/Input/dualsense_pad_handler.h index e51c87b24de4..e74d4fdfdadb 100644 --- a/rpcs3/Input/dualsense_pad_handler.h +++ b/rpcs3/Input/dualsense_pad_handler.h @@ -14,11 +14,11 @@ class DualSenseDevice : public HidDevice Enhanced }; - bool btCon{false}; + bool bt_controller{false}; u8 bt_sequence{0}; bool has_calib_data{false}; std::array calib_data{}; - DualSenseDataMode dataMode{DualSenseDataMode::Simple}; + DualSenseDataMode data_mode{DualSenseDataMode::Simple}; bool init_lightbar{true}; bool update_lightbar{true}; bool update_player_leds{true}; diff --git a/rpcs3/Input/hid_pad_handler.cpp b/rpcs3/Input/hid_pad_handler.cpp index eff198a94c1f..924650604641 100644 --- a/rpcs3/Input/hid_pad_handler.cpp +++ b/rpcs3/Input/hid_pad_handler.cpp @@ -40,7 +40,6 @@ hid_pad_handler::~hid_pad_handler() { hid_log.error("hid_exit failed!"); } - hid_log.error("hid_exit !"); } } From 3de0784d67ddb6b5de79bc33f2b5ff5ef3213613 Mon Sep 17 00:00:00 2001 From: Megamouse Date: Mon, 22 Feb 2021 09:52:36 +0100 Subject: [PATCH 11/11] evdev: fix build --- rpcs3/Input/evdev_joystick_handler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpcs3/Input/evdev_joystick_handler.cpp b/rpcs3/Input/evdev_joystick_handler.cpp index fecd0672384c..81c8b89a8666 100644 --- a/rpcs3/Input/evdev_joystick_handler.cpp +++ b/rpcs3/Input/evdev_joystick_handler.cpp @@ -517,7 +517,7 @@ void evdev_joystick_handler::SetPadData(const std::string& padId, u32 largeMotor return; } - SetRumble(dev, largeMotor, smallMotor); + SetRumble(static_cast(dev.get()), largeMotor, smallMotor); } int evdev_joystick_handler::GetButtonInfo(const input_event& evt, const std::shared_ptr& device, int& value)