Skip to content

Commit f785aa3

Browse files
committed
Try Qt socket for SBB.
1 parent e964679 commit f785aa3

File tree

5 files changed

+212
-34
lines changed

5 files changed

+212
-34
lines changed

Common/Cpp/Sockets/ClientSocket.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@
1010

1111

1212
#ifdef _WIN32
13-
#include "ClientSocket_WinSocket.h"
13+
//#include "ClientSocket_WinSocket.h"
14+
#include "ClientSocket_Qt.h"
1415
namespace PokemonAutomation{
15-
using ClientSocket = ClientSocket_WinSocket;
16+
// using ClientSocket = ClientSocket_WinSocket;
17+
using ClientSocket = ClientSocket_Qt;
1618
}
1719
#else
1820
#include "ClientSocket_POSIX.h"
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
/* Client Socket (Qt)
2+
*
3+
* From: https://github.com/PokemonAutomation/
4+
*
5+
*/
6+
7+
#ifndef PokemonAutomation_ClientSocket_Qt_H
8+
#define PokemonAutomation_ClientSocket_Qt_H
9+
10+
#include <mutex>
11+
#include <condition_variable>
12+
#include <QThread>
13+
#include <QTcpSocket>
14+
//#include "Common/Cpp/Concurrency/SpinPause.h"
15+
#include "AbstractClientSocket.h"
16+
17+
//#include <iostream>
18+
//using std::cout;
19+
//using std::endl;
20+
21+
namespace PokemonAutomation{
22+
23+
24+
25+
class ClientSocket_Qt final : public QThread, public AbstractClientSocket{
26+
Q_OBJECT
27+
28+
struct SendData{
29+
const void* data;
30+
size_t bytes;
31+
std::mutex lock;
32+
std::condition_variable cv;
33+
};
34+
35+
36+
public:
37+
ClientSocket_Qt()
38+
: m_socket(nullptr)
39+
{
40+
// cout << "ClientSocket_Qt()" << endl;
41+
start();
42+
43+
// cout << "ClientSocket_Qt() - waiting" << endl;
44+
std::unique_lock<std::mutex> lg(m_lock);
45+
m_cv.wait(lg, [this]{ return m_socket != nullptr; });
46+
}
47+
48+
virtual ~ClientSocket_Qt(){
49+
// cout << "~ClientSocket_Qt()" << endl;
50+
close();
51+
}
52+
virtual void close() noexcept override{
53+
// cout << "close()" << endl;
54+
m_state.store(State::DESTRUCTING, std::memory_order_release);
55+
quit();
56+
wait();
57+
}
58+
59+
virtual void connect(const std::string& address, uint16_t port) override{
60+
// cout << "connect()" << endl;
61+
emit internal_connect(address, port);
62+
}
63+
64+
virtual size_t blocking_send(const void* data, size_t bytes) override{
65+
// cout << "blocking_send() - start: " << std::string((const char*)data, bytes) << endl;
66+
67+
SendData send_data;
68+
send_data.data = data;
69+
send_data.bytes = bytes;
70+
71+
emit send(&send_data);
72+
73+
std::unique_lock<std::mutex> lg(send_data.lock);
74+
send_data.cv.wait(lg, [&]{
75+
return send_data.data == nullptr || m_socket == nullptr;
76+
});
77+
78+
// cout << "blocking_send() - end: " << std::string((const char*)data, bytes) << endl;
79+
return send_data.bytes;
80+
}
81+
82+
83+
signals:
84+
void internal_connect(const std::string& address, uint16_t port);
85+
void send(void* data);
86+
87+
private:
88+
virtual void run() override{
89+
QTcpSocket socket;
90+
91+
QThread::connect(
92+
&socket, &QTcpSocket::connected,
93+
&socket, [this]{
94+
// cout << "connected()" << endl;
95+
m_state.store(State::CONNECTED, std::memory_order_release);
96+
m_listeners.run_method_unique(&Listener::on_connect_finished, "");
97+
}
98+
);
99+
QThread::connect(
100+
&socket, &QTcpSocket::readyRead,
101+
&socket, [this]{
102+
// cout << "readyRead()" << endl;
103+
constexpr size_t BUFFER_SIZE = 4096;
104+
char buffer[BUFFER_SIZE];
105+
qint64 bytes = m_socket->read(buffer, BUFFER_SIZE);
106+
if (bytes > 0){
107+
// cout << "Received: " << std::string(buffer, bytes) << endl;
108+
m_listeners.run_method_unique(&Listener::on_receive_data, buffer, bytes);
109+
}
110+
}
111+
);
112+
QThread::connect(
113+
this, &ClientSocket_Qt::internal_connect,
114+
&socket, [this](const std::string& address, uint16_t port){
115+
m_state.store(State::CONNECTING, std::memory_order_release);
116+
m_socket->connectToHost(QHostAddress(QString::fromStdString(address)), port);
117+
}
118+
);
119+
QThread::connect(
120+
this, &ClientSocket_Qt::send,
121+
&socket, [this](void* params){
122+
// cout << "internal_send() - enter " << endl;
123+
124+
SendData& data = *(SendData*)params;
125+
size_t sent = 0;
126+
127+
size_t bytes = data.bytes;
128+
129+
const char* ptr = (const char*)data.data;
130+
while (bytes > 0 && m_socket->state() == QAbstractSocket::ConnectedState){
131+
qint64 current_sent = m_socket->write((const char*)ptr, bytes);
132+
if (current_sent <= 0){
133+
break;
134+
}
135+
sent += current_sent;
136+
ptr += current_sent;
137+
bytes -= current_sent;
138+
data.bytes = sent;
139+
}
140+
141+
m_socket->flush();
142+
143+
std::lock_guard<std::mutex> lg(data.lock);
144+
data.data = nullptr;
145+
data.bytes = sent;
146+
data.cv.notify_all();
147+
148+
// cout << "internal_send() - exit " << endl;
149+
}
150+
);
151+
152+
153+
{
154+
std::lock_guard<std::mutex> lg(m_lock);
155+
m_socket = &socket;
156+
}
157+
m_cv.notify_all();
158+
159+
exec();
160+
161+
{
162+
std::lock_guard<std::mutex> lg(m_lock);
163+
m_socket = nullptr;
164+
}
165+
m_cv.notify_all();
166+
}
167+
168+
private:
169+
std::mutex m_lock;
170+
std::condition_variable m_cv;
171+
QTcpSocket* m_socket;
172+
};
173+
174+
175+
176+
177+
178+
}
179+
#endif

