v2.0.0
Loading...
Searching...
No Matches
rt_cmd_client.cpp
Go to the documentation of this file.
1//=============================================================================================================
21
22//=============================================================================================================
23// INCLUDES
24//=============================================================================================================
25
26#include "rt_cmd_client.h"
27
28//=============================================================================================================
29// QT INCLUDES
30//=============================================================================================================
31
32#include <QDateTime>
33#include <QThread>
34
35#include <iostream>
36
37constexpr bool USENEW = true;
38
39//=============================================================================================================
40// USED NAMESPACES
41//=============================================================================================================
42
43using namespace COMLIB;
44
45//=============================================================================================================
46// DEFINE MEMBER METHODS
47//=============================================================================================================
48
50: QTcpSocket(parent)
51{
52 QObject::connect(&m_commandManager, &CommandManager::triggered, this,
54}
55
56//=============================================================================================================
57
58QString RtCmdClient::sendCLICommand(const QString& p_sCommand)
59{
60 QString t_sCommand = QString("%1\n").arg(p_sCommand);
61 QString p_sReply;
62
63 if (this->state() == QAbstractSocket::ConnectedState) {
64 this->write(t_sCommand.toUtf8().constData(), t_sCommand.size());
65 this->waitForBytesWritten();
66
67 //thats not the most elegant way
68 this->waitForReadyRead(1000);
69 QByteArray t_qByteArrayRaw;
70 // TODO(cpieloth): We need a break condition e.g. last byte == \0 or \n
71 // Large responses can be split to more than one packet which could be a problem on big network latencies.
72 while (this->bytesAvailable() > 0 && this->canReadLine())
73 t_qByteArrayRaw += this->readAll();
74
75 p_sReply = QString(t_qByteArrayRaw);
76 }
77 return p_sReply;
78}
79
80//=============================================================================================================
81
83{
84 const QString t_sCommand = QString("{\"commands\":{%1}}\n").arg(p_command.toStringReadySend());
85
86 QString t_sReply;
87
88 if (this->state() == QAbstractSocket::ConnectedState) {
89 // Send request
90 if constexpr (USENEW) {
91 QByteArray block;
92 QDataStream out(&block, QIODevice::WriteOnly);
93 out.setVersion(QDataStream::Qt_5_1);
94
95 out << static_cast<quint16>(0);
96 out << t_sCommand;
97 out.device()->seek(0);
98 out << static_cast<quint16>(static_cast<unsigned long>(block.size()) - sizeof(quint16));
99
100 this->write(block);
101 this->waitForBytesWritten();
102
103 // Receive response
104 QDataStream in(this);
105 in.setVersion(QDataStream::Qt_5_1);
106
107 quint16 blockSize = 0;
108
109 bool respComplete = false;
110
111 do {
112 this->waitForReadyRead(100);
113
114 if (blockSize == 0) {
115 if (this->bytesAvailable() >= static_cast<int>(sizeof(quint16)))
116 in >> blockSize;
117 } else if (this->bytesAvailable() >= blockSize) {
118 in >> t_sReply;
119 respComplete = true;
120 }
121 } while (!respComplete && blockSize < 65000); //Sanity Check -> allowed maximal blocksize is 65.000
122 } else {
123 this->write(t_sCommand.toUtf8().constData(), t_sCommand.size());
124 this->waitForBytesWritten();
125
126 // Receive response
127 bool respComplete = false;
128 QByteArray t_qByteArrayRaw;
129 do {
130 if (this->waitForReadyRead(100)) {
131 t_qByteArrayRaw += this->readAll();
132 // We need a break condition,
133 // because we do not have a stop character and do not know how many bytes to receive.
134 respComplete = t_qByteArrayRaw.count('{') == t_qByteArrayRaw.count('}');
135 }
136 qDebug() << "Response: " << t_qByteArrayRaw.size() << " bytes";
137 } while (!respComplete);
138 t_sReply = QString(t_qByteArrayRaw);
139 }
140 } else {
141 qWarning() << "Request was not send, because client is not connected!";
142 }
143
144 m_qMutex.lock();
145 m_sAvailableData = t_sReply;
146 m_qMutex.unlock();
147
148 emit response(t_sReply);
149}
150
151//=============================================================================================================
152
154{
155 //Send
156 m_commandManager["getbufsize"].send();
157
158 //Receive
159 m_qMutex.lock();
160 QByteArray t_sJsonCommands = m_sAvailableData.toUtf8();
161 m_qMutex.unlock();
162
163 //Parse
164 QJsonParseError error;
165 QJsonDocument t_jsonDocumentOrigin = QJsonDocument::fromJson(t_sJsonCommands, &error);
166
167 if (error.error == QJsonParseError::NoError) {
168 // qDebug() << t_jsonDocumentOrigin;//"Received Commands" << m_commandManager.commandMap().keys();
169
170 //Switch to command object
171 if (t_jsonDocumentOrigin.isObject() && t_jsonDocumentOrigin.object().value(QString("bufsize")) != QJsonValue::Undefined) {
172 qint32 size = (qint32)t_jsonDocumentOrigin.object().value(QString("bufsize")).toDouble();
173 return size;
174 }
175 }
176
177 qCritical() << "Unable to parse JSON response: " << error.errorString();
178 return -1;
179}
180
181//=============================================================================================================
182
184{
185 //No commands are present -> thats why help has to be send using a self created command
186 const QString help("help");
187 const QString description("");
188 const Command cmdHelp(help, description);
189 this->sendCommandJSON(cmdHelp);
190
191 //Clear Commands
192 m_commandManager.clear();
193
194 //Receive
195 m_qMutex.lock();
196 QByteArray t_sJsonCommands = m_sAvailableData.toUtf8();
197 m_qMutex.unlock();
198
199 //Parse
200 QJsonParseError error;
201 QJsonDocument t_jsonDocumentOrigin = QJsonDocument::fromJson(
202 t_sJsonCommands, &error);
203
204 if (error.error == QJsonParseError::NoError)
205 m_commandManager.insert(t_jsonDocumentOrigin);
206 else
207 qCritical() << "Unable to parse JSON response: " << error.errorString();
208}
209
210//=============================================================================================================
211
212qint32 RtCmdClient::requestConnectors(QMap<qint32, QString>& p_qMapConnectors)
213{
214 //Send
215 m_commandManager["conlist"].send();
216
217 //Receive
218 m_qMutex.lock();
219 QByteArray t_sJsonConnectors = m_sAvailableData.toUtf8();
220 m_qMutex.unlock();
221
222 //Parse
223 QJsonParseError error;
224 QJsonDocument t_jsonDocumentOrigin = QJsonDocument::fromJson(
225 t_sJsonConnectors, &error);
226
227 QJsonObject t_jsonObjectConnectors;
228
229 //Switch to command object
230 if (t_jsonDocumentOrigin.isObject() && t_jsonDocumentOrigin.object().value(QString("connectors")) != QJsonValue::Undefined)
231 t_jsonObjectConnectors = t_jsonDocumentOrigin.object().value(QString("connectors")).toObject();
232
233 //inits
234 qint32 p_iActiveId = -1;
235 p_qMapConnectors.clear();
236
237 //insert connectors
238 QJsonObject::Iterator it;
239 for (it = t_jsonObjectConnectors.begin(); it != t_jsonObjectConnectors.end(); ++it) {
240 QString t_qConnectorName = it.key();
241
242 qint32 id = it.value().toObject().value(QString("id")).toDouble();
243
244 if (!p_qMapConnectors.contains(id))
245 p_qMapConnectors.insert(id, t_qConnectorName);
246 else
247 qWarning("Warning: CommandMap contains command %s already. Insertion skipped.\n", it.key().toUtf8().constData());
248
249 //if connector is active indicate it
250 if (it.value().toObject().value(QString("active")).toBool())
251 p_iActiveId = id;
252 }
253
254 return p_iActiveId;
255}
256
258
259//void RtCmdClient::requestMeasInfo(qint32 p_id)
260//{
261// QString t_sCommand = QString("measinfo %1").arg(p_id);
262// this->sendCommand(t_sCommand);
263//}
264
266
267//void RtCmdClient::requestMeasInfo(const QString &p_Alias)
268//{
269// QString t_sCommand = QString("measinfo %1").arg(p_Alias);
270// this->sendCommand(t_sCommand);
271//}
272
274
275//void RtCmdClient::requestMeas(qint32 p_id)
276//{
277// QString t_sCommand = QString("start %1").arg(p_id);
278// this->sendCommand(t_sCommand);
279//}
280
282
283//void RtCmdClient::requestMeas(QString p_Alias)
284//{
285// QString t_sCommand = QString("start %1").arg(p_Alias);
286// this->sendCommand(t_sCommand);
287//}
288
290
291//void RtCmdClient::stopAll()
292//{
293// QString t_sCommand = QString("stop-all");
294// this->sendCommand(t_sCommand);
295//}
296
297//=============================================================================================================
298
299bool RtCmdClient::waitForDataAvailable(qint32 msecs) const
300{
301 if (m_sAvailableData.size() > 0)
302 return true;
303
304 qint64 t_msecsStart = QDateTime::currentMSecsSinceEpoch();
305
306 while (msecs == -1 || (qint64)msecs < QDateTime::currentMSecsSinceEpoch() - t_msecsStart) {
307 QThread::msleep(5);
308 if (m_sAvailableData.size() > 0)
309 return true;
310 }
311 return false;
312}
313
314//=============================================================================================================
315
317{
318 return m_commandManager[key];
319}
320
321//=============================================================================================================
322
323const Command RtCmdClient::operator[](const QString& key) const
324{
325 return m_commandManager[key];
326}
constexpr bool USENEW
TCP client for the mne_rt_server command port (4217): negotiates session state via line- or JSON-enco...
Real-time client/server communication primitives for talking to mne_rt_server.
Command & operator[](const QString &key)
void sendCommandJSON(const Command &p_command)
qint32 requestConnectors(QMap< qint32, QString > &p_qMapConnectors)
RtCmdClient(QObject *parent=nullptr)
void response(QString p_sResponse)
QString sendCLICommand(const QString &p_sCommand)
bool waitForDataAvailable(qint32 msecs=30000) const
Named, parameterised command exchanged with mne_rt_server; supports both JSON and CLI serialisation.
Definition command.h:87
QString toStringReadySend() const
Definition command.cpp:215
void triggered(Command p_command)