A scripting environment used to define precise output/input temporal relationships.

Dependencies:   SMARTWAV mbed HelloWorld

Dependents:   perturbRoom_legacy

Fork of HelloWorld by Simon Ford

behave.cpp

Committer:
mkarlsso
Date:
2014-07-19
Revision:
3:ae33b7f5a7c1
Parent:
2:298679fff37c
Child:
4:34aca2142df9

File content as of revision 3:ae33b7f5a7c1:

#include "behave.h"
#include <ctype.h>
#include <sstream> 

// These external symbols are maintained by the linker to indicate the
// location of various regions in the device's memory.  They will be used by
// DisplayRAMBanks() to dump the size of each RAM bank to stdout.
extern unsigned int Image$$RW_IRAM1$$Base;
extern unsigned int Image$$RW_IRAM1$$ZI$$Limit;
extern unsigned int Image$$RW_IRAM2$$Base;
extern unsigned int Image$$RW_IRAM2$$ZI$$Limit;
extern unsigned int Image$$RW_IRAM3$$Base;
extern unsigned int Image$$RW_IRAM3$$ZI$$Limit;

uint32_t* globalTimeKeeperPtr; //this is a pointer to the slave timer (do not change this directly)
extern eventQueue mainQueue;
extern digitalPort* portVector[];

extern Serial pc;
extern bool resetTimer;
extern bool clockSlave;
extern bool changeToSlave;
extern bool changeToStandAlone;
extern outputStream textDisplay;
extern int currentDIOstate[2];
extern bool broadCastStateChanges;
extern bool textStreaming;


//static pools of memory for each object type
extern event eventBlock[NUMEVENTS];
extern condition conditionBlock[NUMCONDITIONS];
extern intCompare intCompareBlock[NUMINTCOMPARE];
extern action actionBlock[NUMACTIONS];
extern portMessage portMessageBlock[NUMPORTMESSAGES];
extern intOperation intOperationBlock[NUMINTOPERATIONS];
extern displayAction displayActionBlock[NUMDISPLAYACTIONS];

//used to find the first available object in the staticly defined pools of memory
template<class T> T* findFirstUnUsed(T a[], const int arrayLength) {
  
  T* returnPtr = NULL;
  for (int i = 0; i < arrayLength; i++) {
    if (!a[i].isUsed) {
        returnPtr = &a[i];
        break;
    }
  }
  return returnPtr;
}
        
//used to count the number of available objects in the memory pool
template<class T> int countUnUsed(T a[], const int arrayLength) {
  
  int count = 0;
  for (int i = 0; i < arrayLength; i++) {
    if (!a[i].isUsed) {
        count++;
    }
  }
  return count;
}


void displayMemoryLeft(void) {
    pc.printf("Available slots left in memory\r\n");
    pc.printf("  Blocks:  %d\r\n", countUnUsed(eventBlock, NUMEVENTS));
    pc.printf("  Condition containers:  %d\r\n", countUnUsed(conditionBlock, NUMCONDITIONS));
    pc.printf("  Int compare conditions:  %d\r\n", countUnUsed(intCompareBlock, NUMINTCOMPARE));
    pc.printf("  Command containers:  %d\r\n", countUnUsed(actionBlock, NUMACTIONS));
    pc.printf("  Port commands:  %d\r\n", countUnUsed(portMessageBlock, NUMPORTMESSAGES));
    pc.printf("  Integer operater commands:  %d\r\n", countUnUsed(intOperationBlock, NUMINTOPERATIONS));
    pc.printf("  Text display commands:  %d\r\n", countUnUsed(displayActionBlock, NUMDISPLAYACTIONS));
}

// Displays the size of static allocations for each RAM bank as indicated by
// ARM linker to stdout.
static void DisplayRAMBanks(void) {

    pc.printf("Static RAM bank allocations\r\n");
    pc.printf("  Main RAM = %u\r\n", (unsigned int)&Image$$RW_IRAM1$$ZI$$Limit - 
                                  (unsigned int)&Image$$RW_IRAM1$$Base);
    pc.printf("  RAM0     = %u\r\n", (unsigned int)&Image$$RW_IRAM2$$ZI$$Limit -
                                  (unsigned int)&Image$$RW_IRAM2$$Base);
    pc.printf("  RAM1     = %u\r\n", (unsigned int)&Image$$RW_IRAM3$$ZI$$Limit -
                                  (unsigned int)&Image$$RW_IRAM3$$Base);
}


bool isNumber(const std::string& s) {
    std::string::const_iterator it = s.begin();
    while (it != s.end() && isdigit(*it)) ++it;
    return !s.empty() && it == s.end();
}

void tokenize(const string& str,
                      vector<string>& tokens,
                      const string& delimiters = " ")
{
    // Skip delimiters at beginning.
    string::size_type lastPos = str.find_first_not_of(delimiters, 0);
    // Find first "non-delimiter".
    string::size_type pos     = str.find_first_of(delimiters, lastPos);

    while (string::npos != pos || string::npos != lastPos)
    {
        // Found a token, add it to the vector.
        tokens.push_back(str.substr(lastPos, pos - lastPos));
        // Skip delimiters.  Note the "not_of"
        lastPos = str.find_first_not_of(delimiters, pos);
        // Find next "non-delimiter"
        pos = str.find_first_of(delimiters, lastPos);
    }
}


digitalPort::digitalPort(DigitalOut* DOP, DigitalIn* DIP):
    outPin(DOP),
    inPin(DIP),
    outState(0){
    
    lastInState = getDigitalIn();
    inState = getDigitalIn();
    lastChangeTime = 0;
    lastOutChangeTime = 0;
    lastChangeInterval = 0;
    lastDownEvent.triggered = false;
    lastUpEvent.triggered = false;
    triggerUpEventPtr = NULL;
    triggerDownEventPtr = NULL;
    outStateChanged = false;
}

void digitalPort::setTriggerUpEvent(event* eventInput) {
    if (triggerUpEventPtr != NULL) {
         //delete triggerUpEventPtr;
         triggerUpEventPtr->release();
    }
    triggerUpEventPtr = eventInput;
}

void digitalPort::setTriggerDownEvent(event* eventInput) {
    if (triggerDownEventPtr != NULL) {
         //delete triggerDownEventPtr;
         triggerDownEventPtr->release();
         
    }
    triggerDownEventPtr = eventInput;
}


int digitalPort::getDigitalIn() {
    return inPin->read();
}


void digitalPort::setDigitalOut(int outVal) {
    if (outVal == -1) {
        outVal = 1-outState;
    }
    outPin->write(outVal);
    if (outState != outVal) {
        outStateChanged = true;
        lastOutChangeTime = *globalTimeKeeperPtr;
    }
    outState = outVal;  
}

//called when a digital in gets triggered
void digitalPort::addStateChange(int newState, uint32_t timeStamp) {
    
    if ((newState == 0) && (!lastDownEvent.triggered)){
        lastDownEvent.timeStamp = timeStamp;
        lastDownEvent.triggered = true;
    } else if ((newState == 1) && (!lastUpEvent.triggered)) {
        lastUpEvent.timeStamp = timeStamp;
        lastUpEvent.triggered = true;
    }
}

bool digitalPort::update() {

  bool changed = false;
  if ((*globalTimeKeeperPtr - lastChangeTime) > 1) { //prevents flutter triggers when button is pressed
    inState = getDigitalIn();
    changed = (lastInState != inState);   
    if (changed) {
        if (inState == 1) {
            if (lastUpEvent.triggered) {
                //there were hardware triggered since the last main loop.  We use that time
                lastChangeInterval = lastUpEvent.timeStamp - lastChangeTime;
                lastChangeTime = lastUpEvent.timeStamp;
            } else {
                //otherwise we use the current time
                lastChangeInterval = *globalTimeKeeperPtr - lastChangeTime;
                lastChangeTime = *globalTimeKeeperPtr;
            }
            if (triggerUpEventPtr != NULL) {triggerUpEventPtr->execute();}          
        } else if (inState == 0) {
            if (lastDownEvent.triggered) {
                lastChangeInterval = lastDownEvent.timeStamp - lastChangeTime;
                lastChangeTime = lastDownEvent.timeStamp;
            } else {
                lastChangeInterval = *globalTimeKeeperPtr - lastChangeTime;
                lastChangeTime = *globalTimeKeeperPtr;
            }
            if (triggerDownEventPtr != NULL) {triggerDownEventPtr->execute();}            
        }
        
    }      
        
    lastInState = inState;
    
  }
  lastUpEvent.triggered = false;
  lastDownEvent.triggered = false;
  return changed;
}

int digitalPort::getLastChangeState() {
    return lastInState;
}
uint32_t digitalPort::getTimeSinceLastChange() {
    return lastChangeInterval;
    
}

intVariable::intVariable():
    value(0), 
    tag(string("--------------------")) {  
    isUsed = false;  
}

intVariable::intVariable(string tagInput, int initialValue):
    value(initialValue), 
    tag(string(tagInput)) {   
    isUsed = true;   
}

void intVariable::set(string tagInput, int initialValue) {
    value = initialValue; 
    tag = string(tagInput);
    isUsed = true;      
}

displayAction::displayAction():
    dText(string("--------------------------------------------------")),
    pcPtr(NULL) {   
    dVariable = NULL;
    isUsed = false;  
}

void displayAction::release() {
    dText = "--------------------------------------------------";
    pcPtr = NULL;  
    dVariable = NULL;
    isUsed = false;     
}

displayAction::displayAction(int* variable, string varNameInput, Serial* pcPtrInput):
    dVariable(variable),
    dText(varNameInput),
    pcPtr(pcPtrInput) {
    isUsed = true;  
    
}

displayAction::displayAction(string text, Serial* pcPtrInput):
    dText(text),
    pcPtr(pcPtrInput) {   
    dVariable = NULL;
    isUsed = true;  
}

void displayAction::set(int* variable, string varNameInput, Serial* pcPtrInput) {
    dVariable = variable;
    dText = varNameInput;
    pcPtr = pcPtrInput;
    isUsed = true;  
    
}

void displayAction::set(string text, Serial* pcPtrInput) {
    dText = text;
    pcPtr = pcPtrInput;   
    dVariable = NULL;
    isUsed = true;  
}

void displayAction::execute() {
    
    ostringstream convert;   // stream used for the conversion
    convert << *globalTimeKeeperPtr;      // insert the textual representation of 'Number' in the characters in the stream

    if (dVariable != NULL) {
        ostringstream varConvert;
        varConvert << *dVariable;
        //pcPtr->printf("%d   %s = %d\r\n",*globalTimeKeeperPtr, dText.data(),*dVariable);
        textDisplay.send(convert.str() + "  " + dText + " = " + varConvert.str() + "\r\n");
    } else {
        //pcPtr->printf("%d   %s\r\n",*globalTimeKeeperPtr, dText.data());
        textDisplay.send(convert.str() + "  " + dText + "\r\n");
       
    }
}

intCompare::intCompare():
    port(NULL) {
    cmpVal = NULL;
    cmpValGlobal = false;
    intVal = NULL;
    intOp = NULL;
    portValPtr = NULL;
    isUsed = false;  
    
}
intCompare::intCompare(digitalPort* portInput, const char* cmpString, int cmpValInput, int whichToUse):
    port(portInput) {
    cmpVal = new int(cmpValInput);
    cmpValGlobal = false;
    intVal = NULL;
    intOp = NULL;
    setPointer(cmpString); 
    isUsed = true;  
    if (whichToUse == 1) {
        portValPtr = &port->inState;
    } else {
        portValPtr = &port->outState;
    } 
}

intCompare::intCompare(digitalPort* portInput, const char* cmpString, int* cmpIntVarInput, int whichToUse):
    port(portInput),
    cmpVal(cmpIntVarInput) {
    cmpValGlobal = true;
    intVal = NULL;
    intOp = NULL;
    setPointer(cmpString);
    isUsed = true;  
    if (whichToUse == 1) {
        portValPtr = &port->inState;
    } else {
        portValPtr = &port->outState;
    }
}

intCompare::intCompare(int* intVarInput, const char* cmpString, int* cmpIntVarInput):
    cmpVal(cmpIntVarInput),
    intVal(intVarInput) {
    cmpValGlobal = true;
    port = NULL;
    intOp = NULL;
    portValPtr = NULL;
    isUsed = true;  
    setPointer(cmpString);  
}

intCompare::intCompare(int* intVarInput, const char* cmpString, int cmpValInput):
    intVal(intVarInput){
    cmpVal = new int(cmpValInput);
    cmpValGlobal = false;
    port = NULL;
    intOp = NULL;
    portValPtr = NULL;
    isUsed = true;  
    setPointer(cmpString);
}

intCompare::intCompare(int* intVarInput, const char* cmpString, intOperation* cmpIntOpInput):
    intVal(intVarInput) {
    cmpVal = NULL;
    port = NULL;
    portValPtr = NULL;
    cmpValGlobal = true;
    intOp = cmpIntOpInput;
    isUsed = true;  
    setPointer_operation(cmpString);
}

intCompare::intCompare(digitalPort* portInput, const char* cmpString, intOperation* cmpIntOpInput, int whichToUse):
    port(portInput) {
    cmpVal = NULL;
    intVal = NULL;
    cmpValGlobal = true;
    intOp = cmpIntOpInput;
    setPointer_operation(cmpString);
    isUsed = true;  
    if (whichToUse == 1) {
        portValPtr = &port->inState;
    } else {
        portValPtr = &port->outState;
    }
}



void intCompare::set(digitalPort* portInput, const char* cmpString, int cmpValInput, int whichToUse) {
    port = portInput;
    cmpVal = new int(cmpValInput);
    cmpValGlobal = false;
    intVal = NULL;
    intOp = NULL;
    setPointer(cmpString); 
    isUsed = true; 
    if (whichToUse == 1) {
        portValPtr = &port->inState;
    } else {
        portValPtr = &port->outState;
    } 
}

void intCompare::set(digitalPort* portInput, const char* cmpString, int* cmpIntVarInput, int whichToUse) {
    port = portInput;
    cmpVal = cmpIntVarInput;
    cmpValGlobal = true;
    intVal = NULL;
    intOp = NULL;
    setPointer(cmpString);
    isUsed = true; 
    if (whichToUse == 1) {
        portValPtr = &port->inState;
    } else {
        portValPtr = &port->outState;
    }
}

void intCompare::set(int* intVarInput, const char* cmpString, int* cmpIntVarInput) {
    cmpVal = cmpIntVarInput;
    intVal = intVarInput; 
    cmpValGlobal = true;
    port = NULL;
    intOp = NULL;
    portValPtr = NULL;
    setPointer(cmpString); 
    isUsed = true;  
}

void intCompare::set(int* intVarInput, const char* cmpString, int cmpValInput) {
    intVal = intVarInput;
    cmpVal = new int(cmpValInput);
    cmpValGlobal = false;
    port = NULL;
    intOp = NULL;
    portValPtr = NULL;
    setPointer(cmpString);
    isUsed = true; 
}

void intCompare::set(int* intVarInput, const char* cmpString, intOperation* cmpIntOpInput) {
    intVal = intVarInput;
    cmpVal = NULL;
    port = NULL;
    portValPtr = NULL;
    cmpValGlobal = true;
    intOp = cmpIntOpInput;
    setPointer_operation(cmpString);
    isUsed = true; 
}

void intCompare::set(digitalPort* portInput, const char* cmpString, intOperation* cmpIntOpInput, int whichToUse) {
    port = portInput;
    cmpVal = NULL;
    intVal = NULL;
    cmpValGlobal = true;
    intOp = cmpIntOpInput;
    setPointer_operation(cmpString);
    isUsed = true; 
    if (whichToUse == 1) {
        portValPtr = &port->inState;
    } else {
        portValPtr = &port->outState;
    }
}



intCompare::~intCompare() {
    if (!cmpValGlobal) delete cmpVal; //we only delete the intCompare object if it was created locally 
    delete intOp;
}

void intCompare::release() {
    if (!cmpValGlobal) delete cmpVal; //we only delete the intCompare object if it was created locally 
    if (intOp != NULL) {
        intOp->release();
    }
    port = NULL;
    cmpVal = NULL;
    cmpValGlobal = false;
    intVal = NULL;
    intOp = NULL;
    portValPtr = NULL;
    isUsed = false; 
} 
    

void intCompare::setPointer(const char* cmpString) {
    if (strcmp(cmpString, ">") == 0) {
        isTruePtr = &intCompare::greaterThan;
    }else if (strcmp(cmpString, ">=") == 0) {
        isTruePtr = &intCompare::greaterOrEqual;
    }else if (strcmp(cmpString, "<") == 0) {
        isTruePtr = &intCompare::lessThan;
    }else if (strcmp(cmpString, "<=") == 0) {
        isTruePtr = &intCompare::lessOrEqual;
    }else if (strcmp(cmpString, "==") == 0) {
        isTruePtr = &intCompare::equal;
    }else if (strcmp(cmpString, "!=") == 0) {
        isTruePtr = &intCompare::notEqual;
    }   
}

void intCompare::setPointer_operation(const char* cmpString) {
    if (strcmp(cmpString, ">") == 0) {
        isTruePtr = &intCompare::greaterThan_op;
    }else if (strcmp(cmpString, ">=") == 0) {
        isTruePtr = &intCompare::greaterOrEqual_op;
    }else if (strcmp(cmpString, "<") == 0) {
        isTruePtr = &intCompare::lessThan_op;
    }else if (strcmp(cmpString, "<=") == 0) {
        isTruePtr = &intCompare::lessOrEqual_op;
    }else if (strcmp(cmpString, "==") == 0) {
        isTruePtr = &intCompare::equal_op;
    }else if (strcmp(cmpString, "!=") == 0) {
        isTruePtr = &intCompare::notEqual_op;
    }   
}

bool intCompare::isTrue() {
    return (this->*isTruePtr)();
    
}

bool intCompare::notEqual() {
    if (intVal != NULL) {
        return (*intVal != *cmpVal);
    } else {
        return (*portValPtr != *cmpVal);
    }
}

bool intCompare::greaterThan() {
    if (intVal != NULL) {
        return (*intVal > *cmpVal);
    } else {
        return (*portValPtr > *cmpVal);
    }
}

bool intCompare::greaterOrEqual() {
    if (intVal != NULL) {
        return (*intVal >= *cmpVal);
    } else {
        return (*portValPtr >= *cmpVal);
    }
}

bool intCompare::lessThan() {
    if (intVal != NULL) {
        return (*intVal < *cmpVal);
    } else {
        return (*portValPtr < *cmpVal);
    }
}

bool intCompare::lessOrEqual() {
    if (intVal != NULL) {
        return (*intVal <= *cmpVal);
    } else {
        return (*portValPtr <= *cmpVal);
    }
}

bool intCompare::equal() {
    if (intVal != NULL) {
        return (*intVal == *cmpVal);
    } else {
        return (*portValPtr == *cmpVal);
    }
}

bool intCompare::notEqual_op() {
    if (intVal != NULL) {
        return (*intVal != intOp->execute());
    } else {
        return (*portValPtr != intOp->execute());
    }
}

bool intCompare::greaterThan_op() {
    if (intVal != NULL) {
        return (*intVal > intOp->execute());
    } else {
        return (*portValPtr > intOp->execute());
    }
}

bool intCompare::greaterOrEqual_op() {
    if (intVal != NULL) {
        return (*intVal >= intOp->execute());
    } else {
        return (*portValPtr >= intOp->execute());
    }
}

bool intCompare::lessThan_op() {
    if (intVal != NULL) {
        return (*intVal < intOp->execute());
    } else {
        return (*portValPtr < intOp->execute());
    }
}

bool intCompare::lessOrEqual_op() {
    if (intVal != NULL) {
        return (*intVal <= intOp->execute());
    } else {
        return (*portValPtr <= intOp->execute());
    }
}

bool intCompare::equal_op() {
    if (intVal != NULL) {
        return (*intVal == intOp->execute());
    } else {
        return (*portValPtr == intOp->execute());
    }
}

intOperation::intOperation():
    randHigh(-1) {
    cmpVal = NULL;
    intVal = NULL;
    opPtr = NULL;
    executePtr = NULL;
    cmpValGlobal = false;
    isUsed = false; 
      
}

intOperation::intOperation(int randParam, const char* cmpString, int cmpValInput):
    randHigh(randParam) {
    cmpVal = new int(cmpValInput);
    intVal = NULL;
    opPtr = NULL;
    cmpValGlobal = false;
    isUsed = true; 
    if (strcmp(cmpString, "+") == 0) {
        executePtr = &intOperation::add;
    }else if (strcmp(cmpString, "-") == 0) {
        executePtr = &intOperation::subtract;
    }else if (strcmp(cmpString, "+=") == 0) {
        executePtr = &intOperation::addAndStore;
    }else if (strcmp(cmpString, "-=") == 0) {
        executePtr = &intOperation::subtractAndStore;
    }else if (strcmp(cmpString, "=") == 0) {
        executePtr = &intOperation::equals;
    }
    
}

intOperation::intOperation(int randParam, const char* cmpString, int* cmpIntVarInput):
    randHigh(randParam),
    cmpVal(cmpIntVarInput) {
    intVal = NULL;
    opPtr = NULL;
    cmpValGlobal = true;
    isUsed = true; 
    if (strcmp(cmpString, "+") == 0) {
        executePtr = &intOperation::add;
    }else if (strcmp(cmpString, "-") == 0) {
        executePtr = &intOperation::subtract;
    }else if (strcmp(cmpString, "+=") == 0) {
        executePtr = &intOperation::addAndStore;
    }else if (strcmp(cmpString, "-=") == 0) {
        executePtr = &intOperation::subtractAndStore;
    }else if (strcmp(cmpString, "=") == 0) {
        executePtr = &intOperation::equals;
    }
}

intOperation::intOperation(int* intVarInput, const char* cmpString, int cmpValInput):
    intVal(intVarInput) {
    cmpVal = new int(cmpValInput);
    randHigh = -1;
    opPtr = NULL;
    cmpValGlobal = false;
    isUsed = true; 
    if (strcmp(cmpString, "+") == 0) {
        executePtr = &intOperation::add;
    }else if (strcmp(cmpString, "-") == 0) {
        executePtr = &intOperation::subtract;
    }else if (strcmp(cmpString, "+=") == 0) {
        executePtr = &intOperation::addAndStore;
    }else if (strcmp(cmpString, "-=") == 0) {
        executePtr = &intOperation::subtractAndStore;
    }else if (strcmp(cmpString, "=") == 0) {
        executePtr = &intOperation::equals;
    }
}

intOperation::intOperation(int* intVarInput, const char* cmpString, int* cmpIntVarInput):
    cmpVal(cmpIntVarInput),
    intVal(intVarInput) {
    randHigh = -1;
    opPtr = NULL;
    cmpValGlobal = true;
    isUsed = true; 
    if (strcmp(cmpString, "+") == 0) {
        executePtr = &intOperation::add;
    }else if (strcmp(cmpString, "-") == 0) {
        executePtr = &intOperation::subtract;
    }else if (strcmp(cmpString, "+=") == 0) {
        executePtr = &intOperation::addAndStore;
    }else if (strcmp(cmpString, "-=") == 0) {
        executePtr = &intOperation::subtractAndStore;
    }else if (strcmp(cmpString, "=") == 0) {
        executePtr = &intOperation::equals;
    }
}

intOperation::intOperation(int* intVarInput, intOperation* operationInput):
    intVal(intVarInput) {
    cmpVal = NULL;  
    randHigh = -1;
    opPtr = operationInput; 
    executePtr = &intOperation::equals;
    isUsed = true; 
}

void intOperation::set(int randParam, const char* cmpString, int cmpValInput) {
    randHigh = randParam;
    cmpVal = new int(cmpValInput);
    intVal = NULL;
    opPtr = NULL;
    cmpValGlobal = false;
    isUsed = true; 
    if (strcmp(cmpString, "+") == 0) {
        executePtr = &intOperation::add;
    }else if (strcmp(cmpString, "-") == 0) {
        executePtr = &intOperation::subtract;
    }else if (strcmp(cmpString, "+=") == 0) {
        executePtr = &intOperation::addAndStore;
    }else if (strcmp(cmpString, "-=") == 0) {
        executePtr = &intOperation::subtractAndStore;
    }else if (strcmp(cmpString, "=") == 0) {
        executePtr = &intOperation::equals;
    }
    
}

void intOperation::set(int randParam, const char* cmpString, int* cmpIntVarInput) {
    randHigh = randParam;
    cmpVal = cmpIntVarInput;
    intVal = NULL;
    opPtr = NULL;
    cmpValGlobal = true;
    isUsed = true; 
    if (strcmp(cmpString, "+") == 0) {
        executePtr = &intOperation::add;
    }else if (strcmp(cmpString, "-") == 0) {
        executePtr = &intOperation::subtract;
    }else if (strcmp(cmpString, "+=") == 0) {
        executePtr = &intOperation::addAndStore;
    }else if (strcmp(cmpString, "-=") == 0) {
        executePtr = &intOperation::subtractAndStore;
    }else if (strcmp(cmpString, "=") == 0) {
        executePtr = &intOperation::equals;
    }
}

void intOperation::set(int* intVarInput, const char* cmpString, int cmpValInput) {
    
    intVal = intVarInput;
    cmpVal = new int(cmpValInput);
    randHigh = -1;
    opPtr = NULL;
    cmpValGlobal = false;
    isUsed = true; 
    if (strcmp(cmpString, "+") == 0) {
        executePtr = &intOperation::add;
    }else if (strcmp(cmpString, "-") == 0) {
        executePtr = &intOperation::subtract;
    }else if (strcmp(cmpString, "+=") == 0) {
        executePtr = &intOperation::addAndStore;
    }else if (strcmp(cmpString, "-=") == 0) {
        executePtr = &intOperation::subtractAndStore;
    }else if (strcmp(cmpString, "=") == 0) {
        executePtr = &intOperation::equals;
    }
}

void intOperation::set(int* intVarInput, const char* cmpString, int* cmpIntVarInput) {
    cmpVal = cmpIntVarInput;
    intVal =intVarInput;
    randHigh = -1;
    opPtr = NULL;
    cmpValGlobal = true;
    isUsed = true; 
    if (strcmp(cmpString, "+") == 0) {
        executePtr = &intOperation::add;
    }else if (strcmp(cmpString, "-") == 0) {
        executePtr = &intOperation::subtract;
    }else if (strcmp(cmpString, "+=") == 0) {
        executePtr = &intOperation::addAndStore;
    }else if (strcmp(cmpString, "-=") == 0) {
        executePtr = &intOperation::subtractAndStore;
    }else if (strcmp(cmpString, "=") == 0) {
        executePtr = &intOperation::equals;
    }
}

void intOperation::set(int* intVarInput, intOperation* operationInput) {
    
    intVal = intVarInput;
    cmpVal = NULL;  
    randHigh = -1;
    opPtr = operationInput; 
    executePtr = &intOperation::equals;
    isUsed = true; 

}


intOperation::~intOperation() {
    if (!cmpValGlobal) delete cmpVal;
    delete opPtr;
}

void intOperation::release() {
    if (!cmpValGlobal) delete cmpVal;
    if (opPtr != NULL) {
        opPtr->release();
    }
    randHigh = -1;
    cmpVal = NULL;
    intVal = NULL;
    opPtr = NULL;
    executePtr = NULL;
    cmpValGlobal = false;
    isUsed = false;
}
    

int intOperation::execute() {
    
    return (this->*executePtr)();
    
    
}

int intOperation::add() {
    
    if (intVal != NULL) {
        return (*intVal + *cmpVal);
    }
    else {
        //srand(time(NULL));
        srand(*globalTimeKeeperPtr);   
        return (rand() % (randHigh+1)) + *cmpVal;
        //return (port->getState() + *cmpVal);
    }    
}

int intOperation::subtract() {
    if (intVal != NULL) {
        return (*intVal - *cmpVal);
    }
    else {
        srand(*globalTimeKeeperPtr);   
        return (rand() % (randHigh+1)) - *cmpVal;
        //return (port->getState() - *cmpVal);
    }    
}

int intOperation::addAndStore() {
    if (intVal != NULL) {
        *intVal = *intVal + *cmpVal;
        return *intVal;
    }
    else {
        
        //Doesn't happen
        return 0;
        //port->setState(port->getState() + *cmpVal);
        //return port->getState();
    }
    
}

int intOperation::subtractAndStore() {
    if (intVal != NULL) {
        *intVal = *intVal - *cmpVal;
        return *intVal;
    } else {
        //doesn't happen
        return 0;
        //port->setState(port->getState() - *cmpVal);
        //return port->getState();
    }
}

int intOperation::equals() {
    if ((intVal != NULL) && (opPtr == NULL)) {
        *intVal = *cmpVal;
        return *intVal;
    } else if ((intVal != NULL) && (opPtr != NULL)) {
        
        *intVal = opPtr->execute();
        return *intVal;    
    } else if (cmpVal != NULL){
        
        srand(*globalTimeKeeperPtr);     
        *cmpVal = (rand() % (randHigh+1)); //this is how we assign a random number to variable
        return *cmpVal;
        
    } 
    return -1;
}

condition::condition() {
    intCmp = NULL;
    conditionPtrs[0] = NULL;
    conditionPtrs[1] = NULL;
    isUsed = false; 
    conditionType = ARITHMATIC_CONDITION;
}

condition::condition(intCompare* compareInput) {

    intCmp = compareInput;
    conditionPtrs[0] = NULL;
    conditionPtrs[1] = NULL;
    
    isUsed = true; 
    conditionType = ARITHMATIC_CONDITION;
    
}

condition::condition(condition* condition1, char condType, condition* condition2) {
    intCmp = NULL;
    conditionPtrs[0] = condition1;
    conditionPtrs[1] = condition2;
    isUsed = true; 
    conditionType = condType;
}

condition::~condition() {
    if (intCmp != NULL) {
        delete intCmp;
     }
} 

void condition::release() {
   if (intCmp != NULL) {
        intCmp->release();
        intCmp=NULL;
   }
   if (conditionPtrs[0] != NULL) {
        conditionPtrs[0]->release();
        conditionPtrs[1]->release();
        conditionPtrs[0]=NULL;
        conditionPtrs[1]=NULL;
   }
   isUsed = false;
}

void condition::set(intCompare* compareInput) {
    release();
    intCmp = compareInput;
    conditionPtrs[0] = NULL;
    conditionPtrs[1] = NULL;
    isUsed = true; 
    conditionType = ARITHMATIC_CONDITION;
}

void condition::set(condition* condition1, char condType, condition* condition2) {
    release();
    intCmp = NULL;
    conditionPtrs[0] = condition1;
    conditionPtrs[1] = condition2;
    isUsed = true; 
    conditionType = condType;
}

bool condition::isTrue() {
    
    
    bool result = true;
    if (conditionType == ARITHMATIC_CONDITION) {
        //pc.printf("Evauating arithmatic condition \r\n");
        result = (intCmp->isTrue)();        
    } else if (conditionType == AND_CONDITION) {
        //pc.printf("Evauating AND condition \r\n");
        result = conditionPtrs[0]->isTrue() && conditionPtrs[1]->isTrue();
    } else if (conditionType == OR_CONDITION) {
        //pc.printf("Evauating OR condition \r\n");
        result = conditionPtrs[0]->isTrue() || conditionPtrs[1]->isTrue();
    }
    return result;
    
}

portMessage::portMessage():
    whichToSet(0),
    value(0),
    port(NULL) {
    isUsed = false; 
}

