fast-feedback virtual target task code on STM Nucleo

Dependencies:   mbed

states.cpp

Committer:
gwappa
Date:
2018-06-30
Revision:
16:33c17c62840e
Parent:
15:20f7f737c256
Child:
17:0b241aa1f5b6

File content as of revision 16:33c17c62840e:

#include "states.h"
#include "rig.h"
#include "automaton.h"
#include "events.h"
#include "IO.h"

#define STATE_IS_LOGGED

#ifdef STATE_IS_LOGGED
#define LOGSTATE(S) IO::info(#S);
#else
#define LOGSTATE(S)
#endif

void tickBuzzer() {
    audioOut = !audioOut;
}

void finalize() {
    audioOut.write(0); // if any
    trial.markTrialEnd();
}

void Delay::setup() {
    LOGSTATE(Delay)
    
    // initialize the trial-related params
    trial.reset(task);
    audioOut.write(0);
    events::setup(true);
    
    // 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 MotionAlt:
        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));
    }
    
    trial.markTrialStart();
}

void Delay::teardown() {
    // do nothing
}

void Paired::setup() {
    LOGSTATE(Paired)
    trial.markEndOfWait();
    
    trial.response      |= TrialFlags::Cues;
    events::lickhandler  = &automaton::jump<Paired,WithResp>;
    
    // reward & visual feedback
    visualOut.start();
    rewardOut.start();
    
    stateTimeout.attach_us(&automaton::jump<Paired,NoResp>, ms_to_us(task.aud_dur_ms.value));
}

void Paired::teardown() {
    visualOut.stop();
    events::lickhandler = 0;
}

void Prepare::setup() {
    // mostly the same with for Delay
    // except that the animal cannot lick freely
    LOGSTATE(Prepare)
    
    // configure the interrupts
    // no whisk handler
    events::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
    events::lickhandler = 0;
}

void Cued::setup() {
    LOGSTATE(Cued)
    
    trial.markEndOfWait();
    
    trial.response &= ~TrialFlags::Cues;
    
    // configure the interrupts
    if (task.mode.value != MotionAlt) {
        events::lickhandler = &automaton::jump<Cued,Abort>;
    }
    
    // "cue" comes from either internal visual stimulus generation (Report, Associate)
    // or the animal's whisker motion (Motion)
    switch (task.mode.value) {
    case Motion:
        events::whiskhandler = &Cued::gate;
        break;
    case MotionAlt:
        events::whiskhandler = &automaton::jump<Cued,WithResp>;
        break;
    default:
        events::gatehandler  = &Cued::gate;
    }
    
    // start cue output
    switch(task.mode.value) {
    case Report:
        visualOut.run();
        // no auditory cue
        break;
    case Associate:
        visualOut.run();
        // fallthrough (with auditory cue)
    case Motion:
    case MotionAlt:
        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.aud_dur_ms.value));
}

void Cued::gate() {
    events::gatehandler  = 0;
    events::whiskhandler = 0;
    trial.response      |= TrialFlags::Cues;
    events::lickhandler  = &automaton::jump<Cued,WithResp>;
}

void Cued::teardown() {
    events::whiskhandler = 0;
    events::lickhandler  = 0;
    events::gatehandler  = 0;
    // end cue output
    buzzerTicker.detach();
    audioOut.write(0);
    if ((task.mode.value != Motion) && (task.mode.value != MotionAlt)) {
        visualOut.stop();
    }
}

void Abort::setup() {
    LOGSTATE(Abort)
    events::whiskhandler = 0;
    events::lickhandler  = 0;
    events::gatehandler  = 0;
    trial.markEndOfWait();
    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;
    events::whiskhandler = 0;
    events::lickhandler  = 0;
    events::gatehandler  = 0;
    
    if (task.mode.value != Pair) {
        // open/close the valve
        rewardOut.start();
    }
    
    stateTimeout.attach_us(&automaton::done<WithResp>, ms_to_us(task.post_dur_ms.value));
}

void WithResp::teardown() {
    finalize();
}

void NoResp::setup() {
    LOGSTATE(NoResp)
    events::whiskhandler = 0;
    events::lickhandler  = 0;
    events::gatehandler  = 0;
    
    // no reward here no matter the mode
    
    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.setOnset(0);
    rewardOut.setDuration(ms_to_us(task.reward_dur_ms.value));
    rewardOut.start();
    stateTimeout.attach_us(&automaton::done<TestReward>, ms_to_us(task.reward_dur_ms.value+100));
}

void TestReward::teardown() {
    // do nothing
}