5 changed files with 310 additions and 3 deletions
-
2src/input_common/CMakeLists.txt
-
54src/input_common/helpers/joycon_driver.cpp
-
2src/input_common/helpers/joycon_driver.h
-
147src/input_common/helpers/joycon_protocol/generic_functions.cpp
-
108src/input_common/helpers/joycon_protocol/generic_functions.h
@ -0,0 +1,147 @@ |
|||||
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
|
||||
|
#include "common/logging/log.h"
|
||||
|
#include "input_common/helpers/joycon_protocol/generic_functions.h"
|
||||
|
|
||||
|
namespace InputCommon::Joycon { |
||||
|
|
||||
|
GenericProtocol::GenericProtocol(std::shared_ptr<JoyconHandle> handle) |
||||
|
: JoyconCommonProtocol(handle) {} |
||||
|
|
||||
|
DriverResult GenericProtocol::EnablePassiveMode() { |
||||
|
SetBlocking(); |
||||
|
const auto result = SetReportMode(ReportMode::SIMPLE_HID_MODE); |
||||
|
SetNonBlocking(); |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
DriverResult GenericProtocol::EnableActiveMode() { |
||||
|
SetBlocking(); |
||||
|
const auto result = SetReportMode(ReportMode::STANDARD_FULL_60HZ); |
||||
|
SetNonBlocking(); |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
DriverResult GenericProtocol::GetDeviceInfo(DeviceInfo& device_info) { |
||||
|
std::vector<u8> output; |
||||
|
SetBlocking(); |
||||
|
|
||||
|
const auto result = SendSubCommand(SubCommand::REQ_DEV_INFO, {}, output); |
||||
|
|
||||
|
device_info = {}; |
||||
|
if (result == DriverResult::Success) { |
||||
|
memcpy(&device_info, output.data(), sizeof(DeviceInfo)); |
||||
|
} |
||||
|
|
||||
|
SetNonBlocking(); |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
DriverResult GenericProtocol::GetControllerType(ControllerType& controller_type) { |
||||
|
return GetDeviceType(controller_type); |
||||
|
} |
||||
|
|
||||
|
DriverResult GenericProtocol::EnableImu(bool enable) { |
||||
|
const std::vector<u8> buffer{static_cast<u8>(enable ? 1 : 0)}; |
||||
|
std::vector<u8> output; |
||||
|
SetBlocking(); |
||||
|
const auto result = SendSubCommand(SubCommand::ENABLE_IMU, buffer, output); |
||||
|
SetNonBlocking(); |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
DriverResult GenericProtocol::SetImuConfig(GyroSensitivity gsen, GyroPerformance gfrec, |
||||
|
AccelerometerSensitivity asen, |
||||
|
AccelerometerPerformance afrec) { |
||||
|
const std::vector<u8> buffer{static_cast<u8>(gsen), static_cast<u8>(asen), |
||||
|
static_cast<u8>(gfrec), static_cast<u8>(afrec)}; |
||||
|
std::vector<u8> output; |
||||
|
SetBlocking(); |
||||
|
const auto result = SendSubCommand(SubCommand::SET_IMU_SENSITIVITY, buffer, output); |
||||
|
SetNonBlocking(); |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
DriverResult GenericProtocol::GetBattery(u32& battery_level) { |
||||
|
battery_level = 0; |
||||
|
return DriverResult::NotSupported; |
||||
|
} |
||||
|
|
||||
|
DriverResult GenericProtocol::GetColor(Color& color) { |
||||
|
std::vector<u8> buffer; |
||||
|
SetBlocking(); |
||||
|
const auto result = ReadSPI(CalAddr::COLOR_DATA, 12, buffer); |
||||
|
SetNonBlocking(); |
||||
|
|
||||
|
color = {}; |
||||
|
if (result == DriverResult::Success) { |
||||
|
color.body = static_cast<u32>((buffer[0] << 16) | (buffer[1] << 8) | buffer[2]); |
||||
|
color.buttons = static_cast<u32>((buffer[3] << 16) | (buffer[4] << 8) | buffer[5]); |
||||
|
color.left_grip = static_cast<u32>((buffer[6] << 16) | (buffer[7] << 8) | buffer[8]); |
||||
|
color.right_grip = static_cast<u32>((buffer[9] << 16) | (buffer[10] << 8) | buffer[11]); |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
DriverResult GenericProtocol::GetSerialNumber(SerialNumber& serial_number) { |
||||
|
std::vector<u8> buffer; |
||||
|
SetBlocking(); |
||||
|
const auto result = ReadSPI(CalAddr::SERIAL_NUMBER, 16, buffer); |
||||
|
SetNonBlocking(); |
||||
|
|
||||
|
serial_number = {}; |
||||
|
if (result == DriverResult::Success) { |
||||
|
memcpy(serial_number.data(), buffer.data() + 1, sizeof(SerialNumber)); |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
DriverResult GenericProtocol::GetTemperature(u32& temperature) { |
||||
|
// Not all devices have temperature sensor
|
||||
|
temperature = 25; |
||||
|
return DriverResult::NotSupported; |
||||
|
} |
||||
|
|
||||
|
DriverResult GenericProtocol::GetVersionNumber(FirmwareVersion& version) { |
||||
|
DeviceInfo device_info{}; |
||||
|
|
||||
|
const auto result = GetDeviceInfo(device_info); |
||||
|
version = device_info.firmware; |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
DriverResult GenericProtocol::SetHomeLight() { |
||||
|
const std::vector<u8> buffer{0x0f, 0xf0, 0x00}; |
||||
|
std::vector<u8> output; |
||||
|
SetBlocking(); |
||||
|
|
||||
|
const auto result = SendSubCommand(SubCommand::SET_HOME_LIGHT, buffer, output); |
||||
|
|
||||
|
SetNonBlocking(); |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
DriverResult GenericProtocol::SetLedBusy() { |
||||
|
return DriverResult::NotSupported; |
||||
|
} |
||||
|
|
||||
|
DriverResult GenericProtocol::SetLedPattern(u8 leds) { |
||||
|
const std::vector<u8> buffer{leds}; |
||||
|
std::vector<u8> output; |
||||
|
SetBlocking(); |
||||
|
|
||||
|
const auto result = SendSubCommand(SubCommand::SET_PLAYER_LIGHTS, buffer, output); |
||||
|
|
||||
|
SetNonBlocking(); |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
DriverResult GenericProtocol::SetLedBlinkPattern(u8 leds) { |
||||
|
return SetLedPattern(static_cast<u8>(leds << 4)); |
||||
|
} |
||||
|
|
||||
|
} // namespace InputCommon::Joycon
|
||||
@ -0,0 +1,108 @@ |
|||||
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project |
||||
|
// SPDX-License-Identifier: GPL-2.0-or-later |
||||
|
|
||||
|
// Based on dkms-hid-nintendo implementation, CTCaer joycon toolkit and dekuNukem reverse |
||||
|
// engineering https://github.com/nicman23/dkms-hid-nintendo/blob/master/src/hid-nintendo.c |
||||
|
// https://github.com/CTCaer/jc_toolkit |
||||
|
// https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include "input_common/helpers/joycon_protocol/common_protocol.h" |
||||
|
#include "input_common/helpers/joycon_protocol/joycon_types.h" |
||||
|
|
||||
|
namespace InputCommon::Joycon { |
||||
|
|
||||
|
/// Joycon driver functions that easily implemented |
||||
|
class GenericProtocol final : private JoyconCommonProtocol { |
||||
|
public: |
||||
|
GenericProtocol(std::shared_ptr<JoyconHandle> handle); |
||||
|
|
||||
|
/// Enables passive mode. This mode only sends button data on change. Sticks will return digital |
||||
|
/// data instead of analog. Motion will be disabled |
||||
|
DriverResult EnablePassiveMode(); |
||||
|
|
||||
|
/// Enables active mode. This mode will return the current status every 5-15ms |
||||
|
DriverResult EnableActiveMode(); |
||||
|
|
||||
|
/** |
||||
|
* Sends a request to obtain the joycon firmware and mac from handle |
||||
|
* @returns controller device info |
||||
|
*/ |
||||
|
DriverResult GetDeviceInfo(DeviceInfo& controller_type); |
||||
|
|
||||
|
/** |
||||
|
* Sends a request to obtain the joycon type from handle |
||||
|
* @returns controller type of the joycon |
||||
|
*/ |
||||
|
DriverResult GetControllerType(ControllerType& controller_type); |
||||
|
|
||||
|
/** |
||||
|
* Enables motion input |
||||
|
* @param enable if true motion data will be enabled |
||||
|
*/ |
||||
|
DriverResult EnableImu(bool enable); |
||||
|
|
||||
|
/** |
||||
|
* Configures the motion sensor with the specified parameters |
||||
|
* @param gsen gyroscope sensor sensitvity in degrees per second |
||||
|
* @param gfrec gyroscope sensor frequency in hertz |
||||
|
* @param asen accelerometer sensitivity in G force |
||||
|
* @param afrec accelerometer frequency in hertz |
||||
|
*/ |
||||
|
DriverResult SetImuConfig(GyroSensitivity gsen, GyroPerformance gfrec, |
||||
|
AccelerometerSensitivity asen, AccelerometerPerformance afrec); |
||||
|
|
||||
|
/** |
||||
|
* Request battery level from the device |
||||
|
* @returns battery level |
||||
|
*/ |
||||
|
DriverResult GetBattery(u32& battery_level); |
||||
|
|
||||
|
/** |
||||
|
* Request joycon colors from the device |
||||
|
* @returns colors of the body and buttons |
||||
|
*/ |
||||
|
DriverResult GetColor(Color& color); |
||||
|
|
||||
|
/** |
||||
|
* Request joycon serial number from the device |
||||
|
* @returns 16 byte serial number |
||||
|
*/ |
||||
|
DriverResult GetSerialNumber(SerialNumber& serial_number); |
||||
|
|
||||
|
/** |
||||
|
* Request joycon serial number from the device |
||||
|
* @returns 16 byte serial number |
||||
|
*/ |
||||
|
DriverResult GetTemperature(u32& temperature); |
||||
|
|
||||
|
/** |
||||
|
* Request joycon serial number from the device |
||||
|
* @returns 16 byte serial number |
||||
|
*/ |
||||
|
DriverResult GetVersionNumber(FirmwareVersion& version); |
||||
|
|
||||
|
/** |
||||
|
* Sets home led behaviour |
||||
|
*/ |
||||
|
DriverResult SetHomeLight(); |
||||
|
|
||||
|
/** |
||||
|
* Sets home led into a slow breathing state |
||||
|
*/ |
||||
|
DriverResult SetLedBusy(); |
||||
|
|
||||
|
/** |
||||
|
* Sets the 4 player leds on the joycon on a solid state |
||||
|
* @params bit flag containing the led state |
||||
|
*/ |
||||
|
DriverResult SetLedPattern(u8 leds); |
||||
|
|
||||
|
/** |
||||
|
* Sets the 4 player leds on the joycon on a blinking state |
||||
|
* @returns bit flag containing the led state |
||||
|
*/ |
||||
|
DriverResult SetLedBlinkPattern(u8 leds); |
||||
|
}; |
||||
|
} // namespace InputCommon::Joycon |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue