Saturday November 25 2017

Brain Bug Arduino Code

// ***  ALL MY Code is 100% free of cost and liability  ***
//------------------------------------------------------------------------//
#include < SoftwareSerial.h >
// Serial
int rxPin = 2;
int txPin = 3; // Not used
SoftwareSerial SerialToRepeat(rxPin,txPin);
byte buff[3] = {0};
byte FrameData[37] = {0}; // 36 Data + 1 OF
byte Index = 0;
bool Framed = false;
bool Debug = true;
bool TurningENB = false;
// FSM
char FSM[3] = {0,0,0};
// Brain Values
byte Attention  = 0;
byte AttentionValues[8] = {0}; // For averaging
byte AvgAttention = 0;
byte Meditation = 0;
byte MeditationValues[8] = {0};// For averaging
byte AvgMeditation = 0;
byte AvgIndex = 0;
byte SigQuality = 0;
int32_t EEGValues[8] = {0};
//------------------------------------------------------------------------//
void setup() {
    // RX GND Reference -> MindFlex
    pinMode(4,OUTPUT);
    digitalWrite(4,LOW);
    // IR LEDS pinModes (use GND for GND)
    DDRB |= B1111; // Remember this is for bursting
    // Startup the two software serials
    Serial.begin(9600);
    Serial.println("BrainBug Started!");
    SerialToRepeat.begin(9600);
}
//------------------------------------------------------------------------//
void loop() {
    if(SerialToRepeat.available()) {   // Move to INTR..?
        byte valueOut = SerialToRepeat.read();
        // Capture if framed
        if(Framed) {
            FrameData[Index] = valueOut;
            if(Index < 36) Index++; // Gets cleared by new Frame, sticks at OF index
        }
        // Cycle buffer
        for(int i=2;i >= 0;i--) buff[i] = (i==0)? valueOut : buff[i-1];
        // Frame
        if((buff[0]==32)&&(buff[1]==170)&&(buff[2]==170)) {
            for(uint8_t i=0;i < 3;i++) buff[i]=0; // To be safe
            Index = 0;
            if(!Framed) Framed = true;
            else {
                if(CheckFrame()) ProcessAndSendFrameData();
                else {
                    Framed = false;
                    Serial.println("\nFrame ERROR");
                }
            }
        }
    }
    // Check other Serial for CMDs
    if(Serial.available()) CrunchFSM(Serial.read());
}
//------------------------------------------------------------------------//
void CrunchFSM(char newChar) {
    if(newChar != 0) {
        for(int i=2;i >= 0;i--) {
            if(i==0) FSM[i] = newChar;
            else     FSM[i] = FSM[i-1];
        }
        if((FSM[0]==FSM[2])&&(FSM[2]=='_')) {
            if(FSM[1]=='t') {
                TurningENB = !TurningENB;
                Serial.print("Turning is now:");
                Serial.println((TurningENB)?"ON":"OFF");
            }
        }
    }
}
//------------------------------------------------------------------------//
bool CheckFrame() {
    bool toReturn = true; // assume pass and mask out to fail
    toReturn &= (FrameData[35] == (byte) 32); // Header2
    toReturn &= (FrameData[34] == (byte)170); // Header1
    toReturn &= (FrameData[33] == (byte)170); // Header0
    toReturn &= (FrameData[ 0] == (byte)  2); // Signal Quality ID
    toReturn &= (FrameData[ 2] == (byte)131); // EEG Array ID
    toReturn &= (FrameData[ 3] == (byte) 24); // Number bits per EEG value
    toReturn &= (FrameData[28] == (byte)  4); // Attention ID
    toReturn &= (FrameData[30] == (byte)  5); // Meditation ID
    // Check data sum
    uint8_t CheckSum = 0;
    for(byte i=0;i < 36;i++) if(i!=32) CheckSum += FrameData[i];
    if(CheckSum != (byte)(115-FrameData[32])) { // TODO: Figure out why it's 115
        Serial.println("\nChecksum Failure!");
        return false;
    }
    return toReturn;
}
//------------------------------------------------------------------------//
void ProcessAndSendFrameData() {
    // Process
    byte offset = 4; // Where the EEG data starts (it's 8x24-bit numbers[accross 3bytes])
    SigQuality  = (200-FrameData[1])>>1; // 200 Seems to be the worst, so quality=0
    Attention   = FrameData[29];
    Meditation  = FrameData[31];
    // Calculate Averages
    AttentionValues[AvgIndex] = Attention;
    MeditationValues[AvgIndex] = Meditation;
    long TempAttention = 0;
    long TempMeditation = 0;
    for(byte i=0;i < 8;i++) {
        TempAttention += (uint16_t)AttentionValues[i];
        TempMeditation += (uint16_t)MeditationValues[i];
    }
    AvgAttention  = TempAttention>>3;
    AvgMeditation = TempMeditation>>3;
    if(AvgIndex == 7) AvgIndex=0;
    else              AvgIndex++;
    // EEGValues
    for(byte i=0;i < 8;i++) { // Stored in FrameData as 23:16,15:8,7:0 in index,index+,index++
        EEGValues[i]  = FrameData[i*3+offset+2];     //  7:0
        EEGValues[i] |= FrameData[i*3+offset+1]<<8;  // 15:8
        EEGValues[i] |= FrameData[i*3+offset+0]<<16; // 23:16
    }
    // Send Info
    if(Debug) {
        Serial.print("Qual:");Serial.print(SigQuality);
        Serial.print(" Attn:");Serial.print(Attention);
        Serial.print(" AvgAttn:");Serial.print(AvgAttention);
        Serial.print(" Medt:");Serial.print(Meditation);
        Serial.print(" AvgMedt:");Serial.print(AvgMeditation);
        Serial.print(" EEGValues:"); // TODO: Figure out what each one is
        for(byte i=0;i < 8;i++) {
            Serial.print(EEGValues[i]);
            if(i!=7) Serial.print("_");
            else     Serial.println(" ");
        }
    }
    // Send InchCode
    if(SigQuality == 100) {
        if((Attention > AvgAttention+10)||(Attention > 90)) {
            Xmit_InchCode('F');
            Serial.println("Move Forward");
        } else if((Attention < AvgAttention-10)||(Attention < 20)) {
            Xmit_InchCode('B');
            Serial.println("Move Backward");
        }
        if(TurningENB) {
            if(Meditation > AvgMeditation+15) {
                Xmit_InchCode('R');
                Serial.println("Move Right");
            } else if(Meditation < AvgMeditation-15) {
                Xmit_InchCode('L');
                Serial.println("Move Left");
            }
        }
    }
}
//------------------------------------------------------------------------//
void Xmit_InchCode(char Code) {
    int CodeArray[1] = {0};
    if      (Code == 'F') CodeArray[0] = 131;
    else if (Code == 'B') CodeArray[0] = 69; // heheh
    else if (Code == 'R') CodeArray[0] = 38;
    else if (Code == 'L') CodeArray[0] = 193;
    // Header
    pulseIR_38KHz(4000); delayMicroseconds(400);
    pulseIR_38KHz(2000); delayMicroseconds(800);
    // Body
    sendCharArray(CodeArray,1,400,1400,500);
    // Footer
    pulseIR_38KHz(400); delayMicroseconds(1400);
    pulseIR_38KHz(400); delayMicroseconds(1400);
    pulseIR_38KHz(400);
    delay(65);
}
//------------------------------------------------------------------------//
void sendCharArray(int CharArray[], uint16_t size, uint16_t PulseOn, uint16_t DelayTrue, uint16_t DelayFalse) {
    int tempc = 0;
    for(int i=0;i < size;i++) {
        tempc = CharArray[i];
        for(int j=7;j >= 0;j--) {
            pulseIR_38KHz(PulseOn);
            if (((tempc>>j)%2) == 1) delayMicroseconds(DelayTrue);
            else                     delayMicroseconds(DelayFalse);
        }
    }
}
//------------------------------------------------------------------------//
void pulseIR_38KHz(long microsecs) {
    while (microsecs > 0) {
        // 38KHz = 26.316us -> 26us, so cut in 1/2 for IR pulse -> 13us high, 13us low
        PORTB = B1111;  // Takes ~1/2us
        delayMicroseconds(13);
        PORTB = B0000;  // Takes ~1/2us
        delayMicroseconds(12);
        microsecs -= 26;
    }
}
//------------------------------------------------------------------------//