diff options
Diffstat (limited to 'src/input_common')
| -rw-r--r-- | src/input_common/udp/client.cpp | 147 | ||||
| -rw-r--r-- | src/input_common/udp/client.h | 44 | 
2 files changed, 96 insertions, 95 deletions
diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp index df73f9ff7..e72df924b 100644 --- a/src/input_common/udp/client.cpp +++ b/src/input_common/udp/client.cpp @@ -27,11 +27,9 @@ class Socket {  public:      using clock = std::chrono::system_clock; -    explicit Socket(const std::string& host, u16 port, std::size_t pad_index_, -                    SocketCallback callback_) +    explicit Socket(const std::string& host, u16 port, SocketCallback callback_)          : callback(std::move(callback_)), timer(io_service), -          socket(io_service, udp::endpoint(udp::v4(), 0)), client_id(GenerateRandomClientId()), -          pad_index(pad_index_) { +          socket(io_service, udp::endpoint(udp::v4(), 0)), client_id(GenerateRandomClientId()) {          boost::system::error_code ec{};          auto ipv4 = boost::asio::ip::make_address_v4(host, ec);          if (ec.value() != boost::system::errc::success) { @@ -99,15 +97,15 @@ private:      void HandleSend(const boost::system::error_code&) {          boost::system::error_code _ignored{};          // Send a request for getting port info for the pad -        const Request::PortInfo port_info{1, {static_cast<u8>(pad_index), 0, 0, 0}}; +        const Request::PortInfo port_info{4, {0, 1, 2, 3}};          const auto port_message = Request::Create(port_info, client_id);          std::memcpy(&send_buffer1, &port_message, PORT_INFO_SIZE);          socket.send_to(boost::asio::buffer(send_buffer1), send_endpoint, {}, _ignored);          // Send a request for getting pad data for the pad          const Request::PadData pad_data{ -            Request::PadData::Flags::Id, -            static_cast<u8>(pad_index), +            Request::PadData::Flags::AllPorts, +            0,              EMPTY_MAC_ADDRESS,          };          const auto pad_message = Request::Create(pad_data, client_id); @@ -122,7 +120,6 @@ private:      udp::socket socket;      const u32 client_id; -    std::size_t pad_index{};      static constexpr std::size_t PORT_INFO_SIZE = sizeof(Message<Request::PortInfo>);      static constexpr std::size_t PAD_DATA_SIZE = sizeof(Message<Request::PadData>); @@ -150,34 +147,32 @@ Client::~Client() {      Reset();  } -Client::ClientData::ClientData() = default; +Client::ClientConnection::ClientConnection() = default; -Client::ClientData::~ClientData() = default; +Client::ClientConnection::~ClientConnection() = default;  std::vector<Common::ParamPackage> Client::GetInputDevices() const {      std::vector<Common::ParamPackage> devices; -    for (std::size_t client = 0; client < clients.size(); client++) { -        if (!DeviceConnected(client)) { +    for (std::size_t pad = 0; pad < pads.size(); pad++) { +        if (!DeviceConnected(pad)) {              continue;          } -        std::string name = fmt::format("UDP Controller {}", client); +        std::string name = fmt::format("UDP Controller {}", pad);          devices.emplace_back(Common::ParamPackage{              {"class", "cemuhookudp"},              {"display", std::move(name)}, -            {"port", std::to_string(client)}, +            {"port", std::to_string(pad)},          });      }      return devices;  } -bool Client::DeviceConnected(std::size_t client) const { +bool Client::DeviceConnected(std::size_t pad) const {      // Use last timestamp to detect if the socket has stopped sending data      const auto now = std::chrono::steady_clock::now(); -    const auto time_difference = -        static_cast<u64>(std::chrono::duration_cast<std::chrono::milliseconds>( -                             now - clients[client].last_motion_update) -                             .count()); -    return time_difference < 1000 && clients[client].active == 1; +    const auto time_difference = static_cast<u64>( +        std::chrono::duration_cast<std::chrono::milliseconds>(now - pads[pad].last_update).count()); +    return time_difference < 1000 && pads[pad].connected;  }  void Client::ReloadSockets() { @@ -202,25 +197,21 @@ void Client::ReloadSockets() {              continue;          } -        for (std::size_t pad = 0; pad < 4; ++pad) { -            const std::size_t client_number = -                GetClientNumber(udp_input_address, udp_input_port, pad); -            if (client_number != MAX_UDP_CLIENTS) { -                LOG_ERROR(Input, "Duplicated UDP servers found"); -                continue; -            } -            StartCommunication(client++, udp_input_address, udp_input_port, pad); +        const std::size_t client_number = GetClientNumber(udp_input_address, udp_input_port); +        if (client_number != MAX_UDP_CLIENTS) { +            LOG_ERROR(Input, "Duplicated UDP servers found"); +            continue;          } +        StartCommunication(client++, udp_input_address, udp_input_port);      }  } -std::size_t Client::GetClientNumber(std::string_view host, u16 port, std::size_t pad) const { +std::size_t Client::GetClientNumber(std::string_view host, u16 port) const {      for (std::size_t client = 0; client < clients.size(); client++) {          if (clients[client].active == -1) {              continue;          } -        if (clients[client].host == host && clients[client].port == port && -            clients[client].pad_index == pad) { +        if (clients[client].host == host && clients[client].port == port) {              return client;          }      } @@ -236,69 +227,75 @@ void Client::OnPortInfo([[maybe_unused]] Response::PortInfo data) {  }  void Client::OnPadData(Response::PadData data, std::size_t client) { -    // Accept packets only for the correct pad -    if (static_cast<u8>(clients[client].pad_index) != data.info.id) { +    const std::size_t pad_index = (client * PADS_PER_CLIENT) + data.info.id; + +    if (pad_index >= pads.size()) { +        LOG_ERROR(Input, "Invalid pad id {}", data.info.id);          return;      }      LOG_TRACE(Input, "PadData packet received"); -    if (data.packet_counter == clients[client].packet_sequence) { +    if (data.packet_counter == pads[pad_index].packet_sequence) {          LOG_WARNING(              Input,              "PadData packet dropped because its stale info. Current count: {} Packet count: {}", -            clients[client].packet_sequence, data.packet_counter); +            pads[pad_index].packet_sequence, data.packet_counter); +        pads[pad_index].connected = false;          return;      } -    clients[client].active = static_cast<s8>(data.info.is_pad_active); -    clients[client].packet_sequence = data.packet_counter; + +    clients[client].active = 1; +    pads[pad_index].connected = true; +    pads[pad_index].packet_sequence = data.packet_counter; +      const auto now = std::chrono::steady_clock::now(); -    const auto time_difference = -        static_cast<u64>(std::chrono::duration_cast<std::chrono::microseconds>( -                             now - clients[client].last_motion_update) -                             .count()); -    clients[client].last_motion_update = now; +    const auto time_difference = static_cast<u64>( +        std::chrono::duration_cast<std::chrono::microseconds>(now - pads[pad_index].last_update) +            .count()); +    pads[pad_index].last_update = now; +      const Common::Vec3f raw_gyroscope = {data.gyro.pitch, data.gyro.roll, -data.gyro.yaw}; -    clients[client].motion.SetAcceleration({data.accel.x, -data.accel.z, data.accel.y}); +    pads[pad_index].motion.SetAcceleration({data.accel.x, -data.accel.z, data.accel.y});      // Gyroscope values are not it the correct scale from better joy.      // Dividing by 312 allows us to make one full turn = 1 turn      // This must be a configurable valued called sensitivity -    clients[client].motion.SetGyroscope(raw_gyroscope / 312.0f); -    clients[client].motion.UpdateRotation(time_difference); -    clients[client].motion.UpdateOrientation(time_difference); +    pads[pad_index].motion.SetGyroscope(raw_gyroscope / 312.0f); +    pads[pad_index].motion.UpdateRotation(time_difference); +    pads[pad_index].motion.UpdateOrientation(time_difference);      { -        std::lock_guard guard(clients[client].status.update_mutex); -        clients[client].status.motion_status = clients[client].motion.GetMotion(); +        std::lock_guard guard(pads[pad_index].status.update_mutex); +        pads[pad_index].status.motion_status = pads[pad_index].motion.GetMotion();          for (std::size_t id = 0; id < data.touch.size(); ++id) {              UpdateTouchInput(data.touch[id], client, id);          }          if (configuring) { -            const Common::Vec3f gyroscope = clients[client].motion.GetGyroscope(); -            const Common::Vec3f accelerometer = clients[client].motion.GetAcceleration(); -            UpdateYuzuSettings(client, accelerometer, gyroscope); +            const Common::Vec3f gyroscope = pads[pad_index].motion.GetGyroscope(); +            const Common::Vec3f accelerometer = pads[pad_index].motion.GetAcceleration(); +            UpdateYuzuSettings(client, data.info.id, accelerometer, gyroscope);          }      }  } -void Client::StartCommunication(std::size_t client, const std::string& host, u16 port, -                                std::size_t pad_index) { +void Client::StartCommunication(std::size_t client, const std::string& host, u16 port) {      SocketCallback callback{[this](Response::Version version) { OnVersion(version); },                              [this](Response::PortInfo info) { OnPortInfo(info); },                              [this, client](Response::PadData data) { OnPadData(data, client); }}; -    LOG_INFO(Input, "Starting communication with UDP input server on {}:{}:{}", host, port, -             pad_index); +    LOG_INFO(Input, "Starting communication with UDP input server on {}:{}", host, port);      clients[client].host = host;      clients[client].port = port; -    clients[client].pad_index = pad_index;      clients[client].active = 0; -    clients[client].socket = std::make_unique<Socket>(host, port, pad_index, callback); +    clients[client].socket = std::make_unique<Socket>(host, port, callback);      clients[client].thread = std::thread{SocketLoop, clients[client].socket.get()}; +      // Set motion parameters      // SetGyroThreshold value should be dependent on GyroscopeZeroDriftMode      // Real HW values are unknown, 0.0001 is an approximate to Standard -    clients[client].motion.SetGyroThreshold(0.0001f); +    for (std::size_t pad = 0; pad < PADS_PER_CLIENT; pad++) { +        pads[client * PADS_PER_CLIENT + pad].motion.SetGyroThreshold(0.0001f); +    }  }  void Client::Reset() { @@ -311,8 +308,8 @@ void Client::Reset() {      }  } -void Client::UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc, -                                const Common::Vec3<float>& gyro) { +void Client::UpdateYuzuSettings(std::size_t client, std::size_t pad_index, +                                const Common::Vec3<float>& acc, const Common::Vec3<float>& gyro) {      if (gyro.Length() > 0.2f) {          LOG_DEBUG(Input, "UDP Controller {}: gyro=({}, {}, {}), accel=({}, {}, {})", client,                    gyro[0], gyro[1], gyro[2], acc[0], acc[1], acc[2]); @@ -320,7 +317,7 @@ void Client::UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& a      UDPPadStatus pad{          .host = clients[client].host,          .port = clients[client].port, -        .pad_index = clients[client].pad_index, +        .pad_index = pad_index,      };      for (std::size_t i = 0; i < 3; ++i) {          if (gyro[i] > 5.0f || gyro[i] < -5.0f) { @@ -391,19 +388,19 @@ void Client::EndConfiguration() {  }  DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) { -    const std::size_t client_number = GetClientNumber(host, port, pad); -    if (client_number == MAX_UDP_CLIENTS) { -        return clients[0].status; +    const std::size_t client_number = GetClientNumber(host, port); +    if (client_number == MAX_UDP_CLIENTS || pad >= PADS_PER_CLIENT) { +        return pads[0].status;      } -    return clients[client_number].status; +    return pads[(client_number * PADS_PER_CLIENT) + pad].status;  }  const DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) const { -    const std::size_t client_number = GetClientNumber(host, port, pad); -    if (client_number == MAX_UDP_CLIENTS) { -        return clients[0].status; +    const std::size_t client_number = GetClientNumber(host, port); +    if (client_number == MAX_UDP_CLIENTS || pad >= PADS_PER_CLIENT) { +        return pads[0].status;      } -    return clients[client_number].status; +    return pads[(client_number * PADS_PER_CLIENT) + pad].status;  }  Input::TouchStatus& Client::GetTouchState() { @@ -422,7 +419,7 @@ const Common::SPSCQueue<UDPPadStatus>& Client::GetPadQueue() const {      return pad_queue;  } -void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, +void TestCommunication(const std::string& host, u16 port,                         const std::function<void()>& success_callback,                         const std::function<void()>& failure_callback) {      std::thread([=] { @@ -432,9 +429,10 @@ void TestCommunication(const std::string& host, u16 port, std::size_t pad_index,              .port_info = [](Response::PortInfo) {},              .pad_data = [&](Response::PadData) { success_event.Set(); },          }; -        Socket socket{host, port, pad_index, std::move(callback)}; +        Socket socket{host, port, std::move(callback)};          std::thread worker_thread{SocketLoop, &socket}; -        const bool result = success_event.WaitFor(std::chrono::seconds(5)); +        const bool result = +            success_event.WaitUntil(std::chrono::steady_clock::now() + std::chrono::seconds(10));          socket.Stop();          worker_thread.join();          if (result) { @@ -446,8 +444,7 @@ void TestCommunication(const std::string& host, u16 port, std::size_t pad_index,  }  CalibrationConfigurationJob::CalibrationConfigurationJob( -    const std::string& host, u16 port, std::size_t pad_index, -    std::function<void(Status)> status_callback, +    const std::string& host, u16 port, std::function<void(Status)> status_callback,      std::function<void(u16, u16, u16, u16)> data_callback) {      std::thread([=, this] { @@ -491,7 +488,7 @@ CalibrationConfigurationJob::CalibrationConfigurationJob(                                          complete_event.Set();                                      }                                  }}; -        Socket socket{host, port, pad_index, std::move(callback)}; +        Socket socket{host, port, std::move(callback)};          std::thread worker_thread{SocketLoop, &socket};          complete_event.Wait();          socket.Stop(); diff --git a/src/input_common/udp/client.h b/src/input_common/udp/client.h index e9e438e88..a11ea3068 100644 --- a/src/input_common/udp/client.h +++ b/src/input_common/udp/client.h @@ -84,7 +84,7 @@ public:      std::vector<Common::ParamPackage> GetInputDevices() const; -    bool DeviceConnected(std::size_t client) const; +    bool DeviceConnected(std::size_t pad) const;      void ReloadSockets();      Common::SPSCQueue<UDPPadStatus>& GetPadQueue(); @@ -97,38 +97,40 @@ public:      const Input::TouchStatus& GetTouchState() const;  private: -    struct ClientData { -        ClientData(); -        ~ClientData(); - -        std::string host{"127.0.0.1"}; -        u16 port{26760}; +    struct PadData {          std::size_t pad_index{}; -        std::unique_ptr<Socket> socket; +        bool connected{};          DeviceStatus status; -        std::thread thread;          u64 packet_sequence{}; -        s8 active{-1};          // Realtime values          // motion is initalized with PID values for drift correction on joycons          InputCommon::MotionInput motion{0.3f, 0.005f, 0.0f}; -        std::chrono::time_point<std::chrono::steady_clock> last_motion_update; +        std::chrono::time_point<std::chrono::steady_clock> last_update; +    }; + +    struct ClientConnection { +        ClientConnection(); +        ~ClientConnection(); +        std::string host{"127.0.0.1"}; +        u16 port{26760}; +        s8 active{-1}; +        std::unique_ptr<Socket> socket; +        std::thread thread;      };      // For shutting down, clear all data, join all threads, release usb      void Reset();      // Translates configuration to client number -    std::size_t GetClientNumber(std::string_view host, u16 port, std::size_t pad) const; +    std::size_t GetClientNumber(std::string_view host, u16 port) const;      void OnVersion(Response::Version);      void OnPortInfo(Response::PortInfo);      void OnPadData(Response::PadData, std::size_t client); -    void StartCommunication(std::size_t client, const std::string& host, u16 port, -                            std::size_t pad_index); -    void UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc, -                            const Common::Vec3<float>& gyro); +    void StartCommunication(std::size_t client, const std::string& host, u16 port); +    void UpdateYuzuSettings(std::size_t client, std::size_t pad_index, +                            const Common::Vec3<float>& acc, const Common::Vec3<float>& gyro);      // Returns an unused finger id, if there is no fingers available std::nullopt will be      // returned @@ -140,10 +142,12 @@ private:      bool configuring = false;      // Allocate clients for 8 udp servers -    static constexpr std::size_t MAX_UDP_CLIENTS = 4 * 8; +    static constexpr std::size_t MAX_UDP_CLIENTS = 8; +    static constexpr std::size_t PADS_PER_CLIENT = 4;      // Each client can have up 2 touch inputs      static constexpr std::size_t MAX_TOUCH_FINGERS = MAX_UDP_CLIENTS * 2; -    std::array<ClientData, MAX_UDP_CLIENTS> clients{}; +    std::array<PadData, MAX_UDP_CLIENTS * PADS_PER_CLIENT> pads{}; +    std::array<ClientConnection, MAX_UDP_CLIENTS> clients{};      Common::SPSCQueue<UDPPadStatus> pad_queue{};      Input::TouchStatus touch_status{};      std::array<std::size_t, MAX_TOUCH_FINGERS> finger_id{}; @@ -164,7 +168,7 @@ public:       * @param status_callback Callback for job status updates       * @param data_callback Called when calibration data is ready       */ -    explicit CalibrationConfigurationJob(const std::string& host, u16 port, std::size_t pad_index, +    explicit CalibrationConfigurationJob(const std::string& host, u16 port,                                           std::function<void(Status)> status_callback,                                           std::function<void(u16, u16, u16, u16)> data_callback);      ~CalibrationConfigurationJob(); @@ -174,7 +178,7 @@ private:      Common::Event complete_event;  }; -void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, +void TestCommunication(const std::string& host, u16 port,                         const std::function<void()>& success_callback,                         const std::function<void()>& failure_callback);  | 
