MNE-CPP  beta 1.0
connectormanager.cpp
Go to the documentation of this file.
1 //=============================================================================================================
36 //*************************************************************************************************************
37 //=============================================================================================================
38 // INCLUDES
39 //=============================================================================================================
40 
41 #include "connectormanager.h"
42 #include "mne_rt_server.h"
43 #include "commandserver.h"
44 #include "fiffstreamserver.h"
45 
46 #include "IConnector.h"
47 
48 #include <rtCommand/commandmanager.h>
49 
50 
51 //*************************************************************************************************************
52 //=============================================================================================================
53 // STL INCLUDES
54 //=============================================================================================================
55 
56 #include <iostream>
57 
58 
59 //*************************************************************************************************************
60 //=============================================================================================================
61 // QT INCLUDES
62 //=============================================================================================================
63 
64 #include <QDir>
65 #include <QVector>
66 #include <QString>
67 #include <QStringList>
68 #include <QTextStream>
69 
70 #include <QDebug>
71 
72 
73 //*************************************************************************************************************
74 //=============================================================================================================
75 // USED NAMESPACES
76 //=============================================================================================================
77 
78 using namespace RTSERVER;
79 
80 
81 //*************************************************************************************************************
82 //=============================================================================================================
83 // DEFINE MEMBER METHODS
84 //=============================================================================================================
85 
86 ConnectorManager::ConnectorManager(FiffStreamServer* p_pFiffStreamServer, QObject *parent)
87 : QPluginLoader(parent)
88 , m_pFiffStreamServer(p_pFiffStreamServer)
89 {
90 
91 }
92 
93 
94 //*************************************************************************************************************
95 
97 {
98  QVector<IConnector*>::const_iterator it = s_vecConnectors.begin();
99  for( ; it != s_vecConnectors.end(); ++it)
100  delete (*it);
101 }
102 
103 
104 //*************************************************************************************************************
105 
106 void ConnectorManager::clearConnectorActivation()
107 {
108  // deactivate activated connectors
109  if(s_vecConnectors.size() > 0)
110  {
111  QVector<IConnector*>::const_iterator it = s_vecConnectors.begin();
112  for( ; it != s_vecConnectors.end(); ++it)
113  if((*it)->isActive())
114  (*it)->setStatus(false);
115  }
116 }
117 
118 
119 //*************************************************************************************************************
120 
121 void ConnectorManager::comConlist(Command p_command)
122 {
123  bool t_bCommandIsJson = p_command.isJson();
124 
125  MNERTServer* t_pMNERTServer = qobject_cast<MNERTServer*> (this->parent());
126 
127  if(!t_bCommandIsJson)
128  t_pMNERTServer->getCommandManager()["conlist"].reply(this->getConnectorList());
129  else
130  t_pMNERTServer->getCommandManager()["conlist"].reply(this->getConnectorList(true));
131 
132 }
133 
134 
135 //*************************************************************************************************************
136 
137 void ConnectorManager::comSelcon(Command p_command)
138 {
139  bool t_bIsInt;
140 
141  qint32 t_id = p_command.pValues()[0].toInt(&t_bIsInt);
142  if(t_bIsInt)
143  {
144 // qobject_cast<MNERTServer*> (this->parent())->getCommandManager()["selcon"].reply(this->setActiveConnector(t_id));
145  QString t_sActivated = this->setActiveConnector(t_id);
146 
147  qDebug() << t_sActivated;
148 
149  bool t_bCommandIsJson = p_command.isJson();
150 
151  if(!t_bCommandIsJson)
152  qobject_cast<MNERTServer*> (this->parent())->getCommandManager()["selcon"].reply(this->getConnectorList());
153  else
154  qobject_cast<MNERTServer*> (this->parent())->getCommandManager()["selcon"].reply(this->getConnectorList(true));
155  }
156 
157 }
158 
159 
160 //*************************************************************************************************************
161 
162 void ConnectorManager::comStart(Command p_command)//comMeas
163 {
165  qobject_cast<MNERTServer*>(this->parent())->getCommandManager()["start"].reply("Starting active connector.\n");
166 
167  Q_UNUSED(p_command);
168 }
169 
170 
171 //*************************************************************************************************************
172 
173 void ConnectorManager::comStopAll(Command p_command)
174 {
176  qobject_cast<MNERTServer*>(this->parent())->getCommandManager()["stop-all"].reply("Stoping all connectors.\r\n");
177 
178  Q_UNUSED(p_command);
179 }
180 
181 
182 //*************************************************************************************************************
183 
184 void ConnectorManager::connectActiveConnector()
185 {
186  IConnector* t_activeConnector = ConnectorManager::getActiveConnector();
187 
188  if(t_activeConnector)
189  {
190  // use signal slots instead of call backs
191  //Consulting the Signal/Slot documentation describes why the Signal/Slot approach is better:
192  // Callbacks have two fundamental flaws: Firstly, they are not type-safe. We can never be certain
193  // that the processing function will call the callback with the correct arguments.
194  // Secondly, the callback is strongly coupled to the processing function since the processing
195  // function must know which callback to call.
196  //Do be aware of the following though:
197  // Compared to callbacks, signals and slots are slightly slower because of the increased
198  // flexibility they provide
199  //The speed probably doesn't matter for most cases, but there may be some extreme cases of repeated
200  //calling that makes a difference.
201 
202  //
203  // Meas Info
204  //
205  // connect command server and connector manager
206  QObject::connect( this->m_pFiffStreamServer, &FiffStreamServer::requestMeasInfo,
207  t_activeConnector, &IConnector::info);
208 
209  // connect connector manager and fiff stream server
210  QObject::connect( t_activeConnector, &IConnector::remitMeasInfo,
211  this->m_pFiffStreamServer, &FiffStreamServer::forwardMeasInfo);
212 
213  //
214  // Raw Data
215  //
216  // connect command server and connector manager
217 
218  // connect connector manager and fiff stream server
219  QObject::connect( t_activeConnector, &IConnector::remitRawBuffer,
220  this->m_pFiffStreamServer, &FiffStreamServer::forwardRawBuffer);
221  }
222  else
223  {
224  printf("Error: Can't connect, no connector active!\n");
225  }
226 }
227 
228 
229 //*************************************************************************************************************
230 
231 void ConnectorManager::disconnectActiveConnector()
232 {
233  IConnector* t_activeConnector = ConnectorManager::getActiveConnector();
234 
235  if(t_activeConnector)
236  {
237  // use signal slots instead of call backs
238  //Consulting the Signal/Slot documentation describes why the Signal/Slot approach is better:
239  // Callbacks have two fundamental flaws: Firstly, they are not type-safe. We can never be certain
240  // that the processing function will call the callback with the correct arguments.
241  // Secondly, the callback is strongly coupled to the processing function since the processing
242  // function must know which callback to call.
243  //Do be aware of the following though:
244  // Compared to callbacks, signals and slots are slightly slower because of the increased
245  // flexibility they provide
246  //The speed probably doesn't matter for most cases, but there may be some extreme cases of repeated
247  //calling that makes a difference.
248 
249  //
250  // Meas Info
251  //
252  this->disconnect(t_activeConnector);
253  //
254  t_activeConnector->disconnect(this->m_pFiffStreamServer);
255 
256  this->m_pFiffStreamServer->disconnect(t_activeConnector);
257 
258  //
259  // Raw Data
260  //
261 // t_pMNERTServer->m_pCommandServer->disconnect(t_activeConnector);
262  //
263 // t_activeConnector->disconnect(t_pMNERTServer->m_pFiffStreamServer);
264  // connect command server and connector manager
265 // t_pMNERTServer->m_pCommandServer->disconnect(t_activeConnector);
266 
267  //
268  // Reset Raw Buffer
269  //
270 // t_pMNERTServer->m_pCommandServer->disconnect(t_activeConnector);
271  }
272  else
273  {
274  printf("Error: Can't connect, no connector active!\n");
275  }
276 }
277 
278 
279 //*************************************************************************************************************
280 
282 {
283  QVector<IConnector*>::const_iterator it = s_vecConnectors.begin();
284  for( ; it != s_vecConnectors.end(); ++it)
285  {
286  if((*it)->isActive())
287  return *it;
288  }
289 
290  return NULL;
291 }
292 
293 
294 //*************************************************************************************************************
295 
296 QByteArray ConnectorManager::getConnectorList(bool p_bFlagJSON) const
297 {
298  QByteArray t_blockConnectorList;
299 
300  if(p_bFlagJSON)
301  {
302  QJsonObject t_qJsonObjectConnectors;
303 
304  QVector<IConnector*>::const_iterator it = s_vecConnectors.begin();
305  for( ; it != s_vecConnectors.end(); ++it)
306  {
307  QJsonObject t_qJsonObjectConnector;
308 
309  //insert id
310  t_qJsonObjectConnector.insert(QString("id"), QJsonValue((*it)->getConnectorID()));
311 
312  //insert isActive
313  t_qJsonObjectConnector.insert(QString("active"), QJsonValue((*it)->isActive()));
314 
315  //insert Connector JsonObject
316  t_qJsonObjectConnectors.insert((*it)->getName(),t_qJsonObjectConnector);//QJsonObject());//QJsonValue());
317 
318  }
319 
320  QJsonObject t_qJsonObjectRoot;
321  t_qJsonObjectRoot.insert("connectors", t_qJsonObjectConnectors);
322  QJsonDocument p_qJsonDocument(t_qJsonObjectRoot);
323 
324  t_blockConnectorList.append(p_qJsonDocument.toJson());
325  }
326  else
327  {
328  if(s_vecConnectors.size() > 0)
329  {
330  QVector<IConnector*>::const_iterator it = s_vecConnectors.begin();
331  for( ; it != s_vecConnectors.end(); ++it)
332  {
333  if((*it)->isActive())
334  t_blockConnectorList.append(QString(" * (%1) %2\r\n").arg((*it)->getConnectorID()).arg((*it)->getName()));
335  else
336  t_blockConnectorList.append(QString(" (%1) %2\r\n").arg((*it)->getConnectorID()).arg((*it)->getName()));
337  }
338  }
339  else
340  t_blockConnectorList.append(" - no connector loaded - \r\n");
341  t_blockConnectorList.append("\r\n");
342  }
343  return t_blockConnectorList;
344 }
345 
346 //*************************************************************************************************************
347 
349 {
350  //Connect slots
351  MNERTServer* t_pMNERTServer = qobject_cast<MNERTServer*> (this->parent());
352 
353  QObject::connect(&t_pMNERTServer->getCommandManager()["conlist"], &Command::executed, this, &ConnectorManager::comConlist);
354  QObject::connect(&t_pMNERTServer->getCommandManager()["selcon"], &Command::executed, this, &ConnectorManager::comSelcon);
355  QObject::connect(&t_pMNERTServer->getCommandManager()["start"], &Command::executed, this, &ConnectorManager::comStart);
356  QObject::connect(&t_pMNERTServer->getCommandManager()["stop-all"], &Command::executed, this, &ConnectorManager::comStopAll);
357 }
358 
359 
360 //*************************************************************************************************************
361 
362 void ConnectorManager::loadConnectors(const QString& dir)
363 {
364  clearConnectorActivation();
365 
366  QDir ConnectorsDir(dir);
367 
368  printf("Loading connectors in directory... %s\n", ConnectorsDir.path().toUtf8().constData() );
369 
370  foreach(QString fileName, ConnectorsDir.entryList(QDir::Files))
371  {
372  if(fileName.compare("README") == 0 || fileName.compare("plugin.cfg") == 0)
373  continue;
374 
375  this->setFileName(ConnectorsDir.absoluteFilePath(fileName));
376  QObject *pConnector = this->instance();
377 
378  printf("\tLoading %s... ", fileName.toUtf8().constData() );
379 
380  // IModule
381  if(pConnector)
382  {
383  IConnector* t_pIConnector = qobject_cast<IConnector*>(pConnector);
384  t_pIConnector->setStatus(false);
385 
386  //Add the curent plugin meta data
387  QJsonObject t_qJsonObjectMetaData = this->metaData().value("MetaData").toObject();
388  t_pIConnector->setMetaData(t_qJsonObjectMetaData);
389  QJsonDocument t_jsonDocumentOrigin(t_qJsonObjectMetaData);
390  t_pIConnector->getCommandManager().insert(t_jsonDocumentOrigin);
391  t_pIConnector->connectCommandManager();
392 
393  s_vecConnectors.push_back(t_pIConnector);
394  printf("[done]\n");
395  }
396  else
397  printf("failed!\n");
398  }
399 
400  //
401  // search config for default connector
402  //
403  qint32 configConnector = -1;
404  QString configFileName("plugin.cfg");
405  QFile configFile(dir+"/"+configFileName);
406  if(!configFile.open(QIODevice::ReadOnly)) {
407  printf("Not able to read config file... %s\n", configFile.fileName().toUtf8().constData());
408  }
409  else
410  {
411  printf("\tReading %s... ", configFileName.toUtf8().constData());
412 
413  QTextStream in(&configFile);
414  QString line = in.readLine();
415  QStringList list;
416  while (!line.isNull()) {
417  list = line.split(":");
418 
419  if(list[0].simplified().compare("defaultConnector") == 0)
420  {
421  configConnector = list[1].simplified().toInt();
422  break;
423  }
424  line = in.readLine();
425  }
426  }
427  if(s_vecConnectors.size() > 0)
428  {
429 
430  bool activated = false;
431 
432  if( configConnector != -1)
433  {
434  for(qint32 i = 0; i < s_vecConnectors.size(); ++i)
435  {
436  if(s_vecConnectors[i]->getConnectorID() == configConnector)
437  {
438  s_vecConnectors[i]->setStatus(true);
439  printf("activate %s... ", s_vecConnectors[i]->getName());
440  activated = true;
441  break;
442  }
443  }
444  }
445  printf("[done]\n");
446 
447  //default
448  if(!activated)
449  s_vecConnectors[0]->setStatus(true);
450  }
451 
452  //print
453  printf("Connector list\n");
454  printf("%s", getConnectorList().data());
455 }
456 
457 
458 //*************************************************************************************************************
459 
461 {
462  QByteArray p_blockClientList;
463  QString str;
464 
465  if(ID != getActiveConnector()->getConnectorID())
466  {
467  IConnector* t_pNewActiveConnector = NULL;
468  QVector<IConnector*>::const_iterator it = s_vecConnectors.begin();
469  for( ; it != s_vecConnectors.end(); ++it)
470  if((*it)->getConnectorID() == ID)
471  t_pNewActiveConnector = *it;
472 
473  if (t_pNewActiveConnector)
474  {
475 
476  IConnector* t_pActiveConnector = getActiveConnector();
477 
478  //Stop and disconnect active connector
479  t_pActiveConnector->stop();
480  this->disconnectActiveConnector();
481  t_pActiveConnector->setStatus(false);
482 
483  //set new active connector
484  t_pNewActiveConnector->setStatus(true);
485  this->connectActiveConnector();
486 
487  str = QString("\t%1 activated.\r\n\n").arg(t_pNewActiveConnector->getName());
488  p_blockClientList.append(str);
489  }
490  else
491  {
492  str = QString("\tID %1 doesn't match a connector ID.\r\n\n").arg(ID);
493  p_blockClientList.append(str);
494  p_blockClientList.append(getConnectorList());
495  }
496  }
497  else
498  {
499  str = QString("\t%1 is already active.\r\n\n").arg(getActiveConnector()->getName());
500  p_blockClientList.append(str);
501  }
502 
503  return p_blockClientList;
504 }
505 
506 
507 //*************************************************************************************************************
508 //=============================================================================================================
509 // STATIC DEFINITIONS
510 //=============================================================================================================
511 
512 QVector<IConnector*> ConnectorManager:: s_vecConnectors;
void insert(const QJsonDocument &p_jsonDocument)
QByteArray setActiveConnector(qint32 ID)
CommandManager & getCommandManager()
Definition: IConnector.h:239
The FiffStreamServer class provides.
virtual bool stop()=0
void forwardMeasInfo(qint32 ID, FiffInfo p_fiffInfo)
void loadConnectors(const QString &dir)
CommandManager & getCommandManager()
The MNERTServer class provides a Fiff data simulator.
Definition: mne_rt_server.h:92
virtual void connectCommandManager()=0
implementation of the FiffStreamServer Class.
The IConnector class is the interface class of all plugins.
Definition: IConnector.h:119
QByteArray getConnectorList(bool p_bFlagJSON=false) const
implementation of the MNERTServer Class.
The connector interface.
virtual bool start()=0
ConnectorManager(FiffStreamServer *p_pFiffStreamServer, QObject *parent=0)
QList< QVariant > & pValues()
Definition: command.h:370
implementation of the ConnectorManager Class.
void executed(Command p_command)
void setStatus(bool status)
Definition: IConnector.h:263
virtual const char * getName() const =0
void setMetaData(QJsonObject &p_MetaData)
Definition: IConnector.h:255
implementation of the CommandServer Class.
virtual void info(qint32 ID)=0