fast-feedback virtual target task code on STM Nucleo

Dependencies:   mbed

Committer:
gwappa
Date:
Thu Jun 21 17:57:22 2018 +0000
Revision:
11:897ecd5413e0
Parent:
10:7c216d528c35
Child:
12:06ea96546af1
add auditory cue tickering

Who changed what in which revision?

UserRevisionLine numberNew contents of line
gwappa 4:fcf597f82632 1 #include "states.h"
gwappa 4:fcf597f82632 2 #include "rig.h"
gwappa 4:fcf597f82632 3 #include "automaton.h"
gwappa 4:fcf597f82632 4 #include "IO.h"
gwappa 4:fcf597f82632 5
gwappa 4:fcf597f82632 6 #define STATE_IS_LOGGED
gwappa 4:fcf597f82632 7
gwappa 4:fcf597f82632 8 #ifdef STATE_IS_LOGGED
gwappa 4:fcf597f82632 9 #define LOGSTATE(S) IO::info(#S);
gwappa 4:fcf597f82632 10 #else
gwappa 4:fcf597f82632 11 #define LOGSTATE(S)
gwappa 4:fcf597f82632 12 #endif
gwappa 4:fcf597f82632 13
gwappa 4:fcf597f82632 14 void (*whiskhandler)() = 0;
gwappa 4:fcf597f82632 15 void (*lickhandler)() = 0;
gwappa 11:897ecd5413e0 16 void (*gatehandler)() = 0;
gwappa 4:fcf597f82632 17 bool logged = false;
gwappa 4:fcf597f82632 18
gwappa 4:fcf597f82632 19 void whiskcallback() {
gwappa 4:fcf597f82632 20 if (logged) {
gwappa 4:fcf597f82632 21 trial.whisking_events.add(timer.read_ms());
gwappa 4:fcf597f82632 22 }
gwappa 4:fcf597f82632 23 if (whiskhandler != 0) {
gwappa 4:fcf597f82632 24 whiskhandler();
gwappa 4:fcf597f82632 25 }
gwappa 4:fcf597f82632 26 }
gwappa 4:fcf597f82632 27
gwappa 4:fcf597f82632 28 void lickcallback() {
gwappa 4:fcf597f82632 29 if (logged) {
gwappa 4:fcf597f82632 30 trial.licking_events.add(timer.read_ms());
gwappa 4:fcf597f82632 31 }
gwappa 4:fcf597f82632 32 if (lickhandler != 0) {
gwappa 4:fcf597f82632 33 lickhandler();
gwappa 4:fcf597f82632 34 }
gwappa 4:fcf597f82632 35 }
gwappa 4:fcf597f82632 36
gwappa 11:897ecd5413e0 37 void gateReward() {
gwappa 11:897ecd5413e0 38 if (gatehandler != 0) {
gwappa 11:897ecd5413e0 39 gatehandler();
gwappa 11:897ecd5413e0 40 }
gwappa 11:897ecd5413e0 41 }
gwappa 11:897ecd5413e0 42
gwappa 11:897ecd5413e0 43 void tickBuzzer() {
gwappa 11:897ecd5413e0 44 audioOut = !audioOut;
gwappa 9:e136394bdb39 45 }
gwappa 9:e136394bdb39 46
gwappa 11:897ecd5413e0 47 void setupInterrupts() {
gwappa 11:897ecd5413e0 48 // configure the interrupts
gwappa 11:897ecd5413e0 49 whiskIn.rise(&whiskcallback);
gwappa 11:897ecd5413e0 50 lickIn.rise(&lickcallback);
gwappa 11:897ecd5413e0 51
gwappa 11:897ecd5413e0 52 whiskhandler = 0;
gwappa 11:897ecd5413e0 53 lickhandler = 0;
gwappa 11:897ecd5413e0 54 gatehandler = 0;
gwappa 11:897ecd5413e0 55
gwappa 11:897ecd5413e0 56 // no whisk handler, no lick handler
gwappa 11:897ecd5413e0 57 // only to be logged
gwappa 11:897ecd5413e0 58 logged = true;
gwappa 9:e136394bdb39 59 }
gwappa 9:e136394bdb39 60
gwappa 4:fcf597f82632 61 void finalize() {
gwappa 11:897ecd5413e0 62 audioOut.write(0); // if any
gwappa 11:897ecd5413e0 63 trial.markTrialEnd();
gwappa 4:fcf597f82632 64 }
gwappa 4:fcf597f82632 65
gwappa 4:fcf597f82632 66 void Delay::setup() {
gwappa 4:fcf597f82632 67 LOGSTATE(Delay)
gwappa 4:fcf597f82632 68
gwappa 4:fcf597f82632 69 // initialize the trial-related params
gwappa 4:fcf597f82632 70 trial.reset(task);
gwappa 11:897ecd5413e0 71 visualOut.reset(task, (task.mode.value==Associate)||(task.mode.value==Motion));
gwappa 11:897ecd5413e0 72 audioOut.write(0);
gwappa 11:897ecd5413e0 73 rewardOut.setDuration(ms_to_us(task.reward_ms.value));
gwappa 11:897ecd5413e0 74 setupInterrupts();
gwappa 4:fcf597f82632 75
gwappa 11:897ecd5413e0 76 // set up the timeout for the next state
gwappa 9:e136394bdb39 77 switch (task.mode.value) {
gwappa 9:e136394bdb39 78 case Pair:
gwappa 9:e136394bdb39 79 stateTimeout.attach_us(&automaton::jump<Delay,Paired>, ms_to_us(trial.delay_dur_ms + task.prep_dur_ms.value));
gwappa 9:e136394bdb39 80 break;
gwappa 9:e136394bdb39 81 default:
gwappa 7:6744ec9ccc25 82 stateTimeout.attach_us(&automaton::jump<Delay,Prepare>, ms_to_us(trial.delay_dur_ms));
gwappa 7:6744ec9ccc25 83 }
gwappa 4:fcf597f82632 84
gwappa 11:897ecd5413e0 85 // TODO: start visual stim sequence for Associate mode
gwappa 9:e136394bdb39 86
gwappa 11:897ecd5413e0 87 trial.markTrialStart();
gwappa 4:fcf597f82632 88 }
gwappa 4:fcf597f82632 89
gwappa 4:fcf597f82632 90 void Delay::teardown() {
gwappa 4:fcf597f82632 91 // do nothing
gwappa 4:fcf597f82632 92 }
gwappa 4:fcf597f82632 93
gwappa 11:897ecd5413e0 94 void Paired::setup() {
gwappa 11:897ecd5413e0 95 LOGSTATE(Paired)
gwappa 11:897ecd5413e0 96 trial.markEndOfWait();
gwappa 11:897ecd5413e0 97
gwappa 11:897ecd5413e0 98 trial.response |= TrialFlags::Cues;
gwappa 11:897ecd5413e0 99 lickhandler = &automaton::jump<Paired,WithResp>;
gwappa 11:897ecd5413e0 100
gwappa 11:897ecd5413e0 101 // reward & visual feedback
gwappa 11:897ecd5413e0 102 visualOut.direct(true);
gwappa 11:897ecd5413e0 103 rewardOut.start();
gwappa 11:897ecd5413e0 104
gwappa 11:897ecd5413e0 105 stateTimeout.attach_us(&automaton::jump<Paired,NoResp>, ms_to_us(task.aud_dur_ms.value));
gwappa 11:897ecd5413e0 106 }
gwappa 11:897ecd5413e0 107
gwappa 11:897ecd5413e0 108 void Paired::teardown() {
gwappa 11:897ecd5413e0 109 visualOut.direct(false);
gwappa 11:897ecd5413e0 110 lickhandler = 0;
gwappa 11:897ecd5413e0 111 }
gwappa 11:897ecd5413e0 112
gwappa 7:6744ec9ccc25 113 void Prepare::setup() {
gwappa 7:6744ec9ccc25 114 // mostly the same with for Delay
gwappa 7:6744ec9ccc25 115 // except that the animal cannot lick freely
gwappa 7:6744ec9ccc25 116 LOGSTATE(Prepare)
gwappa 7:6744ec9ccc25 117
gwappa 7:6744ec9ccc25 118 // configure the interrupts
gwappa 7:6744ec9ccc25 119 // no whisk handler (i.e. only to be logged)
gwappa 7:6744ec9ccc25 120 lickhandler = &automaton::jump<Prepare,Abort>;
gwappa 7:6744ec9ccc25 121
gwappa 7:6744ec9ccc25 122 // set timeout for the next state
gwappa 7:6744ec9ccc25 123 stateTimeout.attach_us(&automaton::jump<Prepare,Cued>, ms_to_us(task.prep_dur_ms.value));
gwappa 11:897ecd5413e0 124 if (task.mode.value != Motion) {
gwappa 11:897ecd5413e0 125 visualOut.startPrepare();
gwappa 11:897ecd5413e0 126 }
gwappa 7:6744ec9ccc25 127 }
gwappa 7:6744ec9ccc25 128
gwappa 7:6744ec9ccc25 129 void Prepare::teardown() {
gwappa 7:6744ec9ccc25 130 // de-register lick inhibition
gwappa 7:6744ec9ccc25 131 lickhandler = 0;
gwappa 11:897ecd5413e0 132 if (task.mode.value != Motion) {
gwappa 11:897ecd5413e0 133 visualOut.endState();
gwappa 11:897ecd5413e0 134 }
gwappa 9:e136394bdb39 135 }
gwappa 9:e136394bdb39 136
gwappa 4:fcf597f82632 137 void Cued::setup() {
gwappa 4:fcf597f82632 138 LOGSTATE(Cued)
gwappa 4:fcf597f82632 139
gwappa 11:897ecd5413e0 140 trial.markEndOfWait();
gwappa 7:6744ec9ccc25 141
gwappa 4:fcf597f82632 142 // configure the interrupts
gwappa 11:897ecd5413e0 143 lickhandler = &automaton::jump<Cued,Abort>;
gwappa 11:897ecd5413e0 144
gwappa 11:897ecd5413e0 145 // "cue" comes from either internal visual stimulus generation (Report, Associate)
gwappa 11:897ecd5413e0 146 // or the animal's whisker motion (Motion)
gwappa 11:897ecd5413e0 147 if (task.mode.value == Motion) {
gwappa 11:897ecd5413e0 148 whiskhandler = &Cued::gate;
gwappa 7:6744ec9ccc25 149 } else {
gwappa 11:897ecd5413e0 150 gatehandler = &Cued::gate;
gwappa 7:6744ec9ccc25 151 }
gwappa 7:6744ec9ccc25 152
gwappa 7:6744ec9ccc25 153 // start cue output
gwappa 11:897ecd5413e0 154 switch (task.mode.value) {
gwappa 11:897ecd5413e0 155 case Report:
gwappa 11:897ecd5413e0 156 visualOut.startCue(&gateReward);
gwappa 11:897ecd5413e0 157 break;
gwappa 11:897ecd5413e0 158 case Associate:
gwappa 11:897ecd5413e0 159 visualOut.startCue(&gateReward);
gwappa 11:897ecd5413e0 160 // fallthrough
gwappa 11:897ecd5413e0 161 case Motion:
gwappa 11:897ecd5413e0 162 audioOut.write(1);
gwappa 11:897ecd5413e0 163 buzzerTicker.attach_us(&tickBuzzer, trial.aud_ticker_cycle);
gwappa 11:897ecd5413e0 164 }
gwappa 4:fcf597f82632 165
gwappa 4:fcf597f82632 166 // sets the timeout for the next state
gwappa 11:897ecd5413e0 167 stateTimeout.attach_us(&automaton::jump<Cued,NoResp>, ms_to_us(task.aud_dur_ms.value));
gwappa 4:fcf597f82632 168 }
gwappa 4:fcf597f82632 169
gwappa 7:6744ec9ccc25 170 void Cued::gate() {
gwappa 11:897ecd5413e0 171 gatehandler = 0;
gwappa 11:897ecd5413e0 172 whiskhandler = 0;
gwappa 8:973dcd190672 173 trial.response |= TrialFlags::Cues;
gwappa 7:6744ec9ccc25 174 lickhandler = &automaton::jump<Cued,WithResp>;
gwappa 7:6744ec9ccc25 175 }
gwappa 7:6744ec9ccc25 176
gwappa 4:fcf597f82632 177 void Cued::teardown() {
gwappa 4:fcf597f82632 178 whiskhandler = 0;
gwappa 7:6744ec9ccc25 179 lickhandler = 0;
gwappa 11:897ecd5413e0 180 gatehandler = 0;
gwappa 7:6744ec9ccc25 181 // end cue output
gwappa 11:897ecd5413e0 182 buzzerTicker.detach();
gwappa 11:897ecd5413e0 183 audioOut.write(0);
gwappa 11:897ecd5413e0 184 if (task.mode.value != Motion) {
gwappa 11:897ecd5413e0 185 visualOut.endState();
gwappa 7:6744ec9ccc25 186 }
gwappa 7:6744ec9ccc25 187 }
gwappa 7:6744ec9ccc25 188
gwappa 7:6744ec9ccc25 189 void Abort::setup() {
gwappa 7:6744ec9ccc25 190 LOGSTATE(Abort)
gwappa 11:897ecd5413e0 191 trial.markEndOfWait();
gwappa 8:973dcd190672 192 trial.response = TrialFlags::Licked;
gwappa 8:973dcd190672 193 stateTimeout.attach_us(&automaton::done<Abort>, ms_to_us(task.post_dur_ms.value));
gwappa 7:6744ec9ccc25 194 }
gwappa 7:6744ec9ccc25 195
gwappa 7:6744ec9ccc25 196 void Abort::teardown() {
gwappa 7:6744ec9ccc25 197 finalize();
gwappa 4:fcf597f82632 198 }
gwappa 4:fcf597f82632 199
gwappa 4:fcf597f82632 200 void WithResp::setup() {
gwappa 4:fcf597f82632 201 LOGSTATE(WithResp)
gwappa 4:fcf597f82632 202
gwappa 4:fcf597f82632 203 trial.response |= TrialFlags::Responded;
gwappa 4:fcf597f82632 204
gwappa 9:e136394bdb39 205 if (task.mode.value != Pair) {
gwappa 9:e136394bdb39 206 // open/close the valve
gwappa 11:897ecd5413e0 207 rewardOut.start();
gwappa 9:e136394bdb39 208 }
gwappa 4:fcf597f82632 209
gwappa 5:849446d19406 210 stateTimeout.attach_us(&automaton::done<WithResp>, ms_to_us(task.post_dur_ms.value));
gwappa 11:897ecd5413e0 211 if (task.mode.value != Motion) {
gwappa 11:897ecd5413e0 212 visualOut.startPrepare();
gwappa 11:897ecd5413e0 213 }
gwappa 4:fcf597f82632 214 }
gwappa 4:fcf597f82632 215
gwappa 4:fcf597f82632 216 void WithResp::teardown() {
gwappa 11:897ecd5413e0 217 if (task.mode.value != Motion) {
gwappa 11:897ecd5413e0 218 visualOut.endState();
gwappa 11:897ecd5413e0 219 }
gwappa 4:fcf597f82632 220 finalize();
gwappa 4:fcf597f82632 221 }
gwappa 4:fcf597f82632 222
gwappa 4:fcf597f82632 223 void NoResp::setup() {
gwappa 4:fcf597f82632 224 LOGSTATE(NoResp)
gwappa 4:fcf597f82632 225
gwappa 11:897ecd5413e0 226 // no reward here no matter the mode
gwappa 7:6744ec9ccc25 227
gwappa 5:849446d19406 228 stateTimeout.attach_us(&automaton::done<NoResp>, ms_to_us(task.post_dur_ms.value));
gwappa 11:897ecd5413e0 229 if (task.mode.value != Motion) {
gwappa 11:897ecd5413e0 230 visualOut.startPrepare();
gwappa 11:897ecd5413e0 231 }
gwappa 4:fcf597f82632 232 }
gwappa 4:fcf597f82632 233 void NoResp::teardown() {
gwappa 11:897ecd5413e0 234 if (task.mode.value != Motion) {
gwappa 11:897ecd5413e0 235 visualOut.endState();
gwappa 11:897ecd5413e0 236 }
gwappa 4:fcf597f82632 237 finalize();
gwappa 8:973dcd190672 238 }
gwappa 8:973dcd190672 239
gwappa 8:973dcd190672 240 void TestReward::setup() {
gwappa 8:973dcd190672 241 LOGSTATE(TestReward)
gwappa 8:973dcd190672 242
gwappa 8:973dcd190672 243 // open/close the valve
gwappa 11:897ecd5413e0 244 rewardOut.setDuration(ms_to_us(task.reward_ms.value));
gwappa 11:897ecd5413e0 245 rewardOut.start();
gwappa 8:973dcd190672 246 stateTimeout.attach_us(&automaton::done<TestReward>, ms_to_us(task.reward_ms.value+20));
gwappa 8:973dcd190672 247 }
gwappa 8:973dcd190672 248
gwappa 8:973dcd190672 249 void TestReward::teardown() {
gwappa 8:973dcd190672 250 // do nothing
gwappa 4:fcf597f82632 251 }