MNE-CPP  beta 1.0
dacqserver.cpp
Go to the documentation of this file.
1 //=============================================================================================================
36 //*************************************************************************************************************
37 //=============================================================================================================
38 // INCLUDES
39 //=============================================================================================================
40 
41 #include "dacqserver.h"
42 #include "neuromag.h"
43 #include "collectorsocket.h"
44 #include "shmemsocket.h"
45 #include <fiff/fiff_constants.h>
46 #include <fiff/fiff_stream.h>
47 
48 
49 //*************************************************************************************************************
50 //=============================================================================================================
51 // Qt INCLUDES
52 //=============================================================================================================
53 
54 #include <QDebug>
55 #include <QTcpSocket>
56 #include <QtNetwork>
57 #include <QDataStream>
58 
59 
60 //*************************************************************************************************************
61 //=============================================================================================================
62 // USED NAMESPACES
63 //=============================================================================================================
64 
65 using namespace NeuromagPlugin;
66 
67 
68 //*************************************************************************************************************
69 //=============================================================================================================
70 // DEFINE MEMBER METHODS
71 //=============================================================================================================
72 
73 DacqServer::DacqServer(Neuromag* p_pNeuromag, QObject * parent)
74 : QThread(parent)
75 , m_pCollectorSock(NULL)
76 , m_pShmemSock(NULL)
77 , m_bIsRunning(false)
78 , m_bMeasInfoRequest(true)
79 , m_bMeasRequest(true)
80 , m_bMeasStopRequest(false)
81 , m_bSetBuffersizeRequest(false)
82 , m_pNeuromag(p_pNeuromag)
83 {
84 }
85 
86 
87 //*************************************************************************************************************
88 
90 {
91  if(m_pCollectorSock)
92  delete m_pCollectorSock;
93  if(m_pShmemSock)
94  delete m_pShmemSock;
95 }
96 
97 
98 //*************************************************************************************************************
99 
100 bool DacqServer::getMeasInfo(FiffInfo& p_fiffInfo)
101 {
102 
103 // if (p_pFiffInfo)
104 // delete p_pFiffInfo;
105  p_fiffInfo.clear();
106 
107 #ifdef DACQ_AUTOSTART
108  m_pCollectorSock->server_stop();
109  m_pCollectorSock->server_start();
110 #endif
111 
112  FiffTag::SPtr t_pTag;
113  bool t_bReadHeader = true;
114 
115  while(t_bReadHeader)
116  {
117  if (m_pShmemSock->receive_tag(t_pTag) == -1)
118  break;
119  //
120  // Projector Item
121  //
122  if( t_pTag->kind == FIFF_BLOCK_START && *(t_pTag->toInt()) == FIFFB_PROJ_ITEM )
123  {
124  printf("\tProjector... ");
125 
126  int nvec = -1;
127  int nchan = -1;
128  QStringList defaultList;
129  QStringList names;
130  MatrixXd data;
131 
132  fiff_int_t kind;
133  bool active;
134  QString desc; // maybe, in some cases this has to be a struct.
135 
136  //
137  while(!(t_pTag->kind == FIFF_BLOCK_END && *(t_pTag->toInt()) == FIFFB_PROJ_ITEM))
138  {
139  m_pShmemSock->receive_tag(t_pTag);
140 
141  switch(t_pTag->kind)
142  {
143  case FIFF_NCHAN:
144  nchan = *(t_pTag->toInt());
145  break;
146  case FIFF_PROJ_ITEM_CH_NAME_LIST:
147  names = FiffStream::split_name_list(t_pTag->toString());
148  break;
149  case FIFF_NAME:
150  desc = t_pTag->toString();
151  printf("%s... ", desc.toUtf8().constData());
152  break;
153  case FIFF_PROJ_ITEM_KIND:
154  kind = *(t_pTag->toInt());
155  break;
156 // case FIFF_PROJ_ITEM_TIME:
157 // qDebug() << "FIFF_PROJ_ITEM_TIME";
158 // break;
159  case FIFF_PROJ_ITEM_NVEC:
160  nvec == *(t_pTag->toInt());
161  break;
163  active == *(t_pTag->toInt());
164  break;
165  case FIFF_PROJ_ITEM_VECTORS:
166  data = t_pTag->toFloatMatrix().cast<double>();
167  data.transposeInPlace();
168  break;
169  }
170  }
171 
172  FiffNamedMatrix t_fiffNamedMatrix(nvec, nchan, defaultList, names, data);
173 
174  FiffProj one(kind, active, desc, t_fiffNamedMatrix);
175 
176  p_fiffInfo.projs.append(one);
177 
178  printf("[done]\r\n");
179  }
180 
181 
182  switch(t_pTag->kind)
183  {
184  case FIFF_BLOCK_START:
185  if(*(t_pTag->toInt()) == FIFFB_MEAS_INFO)
186  printf("Reading measurement info... \r\n");
187  break;
188  case FIFFB_PROCESSED_DATA:
189  printf("Measurement ID... ");
190  p_fiffInfo.meas_id = t_pTag->toFiffID();
191  printf("[done]\r\n");
192  break;
193  case FIFF_MEAS_DATE:
194  printf("\tMeasurement date... ");
195  p_fiffInfo.meas_date[0] = t_pTag->toInt()[0];
196  p_fiffInfo.meas_date[1] = t_pTag->toInt()[1];
197  printf("[done]\r\n");
198  break;
199  case FIFF_NCHAN:
200  printf("\tNumber of channels... ");
201  p_fiffInfo.nchan = *(t_pTag->toInt());
202  printf("%d... [done]\r\n", p_fiffInfo.nchan);
203  break;
204  case FIFF_SFREQ:
205  printf("\tSampling frequency... ");
206  p_fiffInfo.sfreq = *(t_pTag->toFloat());
207  printf("%f... [done]\r\n", p_fiffInfo.sfreq);
208  break;
209  case FIFF_LOWPASS:
210  printf("\tLowpass frequency... ");
211  p_fiffInfo.lowpass = *(t_pTag->toFloat());
212  printf("%f Hz... [done]\r\n", p_fiffInfo.lowpass);
213  break;
214  case FIFF_HIGHPASS:
215  printf("\tHighpass frequency... ");
216  p_fiffInfo.highpass = *(t_pTag->toFloat());
217  printf("%f Hz... [done]\r\n", p_fiffInfo.highpass);
218  break;
219 // case FIFF_LINE_FREQ:
220 // qDebug() << "FIFF_LINE_FREQ " << *(t_pTag->toFloat());
221 // break;
222 // case FIFF_UNIT_AM:
223 // qDebug() << "FIFF_UNIT_AM " << *(t_pTag->toInt());
224 // break;
225  case FIFF_CH_INFO:
226 // qDebug() << "Processed FIFF_CH_INFO";
227  p_fiffInfo.chs.append( t_pTag->toChInfo() );
228  break;
229  case FIFF_BLOCK_END:
230  switch(*(t_pTag->toInt()))
231  {
232  case FIFFB_MEAS_INFO:
233  t_bReadHeader = false;
234  break;
235  }
236  break;
237 // case FIFF_HPI_NCOIL:
238 // qDebug() << "FIFF_HPI_NCOIL " << *(t_pTag->toInt());
239 // break;
240 // case FIFFV_RESP_CH:
241 // qDebug() << "FIFFV_RESP_CH " << t_pTag->toString();
242 // break;
243 // default:
244 // qDebug() << "Unknown Tag Kind: " << t_pTag->kind << " Type: " << t_pTag->type << "Size: " << t_pTag->size();
245  }
246  }
247 
248  printf("\tProcessing channels... ");
249  for(qint32 i = 0; i < p_fiffInfo.chs.size(); ++i)
250  p_fiffInfo.ch_names.append(p_fiffInfo.chs[i].ch_name);
251 
252  printf("[done]\r\n %d", p_fiffInfo.chs.size());
253 
254  printf("measurement info read.\r\n");
255 
256 #ifdef DACQ_AUTOSTART
257  if (!m_bMeasRequest)
258  m_pCollectorSock->server_stop();
259 #endif
260 
261  //t_bReadHeader is still true --> that means a break occured
262  if (t_bReadHeader)
263  return false;
264 
265  return true;
266 }
267 
268 
269 
270 
271 //*************************************************************************************************************
272 //=============================================================================================================
273 // run
274 //=============================================================================================================
275 
277 {
278  m_bIsRunning = true;
279 
280  connect(this, &DacqServer::measInfoAvailable,
281  m_pNeuromag, &Neuromag::releaseMeasInfo);
282 
283 
284  if(m_pCollectorSock)
285  delete m_pCollectorSock;
286  m_pCollectorSock = new CollectorSocket();
287 
288  //
289  // Make sure the buffer size is at least as big as the minimal buffer size
290  //
291  if(m_pNeuromag->m_uiBufferSampleSize < MIN_BUFLEN)
292  m_pNeuromag->m_uiBufferSampleSize = MIN_BUFLEN;
293 
294  int t_iOriginalMaxBuflen = 1500;// set the standard size as long as we can't get it without setting it
295  // this doesn't work without reseting it
296  // t_iOriginalMaxBuflen = collector_getMaxBuflen();
297  // if (t_iOriginalMaxBuflen < 1) {
298  // printf("Could not query the current Neuromag buffer length\r\n");//dacq_log("Could not query the current Neuromag buffer length\n");
299  // collector_close();
300  // return;
301  // }
302  Q_UNUSED(t_iOriginalMaxBuflen);
303 
304  if (m_pNeuromag->m_uiBufferSampleSize < MIN_BUFLEN) {
305  fprintf(stderr, "%ui: Too small Neuromag buffer length requested, should be at least %d\n", m_pNeuromag->m_uiBufferSampleSize, MIN_BUFLEN);
306  return;
307  }
308  else {
309  /* Connect to the Elekta Neuromag acquisition control server, change the buffer length and exit*/
310  if (!m_pCollectorSock->open()) {
311  printf("Cannot change the Neuromag buffer length: Could not open collector connection\n");//dacq_log("Cannot change the Neuromag buffer length: Could not open collector connection\n");
312  return;
313  }
314  printf("Changing the Neuromag buffer length to %d... ", m_pNeuromag->m_uiBufferSampleSize);//dacq_log("Changing the Neuromag buffer length to %d\n", newMaxBuflen);
315  if (m_pCollectorSock->setMaxBuflen(m_pNeuromag->m_uiBufferSampleSize)) {
316  printf("Setting a new Neuromag buffer length failed\r\n");//dacq_log("Setting a new Neuromag buffer length failed\n");
317  m_pCollectorSock->close();
318  return;
319  }
320  printf("[done]\r\n");
321  }
322 
323 
324 
326 
327  if(m_pShmemSock)
328  delete m_pShmemSock;
329  m_pShmemSock = new ShmemSocket();
330 
331  m_pShmemSock->set_data_filter (NULL, 0);
332 
333  /* Connect to the Elekta Neuromag shared memory system */
334  if (!m_pShmemSock->connect_client()) {
335  printf("Could not connect!\r\n");//dacq_log("Could not connect!\n");
336  return;//(2);
337  }
338 
339 
340  /* Mainloop */
341 // printf("Will scale up MEG mags by %g, grads by %g and EEG data by %g\n",
342 // meg_mag_multiplier, meg_grad_multiplier, eeg_multiplier);
343  printf("Waiting for the measurement to start...\n");
344 
345  //
346  // Receive shmem tags
347  //
348  qint32 nchan = -1;
349  float sfreq = -1.0f;
350 
351  FiffTag::SPtr t_pTag;
352 
353  qint32 t_nSamples = 0;
354  qint32 t_nSamplesNew = 0;
355 
356 
357  //
358  // Requesting new header info: read it every time a measurement starts or a measurement info is requested
359  //
360  if(m_pNeuromag->m_info.isEmpty() || m_bMeasInfoRequest)
361  {
362  m_pNeuromag->mutex.lock();
363  if(getMeasInfo(m_pNeuromag->m_info))
364  {
365  if(m_bMeasInfoRequest)
366  {
367  emit measInfoAvailable();
368  m_bMeasInfoRequest = false;
369  }
370 
371  // Reset Buffer Size
372  if(m_pNeuromag->m_pRawMatrixBuffer)
373  delete m_pNeuromag->m_pRawMatrixBuffer;
374  m_pNeuromag->m_pRawMatrixBuffer = NULL;
375 
376  if(!m_pNeuromag->m_info.isEmpty())
377  m_pNeuromag->m_pRawMatrixBuffer = new RawMatrixBuffer(RAW_BUFFFER_SIZE, m_pNeuromag->m_info.nchan, m_pNeuromag->m_uiBufferSampleSize);
378  }
379  else
380  m_bIsRunning = false;
381  m_pNeuromag->mutex.unlock();
382 
383  //Stop if only meas info is requested
384  if(!m_pNeuromag->m_bIsRunning)
385  this->wait();
386  }
387 
388  //
389  // Control measurement start through Neuromag connector. ToDo: in Case Realtime measurement should be performed during normal acqusition process, change this!!
390  //
391 #ifdef DACQ_AUTOSTART
392  if(m_bMeasRequest)
393  m_pCollectorSock->server_start();
394 #endif
395 
396  while(m_bIsRunning)
397  {
398  if(m_bMeasRequest)
399  {
400  if (m_pShmemSock->receive_tag(t_pTag) == -1)
401  break;
402  }
403  else
404  {
405  // break while loop when no measurement request
406  break;
407  }
408 
409  if (nchan < 0 && !m_pNeuromag->m_info.isEmpty())
410  {
411  nchan = m_pNeuromag->m_info.nchan;
412  sfreq = m_pNeuromag->m_info.sfreq;
413  }
414 
415 
416  switch(t_pTag->kind)
417  {
418  case FIFF_DATA_BUFFER:
419  if(nchan > 0)
420  {
421  t_nSamplesNew = t_nSamples + m_pNeuromag->m_uiBufferSampleSize - 1;
422  printf("Reading %d ... %d = %9.3f ... %9.3f secs...", t_nSamples, t_nSamplesNew, ((float)t_nSamples) / sfreq, ((float)t_nSamplesNew) / sfreq );
423  t_nSamples += m_pNeuromag->m_uiBufferSampleSize;
424 
425  float a;
426  float meg_mag_multiplier = 1.0;
427  float meg_grad_multiplier = 1.0;
428  float eeg_multiplier = 1.0;
429 
430  MatrixXf* t_pMatrix = new MatrixXf(nchan, m_pNeuromag->m_uiBufferSampleSize);
431 
432  fiff_int_t *data32 = (fiff_int_t *)t_pTag->data();
433  for (qint32 ch = 0; ch < nchan; ch++) {
434  switch(m_pNeuromag->m_info.chs[ch].kind) {
435  case FIFFV_MAGN_CH:
436  if (m_pNeuromag->m_info.chs[ch].unit == FIFF_UNIT_T_M)
437  a = meg_grad_multiplier;
438  else
439  a = meg_mag_multiplier;
440  break;
441  case FIFFV_EL_CH:
442  a = eeg_multiplier;
443  break;
444  default:
445  a = 1.0;
446  }
447  for (qint32 ns = 0; ns < m_pNeuromag->m_uiBufferSampleSize; ns++)
448  (*t_pMatrix)(ch,ns) = a * m_pNeuromag->m_info.chs[ch].cal * m_pNeuromag->m_info.chs[ch].range * data32[nchan*ns+ch];
449  }
450 
451  m_pNeuromag->m_pRawMatrixBuffer->push(t_pMatrix);
452 
453  delete t_pMatrix;
454 /*
455  MatrixXf* t_pMatrix = new MatrixXf( (Map<MatrixXi>( (int*) t_pTag->data(), nchan, m_pNeuromag->m_uiBufferSampleSize)).cast<float>());
456 // std::cout << "Matrix Xf " << t_pMatrix->block(0,0,1,4);
457  m_pNeuromag->m_pRawMatrixBuffer->push(t_pMatrix);
458  delete t_pMatrix;
459 */
460  printf(" [done]\r\n");
461  }
462  break;
463  case FIFF_BLOCK_START:
464 // qDebug() << "FIFF_BLOCK_START";
465  switch(*(t_pTag->toInt()))
466  {
467  case FIFFB_RAW_DATA:
468  printf("Processing raw data...\r\n");
469  break;
470 // default:
471 // qDebug() << " Unknown " << *(t_pTag->toInt());
472  }
473  break;
474  case FIFF_ERROR_MESSAGE:
475  printf("Error: %s\r\n", t_pTag->data());
476  m_bIsRunning = false;
477  break;
478  case FIFF_CLOSE_FILE:
479  printf("Measurement stopped.\r\n");
480  break;
481  default:
482  printf("Unknow tag; Kind: %d, Type: %d, Size: %d \r\n", t_pTag->kind, t_pTag->type, t_pTag->size());
483  }
484  }
485 
486  //
487  // Stop and clean up
488  //
489 #ifdef DACQ_AUTOSTART
490  m_pCollectorSock->server_stop();
491 #endif
492 
493  m_pShmemSock->disconnect_client();
494  m_pCollectorSock->close();
495 
496  delete m_pCollectorSock;
497  m_pCollectorSock = NULL;
498 
499  printf("\r\n");
500 }
FIFF measurement file information.
Definition: fiff_info.h:96
fiff_int_t meas_date[2]
Definition: fiff_info.h:259
The Neuromag class provides an Elekta Neuromag connector.
Definition: neuromag.h:100
static QStringList split_name_list(QString p_sNameList)
QList< FiffProj > projs
Definition: fiff_info.h:266
declaration of the DacqServer Class.
QSharedPointer< FiffTag > SPtr
Definition: fiff_tag.h:166
#define MIN_BUFLEN
Fiff constants.
DacqServer(Neuromag *p_pNeuromag, QObject *parent=0)
Definition: dacqserver.cpp:73
#define FIFF_MNE_PROJ_ITEM_ACTIVE
The CollectorSocket class provides ....
SSP projector data.
Definition: fiff_proj.h:89
int receive_tag(FiffTag::SPtr &p_pTag)
FiffStream class declaration.
#define FIFF_UNIT_T_M
QList< FiffChInfo > chs
The ShmemSocket class provides...
Definition: shmemsocket.h:88
#define FIFF_DATA_BUFFER
implementation of the CollectorSocket Class.
implementation of the ShmemSocket Class.