void portMessage::release() {
    
    whichToSet = 0;
    value = 0;
    port = NULL;
    isUsed = false; 
}

/*
portMessage::portMessage(digitalPort* portIn, int whichToSetIn, int valueIn):
    whichToSet(whichToSetIn),
    value(valueIn),
    port(portIn) {
    isUsed = true; 
}

void portMessage::setMessage(digitalPort* portIn, int whichToSetIn, int valueIn) {
    whichToSet = whichToSetIn;
    value = valueIn;
    port = portIn;
    isUsed = true; 
}*/

portMessage::portMessage(int* portIn, int whichToSetIn, int valueIn):
    whichToSet(whichToSetIn),
    value(valueIn),
    port(portIn) {
    isUsed = true; 
}

void portMessage::setMessage(int* portIn, int whichToSetIn, int valueIn) {
    whichToSet = whichToSetIn;
    value = valueIn;
    port = portIn;
    isUsed = true; 
}
 
void portMessage::execute() {
 
    if (port != NULL) {
        if ((*port > 0) && (*port <= NUMPORTS)) {
            portVector[*port]->setDigitalOut(value);
        } else {
            pc.printf("Error: port index assigned by variable does not exist.");
        }
    } else {
        portVector[whichToSet]->setDigitalOut(value);
    }
    
    /*
    if (whichToSet == 1) {
        port->setDigitalOut(value);
    } else if (whichToSet == 2) {
        //port->setState(value);
    }*/
}

action::action():
    actionType(0) {
    op = NULL;
    message = NULL;
    eventToCreate = NULL;
    displayActionPtr = NULL;
    //eventDelay = 0;
    sound = NULL;
    sysCommand = -1;
    isUsed = false; 
        
}

action::~action() {
    if (eventToCreate != NULL) delete eventToCreate;
    if (op != NULL) delete op;
    if (message != NULL) delete message;
    delete displayActionPtr;
    delete sound;
}

void action::release() {
    if (eventToCreate != NULL) eventToCreate->release();
    if (op != NULL) op->release();
    if (message != NULL) message->release();
    if (displayActionPtr != NULL) displayActionPtr->release();
    delete sound; //still need to make a static soundControl array
    
    actionType = 0;
    op = NULL;
    message = NULL;
    eventToCreate = NULL;
    displayActionPtr = NULL;
    //eventDelay = 0;
    sound = NULL;
    sysCommand = -1;
    isUsed = false; 
}

action::action(intOperation* opInput):
    actionType(1) {
    op = opInput;
    message = NULL;
    eventToCreate = NULL;
    displayActionPtr= NULL;
    //eventDelay = 0;
    sound = NULL;
    sysCommand = -1;
    isUsed = true; 
}

action::action(portMessage* messageInput):
    actionType(2) {
    op = NULL;
    eventToCreate = NULL;
    message = messageInput;   
    displayActionPtr= NULL;
    //eventDelay = 0;
    sound = NULL;
    sysCommand = -1;
    isUsed = true; 

}

action::action(event* eventInput):
    actionType(3) {
    op = NULL;
    message = NULL;
    eventToCreate = eventInput;
    displayActionPtr= NULL;
    sound = NULL;
    
    //eventDelay = eventInput->timeLag;
   
    
    sysCommand = -1;
    isUsed = true; 
}

/*
action::action(event* eventInput, uint32_t delay):
    actionType(3) {
    op = NULL;
    message = NULL;
    eventToCreate = eventInput;
    displayActionPtr= NULL;
    sound = NULL;
    eventDelay = delay;
    sysCommand = -1;
    isUsed = true; 
    
}*/



action::action(displayAction* displayInput): 
    actionType(4) {
    op = NULL;
    message = NULL;
    eventToCreate = NULL;
    sound = NULL;
    displayActionPtr = displayInput;
    //eventDelay = 0;
    sysCommand = -1;  
    isUsed = true;   
}

action::action(soundControl* soundInput): 
    actionType(5) {
    op = NULL;
    message = NULL;
    eventToCreate = NULL;
    sound = soundInput;
    displayActionPtr = NULL;
    //eventDelay = 0;
    sysCommand = -1; 
    isUsed = true;   
}

action::action(int8_t sysCommandInput): 
    actionType(6) {
    op = NULL;
    message = NULL;
    eventToCreate = NULL;
    sound = NULL;
    displayActionPtr = NULL;
    //eventDelay = 0;
    sysCommand = sysCommandInput; 
    isUsed = true;   
}

void action::set(intOperation* opInput) {
    actionType = 1;
    op = opInput;
    //eventDelay = 0;
    isUsed = true; 
    
}

void action::set(portMessage* messageInput) {
    actionType = 2;
    message = messageInput;
    //eventDelay = 0;
    isUsed = true; 
    
}

void action::set(event* eventInput) {
    actionType = 3;
    eventToCreate = eventInput;  
    //eventDelay = eventInput->timeLag;
    
    isUsed = true; 
    
}

/*
void action::set(event* eventInput, uint32_t delay) {
    actionType = 3;
    eventToCreate = eventInput;
    eventDelay = delay;
    isUsed = true; 
    
}*/



void action::set(displayAction* displayInput) {
    actionType = 4;
    displayActionPtr = displayInput;
    isUsed = true; 
}

void action::set(soundControl* soundInput) {
    actionType = 5;
    sound = soundInput;
    isUsed = true; 
}

void action::set(int8_t sysCommandInput) {
    actionType = 6;
    sysCommand = sysCommandInput;
    isUsed = true; 
}

void action::execute() {

    if (actionType == 1) {
        op->execute();
    } else if (actionType == 2) {
        message->execute();
    } else if (actionType == 3) {       
        this->execute(*globalTimeKeeperPtr); //route to the other overloaded method  
    } else if (actionType == 4) {       
        displayActionPtr->execute(); //send text via serial  
    } else if (actionType == 5) {       
        sound->execute(); //operate sound device
    } else if (actionType == 6) {
        switch(sysCommand) {
            case 0:
               mainQueue.eraseQueue();
               break; 
            case 1:
               textStreaming = true;
               break; 
            case 2:
               textStreaming = false;
               break;  
            case 3:
                broadCastStateChanges = true;
                break;
            case 4:
                broadCastStateChanges = false;
                break;     
        }
        
    }
}

void action::execute(uint32_t blockExecTime) {
   
    if (actionType == 1) {
        op->execute();
    } else if (actionType == 2) {
        message->execute();
    } else if (actionType == 3) { //an event block
        //Because time will pass from the begining of the block, any defined delays should be updated
        
        //int newDelay = eventDelay-(*globalTimeKeeperPtr-blockExecTime);
        int newDelay;
        if (eventToCreate->timeLagIsConstant) {
            newDelay = eventToCreate->timeLag - (*globalTimeKeeperPtr-blockExecTime);
        } else {
            newDelay = *eventToCreate->timeLagVar - (*globalTimeKeeperPtr-blockExecTime);
        }
        if (newDelay < 0) {newDelay = 0;}          
        eventToCreate->addToQueue(newDelay); //add the event to the queue to be executed later 
       
        if (eventToCreate->hasWhileLoop) { //this is a while loop         
             if (eventToCreate->isConditionTrue()) {
                //newDelay = (blockExecTime + eventToCreate->whileLoopPeriod) - *globalTimeKeeperPtr;
                int tmpPeriod;
                if (eventToCreate->whileLoopPeriodIsConstant) { //constant while loop period
                    newDelay = (blockExecTime + eventToCreate->whileLoopPeriod);
                    tmpPeriod = eventToCreate->whileLoopPeriod;
                } else {
                    tmpPeriod = *eventToCreate->whileLoopPeriodVar;
                    if (tmpPeriod < 0) {
                        tmpPeriod = 0;
                    }
                    newDelay = (blockExecTime + tmpPeriod);
                }
                while ( (newDelay-*globalTimeKeeperPtr < 0) && (eventToCreate->isConditionTrue()) ) {
                    eventToCreate->execute();
                    newDelay = newDelay + tmpPeriod;
                                   
                }
                newDelay = newDelay-*globalTimeKeeperPtr;           
                if (newDelay > 0) {
                    eventToCreate->addToQueue(newDelay);
                } else {
                    eventToCreate->addToQueue(1);
                }
             } else if (eventToCreate->nextElseEventPtr != NULL) {
                    eventToCreate->nextElseEventPtr->addToQueue();
                 
            }         
         }   
    } else if (actionType == 4) {       
        displayActionPtr->execute(); //send text via serial  
    } else if (actionType == 5) {       
        sound->execute(); //operate sound device    
    } else if (actionType == 6) {       
        switch(sysCommand) {
            case 0:
               mainQueue.eraseQueue();
               break; 
            case 1:
               textStreaming = true;
               break; 
            case 2:
               textStreaming = false;
               break; 
            case 3:
                broadCastStateChanges = true;
                break;
            case 4:
                broadCastStateChanges = false;
                break;  
        }
    }
}

eventQueue::eventQueue(digitalPort** portVectorInput, uint32_t* timeKeeperSlaveInput):
    portVector(portVectorInput),
    timeKeeperPtr(timeKeeperSlaveInput){
    
    globalTimeKeeperPtr = timeKeeperPtr;
    queueItem blankEvent;
    blankEvent.timeToExecute = 0;
    blankEvent.eventPtr = NULL;
    queueSize = 100;
    events.resize(queueSize,blankEvent);
    
    
}

void eventQueue::addEventToQueue(event* eventInput, uint32_t delay) {
    //*updateSlavePtr = false;
    uint32_t eventTime = *timeKeeperPtr + delay;
    //*updateSlavePtr = true;  
    //std::vector<queueItem>::size_type sz = events.size();
    //Look for the first empty slot in the queue and place the event there.
    //This means that the events in the queue are out of order, but 
    //it prevents us from having to push_pack and pop off all the time.
    for (unsigned i = 0; i < queueSize; i++) {
        if (events[i].eventPtr == NULL) {
            events[i].eventPtr = eventInput;
            events[i].timeToExecute = eventTime;
            break;
        }
    }    
}

void eventQueue::eraseQueue() {
    //Erase all events in the queue 
    std::vector<queueItem>::size_type sz = events.size();
    for (unsigned i = 0; i < sz; i++) {
        events[i].eventPtr = NULL;
        
    }
}

   
//check if any of the events in the queue are up for execution
void eventQueue::check(void) {

    //*updateSlavePtr = false;
    uint32_t currentTime = *timeKeeperPtr;
    //*updateSlavePtr = true;
    //std::vector<queueItem>::size_type sz = events.size();
    for (unsigned i = 0; i < queueSize; i++) {
        if (events[i].eventPtr != NULL) {
          if(events[i].timeToExecute <= currentTime) {
            if (!events[i].eventPtr->hasWhileLoop) {
                //this is not a while loop, so no need to check if the condition is still true
                events[i].eventPtr->execute();
            } else if (events[i].eventPtr->isConditionTrue()){              
                //The event is part of a while loop, so recheck the condition before executing
                events[i].eventPtr->execute();
                //if (events[i].eventPtr->isConditionTrue()) { //is the condition still true?
                    int nextTime;
                    int tmpPeriod;
                    if (events[i].eventPtr->whileLoopPeriodIsConstant) {
                        nextTime = (events[i].timeToExecute + events[i].eventPtr->whileLoopPeriod);
                        tmpPeriod = events[i].eventPtr->whileLoopPeriod;
                    } else {
                        tmpPeriod = *events[i].eventPtr->whileLoopPeriodVar;
                        if (tmpPeriod < 0) {
                            tmpPeriod = 0;
                        }
                        nextTime = (events[i].timeToExecute + tmpPeriod);
                        
                    }
                    //Just in case we are not keeping up, execute the event until we have cought up
                    while ((nextTime-*timeKeeperPtr <= 0) && (events[i].eventPtr->isConditionTrue())) {
                        events[i].eventPtr->execute();
                        nextTime = nextTime+tmpPeriod;
                                                
                    }
                    nextTime = nextTime - *timeKeeperPtr;
                    if (nextTime > 0) {         
                        //we add the event to the queue (but the condition is rechecked first)
                        //if the condition is false, the 'then' statement is added to the queue instead
                        events[i].eventPtr->addToQueue(nextTime);
                    } else {
                        //if we are having trouble keeping up, just add the next event in 1 ms
                        events[i].eventPtr->addToQueue(1);
                    }
                /*
                } else {
                    if (events[i].eventPtr->nextElseEventPtr != NULL) {
                        events[i].eventPtr->nextElseEventPtr->addToQueue();
                    }
                }*/
                    
            } else {
                if (events[i].eventPtr->nextElseEventPtr != NULL) {
                    events[i].eventPtr->nextElseEventPtr->addToQueue();
                }
            }
            events[i].eventPtr = NULL;
        }
      }  
    }    
}


event::event():
    timeLag(0),
    queuePtr(&mainQueue) {
    nextElseEventPtr = NULL;
    conditionToCheck = NULL;
    blockType = 0; 
    whileLoopPeriod = 0;
    numConditions = 0;
    numActions = 0;
    isUsed = false; 
    timeLagVar = NULL;
    timeLagIsConstant = true;
    whileLoopPeriodIsConstant = true;
    hasWhileLoop = false;
    whileLoopPeriodVar = NULL;
   
 }

event::event(eventQueue* queueInput):
    timeLag(0),
    queuePtr(&mainQueue) {
    nextElseEventPtr = NULL;
    conditionToCheck = NULL;
    blockType = 0; 
    whileLoopPeriod = 0;
    numConditions = 0;
    numActions = 0;
    isUsed = true; 
    timeLagVar = NULL;
    timeLagIsConstant = true;
    whileLoopPeriodIsConstant = true;
    hasWhileLoop = false;
    whileLoopPeriodVar = NULL;
   
 }
 
 event::~event() {
    /*
    while (!conditionArray.empty())
    {
        delete conditionArray.back();
        conditionArray.pop_back();
    }
    
    while (!actionArray.empty())
    {
        delete actionArray.back();
        actionArray.pop_back();
    }
    
    delete nextElseEventPtr;
    */
 
 }
 
void event::release() {
    
    for (int i = 0; i < numActions; i++) {
        actionArray[i]->release();
    }
    
    if (conditionToCheck != NULL) {
        conditionToCheck->release();
        conditionToCheck = NULL;
    }
    
    if (nextElseEventPtr != NULL) {
        nextElseEventPtr->release();
    }
    timeLag = 0;
    nextElseEventPtr = NULL;
    blockType = 0; 
    whileLoopPeriod = 0;
    numConditions = 0;
    numActions = 0;
    isUsed = false;
    timeLagVar = NULL;
    timeLagIsConstant = true;
    whileLoopPeriodIsConstant = true;
    hasWhileLoop = false;
    whileLoopPeriodVar = NULL;
 }
 
 void event::setTimeLag(uint32_t timeLagInput) {
    timeLag = timeLagInput;
    timeLagIsConstant = true;
 }
 
 void event::setTimeLag(int* timeLagInput) {
    timeLagVar = timeLagInput;
    timeLagIsConstant = false; //time lag is not defined by a constant
 }
 
 void event::setWhileLoopPeriod(uint32_t period) {
    whileLoopPeriodIsConstant = true;
    hasWhileLoop = true;
    whileLoopPeriod = period;
    
 }
 
 void event::setWhileLoopPeriod(int* period) {
    whileLoopPeriodIsConstant = false;
    hasWhileLoop = true;
    whileLoopPeriodVar = period;

 }
 
 void event::addCondition(condition* conditionInput) {
    if (conditionToCheck != NULL) {
        conditionToCheck->release();
    }
    conditionToCheck = conditionInput;
    
    //conditionArray.push_back(conditionInput);
 }
 
 void event::addAction(action* actionInput) {
    actionArray[numActions] = actionInput;
    numActions++;
    //actionArray.push_back(actionInput);
 }
 
 bool event::isConditionTrue(void) {
    //if statement (can be left empty, which is interpreted as 'true')
    //queuePtr->pcPtr->printf("Checking condition...\r\n");
    bool result = true;
    /*
    std::vector<condition*>::size_type sz = conditionArray.size();
    for (unsigned i = 0; i < sz; i++) {
        if (!conditionArray[i]->isTrue()) {
            result = false;
            //queuePtr->pcPtr->printf("Consition false\r\n");
        } //else {queuePtr->pcPtr->printf("Consition true\r\n");}
    }
    */
    
    if ((conditionToCheck!=NULL)&&(!conditionToCheck->isTrue())) {
        result = false;        
    } 
    
    return result;
 } 
 
 void event::execute(void) {   
    //called from the event queue.  The condition is bypassed because it was already checked  
    
   
    uint32_t timeAtStartExec = *globalTimeKeeperPtr;      
    //std::vector<action*>::size_type sz = actionArray.size();
    
    /*
    std::deque<action*>::size_type sz = actionArray.size();
       
    for (unsigned i = 0; i < sz; i++) {
        actionArray[i]->execute(timeAtStartExec);
        
    }
    */
     for (unsigned i = 0; i < numActions; i++) {
        actionArray[i]->execute(timeAtStartExec);
        
    }
    
 }
 
 //Attach an 'else' statement to the event
 void event::setNextElseEvent(event* eventInput) {
    nextElseEventPtr = eventInput;
 }
 
 
 //When we we call addToQueue() the condition is checked.  If true, the event is added
 //to the queue, otherwise we check if there was an 'else' statement attached to the event.
 void event::addToQueue(void) {   
    if (isConditionTrue()) {
        if ((timeLagIsConstant)&&(timeLag == 0)) {
            execute();
            
        } else if (timeLagIsConstant) {
            queuePtr->addEventToQueue(this, this->timeLag);
        } else if ((!timeLagIsConstant)&&(*timeLagVar <= 0)) {           
            execute();
        } else {
            queuePtr->addEventToQueue(this, *timeLagVar);           
        }
    } else if ((this->nextElseEventPtr != NULL)&&(whileLoopPeriod == 0)) {
        this->nextElseEventPtr->addToQueue();
    }
 }
 
 //We can override the timeLag field and use another delay
 void event::addToQueue(uint32_t delay) {   
    if (this->isConditionTrue()) {
        //if ((delay == 0) && (whileLoopPeriod == 0)) {
        if ((delay == 0)) {
            this->execute();
        } else {
            queuePtr->addEventToQueue(this, delay);
        }
    } else if ((this->nextElseEventPtr != NULL)) { //&&(!hasWhileLoop)) {
        this->nextElseEventPtr->addToQueue();
    }
 }
 
 
 
 functionItem::functionItem(action* actionInput, string tagInput): 
    tag(tagInput),
    actionPtr(actionInput) {
 }
 
 functionItem::~functionItem() {
    delete actionPtr;
 }
 
 scriptStream::scriptStream(Serial* serialInput, digitalPort** portVectorInput, int numPortsInput, eventQueue* queueInput):
    portVector(portVectorInput),
    numPorts(numPortsInput),
    pcPtr(serialInput),
    queuePtr(queueInput) {
    
    currentPort = -1;
    currentTriggerPort = -1;
    currentTriggerDir = 1;
    currentFunction = -1;
     
    lineError = false;
    blockDepth = 0;
    ifBlockInit = false;
    whileBlockInit = false;
    elseFlag = false;
    currentDelay = 0;
    
 }
 
 void scriptStream::addLineToCurrentBlock(char* lineInput) {
     
    bool compile = false;
    bool keep = false;
    for (int i = 0; i < 128; i++) {
        if (lineInput[i] == ';') {
            compile = true;
        } else if (lineInput[i] == ' ') {
            continue;
        } else if (lineInput[i] == '\0') {
            break;
        } else {
            keep = true;
            compile = false;
        }
    }
    if (keep) currentBlock.insert(currentBlock.begin(),string(lineInput));
    if (compile) parseBlock();
    
 }
 
 
 //SCRIPT PARSING - all script commands are defined here.
 //-------------------------------------------------------
 void scriptStream::parseBlock() {
          
    lineError = false;
    blockDepth = 0;
    ifBlockInit = false;
    whileBlockInit = false;
    elseFlag = false;
    thenFlag = false;
    currentDelay = 0;
    
    std::size_t stringInd = 0;
    
    bool wholeLineEvaluated = false;
   
    //pcPtr->printf("\r\n"); 
    while (!currentBlock.empty()) {
        wholeLineEvaluated = false;
        tmpLine = currentBlock.back();
        lineError = false;
        //remove tabs
        std::size_t found = tmpLine.find_first_of(9); //tab
        while (found!=std::string::npos) {
            tmpLine[found]= ' ';
            found=tmpLine.find_first_of(9,found+1);
        }
        
        found = tmpLine.find_first_of(37); //% for commenting
        if (found!=std::string::npos) {
            for (int p=found; p<tmpLine.size() ;p++) {
                tmpLine[p]= ' ';
            }
        }

        //break up the line into tokens separated by spaces
        tokenize(tmpLine,tokens," ;");
        
        std::vector<string>::size_type sz = tokens.size();
    
        for (unsigned i = 0; i < sz; i++) {
            //pcPtr->printf("%s", tokens[i].c_str());
            
            
            //end statement signals the end of a block-----------------------------------------
            if (tokens[i].compare("end") == 0) { //ends the current block
                
                if (ifBlockInit || whileBlockInit) {
                    pcPtr->printf("Error: expected a 'do' statement\r\n");
                    lineError = true;
                }
                
                ifBlockInit = false;
                whileBlockInit = false;
                elseFlag = false;
                
                if (blockDepth > 0) {
                    if (blockDepth == 1) {
                        
                        
                        //pcPtr->printf("Close trigger block for port %d\r\n",currentTriggerPort);
                        currentTriggerPort = -1;
                        
                        
                        
                        blockDepth = 0;
                    } else if (blockDepth > 1) {
                        //pcPtr->printf("Close block\r\n");
                        blockDepth = blockDepth - 1;
                    }
                    
                    while ((tmpEventPtrArray.back()->blockType == 3) || (tmpEventPtrArray.back()->blockType == 4)){
                       tmpEventPtrArray.pop_back(); //recursively remove the pointers to all else blocks
                    }
                    tmpEventPtrArray.pop_back(); //remove the pointer to the finished block
                } else {
                    pcPtr->printf("Error: End statement without block\r\n");
                    lineError = true;
                }
                
                
            
            //sound statement used to play wave files------------------------------------------------
            //example: sound('soundfile')
            //         sound(stop) 
            } else if (tokens[i].find("sound(") != std::string::npos) {
                if (ifBlockInit || whileBlockInit || elseFlag) {
                    pcPtr->printf("Error: expected a 'do' statement\r\n");
                    lineError = true;
                }
                wholeLineEvaluated = true;
                int pos1 = tmpLine.find("sound(")+6;
                int pos2 = tmpLine.find_first_of(")",pos1);
                string dispVar = tmpLine.substr(pos1,pos2-pos1);
                
                int* tmpVar = findIntVariable(dispVar);
                bool isText = false;
                bool stopSignal = false;
                bool resetSignal = false;
                if (tmpVar == NULL) {
                    if ((tmpLine.compare(pos1,1,"'")==0) && (tmpLine.compare(pos2-1,1,"'")==0)) {
                        isText = true;                        
                    } else if (dispVar.compare("stop") == 0) {
                        stopSignal = true;
                    } else if (dispVar.compare("reset") == 0) {
                        resetSignal = true;    
                    } else {    
                        pcPtr->printf("Error: variable input to sound() does not exist\r\n");
                        lineError = true;
                    }
                }
                action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS);                   
                if (tmpAction == NULL) {                    
                    pcPtr->printf("Error: no memory slots available.\r\n"); 
                    lineError = true;
                }
                if (!lineError && (blockDepth == 0)) {
                    //we are not inside a block structure, so play sound now
                    if (stopSignal) {
                        soundControl S;
                        S.setPlayback(false);
                        S.execute();
                    } else if (resetSignal) {
                        soundControl S;
                        S.setReset();
                        S.execute();
                    } else if (isText) {
                                             
                        if (pos2-pos1-2 <= 20) {
                            
                            soundControl S;
                            S.setFile(tmpLine.substr(pos1+1,pos2-pos1-2));
                            S.execute();
                        } else {
                            pcPtr->printf("Error: sound file names must be 20 characters or less.\r\n");
                            lineError = true;
                        }
                    } else {
                        pcPtr->printf("Error: variable input to sound() not yet supported.  Enter a string in single quotes.\r\n");
                        lineError = true;
                    }
                    
                } else if (!lineError && (blockDepth > 0) ){
                    //the disp function was put inside a block
                    if (stopSignal) {
                        soundControl* sPtr = new soundControl();
                        sPtr->setPlayback(false);
                        //action* tmpAction = new action(sPtr);
                        tmpAction->set(sPtr);
                        tmpEventPtrArray.back()->addAction(tmpAction);
                    } else if (resetSignal) {
                        soundControl* sPtr = new soundControl();
                        sPtr->setReset();
                        //action* tmpAction = new action(sPtr);
                        tmpAction->set(sPtr);
                        tmpEventPtrArray.back()->addAction(tmpAction);    
                    } else if (isText) {
                                             
                        if (pos2-pos1-2 <= 20) {
                            soundControl* sPtr = new soundControl();
                            sPtr->setFile(tmpLine.substr(pos1+1,pos2-pos1-2));
                            //action* tmpAction = new action(sPtr);
                            tmpAction->set(sPtr);
                            tmpEventPtrArray.back()->addAction(tmpAction);
                        } else {
                            pcPtr->printf("Error: sound file names must be 20 characters or less.\r\n");
                            lineError = true;
                        }
                    } else {
                        pcPtr->printf("Error: variable input to sound() not yet supported.  Enter a string in single quotes.\r\n");
                        lineError = true;
                    }
                    
                    //pcPtr->printf("Sound action\r\n");
                }
                
            } else if (tokens[i].find("volume(") != std::string::npos) {
                if (ifBlockInit || whileBlockInit || elseFlag) {
                    pcPtr->printf("Error: expected a 'do' statement\r\n");
                    lineError = true;
                }
                wholeLineEvaluated = true;
                int pos1 = tmpLine.find("volume(")+7;
                int pos2 = tmpLine.find_first_of(")",pos1);
                string dispVar = tmpLine.substr(pos1,pos2-pos1);
                
                int* tmpVar = findIntVariable(dispVar);
                bool isText = false;
                if (tmpVar == NULL) {
                    if (isNumber(dispVar)) {
                        isText = true;
                    } else {    
                        pcPtr->printf("Error: variable input to volume() does not exist\r\n");
                        lineError = true;
                    }
                }
                action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS);                   
                if (tmpAction == NULL) {                    
                    pcPtr->printf("Error: no memory slots available.\r\n"); 
                    lineError = true;
                }
                if (!lineError && (blockDepth == 0)) {
                    //we are not inside a block structure, so play sound now
                    if (isText) {
                        int newVolume = atoi(dispVar.data());                   
                        if ((newVolume >=0)&&(newVolume <= 255)) {
                            soundControl S;
                            S.setVolume(newVolume);
                            S.execute();
                        } else {
                            pcPtr->printf("Error: sound volume must be between 0 and 255 .\r\n");
                            lineError = true;
                        }
                    } else {
                        soundControl S;
                        S.setVolume(tmpVar);
                        S.execute();
                    }
                    
                } else if (!lineError && (blockDepth > 0) ){
                    //the disp function was put inside a block
                    if (isText) {
                        int newVolume = atoi(dispVar.data());                   
                        
                        soundControl* sPtr = new soundControl();
                        sPtr->setVolume(newVolume);
                        
                        //action* tmpAction = new action(sPtr);
                        tmpAction->set(sPtr);                      
                        tmpEventPtrArray.back()->addAction(tmpAction);
                                                       
                    } else {
                        soundControl* sPtr = new soundControl();
                        sPtr->setVolume(tmpVar);
                        //action* tmpAction = new action(sPtr);
                        tmpAction->set(sPtr);
                        tmpEventPtrArray.back()->addAction(tmpAction);
                    }
                                     
                    //pcPtr->printf("Volume action\r\n");
                }
            //clock statement used to is used to control the clock-------------------------
            //example: clock(reset); clock(slave); clock(standalone)    
            } else if (tokens[i].find("clock(") != std::string::npos) { //clock commands
                if (ifBlockInit || whileBlockInit || elseFlag) {
                    pcPtr->printf("Error: expected a 'do' statement\r\n");
                    lineError = true;
                }
                if (blockDepth > 0) {
                    pcPtr->printf("Error: clock commands only allowed outside of block structure\r\n");
                    lineError = true;
                }
                
                if (!lineError) {
                    int pos1 = tmpLine.find("clock(")+6;
                    int pos2 = tmpLine.find_first_of(")",pos1);
                    string dispVar = tmpLine.substr(pos1,pos2-pos1);
                    
                    
                    if (blockDepth == 0) {
                        if (dispVar.compare("reset") == 0) {
                            resetTimer = true;
                            queuePtr->eraseQueue();
                            textDisplay.send(string("Clock reset to 0\r\n"));
                            //pcPtr->printf("Clock reset to 0\r\n");
                        } else if (dispVar.compare("slave") == 0) {
                            if (!clockSlave) {
                                changeToSlave = true;
                                textDisplay.send(string("Slave mode\r\n"));
                                //pcPtr->printf("Slave mode\r\n");
                            }
                        } else if (dispVar.compare("standalone") == 0) {
                            if (clockSlave) {
                                changeToStandAlone = true;
                                textDisplay.send(string("Standalone mode\r\n"));
                                //pcPtr->printf("Standalone mode\r\n");
                            }
                        } else {
                            pcPtr->printf("Clock control statement not understood\r\n");
                            lineError = true;
                        }
                    } 
                }
                    
            //disp command used to display text via serial---------------------------------------
            //example: disp('hello'); disp(myVar)   
            } else if (tokens[i].find("disp(") != std::string::npos) { //display value of variable
                
                if (ifBlockInit || whileBlockInit || elseFlag) {
                    pcPtr->printf("Error: expected a 'do' statement\r\n");
                    lineError = true;
                }
                
                //int pos1 = tokens[i].find("disp(")+5;
                //int pos2 = tokens[i].find_first_of(")",pos1);
                //string dispVar = tokens[i].substr(pos1,pos2-pos1);
                
                wholeLineEvaluated = true;
                int pos1 = tmpLine.find("disp(")+5;
                int pos2 = tmpLine.find_first_of(")",pos1);
                string dispVar = tmpLine.substr(pos1,pos2-pos1);
                
                int* tmpVar = findIntVariable(dispVar);
                bool isText = false;
                if (tmpVar == NULL) {
                    if ((tmpLine.compare(pos1,1,"'")==0) && (tmpLine.compare(pos2-1,1,"'")==0)) {
                        isText = true;
                    } else {    
                        pcPtr->printf("Error: variable to display does not exist\r\n");
                        lineError = true;
                    }
                }
                displayAction* dPtr = findFirstUnUsed(displayActionBlock, NUMDISPLAYACTIONS);                   
                if (dPtr == NULL) {                    
                    pcPtr->printf("Error: no memory slots available.\r\n"); 
                    lineError = true;
                } 
                if (!lineError && (blockDepth == 0)) {
                    //we are not inside a block structure, so display now
                   
                    if (isText) {
                        //displayAction* dPtr = new displayAction(tmpLine.substr(pos1+1,pos2-pos1-2), pcPtr);
                        dPtr->set(tmpLine.substr(pos1+1,pos2-pos1-2), pcPtr);
                        dPtr->execute();
                        //delete dPtr;
                        dPtr->release();
                    } else {
                        //displayAction* dPtr = new displayAction(tmpVar, dispVar, pcPtr);
                        dPtr->set(tmpVar, dispVar, pcPtr);
                        dPtr->execute();
                        //delete dPtr;   
                        dPtr->release();                  
                    }
                                      
                } else if (!lineError && (blockDepth > 0) ){
                    //the disp function was put inside a block
                    action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS);                   
                    if (tmpAction == NULL) {                    
                        pcPtr->printf("Error: no memory slots available.\r\n"); 
                        lineError = true;
                    }
                    if (!lineError && isText) {
                        //displayAction* dPtr = new displayAction(tmpLine.substr(pos1+1,pos2-pos1-2), pcPtr);
                        dPtr->set(tmpLine.substr(pos1+1,pos2-pos1-2), pcPtr);
                        tmpAction->set(dPtr);
                        //action* tmpAction = new action(dPtr);
                        tmpEventPtrArray.back()->addAction(tmpAction);
                    } else if (!lineError) {
                        //displayAction* dPtr = new displayAction(tmpVar, dispVar, pcPtr);
                        dPtr->set(tmpVar, dispVar, pcPtr);
                        tmpAction->set(dPtr);
                        //action* tmpAction = new action(dPtr);
                        tmpEventPtrArray.back()->addAction(tmpAction);
                    }
                    
                    //pcPtr->printf("Display action\r\n");
                }
            
            
            //int is used to decalar new variables.  Only allowed outside of callbacks-------------------
            //example: int a;  int b = 9    
            } else if (tokens[i].compare("int") == 0) { //define a new integer variable
                
                if (ifBlockInit || whileBlockInit) {
                    pcPtr->printf("Error: expected a 'do' statement\r\n");
                    lineError = true;
                }
                tmpString = "";
                wholeLineEvaluated = true;
                int spacesBeforeEqualSign = 0;
                bool countSpaces = true;
                //combine the tokens without whitespaces
                for (unsigned j = i+1; j < sz; j++) { 
                    tmpString.append(tokens[j]);
                    if (tokens[j].find_first_of("=") != std::string::npos) {
                        if (tokens[j].find_first_of("=") > 0) spacesBeforeEqualSign++;
                        countSpaces = false;
                    } else if (countSpaces) {
                        spacesBeforeEqualSign++;
                    }   
                }
                
                if (blockDepth > 0) {
                    pcPtr->printf("Error: Variables can only be first declared outside of callbacks.\r\n");
                    lineError = true;
                }
                
                if ((!lineError) && (spacesBeforeEqualSign > 1)) {
                    pcPtr->printf("Error: Variable can't have a space in it.\r\n");
                    lineError = true;
                }
                stringInd = tmpString.find_first_of("=");
                
                bool variableCreated = false;
                if (!lineError) {
                    if (((stringInd == std::string::npos) && (sz == 2)) || (stringInd != std::string::npos)) {
                        if (createIntVariable(tmpString.substr(0,stringInd))) {
                            //pcPtr->printf("Created variable: %s\r\n", tmpString.substr(0,stringInd).data());
                            variableCreated = true;
                        } else {                         
                            int* tmpVar = findIntVariable(tmpString.substr(0,stringInd));
                            *tmpVar = 0;
                            //pcPtr->printf("Reset variable %s to 0\r\n", tmpString.substr(0,stringInd).data());
                            //lineError = true;
                        }
                    } else {
                        pcPtr->printf("Error: variable declaration not understood.\r\n", tmpString.substr(0,stringInd).data());
                        lineError = true;
                    } 
                }   
                    
                if ((!lineError) && (stringInd != std::string::npos)) { //evaluate the expression                  
                    action* tmpAction = evaluateAssignmentForAction(tmpString);
                    if (tmpAction != NULL) {
                        tmpAction->execute();
                        //delete tmpAction;
                        tmpAction->release();
                     } else {
                        lineError = true;
                        if (variableCreated) {
                            delete globalVariables.back();
                            globalVariables.pop_back();
                        }
                    } 
                }
            
            //serial command is used to toggle whether or not to buffer up output text----------------
            //examples: serial buffer; serial send
            } else if (tokens[i].compare("serial") == 0) {
                 if (ifBlockInit || whileBlockInit || elseFlag) {
                    pcPtr->printf("Error: expected a 'do' statement\r\n");
                    lineError = true;
                }
                bool stream = true;
                if ((!lineError)&&(i+1 < sz)){
                    if (tokens[i+1].compare("buffer") == 0) {                      
                            stream = false;                        
                    } else if (tokens[i+1].compare("send") == 0) {                   
                            stream = true;                                             
                    } else {
                        pcPtr->printf("Error: 'serial' useage: 'serial buffer' or 'serial send'\r\n");
                        lineError = true;
                    }
                }
                i++;
                if ((!lineError) && (blockDepth == 0)) {                    
                    if (stream) {
                        textStreaming = true;
                    } else {
                        textStreaming = false;
                    }
                } else if ((!lineError) && (blockDepth > 0)) {
                     if (stream) {
                        //action* tmpAction = new action(1); //code 1 = turn on text streaming
                        action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS);                   
                        if (tmpAction == NULL) {                    
                            pcPtr->printf("Error: no memory slots available.\r\n"); 
                            lineError = true;
                        } else {
                            tmpAction->set(1);
                            tmpEventPtrArray.back()->addAction(tmpAction);
                        }
                        
                     } else {
                        //action* tmpAction = new action(2); //code 2 = turn on text buffering
                        action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS);                   
                        if (tmpAction == NULL) {                    
                            pcPtr->printf("Error: no memory slots available.\r\n"); 
                            lineError = true;
                        } else {
                            tmpAction->set(2);
                            tmpEventPtrArray.back()->addAction(tmpAction);
                        }
                     }
                }
             
            //updates command toggles the DIO update messages upon a change------------------
            //examples: updates on; updates off     
            } else if (tokens[i].compare("updates") == 0) {
                 if (ifBlockInit || whileBlockInit || elseFlag) {
                    pcPtr->printf("Error: expected a 'do' statement\r\n");
                    lineError = true;
                }
                bool stream = true;
                if ((!lineError)&&(i+1 < sz)){
                    if (tokens[i+1].compare("on") == 0) {                      
                            stream = true;                        
                    } else if (tokens[i+1].compare("off") == 0) {                   
                            stream = false;                                             
                    } else {
                        pcPtr->printf("Error: 'updates' useage: 'updates on' or 'updates off'\r\n");
                        lineError = true;
                    }
                }
                i++;
                if ((!lineError) && (blockDepth == 0)) {                   
                    if (stream) {
                        broadCastStateChanges = true;
                    } else {
                        broadCastStateChanges = false;
                    }
                } else if ((!lineError) && (blockDepth > 0)) {                    
                     if (stream) {
                        //action* tmpAction = new action(3); //code 3 = turn on updates
                        action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS);                   
                        if (tmpAction == NULL) {                    
                            pcPtr->printf("Error: no memory slots available.\r\n"); 
                            lineError = true;
                        } else {
                            tmpAction->set(3);
                            tmpEventPtrArray.back()->addAction(tmpAction);
                        }
                     } else {
                        //action* tmpAction = new action(4); //code 4 = turn off updates
                        action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS);                   
                        if (tmpAction == NULL) {                    
                            pcPtr->printf("Error: no memory slots available.\r\n"); 
                            lineError = true;
                        } else {
                            tmpAction->set(4);
                            tmpEventPtrArray.back()->addAction(tmpAction);
                        }
                        
                     }
                }
                 
            //clear is used to clear things from memory---------------------------------
            //examples: clear all; clear callbacks; clear queue
            } else if (tokens[i].compare("ram") == 0) {
                if (ifBlockInit || whileBlockInit || elseFlag) {
                    pcPtr->printf("Error: expected a 'do' statement\r\n");
                    lineError = true;
                }
                if ((!lineError) && (blockDepth > 0)) {
                    pcPtr->printf("Error: ram statement is not allowed inside a block.\r\n");
                    lineError = true;
                }
                if (!lineError) {
                    DisplayRAMBanks();
                }
            } else if (tokens[i].compare("memory") == 0) {
                if (ifBlockInit || whileBlockInit || elseFlag) {
                    pcPtr->printf("Error: expected a 'do' statement\r\n");
                    lineError = true;
                }
                if ((!lineError) && (blockDepth > 0)) {
                    pcPtr->printf("Error: memory statement is not allowed inside a block.\r\n");
                    lineError = true;
                }
                if (!lineError) {
                    displayMemoryLeft();
                }
            
            
            } else if (tokens[i].compare("clear") == 0) { //delete all created events and variables
                if (ifBlockInit || whileBlockInit || elseFlag) {
                    pcPtr->printf("Error: expected a 'do' statement\r\n");
                    lineError = true;
                }
                int clearMode = 0;
                if ((!lineError)&&(i+1 < sz)){
                    if (tokens[i+1].compare("all") == 0) {
                        clearMode = 1;
                    } else if (tokens[i+1].compare("blocks") == 0) {
                        clearMode = 2;                   
                    } else if (tokens[i+1].compare("queue") == 0) {
                        clearMode = 3;                    
                    } else {
                        pcPtr->printf("Error: clear what: all, blocks, or queue? \r\n");
                        lineError = true;
                    }
                } else {
                    pcPtr->printf("Error: clear what: all, blocks, or queue? \r\n");
                    lineError = true;
                }
                    
                
                if ((!lineError) && (clearMode < 3) && (blockDepth > 0)) {
                    pcPtr->printf("Error: 'clear all' and 'clear blocks' only allowed outside of block structures\r\n");
                    lineError = true;
                }
                if (!lineError) {
                    i++;
                    //clear variables
                    if (clearMode == 1) {
                        while (!globalVariables.empty()) {               
                            globalVariables.pop_back();                      
                        }
                    }
                    
                    //clear callbacks, functions, and queue
                    if (clearMode < 3) { 
                        for (int pNum = 1; pNum <= numPorts; pNum++) {
                            //delete portVector[pNum]->triggerUpEventPtr;
                            if (portVector[pNum]->triggerUpEventPtr != NULL) {
                                portVector[pNum]->triggerUpEventPtr->release();
                            }
                            portVector[pNum]->triggerUpEventPtr = NULL;
                            
                            //delete portVector[pNum]->triggerDownEventPtr;
                            if (portVector[pNum]->triggerDownEventPtr != NULL) {
                                portVector[pNum]->triggerDownEventPtr->release();
                            }
                            portVector[pNum]->triggerDownEventPtr = NULL;
                            while (!functionArray.empty()) {               
                                delete functionArray.back();
                                functionArray.pop_back();                      
                            }                           
                        }
                        
                        queuePtr->eraseQueue();
                    }
                    
                    if (clearMode == 4) {
                        if (blockDepth > 0) { //we are inside a block
                            action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS);                   
                            if (tmpAction == NULL) {                    
                                pcPtr->printf("Error: no memory slots available.\r\n"); 
                                lineError = true;
                            } else {
                                                   
                                int8_t code = 0;
                                tmpAction->set(code);
                                //action* tmpAction = new action(code); //code 0 = clear queue
                                tmpEventPtrArray.back()->addAction(tmpAction);
                            }
                        } else {
                            //clear queue now
                            queuePtr->eraseQueue();
                        }
                    }
                                     
                    
                }
                
            //do starts a block---------------------------------------------------------  
            //example:  do in 500
            //              ...
            //          end
                                
            } else if (tokens[i].compare("do") == 0) { //the start of a block
                                      
                     if (!ifBlockInit && !whileBlockInit) {
                         
                         if ((currentTriggerPort > 0) || (currentFunction > 0)) { //check to make sure we are inside a trigger block
                             //pcPtr->printf("Start new block\r\n"); 
                                
                         } else {
                             pcPtr->printf("Error: a statement block must be placed inside a callback or function.\r\n"); 
                             lineError = true;
                         }
                            
                     }
                     tmpEvent = findFirstUnUsed(eventBlock, NUMEVENTS);
                     action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS);
                     bool eventReserved = false;
                     if ((tmpEvent == NULL)||(tmpAction == NULL)) {                    
                        pcPtr->printf("Error: no memory slots available.\r\n"); 
                        lineError = true;
                                       
                    } else {
                       
                             
                    }
                                  
                    if (i+2 < sz) { //a time delay in the block
                        
                        if ((!lineError) && (tokens[i+1].compare("in") == 0) && (isNumber(tokens[i+2]))) {
                            
                            currentDelay = atoi(tokens[i+2].data());
                            if (currentDelay < 0) {
                               pcPtr->printf("Error: block delay time must be a positive integer\r\n"); 
                               lineError = true; 
                            } else if (!ifBlockInit) { //a standalone do block
                               //tmpEvent = new event(queuePtr);
                               tmpEvent->isUsed = true;
                               eventReserved = true;
                               tmpEvent->setTimeLag(currentDelay);
                                                             
                               if ((!elseFlag) && ((!thenFlag))) {
                                    //tmpEventPtrArray.back()->addAction(new action(tmpEvent));
                                    tmpAction->set(tmpEvent);
                                    tmpEventPtrArray.back()->addAction(tmpAction);
                                    tmpEventPtrArray.push_back(tmpEvent);
                                    tmpEventPtrArray.back()->blockType = 2; //this is a do block
                                    blockDepth = blockDepth+1;
                               } else if (elseFlag) {
                                    tmpEventPtrArray.back()->setNextElseEvent(tmpEvent);
                                    tmpEventPtrArray.push_back(tmpEvent);
                                    tmpEventPtrArray.back()->blockType = 4; //an else block
                               } else if (thenFlag) {
                                    
                                    tmpEventPtrArray.back()->setNextElseEvent(tmpEvent);
                                    tmpEventPtrArray.push_back(tmpEvent);
                                    tmpEventPtrArray.back()->blockType = 8; //a then block
                               }
                               //pcPtr->printf("Block delay: %d\r\n", tmpEventPtrArray.back()->timeLag); 
                            } else { //an if block
                               tmpEventPtrArray.back()->setTimeLag(currentDelay);
                                                               
                               if (!elseFlag && !thenFlag) {                 
                                   if (blockDepth > 1) { //this is a nested block, so add it as an action to the parent block
                                        tmpAction->set(tmpEventPtrArray.back());
                                        tmpEventPtrArray.at(tmpEventPtrArray.size()-2)->addAction(tmpAction);
                                        //tmpEventPtrArray.at(tmpEventPtrArray.size()-2)->addAction(new action(tmpEventPtrArray.back())); 
                                   }                    
                               } else if (elseFlag){
                                   tmpEventPtrArray.at(tmpEventPtrArray.size()-2)->setNextElseEvent(tmpEventPtrArray.back());
                               } else if (thenFlag){
                                   tmpEventPtrArray.at(tmpEventPtrArray.size()-2)->setNextElseEvent(tmpEventPtrArray.back());
                                   
                               }
                               //pcPtr->printf("Block delay: %d\r\n", tmpEventPtrArray.back()->timeLag); 
                               
                            }
                            
                         } else if ((!lineError) && (tokens[i+1].compare("in") == 0) && (findIntVariable(tokens[i+2])!=NULL)) {
                            
                            int* delayVar = findIntVariable(tokens[i+2]);
                            //currentDelay = atoi(tokens[i+2].data());
                            if (!ifBlockInit) { //a standalone do block
                               //tmpEvent = new event(queuePtr);
                               tmpEvent->isUsed = true;
                               eventReserved = true;
                               tmpEvent->setTimeLag(delayVar);
                                                             
                               if ((!elseFlag) && ((!thenFlag))) {
                                    //tmpEventPtrArray.back()->addAction(new action(tmpEvent));
                                    tmpAction->set(tmpEvent);
                                    tmpEventPtrArray.back()->addAction(tmpAction);
                                    tmpEventPtrArray.push_back(tmpEvent);
                                    tmpEventPtrArray.back()->blockType = 2; //this is a do block
                                    blockDepth = blockDepth+1;
                               } else if (elseFlag) {
                                    tmpEventPtrArray.back()->setNextElseEvent(tmpEvent);
                                    tmpEventPtrArray.push_back(tmpEvent);
                                    tmpEventPtrArray.back()->blockType = 4; //an else block
                               } else if (thenFlag) {
                                    
                                    tmpEventPtrArray.back()->setNextElseEvent(tmpEvent);
                                    tmpEventPtrArray.push_back(tmpEvent);
                                    tmpEventPtrArray.back()->blockType = 8; //a then block
                               }
                               //pcPtr->printf("Block delay: %d\r\n", tmpEventPtrArray.back()->timeLag); 
                            } else { //an if block
                               tmpEventPtrArray.back()->setTimeLag(delayVar);
                                                               
                               if (!elseFlag && !thenFlag) {                 
                                   if (blockDepth > 1) { //this is a nested block, so add it as an action to the parent block
                                        tmpAction->set(tmpEventPtrArray.back());
                                        tmpEventPtrArray.at(tmpEventPtrArray.size()-2)->addAction(tmpAction);
                                        //tmpEventPtrArray.at(tmpEventPtrArray.size()-2)->addAction(new action(tmpEventPtrArray.back())); 
                                   }                    
                               } else if (elseFlag){
                                   tmpEventPtrArray.at(tmpEventPtrArray.size()-2)->setNextElseEvent(tmpEventPtrArray.back());
                               } else if (thenFlag){
                                   tmpEventPtrArray.at(tmpEventPtrArray.size()-2)->setNextElseEvent(tmpEventPtrArray.back());
                                   
                               }
                               //pcPtr->printf("Block delay: %d\r\n", tmpEventPtrArray.back()->timeLag); 
                               
                            }
                            
                         } else {
                             pcPtr->printf("Error: block delay time must be a positive integer or a variable\r\n"); 
                             lineError = true; 
                         }
                      } else if (!lineError && !ifBlockInit) { //no time delay given, standalone do
                         currentDelay = 0;
                         //tmpEvent = new event(queuePtr);
                         tmpEvent->isUsed = true;
                         eventReserved = true;
                         tmpEvent->setTimeLag(currentDelay);
                         if (!elseFlag && !thenFlag) {
                            tmpAction->set(tmpEvent);
                            tmpEventPtrArray.back()->addAction(tmpAction);
                            //tmpEventPtrArray.back()->addAction(new action(tmpEvent));                            
                            tmpEventPtrArray.push_back(tmpEvent);
                            blockDepth = blockDepth+1;
                         } else if (elseFlag) {
                            tmpEventPtrArray.back()->setNextElseEvent(tmpEvent);
                            tmpEventPtrArray.push_back(tmpEvent);
                            tmpEventPtrArray.back()->blockType = 4; //an else block
                         } else if (thenFlag) {
                            tmpEventPtrArray.back()->setNextElseEvent(tmpEvent);
                            tmpEventPtrArray.push_back(tmpEvent);
                            tmpEventPtrArray.back()->blockType = 8; //a then block
                         }
                         //pcPtr->printf("Block delay: %d\r\n", tmpEventPtrArray.back()->timeLag); 
                      } else if (!lineError) { //no time delay, if block
                         
                         currentDelay = 0;     
                         tmpEventPtrArray.back()->setTimeLag(currentDelay);
                         
                         
                         if (!elseFlag && !thenFlag) {
                             if (blockDepth > 1) {
                                tmpAction->set(tmpEventPtrArray.back());
                                tmpEventPtrArray.at(tmpEventPtrArray.size()-2)->addAction(tmpAction);
                                //tmpEventPtrArray.at(tmpEventPtrArray.size()-2)->addAction(new action(tmpEventPtrArray.back()));
                             }
                         } else {
                             tmpEventPtrArray.at(tmpEventPtrArray.size()-2)->setNextElseEvent(tmpEventPtrArray.back());
                         }
                         
                         
                         //pcPtr->printf("Block delay: %d\r\n", tmpEventPtrArray.back()->timeLag); 
                      }
                      if (lineError && eventReserved) {
                        tmpEvent->release();
                      }           
                      //close block initiation 
                      ifBlockInit = false;
                      whileBlockInit = false;
                      wholeLineEvaluated = true;
                      elseFlag = false;
                      thenFlag = false;
            
            //callback starts a callback block------------------------------------------
            //exmaple: callback portin(1) down
            //              ...
            //         end
            } else if (tokens[i].compare("callback") == 0) { //a new callback block 
                if (ifBlockInit || whileBlockInit || elseFlag) {
                    pcPtr->printf("Error: expected a 'do' statement\r\n");
                    lineError = true;
                }
                if (blockDepth != 0)  {
                    pcPtr->printf("Error: Can't declare a callback block within another block\r\n"); 
                    lineError = true;
                }
                if (!lineError) {  
                    wholeLineEvaluated = true;                               
                    if (i+2 < sz) {
                        if ((tokens[i+1].find("portin[") != std::string::npos) && (tokens[i+1].size() > 8) ) { //callback for a digital port 
                            int pos1 = tokens[i+1].find("portin[")+7;
                            int pos2 = tokens[i+1].find_first_of("]",pos1);
                            currentTriggerPort = atoi(tokens[i+1].substr(pos1,pos2-pos1).data());
                                     
                            if (currentTriggerPort <= 0) { 
                                currentTriggerPort = -1;
                                pcPtr->printf("Error: Not a valid port number\r\n");
                                lineError = true;
                            }
                        } else {
                            pcPtr->printf("Error: Not a valid callback input\r\n");
                            lineError = true;
                        } 
                        if (tokens[i+2].compare("up") == 0) {
                            currentTriggerDir = 1;
                        } else if (tokens[i+2].compare("down") == 0) {
                            currentTriggerDir = -1;
                        } else {
                            pcPtr->printf("Error: No trigger direction given\r\n");
                            lineError = true;
                        }
                                    
                    } else {
                        if (!lineError) pcPtr->printf("Error: Not enough arguments for callback statement\r\n");
                        lineError = true;
                    } 
                    if (sz > 3) {
                        if (!((sz == 4) && (tokens[i+3].compare("do") == 0))) {
                            pcPtr->printf("Error: Too many arguments in callback statement\r\n");
                            lineError = true;
                        }
                    }
                    
                    tmpEvent = findFirstUnUsed(eventBlock, NUMEVENTS);                   
                    if (tmpEvent != NULL) {                    
                        tmpEvent->isUsed = true;
                                             
                    } else {
                        pcPtr->printf("Error: no memory slots available.\r\n"); 
                        lineError = true;
                    }
                    if (!lineError) {
                        //pcPtr->printf("Current port: %d\r\n", currentTriggerPort); 
                        blockDepth = 1;
                        i = i+2;
                        //create new event and attach it to the port
                        //tmpEventPtrArray.push_back(new event(queuePtr));
                        tmpEventPtrArray.push_back(tmpEvent);
                        if (currentTriggerDir == 1) {
                            
                            portVector[currentTriggerPort]->setTriggerUpEvent(tmpEventPtrArray.back());
                        } else {
                            
                            portVector[currentTriggerPort]->setTriggerDownEvent(tmpEventPtrArray.back());
                        }
                    
                    }                                             
                }
            
            //if starts an if block----------------------------------------------
            //examples: if x < 10 && y == 1 do;  if a==1 do in 1000       
            } else if (tokens[i].compare("if") == 0) { //a new if block
                if (ifBlockInit || whileBlockInit) {
                    pcPtr->printf("Error: expected a 'do' statement\r\n");
                    lineError = true;
                }
                
                ifBlockInit = true;
                currentDelay = 0;
                bool eventDefined = false;
                tmpEvent = findFirstUnUsed(eventBlock, NUMEVENTS);
                if (tmpEvent != NULL) {                    
                    tmpEvent->isUsed = true; 
                    eventDefined = true;                     
                } else {
                    pcPtr->printf("Error: no memory slots available.\r\n"); 
                    lineError = true;
                }
                if (!lineError) {
                    //this is a regular event
                    //tmpEventPtrArray.push_back(new event(queuePtr)); 
                    tmpEventPtrArray.push_back(tmpEvent); 
                    
                    if ((!elseFlag) && ((!thenFlag))) {
                        tmpEventPtrArray.back()->blockType = 1; //this is an if block
                        blockDepth = blockDepth + 1;
                    } else if (elseFlag) {
                         tmpEventPtrArray.back()->blockType = 3; //this is an else if block
                    } else if (thenFlag) {
                         tmpEventPtrArray.back()->blockType = 7; //this is a then if block
                    }  
                }    
                
                if (!lineError) {
                    //combine the condition tokens without whitespaces
                    tmpString = "";
                    for (unsigned j = i+1; j < sz; j++) { 
                        if (tokens[j].compare("do") != 0) {
                           i++;
                           tmpString.append(tokens[j]);
                        } else {                     
                            break;
                        }
                    }
                    //adds the conditions to the current event
                    
                    if (!evaluateConditions(tmpString, tmpEventPtrArray.back())) lineError = true; 
                }
                
                if (lineError && eventDefined) {
                    tmpEvent->release();
                } 
                
            
            //else starts an else block-------------------------------------
            //examples:  else do in 500;  else if x==7 do
            } else if (tokens[i].compare("else") == 0) { //an else block
                if (ifBlockInit || whileBlockInit) {
                    pcPtr->printf("Error: expected a 'do' statement\r\n");
                    lineError = true;
                }
                
                //trigger blocks can't have else conditions
                if ((!lineError) && (blockDepth < 2) && (currentTriggerPort > -1)) {
                    pcPtr->printf("Error: else statement can not occur after a trigger block or outside a block\r\n");
                    lineError = true;
                }
                
                //check to make sure we are in an 'if' block
                if ((!lineError) && (tmpEventPtrArray.back()->blockType != 1) && (tmpEventPtrArray.back()->blockType != 3)) { //not currently in an 'if' or 'else if' block
                    pcPtr->printf("Error: else statement can only occur in an 'if' block\r\n");
                    lineError = true;
                }
                if (!lineError) {
                    elseFlag = true;
                
                }
            } else if (tokens[i].compare("then") == 0) { //a then block
                if (ifBlockInit || whileBlockInit) {
                    pcPtr->printf("Error: expected a 'do' statement\r\n");
                    lineError = true;
                }
                
                //trigger blocks can't have else conditions
                if ((!lineError) && (blockDepth < 2) && (currentTriggerPort > -1)) {
                    pcPtr->printf("Error: 'then' statement can only occur after a 'while' block\r\n");
                    lineError = true;
                }
                
                //check to make sure we are in a 'while' block
                if ((!lineError) && (tmpEventPtrArray.back()->blockType != 5)) { //not currently in a while block
                    pcPtr->printf("Error: 'then' statement can only occur in a 'while' block\r\n");
                    lineError = true;
                }
                if (!lineError) {
                    thenFlag = true;
                
                }            
            //while starts a while block----------------------------------------
            //example:  while x<10 do every 100
            //              ...
            //          end
            } else if (tokens[i].compare("while") == 0) { //a new while block
                if (ifBlockInit || whileBlockInit) {
                    pcPtr->printf("Error: expected a 'do' statement\r\n");
                    lineError = true;
                }
                
                if ((currentTriggerPort > 0) || (currentFunction > 0)) { //check to make sure we are inside a trigger block
                       //pcPtr->printf("Start new block\r\n"); 
                                
                } else {
                      pcPtr->printf("Error: a statement block must be placed inside a callback or function.\r\n"); 
                      lineError = true;
                }
                //whileBlockInit = true;
                currentDelay = 0;
                
                tmpEvent = findFirstUnUsed(eventBlock, NUMEVENTS);
                if (tmpEvent != NULL) {                    
                    tmpEvent->isUsed = true;
                    tmpEvent->setTimeLag(currentDelay); 
                } else {
                    pcPtr->printf("Error: no memory slots available.\r\n"); 
                    lineError = true;
                }
                
                //tmpEvent = new event(queuePtr);
                
                                         
                if (!lineError) {
                    //combine the condition tokens without whitespaces
                    tmpString = "";
                    for (unsigned j = i+1; j < sz; j++) { 
                        if (tokens[j].compare("do") != 0) {
                           i++;
                           tmpString.append(tokens[j]);
                        } else {                     
                            break;
                        }
                    }
                    //adds the conditions to the current event
                    if (!evaluateConditions(tmpString, tmpEvent)) lineError = true; 
                }
                
                if (!lineError) {
                    if ((i+3) < sz) {
                        if ((tokens[i+1].compare("do") == 0) && (tokens[i+2].compare("every") == 0)) {
                            
                            if (isNumber(tokens[i+3])) {
                                uint32_t period = atoi(tokens[i+3].data());
                                if (period > 0) {
                                    //pcPtr->printf("While block\r\n");
                            
                                    //tmpEvent->whileLoopPeriod = period;
                                    tmpEvent->setWhileLoopPeriod(period);
                                    if (!elseFlag) {
                                        tmpEvent->blockType = 5; //this is a while block
                                     
                                        action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS);
                                        if (tmpAction == NULL) {
                                            pcPtr->printf("Error: no memory slots available.\r\n");
                                            lineError = true;      
                                        } else {
                                            tmpAction->set(tmpEvent);
                                        }
                                        //tmpEventPtrArray.back()->addAction(new action(tmpEvent));
                                        tmpEventPtrArray.back()->addAction(tmpAction);
                                    
                                        tmpEventPtrArray.push_back(tmpEvent);
                                        blockDepth = blockDepth+1;
                                    } else {
                                        tmpEvent->blockType = 6; //this is an else while block
                                        tmpEventPtrArray.back()->setNextElseEvent(tmpEvent);
                                        tmpEventPtrArray.push_back(tmpEvent);
                                    }
                                    wholeLineEvaluated = true;
                                } else {
                                    pcPtr->printf("Error: loop period must be a positive integer.\r\n");
                                    lineError = true;
                                }
                            } else if (findIntVariable(tokens[i+3])!=NULL) {
                                
                                int* period = findIntVariable(tokens[i+3]);  
                                //tmpEvent->whileLoopPeriodVar = period;
                                tmpEvent->setWhileLoopPeriod(period);
                                if (!elseFlag) {
                                    tmpEvent->blockType = 5; //this is a while block
                                     
                                    action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS);
                                    if (tmpAction == NULL) {
                                        pcPtr->printf("Error: no memory slots available.\r\n");
                                        lineError = true;      
                                    } else {
                                        tmpAction->set(tmpEvent);
                                    }
                                    //tmpEventPtrArray.back()->addAction(new action(tmpEvent));
                                    tmpEventPtrArray.back()->addAction(tmpAction);
                                    
                                    tmpEventPtrArray.push_back(tmpEvent);
                                    blockDepth = blockDepth+1;
                                } else {
                                    tmpEvent->blockType = 6; //this is an else while block
                                    tmpEventPtrArray.back()->setNextElseEvent(tmpEvent);
                                    tmpEventPtrArray.push_back(tmpEvent);
                                }
                                wholeLineEvaluated = true; 
                            }
                        } else {
                            pcPtr->printf("Error: expected a 'do every' statement\r\n");
                            lineError = true;
                        }
                    } else {
                        pcPtr->printf("Error: expected a 'do every' statement\r\n");
                        lineError = true;
                    }
                }
            
            //if the line contains an '=' sign,the equality is evaulated-------------------------
            //examples:  a = 1;  a = b + 5; a = random(100); portout[2] = 1; portout[2] = flip           
            } else if ((tmpLine.find_first_of("=") != std::string::npos) ) { //an expression
                if (ifBlockInit || whileBlockInit || elseFlag) {
                    pcPtr->printf("Error: expected a 'do' statement\r\n");
                    lineError = true;
                }
                                  
                wholeLineEvaluated = true;                
                tmpString = "";
                int spacesBeforeEqualSign = 0;
                bool countSpaces = true;
                //combine the tokens without whitespaces
                for (unsigned j = i; j < sz; j++) { 
                    tmpString.append(tokens[j]);
                    if (tokens[j].find_first_of("=") != std::string::npos) {
                        if (tokens[j].find_first_of("=") > 0) spacesBeforeEqualSign++;
                        countSpaces = false;
                    } else if (countSpaces) {
                        spacesBeforeEqualSign++;
                    }   
                }
                if (!lineError && spacesBeforeEqualSign > 1) {
                    pcPtr->printf("Error: Variable can't have a space in it.\r\n");
                    lineError = true;
                }
               
                if (!lineError) {
                    if (blockDepth > 0) {
                        action* tmpAction = evaluateAssignmentForAction(tmpString);
                        if (tmpAction != NULL) {
                            tmpEventPtrArray.back()->addAction(tmpAction);
                            //pcPtr->printf("Added action with delay: %d\r\n", tmpEventPtrArray.back()->timeLag);
                            
                        } else {
                            lineError = true;
                        }
                                         
                    } else { //assignment was written outside of any block structure, so execute now
                        
                        
                        action* tmpAction = evaluateAssignmentForAction(tmpString);
                        
                        if (tmpAction != NULL) {                           
                            tmpAction->execute();
                            
                            //delete tmpAction;   
                            tmpAction->release();                    
                        } else {                         
                            lineError = true;
                        }                                        
                    }
                }
            } else {
                //if there was no match to any of the above, an error is given
                pcPtr->printf("Error: statement not understood.\r\n");
                lineError = true;
            }
            
            if (lineError) break; //stop parsing the rest of the line if an error was detected   
            
            if (wholeLineEvaluated) { //some of the tokens forces the whole line to be avaluated at once
                    i = sz; //skip ahead to end of the line
            }
            
        } 
        
        //if there was an error, we quit compiling the code
        if (lineError) {
            pcPtr->printf("Line text: ");
            while (!tokens.empty()) {
                pcPtr->printf("%s ",tokens.front().data());
                tokens.erase(tokens.begin());
            }
            pcPtr->printf("\r\n"); 
            while (!currentBlock.empty()) {
                currentBlock.pop_back();
            }
            delete tmpEvent;
        } else {
            
            while (!tokens.empty()) {
                tokens.pop_back();
            }
            currentBlock.pop_back();
        }

    }
    
    //make sure that all blocks have a matching end statement
    if ((!lineError)&&(blockDepth > 0)) {
        pcPtr->printf("Error: Missing 1 or more end statements\r\n");
        lineError = true;
    }    
    //pcPtr->printf("~~~\r\n"); //signals that the code was compiled
    textDisplay.send("~~~\r\n");
    //displayMemoryLeft();
    //DisplayRAMBanks();
        
}


//used to return a pointer to a variable, if it exists
int* scriptStream::findIntVariable(string nameInput) {
    
    int* outPtr = NULL; 
    bool foundIt = false;
    
    if (nameInput.find("portout") != std::string::npos) { 
        int pos1 = nameInput.find("portout[")+8;
        int pos2 = nameInput.find_first_of("]",pos1);
        int portnum = atoi(nameInput.substr(pos1,pos2-pos1).data());
        int portVal = 0;
        if ((portnum > 0) && (portnum <= numPorts)) {
            outPtr = &portVector[portnum]->outState;
            foundIt = true;
        }
    } else if (nameInput.find("portin") != std::string::npos) { 
        int pos1 = nameInput.find("portin[")+7;
        int pos2 = nameInput.find_first_of("]",pos1);
        int portnum = atoi(nameInput.substr(pos1,pos2-pos1).data());
        int portVal = 0;
        if ((portnum > 0) && (portnum <= numPorts)) {
            outPtr = &portVector[portnum]->inState;
            foundIt = true;
        }
    }
    
    if (!foundIt) {
        std::vector<intVariable*>::size_type sz = globalVariables.size();
        for (unsigned i = 0; i < sz; i++) {
            if (nameInput.compare(globalVariables[i]->tag) == 0) {
                outPtr = &globalVariables[i]->value;
                break;
            }
        }
    }
      
    return outPtr;
}

