| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201 |
- // 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 <memory>
- #include <span>
- #include <vector>
- #include "common/common_types.h"
- #include "input_common/helpers/joycon_protocol/joycon_types.h"
- namespace InputCommon::Joycon {
- /// Joycon driver functions that handle low level communication
- class JoyconCommonProtocol {
- public:
- explicit JoyconCommonProtocol(std::shared_ptr<JoyconHandle> hidapi_handle_);
- /**
- * Sets handle to blocking. In blocking mode, SDL_hid_read() will wait (block) until there is
- * data to read before returning.
- */
- void SetBlocking();
- /**
- * Sets handle to non blocking. In non-blocking mode calls to SDL_hid_read() will return
- * immediately with a value of 0 if there is no data to be read
- */
- void SetNonBlocking();
- /**
- * Sends a request to obtain the joycon type from device
- * @returns controller type of the joycon
- */
- DriverResult GetDeviceType(ControllerType& controller_type);
- /**
- * Verifies and sets the joycon_handle if device is valid
- * @param device info from the driver
- * @returns success if the device is valid
- */
- DriverResult CheckDeviceAccess(SDL_hid_device_info* device);
- /**
- * Sends a request to set the polling mode of the joycon
- * @param report_mode polling mode to be set
- */
- DriverResult SetReportMode(Joycon::ReportMode report_mode);
- /**
- * Sends data to the joycon device
- * @param buffer data to be send
- */
- DriverResult SendRawData(std::span<const u8> buffer);
- template <typename Output>
- requires std::is_trivially_copyable_v<Output>
- DriverResult SendData(const Output& output) {
- std::array<u8, sizeof(Output)> buffer;
- std::memcpy(buffer.data(), &output, sizeof(Output));
- return SendRawData(buffer);
- }
- /**
- * Waits for incoming data of the joycon device that matchs the subcommand
- * @param sub_command type of data to be returned
- * @returns a buffer containing the response
- */
- DriverResult GetSubCommandResponse(SubCommand sub_command, SubCommandResponse& output);
- /**
- * Sends a sub command to the device and waits for it's reply
- * @param sc sub command to be send
- * @param buffer data to be send
- * @returns output buffer containing the response
- */
- DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer,
- SubCommandResponse& output);
- /**
- * Sends a sub command to the device and waits for it's reply and ignores the output
- * @param sc sub command to be send
- * @param buffer data to be send
- */
- DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer);
- /**
- * Sends a mcu command to the device
- * @param sc sub command to be send
- * @param buffer data to be send
- */
- DriverResult SendMCUCommand(SubCommand sc, std::span<const u8> buffer);
- /**
- * Sends vibration data to the joycon
- * @param buffer data to be send
- */
- DriverResult SendVibrationReport(std::span<const u8> buffer);
- /**
- * Reads the SPI memory stored on the joycon
- * @param Initial address location
- * @returns output buffer containing the response
- */
- DriverResult ReadRawSPI(SpiAddress addr, std::span<u8> output);
- /**
- * Reads the SPI memory stored on the joycon
- * @param Initial address location
- * @returns output object containing the response
- */
- template <typename Output>
- requires std::is_trivially_copyable_v<Output>
- DriverResult ReadSPI(SpiAddress addr, Output& output) {
- std::array<u8, sizeof(Output)> buffer;
- output = {};
- const auto result = ReadRawSPI(addr, buffer);
- if (result != DriverResult::Success) {
- return result;
- }
- std::memcpy(&output, buffer.data(), sizeof(Output));
- return DriverResult::Success;
- }
- /**
- * Enables MCU chip on the joycon
- * @param enable if true the chip will be enabled
- */
- DriverResult EnableMCU(bool enable);
- /**
- * Configures the MCU to the correspoinding mode
- * @param MCUConfig configuration
- */
- DriverResult ConfigureMCU(const MCUConfig& config);
- /**
- * Waits until there's MCU data available. On timeout returns error
- * @param report mode of the expected reply
- * @returns a buffer containing the response
- */
- DriverResult GetMCUDataResponse(ReportMode report_mode_, MCUCommandResponse& output);
- /**
- * Sends data to the MCU chip and waits for it's reply
- * @param report mode of the expected reply
- * @param sub command to be send
- * @param buffer data to be send
- * @returns output buffer containing the response
- */
- DriverResult SendMCUData(ReportMode report_mode, SubCommand sc, std::span<const u8> buffer,
- MCUCommandResponse& output);
- /**
- * Wait's until the MCU chip is on the specified mode
- * @param report mode of the expected reply
- * @param MCUMode configuration
- */
- DriverResult WaitSetMCUMode(ReportMode report_mode, MCUMode mode);
- /**
- * Calculates the checksum from the MCU data
- * @param buffer containing the data to be send
- * @param size of the buffer in bytes
- * @returns byte with the correct checksum
- */
- u8 CalculateMCU_CRC8(u8* buffer, u8 size) const;
- private:
- /**
- * Increments and returns the packet counter of the handle
- * @param joycon_handle device to send the data
- * @returns packet counter value
- */
- u8 GetCounter();
- std::shared_ptr<JoyconHandle> hidapi_handle;
- };
- class ScopedSetBlocking {
- public:
- explicit ScopedSetBlocking(JoyconCommonProtocol* self) : m_self{self} {
- m_self->SetBlocking();
- }
- ~ScopedSetBlocking() {
- m_self->SetNonBlocking();
- }
- private:
- JoyconCommonProtocol* m_self{};
- };
- } // namespace InputCommon::Joycon
|