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