bool scriptStream::createIntVariable(string nameInput) {
    if (findIntVariable(nameInput) == NULL) {
        globalVariables.push_back(new intVariable(nameInput, 0));
        return true;
    } else {
        return false;
    }
}


action* scriptStream::evaluateAssignmentForAction(string expression) {
    
    //action* tmpAction = new action(); //create a new action
    action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS);
    if (tmpAction == NULL) {
        pcPtr->printf("Error: no action memory slots available.\r\n");
        return NULL;
    }
    std::size_t stringInd;
    std::size_t stringInd2;
    string afterEqual;
    string beforeEqual;
    //The expression might have up to three variables
    int* tmpVar;
    int* tmpVar2;
    int* tmpVar3;
    stringInd = expression.find_first_of("="); //location of = sign, if it exists
    beforeEqual = expression.substr(0,stringInd); // the string after the = sign
    afterEqual = expression.substr(stringInd+1,std::string::npos); // the string after the = sign
    stringInd2 = afterEqual.find_first_of("+-"); //location of +/- sign (only one allowed)
    tmpVar = findIntVariable(expression.substr(0,stringInd)); //returns pointer to the variable
    
    if (beforeEqual.find("portout[") != std::string::npos) { //set the output of a digital port 
        int pos1 = beforeEqual.find("portout[")+8;
        int pos2 = beforeEqual.find_first_of("]",pos1);
        int portnum = atoi(beforeEqual.substr(pos1,pos2-pos1).data());
        int* tmpVar = findIntVariable(beforeEqual.substr(pos1,pos2-pos1)); //returns pointer to the variable, if given
        int portVal = 0;
        if ((tmpVar != NULL)||((portnum > 0) && (portnum <= numPorts))) {
           if (isNumber(afterEqual)) { //a simple numeric assign
                portVal = atoi(afterEqual.data());
                if ((portVal == 0) || (portVal == 1)) {
                    //portMessage* tmpMessage = new portMessage(portVector[portnum],1,portVal);
                    portMessage* tmpMessage = findFirstUnUsed(portMessageBlock, NUMPORTMESSAGES);
                    if (tmpMessage == NULL) {
                        pcPtr->printf("Error: no memory slots available.\r\n");
                        tmpAction->release();
                        return NULL;
                    } else {
                        //tmpMessage->setMessage(portVector[portnum],1,portVal);
                        if (tmpVar == NULL) { //a constant port number was given
                            tmpMessage->setMessage(NULL,portnum,portVal);
                        } else {
                            tmpMessage->setMessage(tmpVar,0,portVal);
                        }
                    }
                        
                    
                    tmpAction->set(tmpMessage);
                    //pcPtr->printf("Action: digital port %d set to %d\r\n",portnum,portVal);
                } else {
                    pcPtr->printf("Error: portouts can only be directly assigned a 1, 0 or 'flip'\r\n");
                    //delete tmpAction;
                    tmpAction->release();
                    return NULL;
                }
           } else if (afterEqual.compare("flip") == 0) {
                //portMessage* tmpMessage = new portMessage(portVector[portnum],1,-1);
                portMessage* tmpMessage = findFirstUnUsed(portMessageBlock, NUMPORTMESSAGES);
                if (tmpMessage == NULL) {
                    pcPtr->printf("Error: no memory slots available.\r\n");
                    tmpAction->release();
                    return NULL;
                } else {
                    //tmpMessage->setMessage(portVector[portnum],1,-1);
                    if (tmpVar == NULL) { //a constant port number was given
                        tmpMessage->setMessage(NULL,portnum,-1);
                    } else {
                        tmpMessage->setMessage(tmpVar,0,-1);
                    }               
                }
                tmpAction->set(tmpMessage);
           } else {
                pcPtr->printf("Error: portouts can only be directly assigned a 1, 0, or 'flip'\r\n");
                //delete tmpAction;
                tmpAction->release();
                return NULL;
           }
        } else {
           pcPtr->printf("Port number not found (must be between 1 and %d, or an existing variable)\r\n", numPorts);
           //delete tmpAction;
           tmpAction->release();
           return NULL;
        }
    } else if (beforeEqual.find("portin") != std::string::npos) {
        pcPtr->printf("Error: portins can not be set\r\n");
        //delete tmpAction;
        tmpAction->release();
        return NULL;
    } else if (tmpVar != NULL) {
        intOperation* tmpOp;
        intOperation* tmpOp2;
        if (isNumber(afterEqual)) { //a simple numeric assign
            //tmpOp = new intOperation(tmpVar, "=", atoi(afterEqual.data()));
            tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
            if (tmpOp == NULL) {
                pcPtr->printf("Error: no memory slots available.\r\n");
                tmpAction->release();
                return NULL;
            } else {
                tmpOp->set(tmpVar, "=", atoi(afterEqual.data()));
            }
            tmpAction->set(tmpOp);
            //pcPtr->printf("Action: set variable to constant numeric value\r\n");
        } else if ((stringInd2 == std::string::npos)&&(afterEqual.find("random") != std::string::npos)) {
             
             int highVal = getRandomParam(afterEqual);
            
             if (highVal > 0) {
                //tmpOp = new intOperation(highVal, "=", tmpVar); //for random assignment, we reverse the input order (because of overloading uniqueness)
                tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                if (tmpOp == NULL) {
                    pcPtr->printf("Error: no memory slots available.\r\n");
                    tmpAction->release();
                    return NULL;
                } else {
                    tmpOp->set(highVal, "=", tmpVar); //for random assignment, we reverse the input order (because of overloading uniqueness)
                }
                tmpAction->set(tmpOp);
                //pcPtr->printf("Action: set variable to random value up to %d\r\n", highVal);
             } else {
                //delete tmpAction;
                tmpAction->release();
                return NULL;
             }
             
        } else if (stringInd2 != std::string::npos) { //a +/- operation is there 
           string multiplier("+");
           int multiplierInt = 1;
           if (afterEqual[stringInd2] == '-') {
                multiplier = "-";
                multiplierInt = -1;
           }
           tmpVar2 = findIntVariable(afterEqual.substr(0,stringInd2)); //before the +/- sign
           tmpVar3 = findIntVariable(afterEqual.substr(stringInd2+1,std::string::npos)); //after the +/- sign
           
           if ((tmpVar2 != NULL) && isNumber(afterEqual.substr(stringInd2+1,std::string::npos))) { //variable +/- number
                if (tmpVar2 == tmpVar) {
                    multiplier.append("="); //final sign is += or -=
                    //tmpOp = new intOperation(tmpVar, multiplier.data(), atoi(afterEqual.substr(stringInd2+1,std::string::npos).data()));
                    tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                    if (tmpOp == NULL) {
                        pcPtr->printf("Error: no memory slots available.\r\n");
                        tmpAction->release();
                        return NULL;
                    } else {
                        tmpOp->set(tmpVar, multiplier.data(), atoi(afterEqual.substr(stringInd2+1,std::string::npos).data()));
                    }
                    tmpAction->set(tmpOp);
                    pcPtr->printf("Action: change variable by constant amount\r\n");
                } else {
                    
                    tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                    if (tmpOp2 == NULL) {
                        pcPtr->printf("Error: no memory slots available.\r\n");
                        tmpAction->release();
                        return NULL;
                    } else {
                                              
                        tmpOp2->set(tmpVar2,multiplier.data(), atoi(afterEqual.substr(stringInd2+1,std::string::npos).data()));
                        //tmpOp->set(tmpVar, tmpOp2);
                    }
                    
                    tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                    if (tmpOp == NULL) {
                        pcPtr->printf("Error: no memory slots available.\r\n");
                        tmpOp2->release();
                        tmpAction->release();
                        return NULL;
                    } else {
                        tmpOp->set(tmpVar, tmpOp2);
                    }  
                    
                    tmpAction->set(tmpOp);
                    //pcPtr->printf("Action: variable equals expression\r\n");
                }
                
           } else if ((tmpVar3 != NULL) && isNumber(afterEqual.substr(0,stringInd2))) { //number +/- variable
                if (tmpVar3 == tmpVar) {
                    multiplier.append("="); //makes "+=" or "-="
                    //tmpOp = new intOperation(tmpVar, multiplier.data(), atoi(afterEqual.substr(0,stringInd2).data()));
                    tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                    if (tmpOp == NULL) {
                        pcPtr->printf("Error: no memory slots available.\r\n");
                        tmpAction->release();
                        return NULL;
                    } else {
                        tmpOp->set(tmpVar, multiplier.data(), atoi(afterEqual.substr(0,stringInd2).data()));
                    }
                    tmpAction->set(tmpOp);
                    //pcPtr->printf("Action: change variable by constant amount\r\n");
                } else {
                                      
                    tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                    if (tmpOp2 == NULL) {
                        pcPtr->printf("Error: no memory slots available.\r\n");
                        tmpAction->release();
                        return NULL;
                    } else {
                        tmpOp2->set(tmpVar3, multiplier.data(), atoi(afterEqual.substr(0, stringInd2).data()));                       
                    }
                    tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                    
                    if (tmpOp == NULL) {
                        pcPtr->printf("Error: no memory slots available.\r\n");
                        tmpOp2->release();
                        tmpAction->release();
                        return NULL;
                    } else {                        
                        tmpOp->set(tmpVar, tmpOp2);
                    }
                    tmpAction->set(tmpOp);
                    //pcPtr->printf("Action: variable equals expression\r\n");
                }
                
           } else if ((tmpVar2 != NULL) && (tmpVar3 != NULL)) { //variable +/- variable
                              
                tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                if (tmpOp2 == NULL) {
                    pcPtr->printf("Error: no memory slots available.\r\n");
                    tmpAction->release();
                    return NULL;
                } else {
                    tmpOp2->set(tmpVar2, multiplier.data(), tmpVar3);                   
                }
                tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                
                if (tmpOp == NULL) {
                    pcPtr->printf("Error: no memory slots available.\r\n");
                    tmpOp2->release();
                    tmpAction->release();
                    return NULL;
                } else {
                    
                    tmpOp->set(tmpVar, tmpOp2);
                }
                tmpAction->set(tmpOp);
                //pcPtr->printf("Action: set variable to operation involving two variables\r\n");
                //tmpVar->value = tmpVar2->value + (multiplier * tmpVar3->value);
           } else if ( isNumber(afterEqual.substr(stringInd2+1,std::string::npos)) && isNumber(afterEqual.substr(0,stringInd2)) ) { //number +/- number
                //tmpOp = new intOperation(tmpVar, "=", atoi(afterEqual.substr(0,stringInd2).data()) + (multiplierInt * atoi(afterEqual.substr(stringInd2+1,std::string::npos).data())));
                tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                if (tmpOp == NULL) {
                    pcPtr->printf("Error: no memory slots available.\r\n");
                    tmpAction->release();
                    return NULL;
                } else {
                    tmpOp->set(tmpVar, "=", atoi(afterEqual.substr(0,stringInd2).data()) + (multiplierInt * atoi(afterEqual.substr(stringInd2+1,std::string::npos).data())));
                }
                tmpAction->set(tmpOp);
                //pcPtr->printf("Action: set variable to constant numeric value\r\n");
       
           } else if ((afterEqual.substr(0,stringInd2).find("random") != std::string::npos) && isNumber(afterEqual.substr(stringInd2+1,std::string::npos))) { //random +/- number
                int highVal = getRandomParam(afterEqual.substr(0,stringInd2));
            
                if (highVal > 0) {
                    
                    
                    tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                    if (tmpOp2 == NULL) {
                        pcPtr->printf("Error: no memory slots available.\r\n");
                        tmpAction->release();
                        return NULL;
                    } else {
                        tmpOp2->set(highVal, multiplier.data(), atoi(afterEqual.substr(stringInd2+1,std::string::npos).data()));                       
                    }
                    tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                    
                    if (tmpOp == NULL) {
                        pcPtr->printf("Error: no memory slots available.\r\n");
                        tmpOp2->release();
                        tmpAction->release();
                        return NULL;
                    } else {
                        tmpOp->set(tmpVar, tmpOp2);
                    }
                    tmpAction->set(tmpOp);
                    //pcPtr->printf("Action: set variable to random value plus number %d\r\n", highVal);
                } else {
                    //delete tmpAction;
                    tmpAction->release();
                    return NULL;
                }
           } else if ((afterEqual.substr(0,stringInd2).find("random") != std::string::npos) && (tmpVar3 != NULL)) { //random +/- variable
                int highVal = getRandomParam(afterEqual.substr(0,stringInd2));
            
                if (highVal > 0) {
                    
                    
                    tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                    if (tmpOp2 == NULL) {
                        pcPtr->printf("Error: no memory slots available.\r\n");
                        tmpAction->release();
                        return NULL;
                    } else {
                        tmpOp2->set(highVal, multiplier.data(), tmpVar3);                     
                    }
                    tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);                   
                    if (tmpOp == NULL) {
                        pcPtr->printf("Error: no memory slots available.\r\n");
                        tmpOp2->release();
                        tmpAction->release();
                        return NULL;
                    } else {                       
                        tmpOp->set(tmpVar, tmpOp2);
                    }
                    tmpAction->set(tmpOp);
                    //pcPtr->printf("Action: set variable to random value plus number %d\r\n", highVal);
                } else {
                    //delete tmpAction;
                    tmpAction->release();
                    return NULL;
                }
           
           
           } else if ((afterEqual.substr(stringInd2+1,std::string::npos).find("random") != std::string::npos) && isNumber(afterEqual.substr(0,stringInd2))) { //random +/- number
                int highVal = getRandomParam(afterEqual.substr(stringInd2+1,std::string::npos));
            
                if (highVal > 0) {
                   
                    
                    tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                    if (tmpOp2 == NULL) {
                        pcPtr->printf("Error: no memory slots available.\r\n");
                        tmpAction->release();
                        return NULL;
                    } else {
                        tmpOp2->set(highVal, multiplier.data(), atoi(afterEqual.substr(0, stringInd2).data()));                        
                    }
                    tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);                   
                    if (tmpOp == NULL) {
                        pcPtr->printf("Error: no memory slots available.\r\n");
                        tmpOp2->release();
                        tmpAction->release();
                        return NULL;
                    } else {                      
                        tmpOp->set(tmpVar, tmpOp2);
                    }
                    tmpAction->set(tmpOp);
                    //pcPtr->printf("Action: set variable to random value plus number %d\r\n", highVal);
                } else {
                    //delete tmpAction;
                    tmpAction->release();
                    return NULL;
                }
           } else if ((afterEqual.substr(stringInd2+1,std::string::npos).find("random") != std::string::npos) && (tmpVar2 != NULL)) { //random +/- number
                int highVal = getRandomParam(afterEqual.substr(stringInd2+1,std::string::npos));
            
                if (highVal > 0) {
                   
                   
                    tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                    if (tmpOp2 == NULL) {
                        pcPtr->printf("Error: no memory slots available.\r\n");
                        tmpAction->release();
                        return NULL;
                    } else {
                        tmpOp2->set(highVal, multiplier.data(), tmpVar2);                       
                    }
                    tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);                  
                    if (tmpOp == NULL) {
                        pcPtr->printf("Error: no memory slots available.\r\n");
                        tmpOp2->release();
                        tmpAction->release();
                        return NULL;
                    } else {                       
                        tmpOp->set(tmpVar, tmpOp2);
                    }
                    tmpAction->set(tmpOp);
                    //pcPtr->printf("Action: set variable to random value plus number %d\r\n", highVal);
                } else {
                    //delete tmpAction;
                    tmpAction->release();
                    return NULL;
                }
           } else {
                pcPtr->printf("Expression not understood: %s\r\n",afterEqual.data());
                //delete tmpAction;
                tmpAction->release();
                return NULL;
           }
              
        } else if (findIntVariable(afterEqual) != NULL) { //assign value of another variable
           //tmpOp = new intOperation(tmpVar, "=", findIntVariable(afterEqual));
           tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
           if (tmpOp == NULL) {
               pcPtr->printf("Error: no memory slots available.\r\n");
               tmpAction->release();
               return NULL;
           } else {
               tmpOp->set(tmpVar, "=", findIntVariable(afterEqual));
           }
           tmpAction->set(tmpOp);       
           //pcPtr->printf("Action: set variable to value of another\r\n");
        } else {
           pcPtr->printf("Variable not found: %s\r\n",afterEqual.data());
           //delete tmpAction;
           tmpAction->release();
           return NULL;
        }
        
    } else {
        pcPtr->printf("Variable not found\r\n");
        //delete tmpAction;
        tmpAction->release();
        return NULL;
    }
    return tmpAction;
}

