fast-feedback virtual target task code on STM Nucleo

Dependencies:   mbed

main.cpp

Committer:
gwappa
Date:
2018-05-14
Revision:
0:f736749c33d2
Child:
1:871d3066c2ab

File content as of revision 0:f736749c33d2:

#include "mbed.h"
#include "IO.h"
#include "random.h"

/*
 * command characters
 */
#define CMD_MODE_PAIR     'P'
#define CMD_MODE_APPEAR   'A'
#define CMD_TEST_REWARD   'T'
#define CMD_EXECUTE       'x'

#define CHR_DELAY_MIN     'm'
#define CHR_DELAY_VAR     'v'
#define CHR_PREP_DUR      'p'
#define CHR_CUE_DUR       'c'
#define CHR_POST_DUR      'n'
#define CHR_REWARD_DUR    'r'

#define STR_DELIMITER     ";"
#define STR_NEWLINE       "\r\n"

Timeout     interval;
DigitalOut  cue(LED1);
InterruptIn whisking(USER_BUTTON);

enum Mode {
    Pair,
    Appear
};

/**
 * the trial mode.
 */
Mode mode = Pair;

/**
 * the minimum duration for the delay.
 */
uint16_t      delay_min_ms  = 3500;
/**
 * the average for the (exponential) variable duration of the delay.
 */
uint16_t      delay_var_ms  = 3000;
/**
 * the duration of the "preparatory period", during which licking is not allowed.
 */
uint16_t      prep_dur_ms   = 1500;
/**
 * the cue duration.
 */
uint16_t      cue_dur_ms    = 3000;
/**
 * the post-reward recording duration.
 */
uint16_t      post_dur_ms   = 4000;
/**
 * the duration of reward, in microseconds
 */
unsigned long reward_us     = 40000;


void writeModeToSerial(bool newline=true){
    IO::write(IO::CONFIG_HEADER);
#define WRITE(CHR, VAL) if (mode == (VAL)) { IO::write("[%c]",CHR); } else { IO::write("%c",CHR); }
    WRITE(CMD_MODE_PAIR, Pair)
    WRITE(CMD_MODE_APPEAR, Appear)
#undef WRITE
    if (newline) {
        IO::write(STR_NEWLINE);
    }
}

void writeSettingsToSerial()
{
  writeModeToSerial(false);
  IO::write(STR_DELIMITER);
#define WRITE(CHR, PARAM, END) IO::write("%c%u",CHR,PARAM); if (END) { IO::write(STR_NEWLINE); } else { IO::write(STR_DELIMITER); }
  WRITE(CHR_DELAY_MIN,  delay_min_ms,   false)
  WRITE(CHR_DELAY_VAR,  delay_var_ms,   false)
  WRITE(CHR_PREP_DUR,   prep_dur_ms,    false)
  WRITE(CHR_CUE_DUR,    cue_dur_ms,     false)
  WRITE(CHR_POST_DUR,   post_dur_ms,    false)
  WRITE(CHR_REWARD_DUR, reward_us/1000, true)
#undef WRITE
}

inline bool isWhitespace(const char& ch) {
    return  (ch == ' ') ||
            (ch == '\t') ||
            (ch == '\r') ||
            (ch == '\n') ||
            (ch == '\v') ||
            (ch == '\f');
}

uint16_t parseUnsignedFromSerial(const uint16_t& orig)
{
  uint16_t value = 0;
  while(true) {
    
    int readChar = IO::getc();

    // only accepts digits
    if ((readChar >= 48) && (readChar <= 57)) {
      value = value * 10 + (readChar - 48);
      // continues parsing
      
    } else if ( isWhitespace((char)readChar) || (readChar == 59) ) {
      // space or ';'
      // ends parsing
      break;
      
    } else {
      IO::error("%c",(char)readChar);
      // set value back to original
      value = orig;
      break;
      
    }
  }
  
  return value;
}

void parse(const char& in) {
    if (isWhitespace(in)) {
        return;
    }
    
    switch(in) {
    case CMD_TEST_REWARD:
        // Cued::turnOnReward();
        // while(Cued::phase != Cued::Done);
        // LOG_REWARDED
        IO::result("done");
        break;
    
    case CMD_EXECUTE:
        // TRIAL_STARTING
        // automaton::run();
        IO::result("done");
        break;
    
    case '?': writeSettingsToSerial(); break;
    case CMD_MODE_PAIR:   mode = Pair;   writeModeToSerial(); break;
    case CMD_MODE_APPEAR: mode = Appear; writeModeToSerial(); break;
#define PARSE(CHR, TYPE, PARAM, FACTOR) case (CHR): PARAM = ((TYPE)(parseUnsignedFromSerial((uint16_t)((PARAM)/(FACTOR)))))*(FACTOR);\
        IO::config("%c%u",(CHR),((PARAM)/(FACTOR))); break;
    
    PARSE(CHR_DELAY_MIN, uint16_t, delay_min_ms, 1)
    PARSE(CHR_DELAY_VAR, uint16_t, delay_var_ms, 1)
    PARSE(CHR_PREP_DUR,  uint16_t, prep_dur_ms,  1)
    PARSE(CHR_CUE_DUR,   uint16_t, cue_dur_ms,   1)
    PARSE(CHR_POST_DUR,  uint16_t, post_dur_ms,  1)
    PARSE(CHR_REWARD_DUR, unsigned long, reward_us, 1000)
#undef PARSE
    default:
        IO::error("%c",in);
        break;
    }
}

int main()
{
    // random::init();
    // automaton::init<Delay>();
    while(1){
        // wait for the host to access
        parse(IO::getc());
    }
}