SerialPrograms/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ file(GLOB MAIN_SOURCES
193193
../Common/Cpp/Sockets/ClientSocket.cpp
194194
../Common/Cpp/Sockets/ClientSocket.h
195195
../Common/Cpp/Sockets/ClientSocket_POSIX.h
196+
../Common/Cpp/Sockets/ClientSocket_Qt.h
196197
../Common/Cpp/Sockets/ClientSocket_WinSocket.h
197198
../Common/Cpp/StreamConverters.cpp
198199
../Common/Cpp/StreamConverters.h

SerialPrograms/Source/NintendoSwitch/Controllers/SysbotBase/SysbotBase_Connection.cpp

Lines changed: 25 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ TcpSysbotBase_Connection::TcpSysbotBase_Connection(
4949
)
5050
: m_logger(logger)
5151
, m_supports_command_queue(false)
52-
, m_last_receive(WallClock::min())
52+
, m_last_ping_send(WallClock::min())
53+
, m_last_ping_receive(WallClock::min())
5354
{
5455
QHostAddress address;
5556
int port;
@@ -122,7 +123,7 @@ std::string pretty_print(uint64_t x){
122123

123124
void TcpSysbotBase_Connection::thread_loop(){
124125
std::unique_lock<std::mutex> lg(m_lock);
125-
WallClock send_time = current_time();
126+
m_last_ping_send = current_time();
126127
while (true){
127128
ClientSocket::State state = m_socket.state();
128129
if (state == ClientSocket::State::DESTRUCTING || state == ClientSocket::State::NOT_RUNNING){
@@ -131,30 +132,14 @@ void TcpSysbotBase_Connection::thread_loop(){
131132

132133
WallClock now = current_time();
133134

134-
if (m_last_receive == WallClock::min()){
135-
send_time = now;
136-
write_data("getVersion\r\n");
137-
}else if (send_time < m_last_receive && now - m_last_receive < std::chrono::seconds(1)){
138-
std::chrono::microseconds latency = std::chrono::duration_cast<std::chrono::microseconds>(m_last_receive - send_time);
139-
std::string str = "Response Time: " + pretty_print(latency.count()) + " ms";
140-
if (latency < 10ms){
141-
set_status_line1(str, COLOR_BLUE);
142-
}else if (latency < 50ms){
143-
set_status_line1(str, COLOR_DARKGREEN);
144-
}else{
145-
set_status_line1(str, COLOR_ORANGE);
146-
}
147-
send_time = current_time();
148-
write_data("getVersion\r\n");
149-
// cout << std::chrono::duration_cast<std::chrono::microseconds>(current_time() - send_time) << endl;
150-
}else{
151-
std::chrono::milliseconds time_since = std::chrono::duration_cast<std::chrono::milliseconds>(now - m_last_receive);
135+
std::chrono::milliseconds time_since = std::chrono::duration_cast<std::chrono::milliseconds>(now - m_last_ping_receive);
136+
if (time_since > std::chrono::seconds(5)){
152137
std::string str = "Last Ack: " + pretty_print(time_since.count()) + " seconds ago";
153138
set_status_line1(str, COLOR_RED);
154-
send_time = current_time();
155-
write_data("getVersion\r\n");
156-
// cout << std::chrono::duration_cast<std::chrono::microseconds>(current_time() - send_time) << endl;
157139
}
140+
141+
m_last_ping_send = current_time();
142+
write_data("getVersion\r\n");
158143
m_cv.wait_for(lg, std::chrono::seconds(1));
159144
}
160145
}
@@ -185,11 +170,6 @@ void TcpSysbotBase_Connection::on_receive_data(const void* data, size_t bytes){
185170
// cout << "on_receive_data(): " << std::string((const char*)data, bytes - 2) << endl;
186171

187172
WallClock now = current_time();
188-
{
189-
std::lock_guard<std::mutex> lg(m_lock);
190-
m_last_receive = now;
191-
}
192-
193173

194174
try{
195175
const char* ptr = (const char*)data;
@@ -206,7 +186,8 @@ void TcpSysbotBase_Connection::on_receive_data(const void* data, size_t bytes){
206186
std::string(
207187
m_receive_buffer.begin(),
208188
m_receive_buffer.end()
209-
)
189+
),
190+
now
210191
);
211192
m_receive_buffer.clear();
212193
}
@@ -215,7 +196,7 @@ void TcpSysbotBase_Connection::on_receive_data(const void* data, size_t bytes){
215196

216197
}catch (...){}
217198
}
218-
void TcpSysbotBase_Connection::process_message(const std::string& message){
199+
void TcpSysbotBase_Connection::process_message(const std::string& message, WallClock timestamp){
219200
// cout << "sys-botbase Response: " << message << endl;
220201

221202
m_listeners.run_method_unique(&Listener::on_message, message);
@@ -229,6 +210,20 @@ void TcpSysbotBase_Connection::process_message(const std::string& message){
229210
set_status_line0("sys-botbase: Version " + str, COLOR_BLUE);
230211

231212
std::lock_guard<std::mutex> lg(m_lock);
213+
m_last_ping_receive = timestamp;
214+
215+
if (m_last_ping_send != WallClock::min()){
216+
std::chrono::microseconds latency = std::chrono::duration_cast<std::chrono::microseconds>(timestamp - m_last_ping_send);
217+
std::string text = "Response Time: " + pretty_print(latency.count()) + " ms";
218+
if (latency < 10ms){
219+
set_status_line1(text, COLOR_BLUE);
220+
}else if (latency < 50ms){
221+
set_status_line1(text, COLOR_DARKGREEN);
222+
}else{
223+
set_status_line1(text, COLOR_ORANGE);
224+
}
225+
}
226+
232227
if (!m_thread.joinable()){
233228
set_mode(str);
234229
}

SerialPrograms/Source/NintendoSwitch/Controllers/SysbotBase/SysbotBase_Connection.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ class TcpSysbotBase_Connection : public ControllerConnection, private ClientSock
5555
virtual void on_connect_finished(const std::string& error_message) override;
5656
virtual void on_receive_data(const void* data, size_t bytes) override;
5757

58-
void process_message(const std::string& message);
58+
void process_message(const std::string& message, WallClock timestamp);
5959
void set_mode(const std::string& sbb_version);
6060

6161
private:
@@ -66,7 +66,8 @@ class TcpSysbotBase_Connection : public ControllerConnection, private ClientSock
6666

6767
std::string m_connecting_message;
6868
// std::string m_version;
69-
WallClock m_last_receive;
69+
WallClock m_last_ping_send;
70+
WallClock m_last_ping_receive;
7071
std::deque<char> m_receive_buffer;
7172

7273
SpinLock m_send_lock;

0 commit comments

Comments
 (0)