Dependencies:   mbed

main.cpp

Committer:
akpc806a
Date:
2016-12-04
Revision:
0:2cb59ea20ace
Child:
1:4683702d7ad8

File content as of revision 0:2cb59ea20ace:

#include "mbed.h"

#define USE_PRINTF (1)

DigitalOut led_blue(PB_5);



#include "OpenBCI_32_Daisy.h"

//------------------------------------------------------------------------------
void setup(void);
void loop();
void loadChannelSettings(char c);
void eventSerial();
void getCommand(char token);
void sendEOT();
void loadChannelSettings(char c);
void writeChannelSettings_maintainRunningState(char chan);
void setChannelsToDefaultSetting();
void loadLeadOffSettings(char c);
char getChannelNumber(char n);
void changeChannelState_maintainRunningState(byte chan, int start);
void activateAllChannelsToTestCondition(byte testInputCode, byte amplitudeCode, byte freqCode);
int changeChannelLeadOffDetect_maintainRunningState(char chan);
void sendDefaultChannelSettings();
boolean stopRunning(void);
boolean startRunning(int OUT_TYPE);
void printRegisters();
void startFromScratch();


//------------------------------------------------------------------------------
//  << SD CARD BUSINESS >>
boolean SDfileOpen = false;
char fileSize = '0';  // SD file size indicator
int blockCounter = 0;
//------------------------------------------------------------------------------
//  << OpenBCI BUSINESS >>
boolean is_running = false;    // this flag is set in serialEvent on reciept of ascii prompt
OpenBCI_32_Daisy OBCI;         //Uses SPI bus and pins to say data is ready.
// these are used to change individual channel settings from PC
char currentChannelToSet;      // keep track of what channel we're loading settings for
boolean getChannelSettings = false; // used to receive channel settings command
int channelSettingsCounter;    // used to retrieve channel settings from serial port
int leadOffSettingsCounter;
boolean getLeadOffSettings = false;
// these are all subject to the radio requirements: 31byte max packet length (maxPacketLength - 1 for packet checkSum)
#define OUTPUT_NOTHING (0)        // quiet
#define OUTPUT_8_CHAN (1)         // not using Daisy module
#define OUTPUT_16_CHAN (2)        // using Daisy module
int outputType = OUTPUT_8_CHAN;   // default to 8 channels

//------------------------------------------------------------------------------
//  << LIS3DH Accelerometer Business >>
boolean addAccelToSD = false;   // this flag get's set and cleared in the code below
//------------------------------------------------------------------------------
//  << PUT FILTER STUFF HERE >>
boolean useFilters = false;     // add DSP if you like, and set this true to turn them on
//------------------------------------------------------------------------------
//  << BASIC BOARD STUFF >>
int LED = 11;     // alias for the blue LED
int PGCpin = 12;  // PGC pin goes high when PIC is in bootloader mode
//------------------------------------------------------------------------------
//  << AUXILIARY DATA STUFF >>
boolean addAuxToSD = false;     // use this to write auxiliary data to SD if you like
//------------------------------------------------------------------------------
void setup(void) {

  pinMode(LED, OUTPUT); digitalWrite(LED, HIGH);   // blue LED
  pinMode(PGCpin, OUTPUT); digitalWrite(PGCpin, LOW); // used to tell RFduino if we are in bootloader mode NOT IMPLEMENTED
  delay(1000);            // take a break

  startFromScratch();     // initialize OpenBCI, read device IDs
  // you can set EITHER useAccel or useAux to true
  // if you want both, you MUST set and clear one of the variables every sample
  OBCI.useAccel = true;  // option to add/remove accelerometer data to stream
  OBCI.useAux = false;     // option to add/remove auxiliary data to stream


}



void loop() {

  if (is_running) {

    while (!(OBCI.isDataAvailable())) {} // wait for DRDY pin...

    OBCI.updateChannelData();            // get the fresh ADS results
    if (OBCI.useAccel && OBCI.LIS3DH_DataAvailable()) {
      OBCI.LIS3DH_updateAxisData();      // fresh axis data goes into the X Y Z
      addAccelToSD = true;
    }
    if (SDfileOpen) {
      writeDataToSDcard(OBCI.sampleCounter); // store data locally
    }

    OBCI.sendChannelData();  // serial fire hose
  }

  eventSerial();

}


