input_common, common: Add a few functions
These functions include reloading udp client, testing communication and configuring calibration. I also added a function to common/thread.h to use WaitFor.
This commit is contained in:
parent
58639220a0
commit
8af89b6979
7 changed files with 153 additions and 7 deletions
|
@ -55,6 +55,15 @@ public:
|
||||||
is_set = false;
|
is_set = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class Duration>
|
||||||
|
bool WaitFor(const std::chrono::duration<Duration>& time) {
|
||||||
|
std::unique_lock<std::mutex> lk(mutex);
|
||||||
|
if (!condvar.wait_for(lk, time, [this] { return is_set; }))
|
||||||
|
return false;
|
||||||
|
is_set = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
template <class Clock, class Duration>
|
template <class Clock, class Duration>
|
||||||
bool WaitUntil(const std::chrono::time_point<Clock, Duration>& time) {
|
bool WaitUntil(const std::chrono::time_point<Clock, Duration>& time) {
|
||||||
std::unique_lock<std::mutex> lk(mutex);
|
std::unique_lock<std::mutex> lk(mutex);
|
||||||
|
|
|
@ -76,6 +76,11 @@ std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left,
|
||||||
return circle_pad_param.Serialize();
|
return circle_pad_param.Serialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ReloadInputDevices() {
|
||||||
|
if (udp)
|
||||||
|
udp->ReloadUDPClient();
|
||||||
|
}
|
||||||
|
|
||||||
namespace Polling {
|
namespace Polling {
|
||||||
|
|
||||||
std::vector<std::unique_ptr<DevicePoller>> GetPollers(DeviceType type) {
|
std::vector<std::unique_ptr<DevicePoller>> GetPollers(DeviceType type) {
|
||||||
|
|
|
@ -37,6 +37,9 @@ std::string GenerateKeyboardParam(int key_code);
|
||||||
std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left, int key_right,
|
std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left, int key_right,
|
||||||
int key_modifier, float modifier_scale);
|
int key_modifier, float modifier_scale);
|
||||||
|
|
||||||
|
/// Reloads the input devices
|
||||||
|
void ReloadInputDevices();
|
||||||
|
|
||||||
namespace Polling {
|
namespace Polling {
|
||||||
|
|
||||||
enum class DeviceType { Button, Analog };
|
enum class DeviceType { Button, Analog };
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
#include <boost/bind.hpp>
|
#include <boost/bind.hpp>
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/vector_math.h"
|
|
||||||
#include "input_common/udp/client.h"
|
#include "input_common/udp/client.h"
|
||||||
#include "input_common/udp/protocol.h"
|
#include "input_common/udp/protocol.h"
|
||||||
|
|
||||||
|
@ -128,12 +127,7 @@ static void SocketLoop(Socket* socket) {
|
||||||
Client::Client(std::shared_ptr<DeviceStatus> status, const std::string& host, u16 port,
|
Client::Client(std::shared_ptr<DeviceStatus> status, const std::string& host, u16 port,
|
||||||
u8 pad_index, u32 client_id)
|
u8 pad_index, u32 client_id)
|
||||||
: status(status) {
|
: status(status) {
|
||||||
SocketCallback callback{[this](Response::Version version) { OnVersion(version); },
|
StartCommunication(host, port, pad_index, client_id);
|
||||||
[this](Response::PortInfo info) { OnPortInfo(info); },
|
|
||||||
[this](Response::PadData data) { OnPadData(data); }};
|
|
||||||
LOG_INFO(Input, "Starting communication with UDP input server on {}:{}", host, port);
|
|
||||||
socket = std::make_unique<Socket>(host, port, pad_index, client_id, callback);
|
|
||||||
thread = std::thread{SocketLoop, this->socket.get()};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Client::~Client() {
|
Client::~Client() {
|
||||||
|
@ -141,6 +135,12 @@ Client::~Client() {
|
||||||
thread.join();
|
thread.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Client::ReloadSocket(const std::string& host, u16 port, u8 pad_index, u32 client_id) {
|
||||||
|
socket->Stop();
|
||||||
|
thread.join();
|
||||||
|
StartCommunication(host, port, pad_index, client_id);
|
||||||
|
}
|
||||||
|
|
||||||
void Client::OnVersion(Response::Version data) {
|
void Client::OnVersion(Response::Version data) {
|
||||||
LOG_TRACE(Input, "Version packet received: {}", data.version);
|
LOG_TRACE(Input, "Version packet received: {}", data.version);
|
||||||
}
|
}
|
||||||
|
@ -192,4 +192,93 @@ void Client::OnPadData(Response::PadData data) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Client::StartCommunication(const std::string& host, u16 port, u8 pad_index, u32 client_id) {
|
||||||
|
SocketCallback callback{[this](Response::Version version) { OnVersion(version); },
|
||||||
|
[this](Response::PortInfo info) { OnPortInfo(info); },
|
||||||
|
[this](Response::PadData data) { OnPadData(data); }};
|
||||||
|
LOG_INFO(Input, "Starting communication with UDP input server on {}:{}", host, port);
|
||||||
|
socket = std::make_unique<Socket>(host, port, pad_index, client_id, callback);
|
||||||
|
thread = std::thread{SocketLoop, this->socket.get()};
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestCommunication(const std::string& host, u16 port, u8 pad_index, u32 client_id,
|
||||||
|
std::function<void()> success_callback,
|
||||||
|
std::function<void()> failure_callback) {
|
||||||
|
std::thread([=] {
|
||||||
|
Common::Event success_event;
|
||||||
|
SocketCallback callback{[](Response::Version version) {}, [](Response::PortInfo info) {},
|
||||||
|
[&](Response::PadData data) { success_event.Set(); }};
|
||||||
|
Socket socket{host, port, pad_index, client_id, callback};
|
||||||
|
std::thread worker_thread{SocketLoop, &socket};
|
||||||
|
bool result = success_event.WaitFor(std::chrono::seconds(8));
|
||||||
|
socket.Stop();
|
||||||
|
worker_thread.join();
|
||||||
|
if (result)
|
||||||
|
success_callback();
|
||||||
|
else
|
||||||
|
failure_callback();
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
CalibrationConfigurationJob::CalibrationConfigurationJob(
|
||||||
|
const std::string& host, u16 port, u8 pad_index, u32 client_id,
|
||||||
|
std::function<void(Status)> status_callback,
|
||||||
|
std::function<void(u16, u16, u16, u16)> data_callback) {
|
||||||
|
|
||||||
|
std::thread([=] {
|
||||||
|
constexpr u16 CALIBRATION_THRESHOLD = 100;
|
||||||
|
|
||||||
|
u16 min_x{UINT16_MAX}, min_y{UINT16_MAX};
|
||||||
|
u16 max_x, max_y;
|
||||||
|
|
||||||
|
Status current_status{Status::Initialized};
|
||||||
|
SocketCallback callback{[](Response::Version version) {}, [](Response::PortInfo info) {},
|
||||||
|
[&](Response::PadData data) {
|
||||||
|
if (current_status == Status::Initialized) {
|
||||||
|
// Receiving data means the communication is ready now
|
||||||
|
current_status = Status::Ready;
|
||||||
|
status_callback(current_status);
|
||||||
|
}
|
||||||
|
if (!data.touch_1.is_active)
|
||||||
|
return;
|
||||||
|
LOG_DEBUG(Input, "Current touch: {} {}", data.touch_1.x,
|
||||||
|
data.touch_1.y);
|
||||||
|
min_x = std::min(min_x, static_cast<u16>(data.touch_1.x));
|
||||||
|
min_y = std::min(min_y, static_cast<u16>(data.touch_1.y));
|
||||||
|
if (current_status == Status::Ready) {
|
||||||
|
// First touch - min data (min_x/min_y)
|
||||||
|
current_status = Status::Stage1Completed;
|
||||||
|
status_callback(current_status);
|
||||||
|
}
|
||||||
|
if (data.touch_1.x - min_x > CALIBRATION_THRESHOLD &&
|
||||||
|
data.touch_1.y - min_y > CALIBRATION_THRESHOLD) {
|
||||||
|
// Set the current position as max value and finishes
|
||||||
|
// configuration
|
||||||
|
max_x = data.touch_1.x;
|
||||||
|
max_y = data.touch_1.y;
|
||||||
|
current_status = Status::Completed;
|
||||||
|
data_callback(min_x, min_y, max_x, max_y);
|
||||||
|
status_callback(current_status);
|
||||||
|
|
||||||
|
complete_event.Set();
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
Socket socket{host, port, pad_index, client_id, callback};
|
||||||
|
std::thread worker_thread{SocketLoop, &socket};
|
||||||
|
complete_event.Wait();
|
||||||
|
socket.Stop();
|
||||||
|
worker_thread.join();
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
CalibrationConfigurationJob::~CalibrationConfigurationJob() {
|
||||||
|
Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CalibrationConfigurationJob::Stop() {
|
||||||
|
complete_event.Set();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace InputCommon::CemuhookUDP
|
} // namespace InputCommon::CemuhookUDP
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "common/thread.h"
|
||||||
#include "common/vector_math.h"
|
#include "common/vector_math.h"
|
||||||
|
|
||||||
namespace InputCommon::CemuhookUDP {
|
namespace InputCommon::CemuhookUDP {
|
||||||
|
@ -47,15 +48,48 @@ public:
|
||||||
explicit Client(std::shared_ptr<DeviceStatus> status, const std::string& host = DEFAULT_ADDR,
|
explicit Client(std::shared_ptr<DeviceStatus> status, const std::string& host = DEFAULT_ADDR,
|
||||||
u16 port = DEFAULT_PORT, u8 pad_index = 0, u32 client_id = 24872);
|
u16 port = DEFAULT_PORT, u8 pad_index = 0, u32 client_id = 24872);
|
||||||
~Client();
|
~Client();
|
||||||
|
void ReloadSocket(const std::string& host = "127.0.0.1", u16 port = 26760, u8 pad_index = 0,
|
||||||
|
u32 client_id = 24872);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void OnVersion(Response::Version);
|
void OnVersion(Response::Version);
|
||||||
void OnPortInfo(Response::PortInfo);
|
void OnPortInfo(Response::PortInfo);
|
||||||
void OnPadData(Response::PadData);
|
void OnPadData(Response::PadData);
|
||||||
|
void StartCommunication(const std::string& host, u16 port, u8 pad_index, u32 client_id);
|
||||||
|
|
||||||
std::unique_ptr<Socket> socket;
|
std::unique_ptr<Socket> socket;
|
||||||
std::shared_ptr<DeviceStatus> status;
|
std::shared_ptr<DeviceStatus> status;
|
||||||
std::thread thread;
|
std::thread thread;
|
||||||
u64 packet_sequence = 0;
|
u64 packet_sequence = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// An async job allowing configuration of the touchpad calibration.
|
||||||
|
class CalibrationConfigurationJob {
|
||||||
|
public:
|
||||||
|
enum class Status {
|
||||||
|
Initialized,
|
||||||
|
Ready,
|
||||||
|
Stage1Completed,
|
||||||
|
Completed,
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Constructs and starts the job with the specified parameter.
|
||||||
|
*
|
||||||
|
* @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, u8 pad_index,
|
||||||
|
u32 client_id, std::function<void(Status)> status_callback,
|
||||||
|
std::function<void(u16, u16, u16, u16)> data_callback);
|
||||||
|
~CalibrationConfigurationJob();
|
||||||
|
void Stop();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Common::Event complete_event;
|
||||||
|
};
|
||||||
|
|
||||||
|
void TestCommunication(const std::string& host, u16 port, u8 pad_index, u32 client_id,
|
||||||
|
std::function<void()> success_callback,
|
||||||
|
std::function<void()> failure_callback);
|
||||||
|
|
||||||
} // namespace InputCommon::CemuhookUDP
|
} // namespace InputCommon::CemuhookUDP
|
||||||
|
|
|
@ -85,6 +85,11 @@ State::~State() {
|
||||||
Input::UnregisterFactory<Input::MotionDevice>("cemuhookudp");
|
Input::UnregisterFactory<Input::MotionDevice>("cemuhookudp");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void State::ReloadUDPClient() {
|
||||||
|
client->ReloadSocket(Settings::values.udp_input_address, Settings::values.udp_input_port,
|
||||||
|
Settings::values.udp_pad_index);
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<State> Init() {
|
std::unique_ptr<State> Init() {
|
||||||
return std::make_unique<State>();
|
return std::make_unique<State>();
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ class State {
|
||||||
public:
|
public:
|
||||||
State();
|
State();
|
||||||
~State();
|
~State();
|
||||||
|
void ReloadUDPClient();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<Client> client;
|
std::unique_ptr<Client> client;
|
||||||
|
|
Loading…
Reference in a new issue