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