Keisuke Sehara
/
STM32_Whisking
fast-feedback virtual target task code on STM Nucleo
Diff: states.cpp
- Revision:
- 11:897ecd5413e0
- Parent:
- 10:7c216d528c35
- Child:
- 12:06ea96546af1
--- a/states.cpp Tue Jun 19 10:11:23 2018 +0000 +++ b/states.cpp Thu Jun 21 17:57:22 2018 +0000 @@ -13,6 +13,7 @@ void (*whiskhandler)() = 0; void (*lickhandler)() = 0; +void (*gatehandler)() = 0; bool logged = false; void whiskcallback() { @@ -33,22 +34,33 @@ } } -void turnOff_trialStart() { - trialStart.write(0); +void gateReward() { + if (gatehandler != 0) { + gatehandler(); + } +} + +void tickBuzzer() { + audioOut = !audioOut; } -void stopReward() { - rewardOut.write(0); +void setupInterrupts() { + // configure the interrupts + whiskIn.rise(&whiskcallback); + lickIn.rise(&lickcallback); + + whiskhandler = 0; + lickhandler = 0; + gatehandler = 0; + + // no whisk handler, no lick handler + // only to be logged + logged = true; } void finalize() { - cueOut.write(0); // if any - trialEnd.write(1); - wait_us(ms_to_us(TRIGGER_DUR_MS)); - - trial.writeToSerial(); - timer.stop(); - timer.reset(); + audioOut.write(0); // if any + trial.markTrialEnd(); } void Delay::setup() { @@ -56,48 +68,48 @@ // initialize the trial-related params trial.reset(task); + visualOut.reset(task, (task.mode.value==Associate)||(task.mode.value==Motion)); + audioOut.write(0); + rewardOut.setDuration(ms_to_us(task.reward_ms.value)); + setupInterrupts(); - // configure the flags - cueOut.write(0); - if ( (task.mode.value == WithCue) || (task.mode.value == Report) ) { - enableOut.write(1); - } else { - enableOut.write(0); - } - rewardOut.write(0); - - // configure the interrupts - whiskIn.rise(&whiskcallback); - lickIn.rise(&lickcallback); - // no whisk handler, no lick handler - // only to be logged - logged = true; - - // sets the timeout for the next state + // set up the timeout for the next state switch (task.mode.value) { case Pair: stateTimeout.attach_us(&automaton::jump<Delay,Paired>, ms_to_us(trial.delay_dur_ms + task.prep_dur_ms.value)); break; - case WithCue: - stateTimeout.attach_us(&automaton::jump<Delay,Cued>, ms_to_us(trial.delay_dur_ms + task.prep_dur_ms.value)); - break; default: stateTimeout.attach_us(&automaton::jump<Delay,Prepare>, ms_to_us(trial.delay_dur_ms)); } - // trigger trialStart - trialStart.write(1); - triggerTimeout.attach_us(&turnOff_trialStart, ms_to_us(TRIGGER_DUR_MS)); + // TODO: start visual stim sequence for Associate mode - // update the timestamp - trial.starting = timer.read_ms(); - timer.start(); + trial.markTrialStart(); } void Delay::teardown() { // do nothing } +void Paired::setup() { + LOGSTATE(Paired) + trial.markEndOfWait(); + + trial.response |= TrialFlags::Cues; + lickhandler = &automaton::jump<Paired,WithResp>; + + // reward & visual feedback + visualOut.direct(true); + rewardOut.start(); + + stateTimeout.attach_us(&automaton::jump<Paired,NoResp>, ms_to_us(task.aud_dur_ms.value)); +} + +void Paired::teardown() { + visualOut.direct(false); + lickhandler = 0; +} + void Prepare::setup() { // mostly the same with for Delay // except that the animal cannot lick freely @@ -109,64 +121,55 @@ // set timeout for the next state stateTimeout.attach_us(&automaton::jump<Prepare,Cued>, ms_to_us(task.prep_dur_ms.value)); + if (task.mode.value != Motion) { + visualOut.startPrepare(); + } } void Prepare::teardown() { // de-register lick inhibition lickhandler = 0; -} - -void Paired::setup() { - LOGSTATE(Paired) - trial.response |= TrialFlags::Cues; - lickhandler = &automaton::jump<Paired,WithResp>; - - // reward & visual feedback - enableOut.write(1); - trial.cuestarting = timer.read_ms(); - trial.waiting = trial.cuestarting - trial.starting; - - rewardOut.write(1); - rewardTimeout.attach_us(&stopReward, ms_to_us(task.reward_ms.value)); - - stateTimeout.attach_us(&automaton::jump<Paired,NoResp>, ms_to_us(task.cue_dur_ms.value)); -} - -void Paired::teardown() { - enableOut.write(0); + if (task.mode.value != Motion) { + visualOut.endState(); + } } void Cued::setup() { LOGSTATE(Cued) - if (task.mode.value == Report) { - enableOut.write(1); // enable the feedback only during Cued - } + trial.markEndOfWait(); // configure the interrupts - if (task.mode.value == WithCue) { - whiskhandler = &automaton::jump<Cued,WithResp>; - trial.response |= TrialFlags::Cues; - lickhandler = 0; - + lickhandler = &automaton::jump<Cued,Abort>; + + // "cue" comes from either internal visual stimulus generation (Report, Associate) + // or the animal's whisker motion (Motion) + if (task.mode.value == Motion) { + whiskhandler = &Cued::gate; } else { - whiskhandler = &Cued::gate; - lickhandler = &automaton::jump<Cued,Abort>; + gatehandler = &Cued::gate; } // start cue output - cueOut.write(1); + switch (task.mode.value) { + case Report: + visualOut.startCue(&gateReward); + break; + case Associate: + visualOut.startCue(&gateReward); + // fallthrough + case Motion: + audioOut.write(1); + buzzerTicker.attach_us(&tickBuzzer, trial.aud_ticker_cycle); + } // sets the timeout for the next state - stateTimeout.attach_us(&automaton::jump<Cued,NoResp>, ms_to_us(task.cue_dur_ms.value)); - - // update the timestamp - trial.cuestarting = timer.read_ms(); - trial.waiting = trial.cuestarting - trial.starting; + stateTimeout.attach_us(&automaton::jump<Cued,NoResp>, ms_to_us(task.aud_dur_ms.value)); } void Cued::gate() { - whiskhandler = 0; // logging only + gatehandler = 0; + whiskhandler = 0; trial.response |= TrialFlags::Cues; lickhandler = &automaton::jump<Cued,WithResp>; } @@ -174,19 +177,18 @@ void Cued::teardown() { whiskhandler = 0; lickhandler = 0; + gatehandler = 0; // end cue output - cueOut.write(0); - - stateTimeout.detach(); - - if (task.mode.value == Report) { - enableOut.write(0); + buzzerTicker.detach(); + audioOut.write(0); + if (task.mode.value != Motion) { + visualOut.endState(); } } void Abort::setup() { LOGSTATE(Abort) - trial.waiting = timer.read_ms() - trial.starting; + trial.markEndOfWait(); trial.response = TrialFlags::Licked; stateTimeout.attach_us(&automaton::done<Abort>, ms_to_us(task.post_dur_ms.value)); } @@ -200,30 +202,38 @@ trial.response |= TrialFlags::Responded; - whiskhandler = 0; - lickhandler = 0; - if (task.mode.value != Pair) { // open/close the valve - rewardOut.write(1); - rewardTimeout.attach_us(&stopReward, ms_to_us(task.reward_ms.value)); + rewardOut.start(); } stateTimeout.attach_us(&automaton::done<WithResp>, ms_to_us(task.post_dur_ms.value)); + if (task.mode.value != Motion) { + visualOut.startPrepare(); + } } void WithResp::teardown() { + if (task.mode.value != Motion) { + visualOut.endState(); + } finalize(); } void NoResp::setup() { LOGSTATE(NoResp) - // no reward here + // no reward here no matter the mode stateTimeout.attach_us(&automaton::done<NoResp>, ms_to_us(task.post_dur_ms.value)); + if (task.mode.value != Motion) { + visualOut.startPrepare(); + } } void NoResp::teardown() { + if (task.mode.value != Motion) { + visualOut.endState(); + } finalize(); } @@ -231,8 +241,8 @@ LOGSTATE(TestReward) // open/close the valve - rewardOut.write(1); - rewardTimeout.attach_us(&stopReward, ms_to_us(task.reward_ms.value)); + rewardOut.setDuration(ms_to_us(task.reward_ms.value)); + rewardOut.start(); stateTimeout.attach_us(&automaton::done<TestReward>, ms_to_us(task.reward_ms.value+20)); }