bool scriptStream::isOutsideParenth(string expression,std::size_t foundItem) {
       
    int pDepth = 0;  // How many nested parentheses 
    //pcPtr->printf("Check outside parentheses...");
    if (foundItem < expression.length()) {
        for (int i = 0; i <= foundItem; i++) { 
            if (expression[i] == '(') {             
                pDepth++;
            } else if (expression[i] == ')') {              
                pDepth--;
            }
        }
        if (pDepth<=0) {
            //pcPtr->printf("yes.");
            return true;
        } else {
            //pcPtr->printf("no.");
            return false;
        }
    } else {
        return true;
    }
    
}

std::size_t scriptStream::findFirstOrOutsideParenth(string expression) {
    
    std::size_t foundItem = expression.find("||");    
    while (foundItem != std::string::npos) {   
        if (isOutsideParenth(expression,foundItem)) {
            break;
        }          
        foundItem = expression.find("||",foundItem+1);
    }   
    return foundItem; 
}

std::size_t scriptStream::findFirstAndOutsideParenth(string expression) {
    
    std::size_t foundItem = expression.find("&&");    
    while (foundItem != std::string::npos) {   
        if (isOutsideParenth(expression,foundItem)){
            break;
        }          
        foundItem = expression.find("&&",foundItem+1);
    }   
    return foundItem; 
}
    
