v2.0.0
Loading...
Searching...
No Matches
rtsensordatacontroller.cpp
Go to the documentation of this file.
1//=============================================================================================================
34
35//=============================================================================================================
36// INCLUDES
37//=============================================================================================================
38
40#include "rtsensordataworker.h"
42
43#include <QThread>
44#include <QTimer>
45#include <QDebug>
46
47//=============================================================================================================
48// DEFINE MEMBER METHODS
49//=============================================================================================================
50
52 : QObject(parent)
53{
54 // Create data worker
55 m_pWorker = new DISP3DRHILIB::RtSensorDataWorker();
56
57 // Create and configure data thread
58 m_pWorkerThread = new QThread(this);
59 m_pWorker->moveToThread(m_pWorkerThread);
60
61 // Clean up worker when thread finishes
62 connect(m_pWorkerThread, &QThread::finished, m_pWorker, &QObject::deleteLater);
63
64 // Forward worker signals to controller signals
69
70 // Create timer for driving the streaming cadence
71 m_pTimer = new QTimer(this);
72 m_pTimer->setTimerType(Qt::PreciseTimer);
73 connect(m_pTimer, &QTimer::timeout, m_pWorker, &DISP3DRHILIB::RtSensorDataWorker::streamData);
74
75 // Start the data worker thread
76 m_pWorkerThread->start();
77
78 // Create interpolation matrix worker
80 m_pInterpThread = new QThread(this);
81 m_pInterpWorker->moveToThread(m_pInterpThread);
82
83 connect(m_pInterpThread, &QThread::finished, m_pInterpWorker, &QObject::deleteLater);
84
85 // Forward interpolation results: auto-apply to data worker + re-emit for external listeners
87 this, &RtSensorDataController::onNewMegMapping);
89 this, &RtSensorDataController::onNewEegMapping);
90
91 m_pInterpThread->start();
92
93 qDebug() << "RtSensorDataController: Initialized with" << m_iTimeInterval << "ms interval";
94}
95
96//=============================================================================================================
97
99{
100 // Stop timer
101 if (m_pTimer) {
102 m_pTimer->stop();
103 }
104
105 // Stop the data worker thread
106 if (m_pWorkerThread) {
107 m_pWorkerThread->quit();
108 m_pWorkerThread->wait();
109 }
110
111 // Stop the interpolation worker thread
112 if (m_pInterpThread) {
113 m_pInterpThread->quit();
114 m_pInterpThread->wait();
115 }
116}
117
118//=============================================================================================================
119
120void RtSensorDataController::addData(const Eigen::VectorXf &data)
121{
122 if (m_pWorker) {
123 // Direct call is thread-safe because RtSensorDataWorker uses a mutex
124 m_pWorker->addData(data);
125 }
126}
127
128//=============================================================================================================
129
130void RtSensorDataController::setMappingMatrix(QSharedPointer<Eigen::MatrixXf> mat)
131{
132 if (m_pWorker) {
133 m_pWorker->setMappingMatrix(mat);
134 }
135}
136
137//=============================================================================================================
138
140{
141 m_bIsStreaming = state;
142
143 if (state) {
144 m_pTimer->start(m_iTimeInterval);
145 qDebug() << "RtSensorDataController: Streaming started at" << m_iTimeInterval << "ms interval";
146 } else {
147 m_pTimer->stop();
148 qDebug() << "RtSensorDataController: Streaming stopped";
149 }
150}
151
152//=============================================================================================================
153
155{
156 return m_bIsStreaming;
157}
158
159//=============================================================================================================
160
162{
163 m_iTimeInterval = qMax(1, msec);
164
165 if (m_bIsStreaming) {
166 m_pTimer->setInterval(m_iTimeInterval);
167 }
168
169 qDebug() << "RtSensorDataController: Time interval set to" << m_iTimeInterval << "ms";
170}
171
172//=============================================================================================================
173
175{
176 if (m_pWorker) {
177 m_pWorker->setNumberAverages(numAvr);
178 }
179}
180
181//=============================================================================================================
182
184{
185 if (m_pWorker) {
186 m_pWorker->setColormapType(name);
187 }
188}
189
190//=============================================================================================================
191
192void RtSensorDataController::setThresholds(double min, double max)
193{
194 if (m_pWorker) {
195 m_pWorker->setThresholds(min, max);
196 }
197}
198
199//=============================================================================================================
200
202{
203 if (m_pWorker) {
204 m_pWorker->setLoopState(enabled);
205 }
206}
207
208//=============================================================================================================
209
211{
212 if (m_pWorker) {
213 m_pWorker->setSFreq(sFreq);
214 }
215}
216
217//=============================================================================================================
218
220{
221 if (m_pWorker) {
222 m_pWorker->clear();
223 }
224}
225
226//=============================================================================================================
227
229{
230 if (m_pWorker) {
231 m_pWorker->setStreamSmoothedData(bStreamSmoothedData);
232 }
233}
234
235//=============================================================================================================
236// ── On-the-fly interpolation matrix computation ────────────────────────
237//=============================================================================================================
238
240{
241 if (m_pInterpWorker) {
242 m_pInterpWorker->setEvoked(evoked);
243 }
244}
245
246//=============================================================================================================
247
249 bool applySensorTrans)
250{
251 if (m_pInterpWorker) {
252 m_pInterpWorker->setTransform(trans, applySensorTrans);
253 }
254}
255
256//=============================================================================================================
257
259{
260 if (m_pInterpWorker) {
261 m_pInterpWorker->setMegFieldMapOnHead(onHead);
262 }
263}
264
265//=============================================================================================================
266
267void RtSensorDataController::setMegSurface(const QString &surfaceKey,
268 const Eigen::MatrixX3f &vertices,
269 const Eigen::MatrixX3f &normals,
270 const Eigen::MatrixX3i &triangles)
271{
272 if (m_pInterpWorker) {
273 m_pInterpWorker->setMegSurface(surfaceKey, vertices, normals, triangles);
274 }
275}
276
277//=============================================================================================================
278
279void RtSensorDataController::setEegSurface(const QString &surfaceKey,
280 const Eigen::MatrixX3f &vertices)
281{
282 if (m_pInterpWorker) {
283 m_pInterpWorker->setEegSurface(surfaceKey, vertices);
284 }
285}
286
287//=============================================================================================================
288
289void RtSensorDataController::setBadChannels(const QStringList &bads)
290{
291 if (m_pInterpWorker) {
292 m_pInterpWorker->setBadChannels(bads);
293 }
294}
295
296//=============================================================================================================
297
299{
300 if (m_pInterpWorker) {
301 // Use QMetaObject::invokeMethod with queued connection to ensure
302 // computeMapping() runs on the interpolation worker thread.
303 QMetaObject::invokeMethod(m_pInterpWorker, "computeMapping", Qt::QueuedConnection);
304 }
305}
306
307//=============================================================================================================
308
309void RtSensorDataController::onNewMegMapping(const QString &surfaceKey,
310 QSharedPointer<Eigen::MatrixXf> mappingMat,
311 const QVector<int> &pick)
312{
313 // Auto-forward the new matrix to the data worker
314 if (m_pWorker && mappingMat) {
315 m_pWorker->setMappingMatrix(mappingMat);
316 }
317
318 // Re-emit for external listeners (e.g. BrainView)
319 emit newMegMappingAvailable(surfaceKey, mappingMat, pick);
320
321 qDebug() << "RtSensorDataController: New MEG mapping received and forwarded"
322 << "(" << mappingMat->rows() << "x" << mappingMat->cols() << ")";
323}
324
325//=============================================================================================================
326
327void RtSensorDataController::onNewEegMapping(const QString &surfaceKey,
328 QSharedPointer<Eigen::MatrixXf> mappingMat,
329 const QVector<int> &pick)
330{
331 // Auto-forward the new matrix to the data worker
332 if (m_pWorker && mappingMat) {
333 m_pWorker->setMappingMatrix(mappingMat);
334 }
335
336 // Re-emit for external listeners (e.g. BrainView)
337 emit newEegMappingAvailable(surfaceKey, mappingMat, pick);
338
339 qDebug() << "RtSensorDataController: New EEG mapping received and forwarded"
340 << "(" << mappingMat->rows() << "x" << mappingMat->cols() << ")";
341}
RtSensorInterpolationMatWorker class declaration.
RtSensorDataWorker class declaration.
RtSensorDataController class declaration.
void newSensorColorsAvailable(const QString &surfaceKey, const QVector< uint32_t > &colors)
void newMegMappingAvailable(const QString &surfaceKey, QSharedPointer< Eigen::MatrixXf > mappingMat, const QVector< int > &pick)
void setColormapType(const QString &name)
void setMegSurface(const QString &surfaceKey, const Eigen::MatrixX3f &vertices, const Eigen::MatrixX3f &normals, const Eigen::MatrixX3i &triangles)
void setBadChannels(const QStringList &bads)
void setTransform(const FIFFLIB::FiffCoordTrans &trans, bool applySensorTrans)
void setMappingMatrix(QSharedPointer< Eigen::MatrixXf > mat)
void setEegSurface(const QString &surfaceKey, const Eigen::MatrixX3f &vertices)
void newRawSensorDataAvailable(const Eigen::VectorXf &data)
void addData(const Eigen::VectorXf &data)
void setEvoked(const FIFFLIB::FiffEvoked &evoked)
void setStreamSmoothedData(bool bStreamSmoothedData)
void newEegMappingAvailable(const QString &surfaceKey, QSharedPointer< Eigen::MatrixXf > mappingMat, const QVector< int > &pick)
RtSensorDataController(QObject *parent=nullptr)
void setThresholds(double min, double max)
Background worker for real-time sensor data streaming.
void setMappingMatrix(QSharedPointer< Eigen::MatrixXf > mat)
void newRtRawSensorData(const Eigen::VectorXf &data)
void newRtSensorColors(const QString &surfaceKey, const QVector< uint32_t > &colors)
Background worker for computing sensor field mapping matrices.
void newMegMappingAvailable(const QString &surfaceKey, QSharedPointer< Eigen::MatrixXf > mappingMat, const QVector< int > &pick)
void newEegMappingAvailable(const QString &surfaceKey, QSharedPointer< Eigen::MatrixXf > mappingMat, const QVector< int > &pick)
Coordinate transformation description.