Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ENH] MNEScan FTBuffer plugin - Channel names compatibility #840

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
3 changes: 2 additions & 1 deletion applications/mne_scan/plugins/ftbuffer/ftbuffertypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ typedef struct {
qint32 nevents;
} samples_events_t;

enum class HeaderChunk : int{
enum class HeaderChunkType : int{
FT_CHUNK_CHANNEL_NAMES = 1,
FT_CHUNK_NEUROMAG_HEADER = 8,
FT_CHUNK_NEUROMAG_ISOTRAK = 9,
FT_CHUNK_NEUROMAG_HPIRESULT = 10
Expand Down
4 changes: 2 additions & 2 deletions applications/mne_scan/plugins/ftbuffer/ftbuffproducer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ void FtBuffProducer::runMainLoop()
QThread::usleep(50000);
}

while(!m_pFtConnector->getHeader()) {
while(!m_pFtConnector->getFixedHeader()) {
QThread::usleep(50000);
}

Expand Down Expand Up @@ -127,7 +127,7 @@ void FtBuffProducer::connectToBuffer(QString addr,

//Try to get info from buffer first, then resort to file
if(m_pFtConnector->connect()) {
auto metadata = m_pFtConnector->parseBufferHeaders();
auto metadata = m_pFtConnector->parseBufferHeader();
if (m_pFtBuffer->setupRTMSA(metadata)){
emit connecStatus(true);
return;
Expand Down
105 changes: 67 additions & 38 deletions applications/mne_scan/plugins/ftbuffer/ftconnector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@

#include <QThread>
#include <QtEndian>
#include <QDateTime>

//=============================================================================================================
// EIGEN INCLUDES
Expand All @@ -69,7 +70,7 @@ FtConnector::FtConnector()
, m_iExtendedHeaderSize(0)
, m_iPort(1972)
, m_bNewData(false)
, m_fSampleFreq(0)
, m_fSamplingFreq(0)
, m_sAddress("127.0.0.1")
, m_pSocket(Q_NULLPTR)
{
Expand Down Expand Up @@ -119,7 +120,7 @@ bool FtConnector::connect()

//=============================================================================================================

bool FtConnector::getHeader()
bool FtConnector::getFixedHeader()
{
qInfo() << "[FtConnector::getHeader] Attempting to get header...";

Expand All @@ -140,7 +141,7 @@ bool FtConnector::getHeader()

//Parse return message from buffer
QBuffer msgBuffer;
prepBuffer(msgBuffer, sizeof (messagedef_t));
copyResponse(msgBuffer, sizeof (messagedef_t));
int bufsize = parseMessageDef(msgBuffer);

if (bufsize == 0) {
Expand All @@ -155,7 +156,7 @@ bool FtConnector::getHeader()

//Parse header info from buffer
QBuffer hdrBuffer;
prepBuffer(hdrBuffer, sizeof (headerdef_t)); // if implementing header chunks: change from sizeof (headerdef) to bufsize
copyResponse(hdrBuffer, sizeof (headerdef_t)); // if implementing header chunks: change from sizeof (headerdef) to bufsize
parseHeaderDef(hdrBuffer);

return true;
Expand Down Expand Up @@ -205,11 +206,11 @@ bool FtConnector::parseHeaderDef(QBuffer &readBuffer)

//Save paramerters
m_iNumChannels = headerdef.nchans;
m_fSampleFreq = headerdef.fsample;
m_fSamplingFreq = headerdef.fsample;
m_iNumNewSamples = headerdef.nsamples;
m_iDataType = headerdef.data_type;
m_iExtendedHeaderSize = headerdef.bufsize;
m_iMinSampleRead = static_cast<int>(m_fSampleFreq/2);
m_iMinSampleRead = static_cast<int>(m_fSamplingFreq/2);

qInfo() << "[FtConnector::parseHeaderDef] Got header parameters.";

Expand Down Expand Up @@ -287,7 +288,7 @@ bool FtConnector::getData()

//Parse return message from buffer
QBuffer msgBuffer;
prepBuffer(msgBuffer, sizeof (messagedef_t));
copyResponse(msgBuffer, sizeof (messagedef_t));
int bufsize = parseMessageDef(msgBuffer);

//Waiting for response.
Expand All @@ -297,12 +298,12 @@ bool FtConnector::getData()

//Parse return data def from buffer
QBuffer datadefBuffer;
prepBuffer(datadefBuffer, sizeof (datadef_t));
copyResponse(datadefBuffer, sizeof (datadef_t));
bufsize = parseDataDef(datadefBuffer);

//Parse actual data from buffer
QBuffer datasampBuffer;
prepBuffer(datasampBuffer, bufsize);
copyResponse(datasampBuffer, bufsize);
parseData(datasampBuffer, bufsize);

//update sample tracking
Expand Down Expand Up @@ -334,8 +335,8 @@ bool FtConnector::setPort(const int &iPort)

//=============================================================================================================

void FtConnector::prepBuffer(QBuffer &buffer,
int numBytes)
void FtConnector::copyResponse(QBuffer &buffer,
int numBytes)
{
buffer.open(QIODevice::ReadWrite);
buffer.write(m_pSocket->read(numBytes));
Expand Down Expand Up @@ -395,7 +396,7 @@ void FtConnector::echoStatus()
qInfo() << "| Socket: " << m_pSocket->state();
qInfo() << "| Address: " << m_sAddress << ":" << m_iPort;
qInfo() << "| Channels: " << m_iNumChannels;
qInfo() << "| Frequency: " << m_fSampleFreq;
qInfo() << "| Frequency: " << m_fSamplingFreq;
qInfo() << "| Samples read:" << m_iNumSamples;
qInfo() << "| New samples: " << m_iNumNewSamples;
qInfo() << "|================================";
Expand Down Expand Up @@ -430,7 +431,7 @@ int FtConnector::totalBuffSamples()

//Parse return message from buffer
QBuffer msgBuffer;
prepBuffer(msgBuffer, sizeof (messagedef_t));
copyResponse(msgBuffer, sizeof (messagedef_t));
parseMessageDef(msgBuffer);

//Waiting for response.
Expand All @@ -441,7 +442,7 @@ int FtConnector::totalBuffSamples()
qint32 iNumSamp;

QBuffer sampeventsBuffer;
prepBuffer(sampeventsBuffer, sizeof(samples_events_t));
copyResponse(sampeventsBuffer, sizeof(samples_events_t));

char cSamps[sizeof(iNumSamp)];
sampeventsBuffer.read(cSamps, sizeof(iNumSamp));
Expand All @@ -468,19 +469,6 @@ bool FtConnector::parseData(QBuffer &datasampBuffer,
QByteArray dataArray = datasampBuffer.readAll();
float* fdata = reinterpret_cast<float*> (dataArray.data());

//TODO: Implement receiving other types of data
// switch (m_iDataType) {
// case DATATYPE_FLOAT32:
// auto data = reinterpret_cast<float*>(dataArray.data(), bufsize);
// qDebug() << "*** Would you look at that, we're all the way here ***";
// qDebug() << "Data sample:";

// for (int i = 0; i < 10 ; i++) {
// qDebug() << data[i];
// }
// break;
// }

//format data into eigen matrix to pass up
Eigen::MatrixXf matData;
matData.resize(m_iNumChannels, m_iMsgSamples);
Expand Down Expand Up @@ -542,24 +530,22 @@ QString FtConnector::getAddr()

//=============================================================================================================

MetaData FtConnector::parseBufferHeaders()
MetaData FtConnector::parseBufferHeader()
{
qInfo() << "[FtConnector::parseNeuromagHeader] Attempting to get extended header...";

MetaData metadata;
QBuffer chunkBuffer;

getHeader();
prepBuffer(chunkBuffer, m_iExtendedHeaderSize);
getFixedHeader();

std::cout << "Parsing extended header\n";
qInfo() << "[FtConnector::parseNeuromagHeader] Parsing extended header\n";
QBuffer allChunksBuffer;
copyResponse(allChunksBuffer, m_iExtendedHeaderSize);

FtHeaderParser parser;
metadata = parser.parseHeader(chunkBuffer);
metadata = parser.parseExtendedHeader(allChunksBuffer);

if (!metadata.bFiffInfo){
metadata.setFiffinfo(infoFromSimpleHeader());
}
checkForMissingMetadataFields(metadata);

return metadata;
}
Expand Down Expand Up @@ -587,11 +573,14 @@ BufferInfo FtConnector::getBufferInfo()

//=============================================================================================================

FIFFLIB::FiffInfo FtConnector::infoFromSimpleHeader()
FIFFLIB::FiffInfo FtConnector::infoFromSimpleHeader() const
{
FIFFLIB::FiffInfo defaultInfo;

defaultInfo.sfreq = m_fSampleFreq;
defaultInfo.meas_date[0] = static_cast<int32_t>(QDateTime::currentDateTime().toSecsSinceEpoch());
defaultInfo.meas_date[1] = 0;

defaultInfo.sfreq = m_fSamplingFreq;
defaultInfo.nchan = m_iNumChannels;

defaultInfo.chs.clear();
Expand All @@ -612,3 +601,43 @@ FIFFLIB::FiffInfo FtConnector::infoFromSimpleHeader()

return defaultInfo;
}

//=============================================================================================================

void FtConnector::checkForMissingMetadataFields(MetaData& data) const
{
if (!data.bFiffInfo){
data.setFiffinfo(infoFromSimpleHeader());
} else {
if ( data.info.meas_date[0] == -1 )
{
data.info.meas_date[0] = static_cast<int32_t>(QDateTime::currentDateTime().toSecsSinceEpoch());
data.info.meas_date[1] = 0;
}

if ( data.info.sfreq <= 0 )
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as long as we have not set on a specific formatting rule, I would propose follow the old style aka no spaces before and after (as well as )

{
data.info.sfreq = m_fSamplingFreq;
}
if ( data.info.nchan == -1 )
{
data.info.nchan = m_iNumChannels;
data.info.chs.clear();
for (int chani = 0; chani< m_iNumChannels; chani++)
{
FIFFLIB::FiffChInfo channel;

channel.ch_name = "Ch. " + QString::number(chani);
channel.kind = FIFFV_MEG_CH;
channel.unit = FIFF_UNIT_T;
channel.unit_mul = FIFF_UNITM_NONE;
channel.chpos.coil_type = FIFFV_COIL_NONE;

data.info.chs.append(channel);

data.info.ch_names.append("Ch. " + QString::number(chani));

}
}
}
}
21 changes: 15 additions & 6 deletions applications/mne_scan/plugins/ftbuffer/ftconnector.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ class FtConnector : public QObject
*
* @return true if successful, false if unsuccessful.
*/
bool getHeader();
bool getFixedHeader();

//=========================================================================================================
/**
Expand Down Expand Up @@ -209,7 +209,7 @@ class FtConnector : public QObject
*
* @return returns the FiffInfo from the parsed fif file from the neuromag header chunk.
*/
MetaData parseBufferHeaders();
MetaData parseBufferHeader();

//=========================================================================================================
/**
Expand Down Expand Up @@ -293,8 +293,8 @@ class FtConnector : public QObject
* @param[out] buffer QBuffer to which daa will be written.
* @param[in] numBytes How many bytes to read from socket.
*/
void prepBuffer(QBuffer &buffer,
int numBytes);
void copyResponse(QBuffer &buffer,
int numBytes);

//=========================================================================================================
/**
Expand All @@ -310,7 +310,16 @@ class FtConnector : public QObject
*
* @return FiffInfo object based on filedtrip header
*/
FIFFLIB::FiffInfo infoFromSimpleHeader();
FIFFLIB::FiffInfo infoFromSimpleHeader() const;

//=========================================================================================================
/**
* Checks for empty or invalid important fields in the parsed metadata and attempts to fill them.
*
* @param[in] data FiffInfo structure with information parsed from the FTBuffer headers.
*
*/
void checkForMissingMetadataFields(MetaData& data) const;

int m_iMinSampleRead; /**< Number of samples that need to be added t obuffer before we try to read. */
int m_iNumSamples; /**< Number of samples we've read from the buffer. */
Expand All @@ -323,7 +332,7 @@ class FtConnector : public QObject

bool m_bNewData; /**< Indicate whether we've received new data. */

float m_fSampleFreq; /**< Sampling frequency of data in the buffer. */
float m_fSamplingFreq; /**< Sampling frequency of data in the buffer. */

QString m_sAddress; /**< Address where the ft buffer is found. */

Expand Down
Loading