diff options
9 files changed, 221 insertions, 154 deletions
| diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp index 3775e2d35..8f94c9f45 100644 --- a/src/input_common/helpers/joycon_driver.cpp +++ b/src/input_common/helpers/joycon_driver.cpp @@ -162,14 +162,14 @@ void JoyconDriver::InputThread(std::stop_token stop_token) {  }  void JoyconDriver::OnNewData(std::span<u8> buffer) { -    const auto report_mode = static_cast<InputReport>(buffer[0]); +    const auto report_mode = static_cast<ReportMode>(buffer[0]);      // Packages can be a litte bit inconsistent. Average the delta time to provide a smoother motion      // experience      switch (report_mode) { -    case InputReport::STANDARD_FULL_60HZ: -    case InputReport::NFC_IR_MODE_60HZ: -    case InputReport::SIMPLE_HID_MODE: { +    case ReportMode::STANDARD_FULL_60HZ: +    case ReportMode::NFC_IR_MODE_60HZ: +    case ReportMode::SIMPLE_HID_MODE: {          const auto now = std::chrono::steady_clock::now();          const auto new_delta_time = static_cast<u64>(              std::chrono::duration_cast<std::chrono::microseconds>(now - last_update).count()); @@ -190,7 +190,7 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) {      };      // TODO: Remove this when calibration is properly loaded and not calculated -    if (ring_connected && report_mode == InputReport::STANDARD_FULL_60HZ) { +    if (ring_connected && report_mode == ReportMode::STANDARD_FULL_60HZ) {          InputReportActive data{};          memcpy(&data, buffer.data(), sizeof(InputReportActive));          calibration_protocol->GetRingCalibration(ring_calibration, data.ring_input); @@ -228,16 +228,16 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) {      }      switch (report_mode) { -    case InputReport::STANDARD_FULL_60HZ: +    case ReportMode::STANDARD_FULL_60HZ:          joycon_poller->ReadActiveMode(buffer, motion_status, ring_status);          break; -    case InputReport::NFC_IR_MODE_60HZ: +    case ReportMode::NFC_IR_MODE_60HZ:          joycon_poller->ReadNfcIRMode(buffer, motion_status);          break; -    case InputReport::SIMPLE_HID_MODE: +    case ReportMode::SIMPLE_HID_MODE:          joycon_poller->ReadPassiveMode(buffer);          break; -    case InputReport::SUBCMD_REPLY: +    case ReportMode::SUBCMD_REPLY:          LOG_DEBUG(Input, "Unhandled command reply");          break;      default: diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.cpp b/src/input_common/helpers/joycon_protocol/common_protocol.cpp index 0ef240344..2b42a4555 100644 --- a/src/input_common/helpers/joycon_protocol/common_protocol.cpp +++ b/src/input_common/helpers/joycon_protocol/common_protocol.cpp @@ -22,12 +22,9 @@ void JoyconCommonProtocol::SetNonBlocking() {  }  DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type) { -    std::array<u8, 1> buffer{}; -    const auto result = ReadRawSPI(SpiAddress::DEVICE_TYPE, buffer); -    controller_type = ControllerType::None; +    const auto result = ReadSPI(SpiAddress::DEVICE_TYPE, controller_type);      if (result == DriverResult::Success) { -        controller_type = static_cast<ControllerType>(buffer[0]);          // Fallback to 3rd party pro controllers          if (controller_type == ControllerType::None) {              controller_type = ControllerType::Pro; @@ -40,6 +37,7 @@ DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type  DriverResult JoyconCommonProtocol::CheckDeviceAccess(SDL_hid_device_info* device_info) {      ControllerType controller_type{ControllerType::None};      const auto result = GetDeviceType(controller_type); +      if (result != DriverResult::Success || controller_type == ControllerType::None) {          return DriverResult::UnsupportedControllerType;      } @@ -62,7 +60,7 @@ DriverResult JoyconCommonProtocol::SetReportMode(ReportMode report_mode) {      return SendSubCommand(SubCommand::SET_REPORT_MODE, buffer);  } -DriverResult JoyconCommonProtocol::SendData(std::span<const u8> buffer) { +DriverResult JoyconCommonProtocol::SendRawData(std::span<const u8> buffer) {      const auto result = SDL_hid_write(hidapi_handle->handle, buffer.data(), buffer.size());      if (result == -1) { @@ -72,15 +70,15 @@ DriverResult JoyconCommonProtocol::SendData(std::span<const u8> buffer) {      return DriverResult::Success;  } -DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc, std::vector<u8>& output) { +DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc, +                                                         SubCommandResponse& output) {      constexpr int timeout_mili = 66;      constexpr int MaxTries = 15;      int tries = 0; -    output.resize(MaxSubCommandResponseSize);      do { -        int result = SDL_hid_read_timeout(hidapi_handle->handle, output.data(), -                                          MaxSubCommandResponseSize, timeout_mili); +        int result = SDL_hid_read_timeout(hidapi_handle->handle, reinterpret_cast<u8*>(&output), +                                          sizeof(SubCommandResponse), timeout_mili);          if (result < 1) {              LOG_ERROR(Input, "No response from joycon"); @@ -88,27 +86,28 @@ DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc, std::vec          if (tries++ > MaxTries) {              return DriverResult::Timeout;          } -    } while (output[0] != 0x21 && output[14] != static_cast<u8>(sc)); - -    if (output[0] != 0x21 && output[14] != static_cast<u8>(sc)) { -        return DriverResult::WrongReply; -    } +    } while (output.input_report.report_mode != ReportMode::SUBCMD_REPLY && +             output.sub_command != sc);      return DriverResult::Success;  }  DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const u8> buffer, -                                                  std::vector<u8>& output) { -    std::vector<u8> local_buffer(MaxResponseSize); - -    local_buffer[0] = static_cast<u8>(OutputReport::RUMBLE_AND_SUBCMD); -    local_buffer[1] = GetCounter(); -    local_buffer[10] = static_cast<u8>(sc); -    for (std::size_t i = 0; i < buffer.size(); ++i) { -        local_buffer[11 + i] = buffer[i]; +                                                  SubCommandResponse& output) { +    SubCommandPacket packet{ +        .output_report = OutputReport::RUMBLE_AND_SUBCMD, +        .packet_counter = GetCounter(), +        .sub_command = sc, +        .command_data = {}, +    }; + +    if (buffer.size() > packet.command_data.size()) { +        return DriverResult::InvalidParameters;      } -    auto result = SendData(local_buffer); +    memcpy(packet.command_data.data(), buffer.data(), buffer.size()); + +    auto result = SendData(packet);      if (result != DriverResult::Success) {          return result; @@ -120,46 +119,57 @@ DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const  }  DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const u8> buffer) { -    std::vector<u8> output; +    SubCommandResponse output{};      return SendSubCommand(sc, buffer, output);  }  DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc, std::span<const u8> buffer) { -    std::vector<u8> local_buffer(MaxResponseSize); - -    local_buffer[0] = static_cast<u8>(OutputReport::MCU_DATA); -    local_buffer[1] = GetCounter(); -    local_buffer[10] = static_cast<u8>(sc); -    for (std::size_t i = 0; i < buffer.size(); ++i) { -        local_buffer[11 + i] = buffer[i]; +    SubCommandPacket packet{ +        .output_report = OutputReport::MCU_DATA, +        .packet_counter = GetCounter(), +        .sub_command = sc, +        .command_data = {}, +    }; + +    if (buffer.size() > packet.command_data.size()) { +        return DriverResult::InvalidParameters;      } -    return SendData(local_buffer); +    memcpy(packet.command_data.data(), buffer.data(), buffer.size()); + +    return SendData(packet);  }  DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffer) { -    std::vector<u8> local_buffer(MaxResponseSize); - -    local_buffer[0] = static_cast<u8>(Joycon::OutputReport::RUMBLE_ONLY); -    local_buffer[1] = GetCounter(); +    VibrationPacket packet{ +        .output_report = OutputReport::RUMBLE_ONLY, +        .packet_counter = GetCounter(), +        .vibration_data = {}, +    }; + +    if (buffer.size() > packet.vibration_data.size()) { +        return DriverResult::InvalidParameters; +    } -    memcpy(local_buffer.data() + 2, buffer.data(), buffer.size()); +    memcpy(packet.vibration_data.data(), buffer.data(), buffer.size()); -    return SendData(local_buffer); +    return SendData(packet);  }  DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, std::span<u8> output) { -    constexpr std::size_t HeaderSize = 20; +    constexpr std::size_t HeaderSize = 5;      constexpr std::size_t MaxTries = 10; -    const auto size = output.size();      std::size_t tries = 0; -    std::array<u8, 5> buffer = {0x00, 0x00, 0x00, 0x00, static_cast<u8>(size)}; -    std::vector<u8> local_buffer{}; - -    buffer[0] = static_cast<u8>(static_cast<u16>(addr) & 0x00FF); -    buffer[1] = static_cast<u8>((static_cast<u16>(addr) & 0xFF00) >> 8); +    SubCommandResponse response{}; +    std::array<u8, sizeof(ReadSpiPacket)> buffer{}; +    const ReadSpiPacket packet_data{ +        .spi_address = addr, +        .size = static_cast<u8>(output.size()), +    }; + +    memcpy(buffer.data(), &packet_data, sizeof(ReadSpiPacket));      do { -        const auto result = SendSubCommand(SubCommand::SPI_FLASH_READ, buffer, local_buffer); +        const auto result = SendSubCommand(SubCommand::SPI_FLASH_READ, buffer, response);          if (result != DriverResult::Success) {              return result;          } @@ -167,14 +177,14 @@ DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, std::span<u8> out          if (tries++ > MaxTries) {              return DriverResult::Timeout;          } -    } while (local_buffer[15] != buffer[0] || local_buffer[16] != buffer[1]); +    } while (response.spi_address != addr); -    if (local_buffer.size() < size + HeaderSize) { +    if (response.command_data.size() < packet_data.size + HeaderSize) {          return DriverResult::WrongReply;      }      // Remove header from output -    memcpy(output.data(), local_buffer.data() + HeaderSize, size); +    memcpy(output.data(), response.command_data.data() + HeaderSize, packet_data.size);      return DriverResult::Success;  } @@ -183,7 +193,7 @@ DriverResult JoyconCommonProtocol::EnableMCU(bool enable) {      const auto result = SendSubCommand(SubCommand::SET_MCU_STATE, mcu_state);      if (result != DriverResult::Success) { -        LOG_ERROR(Input, "SendMCUData failed with error {}", result); +        LOG_ERROR(Input, "Failed with error {}", result);      }      return result; @@ -198,22 +208,21 @@ DriverResult JoyconCommonProtocol::ConfigureMCU(const MCUConfig& config) {      const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, config_buffer);      if (result != DriverResult::Success) { -        LOG_ERROR(Input, "Set MCU config failed with error {}", result); +        LOG_ERROR(Input, "Failed with error {}", result);      }      return result;  } -DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode_, -                                                      std::vector<u8>& output) { -    const int report_mode = static_cast<u8>(report_mode_); +DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode, +                                                      MCUCommandResponse& output) {      constexpr int TimeoutMili = 200;      constexpr int MaxTries = 9;      int tries = 0; -    output.resize(0x170);      do { -        int result = SDL_hid_read_timeout(hidapi_handle->handle, output.data(), 0x170, TimeoutMili); +        int result = SDL_hid_read_timeout(hidapi_handle->handle, reinterpret_cast<u8*>(&output), +                                          sizeof(MCUCommandResponse), TimeoutMili);          if (result < 1) {              LOG_ERROR(Input, "No response from joycon attempt {}", tries); @@ -221,28 +230,29 @@ DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode_,          if (tries++ > MaxTries) {              return DriverResult::Timeout;          } -    } while (output[0] != report_mode || output[49] == 0xFF); - -    if (output[0] != report_mode || output[49] == 0xFF) { -        return DriverResult::WrongReply; -    } +    } while (output.input_report.report_mode != report_mode || +             output.mcu_report == MCUReport::EmptyAwaitingCmd);      return DriverResult::Success;  }  DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, SubCommand sc,                                                 std::span<const u8> buffer, -                                               std::vector<u8>& output) { -    std::vector<u8> local_buffer(MaxResponseSize); - -    local_buffer[0] = static_cast<u8>(OutputReport::MCU_DATA); -    local_buffer[1] = GetCounter(); -    local_buffer[9] = static_cast<u8>(sc); -    for (std::size_t i = 0; i < buffer.size(); ++i) { -        local_buffer[10 + i] = buffer[i]; +                                               MCUCommandResponse& output) { +    SubCommandPacket packet{ +        .output_report = OutputReport::MCU_DATA, +        .packet_counter = GetCounter(), +        .sub_command = sc, +        .command_data = {}, +    }; + +    if (buffer.size() > packet.command_data.size()) { +        return DriverResult::InvalidParameters;      } -    auto result = SendData(local_buffer); +    memcpy(packet.command_data.data(), buffer.data(), buffer.size()); + +    auto result = SendData(packet);      if (result != DriverResult::Success) {          return result; @@ -254,7 +264,7 @@ DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, SubComman  }  DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, MCUMode mode) { -    std::vector<u8> output; +    MCUCommandResponse output{};      constexpr std::size_t MaxTries{8};      std::size_t tries{}; @@ -269,7 +279,8 @@ DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, MCUMod          if (tries++ > MaxTries) {              return DriverResult::WrongReply;          } -    } while (output[49] != 1 || output[56] != static_cast<u8>(mode)); +    } while (output.mcu_report != MCUReport::StateReport || +             output.mcu_data[6] != static_cast<u8>(mode));      return DriverResult::Success;  } diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.h b/src/input_common/helpers/joycon_protocol/common_protocol.h index 188f6ecfa..f44f73ba4 100644 --- a/src/input_common/helpers/joycon_protocol/common_protocol.h +++ b/src/input_common/helpers/joycon_protocol/common_protocol.h @@ -57,22 +57,31 @@ public:       * Sends data to the joycon device       * @param buffer data to be send       */ -    DriverResult SendData(std::span<const u8> buffer); +    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 responce +     * @returns a buffer containing the response       */ -    DriverResult GetSubCommandResponse(SubCommand sub_command, std::vector<u8>& output); +    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 responce +     * @returns output buffer containing the response       */ -    DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer, std::vector<u8>& output); +    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 @@ -97,14 +106,14 @@ public:      /**       * Reads the SPI memory stored on the joycon       * @param Initial address location -     * @returns output buffer containing the responce +     * @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 responce +     * @returns output object containing the response       */      template <typename Output>          requires std::is_trivially_copyable_v<Output> @@ -136,19 +145,19 @@ public:      /**       * Waits until there's MCU data available. On timeout returns error       * @param report mode of the expected reply -     * @returns a buffer containing the responce +     * @returns a buffer containing the response       */ -    DriverResult GetMCUDataResponse(ReportMode report_mode_, std::vector<u8>& output); +    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 responce +     * @returns output buffer containing the response       */      DriverResult SendMCUData(ReportMode report_mode, SubCommand sc, std::span<const u8> buffer, -                             std::vector<u8>& output); +                             MCUCommandResponse& output);      /**       * Wait's until the MCU chip is on the specified mode diff --git a/src/input_common/helpers/joycon_protocol/generic_functions.cpp b/src/input_common/helpers/joycon_protocol/generic_functions.cpp index f3fefd5b6..548a4b9e3 100644 --- a/src/input_common/helpers/joycon_protocol/generic_functions.cpp +++ b/src/input_common/helpers/joycon_protocol/generic_functions.cpp @@ -32,13 +32,13 @@ DriverResult GenericProtocol::TriggersElapsed() {  DriverResult GenericProtocol::GetDeviceInfo(DeviceInfo& device_info) {      ScopedSetBlocking sb(this); -    std::vector<u8> output; +    SubCommandResponse output{};      const auto result = SendSubCommand(SubCommand::REQ_DEV_INFO, {}, output);      device_info = {};      if (result == DriverResult::Success) { -        memcpy(&device_info, output.data() + 15, sizeof(DeviceInfo)); +        device_info = output.device_info;      }      return result; diff --git a/src/input_common/helpers/joycon_protocol/irs.cpp b/src/input_common/helpers/joycon_protocol/irs.cpp index 09e17bc5b..731fd5981 100644 --- a/src/input_common/helpers/joycon_protocol/irs.cpp +++ b/src/input_common/helpers/joycon_protocol/irs.cpp @@ -132,7 +132,7 @@ DriverResult IrsProtocol::RequestImage(std::span<u8> buffer) {  DriverResult IrsProtocol::ConfigureIrs() {      LOG_DEBUG(Input, "Configure IRS");      constexpr std::size_t max_tries = 28; -    std::vector<u8> output; +    SubCommandResponse output{};      std::size_t tries = 0;      const IrsConfigure irs_configuration{ @@ -158,7 +158,7 @@ DriverResult IrsProtocol::ConfigureIrs() {          if (tries++ >= max_tries) {              return DriverResult::WrongReply;          } -    } while (output[15] != 0x0b); +    } while (output.command_data[0] != 0x0b);      return DriverResult::Success;  } @@ -167,7 +167,7 @@ DriverResult IrsProtocol::WriteRegistersStep1() {      LOG_DEBUG(Input, "WriteRegistersStep1");      DriverResult result{DriverResult::Success};      constexpr std::size_t max_tries = 28; -    std::vector<u8> output; +    SubCommandResponse output{};      std::size_t tries = 0;      const IrsWriteRegisters irs_registers{ @@ -218,7 +218,8 @@ DriverResult IrsProtocol::WriteRegistersStep1() {          if (tries++ >= max_tries) {              return DriverResult::WrongReply;          } -    } while (!(output[15] == 0x13 && output[17] == 0x07) && output[15] != 0x23); +    } while (!(output.command_data[0] == 0x13 && output.command_data[2] == 0x07) && +             output.command_data[0] != 0x23);      return DriverResult::Success;  } @@ -226,7 +227,7 @@ DriverResult IrsProtocol::WriteRegistersStep1() {  DriverResult IrsProtocol::WriteRegistersStep2() {      LOG_DEBUG(Input, "WriteRegistersStep2");      constexpr std::size_t max_tries = 28; -    std::vector<u8> output; +    SubCommandResponse output{};      std::size_t tries = 0;      const IrsWriteRegisters irs_registers{ @@ -260,7 +261,7 @@ DriverResult IrsProtocol::WriteRegistersStep2() {          if (tries++ >= max_tries) {              return DriverResult::WrongReply;          } -    } while (output[15] != 0x13 && output[15] != 0x23); +    } while (output.command_data[0] != 0x13 && output.command_data[0] != 0x23);      return DriverResult::Success;  } diff --git a/src/input_common/helpers/joycon_protocol/joycon_types.h b/src/input_common/helpers/joycon_protocol/joycon_types.h index ddb48a553..b91934990 100644 --- a/src/input_common/helpers/joycon_protocol/joycon_types.h +++ b/src/input_common/helpers/joycon_protocol/joycon_types.h @@ -19,8 +19,6 @@  namespace InputCommon::Joycon {  constexpr u32 MaxErrorCount = 50;  constexpr u32 MaxBufferSize = 368; -constexpr u32 MaxResponseSize = 49; -constexpr u32 MaxSubCommandResponseSize = 64;  constexpr std::array<u8, 8> DefaultVibrationBuffer{0x0, 0x1, 0x40, 0x40, 0x0, 0x1, 0x40, 0x40};  using MacAddress = std::array<u8, 6>; @@ -105,14 +103,6 @@ enum class OutputReport : u8 {      USB_CMD = 0x80,  }; -enum class InputReport : u8 { -    SUBCMD_REPLY = 0x21, -    STANDARD_FULL_60HZ = 0x30, -    NFC_IR_MODE_60HZ = 0x31, -    SIMPLE_HID_MODE = 0x3F, -    INPUT_USB_RESPONSE = 0x81, -}; -  enum class FeatureReport : u8 {      Last_SUBCMD = 0x02,      OTA_GW_UPGRADE = 0x70, @@ -171,7 +161,7 @@ enum class CalibrationMagic : u8 {      USR_MAGIC_1 = 0xA1,  }; -enum class SpiAddress { +enum class SpiAddress : u16 {      MAGIC = 0x0000,      MAC_ADDRESS = 0x0015,      PAIRING_INFO = 0x2000, @@ -198,10 +188,12 @@ enum class ReportMode : u8 {      ACTIVE_POLLING_NFC_IR_CAMERA_CONFIGURATION = 0x01,      ACTIVE_POLLING_NFC_IR_CAMERA_DATA_CONFIGURATION = 0x02,      ACTIVE_POLLING_IR_CAMERA_DATA = 0x03, +    SUBCMD_REPLY = 0x21,      MCU_UPDATE_STATE = 0x23,      STANDARD_FULL_60HZ = 0x30,      NFC_IR_MODE_60HZ = 0x31,      SIMPLE_HID_MODE = 0x3F, +    INPUT_USB_RESPONSE = 0x81,  };  enum class GyroSensitivity : u8 { @@ -372,15 +364,16 @@ enum class IrRegistersAddress : u16 {      DenoiseColor = 0x6901,  }; -enum class ExternalDeviceId : u8 { -    RingController = 0x20, -    Starlink = 0x28, +enum class ExternalDeviceId : u16 { +    RingController = 0x2000, +    Starlink = 0x2800,  };  enum class DriverResult {      Success,      WrongReply,      Timeout, +    InvalidParameters,      UnsupportedControllerType,      HandleInUse,      ErrorReadingData, @@ -503,7 +496,7 @@ static_assert(sizeof(MCUConfig) == 0x26, "MCUConfig is an invalid size");  #pragma pack(push, 1)  struct InputReportPassive { -    InputReport report_mode; +    ReportMode report_mode;      u16 button_input;      u8 stick_state;      std::array<u8, 10> unknown_data; @@ -511,7 +504,7 @@ struct InputReportPassive {  static_assert(sizeof(InputReportPassive) == 0xE, "InputReportPassive is an invalid size");  struct InputReportActive { -    InputReport report_mode; +    ReportMode report_mode;      u8 packet_id;      Battery battery_status;      std::array<u8, 3> button_input; @@ -525,7 +518,7 @@ struct InputReportActive {  static_assert(sizeof(InputReportActive) == 0x29, "InputReportActive is an invalid size");  struct InputReportNfcIr { -    InputReport report_mode; +    ReportMode report_mode;      u8 packet_id;      Battery battery_status;      std::array<u8, 3> button_input; @@ -643,6 +636,53 @@ struct RingStatus {      s16 min_value;  }; +struct VibrationPacket { +    OutputReport output_report; +    u8 packet_counter; +    std::array<u8, 0x8> vibration_data; +}; +static_assert(sizeof(VibrationPacket) == 0xA, "VibrationPacket is an invalid size"); + +struct SubCommandPacket { +    OutputReport output_report; +    u8 packet_counter; +    INSERT_PADDING_BYTES(0x8); // This contains vibration data +    SubCommand sub_command; +    std::array<u8, 0x26> command_data; +}; +static_assert(sizeof(SubCommandPacket) == 0x31, "SubCommandPacket is an invalid size"); + +#pragma pack(push, 1) +struct ReadSpiPacket { +    SpiAddress spi_address; +    INSERT_PADDING_BYTES(0x2); +    u8 size; +}; +static_assert(sizeof(ReadSpiPacket) == 0x5, "ReadSpiPacket is an invalid size"); + +struct SubCommandResponse { +    InputReportPassive input_report; +    SubCommand sub_command; +    union { +        std::array<u8, 0x30> command_data; +        SpiAddress spi_address;              // Reply from SPI_FLASH_READ subcommand +        ExternalDeviceId external_device_id; // Reply from GET_EXTERNAL_DEVICE_INFO subcommand +        DeviceInfo device_info;              // Reply from REQ_DEV_INFO subcommand +    }; +    u8 crc; // This is never used +}; +static_assert(sizeof(SubCommandResponse) == 0x40, "SubCommandResponse is an invalid size"); +#pragma pack(pop) + +struct MCUCommandResponse { +    InputReportNfcIr input_report; +    INSERT_PADDING_BYTES(0x8); +    MCUReport mcu_report; +    std::array<u8, 0x13D> mcu_data; +    u8 crc; +}; +static_assert(sizeof(MCUCommandResponse) == 0x170, "MCUCommandResponse is an invalid size"); +  struct JoyconCallbacks {      std::function<void(Battery)> on_battery_data;      std::function<void(Color)> on_color_data; diff --git a/src/input_common/helpers/joycon_protocol/nfc.cpp b/src/input_common/helpers/joycon_protocol/nfc.cpp index 5c0f71722..eeba82986 100644 --- a/src/input_common/helpers/joycon_protocol/nfc.cpp +++ b/src/input_common/helpers/joycon_protocol/nfc.cpp @@ -110,7 +110,7 @@ bool NfcProtocol::HasAmiibo() {  DriverResult NfcProtocol::WaitUntilNfcIsReady() {      constexpr std::size_t timeout_limit = 10; -    std::vector<u8> output; +    MCUCommandResponse output{};      std::size_t tries = 0;      do { @@ -122,8 +122,9 @@ DriverResult NfcProtocol::WaitUntilNfcIsReady() {          if (tries++ > timeout_limit) {              return DriverResult::Timeout;          } -    } while (output[49] != 0x2a || (output[51] << 8) + output[50] != 0x0500 || output[55] != 0x31 || -             output[56] != 0x00); +    } while (output.mcu_report != MCUReport::NFCState || +             (output.mcu_data[1] << 8) + output.mcu_data[0] != 0x0500 || +             output.mcu_data[5] != 0x31 || output.mcu_data[6] != 0x00);      return DriverResult::Success;  } @@ -131,7 +132,7 @@ DriverResult NfcProtocol::WaitUntilNfcIsReady() {  DriverResult NfcProtocol::StartPolling(TagFoundData& data) {      LOG_DEBUG(Input, "Start Polling for tag");      constexpr std::size_t timeout_limit = 7; -    std::vector<u8> output; +    MCUCommandResponse output{};      std::size_t tries = 0;      do { @@ -142,18 +143,20 @@ DriverResult NfcProtocol::StartPolling(TagFoundData& data) {          if (tries++ > timeout_limit) {              return DriverResult::Timeout;          } -    } while (output[49] != 0x2a || (output[51] << 8) + output[50] != 0x0500 || output[56] != 0x09); +    } while (output.mcu_report != MCUReport::NFCState || +             (output.mcu_data[1] << 8) + output.mcu_data[0] != 0x0500 || +             output.mcu_data[6] != 0x09); -    data.type = output[62]; -    data.uuid.resize(output[64]); -    memcpy(data.uuid.data(), output.data() + 65, data.uuid.size()); +    data.type = output.mcu_data[12]; +    data.uuid.resize(output.mcu_data[14]); +    memcpy(data.uuid.data(), output.mcu_data.data() + 15, data.uuid.size());      return DriverResult::Success;  }  DriverResult NfcProtocol::ReadTag(const TagFoundData& data) {      constexpr std::size_t timeout_limit = 10; -    std::vector<u8> output; +    MCUCommandResponse output{};      std::size_t tries = 0;      std::string uuid_string; @@ -168,23 +171,24 @@ DriverResult NfcProtocol::ReadTag(const TagFoundData& data) {      // Read Tag data      while (true) {          auto result = SendReadAmiiboRequest(output, ntag_pages); -        const auto mcu_report = static_cast<MCUReport>(output[49]); -        const auto nfc_status = static_cast<NFCStatus>(output[56]); +        const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);          if (result != DriverResult::Success) {              return result;          } -        if ((mcu_report == MCUReport::NFCReadData || mcu_report == MCUReport::NFCState) && +        if ((output.mcu_report == MCUReport::NFCReadData || +             output.mcu_report == MCUReport::NFCState) &&              nfc_status == NFCStatus::TagLost) {              return DriverResult::ErrorReadingData;          } -        if (mcu_report == MCUReport::NFCReadData && output[51] == 0x07 && output[52] == 0x01) { +        if (output.mcu_report == MCUReport::NFCReadData && output.mcu_data[1] == 0x07 && +            output.mcu_data[2] == 0x01) {              if (data.type != 2) {                  continue;              } -            switch (output[74]) { +            switch (output.mcu_data[24]) {              case 0:                  ntag_pages = NFCPages::Block135;                  break; @@ -200,14 +204,14 @@ DriverResult NfcProtocol::ReadTag(const TagFoundData& data) {              continue;          } -        if (mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::LastPackage) { +        if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::LastPackage) {              // finished              SendStopPollingRequest(output);              return DriverResult::Success;          }          // Ignore other state reports -        if (mcu_report == MCUReport::NFCState) { +        if (output.mcu_report == MCUReport::NFCState) {              continue;          } @@ -221,7 +225,7 @@ DriverResult NfcProtocol::ReadTag(const TagFoundData& data) {  DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) {      constexpr std::size_t timeout_limit = 10; -    std::vector<u8> output; +    MCUCommandResponse output{};      std::size_t tries = 0;      NFCPages ntag_pages = NFCPages::Block135; @@ -229,36 +233,38 @@ DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) {      // Read Tag data      while (true) {          auto result = SendReadAmiiboRequest(output, ntag_pages); -        const auto mcu_report = static_cast<MCUReport>(output[49]); -        const auto nfc_status = static_cast<NFCStatus>(output[56]); +        const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);          if (result != DriverResult::Success) {              return result;          } -        if ((mcu_report == MCUReport::NFCReadData || mcu_report == MCUReport::NFCState) && +        if ((output.mcu_report == MCUReport::NFCReadData || +             output.mcu_report == MCUReport::NFCState) &&              nfc_status == NFCStatus::TagLost) {              return DriverResult::ErrorReadingData;          } -        if (mcu_report == MCUReport::NFCReadData && output[51] == 0x07) { -            std::size_t payload_size = (output[54] << 8 | output[55]) & 0x7FF; -            if (output[52] == 0x01) { -                memcpy(ntag_data.data() + ntag_buffer_pos, output.data() + 116, payload_size - 60); +        if (output.mcu_report == MCUReport::NFCReadData && output.mcu_data[1] == 0x07) { +            std::size_t payload_size = (output.mcu_data[4] << 8 | output.mcu_data[5]) & 0x7FF; +            if (output.mcu_data[2] == 0x01) { +                memcpy(ntag_data.data() + ntag_buffer_pos, output.mcu_data.data() + 66, +                       payload_size - 60);                  ntag_buffer_pos += payload_size - 60;              } else { -                memcpy(ntag_data.data() + ntag_buffer_pos, output.data() + 56, payload_size); +                memcpy(ntag_data.data() + ntag_buffer_pos, output.mcu_data.data() + 6, +                       payload_size);              }              continue;          } -        if (mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::LastPackage) { +        if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::LastPackage) {              LOG_INFO(Input, "Finished reading amiibo");              return DriverResult::Success;          }          // Ignore other state reports -        if (mcu_report == MCUReport::NFCState) { +        if (output.mcu_report == MCUReport::NFCState) {              continue;          } @@ -270,7 +276,7 @@ DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) {      return DriverResult::Success;  } -DriverResult NfcProtocol::SendStartPollingRequest(std::vector<u8>& output) { +DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output) {      NFCRequestState request{          .sub_command = MCUSubCommand::ReadDeviceMode,          .command_argument = NFCReadCommand::StartPolling, @@ -294,7 +300,7 @@ DriverResult NfcProtocol::SendStartPollingRequest(std::vector<u8>& output) {      return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, SubCommand::STATE, request_data, output);  } -DriverResult NfcProtocol::SendStopPollingRequest(std::vector<u8>& output) { +DriverResult NfcProtocol::SendStopPollingRequest(MCUCommandResponse& output) {      NFCRequestState request{          .sub_command = MCUSubCommand::ReadDeviceMode,          .command_argument = NFCReadCommand::StopPolling, @@ -311,7 +317,7 @@ DriverResult NfcProtocol::SendStopPollingRequest(std::vector<u8>& output) {      return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, SubCommand::STATE, request_data, output);  } -DriverResult NfcProtocol::SendStartWaitingRecieveRequest(std::vector<u8>& output) { +DriverResult NfcProtocol::SendStartWaitingRecieveRequest(MCUCommandResponse& output) {      NFCRequestState request{          .sub_command = MCUSubCommand::ReadDeviceMode,          .command_argument = NFCReadCommand::StartWaitingRecieve, @@ -328,7 +334,7 @@ DriverResult NfcProtocol::SendStartWaitingRecieveRequest(std::vector<u8>& output      return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, SubCommand::STATE, request_data, output);  } -DriverResult NfcProtocol::SendReadAmiiboRequest(std::vector<u8>& output, NFCPages ntag_pages) { +DriverResult NfcProtocol::SendReadAmiiboRequest(MCUCommandResponse& output, NFCPages ntag_pages) {      NFCRequestState request{          .sub_command = MCUSubCommand::ReadDeviceMode,          .command_argument = NFCReadCommand::Ntag, diff --git a/src/input_common/helpers/joycon_protocol/nfc.h b/src/input_common/helpers/joycon_protocol/nfc.h index e63665aa9..11e263e07 100644 --- a/src/input_common/helpers/joycon_protocol/nfc.h +++ b/src/input_common/helpers/joycon_protocol/nfc.h @@ -45,13 +45,13 @@ private:      DriverResult GetAmiiboData(std::vector<u8>& data); -    DriverResult SendStartPollingRequest(std::vector<u8>& output); +    DriverResult SendStartPollingRequest(MCUCommandResponse& output); -    DriverResult SendStopPollingRequest(std::vector<u8>& output); +    DriverResult SendStopPollingRequest(MCUCommandResponse& output); -    DriverResult SendStartWaitingRecieveRequest(std::vector<u8>& output); +    DriverResult SendStartWaitingRecieveRequest(MCUCommandResponse& output); -    DriverResult SendReadAmiiboRequest(std::vector<u8>& output, NFCPages ntag_pages); +    DriverResult SendReadAmiiboRequest(MCUCommandResponse& output, NFCPages ntag_pages);      NFCReadBlockCommand GetReadBlockCommand(NFCPages pages) const; diff --git a/src/input_common/helpers/joycon_protocol/ringcon.cpp b/src/input_common/helpers/joycon_protocol/ringcon.cpp index 3c2ca4379..190cef812 100644 --- a/src/input_common/helpers/joycon_protocol/ringcon.cpp +++ b/src/input_common/helpers/joycon_protocol/ringcon.cpp @@ -70,7 +70,7 @@ DriverResult RingConProtocol::StartRingconPolling() {  DriverResult RingConProtocol::IsRingConnected(bool& is_connected) {      LOG_DEBUG(Input, "IsRingConnected");      constexpr std::size_t max_tries = 28; -    std::vector<u8> output; +    SubCommandResponse output{};      std::size_t tries = 0;      is_connected = false; @@ -84,7 +84,7 @@ DriverResult RingConProtocol::IsRingConnected(bool& is_connected) {          if (tries++ >= max_tries) {              return DriverResult::NoDeviceDetected;          } -    } while (output[16] != static_cast<u8>(ExternalDeviceId::RingController)); +    } while (output.external_device_id != ExternalDeviceId::RingController);      is_connected = true;      return DriverResult::Success; | 