// some variables to help find 'burger protocol' commands
int plusCounter = 0;
char testChar;
unsigned long commandTimer;

void eventSerial() {
  while (Serial0.available()) {
    char inChar = (char)Serial0.read();
    
    //getCommand(inChar);    // decode the command

    if (getChannelSettings) { // if we just got an 'x' expect channel setting parameters
      loadChannelSettings(inChar);  // go get em!
    } else if (getLeadOffSettings) { // if we just got a 'z' expect lead-off setting parameters
      loadLeadOffSettings(inChar); // go get em!
    } else {
      getCommand(inChar);    // decode the command
    }
    
/*
    if (plusCounter == 1) { // if we have received the first 'bun'
      testChar = inChar;   // this might be the 'patty', stop laughing
      plusCounter++;       // get ready to look for another 'bun'
      commandTimer = millis();  // don't wait too long!
    }

    if (inChar == '+') { // if we see a 'bun' on the serial
      plusCounter++;    // make a note of it
      if (plusCounter == 3) { // looks like we got a command character
        if (millis() - commandTimer < 5) { // if it's not too late,
          if (getChannelSettings) { // if we just got an 'x' expect channel setting parameters
            loadChannelSettings(testChar);  // go get em!
          } else if (getLeadOffSettings) { // if we just got a 'z' expect lead-off setting parameters
            loadLeadOffSettings(testChar); // go get em!
          } else {
            getCommand(testChar);    // decode the command
          }
        }
        plusCounter = 0;  // get ready for the next one
      }
    }
*/
  }
}


void getCommand(char token) {
  switch (token) {
    //TURN CHANNELS ON/OFF COMMANDS
    case '1':
      changeChannelState_maintainRunningState(1, DEACTIVATE); break;
    case '2':
      changeChannelState_maintainRunningState(2, DEACTIVATE); break;
    case '3':
      changeChannelState_maintainRunningState(3, DEACTIVATE); break;
    case '4':
      changeChannelState_maintainRunningState(4, DEACTIVATE); break;
    case '5':
      changeChannelState_maintainRunningState(5, DEACTIVATE); break;
    case '6':
      changeChannelState_maintainRunningState(6, DEACTIVATE); break;
    case '7':
      changeChannelState_maintainRunningState(7, DEACTIVATE); break;
    case '8':
      changeChannelState_maintainRunningState(8, DEACTIVATE); break;
    case '!':
      changeChannelState_maintainRunningState(1, ACTIVATE); break;
    case '@':
      changeChannelState_maintainRunningState(2, ACTIVATE); break;
    case '#':
      changeChannelState_maintainRunningState(3, ACTIVATE); break;
    case '$':
      changeChannelState_maintainRunningState(4, ACTIVATE); break;
    case '%':
      changeChannelState_maintainRunningState(5, ACTIVATE); break;
    case '^':
      changeChannelState_maintainRunningState(6, ACTIVATE); break;
    case '&':
      changeChannelState_maintainRunningState(7, ACTIVATE); break;
    case '*':
      changeChannelState_maintainRunningState(8, ACTIVATE); break;
    case 'q':
      changeChannelState_maintainRunningState(9, DEACTIVATE); break;
    case 'w':
      changeChannelState_maintainRunningState(10, DEACTIVATE); break;
    case 'e':
      changeChannelState_maintainRunningState(11, DEACTIVATE); break;
    case 'r':
      changeChannelState_maintainRunningState(12, DEACTIVATE); break;
    case 't':
      changeChannelState_maintainRunningState(13, DEACTIVATE); break;
    case 'y':
      changeChannelState_maintainRunningState(14, DEACTIVATE); break;
    case 'u':
      changeChannelState_maintainRunningState(15, DEACTIVATE); break;
    case 'i':
      changeChannelState_maintainRunningState(16, DEACTIVATE); break;
    case 'Q':
      changeChannelState_maintainRunningState(9, ACTIVATE); break;
    case 'W':
      changeChannelState_maintainRunningState(10, ACTIVATE); break;
    case 'E':
      changeChannelState_maintainRunningState(11, ACTIVATE); break;
    case 'R':
      changeChannelState_maintainRunningState(12, ACTIVATE); break;
    case 'T':
      changeChannelState_maintainRunningState(13, ACTIVATE); break;
    case 'Y':
      changeChannelState_maintainRunningState(14, ACTIVATE); break;
    case 'U':
      changeChannelState_maintainRunningState(15, ACTIVATE); break;
    case 'I':
      changeChannelState_maintainRunningState(16, ACTIVATE); break;

    // TEST SIGNAL CONTROL COMMANDS
    case '0':
      activateAllChannelsToTestCondition(ADSINPUT_SHORTED, ADSTESTSIG_NOCHANGE, ADSTESTSIG_NOCHANGE); break;
    case '-':
      activateAllChannelsToTestCondition(ADSINPUT_TESTSIG, ADSTESTSIG_AMP_1X, ADSTESTSIG_PULSE_SLOW); break;
    case '=':
      activateAllChannelsToTestCondition(ADSINPUT_TESTSIG, ADSTESTSIG_AMP_1X, ADSTESTSIG_PULSE_FAST); break;
    case 'p':
      activateAllChannelsToTestCondition(ADSINPUT_TESTSIG, ADSTESTSIG_AMP_2X, ADSTESTSIG_DCSIG); break;
    case '[':
      activateAllChannelsToTestCondition(ADSINPUT_TESTSIG, ADSTESTSIG_AMP_2X, ADSTESTSIG_PULSE_SLOW); break;
    case ']':
      activateAllChannelsToTestCondition(ADSINPUT_TESTSIG, ADSTESTSIG_AMP_2X, ADSTESTSIG_PULSE_FAST); break;

    // SD CARD COMMANDS
    //    5min     15min    30min    1hr      2hr      4hr      12hr     24hr    512blocks
    case 'A': case'S': case'F': case'G': case'H': case'J': case'K': case'L': case 'a':
      fileSize = token; SDfileOpen = setupSDcard(fileSize); //
      break;
    case 'j': // close the file, if it's open
      if (SDfileOpen) {
        SDfileOpen = closeSDfile();
      }
      break;

    // CHANNEL SETTING COMMANDS
    case 'x':  // expect 6 parameters
      if (!is_running) {
        Serial0.println("ready to accept new channel settings");
      }
      channelSettingsCounter = 0;
      getChannelSettings = true; break;
    case 'X':  // latch channel settings
      if (!is_running) {
        Serial0.println("updating channel settings");
      }
      writeChannelSettings_maintainRunningState(currentChannelToSet); break;
    case 'd':  // reset all channel settings to default
      if (!is_running) {
        Serial0.println("updating channel settings to default");
      }
      setChannelsToDefaultSetting(); break;
    case 'D':  // report the default settings
      sendDefaultChannelSettings(); break;

    // LEAD OFF IMPEDANCE DETECTION COMMANDS
    case 'z':  // expect 2 parameters
      if (!is_running) {
        Serial0.println("ready to accept new impedance detect settings");
      }
      leadOffSettingsCounter = 0;  // reset counter
      getLeadOffSettings = true;
      break;
    case 'Z':  // latch impedance parameters
      if (!is_running) {
        Serial0.println("updating impedance detect settings");
      }
      changeChannelLeadOffDetect_maintainRunningState(currentChannelToSet);
      break;

    // DAISY MODULE COMMANDS
    case 'c':  // use 8 channel mode
      if (OBCI.daisyPresent) {
        OBCI.removeDaisy();
      }
      outputType = OUTPUT_8_CHAN;
      break;
    case 'C':  // use 16 channel mode
      if (OBCI.daisyPresent == false) {
        OBCI.attachDaisy();
      }
      if (OBCI.daisyPresent) {
        Serial0.print("16"); outputType = OUTPUT_16_CHAN;
      } else {
        Serial0.print("8"); outputType = OUTPUT_8_CHAN;
      }
      sendEOT();
      break;

    // STREAM DATA AND FILTER COMMANDS
    case 'b':  // stream data
      if (SDfileOpen) stampSD(ACTIVATE);                    // time stamp the start time
      if (OBCI.useAccel) {
        OBCI.enable_accel(RATE_25HZ); // fire up the accelerometer if you want it
      }
      startRunning(outputType);                             // turn on the fire hose
      break;
    case 's':  // stop streaming data
      if (SDfileOpen) stampSD(DEACTIVATE);      // time stamp the stop time
      if (OBCI.useAccel) {
        OBCI.disable_accel(); // shut down the accelerometer if you're using it
      }
      stopRunning();
      break;
    case 'f':
      useFilters = true;
      break;
    case 'g':
      useFilters = false;
      break;

    //  INITIALIZE AND VERIFY
    case 'v':
      startFromScratch();  // initialize ADS and read device IDs
      break;
    //  QUERY THE ADS AND ACCEL REGITSTERS
    case '?':
      printRegisters();     // print the ADS and accelerometer register values
      break;
    default:
      break;
  }
}// end of getCommand

