diff options
Diffstat (limited to 'src/input_common/drivers')
| -rw-r--r-- | src/input_common/drivers/joycon.cpp | 133 | ||||
| -rw-r--r-- | src/input_common/drivers/joycon.h | 18 | ||||
| -rw-r--r-- | src/input_common/drivers/virtual_amiibo.cpp | 130 | ||||
| -rw-r--r-- | src/input_common/drivers/virtual_amiibo.h | 16 | 
4 files changed, 271 insertions, 26 deletions
diff --git a/src/input_common/drivers/joycon.cpp b/src/input_common/drivers/joycon.cpp index b2b5677c8..52494e0d9 100644 --- a/src/input_common/drivers/joycon.cpp +++ b/src/input_common/drivers/joycon.cpp @@ -195,8 +195,8 @@ void Joycons::RegisterNewDevice(SDL_hid_device_info* device_info) {                  OnMotionUpdate(port, type, id, value);              }},              .on_ring_data = {[this](f32 ring_data) { OnRingConUpdate(ring_data); }}, -            .on_amiibo_data = {[this, port, type](const std::vector<u8>& amiibo_data) { -                OnAmiiboUpdate(port, type, amiibo_data); +            .on_amiibo_data = {[this, port, type](const Joycon::TagInfo& tag_info) { +                OnAmiiboUpdate(port, type, tag_info);              }},              .on_camera_data = {[this, port](const std::vector<u8>& camera_data,                                              Joycon::IrsResolution format) { @@ -291,13 +291,105 @@ Common::Input::NfcState Joycons::SupportsNfc(const PadIdentifier& identifier_) c      return Common::Input::NfcState::Success;  }; +Common::Input::NfcState Joycons::StartNfcPolling(const PadIdentifier& identifier) { +    auto handle = GetHandle(identifier); +    if (handle == nullptr) { +        return Common::Input::NfcState::Unknown; +    } +    return TranslateDriverResult(handle->StartNfcPolling()); +}; + +Common::Input::NfcState Joycons::StopNfcPolling(const PadIdentifier& identifier) { +    auto handle = GetHandle(identifier); +    if (handle == nullptr) { +        return Common::Input::NfcState::Unknown; +    } +    return TranslateDriverResult(handle->StopNfcPolling()); +}; + +Common::Input::NfcState Joycons::ReadAmiiboData(const PadIdentifier& identifier, +                                                std::vector<u8>& out_data) { +    auto handle = GetHandle(identifier); +    if (handle == nullptr) { +        return Common::Input::NfcState::Unknown; +    } +    return TranslateDriverResult(handle->ReadAmiiboData(out_data)); +} +  Common::Input::NfcState Joycons::WriteNfcData(const PadIdentifier& identifier,                                                const std::vector<u8>& data) {      auto handle = GetHandle(identifier); -    if (handle->WriteNfcData(data) != Joycon::DriverResult::Success) { -        return Common::Input::NfcState::WriteFailed; +    if (handle == nullptr) { +        return Common::Input::NfcState::Unknown;      } -    return Common::Input::NfcState::Success; +    return TranslateDriverResult(handle->WriteNfcData(data)); +}; + +Common::Input::NfcState Joycons::ReadMifareData(const PadIdentifier& identifier, +                                                const Common::Input::MifareRequest& request, +                                                Common::Input::MifareRequest& data) { +    auto handle = GetHandle(identifier); +    if (handle == nullptr) { +        return Common::Input::NfcState::Unknown; +    } + +    const auto command = static_cast<Joycon::MifareCmd>(request.data[0].command); +    std::vector<Joycon::MifareReadChunk> read_request{}; +    for (const auto& request_data : request.data) { +        if (request_data.command == 0) { +            continue; +        } +        Joycon::MifareReadChunk chunk = { +            .command = command, +            .sector_key = {}, +            .sector = request_data.sector, +        }; +        memcpy(chunk.sector_key.data(), request_data.key.data(), +               sizeof(Joycon::MifareReadChunk::sector_key)); +        read_request.emplace_back(chunk); +    } + +    std::vector<Joycon::MifareReadData> read_data(read_request.size()); +    const auto result = handle->ReadMifareData(read_request, read_data); +    if (result == Joycon::DriverResult::Success) { +        for (std::size_t i = 0; i < read_request.size(); i++) { +            data.data[i] = { +                .command = static_cast<u8>(command), +                .sector = read_data[i].sector, +                .key = {}, +                .data = read_data[i].data, +            }; +        } +    } +    return TranslateDriverResult(result); +}; + +Common::Input::NfcState Joycons::WriteMifareData(const PadIdentifier& identifier, +                                                 const Common::Input::MifareRequest& request) { +    auto handle = GetHandle(identifier); +    if (handle == nullptr) { +        return Common::Input::NfcState::Unknown; +    } + +    const auto command = static_cast<Joycon::MifareCmd>(request.data[0].command); +    std::vector<Joycon::MifareWriteChunk> write_request{}; +    for (const auto& request_data : request.data) { +        if (request_data.command == 0) { +            continue; +        } +        Joycon::MifareWriteChunk chunk = { +            .command = command, +            .sector_key = {}, +            .sector = request_data.sector, +            .data = {}, +        }; +        memcpy(chunk.sector_key.data(), request_data.key.data(), +               sizeof(Joycon::MifareReadChunk::sector_key)); +        memcpy(chunk.data.data(), request_data.data.data(), sizeof(Joycon::MifareWriteChunk::data)); +        write_request.emplace_back(chunk); +    } + +    return TranslateDriverResult(handle->WriteMifareData(write_request));  };  Common::Input::DriverResult Joycons::SetPollingMode(const PadIdentifier& identifier, @@ -403,11 +495,20 @@ void Joycons::OnRingConUpdate(f32 ring_data) {  }  void Joycons::OnAmiiboUpdate(std::size_t port, Joycon::ControllerType type, -                             const std::vector<u8>& amiibo_data) { +                             const Joycon::TagInfo& tag_info) {      const auto identifier = GetIdentifier(port, type); -    const auto nfc_state = amiibo_data.empty() ? Common::Input::NfcState::AmiiboRemoved -                                               : Common::Input::NfcState::NewAmiibo; -    SetNfc(identifier, {nfc_state, amiibo_data}); +    const auto nfc_state = tag_info.uuid_length == 0 ? Common::Input::NfcState::AmiiboRemoved +                                                     : Common::Input::NfcState::NewAmiibo; + +    const Common::Input::NfcStatus nfc_status{ +        .state = nfc_state, +        .uuid_length = tag_info.uuid_length, +        .protocol = tag_info.protocol, +        .tag_type = tag_info.tag_type, +        .uuid = tag_info.uuid, +    }; + +    SetNfc(identifier, nfc_status);  }  void Joycons::OnCameraUpdate(std::size_t port, const std::vector<u8>& camera_data, @@ -726,4 +827,18 @@ std::string Joycons::JoyconName(Joycon::ControllerType type) const {          return "Unknown Switch Controller";      }  } + +Common::Input::NfcState Joycons::TranslateDriverResult(Joycon::DriverResult result) const { +    switch (result) { +    case Joycon::DriverResult::Success: +        return Common::Input::NfcState::Success; +    case Joycon::DriverResult::Disabled: +        return Common::Input::NfcState::WrongDeviceState; +    case Joycon::DriverResult::NotSupported: +        return Common::Input::NfcState::NotSupported; +    default: +        return Common::Input::NfcState::Unknown; +    } +} +  } // namespace InputCommon diff --git a/src/input_common/drivers/joycon.h b/src/input_common/drivers/joycon.h index e3f0ad78f..4c323d7d6 100644 --- a/src/input_common/drivers/joycon.h +++ b/src/input_common/drivers/joycon.h @@ -15,6 +15,7 @@ using SerialNumber = std::array<u8, 15>;  struct Battery;  struct Color;  struct MotionData; +struct TagInfo;  enum class ControllerType : u8;  enum class DriverResult;  enum class IrsResolution; @@ -39,9 +40,18 @@ public:      Common::Input::DriverResult SetCameraFormat(const PadIdentifier& identifier,                                                  Common::Input::CameraFormat camera_format) override; -    Common::Input::NfcState SupportsNfc(const PadIdentifier& identifier_) const override; -    Common::Input::NfcState WriteNfcData(const PadIdentifier& identifier_, +    Common::Input::NfcState SupportsNfc(const PadIdentifier& identifier) const override; +    Common::Input::NfcState StartNfcPolling(const PadIdentifier& identifier) override; +    Common::Input::NfcState StopNfcPolling(const PadIdentifier& identifier) override; +    Common::Input::NfcState ReadAmiiboData(const PadIdentifier& identifier, +                                           std::vector<u8>& out_data) override; +    Common::Input::NfcState WriteNfcData(const PadIdentifier& identifier,                                           const std::vector<u8>& data) override; +    Common::Input::NfcState ReadMifareData(const PadIdentifier& identifier, +                                           const Common::Input::MifareRequest& request, +                                           Common::Input::MifareRequest& out_data) override; +    Common::Input::NfcState WriteMifareData(const PadIdentifier& identifier, +                                            const Common::Input::MifareRequest& request) override;      Common::Input::DriverResult SetPollingMode(          const PadIdentifier& identifier, const Common::Input::PollingMode polling_mode) override; @@ -82,7 +92,7 @@ private:                          const Joycon::MotionData& value);      void OnRingConUpdate(f32 ring_data);      void OnAmiiboUpdate(std::size_t port, Joycon::ControllerType type, -                        const std::vector<u8>& amiibo_data); +                        const Joycon::TagInfo& amiibo_data);      void OnCameraUpdate(std::size_t port, const std::vector<u8>& camera_data,                          Joycon::IrsResolution format); @@ -102,6 +112,8 @@ private:      /// Returns the name of the device in text format      std::string JoyconName(Joycon::ControllerType type) const; +    Common::Input::NfcState TranslateDriverResult(Joycon::DriverResult result) const; +      std::jthread scan_thread;      // Joycon types are split by type to ease supporting dualjoycon configurations diff --git a/src/input_common/drivers/virtual_amiibo.cpp b/src/input_common/drivers/virtual_amiibo.cpp index 6435b8af8..180eb53ef 100644 --- a/src/input_common/drivers/virtual_amiibo.cpp +++ b/src/input_common/drivers/virtual_amiibo.cpp @@ -29,14 +29,13 @@ Common::Input::DriverResult VirtualAmiibo::SetPollingMode(      switch (polling_mode) {      case Common::Input::PollingMode::NFC: -        if (state == State::Initialized) { -            state = State::WaitingForAmiibo; -        } +        state = State::Initialized;          return Common::Input::DriverResult::Success;      default: -        if (state == State::AmiiboIsOpen) { +        if (state == State::TagNearby) {              CloseAmiibo();          } +        state = State::Disabled;          return Common::Input::DriverResult::NotSupported;      }  } @@ -45,6 +44,39 @@ Common::Input::NfcState VirtualAmiibo::SupportsNfc(      [[maybe_unused]] const PadIdentifier& identifier_) const {      return Common::Input::NfcState::Success;  } +Common::Input::NfcState VirtualAmiibo::StartNfcPolling(const PadIdentifier& identifier_) { +    if (state != State::Initialized) { +        return Common::Input::NfcState::WrongDeviceState; +    } +    state = State::WaitingForAmiibo; +    return Common::Input::NfcState::Success; +} + +Common::Input::NfcState VirtualAmiibo::StopNfcPolling(const PadIdentifier& identifier_) { +    if (state == State::Disabled) { +        return Common::Input::NfcState::WrongDeviceState; +    } +    if (state == State::TagNearby) { +        CloseAmiibo(); +    } +    state = State::Initialized; +    return Common::Input::NfcState::Success; +} + +Common::Input::NfcState VirtualAmiibo::ReadAmiiboData(const PadIdentifier& identifier_, +                                                      std::vector<u8>& out_data) { +    if (state != State::TagNearby) { +        return Common::Input::NfcState::WrongDeviceState; +    } + +    if (status.tag_type != 1U << 1) { +        return Common::Input::NfcState::InvalidTagType; +    } + +    out_data.resize(nfc_data.size()); +    memcpy(out_data.data(), nfc_data.data(), nfc_data.size()); +    return Common::Input::NfcState::Success; +}  Common::Input::NfcState VirtualAmiibo::WriteNfcData(      [[maybe_unused]] const PadIdentifier& identifier_, const std::vector<u8>& data) { @@ -66,6 +98,69 @@ Common::Input::NfcState VirtualAmiibo::WriteNfcData(      return Common::Input::NfcState::Success;  } +Common::Input::NfcState VirtualAmiibo::ReadMifareData(const PadIdentifier& identifier_, +                                                      const Common::Input::MifareRequest& request, +                                                      Common::Input::MifareRequest& out_data) { +    if (state != State::TagNearby) { +        return Common::Input::NfcState::WrongDeviceState; +    } + +    if (status.tag_type != 1U << 6) { +        return Common::Input::NfcState::InvalidTagType; +    } + +    for (std::size_t i = 0; i < request.data.size(); i++) { +        if (request.data[i].command == 0) { +            continue; +        } +        out_data.data[i].command = request.data[i].command; +        out_data.data[i].sector = request.data[i].sector; + +        const std::size_t sector_index = +            request.data[i].sector * sizeof(Common::Input::MifareData::data); + +        if (nfc_data.size() < sector_index + sizeof(Common::Input::MifareData::data)) { +            return Common::Input::NfcState::WriteFailed; +        } + +        // Ignore the sector key as we don't support it +        memcpy(out_data.data[i].data.data(), nfc_data.data() + sector_index, +               sizeof(Common::Input::MifareData::data)); +    } + +    return Common::Input::NfcState::Success; +} + +Common::Input::NfcState VirtualAmiibo::WriteMifareData( +    const PadIdentifier& identifier_, const Common::Input::MifareRequest& request) { +    if (state != State::TagNearby) { +        return Common::Input::NfcState::WrongDeviceState; +    } + +    if (status.tag_type != 1U << 6) { +        return Common::Input::NfcState::InvalidTagType; +    } + +    for (std::size_t i = 0; i < request.data.size(); i++) { +        if (request.data[i].command == 0) { +            continue; +        } + +        const std::size_t sector_index = +            request.data[i].sector * sizeof(Common::Input::MifareData::data); + +        if (nfc_data.size() < sector_index + sizeof(Common::Input::MifareData::data)) { +            return Common::Input::NfcState::WriteFailed; +        } + +        // Ignore the sector key as we don't support it +        memcpy(nfc_data.data() + sector_index, request.data[i].data.data(), +               sizeof(Common::Input::MifareData::data)); +    } + +    return Common::Input::NfcState::Success; +} +  VirtualAmiibo::State VirtualAmiibo::GetCurrentState() const {      return state;  } @@ -112,23 +207,31 @@ VirtualAmiibo::Info VirtualAmiibo::LoadAmiibo(std::span<u8> data) {      case AmiiboSizeWithoutPassword:      case AmiiboSizeWithSignature:          nfc_data.resize(AmiiboSize); +        status.tag_type = 1U << 1; +        status.uuid_length = 7;          break;      case MifareSize:          nfc_data.resize(MifareSize); +        status.tag_type = 1U << 6; +        status.uuid_length = 4;          break;      default:          return Info::NotAnAmiibo;      } -    state = State::AmiiboIsOpen; +    status.uuid = {}; +    status.protocol = 1; +    state = State::TagNearby; +    status.state = Common::Input::NfcState::NewAmiibo,      memcpy(nfc_data.data(), data.data(), data.size_bytes()); -    SetNfc(identifier, {Common::Input::NfcState::NewAmiibo, nfc_data}); +    memcpy(status.uuid.data(), nfc_data.data(), status.uuid_length); +    SetNfc(identifier, status);      return Info::Success;  }  VirtualAmiibo::Info VirtualAmiibo::ReloadAmiibo() { -    if (state == State::AmiiboIsOpen) { -        SetNfc(identifier, {Common::Input::NfcState::NewAmiibo, nfc_data}); +    if (state == State::TagNearby) { +        SetNfc(identifier, status);          return Info::Success;      } @@ -136,9 +239,14 @@ VirtualAmiibo::Info VirtualAmiibo::ReloadAmiibo() {  }  VirtualAmiibo::Info VirtualAmiibo::CloseAmiibo() { -    state = polling_mode == Common::Input::PollingMode::NFC ? State::WaitingForAmiibo -                                                            : State::Initialized; -    SetNfc(identifier, {Common::Input::NfcState::AmiiboRemoved, {}}); +    if (state != State::TagNearby) { +        return Info::Success; +    } + +    state = State::WaitingForAmiibo; +    status.state = Common::Input::NfcState::AmiiboRemoved; +    SetNfc(identifier, status); +    status.tag_type = 0;      return Info::Success;  } diff --git a/src/input_common/drivers/virtual_amiibo.h b/src/input_common/drivers/virtual_amiibo.h index 09ca09e68..490f38e05 100644 --- a/src/input_common/drivers/virtual_amiibo.h +++ b/src/input_common/drivers/virtual_amiibo.h @@ -20,9 +20,10 @@ namespace InputCommon {  class VirtualAmiibo final : public InputEngine {  public:      enum class State { +        Disabled,          Initialized,          WaitingForAmiibo, -        AmiiboIsOpen, +        TagNearby,      };      enum class Info { @@ -41,9 +42,17 @@ public:          const PadIdentifier& identifier_, const Common::Input::PollingMode polling_mode_) override;      Common::Input::NfcState SupportsNfc(const PadIdentifier& identifier_) const override; - +    Common::Input::NfcState StartNfcPolling(const PadIdentifier& identifier_) override; +    Common::Input::NfcState StopNfcPolling(const PadIdentifier& identifier_) override; +    Common::Input::NfcState ReadAmiiboData(const PadIdentifier& identifier_, +                                           std::vector<u8>& out_data) override;      Common::Input::NfcState WriteNfcData(const PadIdentifier& identifier_,                                           const std::vector<u8>& data) override; +    Common::Input::NfcState ReadMifareData(const PadIdentifier& identifier_, +                                           const Common::Input::MifareRequest& data, +                                           Common::Input::MifareRequest& out_data) override; +    Common::Input::NfcState WriteMifareData(const PadIdentifier& identifier_, +                                            const Common::Input::MifareRequest& data) override;      State GetCurrentState() const; @@ -61,8 +70,9 @@ private:      static constexpr std::size_t MifareSize = 0x400;      std::string file_path{}; -    State state{State::Initialized}; +    State state{State::Disabled};      std::vector<u8> nfc_data; +    Common::Input::NfcStatus status;      Common::Input::PollingMode polling_mode{Common::Input::PollingMode::Passive};  };  } // namespace InputCommon  | 