condition* scriptStream::parseConditions(string expression) {
    //This function is used to parse a condition string
    //such as (x < y && x != z) || (y == 2)
    //This function first identifies the root node of the logic tree
    //based on operator precedence ( () > && > || ), and then recursively calls itself
    //to find the nodes of the branches. The basic building blocks of 
    //the final condition object are arithmatic comparitors (a > b) and
    //other condition objects.
    
    
    //pcPtr->printf("Parsing condition: %s\r\n", expression.data());
    condition* newCondition = NULL;
    bool singleCondition = false; //no compound conditions
    string afterComparator;
    string beforeComparator;
       
    std::size_t found;
       
    //To make a parse tree, we start by looking for operators with the lowest precendence
    //so we look for OR conditions first
    char currentOperator = OR_CONDITION; 
    //pcPtr->printf("Looking for OR condition...");
    found = findFirstOrOutsideParenth(expression);
    if (found==std::string::npos) { //no or conditions outside parentheses found, so we look for AND conditions
        currentOperator = AND_CONDITION; 
        //pcPtr->printf("Looking for AND condition...");
        found = findFirstAndOutsideParenth(expression);
    }
    if (found==std::string::npos) { //no or/and conditions outside parentheses found
        //if the expression is encapsulated in parentheses, remove the parentheses
        bool removedParenth = false;
        if ((expression[0] == '(') && (expression[expression.length()-1] == ')')) {
            //pcPtr->printf("Remove parentheses");
            expression = expression.substr(1,expression.length()-2);
            removedParenth = true;
        }
        if (removedParenth) { //we removed parentheses, so try again
            return parseConditions(expression);
        } else {
            singleCondition = true; //we assume that the condition is non-compound, i.e., a>b 
        }
    }
    
    if (singleCondition) { //no compound conditions found
        //pcPtr->printf("Single condition");
        std::size_t equalStringInd;
        std::size_t greaterOrEqualStringInd;
        std::size_t lessThanOrEqualStringInd;
        std::size_t notEqualStringInd;
        std::size_t greaterThanStringInd;
        std::size_t lessThanStringInd;
        std::size_t generalCompareStringInd;
    
   
        string tmpCondition = expression;
        string compareString;
        //The expression might have up to three variables 
        int* tmpVar;
        int* tmpVar2;
        int* tmpVar3;
        
        int offset = 0;
        equalStringInd = tmpCondition.find("=="); //location of comparator
        greaterOrEqualStringInd = tmpCondition.find(">="); //location of comparator
        lessThanOrEqualStringInd = tmpCondition.find("<="); //location of comparator
        notEqualStringInd = tmpCondition.find("!="); //location of comparator
        greaterThanStringInd = tmpCondition.find_first_of(">"); //location of comparator
        lessThanStringInd = tmpCondition.find_first_of("<"); //location of comparator
        
        if ((equalStringInd != std::string::npos) && (greaterOrEqualStringInd == std::string::npos) &&
           (lessThanOrEqualStringInd == std::string::npos) && (notEqualStringInd == std::string::npos)){
           
           generalCompareStringInd = equalStringInd;
           compareString = "==";
        } else if ((equalStringInd == std::string::npos) && (greaterOrEqualStringInd != std::string::npos) &&
           (lessThanOrEqualStringInd == std::string::npos) && (notEqualStringInd == std::string::npos)){
          
          generalCompareStringInd = greaterOrEqualStringInd;
          compareString = ">=";
        } else if ((equalStringInd == std::string::npos) && (greaterOrEqualStringInd == std::string::npos) &&
           (lessThanOrEqualStringInd != std::string::npos) && (notEqualStringInd == std::string::npos)){
          
          generalCompareStringInd = lessThanOrEqualStringInd;
          compareString = "<=";
        } else if ((equalStringInd == std::string::npos) && (greaterOrEqualStringInd == std::string::npos) &&
           (lessThanOrEqualStringInd == std::string::npos) && (notEqualStringInd != std::string::npos)){
          
          generalCompareStringInd = notEqualStringInd;
          compareString = "!=";
        } else if ((equalStringInd == std::string::npos) && (greaterOrEqualStringInd == std::string::npos) &&
           (lessThanOrEqualStringInd == std::string::npos) && (notEqualStringInd == std::string::npos) &&
           (greaterThanStringInd != std::string::npos) && (lessThanStringInd == std::string::npos)){
          
          generalCompareStringInd = greaterThanStringInd;
          compareString = ">"; 
          offset = 1;
        } else if ((equalStringInd == std::string::npos) && (greaterOrEqualStringInd == std::string::npos) &&
           (lessThanOrEqualStringInd == std::string::npos) && (notEqualStringInd == std::string::npos) &&
           (greaterThanStringInd == std::string::npos) && (lessThanStringInd != std::string::npos)){
          
          generalCompareStringInd = lessThanStringInd;
          compareString = "<"; 
          offset = 1;
        
        }else {
          pcPtr->printf("Condition not understood: %s\r\n", expression.data());
          return 0;
        }
        
        intCompare* newCompare = findFirstUnUsed(intCompareBlock, NUMINTCOMPARE);                   
        if (newCompare == NULL) {                    
            pcPtr->printf("Error: No memory slots available.");
            return NULL;                                     
        } 
        newCondition = findFirstUnUsed(conditionBlock, NUMCONDITIONS);                   
        if (newCondition == NULL) {                    
            pcPtr->printf("Error: No memory slots available.");
            return NULL;                                     
        }  
        afterComparator = tmpCondition.substr(generalCompareStringInd+2-offset,std::string::npos);
       
        beforeComparator = tmpCondition.substr(0,generalCompareStringInd);
        tmpVar = findIntVariable(beforeComparator); //returns pointer to the variable            
        if (tmpVar != NULL) { //before the comparator is a single variable
            tmpVar2 = findIntVariable(afterComparator); //returns pointer to the variable
            if (tmpVar2 != NULL) { //we are comapring a single variable to another
                //intCompare* newCompare = new intCompare(tmpVar,compareString.data(),tmpVar2);
                //currentEvent->addCondition(new condition(newCompare)); 
                newCompare->set(tmpVar,compareString.data(),tmpVar2);                
                newCondition->set(newCompare);
                
                //pcPtr->printf("Var vs. Var condition added: %s\r\n", tmpCondition.data());
            } else if (isNumber(afterComparator)) {
                //intCompare* newCompare = new intCompare(tmpVar,compareString.data(),atoi(afterComparator.data()));
                //currentEvent->addCondition(new condition(newCompare)); 
                newCompare->set(tmpVar,compareString.data(),atoi(afterComparator.data()));
                newCondition->set(newCompare);
                
                //pcPtr->printf("Var vs. Int condition added: %s\r\n", tmpCondition.data());
            } //more here 
        
        } else {
          pcPtr->printf("Condition not understood: %s\r\n", expression.data());
          
          return NULL;
        }
               
    } else { //this is a compound condition (with either && or ||)
        //pcPtr->printf("Compound condition");
        afterComparator = expression.substr(found+2,std::string::npos);   
        beforeComparator = expression.substr(0,found);
        newCondition = findFirstUnUsed(conditionBlock, NUMCONDITIONS);                   
        if (newCondition == NULL) {                    
            pcPtr->printf("Error: No memory slots available.");
            return NULL;                                     
        } else {
            newCondition->isUsed = true; //reserve the condition slot;
        } 
        //recursively call this function to parse the sub conditions
        condition* cond1 = parseConditions(beforeComparator);
        if (cond1 == NULL) {
            newCondition->release();
            return NULL;
        }
        condition* cond2 = parseConditions(afterComparator);
        if (cond2 == NULL) {
            newCondition->release();
            cond1->release();
            return NULL;
        }
        newCondition->set(cond1,currentOperator, cond2);
        
    }
    
    return newCondition; //all went well, so return the newly made condition
    
}

bool scriptStream::evaluateConditions(string expression, event* currentEvent) {
    //calls the function to parse the condition string.  The condition pointer is then
    //attached to the event
    
    condition* newCondition = NULL;
    newCondition = parseConditions(expression);
    if (newCondition == NULL) {
        return false;
    } else {
        currentEvent->addCondition(newCondition); 
        return true;
    }
}

int scriptStream::getRandomParam(string expression) {

      int pos1 = expression.find("random(")+7;
      int pos2 = expression.find_first_of(")",pos1);
      int highVal = atoi(expression.substr(pos1,pos2-pos1).data());
             
      if ((highVal > 0)) {
         return highVal;
      } else {
         pcPtr->printf("Error: random parameter must be 1 or more\r\n");
         return 0;
      }
 }  
 
 
 outputStream::outputStream(int bufferSizeIn):
       readHead(0),
       writeHead(0),
       totalWriteHead(0),
       totalReadHead(0),
       bufferSize(bufferSizeIn),
       unsentData(false) {
       
       outputBuffer = new char[bufferSize];
 
 }
 
 outputStream::~outputStream() {
    delete[] outputBuffer;
 }
 
 //adds text to the buffer
 void outputStream::send(string outputString) {
    int strLen = outputString.size();
    
    int total = 0;
    int chunk = 0;
    if (!(totalWriteHead+strLen > (totalReadHead + bufferSize))) {
        while (strLen - total > 0) {
            chunk = min((bufferSize - writeHead), strLen - total);
            outputString.copy(outputBuffer + writeHead, chunk, total);
            writeHead = (writeHead + chunk) % bufferSize;
            totalWriteHead += chunk;
            total += chunk;
        }
        if (total > 0) {
            unsentData = true;
        }
    }
 }
 
 //the main loop gets one character per loop and write it to the serial port 
 char outputStream::getNextChar() {
    
    
    if (totalReadHead < totalWriteHead) {
        tmpOut = *(outputBuffer+readHead);
        readHead = (readHead+1) % bufferSize;
        totalReadHead++;
        if (totalReadHead >= totalWriteHead) {
            unsentData = false;
        }
    }
    return tmpOut;
    
 }