void sendEOT() {
  Serial0.print("$$$");  // shake hands with the controlling program
}

void loadChannelSettings(char c) {

  if (channelSettingsCounter == 0) { // if it's the first byte in this channel's array, this byte is the channel number to set
    currentChannelToSet = getChannelNumber(c); // we just got the channel to load settings into (shift number down for array usage)
    channelSettingsCounter++;
    if (!is_running) {
      Serial0.print("load setting ");
      Serial0.print("for channel ");
      Serial0.println(currentChannelToSet + 1, DEC);
    }
    return;
  }
  //  setting bytes are in order: POWER_DOWN, GAIN_SET, INPUT_TYPE_SET, BIAS_SET, SRB2_SET, SRB1_SET
  if (!is_running) {
    Serial0.print(channelSettingsCounter - 1);
    Serial0.print(" with "); Serial0.println(c);
  }
  c -= '0';
  if (channelSettingsCounter - 1 == GAIN_SET) {
    c <<= 4;
  }
  OBCI.channelSettings[currentChannelToSet][channelSettingsCounter - 1] = c;
  channelSettingsCounter++;
  if (channelSettingsCounter == 7) { // 1 currentChannelToSet, plus 6 channelSetting parameters
    if (!is_running) Serial0.print("done receiving settings for channel "); Serial0.println(currentChannelToSet + 1, DEC);
    getChannelSettings = false;
  }
}

void writeChannelSettings_maintainRunningState(char chan) {
  boolean is_running_when_called = is_running;
  int cur_outputType = outputType;
  stopRunning();                   //must stop running to change channel settings

  OBCI.writeChannelSettings(chan + 1);  // change the channel settings on ADS

  if (is_running_when_called == true) {
    startRunning(cur_outputType);  //restart, if it was running before
  }
}

void setChannelsToDefaultSetting() {
  boolean is_running_when_called = is_running;
  int cur_outputType = outputType;
  stopRunning();  //must stop running to change channel settings

  OBCI.setChannelsToDefault();   // default channel settings

  if (is_running_when_called == true) {
    startRunning(cur_outputType);  //restart, if it was running before
  }
}

void loadLeadOffSettings(char c) {
  if (leadOffSettingsCounter == 0) { // if it's the first byte in this channel's array, this byte is the channel number to set
    currentChannelToSet = getChannelNumber(c); // we just got the channel to load settings into (shift number down for array usage)
    if (!is_running) Serial0.print("changing LeadOff settings for channel "); Serial0.println(currentChannelToSet + 1, DEC);
    leadOffSettingsCounter++;
    return;
  }
  //  setting bytes are in order: PCHAN, NCHAN
  if (!is_running) {
    Serial0.print("load setting "); Serial0.print(leadOffSettingsCounter - 1);
    Serial0.print(" with "); Serial0.println(c);
  }
  c -= '0';
  OBCI.leadOffSettings[currentChannelToSet][leadOffSettingsCounter - 1] = c;
  leadOffSettingsCounter++;
  if (leadOffSettingsCounter == 3) { // 1 currentChannelToSet, plus 2 leadOff setting parameters
    if (!is_running) Serial0.print("done receiving leadOff settings for channel "); Serial0.println(currentChannelToSet + 1, DEC);
    getLeadOffSettings = false; // release the serial COM
  }
}

