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 {
65 this->write(t_sCommand.toUtf8().constData(), t_sCommand.size());
66 this->waitForBytesWritten();
67
68 //thats not the most elegant way
69 this->waitForReadyRead(1000);
70 QByteArray t_qByteArrayRaw;
71 // TODO(cpieloth): We need a break condition e.g. last byte == \0 or \n
72 // Large responses can be split to more than one packet which could be a problem on big network latencies.
73 while (this->bytesAvailable() > 0 && this->canReadLine())
74 t_qByteArrayRaw += this->readAll();
75
76 p_sReply = QString(t_qByteArrayRaw);
77 }
78 return p_sReply;
79}
80
81//=============================================================================================================
82
84{
85 const QString t_sCommand = QString("{\"commands\":{%1}}\n").arg(p_command.toStringReadySend());
86
87 QString t_sReply;
88
89 if (this->state() == QAbstractSocket::ConnectedState)
90 {
91 // Send request
92 if constexpr (USENEW)
93 {
94 QByteArray block;
95 QDataStream out(&block, QIODevice::WriteOnly);
96 out.setVersion(QDataStream::Qt_5_1);
97
98 out << static_cast<quint16>(0);
99 out << t_sCommand;
100 out.device()->seek(0);
101 out << static_cast<quint16>(static_cast<unsigned long>(block.size()) - sizeof(quint16));
102
103 this->write(block);
104 this->waitForBytesWritten();
105
106 // Receive response
107 QDataStream in(this);
108 in.setVersion(QDataStream::Qt_5_1);
109
110 quint16 blockSize = 0;
111
112 bool respComplete = false;
113
114 do
115 {
116 this->waitForReadyRead(100);
117
118 if (blockSize == 0)
119 {
120 if (this->bytesAvailable() >= static_cast<int>(sizeof(quint16)))
121 in >> blockSize;
122 }
123 else if(this->bytesAvailable() >= blockSize)
124 {
125 in >> t_sReply;
126 respComplete = true;
127 }
128 } while (!respComplete && blockSize < 65000);//Sanity Check -> allowed maximal blocksize is 65.000
129 }
130 else
131 {
132 this->write(t_sCommand.toUtf8().constData(), t_sCommand.size());
133 this->waitForBytesWritten();
134
135 // Receive response
136 bool respComplete = false;
137 QByteArray t_qByteArrayRaw;
138 do
139 {
140 if (this->waitForReadyRead(100))
141 {
142 t_qByteArrayRaw += this->readAll();
143 // We need a break condition,
144 // because we do not have a stop character and do not know how many bytes to receive.
145 respComplete = t_qByteArrayRaw.count('{')
146 == t_qByteArrayRaw.count('}');
147 }
148 qDebug() << "Response: " << t_qByteArrayRaw.size() << " bytes";
149 } while (!respComplete);
150 t_sReply = QString(t_qByteArrayRaw);
151 }
152 }
153 else
154 {
155 qWarning() << "Request was not send, because client is not connected!";
156 }
157
158 m_qMutex.lock();
159 m_sAvailableData = t_sReply;
160 m_qMutex.unlock();
161
162 emit response(t_sReply);
163}
164
165//=============================================================================================================
166
168{
169 //Send
170 m_commandManager["getbufsize"].send();
171
172 //Receive
173 m_qMutex.lock();
174 QByteArray t_sJsonCommands = m_sAvailableData.toUtf8();
175 m_qMutex.unlock();
176
177 //Parse
178 QJsonParseError error;
179 QJsonDocument t_jsonDocumentOrigin = QJsonDocument::fromJson(t_sJsonCommands, &error);
180
181 if (error.error == QJsonParseError::NoError)
182 {
183// qDebug() << t_jsonDocumentOrigin;//"Received Commands" << m_commandManager.commandMap().keys();
184
185 //Switch to command object
186 if(t_jsonDocumentOrigin.isObject() && t_jsonDocumentOrigin.object().value(QString("bufsize")) != QJsonValue::Undefined)
187 {
188 qint32 size = (qint32)t_jsonDocumentOrigin.object().value(QString("bufsize")).toDouble();
189 return size;
190 }
191 }
192
193 qCritical() << "Unable to parse JSON response: " << error.errorString();
194 return -1;
195}
196
197//=============================================================================================================
198
200{
201 //No commands are present -> thats why help has to be send using a self created command
202 const QString help("help");
203 const QString description("");
204 const Command cmdHelp(help, description);
205 this->sendCommandJSON(cmdHelp);
206
207 //Clear Commands
208 m_commandManager.clear();
209
210 //Receive
211 m_qMutex.lock();
212 QByteArray t_sJsonCommands = m_sAvailableData.toUtf8();
213 m_qMutex.unlock();
214
215 //Parse
216 QJsonParseError error;
217 QJsonDocument t_jsonDocumentOrigin = QJsonDocument::fromJson(
218 t_sJsonCommands, &error);
219
220 if (error.error == QJsonParseError::NoError)
221 m_commandManager.insert(t_jsonDocumentOrigin);
222 else
223 qCritical() << "Unable to parse JSON response: " << error.errorString();
224}
225
226//=============================================================================================================
227
228qint32 RtCmdClient::requestConnectors(QMap<qint32, QString> &p_qMapConnectors)
229{
230 //Send
231 m_commandManager["conlist"].send();
232
233 //Receive
234 m_qMutex.lock();
235 QByteArray t_sJsonConnectors = m_sAvailableData.toUtf8();
236 m_qMutex.unlock();
237
238 //Parse
239 QJsonParseError error;
240 QJsonDocument t_jsonDocumentOrigin = QJsonDocument::fromJson(
241 t_sJsonConnectors, &error);
242
243 QJsonObject t_jsonObjectConnectors;
244
245 //Switch to command object
246 if(t_jsonDocumentOrigin.isObject() && t_jsonDocumentOrigin.object().value(QString("connectors")) != QJsonValue::Undefined)
247 t_jsonObjectConnectors = t_jsonDocumentOrigin.object().value(QString("connectors")).toObject();
248
249 //inits
250 qint32 p_iActiveId = -1;
251 p_qMapConnectors.clear();
252
253 //insert connectors
254 QJsonObject::Iterator it;
255 for(it = t_jsonObjectConnectors.begin(); it != t_jsonObjectConnectors.end(); ++it)
256 {
257 QString t_qConnectorName = it.key();
258
259 qint32 id = it.value().toObject().value(QString("id")).toDouble();
260
261 if(!p_qMapConnectors.contains(id))
262 p_qMapConnectors.insert(id, t_qConnectorName);
263 else
264 qWarning("Warning: CommandMap contains command %s already. Insertion skipped.\n", it.key().toUtf8().constData());
265
266 //if connector is active indicate it
267 if(it.value().toObject().value(QString("active")).toBool())
268 p_iActiveId = id;
269 }
270
271 return p_iActiveId;
272}
273
275
276//void RtCmdClient::requestMeasInfo(qint32 p_id)
277//{
278// QString t_sCommand = QString("measinfo %1").arg(p_id);
279// this->sendCommand(t_sCommand);
280//}
281
283
284//void RtCmdClient::requestMeasInfo(const QString &p_Alias)
285//{
286// QString t_sCommand = QString("measinfo %1").arg(p_Alias);
287// this->sendCommand(t_sCommand);
288//}
289
291
292//void RtCmdClient::requestMeas(qint32 p_id)
293//{
294// QString t_sCommand = QString("start %1").arg(p_id);
295// this->sendCommand(t_sCommand);
296//}
297
299
300//void RtCmdClient::requestMeas(QString p_Alias)
301//{
302// QString t_sCommand = QString("start %1").arg(p_Alias);
303// this->sendCommand(t_sCommand);
304//}
305
307
308//void RtCmdClient::stopAll()
309//{
310// QString t_sCommand = QString("stop-all");
311// this->sendCommand(t_sCommand);
312//}
313
314//=============================================================================================================
315
316bool RtCmdClient::waitForDataAvailable(qint32 msecs) const
317{
318 if (m_sAvailableData.size() > 0)
319 return true;
320
321 qint64 t_msecsStart = QDateTime::currentMSecsSinceEpoch();
322
323 while (msecs == -1
324 || (qint64) msecs
325 < QDateTime::currentMSecsSinceEpoch() - t_msecsStart)
326 {
327 QThread::msleep(5);
328 if (m_sAvailableData.size() > 0)
329 return true;
330 }
331 return false;
332}
333
334//=============================================================================================================
335
337{
338 return m_commandManager[key];
339}
340
341//=============================================================================================================
342
343const Command RtCmdClient::operator[](const QString &key) const
344{
345 return m_commandManager[key];
346}
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:222
void triggered(Command p_command)