#include "eventbuilder.h" EventBuilder::EventBuilder(QObject *parent) : QObject(parent) { connect(this, EventBuilder::sigInit, this, EventBuilder::onInit); connect(this, EventBuilder::sigDeinit, this, EventBuilder::onDeinit); connect(this, EventBuilder::sigStartLogging, this, EventBuilder::onStartLogging); connect(this, EventBuilder::sigStopLogging, this, EventBuilder::onStopLogging); connect(this, EventBuilder::sigStartTakingHistos, this, EventBuilder::onStartTakingHistos); connect(this, EventBuilder::sigStopTakingHistos, this, EventBuilder::onStopTakingHistos); moveToThread(&thread); thread.start(); init(); } EventBuilder::~EventBuilder() { deinit(); thread.quit(); thread.wait(); } //************************* Data processing framework ******************** //main processing slot void EventBuilder::onNewData(DataReceiver* receiver) { while (checkBufferOccupancies()) { //find lowest global sync value int lowest_id = findLowestId(); //get and validate data from buffers for (int dev_nr = 0; dev_nr < nrReceivers; dev_nr++) { BufferData data = receivers[dev_nr]->dataBuffer.look(); if (data.sync_frame.global_ctr == lowest_id) { receivers[dev_nr]->dataBuffer.dump(); //right data, dump it from the buffer } else { data.sync_frame.data_ok = 0; //wrong data, mark as bad } //store data for complete frame currentFrame[dev_nr] = data; } lastFrameMutex.lock(); if (newDataSemaphore.available() == 0) newDataSemaphore.release(1); lastFrame = currentFrame; lastFrameMutex.unlock(); //histogram stuff if (histogramSamplesToTake) { for (int dev_nr = 0; dev_nr < nrReceivers; dev_nr++) for (int ch = 0; ch < channelCounts[dev_nr]; ch++) histograms[baseAddresses[dev_nr] + ch].shoot(currentFrame[dev_nr].sensor_data[ch]); if (histogramSamplesToTake != -1) histogramSamplesToTake--; if (histogramSamplesToTake == 0) emit sigHistoCompleted(); } //log data if (loggingData) logDataToFile(); //************ TODO ************ //Here we can do something more with the complete frame } } //return 1 if buffer levels allow/force data processing int EventBuilder::checkBufferOccupancies() { int result = 1; for (int dev_nr = 0; dev_nr < nrReceivers; dev_nr++) { int nr_items = receivers[dev_nr]->dataBuffer.nrItems(); if (nr_items > EVB_MAX_BUFFER_OCCUPANCY) return 1; //if at least one buffer is above high threshold - return immediately if (nr_items < EVB_MIN_BUFFER_OCCUPANCY) result = 0; } return result; } int EventBuilder::findLowestId() { int min1 = INT_MAX, min2 = INT_MAX; int max1 = INT_MIN, max2 = INT_MIN; for (int dev_nr = 0; dev_nr < nrReceivers; dev_nr++) { int value = receivers[dev_nr]->dataBuffer.look().sync_frame.global_ctr; //for non-zero-crossing case if (value < min1) min1 = value; if (value > max1) max1 = value; //for zero-crossing case if (value > 256) value -= 512; if (value < min2) min2 = value; if (value > max2) max2 = value; } if ((max1-min1) < (max2-min2)) { //non-zero-crossing return min1; } else { //zero-crossing if (min2 < 0) min2 += 512; return min2; } } void EventBuilder::logDataToFile() { /* * Write data in binary format: * - number of boards: N = 1 x unsigned short * - number of channels per each board Cn: N x unsigned short * - N times the following sequence: * - SyncFrame S = 1 x SyncFrame (== 16 bytes) * - Data D = Cn x unsigned short */ logFile.write((const char*)&totalBoards, sizeof(unsigned short)); logFile.write((const char*)channelCounts.constData(), totalBoards * sizeof(unsigned short)); for (int board = 0; board < totalBoards; board++) { logFile.write((const char*)&(currentFrame[board].sync_frame), sizeof(SyncFrame)); logFile.write((const char*)currentFrame[board].sensor_data, currentFrame[board].buffer_size*sizeof(unsigned short)); } //write data in native binary format. All devices written as 5-sensor-wide! //logFile.write((const char*)currentFrame.constData(), nrReceivers*sizeof(BufferData)); } void EventBuilder::recalculateChannels() { totalBoards = baseAddresses.count(); if (totalBoards == 0) return; for (int i = 1; i < totalBoards; i++) baseAddresses[i] = baseAddresses[i-1] + channelCounts[i-1]; totalChannels = 0; for (int i = 0; i < channelCounts.count(); i++) totalChannels += channelCounts[i]; } void EventBuilder::setChannelCount(int sensor_nr, int nr_channels) { channelCounts[sensor_nr] = nr_channels; recalculateChannels(); } //************************* Protected slots ******************** void EventBuilder::onInit() { //Still nothing? Strange... initSemaphore.release(); } void EventBuilder::onDeinit() { //Still nothing? Strange... initSemaphore.release(); } void EventBuilder::onStartLogging() { if (loggingData) onStopLogging(); logFile.setFileName(logFileName); logFile.open(QIODevice::WriteOnly); loggingData = 1; } void EventBuilder::onStopLogging() { loggingData = 0; logFile.close(); } void EventBuilder::onStartTakingHistos(int sample_count) { histograms.resize(totalChannels); for (int ch = 0; ch < histograms.length(); ch++) histograms[ch].resize(65536); histogramSamplesToTake = sample_count; } void EventBuilder::onStopTakingHistos() { histogramSamplesToTake = 0; emit sigHistoCompleted(); } //******************** Thread-safe interface ******************* void EventBuilder::init() { emit sigInit(); initSemaphore.acquire(); //wait for initialization } void EventBuilder::deinit() { emit sigDeinit(); initSemaphore.acquire(); //wait for deinitialization } void EventBuilder::addSource(DataReceiver* source) { baseAddresses.push_back(0); channelCounts.push_back(0); receivers.append(source); nrReceivers = receivers.length(); currentFrame.resize(nrReceivers); connect(source, DataReceiver::sigDataReady, this, EventBuilder::onNewData); } void EventBuilder::deleteSources() { for (int i = 0; i < receivers.length(); i++) disconnect(receivers[i], DataReceiver::sigDataReady, this, EventBuilder::onNewData); receivers.clear(); nrReceivers = receivers.length(); baseAddresses.clear(); channelCounts.clear(); } void EventBuilder::startLogging(QString filename) { logFileName = filename; emit sigStartLogging(); } void EventBuilder::stopLogging() { emit sigStopLogging(); } int EventBuilder::isLogging() { return loggingData; } void EventBuilder::startTakingHistos(int sample_count) { emit sigStartTakingHistos(sample_count); } void EventBuilder::stopTakingHistos() { emit sigStopTakingHistos(); } QVector& EventBuilder::getHistos() { return histograms; } QVector EventBuilder::getLastFrame() { QMutexLocker locker(&lastFrameMutex); return lastFrame; } QVector EventBuilder::getNewFrame() { //wait for new data newDataSemaphore.acquire(1); //and return it return getLastFrame(); }