char getChannelNumber(char n) {
  if (n > '0' && n < '9') {
    n -= '1';
  }
  switch (n) {
    case 'Q':
      n = 0x08; break;
    case 'W':
      n = 0x09; break;
    case 'E':
      n = 0x0A; break;
    case 'R':
      n = 0x0B; break;
    case 'T':
      n = 0x0C; break;
    case 'Y':
      n = 0x0D; break;
    case 'U':
      n = 0x0E; break;
    case 'I':
      n = 0x0F; break;
    default: break;
  }
  return n;
}

void changeChannelState_maintainRunningState(byte chan, int start)
{
  boolean is_running_when_called = is_running;
  int cur_outputType = outputType;

  //must stop running to change channel settings
  stopRunning();
  if (start == 1) {
    OBCI.activateChannel(chan);
  } else if (start == 0) {
    OBCI.deactivateChannel(chan);
  }
  //restart, if it was running before
  if (is_running_when_called == true) {
    startRunning(cur_outputType);
  }
}

void activateAllChannelsToTestCondition(byte testInputCode, byte amplitudeCode, byte freqCode)
{
  boolean is_running_when_called = is_running;
  int cur_outputType = outputType;
  //must stop running to change channel settings
  stopRunning(); delay(10);

  //set the test signal to the desired state
  OBCI.configureInternalTestSignal(amplitudeCode, freqCode);
  //change input type settings for all channels
  OBCI.changeInputType(testInputCode);

  //restart, if it was running before
  if (is_running_when_called == true) {
    startRunning(cur_outputType);
  }
}

int changeChannelLeadOffDetect_maintainRunningState(char chan)
{
  boolean is_running_when_called = is_running;
  int cur_outputType = outputType;

  //must stop running to change channel settings
  stopRunning();

  OBCI.changeChannelLeadOffDetect(chan);

  //restart, if it was running before
  if (is_running_when_called == true) {
    startRunning(cur_outputType);
  }
}

void sendDefaultChannelSettings() {
  boolean is_running_when_called = is_running;
  int cur_outputType = outputType;

  OBCI.reportDefaultChannelSettings();
  sendEOT();
  delay(10);

  //restart, if it was running before
  if (is_running_when_called == true) {
    startRunning(cur_outputType);
  }
}

boolean stopRunning(void) {
  if (is_running) {
    OBCI.stopStreaming();  // stop the data acquisition, turn off accelerometer
    is_running = false;
  }
  return is_running;
}

boolean startRunning(int OUT_TYPE) {
  if (!is_running) {
    outputType = OUT_TYPE;
    OBCI.startStreaming();  // start the data acquisition, turn on accelerometer
    is_running = true;
  }
  return is_running;
}

void printRegisters() {

  if (!is_running) {
    // print the ADS and LIS3DH registers
    OBCI.printAllRegisters();
    sendEOT();
    delay(20);
  }

}

void startFromScratch() {
  if (!is_running) {
    OBCI.initialize();     // initializes accelerometer and on-board ADS and on-daisy ADS if present
    delay(500);
    Serial0.println("OpenBCI V3 16 channel");
    OBCI.configureLeadOffDetection(LOFF_MAG_6NA, LOFF_FREQ_31p2HZ);
    Serial0.print("On Board ADS1299 Device ID: 0x"); Serial0.println(OBCI.ADS_getDeviceID(ON_BOARD), HEX);
    if (OBCI.daisyPresent) { // library will set this in initialize() if daisy present and functional
      Serial0.print("On Daisy ADS1299 Device ID: 0x"); Serial0.println(OBCI.ADS_getDeviceID(ON_DAISY), HEX);
    }
    Serial0.print("LIS3DH Device ID: 0x"); Serial0.println(OBCI.LIS3DH_getDeviceID(), HEX);
    sendEOT();
  }
}



int main() 
{
  setup();

  while (1) loop();
}