This repository has been archived by the owner. It is now read-only.
Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
AudioGameGUI/StateMachineController.cpp
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
266 lines (219 sloc)
8.93 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "StateMachineController.h" | |
StateMachineController::StateMachineController(QObject *parent): | |
QObject(parent) | |
{ | |
qRegisterMetaType<QVector<double>>("QVector<double>"); | |
// seed randomizer | |
srand(time(0)); | |
timerDialog = new TimerDialog(); | |
mainTimer = new QTimer(this); | |
mainTimer->setSingleShot(true); | |
stateMachine = new QStateMachine(this); | |
// Create the two top-level states | |
QState *runningState = new QState(stateMachine); | |
QState *pausedState = new QState(stateMachine); | |
// set up state machine | |
QState *state_preDelay = new QState(runningState); | |
QState *state_iti = new QState(runningState); | |
QState *state_userReaction = new QState(runningState); | |
QState *state_acquisitionBaseline = new QState(runningState); | |
QState *state_sound = new QState(runningState); | |
QHistoryState *historyState = new QHistoryState(runningState); | |
state_preDelay->addTransition(mainTimer, SIGNAL(timeout()), state_iti); | |
state_iti->addTransition(mainTimer, SIGNAL(timeout()), state_userReaction); | |
state_userReaction->addTransition(mainTimer, SIGNAL(timeout()), state_acquisitionBaseline); | |
state_acquisitionBaseline->addTransition(mainTimer, SIGNAL(timeout()), state_sound); | |
state_sound->addTransition(mainTimer, SIGNAL(timeout()), state_iti); | |
/** | |
* If we are in runningState and the pauseRequested() signal is emitted (that happens | |
* when the pause() slot has been invoked) then we go to the pausedState. | |
* If we are now in the pausedState and the pauseRequested() signal is emitted again, | |
* we go to the historyState which will forward us to the phase state we have been in | |
* when we left the runningState. | |
*/ | |
runningState->addTransition(this, SIGNAL(pauseRequested()), pausedState); | |
pausedState->addTransition(this, SIGNAL(pauseRequested()), historyState); | |
// Define which child state should be the initial state | |
runningState->setInitialState(state_preDelay); | |
stateMachine->setInitialState(runningState); | |
// connect states to functions for starting timers | |
// state pre delay | |
connect(state_preDelay, SIGNAL(entered()), this, SLOT(onStatePreDelayEntered())); | |
// state ITI | |
connect(state_iti, SIGNAL(entered()), this, SLOT(onStateItiEntered())); | |
// state user reaction | |
connect(state_userReaction, SIGNAL(entered()), this, SLOT(onStateUserReactionEntered())); | |
connect(state_userReaction, SIGNAL(exited()), this, SLOT(onStateUserReactionExited())); | |
connect(state_userReaction, SIGNAL(exited()), timerDialog, SLOT(removeTimer())); | |
// state baseline | |
connect(state_acquisitionBaseline, SIGNAL(entered()), this, SLOT(onStateAcquisitionBaselineEntered())); | |
// state sound | |
connect(state_sound, SIGNAL(entered()), this, SLOT(onStateSoundEntered())); | |
/*Connect pause signals*/ | |
connect(pausedState, SIGNAL(entered()), this, SLOT(onStatePauseEntered())); | |
connect(pausedState, SIGNAL(exited()), this, SLOT(onStatePauseExited())); | |
nidaq = new NIDAQmxInterface(); | |
nidaq->DAQmxSetDefaultEngine(); | |
// nidaq->DAQmxInitializeInterface(); | |
tdt = new TDTInterface(); | |
if(!tdt->initializeInterface()){ | |
logFileThread = new QThread(this); | |
logFileWriter = new LogFileWriter(); | |
socketThread = new QThread(this); | |
socketClient = new SocketClient(); | |
/*Thread-safe event communication*/ | |
/*Main -> Logfile*/ | |
connect(this, SIGNAL(openLogFile(QString)), logFileWriter, SLOT(onOpen(QString))); | |
connect(this, SIGNAL(closeLogFile()), logFileWriter, SLOT(onClose())); | |
connect(this, SIGNAL(writeToLogFile(QString, uint, uint, QString)), logFileWriter, SLOT(onWrite(QString, uint, uint, QString))); | |
connect(nidaq, SIGNAL(writeToLogFile(QString, uint, uint, QString)), logFileWriter, SLOT(onWrite(QString, uint, uint, QString))); | |
/*Socket -> Logfile*/ | |
connect(socketClient, SIGNAL(socketTrackingResult(QVector<double>)), logFileWriter, SLOT(onWriteTrackingResult(QVector<double>))); | |
socketClient->moveToThread(socketThread); | |
socketThread->start(); | |
logFileWriter->moveToThread(logFileThread); | |
logFileThread->start(); | |
}else{ | |
QMessageBox messageBox; | |
messageBox.critical(0,"Error","Unable to initialize TDT audio interface!\nYou will not be able to use this device."); | |
} | |
} | |
StateMachineController::~StateMachineController() | |
{ | |
if(logFileThread){ | |
logFileThread->quit(); | |
logFileThread->wait(); | |
delete logFileWriter; | |
} | |
if(socketThread){ | |
socketThread->quit(); | |
socketThread->wait(); | |
delete socketClient; | |
} | |
delete timerDialog; | |
delete nidaq; | |
delete tdt; | |
} | |
void StateMachineController::startStateMachine(audioGameSettings settings) | |
{ | |
if(stateMachine->isRunning()) //this should not happen | |
stopStateMachine(); | |
//stateMachine->stop(); | |
nidaq->DAQmxInitializeInterface(); | |
this->settings = settings; | |
trialsCurrent = 1; // set index for first trial (1-based) | |
trialsTotal = settings.trialSequence.length(); | |
nidaq->licksToReward = settings.licksToReward; | |
emit(openLogFile(settings.logFileName)); | |
QString timeString = QTime::currentTime().toString("hh:mm:ss.zzz"); | |
emit(writeToLogFile("INIT",0,0,timeString)); | |
// start state machine | |
stateMachine->start(); | |
} | |
void StateMachineController::pauseStateMachine() | |
{ | |
emit(pauseRequested()); | |
} | |
void StateMachineController::stopStateMachine() | |
{ | |
qDebug()<<"StateMachineController:stopStateMachine()"; | |
timerDialog->removeTimer(); | |
mainTimer->stop(); | |
stateMachine->stop(); | |
nidaq->DAQmxDestroyInterface(); | |
QString timeString = QTime::currentTime().toString("hh:mm:ss.zzz"); | |
emit(writeToLogFile("EXIT",0,0,timeString)); | |
emit(closeLogFile()); | |
} | |
void StateMachineController::onStatePreDelayEntered() | |
{ | |
qDebug() << "Pre delay"; | |
emit(statusMessage("Pre delay running")); | |
QString timeString = QTime::currentTime().toString("hh:mm:ss.zzz"); | |
emit(writeToLogFile("IDLE", 0, trialsCurrent,timeString)); | |
mainTimer->setInterval(settings.preDelay * 1000); | |
mainTimer->start(); | |
} | |
void StateMachineController::onStateItiEntered() | |
{ | |
qDebug() << "Entered Iti"; | |
emit(statusMessage("Starting trial begin")); | |
double nextItiValue = settings.itiSequence.at(trialsCurrent - 1); // -1 because trialsCurrent is 1-based | |
mainTimer->setInterval(nextItiValue * 1000); | |
mainTimer->start(); | |
} | |
void StateMachineController::onStateUserReactionEntered() | |
{ | |
timerDialog->removeTimer(); // remove previous timer dialog | |
timerDialog->setUpTimer(settings.userReaction); | |
timerDialog->show(); | |
timerDialog->startTimer(); | |
qDebug() << "Starting user reaction"; | |
emit(statusMessage("Starting user reaction")); | |
mainTimer->setInterval(settings.userReaction * 1000); | |
mainTimer->start(); | |
} | |
void StateMachineController::onStateUserReactionExited() | |
{ | |
qDebug() << "Triggering microscope"; | |
nidaq->DAQmxTriggerDO(NIDAQmxInterface::DAQ_PORT_DO_IMGAQ, true); | |
} | |
void StateMachineController::onStateAcquisitionBaselineEntered() | |
{ | |
qDebug() << "Starting baseline"; | |
emit(statusMessage("Starting baseline")); | |
mainTimer->setInterval(settings.preImaq * 1000); | |
mainTimer->start(); | |
} | |
void StateMachineController::onStateSoundEntered() | |
{ | |
qDebug() << "Loading sound"; | |
int soundType = settings.trialSequence.first(); | |
settings.trialSequence.pop_front(); | |
switch(soundType){ | |
case 0: | |
mainTimer->setInterval(settings.soundDurationNegative * 1000); | |
qDebug() << "Loading negative sound file:" << settings.fileNameNegative; | |
tdt->loadRCXCircuit(settings.fileNameNegative); | |
break; | |
case 1: | |
mainTimer->setInterval(settings.soundDurationPositive * 1000); | |
qDebug() << "Loading positive sound file:" << settings.fileNamePositive; | |
tdt->loadRCXCircuit(settings.fileNamePositive); | |
break; | |
} | |
qDebug() << "Starting sound"; | |
emit(statusMessage("Starting sound")); | |
mainTimer->start(); | |
nidaq->DAQmxTriggerDO(NIDAQmxInterface::DAQ_PORT_DO_SOUND, true); | |
qDebug() << "Finished sound"; | |
emit(statusMessage("Finished sound")); | |
// go to next trial | |
if(trialsCurrent < trialsTotal) { | |
//increase trial index | |
trialsCurrent++; | |
// or terminate | |
} else { | |
mainTimer->stop(); | |
stateMachine->stop(); | |
nidaq->DAQmxDestroyInterface(); | |
qDebug() << "Terminated"; | |
emit(statusMessage("Terminated")); | |
emit(terminated()); | |
QString timeString = QTime::currentTime().toString("hh:mm:ss.zzz"); | |
emit(writeToLogFile("EXIT",0,0,timeString)); | |
emit(closeLogFile()); | |
} | |
} | |
void StateMachineController::onStatePauseEntered() | |
{ | |
qDebug() << "Pause state entered"; | |
mainTimer->stop(); | |
nidaq->isPaused = true; | |
timerDialog->removeTimer(); | |
} | |
void StateMachineController::onStatePauseExited() | |
{ | |
nidaq->isPaused = false; | |
qDebug() << "Pause state exited"; | |
} |