Keisuke Sehara
/
STM32_Whisking
fast-feedback virtual target task code on STM Nucleo
states.cpp
- Committer:
- gwappa
- Date:
- 2018-06-19
- Revision:
- 10:7c216d528c35
- Parent:
- 9:e136394bdb39
- Child:
- 11:897ecd5413e0
File content as of revision 10:7c216d528c35:
#include "states.h" #include "rig.h" #include "automaton.h" #include "IO.h" #define STATE_IS_LOGGED #ifdef STATE_IS_LOGGED #define LOGSTATE(S) IO::info(#S); #else #define LOGSTATE(S) #endif void (*whiskhandler)() = 0; void (*lickhandler)() = 0; bool logged = false; void whiskcallback() { if (logged) { trial.whisking_events.add(timer.read_ms()); } if (whiskhandler != 0) { whiskhandler(); } } void lickcallback() { if (logged) { trial.licking_events.add(timer.read_ms()); } if (lickhandler != 0) { lickhandler(); } } void turnOff_trialStart() { trialStart.write(0); } void stopReward() { rewardOut.write(0); } void finalize() { cueOut.write(0); // if any trialEnd.write(1); wait_us(ms_to_us(TRIGGER_DUR_MS)); trial.writeToSerial(); timer.stop(); timer.reset(); } void Delay::setup() { LOGSTATE(Delay) // initialize the trial-related params trial.reset(task); // 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 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)); // update the timestamp trial.starting = timer.read_ms(); timer.start(); } void Delay::teardown() { // do nothing } void Prepare::setup() { // mostly the same with for Delay // except that the animal cannot lick freely LOGSTATE(Prepare) // configure the interrupts // no whisk handler (i.e. only to be logged) lickhandler = &automaton::jump<Prepare,Abort>; // set timeout for the next state stateTimeout.attach_us(&automaton::jump<Prepare,Cued>, ms_to_us(task.prep_dur_ms.value)); } 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); } void Cued::setup() { LOGSTATE(Cued) if (task.mode.value == Report) { enableOut.write(1); // enable the feedback only during Cued } // configure the interrupts if (task.mode.value == WithCue) { whiskhandler = &automaton::jump<Cued,WithResp>; trial.response |= TrialFlags::Cues; lickhandler = 0; } else { whiskhandler = &Cued::gate; lickhandler = &automaton::jump<Cued,Abort>; } // start cue output cueOut.write(1); // 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; } void Cued::gate() { whiskhandler = 0; // logging only trial.response |= TrialFlags::Cues; lickhandler = &automaton::jump<Cued,WithResp>; } void Cued::teardown() { whiskhandler = 0; lickhandler = 0; // end cue output cueOut.write(0); stateTimeout.detach(); if (task.mode.value == Report) { enableOut.write(0); } } void Abort::setup() { LOGSTATE(Abort) trial.waiting = timer.read_ms() - trial.starting; trial.response = TrialFlags::Licked; stateTimeout.attach_us(&automaton::done<Abort>, ms_to_us(task.post_dur_ms.value)); } void Abort::teardown() { finalize(); } void WithResp::setup() { LOGSTATE(WithResp) 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)); } stateTimeout.attach_us(&automaton::done<WithResp>, ms_to_us(task.post_dur_ms.value)); } void WithResp::teardown() { finalize(); } void NoResp::setup() { LOGSTATE(NoResp) // no reward here stateTimeout.attach_us(&automaton::done<NoResp>, ms_to_us(task.post_dur_ms.value)); } void NoResp::teardown() { finalize(); } void TestReward::setup() { LOGSTATE(TestReward) // open/close the valve rewardOut.write(1); rewardTimeout.attach_us(&stopReward, ms_to_us(task.reward_ms.value)); stateTimeout.attach_us(&automaton::done<TestReward>, ms_to_us(task.reward_ms.value+20)); } void TestReward::teardown() { // do nothing }