Microcontroller firmware that uses a simple, yet powerful scripting language to control the timing of input and output events with high temporal resolution. Written by Mattias Karlsson

Dependencies:   SMARTWAV mbed

behave.cpp

Committer:
mkarlsso
Date:
2017-02-07
Revision:
8:872b843a3053
Parent:
7:5fe7329751d4

File content as of revision 8:872b843a3053:

#include "behave.h"
#include "hardwareInterface.h"
#include <ctype.h>
#include <sstream>
//#include <string.h>
//#include <cstdlib>

using namespace std;

int16_t randomSeedCounter;  //used for seeding random numbers
VersionInfo vInfo; //Contains the version number

//digitalPort* portVector[NUMPORTS+1]; //a list of pointers to the digital ports

//Main event queue
eventQueue mainQueue;

//The script parser
//scriptStream parser(portVector, NUMPORTS, &mainQueue);

//globals defined in hardwareInterface.cpp
extern uint32_t timeKeeper; //the master clock
extern bool resetTimer;
extern bool clockSlave;
extern bool changeToSlave;
extern bool changeToStandAlone;
extern outputStream textDisplay;

//extern int currentDIOstate[2];
bool broadCastStateChanges;
bool textStreaming;



//These items may be placed in hardware-specific parts of memory

#ifdef MBEDHARDWARE
//__attribute((section("AHBSRAM0"),aligned)) outputStream textDisplay(512);
__attribute((section("AHBSRAM0"),aligned)) char buffer[256];
__attribute((section("AHBSRAM1"),aligned)) event eventBlock[NUMEVENTS];
__attribute((section("AHBSRAM1"),aligned)) condition conditionBlock[NUMCONDITIONS];
__attribute((section("AHBSRAM1"),aligned)) intCompare intCompareBlock[NUMINTCOMPARE];
__attribute((section("AHBSRAM0"),aligned)) action actionBlock[NUMACTIONS];
__attribute((section("AHBSRAM0"),aligned)) portMessage portMessageBlock[NUMPORTMESSAGES];
//__attribute((section("AHBSRAM1"),aligned)) intVariable intVariableBlock[10];
__attribute((section("AHBSRAM0"),aligned)) intOperation intOperationBlock[NUMINTOPERATIONS];
__attribute((section("AHBSRAM0"),aligned)) displayAction displayActionBlock[NUMDISPLAYACTIONS];
__attribute((section("AHBSRAM0"),aligned)) triggerFunctionAction triggerFunctionActionBlock[NUMTRIGGERACTIONS];
#endif

#ifdef FPGAHARDWARE

char buffer[256];
event eventBlock[NUMEVENTS];
condition conditionBlock[NUMCONDITIONS];
intCompare intCompareBlock[NUMINTCOMPARE];
action actionBlock[NUMACTIONS];
portMessage portMessageBlock[NUMPORTMESSAGES];
intOperation intOperationBlock[NUMINTOPERATIONS];
displayAction displayActionBlock[NUMDISPLAYACTIONS];
triggerFunctionAction triggerFunctionActionBlock[NUMTRIGGERACTIONS];
#endif


event* functionEventArray[NUMFUNCTIONS];
bool   functionSpotTaken[NUMFUNCTIONS];


//-----------------------------------------------
//This is the main loop of the program
mainLoop::mainLoop(){


}

void mainLoop::init() {
    currentDIOstate[0] = 0;
    currentDIOstate[1] = 0;
    digitalInChanged = false;
    digitalOutChanged = false;
    textStreaming = true;
    eraseBuffer();
    broadCastStateChanges = true;

    //Set the version number (major.middle.minor)
    vInfo.major = 1;
    vInfo.middle = 1;
    vInfo.minor = 0;

    vInfo.updateDay = 7;
    vInfo.updateMonth = 2;
    vInfo.updateYear = 2017;



//section for MBED hardware
#ifdef MBEDHARDWARE
    hardware = new MBEDSystem();
    hardware->timerinit();
    pc = new MBEDSerialPort();
    pc->init();
    textDisplay.setSerial(pc);

#endif

#ifdef FPGAHARDWARE
       pc = new FPGASerialPort();
       pc->init();

       hardware = new FPGASystem();
       hardware->timerinit();

       textDisplay.setSerial(pc);

       DIO_DCR = DIO_DCR_IE;       // enable DIO edge interrupts
#endif

    //Set up the ports.
    int totalPorts = 0;
    for (int i = 0; i < NUMDIGINPORTS; i++) {
        digInPorts[i].init(hardware->getDigitalInPtr(i));
        ports[totalPorts] = &digInPorts[i];
        totalPorts++;
    }
    for (int i = 0; i < NUMDIGOUTPORTS; i++) {
        digOutPorts[i].init(hardware->getDigitalOutPtr(i));
        ports[totalPorts] = &digOutPorts[i];
        totalPorts++;
    }
    for (int i = 0; i < NUMANINPORTS; i++) {
        anInPorts[i].init(hardware->getAnalogInPtr(i));
        ports[totalPorts] = &anInPorts[i];
        totalPorts++;
    }
    for (int i = 0; i < NUMANOUTPORTS; i++) {
        anOutPorts[i].init(hardware->getAnalogOutPtr(i));
        ports[totalPorts] = &anOutPorts[i];
        totalPorts++;
    }


    //int totalPorts = NUMDIGINPORTS+NUMDIGOUTPORTS+NUMANINPORTS+NUMANOUTPORTS;
    parser = new scriptStream(ports, totalPorts, &mainQueue, hardware);

}

void mainLoop::exec() {
    bool digitalInChanged = false;
    bool digitalOutChanged = false;
    bool *ignoreUpdatePorts = hardware->getIgnoreUpdates();
    uint32_t changeTime;
    timeKeeper = 0; //set main clock to 0;

    int bufferPos = 0;

    //ostringstream timeConvert;   // stream used for the conversion
    //ostringstream stateConvert;
    int tmpChar;
    int junkChar;

    uint16_t shortcutTriggers[PENDINGTRIGGERBUFFERSIZE];
    int numTriggersToProcess;

    while (pc->readable()) {
        junkChar = pc->readChar();
    }

#ifdef MBEDHARDWARE
    LocalFileSystem local("local");

    FILE *fp = fopen("/local/STARTUP.TXT", "r");
    if (fp != NULL) {

        textDisplay.send("Executing startup script...\r\n");

        do {
            tmpChar = fgetc(fp);
            if ((tmpChar >= 32) && (tmpChar <= 126)) {
                buffer[bufferPos] = tmpChar;
                bufferPos++;
            }
            if ((tmpChar == 13) || (tmpChar == 10)) { //carrriage return
                parser->addLineToCurrentBlock(buffer);
                bufferPos = 0;
                eraseBuffer();
            }
            //pc.putc(tmpChar);
        } while (tmpChar != EOF);

        buffer[bufferPos] = 59;
        parser->addLineToCurrentBlock(buffer);
        eraseBuffer();
        fclose(fp);
    } else {
        textDisplay.send("No startup script found.\r\n");
    }
#endif


    //Get the initial state of all input pins
    for (int i = 0; i < NUMDIGINPORTS; i++) {

        if (digInPorts[i].read() == 1) {
            currentDIOstate[0] |= (1 << i);
        } else {
            currentDIOstate[0] &= ~(1 << i);
        }
    }


    //main loop
    while(1) {
        //check the main event queue to see if anything needs to be done

        mainQueue.check();

        //check if anything has been written to the serial input
        while (pc->readable()) {

            buffer[bufferPos] = pc->readChar();
            bufferPos++;


            //'Return' key pressed
            if ((buffer[bufferPos-1] == 13) || (buffer[bufferPos-1] == 10)) {

                buffer[bufferPos-1] = '\0';

                parser->addLineToCurrentBlock(buffer);
                bufferPos = 0;
                eraseBuffer();

            } else {

                //Backspace was pressed
                if (((buffer[bufferPos-1] == 127)||(buffer[bufferPos-1] == 8))) {
                    if (bufferPos > 1) {
                        bufferPos = bufferPos-2; //erase the backspace char plus the one before
                    } else {
                        bufferPos = bufferPos-1; //beginning of line, so nothing to erase
                    }
                }
            }
        }

        //Check all the analog ports to see if anything has changed. In the update routine, the port's
        //script callbacks are called if the port crossed threshold.
        for (int i = 0; i < NUMANINPORTS; i++) {
            anInPorts[i].update();
        }
        for (int i = 0; i < NUMANOUTPORTS; i++) {
            anOutPorts[i].update();
        }

        //Check all the digital ports to see if anything has changed. In the update routine, the port's
        //script callbacks are called if the port was triggered
        digitalInChanged = false;
        digitalOutChanged = false;
        changeTime = timeKeeper;

        for (int i = 0; i < NUMDIGINPORTS; i++) {

            if (digInPorts[i].update()) {

                digitalInChanged = true;
                changeTime = max(changeTime,digInPorts[i].lastChangeTime);

                //The input state of all the ports in condensed into one number (each bit contains the info)
                if (digInPorts[i].getLastChangeState() == 1) {
                    currentDIOstate[0] |= (1 << i);
                } else {
                    currentDIOstate[0] &= ~(1 << i);
                }
            }
        }
        for (int i = 0; i < NUMDIGOUTPORTS; i++) {

            if (digOutPorts[i].update()) {

                digitalOutChanged = true;
                changeTime = max(changeTime,digOutPorts[i].lastChangeTime);

                //The input state of all the ports in condensed into one number (each bit contains the info)
                if (digOutPorts[i].getLastChangeState() == 1) {
                    currentDIOstate[1] |= (1 << i);
                } else {
                    currentDIOstate[1] &= ~(1 << i);
                }
            }
        }
        /*
        for (int i = 0; i < NUMPORTS; i++) {

            if (ports[i].update()) {

                if (!ignoreUpdatePorts[i]) {
                    //Only trigger an output update to the serial port if ignore is false
                    digitalInChanged = true;
                }
                changeTime = min(changeTime,ports[i].lastChangeTime);


                //The input state of all the ports in condensed into one number (each bit contains the info)
                if (ports[i].getLastChangeState() == 1) {
                    currentDIOstate[0] |= (1 << i);
                } else {
                    currentDIOstate[0] &= ~(1 << i);
                }
            }
            if (ports[i].outStateChanged) {
                if (!ignoreUpdatePorts[i]) {
                     //Only trigger an output update to the serial port if ignore is false
                    digitalOutChanged = true;
                }
                changeTime = min(changeTime,ports[i].lastOutChangeTime);
                //The out state of all the ports is condensed into one number (each bit contains the info)
                if (ports[i].outState == 1) {
                    currentDIOstate[1] |= (1 << i);
                } else {
                    currentDIOstate[1] &= ~(1 << i);
                }
                ports[i].outStateChanged = false;
            }
        }*/

        //If anything changed in the DIOs, we write the new values to the serial port (this can be turned off
        //with broadCastStateChanges)
        if ( (digitalInChanged||digitalOutChanged) && broadCastStateChanges) {
            textDisplay << changeTime << " " << currentDIOstate[0] << " " << currentDIOstate[1] << "\r\n";
            digitalInChanged = false;
            digitalOutChanged = false;
        }



        //We use a buffer to send text via the serial port.  For every loop
        //in the main loop, we send one character if there is enything to send.
        //This way, outputting text to serial does not hold up other time-sensitive
        //things in the event queue
        if ((textDisplay.unsentData) && (textStreaming)) {
            pc->writeChar(textDisplay.getNextChar());
        }

        //Here is how we toggle between standalone and slave mode for the clock updating.
        if (changeToSlave) {
            hardware->setSlaveClock();
        } else if (changeToStandAlone) {
           hardware->setStandAloneClock();
        }

        //anything extra to do, defined by the hardware
        hardware->mainLoopToDo();

        //check for shortcut triggers
        numTriggersToProcess = hardware->getPendingFunctionTriggers(shortcutTriggers);
        for (int i = 0; i < numTriggersToProcess; i++) {
            textDisplay << "Trigger function " << shortcutTriggers[i]+1 << " taken: " << (uint16_t)functionSpotTaken[shortcutTriggers[i]] << " isused: " << (uint16_t)functionEventArray[shortcutTriggers[i]]->isUsed<< "\r\n";

            if ((shortcutTriggers[i] < NUMTRIGGERACTIONS) && functionSpotTaken[shortcutTriggers[i]] && functionEventArray[shortcutTriggers[i]]->isUsed) {
                textDisplay << "Executing trigger function.\r\n";
                //textDisplay << "Executing function array index " << shortcutTriggers[i] << "\r\n";
                functionEventArray[shortcutTriggers[i]]->execute();
            }
        }

    }

}

void mainLoop::eraseBuffer() {
    for (int i = 0; i < 256; i++) {
        buffer[i] = NULL;
    }
}

//-------------------------------------------------

//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) {
    textDisplay << "Available slots left in memory\r\n";
    textDisplay << "  Blocks: " << countUnUsed(eventBlock, NUMEVENTS) << "\r\n";
    textDisplay << "  Condition containers: " << countUnUsed(conditionBlock, NUMCONDITIONS) << "\r\n";
    textDisplay << "  Int compare conditions: " << countUnUsed(intCompareBlock, NUMINTCOMPARE) << "\r\n";
    textDisplay << "  Command containers: " << countUnUsed(actionBlock, NUMACTIONS) << "\r\n";
    textDisplay << "  Port commands: "<< countUnUsed(portMessageBlock, NUMPORTMESSAGES) << "\r\n";
    textDisplay << "  Integer operater commands: " << countUnUsed(intOperationBlock, NUMINTOPERATIONS) << "\r\n";
    textDisplay << "  Text display commands: " << countUnUsed(displayActionBlock, NUMDISPLAYACTIONS) << "\r\n";
}

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);
    }
}
//-----------------------------------------
AbstractPort::AbstractPort():
    triggerUpEventPtr(NULL),
    triggerDownEventPtr(NULL),
    state(0),
    portDir(none),
    thresh(0),
    lastChangeTime(0),
    hasTriggerFunction(false),
    reportUpdates(false) {

}



void AbstractPort::write(int outVal) {
    //Default do nothing
}

void AbstractPort::setThresh(int threshVal) {
    thresh = threshVal;
}


void AbstractPort::setTriggerUpEvent(event *eventInput) {

    if (triggerUpEventPtr != NULL) {
        triggerUpEventPtr->release();
    }
    triggerUpEventPtr = eventInput;
    hasTriggerFunction = true;
}

void AbstractPort::setTriggerDownEvent(event *eventInput) {

    if (triggerDownEventPtr != NULL) {
        triggerDownEventPtr->release();
    }
    triggerDownEventPtr = eventInput;
    hasTriggerFunction = true;
}

void AbstractPort::clearTriggerEvents() {

    if (triggerUpEventPtr != NULL) {
        triggerUpEventPtr->release();
        triggerUpEventPtr = NULL;
    }
    if (triggerDownEventPtr != NULL) {
        triggerDownEventPtr->release();
        triggerDownEventPtr = NULL;
    }
    hasTriggerFunction = false;
}

void AbstractPort::setReportUpdates(bool report) {
    reportUpdates = report;
}

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

bool AbstractPort::checkForChange() {
    //Default behavior checks if the signal has crossed threshold using sofware
    //detect change in the software main loop
    //we read the pin state to see if it is different than the
    //remembered state.  This is important in order to report both edges of a
    //fast up-down event.

    state = read();
    bool changed = ((lastInState < thresh && state >= thresh) || (lastInState >= thresh && state < thresh));

    if (changed) {
        if (state >= thresh) {

            lastChangeInterval = timeKeeper - lastChangeTime;
            lastChangeTime = timeKeeper;

            if (triggerUpEventPtr != NULL && triggerUpEventPtr->isUsed) {triggerUpEventPtr->execute();}
        } else if (state < thresh) {

            lastChangeInterval = timeKeeper - lastChangeTime;
            lastChangeTime = timeKeeper;


            if (triggerDownEventPtr != NULL && triggerDownEventPtr->isUsed){triggerDownEventPtr->execute();}
        }

        lastInState = state;

    }
}

bool AbstractPort::update() {


    bool changed = false;

    if ((reportUpdates || hasTriggerFunction)&&(timeKeeper - lastChangeTime) > 1) { //prevents flutter triggers when button is pressed
        changed = checkForChange();
    } else if (portDir == in) {
        state = read();
    }

    return changed;
}



//-----------------------------------------
AnalogPort::AnalogPort():
    outPin(NULL),
    inPin(NULL) {

    portType = analog;
    
}

void AnalogPort::init(sAnalogIn *IP) {

    portDir = in;
    inPin = IP;
    
}

void AnalogPort::init(sAnalogOut *OP){
    portDir = out;
    outPin = OP;
}

void AnalogPort::write(int outVal) {
    if (portDir == out) {
        outPin->write(outVal);
        if (state != outVal) {
            outStateChanged = true;
            lastOutChangeTime = timeKeeper;
        }
        //state = outVal;
        state = outPin->read();
    }
}

int AnalogPort::read() {
    if (portDir == out) {
        return outPin->read();
    } else if (portDir == in) {
        return inPin->read();
    }
}

void AnalogPort::setThresh(int threshVal) {
    thresh = threshVal;
    //TODO: set thresh for hardware object too
}


//-----------------------------------------
DigitalPort::DigitalPort():
    outPin(NULL),
    inPin(NULL) {

    portType = digital;
    thresh = 1;

}

void DigitalPort::init(sDigitalIn *IP) {

    portDir = in;
    inPin = IP;

}

void DigitalPort::init(sDigitalOut *OP){
    portDir = out;
    outPin = OP;
}

void DigitalPort::write(int outVal) {

    if (portDir == out) {

        if (outVal == -1) {
            //'flip' command means to flip to the other state
            outVal = 1-state;
        }
        outPin->write(outVal);
        if (state != outVal) {
            outStateChanged = true;
            lastOutChangeTime = timeKeeper;
        }
        state = outVal;
    }
}

int DigitalPort::read() {
    if (portDir == out) {
        return outPin->read();
    } else if (portDir == in) {
        return inPin->read();
    }
}

bool DigitalPort::checkForChange() {

    //Use hardware to detect state change times
    bool changed = false;

    inPin->setUpdate(true); //Once we get the state of the pin, we buffer any pin changes until we are done checking

    //Every ms, we first check if a hardware trigger occured
    //in the opposite direction of the last remembered state
    if (lastInState == 0) {
        changed = inPin->lastUpEvent.triggered;
        if (changed) state = 1;
    } else if (lastInState == 1) {
        changed = inPin->lastDownEvent.triggered;
        if (changed) state = 0;
    }

    //if not, then we read the pin state to see if it is different than the
    //remembered state.  This is important in order to report both edges of a
    //fast up-down event.
    if (!changed) {
        state = read();
        changed = (lastInState != state);

    }


    //changed = (inPin->lastUpEvent.triggered || inPin->lastDownEvent.triggered);
    if (changed) {
        if (state == 1) {

            lastChangeInterval = inPin->lastUpEvent.timeStamp - lastChangeTime;
            lastChangeTime = inPin->lastUpEvent.timeStamp;

            if (triggerUpEventPtr != NULL && triggerUpEventPtr->isUsed) {triggerUpEventPtr->execute();}
        } else if (state == 0) {

            lastChangeInterval = inPin->lastDownEvent.timeStamp - lastChangeTime;
            lastChangeTime = inPin->lastDownEvent.timeStamp;

            if (triggerDownEventPtr != NULL && triggerDownEventPtr->isUsed){triggerDownEventPtr->execute();}
        }

        lastInState = state;
        inPin->lastUpEvent.triggered = false;
        inPin->lastDownEvent.triggered = false;

        inPin->setUpdate(false); //This also checks if there were any buffered changes that occured
    }

    inPin->setUpdate(false); //This also checks if there were any buffered changes that occured

    return changed;
}


//------------------------------------------
digitalPort::digitalPort():
outPin(NULL),
inPin(NULL),
outState(0){

}

void digitalPort::init(sDigitalOut *DOP, sDigitalIn *DIP) {
    outPin = DOP;
    inPin = DIP;
    lastInState = getDigitalIn();
    inState = getDigitalIn();
    lastChangeTime = 0;
    lastOutChangeTime = 0;
    lastChangeInterval = 0;
    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 = timeKeeper;
    }
    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;
    bool execUp = false;
    bool execDown = false;
    if ((timeKeeper - lastChangeTime) > 1) { //prevents flutter triggers when button is pressed


        inPin->setUpdate(true); //Once we get the state of the pin, we buffer any pin changes until we are done checking

        //Every ms, we first check if a hardware trigger occured
        //in the opposite direction of the last remembered state
        if (lastInState == 0) {
            changed = inPin->lastUpEvent.triggered;
            if (changed) inState = 1;
        } else if (lastInState == 1) {
            changed = inPin->lastDownEvent.triggered;
            if (changed) inState = 0;
        }

        //if not, then we read the pin state to see if it is different than the
        //remembered state.  This is important in order to report both edges of a
        //fast up-down event.
        if (!changed) {
            inState = getDigitalIn();
            changed = (lastInState != inState);

        }


        //changed = (inPin->lastUpEvent.triggered || inPin->lastDownEvent.triggered);
        if (changed) {
            if (inState == 1) {

                lastChangeInterval = inPin->lastUpEvent.timeStamp - lastChangeTime;
                lastChangeTime = inPin->lastUpEvent.timeStamp;


                if (triggerUpEventPtr != NULL && triggerUpEventPtr->isUsed) {triggerUpEventPtr->execute();}
            } else if (inState == 0) {

                lastChangeInterval = inPin->lastDownEvent.timeStamp - lastChangeTime;
                lastChangeTime = inPin->lastDownEvent.timeStamp;


                if (triggerDownEventPtr != NULL && triggerDownEventPtr->isUsed){triggerDownEventPtr->execute();}
            }



            //inPin->setUpdate(true); //Once we get the state of the pin, we buffer any pin changes until we are done checking

            //inState = getDigitalIn();

            //We need to ignore flutter when levers/beam breaks are triggered. So
            //if the current state if different than the last logged state, we only
            //consider the first edge that brough us to the current state

            /*
            if (lastInState != inState) {

                if (inState == 1) {

                    lastChangeInterval = inPin->lastUpEvent.timeStamp - lastChangeTime;
                    lastChangeTime = inPin->lastUpEvent.timeStamp;


                    if (triggerUpEventPtr != NULL && triggerUpEventPtr->isUsed) {triggerUpEventPtr->execute();}
                } else if (inState == 0) {

                    lastChangeInterval = inPin->lastDownEvent.timeStamp - lastChangeTime;
                    lastChangeTime = inPin->lastDownEvent.timeStamp;


                    if (triggerDownEventPtr != NULL && triggerDownEventPtr->isUsed){triggerDownEventPtr->execute();}
                }
            } else if (lastInState == inState) {

                //Both up and down triggers must have happened, so we consider both
                if (inState == 1) {

                    lastChangeInterval = inPin->lastUpEvent.timeStamp - inPin->lastDownEvent.timeStamp;
                    lastChangeTime = inPin->lastUpEvent.timeStamp;

                    if (triggerDownEventPtr != NULL && triggerDownEventPtr->isUsed) {triggerDownEventPtr->execute();}
                    if (triggerUpEventPtr != NULL && triggerUpEventPtr->isUsed) {triggerUpEventPtr->execute();}
                } else if (inState == 0) {

                    lastChangeInterval = inPin->lastDownEvent.timeStamp - inPin->lastUpEvent.timeStamp;
                    lastChangeTime = inPin->lastDownEvent.timeStamp;

                    if (triggerUpEventPtr != NULL && triggerUpEventPtr->isUsed) {triggerUpEventPtr->execute();}
                    if (triggerDownEventPtr != NULL && triggerDownEventPtr->isUsed) {triggerDownEventPtr->execute();}
                }
            }
            */

            lastInState = inState;
            inPin->lastUpEvent.triggered = false;
            inPin->lastDownEvent.triggered = false;

            inPin->setUpdate(false); //This also checks if there were any buffered changes that occured


        }

        inPin->setUpdate(false); //This also checks if there were any buffered changes that occured


    }

    return changed;
}

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

}

intVariable::intVariable():
value(0) {
    isUsed = false;
}

intVariable::intVariable(std::string& tagInput, int initialValue):
value(initialValue)
{
    strncpy(tag,tagInput.data(),MAXVARNAMESIZE);
    isUsed = true;
}

void intVariable::set(std::string& tagInput, int initialValue) {
    value = initialValue;
    //tag = string(tagInput);
    strncpy(tag,tagInput.data(),MAXVARNAMESIZE);
    isUsed = true;
}

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

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


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

}

void displayAction::set(string text) {
    dText = text;
    dVariable = NULL;
    isUsed = true;
}

void displayAction::execute() {

    if (dVariable != NULL) {
        textDisplay << timeKeeper << " " << dText.c_str() << " = " << *dVariable << "\r\n";
    } else {
        textDisplay << timeKeeper << " " << dText.c_str() << "\r\n";
    }
}

triggerFunctionAction::triggerFunctionAction():
functionNum(0) {
    isUsed = false;
}

triggerFunctionAction::triggerFunctionAction(int funcNum):
functionNum(funcNum) {

    isUsed = true;

}

void triggerFunctionAction::set(int funcNum) {
    functionNum = funcNum;
    isUsed = true;
}

void triggerFunctionAction::execute() {

    if (functionSpotTaken[functionNum] && functionEventArray[functionNum]->isUsed) {
        functionEventArray[functionNum]->execute();
    }

}

void triggerFunctionAction::release() {
    isUsed = false;
}



intCompare::intCompare():
port(NULL) {
    cmpVal = NULL;
    cmpValGlobal = false;
    intVal = NULL;
    intOp = NULL;
    portValPtr = NULL;
    isUsed = false;

}
intCompare::intCompare(AbstractPort* 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->state;
    } else {
        portValPtr = &port->state;
    }
}

intCompare::intCompare(AbstractPort* 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->state;
    } else {
        portValPtr = &port->state;
    }
}

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(AbstractPort* 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->state;
    } else {
        portValPtr = &port->state;
    }
}



void intCompare::set(AbstractPort* 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->state;
    } else {
        portValPtr = &port->state;
    }
}

void intCompare::set(AbstractPort* 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->state;
    } else {
        portValPtr = &port->state;
    }
}

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(AbstractPort* 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->state;
    } else {
        portValPtr = &port->state;
    }
}



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;
    isClockAssign = false;
    inputsFlipped = 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::setRandOp(int randParam, const char* cmpString, int cmpValInput, bool flipped) {
    randHigh = randParam;
    cmpVal = new int(cmpValInput);
    intVal = NULL;
    opPtr = NULL;
    cmpValGlobal = false;
    isUsed = true;
    inputsFlipped = flipped;
    if (strcmp(cmpString, "+") == 0) {
        executePtr = &intOperation::add;
    }else if (strcmp(cmpString, "-") == 0) {
        executePtr = &intOperation::subtract;
    }else if (strcmp(cmpString, "=") == 0) {
        executePtr = &intOperation::equals;
    }

}

void intOperation::setRandOp(int randParam, const char* cmpString, int* cmpIntVarInput, bool flipped) {
    randHigh = randParam;
    cmpVal = cmpIntVarInput;
    intVal = NULL;
    opPtr = NULL;
    cmpValGlobal = true;
    isUsed = true;
    inputsFlipped = flipped;
    if (strcmp(cmpString, "+") == 0) {
        executePtr = &intOperation::add;
    }else if (strcmp(cmpString, "-") == 0) {
        executePtr = &intOperation::subtract;
    }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;

}

void intOperation::setClockOp(int* intVarInput) {
    //used to assign current clock to variable
    intVal = intVarInput;
    cmpVal = NULL;
    randHigh = -1;
    opPtr = NULL;
    cmpValGlobal = false;
    isUsed = true;
    isClockAssign = true;
    executePtr = &intOperation::equals;

}

void intOperation::setClockOp(const char* cmpString, int cmpValInput, bool flip) {
    //used to add an integer to the current clock value

    intVal = NULL;
    cmpVal = new int(cmpValInput);
    randHigh = -1;
    opPtr = NULL;
    cmpValGlobal = false;
    isUsed = true;
    isClockAssign = true;
    inputsFlipped = flip;
    if (strcmp(cmpString, "+") == 0) {
        executePtr = &intOperation::add;
    }else if (strcmp(cmpString, "-") == 0) {
        executePtr = &intOperation::subtract;
    }
}

void intOperation::setClockOp(const char* cmpString, int* cmpIntVarInput, bool flip) {
    //used to add a variable to the current clock value

    cmpVal = cmpIntVarInput;
    intVal = NULL;
    randHigh = -1;
    opPtr = NULL;
    isClockAssign = true;
    cmpValGlobal = true;
    isUsed = true;
    inputsFlipped = flip;
    if (strcmp(cmpString, "+") == 0) {
        executePtr = &intOperation::add;
    }else if (strcmp(cmpString, "-") == 0) {
        executePtr = &intOperation::subtract;
    }
}


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;
    isClockAssign = false;
    cmpValGlobal = false;
    isUsed = false;
}


int intOperation::execute() {

    return (this->*executePtr)();


}

int intOperation::add() {

    if ((intVal != NULL) && (!isClockAssign)) {
        return (*intVal + *cmpVal);
    } else if ((intVal == NULL) && (isClockAssign)) {
        return (timeKeeper + *cmpVal);
    } else {
        //srand(time(NULL));
        srand(timeKeeper);
        return (rand() % (randHigh+1)) + *cmpVal;
        //return (port->getState() + *cmpVal);
    }
}

int intOperation::subtract() {
    if ((intVal != NULL) && (!isClockAssign)) {
        return (*intVal - *cmpVal);
    } else if ((intVal == NULL) && (isClockAssign)) {
        if (inputsFlipped) {
            return (*cmpVal-timeKeeper);
        } else {
            return (timeKeeper - *cmpVal);
        }
    } else {
        srand(timeKeeper);
        if (inputsFlipped) {
            return (*cmpVal-(rand() % (randHigh+1)));
        } else {
            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) && (!isClockAssign)) {
        *intVal = *cmpVal;
        return *intVal;
    } else if ((intVal != NULL) && (opPtr != NULL)) {

        *intVal = opPtr->execute();
        return *intVal;
    } else if ((intVal != NULL) && (opPtr == NULL) && (isClockAssign)) {
        *intVal = timeKeeper; //assign the current time to the variable
        return *intVal;
    } else if ((cmpVal != NULL)&& (!isClockAssign)){

        srand(timeKeeper+randomSeedCounter);
        randomSeedCounter++; //for seeding the next rand call, just in case it happens before the clock advances
        *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) {

        result = (intCmp->isTrue)();
    } else if (conditionType == AND_CONDITION) {

        result = conditionPtrs[0]->isTrue() && conditionPtrs[1]->isTrue();
    } else if (conditionType == OR_CONDITION) {

        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;
}

void portMessage::setMessage(int* portIn, int whichToSetIn, int valueIn, AbstractPort** portVectorIn, int portVectorLength) {
    whichToSet = whichToSetIn;
    value = valueIn;
    port = portIn;
    portVector = portVectorIn;
    isUsed = true;
    vectorLength = portVectorLength;
}

void portMessage::execute() {

    if (port != NULL) {
        if ((*port > 0) && (*port <= vectorLength)) {
            portVector[*port-1]->write(value);
        } else {
            textDisplay << "Error: port index assigned by variable does not exist.\r\n";
        }
    } else {
        portVector[whichToSet-1]->write(value);
    }

}

action::action():
actionType(0) {
    op = NULL;
    message = NULL;
    eventToCreate = NULL;
    displayActionPtr = NULL;
    //eventDelay = 0;
    sound = NULL;
    triggerFunc = 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();
    if (triggerFunc != NULL) triggerFunc->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;
    triggerFunc = NULL;
    sysCommand = -1;
    isUsed = false;
}

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

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

}

action::action(event* eventInput):
actionType(3) {
    op = NULL;
    message = NULL;
    eventToCreate = eventInput;
    displayActionPtr= NULL;
    sound = NULL;
    triggerFunc = 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;
    triggerFunc = NULL;
    displayActionPtr = displayInput;
    //eventDelay = 0;
    sysCommand = -1;
    isUsed = true;
}

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

action::action(triggerFunctionAction* triggerFuncInput):
actionType(7) {
    op = NULL;
    message = NULL;
    eventToCreate = NULL;
    sound = NULL;
    triggerFunc = triggerFuncInput;
    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(sSound* soundInput) {
    actionType = 5;
    sound = soundInput;
    isUsed = true;
}

void action::set(triggerFunctionAction* triggerFuncInput) {

    actionType = 7;
    triggerFunc = triggerFuncInput;
    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(timeKeeper); //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;
        }

    } else if (actionType == 7) {
        triggerFunc->execute(); //execute function
    }
}

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 - (timeKeeper-blockExecTime);
        } else {
            newDelay = *eventToCreate->timeLagVar - (timeKeeper-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-timeKeeper < 0) && (eventToCreate->isConditionTrue()) ) {
                    eventToCreate->execute();
                    newDelay = newDelay + tmpPeriod;

                }
                newDelay = newDelay-timeKeeper;
                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;
        }
    } else if (actionType == 7) {

        textDisplay.flush();
        triggerFunc->execute(); //operate sound device
    }
}

eventQueue::eventQueue() {

    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 = timeKeeper + 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 = timeKeeper;
    //*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-timeKeeper <= 0) && (events[i].eventPtr->isConditionTrue())) {
                        events[i].eventPtr->execute();
                        nextTime = nextTime+tmpPeriod;

                    }
                    nextTime = nextTime - timeKeeper;
                    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')
    bool result = true;

    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 = timeKeeper;
    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;
}

blockBuffer::blockBuffer() {
    bufferWritePos = 0;
    bufferReadPos = 0;
    _linesAvailable = 0;

}

bool blockBuffer::addLine(char *input, int numChars) {

    if (bufferWritePos+numChars >= INPUTCHARBUFFERSIZE) {
        return false;
    }
    for(int i=0;i<numChars;i++) {
        charBuffer[bufferWritePos] = input[i];
        bufferWritePos++;
    }
    _linesAvailable++;
    return true;
}

string blockBuffer::getNextLine() {

    string outputLine;
    int endOfLinePos = bufferReadPos;
    bool endOfLineFound = false;

    if (_linesAvailable > 0) {
        //Find the end of the next line

        while (endOfLinePos < INPUTCHARBUFFERSIZE) {

            if (charBuffer[endOfLinePos] == '\0') {
                endOfLineFound = true;
                break;
            }
            endOfLinePos++;
        }

        //If the end was found, copy to output string
        if (endOfLineFound) {

            outputLine.append(charBuffer+bufferReadPos,endOfLinePos-bufferReadPos);
            bufferReadPos = endOfLinePos+1;
            _linesAvailable--;
        } else {
            textDisplay << "Error: No end of line found!";
            textDisplay.flush();
        }
    }
    if (_linesAvailable == 0) {
        //we have read out all of the lines, so reset the buffer for the next block.
        resetBuffer();
    }
    return outputLine;

}

int16_t blockBuffer::linesAvailable() {
    return _linesAvailable;
}

void blockBuffer::resetBuffer() {
    _linesAvailable = 0;
    bufferReadPos = 0;
    bufferWritePos = 0;
}

bool blockBuffer::empty() {
    return (_linesAvailable == 0);
}


scriptStream::scriptStream(AbstractPort** portVectorInput, int numPortsInput, eventQueue* queueInput, sSystem *system):
    portVector(portVectorInput),
    numPorts(numPortsInput),
    queuePtr(queueInput),
    system(system) {

    numAnInPorts = 0;
    numDigInPorts = 0;
    numAnOutPorts = 0;
    numDigOutPorts = 0;

    for (int i=0;i<numPortsInput;i++) {
        if ((portVectorInput[i]->portType == AbstractPort::analog)&&(portVectorInput[i]->portDir == AbstractPort::in)) {
            if(numAnInPorts < NUMANINPORTS) {
                anInPortVector[numAnInPorts] = portVectorInput[i];
                anInLookup[numAnInPorts] = i;
                numAnInPorts++;
            }
        } else if ((portVectorInput[i]->portType == AbstractPort::analog)&&(portVectorInput[i]->portDir == AbstractPort::out)) {
            if(numAnOutPorts < NUMANOUTPORTS) {
                anOutPortVector[numAnOutPorts] = portVectorInput[i];
                anOutLookup[numAnOutPorts] = i;
                numAnOutPorts++;
            }
        } else if ((portVectorInput[i]->portType == AbstractPort::digital)&&(portVectorInput[i]->portDir == AbstractPort::in)) {
            if(numDigInPorts < NUMDIGINPORTS) {
                digInPortVector[numDigInPorts] = portVectorInput[i];
                digInLookup[numDigInPorts] = i;
                numDigInPorts++;
            }
        } else if ((portVectorInput[i]->portType == AbstractPort::digital)&&(portVectorInput[i]->portDir == AbstractPort::out)) {
            if(numDigOutPorts < NUMDIGOUTPORTS) {
                digOutPortVector[numDigOutPorts] = portVectorInput[i];
                digOutLookup[numDigOutPorts] = i;
                numDigOutPorts++;
            }
        }
    }

    currentPort = -1;
    currentTriggerPort = -1;
    currentTriggerDir = 1;
    currentFunction = -1;

    randomSeedCounter = 0;  //used for seeding random numbers

    lineError = false;
    blockDepth = 0;
    ifBlockInit = false;
    whileBlockInit = false;
    expectingDoStatement = false;
    elseFlag = false;
    thenFlag = false;
    currentDelay = 0;

    for (int i = 0; i < NUMFUNCTIONS; i++) {
        functionSpotTaken[i] = false;
        functionEventArray[i] = NULL;
    }


}


void scriptStream::addLineToCurrentBlock(char* lineInput) {

    bool compile = false;
    bool keep = false;
    int numCharInLine = 0;
    //A line ending with ';' then carriage return initiates the compile sequence
    //Otherwise, add the line to the buffer and compile later
    for (int i = 0; i < 256; i++) {
        numCharInLine++;
        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 (keep) {
        if (!currentBlock.addLine(lineInput,numCharInLine)) {
            textDisplay << "Error: script input buffer full. The block is too long.\r\n";
            currentBlock.resetBuffer();
            compile = false;
        }
    }
    if (compile) {
        parseBlock();
    }

}


//SCRIPT PARSING - all script commands are defined here.
//-------------------------------------------------------
void scriptStream::parseBlock() {

    tmpEvent = NULL;
    lineError = false;
    blockDepth = 0;
    ifBlockInit = false;
    whileBlockInit = false;
    expectingDoStatement = false;
    elseFlag = false;
    thenFlag = false;
    currentDelay = 0;


    std::size_t stringInd = 0;

    bool wholeLineEvaluated = false;

    while (!currentBlock.empty()) {

        wholeLineEvaluated = false;
        //tmpLine = currentBlock.back();
        tmpLine = currentBlock.getNextLine();

        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++) {



            //end statement signals the end of a block-----------------------------------------
            if (tokens[i].compare("end") == 0) { //ends the current block

                if (ifBlockInit || whileBlockInit || expectingDoStatement) {
                    textDisplay << "Error: expected a 'do' statement\r\n";
                    lineError = true;
                }

                ifBlockInit = false;
                whileBlockInit = false;
                expectingDoStatement = false;
                elseFlag = false;

                if (blockDepth > 0) {
                    textDisplay.debug("End statement\r\n");
                    if (blockDepth == 1) {


                        currentTriggerPort = -1;
                        currentFunction = -1;



                        blockDepth = 0;
                    } else if (blockDepth > 1) {
                        blockDepth = blockDepth - 1;
                    }

                    while ((tmpEventPtrArray.back()->blockType == 3) || (tmpEventPtrArray.back()->blockType == 4) || (tmpEventPtrArray.back()->blockType == 6) || (tmpEventPtrArray.back()->blockType == 7) || (tmpEventPtrArray.back()->blockType == 8)){
                        tmpEventPtrArray.pop_back(); //recursively remove the pointers to all else blocks
                    }
                    tmpEventPtrArray.pop_back(); //remove the pointer to the finished block

                } else {
                    textDisplay << "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 || expectingDoStatement) {
                    textDisplay << "Error: expected a 'do' statement\r\n";
                    lineError = true;
                }
                wholeLineEvaluated = true;
                int pos1 = tmpLine.find("sound(")+6;
                int pos2 = tmpLine.find_first_of(")",pos1);
                if (pos2 == std::string::npos) {
                    textDisplay << "Syntax error: expected a ')'\r\n";
                    lineError = true;
                }

                if (!lineError) {
                    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 {
                            textDisplay << "Error: variable input to sound() does not exist\r\n";
                            lineError = true;
                        }
                    }
                    action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS);
                    if (tmpAction == NULL) {
                        textDisplay << "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) {
                            sSound* S = system->createNewSoundAction();
                            S->setPlayback(false);
                            S->execute();
                            delete S;
                        } else if (resetSignal) {
                            sSound* S = system->createNewSoundAction();
                            S->setReset();
                            S->execute();
                            delete S;
                        } else if (isText) {

                            if (pos2-pos1-2 <= 20) {

                                sSound* S = system->createNewSoundAction();
                                S->setFile(tmpLine.substr(pos1+1,pos2-pos1-2));
                                S->execute();
                                delete S;
                            } else {
                                textDisplay << "Error: sound file names must be 20 characters or less.\r\n";
                                lineError = true;
                            }
                        } else {
                            textDisplay << "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
                        textDisplay.debug("Sound statement\r\n");
                        if (stopSignal) {
                            sSound* sPtr = system->createNewSoundAction();
                            sPtr->setPlayback(false);
                            //action* tmpAction = new action(sPtr);
                            tmpAction->set(sPtr);
                            tmpEventPtrArray.back()->addAction(tmpAction);
                        } else if (resetSignal) {
                            sSound* sPtr = system->createNewSoundAction();
                            sPtr->setReset();
                            //action* tmpAction = new action(sPtr);
                            tmpAction->set(sPtr);
                            tmpEventPtrArray.back()->addAction(tmpAction);
                        } else if (isText) {

                            if (pos2-pos1-2 <= 20) {
                                sSound* sPtr = system->createNewSoundAction();
                                sPtr->setFile(tmpLine.substr(pos1+1,pos2-pos1-2));
                                //action* tmpAction = new action(sPtr);
                                tmpAction->set(sPtr);
                                tmpEventPtrArray.back()->addAction(tmpAction);
                            } else {
                                textDisplay << "Error: sound file names must be 20 characters or less.\r\n";
                                lineError = true;
                            }
                        } else {
                            textDisplay << "Error: variable input to sound() not yet supported.  Enter a string in single quotes.\r\n";
                            lineError = true;
                        }


                    }
                }

            } else if (tokens[i].find("volume(") != std::string::npos) {
                if (ifBlockInit || whileBlockInit || elseFlag || expectingDoStatement) {
                    textDisplay << "Error: expected a 'do' statement\r\n";
                    lineError = true;
                }
                wholeLineEvaluated = true;
                int pos1 = tmpLine.find("volume(")+7;
                int pos2 = tmpLine.find_first_of(")",pos1);
                if (pos2 == std::string::npos) {
                    textDisplay << "Syntax error: expected a ')'\r\n";
                    lineError = true;
                }
                if (!lineError) {
                    string dispVar = tmpLine.substr(pos1,pos2-pos1);

                    int* tmpVar = findIntVariable(dispVar);
                    bool isText = false;
                    if (tmpVar == NULL) {
                        if (isNumber(dispVar)) {
                            isText = true;
                        } else {
                            textDisplay << "Error: variable input to volume() does not exist\r\n";
                            lineError = true;
                        }
                    }
                    action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS);
                    if (tmpAction == NULL) {
                        textDisplay << "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)) {
                                sSound* S = system->createNewSoundAction();
                                S->setVolume(newVolume);
                                S->execute();
                                delete S;
                            } else {
                                textDisplay << "Error: sound volume must be between 0 and 255 .\r\n";
                                lineError = true;
                            }
                        } else {
                            sSound* S = system->createNewSoundAction();
                            S->setVolume(tmpVar);
                            S->execute();
                            delete S;
                        }

                    } else if (!lineError && (blockDepth > 0) ){
                        //the disp function was put inside a block
                        textDisplay.debug("Volume statement\r\n");
                        if (isText) {
                            int newVolume = atoi(dispVar.data());

                            sSound* sPtr = system->createNewSoundAction();
                            sPtr->setVolume(newVolume);

                            //action* tmpAction = new action(sPtr);
                            tmpAction->set(sPtr);
                            tmpEventPtrArray.back()->addAction(tmpAction);

                        } else {
                            sSound* sPtr = system->createNewSoundAction();
                            sPtr->setVolume(tmpVar);
                            //action* tmpAction = new action(sPtr);
                            tmpAction->set(sPtr);
                            tmpEventPtrArray.back()->addAction(tmpAction);
                        }


                    }
                }
                //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 || expectingDoStatement) {
                    textDisplay << "Error: expected a 'do' statement\r\n";
                    lineError = true;
                }
                if (blockDepth > 0) {
                    textDisplay << "Error: clock commands only allowed outside of block structure\r\n";
                    lineError = true;
                }
                int pos1 = tmpLine.find("clock(")+6;
                int pos2 = tmpLine.find_first_of(")",pos1);
                if (pos2 == std::string::npos) {
                    textDisplay << "Syntax Error: expected a ')'\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"));

                        } else if (dispVar.compare("slave") == 0) {
                            if (!clockSlave) {
                                changeToSlave = true;
                                textDisplay.send(string("Slave mode\r\n"));

                            }
                        } else if (dispVar.compare("standalone") == 0) {
                            if (clockSlave) {
                                changeToStandAlone = true;
                                textDisplay.send(string("Standalone mode\r\n"));

                            }
                        } else if (dispVar.compare("") == 0) {
                            //The user needs the current time displayed.

                            //textDisplay.send(string("Current Clock\r\n"));
                            textDisplay << timeKeeper << " current time\r\n";
                        } else {
                            textDisplay << "Error: 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 || expectingDoStatement) {
                    textDisplay <<"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);
                if (pos2 == std::string::npos) {
                    textDisplay <<"Syntax error: expected a ')'\r\n";
                    lineError = true;
                }

                if (!lineError) {
                    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 {
                            textDisplay << "Error: variable to display does not exist\r\n";
                            lineError = true;
                        }
                    }
                    displayAction* dPtr = findFirstUnUsed(displayActionBlock, NUMDISPLAYACTIONS);
                    if (dPtr == NULL) {
                        textDisplay << "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));
                            dPtr->execute();
                            //delete dPtr;
                            dPtr->release();
                        } else {
                            //displayAction* dPtr = new displayAction(tmpVar, dispVar, pcPtr);
                            dPtr->set(tmpVar, dispVar);
                            dPtr->execute();
                            //delete dPtr;
                            dPtr->release();
                        }

                    } else if (!lineError && (blockDepth > 0) ){
                        //the disp function was put inside a block
                        textDisplay.debug("Display statement\r\n");
                        action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS);
                        if (tmpAction == NULL) {
                            textDisplay <<"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));
                            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);
                            tmpAction->set(dPtr);
                            //action* tmpAction = new action(dPtr);
                            tmpEventPtrArray.back()->addAction(tmpAction);
                        }


                    }
                }
                //----------------------------------------------
                //The trigger command is used like this:
                //trigger(n)
                //Where n is an integer corresponding to a "function n" block
                //When "trigger" is called, the corresponding function is executed.
            } else if (tokens[i].find("trigger(") != std::string::npos) { //trigger a function

                if (ifBlockInit || whileBlockInit || elseFlag || expectingDoStatement) {
                    textDisplay << "Error: expected a 'do' statement\r\n";
                    lineError = true;
                }


                wholeLineEvaluated = true;
                int pos1 = tmpLine.find("trigger(")+8;
                int pos2 = tmpLine.find_first_of(")",pos1);
                if (pos2 == std::string::npos) {
                    textDisplay << "Syntax error: expected a ')'\r\n";
                    lineError = true;
                }

                if (!lineError) {
                    int funcNum = atoi(tmpLine.substr(pos1,pos2-pos1).data());
                    if ((funcNum > 0) && (funcNum < NUMFUNCTIONS+1)) {
                        if (functionSpotTaken[funcNum-1] && functionEventArray[funcNum-1]->isUsed) {


                        } else {
                            textDisplay << "Error: function number does not exist\r\n";                           
                            lineError = true;
                        }
                    } else {
                        textDisplay << "Error: not a valid function number\r\n";
                        lineError = true;
                    }

                    funcNum--;  //change to 0-based index
                    if (!lineError && (blockDepth == 0)) {
                        //we are not inside a block structure, so execute function now
                        //textDisplay << "Exectuting function";
                        //textDisplay.flush();

                        functionEventArray[funcNum]->execute();

                    } else if (!lineError && (blockDepth > 0) ){
                        //the trigger function was put inside a block, so we need to create a new action
                        textDisplay.debug("Trigger statement\r\n");
                        triggerFunctionAction* tPtr = findFirstUnUsed(triggerFunctionActionBlock, NUMTRIGGERACTIONS);
                        if (tPtr == NULL) {
                            textDisplay << "Error: no memory slots available.\r\n";
                            lineError = true;
                        }

                        if (!lineError) {
                            //we only give provide it the function number, instead
                            //of a pointer to the event.  That way, if the user modifies
                            //the function (which would change the pointer), all callbacks
                            //still using that function number will use the new function.
                            tPtr->set(funcNum);
                            action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS);
                            if (tmpAction == NULL) {
                                textDisplay << "Error: no memory slots available.\r\n";
                                lineError = true;
                            }
                            if (!lineError) {

                                tmpAction->set(tPtr);
                                tmpEventPtrArray.back()->addAction(tmpAction);
                            }
                        }


                    }

                }


                //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
                textDisplay.debug("Int statement\r\n");
                if (ifBlockInit || whileBlockInit || expectingDoStatement) {
                    textDisplay << "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) {
                    textDisplay << "Error: Variables can only be first declared outside of callbacks.\r\n";
                    lineError = true;
                }

                if ((!lineError) && (spacesBeforeEqualSign > 1)) {
                    textDisplay << "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 ((stringInd != std::string::npos) && (stringInd > MAXVARNAMESIZE)) {
                            textDisplay << "Error: variable names must be under 30 characters.\r\n";
                            lineError = true;
                        } else if (createIntVariable(tmpString.substr(0,stringInd))) {
                            textDisplay.debug("Created new variable\r\n");
                            variableCreated = true;
                        } else {
                            textDisplay.debug("Attempting to use existing variable\r\n");
                            int* tmpVar = findIntVariable(tmpString.substr(0,stringInd));
                            *tmpVar = 0;
                            //lineError = true;
                        }
                    } else {
                        textDisplay << "Error: variable declaration not understood.\r\n";
                        lineError = true;
                    }
                }
                if ((!lineError) && (stringInd != std::string::npos)) { //evaluate the expression
                    //action* tmpAction = evaluateAssignmentForAction(tmpString);
                    action* tmpAction = evaluateAssignmentForAction(tmpString.data());
                    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 || expectingDoStatement) {
                    textDisplay << "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 {
                        textDisplay << "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) {
                            textDisplay << "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) {
                            textDisplay << "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
                //examples: updates on 3; updates off 3
            } else if (tokens[i].compare("updates") == 0) {
                if (ifBlockInit || whileBlockInit || elseFlag || expectingDoStatement) {
                    textDisplay << "Error: expected a 'do' statement\r\n";
                    lineError = true;
                }
                bool stream = true;
                int specifiedPort = -1;
                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 {
                        textDisplay << "Error: 'updates' usage: 'updates on' or 'updates off'\r\n";
                        lineError = true;
                    }
                }
                if ((!lineError) && (i+2 < sz)) {
                    //There is a port specified
                    //int pos1 = tmpLine.find("trigger(")+8;
                    //int pos2 = tmpLine.find_first_of(")",pos1);
                    int tempPort = atoi(tokens[i+2].data());
                    if (tempPort > 0) {
                        specifiedPort = tempPort-1;
                    } else {
                        textDisplay << "Error: 'updates' usage: 'updates on [port]' or 'updates off [port]'\r\n";
                        lineError = true;
                    }
                    i++;
                }
                i++;
                if ((!lineError) && (blockDepth == 0)) {
                    if (stream) {
                        //applies to all;
                        broadCastStateChanges = true;
                        if ((specifiedPort > -1) && (specifiedPort < NUMDIGINPORTS)) {
                            //system->setPortUpdatesOn(specifiedPort);
                            digInPortVector[specifiedPort]->setReportUpdates(true);
                        } else {
                            for (int i=0;i<NUMDIGINPORTS;i++) {
                                //system->setPortUpdatesOn(i);
                                digInPortVector[i]->setReportUpdates(true);
                            }
                        }
                    } else {
                        if ((specifiedPort > -1) && (specifiedPort < NUMDIGINPORTS)) {
                            //system->setPortUpdatesOff(specifiedPort);
                            digInPortVector[specifiedPort]->setReportUpdates(false);
                        } else {
                            //applies to all
                            //broadCastStateChanges = false;
                            for (int i=0;i<NUMDIGINPORTS;i++) {
                                //system->setPortUpdatesOff(i);
                                digInPortVector[i]->setReportUpdates(false);
                            }
                        }

                    }
                } else if ((!lineError) && (blockDepth > 0)) {
                    //Inside a block-- current no support here to specify a port

                    if (stream) {
                        //action* tmpAction = new action(3); //code 3 = turn on updates
                        action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS);
                        if (tmpAction == NULL) {
                            textDisplay << "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) {
                            textDisplay << "Error: no memory slots available.\r\n";
                            lineError = true;
                        } else {
                            tmpAction->set(4);
                            tmpEventPtrArray.back()->addAction(tmpAction);
                        }

                    }
                }

            } else if (tokens[i].compare("memory") == 0) {
                if (ifBlockInit || whileBlockInit || elseFlag || expectingDoStatement) {
                    textDisplay << "Error: expected a 'do' statement\r\n";
                    lineError = true;
                }
                if ((!lineError) && (blockDepth > 0)) {
                    textDisplay << "Error: memory statement is not allowed inside a block.\r\n";
                    lineError = true;
                }
                if (!lineError) {
                    displayMemoryLeft();
                }

            } else if (tokens[i].compare("version") == 0) {
                if (ifBlockInit || whileBlockInit || elseFlag || expectingDoStatement) {
                    textDisplay << "Error: expected a 'do' statement\r\n";
                    lineError = true;
                }
                if ((!lineError) && (blockDepth > 0)) {
                    textDisplay << "Error: version statement is not allowed inside a block.\r\n";
                    lineError = true;
                }
                if (!lineError) {
                    textDisplay << "StateScript firmware version " <<  vInfo.major << "." <<  vInfo.middle << "." <<  vInfo.minor << "\r\n";
                    textDisplay << vInfo.updateMonth << "." << vInfo.updateDay << "." << vInfo.updateYear << "\r\n";
                }

            } else if (tokens[i].find("maxanalog(") != std::string::npos) {
                if (ifBlockInit || whileBlockInit || elseFlag || expectingDoStatement) {
                    textDisplay << "Error: expected a 'do' statement\r\n";
                    lineError = true;
                }
                if ((!lineError) && (blockDepth > 0)) {
                    textDisplay << "Error: maxanalog statement is not allowed inside a block.\r\n";
                    lineError = true;
                }
                if (!lineError) {
                    wholeLineEvaluated = true;
                    int pos1 = tmpLine.find("maxanalog(")+10;
                    int pos2 = tmpLine.find_first_of(")",pos1);
                    if (pos2 == std::string::npos) {
                        textDisplay << "Syntax error: expected a ')'\r\n";
                        lineError = true;
                    }
                    if (!lineError) {
                        string dispVar = tmpLine.substr(pos1,pos2-pos1);

                        int* tmpVar = findIntVariable(dispVar);
                        bool isText = false;
                        if (tmpVar == NULL) {
                            if (isNumber(dispVar)) {
                                isText = true;
                            } else {
                                textDisplay << "Error: variable input to maxanalog() does not exist\r\n";
                                lineError = true;
                            }
                        }



                        if (isText) {
                            int newVal = atoi(dispVar.data());
                            if ((newVal > 0)) {
                                system->setMaxAnalogOut(newVal);

                            } else {
                                textDisplay << "Error: max analog value must be greater than 0 .\r\n";
                                lineError = true;
                            }
                        } else {
                            int newVal = *tmpVar;
                            if ((newVal > 0)) {
                                system->setMaxAnalogOut(newVal);

                            } else {
                                textDisplay << "Error: max analog value must be greater than 0 .\r\n";
                                lineError = true;
                            }
                        }


                    }
                }


            //clear is used to clear things from memory---------------------------------
            //examples: clear all; clear callbacks; clear queue

            } else if (tokens[i].compare("clear") == 0) { //delete all created events and variables
                if (ifBlockInit || whileBlockInit || elseFlag || expectingDoStatement) {
                    textDisplay << "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 {
                        textDisplay << "Error: clear what: all, blocks, or queue? \r\n";
                        lineError = true;
                    }
                } else {
                    textDisplay << "Error: clear what: all, blocks, or queue? \r\n";
                    lineError = true;
                }


                if ((!lineError) && (clearMode < 3) && (blockDepth > 0)) {
                    textDisplay << "Error: 'clear all' and 'clear blocks' only allowed outside of block structures\r\n";
                    lineError = true;
                }
                if (!lineError) {
                    //i++;
                    //clear variables

                    if (clearMode == 1) {
                        //Clears everything
                        int sendClearMode = 0;
                        sendClearMode |= BLOCKMEMORYTYPES;
                        sendClearMode |= VARIABLEMEMORYTYPES;
                        sendClearMode |= ENVSETTINGSMEMORYTYPES;

                        clearEnvironmentVariables(sendClearMode);

                    } else if  (clearMode == 2) {
                        //Clear just varaibles
                        int sendClearMode = 0;
                        sendClearMode |= VARIABLEMEMORYTYPES;
                        clearEnvironmentVariables(sendClearMode);

                    } else if (clearMode == 3) {
                        //Clear the current event queue (can itself be a queued action)
                        if (blockDepth > 0) { //we are inside a block
                            action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS);
                            if (tmpAction == NULL) {
                                textDisplay << "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();
                        }
                    }
                    wholeLineEvaluated = true;


                }

                //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 > -1) || (currentFunction > -1)) { //check to make sure we are inside a trigger block


                    } else {
                        textDisplay << "Error: a statement block must be placed inside a callback or function.\r\n";
                        lineError = true;
                    }

                }
                expectingDoStatement = false;
                tmpEvent = findFirstUnUsed(eventBlock, NUMEVENTS);
                action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS);
                bool eventReserved = false;
                if ((tmpEvent == NULL)||(tmpAction == NULL)) {
                    textDisplay << "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]))) {
                        textDisplay.debug("Do in number statement\r\n");
                        currentDelay = atoi(tokens[i+2].data());
                        if (currentDelay < 0) {
                            textDisplay <<"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
                            }

                        } 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());

                            }


                        }

                    } else if ((!lineError) && (tokens[i+1].compare("in") == 0) && (findIntVariable(tokens[i+2])!=NULL)) {
                        textDisplay.debug("Do in VAR statement\r\n");
                        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
                            }

                        } 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());

                            }


                        }

                    } else {
                        textDisplay << "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
                    textDisplay.debug("Do statement\r\n");
                    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
                    }

                } 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());
                    }

                }
                if (lineError && eventReserved) {
                    tmpEvent->release();
                }
                //close block initiation
                ifBlockInit = false;
                whileBlockInit = false;
                wholeLineEvaluated = true;
                elseFlag = false;
                thenFlag = false;

                //currently, there are two types of root-level blocks: functions and callbacks
                //
                //A function can be triggered with a command, a callback is tied to a hardware event
            } else if (tokens[i].compare("function") == 0) { //a new function block
                if (ifBlockInit || whileBlockInit || elseFlag || expectingDoStatement) {
                    textDisplay << "Error: expected a 'do' statement\r\n";
                    lineError = true;
                }
                if (blockDepth != 0)  {
                    textDisplay <<"Error: Can't declare a function block within another block\r\n";
                    lineError = true;
                }
                if (!lineError) {
                    textDisplay.debug("Function statement\r\n");
                    wholeLineEvaluated = true;
                    if (i+1 < sz) {
                        int tempFuncNum = atoi(tokens[i+1].data());
                        if ((tempFuncNum > 0) && (tempFuncNum < NUMFUNCTIONS+1)) {
                            currentFunction = tempFuncNum-1;
                        } else {
                            textDisplay << "Error: not a valid function number\r\n";
                            lineError = true;
                        }
                    } else {
                        if (!lineError) textDisplay << "Error: Not enough arguments for function statement\r\n";
                        lineError = true;
                    }
                    if (sz > 2) {
                        if (!((sz == 3) && (tokens[i+2].compare("do") == 0))) {
                            textDisplay << "Error: Too many arguments in function statement\r\n";
                            lineError = true;
                        }
                    }

                    tmpEvent = findFirstUnUsed(eventBlock, NUMEVENTS);
                    if (tmpEvent != NULL) {
                        tmpEvent->isUsed = true;

                    } else {
                        textDisplay << "Error: no memory slots available.\r\n";
                        lineError = true;
                    }
                    if (!lineError) {

                        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 (functionSpotTaken[currentFunction]) {
                            functionEventArray[currentFunction]->release();
                        }
                        functionEventArray[currentFunction] = tmpEvent;
                        functionSpotTaken[currentFunction] = true;

                    }
                }


                //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 || expectingDoStatement) {
                    textDisplay << "Error: expected a 'do' statement\r\n";
                    lineError = true;
                }
                if (blockDepth != 0)  {
                    textDisplay << "Error: Can't declare a callback block within another block\r\n";
                    lineError = true;
                }
                if (!lineError) {
                    textDisplay.debug("Callback statement\r\n");
                    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 > NUMDIGINPORTS) {
                                currentTriggerPort = -1;
                                textDisplay << "Error: Not a valid port number.\r\n";
                                lineError = true;
                            } else {
                                currentTriggerPort = digInLookup[currentTriggerPort-1];
                            }
                        } else {
                            textDisplay << "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 {
                            textDisplay << "Error: No trigger direction given\r\n";
                            lineError = true;
                        }

                    } else {
                        if (!lineError) textDisplay << "Error: Not enough arguments for callback statement\r\n";
                        lineError = true;
                    }
                    if (sz > 3) {
                        if (!((sz == 4) && (tokens[i+3].compare("do") == 0))) {
                            textDisplay << "Error: Too many arguments in callback statement\r\n";
                            lineError = true;
                        }
                    }

                    tmpEvent = findFirstUnUsed(eventBlock, NUMEVENTS);
                    if (tmpEvent != NULL) {
                        tmpEvent->isUsed = true;

                    } else {
                        textDisplay << "Error: no memory slots available.\r\n";
                        lineError = true;
                    }
                    if (!lineError) {

                        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) {
                    textDisplay << "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 {
                    textDisplay << "Error: no memory slots available.\r\n";
                    lineError = true;
                }
                if (!lineError) {
                    textDisplay.debug("If statement\r\n");
                    //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 || expectingDoStatement) {
                    textDisplay << "Error: expected a 'do' statement\r\n";
                    lineError = true;
                }
                textDisplay.debug("Else statement\r\n");
                //callbacks can't have else conditions
                if ((!lineError) && (blockDepth < 2) && ((currentTriggerPort > -1)||(currentFunction > -1))) {
                    textDisplay << "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
                    textDisplay << "Error: else statement can only occur in an 'if' block\r\n";
                    lineError = true;
                }
                if (!lineError) {
                    elseFlag = true;
                    expectingDoStatement = true;

                }
            } else if (tokens[i].compare("then") == 0) { //a then block
                if (ifBlockInit || whileBlockInit) {
                    textDisplay << "Error: expected a 'do' statement\r\n";
                    lineError = true;
                }

                //trigger blocks can't have else conditions
                if ((!lineError) && (blockDepth < 2) && (currentTriggerPort > -1)) {
                    textDisplay << "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
                    textDisplay << "Error: 'then' statement can only occur in a 'while' block\r\n";
                    lineError = true;
                }
                if (!lineError) {
                    thenFlag = true;
                    expectingDoStatement = 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) {
                    textDisplay << "Error: expected a 'do' statement\r\n";
                    lineError = true;
                }
                textDisplay.debug("While statement\r\n");

                if ((currentTriggerPort > -1) || (currentFunction > -1)) { //check to make sure we are inside a trigger block


                } else {
                    textDisplay << "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 {
                    textDisplay << "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) {


                                    //tmpEvent->whileLoopPeriod = period;
                                    tmpEvent->setWhileLoopPeriod(period);
                                    if (!elseFlag) {
                                        tmpEvent->blockType = 5; //this is a while block

                                        action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS);
                                        if (tmpAction == NULL) {
                                            textDisplay << "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 {
                                    textDisplay << "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) {
                                        textDisplay << "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 {
                            textDisplay << "Error: expected a 'do every' statement\r\n";
                            lineError = true;
                        }
                    } else {
                        textDisplay << "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 || expectingDoStatement) {
                    textDisplay << "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) {
                    textDisplay << "Error: Variable can't have a space in it.\r\n";
                    lineError = true;
                }

                if (!lineError) {
                    if (blockDepth > 0) {
                        textDisplay.debug("Variable assignment statement\r\n");
                        //action* tmpAction = evaluateAssignmentForAction(tmpString);
                        action* tmpAction = evaluateAssignmentForAction(tmpString.data());
                        if (tmpAction != NULL) {
                            tmpEventPtrArray.back()->addAction(tmpAction);

                        } else {
                            lineError = true;
                        }

                    } else { //assignment was written outside of any block structure, so execute now


                        //action* tmpAction = evaluateAssignmentForAction(tmpString);
                        action* tmpAction = evaluateAssignmentForAction(tmpString.data());

                        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
                textDisplay << "Error: statement not understood.\r\n";
                lineError = true;
            }

            if (lineError) {
                 textDisplay.flush();
                 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) {

            textDisplay << "Line text: ";
            /*
            while (!tokens.empty()) {
                textDisplay << tokens.front()<< " ";
                //tokens.erase(tokens.begin());
            }*/

            //Display the line with the syntax error
            for (int tokInd = 0; tokInd < tokens.size(); tokInd++) {
                textDisplay << tokens.at(tokInd) << " ";
            }
            textDisplay << "\r\n";
            textDisplay.flush();

            currentBlock.resetBuffer();

            //Clear the line tokens
            while (!tokens.empty()) {
                tokens.pop_back();
            }

            if (tmpEventPtrArray.size() > 0) {
                tmpEventPtrArray.at(0)->release(); //release the unfinished block (and all children)
            }
            while (tmpEventPtrArray.size() > 0){
                tmpEventPtrArray.pop_back();
            }


            //delete tmpEvent;
            /*
            if (tmpEvent != NULL) {
                tmpEvent->release();
            }
            */
        } else {

            //Clear the line tokens
            while (!tokens.empty()) {
                tokens.pop_back();
            }
            //currentBlock.pop_back();

        }

    }

    //make sure that all blocks have a matching end statement


    if ((!lineError)&&(blockDepth > 0)) {
        textDisplay << "Error: Missing 1 or more end statements\r\n";
        lineError = true;
        currentBlock.resetBuffer();
    }

    if ((!lineError)&&(blockDepth == 0)) {
        textDisplay.send("~~~\r\n");
    }

    //displayMemoryLeft();
    //DisplayRAMBanks();

}


//used to return a pointer to a variable, if it exists
int* scriptStream::findIntVariable(string nameInput) {

    textDisplay.debug("Finding variable: ");
    textDisplay.debug(nameInput.data());
    int* outPtr = NULL;
    bool foundIt = false;

    //First check if the variable is the state of a port
    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 <= numDigOutPorts)) {
            outPtr = &digOutPortVector[portnum-1]->state;
            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 <= numDigInPorts)) {
            outPtr = &digInPortVector[portnum-1]->state;
            foundIt = true;
        }
    } else if (nameInput.find("analogout") != std::string::npos) {
        int pos1 = nameInput.find("analogout[")+10;
        int pos2 = nameInput.find_first_of("]",pos1);
        int portnum = atoi(nameInput.substr(pos1,pos2-pos1).data());
        int portVal = 0;
        if ((portnum > 0) && (portnum <= numAnOutPorts)) {
            outPtr = &anOutPortVector[portnum-1]->state;
            foundIt = true;
        }
    } else if (nameInput.find("analogin") != std::string::npos) {
        int pos1 = nameInput.find("analogin[")+9;
        int pos2 = nameInput.find_first_of("]",pos1);
        int portnum = atoi(nameInput.substr(pos1,pos2-pos1).data());
        int portVal = 0;
        if ((portnum > 0) && (portnum <= numAnInPorts)) {
            outPtr = &anInPortVector[portnum-1]->state;
            foundIt = true;
        }
    }

    //Then check if it is a defined int variable
    if (!foundIt) {
        std::vector<intVariable*>::size_type sz = globalVariables.size();
        int start = 0;
        int end = nameInput.length()-1;

        for (unsigned i = 0; i < sz; i++) {


            if ((findStringLoc(nameInput.data(),globalVariables[i]->tag,start,end) != -1) && (strlen(globalVariables[i]->tag)==(end-start+1))) {
                outPtr = &globalVariables[i]->value;
                break;
            }
            /*
            if (nameInput.compare(globalVariables[i]->tag) == 0) {
                outPtr = &globalVariables[i]->value;
                break;
            }*/
        }
    }
    textDisplay.debug("...done\r\n");

    return outPtr;
}


//used to return a pointer to a variable, if it exists
int* scriptStream::findIntVariable(const char* nameInput, int start, int end) {

    textDisplay.debug("Finding variable...");
    int* outPtr = NULL;
    bool foundIt = false;

    //First check if the variable is the current state of a port
    if (findStringLoc(nameInput,"portout[",start,end) != -1) {
        int pos1 = findStringLoc(nameInput,"portout[",start,end)+8;
        int pos2 = findStringLoc(nameInput, "]",pos1,end);
        if ((pos1 == -1)||(pos2 == -1)) {
            //syntax error
            return NULL;
        }

        //int portnum = atoi(nameInput.substr(pos1,pos2-pos1).data());
        long int portnum = strtol(nameInput+pos1,NULL,10);
        if ((portnum > 0) && (portnum <= numDigOutPorts)) {
            outPtr = &digOutPortVector[(int)portnum-1]->state;
            foundIt = true;
        }
    } else if (findStringLoc(nameInput,"portin[",start,end) != -1) {
        int pos1 = findStringLoc(nameInput,"portin[",start,end)+7;
        int pos2 = findStringLoc(nameInput, "]",pos1,end);
        if ((pos1 == -1)||(pos2 == -1)) {
            //syntax error
            return NULL;
        }
        long int portnum = strtol(nameInput+pos1,NULL,10);

        if ((portnum > 0) && (portnum <= numDigInPorts)) {
            outPtr = &digOutPortVector[(int)portnum-1]->state;
            foundIt = true;
        }
    } else if (findStringLoc(nameInput,"analogout[",start,end) != -1) {
        int pos1 = findStringLoc(nameInput,"analogout[",start,end)+10;
        int pos2 = findStringLoc(nameInput, "]",pos1,end);
        if ((pos1 == -1)||(pos2 == -1)) {
            //syntax error
            return NULL;
        }

        //int portnum = atoi(nameInput.substr(pos1,pos2-pos1).data());
        long int portnum = strtol(nameInput+pos1,NULL,10);
        if ((portnum > 0) && (portnum <= numAnOutPorts)) {
            outPtr = &anOutPortVector[(int)portnum-1]->state;
            foundIt = true;
        }
    } else if (findStringLoc(nameInput,"analogin[",start,end) != -1) {
        int pos1 = findStringLoc(nameInput,"portin[",start,end)+9;
        int pos2 = findStringLoc(nameInput, "]",pos1,end);
        if ((pos1 == -1)||(pos2 == -1)) {
            //syntax error
            return NULL;
        }
        long int portnum = strtol(nameInput+pos1,NULL,10);

        if ((portnum > 0) && (portnum <= numAnInPorts)) {
            outPtr = &anOutPortVector[(int)portnum-1]->state;
            foundIt = true;
        }
    }

    if (!foundIt) {
        std::vector<intVariable*>::size_type sz = globalVariables.size();
        for (unsigned i = 0; i < sz; i++) {
            //const char* varName = globalVariables[i]->tag.data();
            if ((findStringLoc(nameInput,globalVariables[i]->tag,start,end) != -1) && (strlen(globalVariables[i]->tag)==(end-start+1))) {
                outPtr = &globalVariables[i]->value;
                break;
            }
        }
    }
    textDisplay.debug("done\r\n");

    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(const char* expression) {

    //action* tmpAction = new action(); //create a new action
    action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS);
    if (tmpAction == NULL) {
        textDisplay << "Error: no action memory slots available.\r\n";
        return NULL;
    }
    int stringInd;
    int stringInd2;
    int afterEqualLoc;
    int beforeEqualLoc;
    int lastCharLoc = strlen(expression)-1;
    int multiplierInt = 1;
    //string afterEqual;
    //string beforeEqual;
    //The expression might have up to three variables
    int* tmpVar;
    int* tmpVar2;
    int* tmpVar3;

    stringInd = findStringLoc(expression,"=",0,strlen(expression)-1); //location of = sign, if it exists
    if (stringInd == -1) {
        //Make sure there is an equal sign
        return NULL;
    }

    beforeEqualLoc = stringInd-1;
    afterEqualLoc = stringInd+1;

    //location of +/- sign (only one allowed)
    stringInd2 = findStringLoc(expression,"+",afterEqualLoc,strlen(expression)-1);
    if (stringInd2 == -1) {
        stringInd2 = findStringLoc(expression,"-",afterEqualLoc,strlen(expression)-1);
        multiplierInt = -1;

    }

    tmpVar = findIntVariable(expression,0,beforeEqualLoc); //returns pointer to the variable
    if (findStringLoc(expression,"portout[",0,beforeEqualLoc) != -1) {  //set the output of a digital port
        textDisplay.debug("Portout assignment\r\n");
        int pos1 = findStringLoc(expression,"portout[",0,beforeEqualLoc)+8;
        int pos2 = findStringLoc(expression,"]",pos1,beforeEqualLoc)-1;
        if (pos2 < pos1) {
            textDisplay << "Error: expected a ] character\r\n";
            return NULL;
        }

        int portnum = -1;
        if (isNum(expression,pos1,pos2)) {
            portnum = atoi(expression+pos1);
        }
        int* tmpVar = findIntVariable(expression, pos1,pos2); //returns pointer to the variable, if given
        int portVal = 0;
        if ((tmpVar != NULL)||((portnum > 0) && (portnum <= numDigOutPorts))) {
            if (isNum(expression,afterEqualLoc,lastCharLoc)) { //a simple numeric assign
                portVal = atoi(expression+afterEqualLoc);
                if ((portVal == 0) || (portVal == 1)) {
                    //portMessage* tmpMessage = new portMessage(portVector[portnum],1,portVal);
                    portMessage* tmpMessage = findFirstUnUsed(portMessageBlock, NUMPORTMESSAGES);
                    if (tmpMessage == NULL) {
                        textDisplay << "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,digOutPortVector,numDigOutPorts);
                        } else {
                            tmpMessage->setMessage(tmpVar,0,portVal,digOutPortVector,numDigOutPorts);
                        }
                    }


                    tmpAction->set(tmpMessage);

                } else {
                    textDisplay << "Error: portouts can only be directly assigned a 1, 0 or 'flip'\r\n";
                    //delete tmpAction;
                    tmpAction->release();
                    return NULL;
                }
            } else if (findStringLoc(expression,"flip",afterEqualLoc,lastCharLoc)!=-1) {
                //portMessage* tmpMessage = new portMessage(portVector[portnum],1,-1);
                portMessage* tmpMessage = findFirstUnUsed(portMessageBlock, NUMPORTMESSAGES);
                if (tmpMessage == NULL) {
                    textDisplay << "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,digOutPortVector,numDigOutPorts);
                    } else {
                        tmpMessage->setMessage(tmpVar,0,-1,digOutPortVector,numDigOutPorts);
                    }
                }
                tmpAction->set(tmpMessage);
            } else {
                textDisplay << "Error: portouts can only be directly assigned a 1, 0, or 'flip'\r\n";
                //delete tmpAction;
                tmpAction->release();
                return NULL;
            }
        } else {
            textDisplay << "Port number not found (must be between 1 and " << numDigOutPorts << " or an existing variable)\r\n";
            //delete tmpAction;
            tmpAction->release();
            return NULL;
        }
    } else if (findStringLoc(expression,"analogout[",0,beforeEqualLoc) != -1) {  //set the output of an analog port
        textDisplay.debug("Portout assignment\r\n");
        int pos1 = findStringLoc(expression,"analogout[",0,beforeEqualLoc)+10;
        int pos2 = findStringLoc(expression,"]",pos1,beforeEqualLoc)-1;
        if (pos2 < pos1) {
            textDisplay << "Error: expected a ] character\r\n";
            return NULL;
        }

        int portnum = -1;
        if (isNum(expression,pos1,pos2)) {
            portnum = atoi(expression+pos1);
        }
        int* tmpVar = findIntVariable(expression, pos1,pos2); //returns pointer to the variable, if given
        int portVal = 0;
        if ((tmpVar != NULL)||((portnum > 0) && (portnum <= numAnOutPorts))) {
            if (isNum(expression,afterEqualLoc,lastCharLoc)) { //a simple numeric assign
                portVal = atoi(expression+afterEqualLoc);
                if ((portVal >= 0) || (portVal <= 3700)) {
                    //portMessage* tmpMessage = new portMessage(portVector[portnum],1,portVal);
                    portMessage* tmpMessage = findFirstUnUsed(portMessageBlock, NUMPORTMESSAGES);
                    if (tmpMessage == NULL) {
                        textDisplay << "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,anOutPortVector,numAnOutPorts);
                        } else {
                            tmpMessage->setMessage(tmpVar,0,portVal,anOutPortVector,numAnOutPorts);
                        }
                    }


                    tmpAction->set(tmpMessage);

                } else {
                    textDisplay << "Error: analogouts can only be directly assigned a value between 0 and 3700 mV\r\n";
                    //delete tmpAction;
                    tmpAction->release();
                    return NULL;
                }
            } else {
                textDisplay << "Error: analogouts can only be directly assigned a value between 0 and 3700 mV\r\n";
                //delete tmpAction;
                tmpAction->release();
                return NULL;
            }
        } else {
            textDisplay << "Port number not found (must be between 1 and " << numAnOutPorts << " or an existing variable)\r\n";
            //delete tmpAction;
            tmpAction->release();
            return NULL;
        }
    } else if (findStringLoc(expression,"portin",0,stringInd)!=-1) {
        textDisplay << "Error: portins can not be set\r\n";
        //delete tmpAction;
        tmpAction->release();
        return NULL;
    } else if (findStringLoc(expression,"analogin",0,stringInd)!=-1) {
        textDisplay << "Error: analog ins can not be set\r\n";
        //delete tmpAction;
        tmpAction->release();
        return NULL;
    } else if (tmpVar != NULL) {
        intOperation* tmpOp;
        intOperation* tmpOp2;
        if (isNum(expression,afterEqualLoc,lastCharLoc)) { //a simple numeric assign
            textDisplay.debug("Numeric assignment\r\n");
            //tmpOp = new intOperation(tmpVar, "=", atoi(afterEqual.data()));
            tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
            if (tmpOp == NULL) {
                textDisplay << "Error: no memory slots available.\r\n";
                tmpAction->release();
                return NULL;
            } else {
                tmpOp->set(tmpVar, "=", atoi(expression+afterEqualLoc));
            }
            tmpAction->set(tmpOp);

        } else if ((stringInd2 == -1)&&(findStringLoc(expression,"random",afterEqualLoc,lastCharLoc)!=-1)) {
            //assign random number
            //no +/- detected, so its a simple assign
            textDisplay.debug("Random number assignment\r\n");
            int highVal = getRandomParam(expression,afterEqualLoc,lastCharLoc);

            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) {
                    textDisplay << "Error: no memory slots available.\r\n";
                    tmpAction->release();
                    return NULL;
                } else {
                    tmpOp->setRandOp(highVal, "=", tmpVar, false);
                }
                tmpAction->set(tmpOp);

            } else {
                //delete tmpAction;
                tmpAction->release();
                return NULL;
            }
        } else if ((stringInd2 == -1)&&(findStringLoc(expression,"clock()",afterEqualLoc,lastCharLoc)!=-1)) {
            //assign clock value
            //no +/- detected, so its a simple assign
            textDisplay.debug("Clock assignment to variable\r\n");
            tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
            if (tmpOp == NULL) {
                textDisplay << "Error: no memory slots available.\r\n";
                tmpAction->release();
                return NULL;
            } else {
                tmpOp->setClockOp(tmpVar); //assigns the current clock value to tmpVar
            }
            tmpAction->set(tmpOp);

        } else if (stringInd2 != -1) { //a +/- operation is there
            textDisplay.debug("equation assignment\r\n");
            //string multiplier("+");
            char multiplier[3];
            if (multiplierInt==1) {
                strcpy(multiplier,"+");
            } else {
                strcpy(multiplier,"-");
            }

            /*
            if (afterEqual[stringInd2] == '-') {
                multiplier = "-";
                multiplierInt = -1;
            }*/
            tmpVar2 = findIntVariable(expression,afterEqualLoc,stringInd2-1); //before the +/- sign
            tmpVar3 = findIntVariable(expression,stringInd2+1,lastCharLoc); //after the +/- sign

            if ((tmpVar2 != NULL) && isNum(expression,stringInd2+1,lastCharLoc)) { //variable +/- number
                if (tmpVar2 == tmpVar) {
                    //final sign is += or -=
                    if (multiplierInt==1) {
                        strcpy(multiplier,"+=");
                    } else {
                        strcpy(multiplier,"-=");
                    }

                    tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                    if (tmpOp == NULL) {
                        textDisplay << "Error: no memory slots available.\r\n";
                        tmpAction->release();
                        return NULL;
                    } else {
                        tmpOp->set(tmpVar, multiplier, atoi(expression+stringInd2+1));
                    }
                    tmpAction->set(tmpOp);

                } else {

                    tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                    if (tmpOp2 == NULL) {
                        textDisplay << "Error: no memory slots available.\r\n";
                        tmpAction->release();
                        return NULL;
                    } else {

                        tmpOp2->set(tmpVar2,multiplier, atoi(expression+stringInd2+1));
                        //tmpOp->set(tmpVar, tmpOp2);
                    }

                    tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                    if (tmpOp == NULL) {
                        textDisplay << "Error: no memory slots available.\r\n";
                        tmpOp2->release();
                        tmpAction->release();
                        return NULL;
                    } else {
                        tmpOp->set(tmpVar, tmpOp2);
                    }

                    tmpAction->set(tmpOp);

                }

            } else if ((tmpVar3 != NULL) && isNum(expression,afterEqualLoc,stringInd2-1)) { //number +/- variable
                if (tmpVar3 == tmpVar) {
                    //final sign is += or -=
                    if (multiplierInt==1) {
                        strcpy(multiplier,"+=");
                    } else {
                        strcpy(multiplier,"-=");
                    }

                    tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                    if (tmpOp == NULL) {
                        textDisplay << "Error: no memory slots available.\r\n";
                        tmpAction->release();
                        return NULL;
                    } else {
                        tmpOp->set(tmpVar, multiplier, atoi(expression+afterEqualLoc));
                    }
                    tmpAction->set(tmpOp);

                } else {

                    tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                    if (tmpOp2 == NULL) {
                        textDisplay << "Error: no memory slots available.\r\n";
                        tmpAction->release();
                        return NULL;
                    } else {
                        tmpOp2->set(tmpVar3, multiplier, atoi(expression+afterEqualLoc));
                    }
                    tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);

                    if (tmpOp == NULL) {
                        textDisplay << "Error: no memory slots available.\r\n";
                        tmpOp2->release();
                        tmpAction->release();
                        return NULL;
                    } else {
                        tmpOp->set(tmpVar, tmpOp2);
                    }
                    tmpAction->set(tmpOp);

                }

            } else if ((tmpVar2 != NULL) && (tmpVar3 != NULL)) { //variable +/- variable

                tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                if (tmpOp2 == NULL) {
                    textDisplay << "Error: no memory slots available.\r\n";
                    tmpAction->release();
                    return NULL;
                } else {
                    tmpOp2->set(tmpVar2, multiplier, tmpVar3);
                }
                tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);

                if (tmpOp == NULL) {
                    textDisplay << "Error: no memory slots available.\r\n";
                    tmpOp2->release();
                    tmpAction->release();
                    return NULL;
                } else {

                    tmpOp->set(tmpVar, tmpOp2);
                }
                tmpAction->set(tmpOp);

            } else if ( isNum(expression,stringInd2+1,lastCharLoc) && isNum(expression,afterEqualLoc,stringInd2-1) ) { //number +/- number
                tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                if (tmpOp == NULL) {
                    textDisplay << "Error: no memory slots available.\r\n";
                    tmpAction->release();
                    return NULL;
                } else {
                    tmpOp->set(tmpVar, "=", atoi(expression+afterEqualLoc) + (multiplierInt * atoi(expression+stringInd2+1)) );
                }
                tmpAction->set(tmpOp);

            } else if ((findStringLoc(expression,"random", afterEqualLoc,stringInd2-1)!=-1)  && isNum(expression,stringInd2+1,lastCharLoc)) { //random +/- number
                int highVal = getRandomParam(expression,afterEqualLoc,stringInd2-1);

                if (highVal > 0) {


                    tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                    if (tmpOp2 == NULL) {
                        textDisplay << "Error: no memory slots available.\r\n";
                        tmpAction->release();
                        return NULL;
                    } else {
                        tmpOp2->setRandOp(highVal, multiplier, atoi(expression+stringInd2+1),false);
                    }
                    tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);

                    if (tmpOp == NULL) {
                        textDisplay << "Error: no memory slots available.\r\n";
                        tmpOp2->release();
                        tmpAction->release();
                        return NULL;
                    } else {
                        tmpOp->set(tmpVar, tmpOp2);
                    }
                    tmpAction->set(tmpOp);

                } else {
                    //delete tmpAction;
                    tmpAction->release();
                    return NULL;
                }
            } else if ((findStringLoc(expression,"random",afterEqualLoc,stringInd2-1)!=-1) && (tmpVar3 != NULL)) { //random +/- variable
                int highVal = getRandomParam(expression,afterEqualLoc,stringInd2-1);

                if (highVal > 0) {


                    tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                    if (tmpOp2 == NULL) {
                        textDisplay << "Error: no memory slots available.\r\n";
                        tmpAction->release();
                        return NULL;
                    } else {
                        tmpOp2->setRandOp(highVal, multiplier, tmpVar3, false);
                    }
                    tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                    if (tmpOp == NULL) {
                        textDisplay << "Error: no memory slots available.\r\n";
                        tmpOp2->release();
                        tmpAction->release();
                        return NULL;
                    } else {
                        tmpOp->set(tmpVar, tmpOp2);
                    }
                    tmpAction->set(tmpOp);

                } else {
                    //delete tmpAction;
                    tmpAction->release();
                    return NULL;
                }


            } else if ((findStringLoc(expression,"random",stringInd2+1,lastCharLoc)!=-1) && isNum(expression,afterEqualLoc,stringInd2-1)) { //number +/- random
                int highVal = getRandomParam(expression,stringInd2+1,lastCharLoc);

                if (highVal > 0) {


                    tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                    if (tmpOp2 == NULL) {
                        textDisplay << "Error: no memory slots available.\r\n";
                        tmpAction->release();
                        return NULL;
                    } else {

                        tmpOp2->setRandOp(highVal, multiplier, atoi(expression+afterEqualLoc),true); //the "true" signifies that the rand value came last
                    }
                    tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                    if (tmpOp == NULL) {
                        textDisplay << "Error: no memory slots available.\r\n";
                        tmpOp2->release();
                        tmpAction->release();
                        return NULL;
                    } else {
                        tmpOp->set(tmpVar, tmpOp2);
                    }
                    tmpAction->set(tmpOp);

                } else {
                    //delete tmpAction;
                    tmpAction->release();
                    return NULL;
                }
            } else if ((findStringLoc(expression,"random",stringInd2+1,lastCharLoc)!=-1) && (tmpVar2 != NULL)) { //variable +/- random
                int highVal = getRandomParam(expression,stringInd2+1,lastCharLoc);

                if (highVal > 0) {


                    tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                    if (tmpOp2 == NULL) {
                        textDisplay << "Error: no memory slots available.\r\n";
                        tmpAction->release();
                        return NULL;
                    } else {

                        tmpOp2->setRandOp(highVal, multiplier, tmpVar2, true); //the "true" signifies that the rand value came last
                    }
                    tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                    if (tmpOp == NULL) {
                        textDisplay << "Error: no memory slots available.\r\n";
                        tmpOp2->release();
                        tmpAction->release();
                        return NULL;
                    } else {
                        tmpOp->set(tmpVar, tmpOp2);
                    }
                    tmpAction->set(tmpOp);

                } else {
                    //delete tmpAction;
                    tmpAction->release();
                    return NULL;
                }
            }


            else if ((findStringLoc(expression,"clock()",afterEqualLoc,stringInd2-1)!=-1) && isNum(expression,stringInd2+1,lastCharLoc)) { //clock() +/- number

                tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                if (tmpOp2 == NULL) {
                    textDisplay << "Error: no memory slots available.\r\n";
                    tmpAction->release();
                    return NULL;
                } else {
                    tmpOp2->setClockOp(multiplier, atoi(expression+stringInd2+1),false);
                }
                tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);

                if (tmpOp == NULL) {
                    textDisplay << "Error: no memory slots available.\r\n";
                    tmpOp2->release();
                    tmpAction->release();
                    return NULL;
                } else {
                    tmpOp->set(tmpVar, tmpOp2);
                }
                tmpAction->set(tmpOp);


            } else if ((findStringLoc(expression,"clock()",afterEqualLoc,stringInd2-1)!=-1) && (tmpVar3 != NULL)) { //clock() +/- variable



                tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                if (tmpOp2 == NULL) {
                    textDisplay << "Error: no memory slots available.\r\n";
                    tmpAction->release();
                    return NULL;
                } else {
                    tmpOp2->setClockOp(multiplier, tmpVar3, false);
                }
                tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                if (tmpOp == NULL) {
                    textDisplay << "Error: no memory slots available.\r\n";
                    tmpOp2->release();
                    tmpAction->release();
                    return NULL;
                } else {
                    tmpOp->set(tmpVar, tmpOp2);
                }
                tmpAction->set(tmpOp);

            } else if ((findStringLoc(expression,"clock()",stringInd2+1,lastCharLoc)!=-1) && isNum(expression,afterEqualLoc,lastCharLoc)) { //number +/- clock()

                tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                if (tmpOp2 == NULL) {
                    textDisplay << "Error: no memory slots available.\r\n";
                    tmpAction->release();
                    return NULL;
                } else {

                    tmpOp2->setClockOp(multiplier, atoi(expression+afterEqualLoc), true); //the "true" signifies that clock() came last
                }
                tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                if (tmpOp == NULL) {
                    textDisplay << "Error: no memory slots available.\r\n";
                    tmpOp2->release();
                    tmpAction->release();
                    return NULL;
                } else {
                    tmpOp->set(tmpVar, tmpOp2);
                }
                tmpAction->set(tmpOp);


            } else if ((findStringLoc(expression,"clock()",stringInd2+1,lastCharLoc)!=-1) && (tmpVar2 != NULL)) { //variable +/- clock()


                tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                if (tmpOp2 == NULL) {
                    textDisplay << "Error: no memory slots available.\r\n";
                    tmpAction->release();
                    return NULL;
                } else {

                    tmpOp2->setClockOp(multiplier, tmpVar2, true); //the "true" signifies that clock() came last
                }
                tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                if (tmpOp == NULL) {
                    textDisplay << "Error: no memory slots available.\r\n";
                    tmpOp2->release();
                    tmpAction->release();
                    return NULL;
                } else {
                    tmpOp->set(tmpVar, tmpOp2);
                }
                tmpAction->set(tmpOp);


            }

            else {
                textDisplay << "Expression not understood: " << expression << "\r\n";
                //delete tmpAction;
                tmpAction->release();
                return NULL;
            }

        } else if (findIntVariable(expression,afterEqualLoc,lastCharLoc) != NULL) { //assign value of another variable
            tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
            if (tmpOp == NULL) {
                textDisplay << "Error: no memory slots available.\r\n";
                tmpAction->release();
                return NULL;
            } else {
                tmpOp->set(tmpVar, "=", findIntVariable(expression,afterEqualLoc,lastCharLoc));
            }
            tmpAction->set(tmpOp);

        } else {
            textDisplay << "Variable not found: " << expression+afterEqualLoc << "\r\n";
            tmpAction->release();
            return NULL;
        }

    } else {
        textDisplay << "Variable not found\r\n";
        tmpAction->release();
        return NULL;
    }
    textDisplay.debug("Assignment successful\r\n");
    return tmpAction;
}

action* scriptStream::evaluateAssignmentForAction(string expression) {

    //action* tmpAction = new action(); //create a new action
    action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS);
    if (tmpAction == NULL) {
        textDisplay << "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
        textDisplay.debug("Portout assignment\r\n");
        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 <= numDigOutPorts))) {
            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) {
                        textDisplay << "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,digOutPortVector,numDigOutPorts);
                        } else {
                            tmpMessage->setMessage(tmpVar,0,portVal,digOutPortVector,numDigOutPorts);
                        }
                    }


                    tmpAction->set(tmpMessage);

                } else {
                    textDisplay << "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) {
                    textDisplay << "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,digOutPortVector,numDigOutPorts);
                    } else {
                        tmpMessage->setMessage(tmpVar,0,-1,digOutPortVector,numDigOutPorts);
                    }
                }
                tmpAction->set(tmpMessage);
            } else {
                textDisplay << "Error: portouts can only be directly assigned a 1, 0, or 'flip'\r\n";
                //delete tmpAction;
                tmpAction->release();
                return NULL;
            }
        } else {
            textDisplay << "Port number not found (must be between 1 and " << numDigOutPorts << " or an existing variable)\r\n";
            //delete tmpAction;
            tmpAction->release();
            return NULL;
        }
    } else if (beforeEqual.find("analogout[") != std::string::npos) { //set the output of a digital port
        textDisplay.debug("Portout assignment\r\n");
        int pos1 = beforeEqual.find("analogout[")+10;
        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 <= numAnOutPorts))) {
            if (isNumber(afterEqual)) { //a simple numeric assign
                portVal = atoi(afterEqual.data());
                if ((portVal >= 0) || (portVal <= 3700)) {
                    //portMessage* tmpMessage = new portMessage(portVector[portnum],1,portVal);
                    portMessage* tmpMessage = findFirstUnUsed(portMessageBlock, NUMPORTMESSAGES);
                    if (tmpMessage == NULL) {
                        textDisplay << "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,anOutPortVector,numAnOutPorts);
                        } else {
                            tmpMessage->setMessage(tmpVar,0,portVal,anOutPortVector,numAnOutPorts);
                        }
                    }


                    tmpAction->set(tmpMessage);

                } else {
                    textDisplay << "Error: analogouts can only be directly assigned a value between 0 and 3700 mV \r\n";
                    //delete tmpAction;
                    tmpAction->release();
                    return NULL;
                }
            } else {
                textDisplay << "Error: analogouts can only be directly assigned a value between 0 and 3700 mV\r\n";
                //delete tmpAction;
                tmpAction->release();
                return NULL;
            }
        } else {
            textDisplay << "Port number not found (must be between 1 and " << numAnOutPorts << " or an existing variable)\r\n";
            //delete tmpAction;
            tmpAction->release();
            return NULL;
        }
    } else if (beforeEqual.find("portin") != std::string::npos) {
        textDisplay << "Error: portins can not be set\r\n";
        //delete tmpAction;
        tmpAction->release();
        return NULL;
    } else if (beforeEqual.find("analogin") != std::string::npos) {
        textDisplay << "Error: analog ins 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
            textDisplay.debug("Numeric assignment\r\n");
            //tmpOp = new intOperation(tmpVar, "=", atoi(afterEqual.data()));
            tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
            if (tmpOp == NULL) {
                textDisplay << "Error: no memory slots available.\r\n";
                tmpAction->release();
                return NULL;
            } else {
                tmpOp->set(tmpVar, "=", atoi(afterEqual.data()));
            }
            tmpAction->set(tmpOp);

        } else if ((stringInd2 == std::string::npos)&&(afterEqual.find("random") != std::string::npos)) {
            //assign random number
            //no +/- detected, so its a simple assign
            textDisplay.debug("Random number assignment\r\n");
            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) {
                    textDisplay << "Error: no memory slots available.\r\n";
                    tmpAction->release();
                    return NULL;
                } else {
                    tmpOp->setRandOp(highVal, "=", tmpVar, false);
                }
                tmpAction->set(tmpOp);

            } else {
                //delete tmpAction;
                tmpAction->release();
                return NULL;
            }
        } else if ((stringInd2 == std::string::npos)&&(afterEqual.find("clock()") != std::string::npos)) {
            //assign clock value
            //no +/- detected, so its a simple assign
            textDisplay.debug("Clock assignment to variable\r\n");
            tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
            if (tmpOp == NULL) {
                textDisplay << "Error: no memory slots available.\r\n";
                tmpAction->release();
                return NULL;
            } else {
                tmpOp->setClockOp(tmpVar); //assigns the current clock value to tmpVar
            }
            tmpAction->set(tmpOp);

        } else if (stringInd2 != std::string::npos) { //a +/- operation is there
            textDisplay.debug("equation assignment\r\n");
            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) {
                        textDisplay << "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);

                } else {

                    tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                    if (tmpOp2 == NULL) {
                        textDisplay << "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) {
                        textDisplay << "Error: no memory slots available.\r\n";
                        tmpOp2->release();
                        tmpAction->release();
                        return NULL;
                    } else {
                        tmpOp->set(tmpVar, tmpOp2);
                    }

                    tmpAction->set(tmpOp);

                }

            } 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) {
                        textDisplay << "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);

                } else {

                    tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                    if (tmpOp2 == NULL) {
                        textDisplay << "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) {
                        textDisplay << "Error: no memory slots available.\r\n";
                        tmpOp2->release();
                        tmpAction->release();
                        return NULL;
                    } else {
                        tmpOp->set(tmpVar, tmpOp2);
                    }
                    tmpAction->set(tmpOp);

                }

            } else if ((tmpVar2 != NULL) && (tmpVar3 != NULL)) { //variable +/- variable

                tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                if (tmpOp2 == NULL) {
                    textDisplay << "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) {
                    textDisplay << "Error: no memory slots available.\r\n";
                    tmpOp2->release();
                    tmpAction->release();
                    return NULL;
                } else {

                    tmpOp->set(tmpVar, tmpOp2);
                }
                tmpAction->set(tmpOp);

            } else if ( isNumber(afterEqual.substr(stringInd2+1,std::string::npos)) && isNumber(afterEqual.substr(0,stringInd2)) ) { //number +/- number
                tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                if (tmpOp == NULL) {
                    textDisplay << "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);

            } 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) {
                        textDisplay << "Error: no memory slots available.\r\n";
                        tmpAction->release();
                        return NULL;
                    } else {
                        tmpOp2->setRandOp(highVal, multiplier.data(), atoi(afterEqual.substr(stringInd2+1,std::string::npos).data()),false);
                    }
                    tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);

                    if (tmpOp == NULL) {
                        textDisplay << "Error: no memory slots available.\r\n";
                        tmpOp2->release();
                        tmpAction->release();
                        return NULL;
                    } else {
                        tmpOp->set(tmpVar, tmpOp2);
                    }
                    tmpAction->set(tmpOp);

                } 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) {
                        textDisplay << "Error: no memory slots available.\r\n";
                        tmpAction->release();
                        return NULL;
                    } else {
                        tmpOp2->setRandOp(highVal, multiplier.data(), tmpVar3, false);
                    }
                    tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                    if (tmpOp == NULL) {
                        textDisplay << "Error: no memory slots available.\r\n";
                        tmpOp2->release();
                        tmpAction->release();
                        return NULL;
                    } else {
                        tmpOp->set(tmpVar, tmpOp2);
                    }
                    tmpAction->set(tmpOp);

                } 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))) { //number +/- random
                int highVal = getRandomParam(afterEqual.substr(stringInd2+1,std::string::npos));

                if (highVal > 0) {


                    tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                    if (tmpOp2 == NULL) {
                        textDisplay << "Error: no memory slots available.\r\n";
                        tmpAction->release();
                        return NULL;
                    } else {

                        tmpOp2->setRandOp(highVal, multiplier.data(), atoi(afterEqual.substr(0, stringInd2).data()),true); //the "true" signifies that the rand value came last
                    }
                    tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                    if (tmpOp == NULL) {
                        textDisplay << "Error: no memory slots available.\r\n";
                        tmpOp2->release();
                        tmpAction->release();
                        return NULL;
                    } else {
                        tmpOp->set(tmpVar, tmpOp2);
                    }
                    tmpAction->set(tmpOp);

                } else {
                    //delete tmpAction;
                    tmpAction->release();
                    return NULL;
                }
            } else if ((afterEqual.substr(stringInd2+1,std::string::npos).find("random") != std::string::npos) && (tmpVar2 != NULL)) { //variable +/- random
                int highVal = getRandomParam(afterEqual.substr(stringInd2+1,std::string::npos));

                if (highVal > 0) {


                    tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                    if (tmpOp2 == NULL) {
                        textDisplay << "Error: no memory slots available.\r\n";
                        tmpAction->release();
                        return NULL;
                    } else {

                        tmpOp2->setRandOp(highVal, multiplier.data(), tmpVar2, true); //the "true" signifies that the rand value came last
                    }
                    tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                    if (tmpOp == NULL) {
                        textDisplay << "Error: no memory slots available.\r\n";
                        tmpOp2->release();
                        tmpAction->release();
                        return NULL;
                    } else {
                        tmpOp->set(tmpVar, tmpOp2);
                    }
                    tmpAction->set(tmpOp);

                } else {
                    //delete tmpAction;
                    tmpAction->release();
                    return NULL;
                }
            }





            else if ((afterEqual.substr(0,stringInd2).find("clock()") != std::string::npos) && isNumber(afterEqual.substr(stringInd2+1,std::string::npos))) { //clock() +/- number



                tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                if (tmpOp2 == NULL) {
                    textDisplay << "Error: no memory slots available.\r\n";
                    tmpAction->release();
                    return NULL;
                } else {
                    tmpOp2->setClockOp(multiplier.data(), atoi(afterEqual.substr(stringInd2+1,std::string::npos).data()),false);
                }
                tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);

                if (tmpOp == NULL) {
                    textDisplay << "Error: no memory slots available.\r\n";
                    tmpOp2->release();
                    tmpAction->release();
                    return NULL;
                } else {
                    tmpOp->set(tmpVar, tmpOp2);
                }
                tmpAction->set(tmpOp);


            } else if ((afterEqual.substr(0,stringInd2).find("clock()") != std::string::npos) && (tmpVar3 != NULL)) { //clock() +/- variable



                tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                if (tmpOp2 == NULL) {
                    textDisplay << "Error: no memory slots available.\r\n";
                    tmpAction->release();
                    return NULL;
                } else {
                    tmpOp2->setClockOp(multiplier.data(), tmpVar3, false);
                }
                tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                if (tmpOp == NULL) {
                    textDisplay << "Error: no memory slots available.\r\n";
                    tmpOp2->release();
                    tmpAction->release();
                    return NULL;
                } else {
                    tmpOp->set(tmpVar, tmpOp2);
                }
                tmpAction->set(tmpOp);




            } else if ((afterEqual.substr(stringInd2+1,std::string::npos).find("clock()") != std::string::npos) && isNumber(afterEqual.substr(0,stringInd2))) { //number +/- clock()



                tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                if (tmpOp2 == NULL) {
                    textDisplay << "Error: no memory slots available.\r\n";
                    tmpAction->release();
                    return NULL;
                } else {

                    tmpOp2->setClockOp(multiplier.data(), atoi(afterEqual.substr(0, stringInd2).data()),true); //the "true" signifies that clock() came last
                }
                tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                if (tmpOp == NULL) {
                    textDisplay << "Error: no memory slots available.\r\n";
                    tmpOp2->release();
                    tmpAction->release();
                    return NULL;
                } else {
                    tmpOp->set(tmpVar, tmpOp2);
                }
                tmpAction->set(tmpOp);


            } else if ((afterEqual.substr(stringInd2+1,std::string::npos).find("clock()") != std::string::npos) && (tmpVar2 != NULL)) { //variable +/- clock()


                tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                if (tmpOp2 == NULL) {
                    textDisplay << "Error: no memory slots available.\r\n";
                    tmpAction->release();
                    return NULL;
                } else {

                    tmpOp2->setClockOp(multiplier.data(), tmpVar2, true); //the "true" signifies that clock() came last
                }
                tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS);
                if (tmpOp == NULL) {
                    textDisplay << "Error: no memory slots available.\r\n";
                    tmpOp2->release();
                    tmpAction->release();
                    return NULL;
                } else {
                    tmpOp->set(tmpVar, tmpOp2);
                }
                tmpAction->set(tmpOp);


            }

            else {
                textDisplay << "Expression not understood: " << afterEqual << "\r\n";
                //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) {
                textDisplay << "Error: no memory slots available.\r\n";
                tmpAction->release();
                return NULL;
            } else {
                tmpOp->set(tmpVar, "=", findIntVariable(afterEqual));
            }
            tmpAction->set(tmpOp);

        } else {
            textDisplay << "Variable not found: " << afterEqual << "\r\n";
            //delete tmpAction;
            tmpAction->release();
            return NULL;
        }

    } else {
        textDisplay << "Variable not found\r\n";
        //delete tmpAction;
        tmpAction->release();
        return NULL;
    }
    textDisplay.debug("Assignment successful\r\n");
    return tmpAction;
}

/*
bool scriptStream::isOutsideParenth(string& expression,std::size_t foundItem) {

    int pDepth = 0;  // How many nested parentheses

    if (foundItem < expression.length()) {
        for (int i = 0; i <= foundItem; i++) {
            if (expression[i] == '(') {
                pDepth++;
            } else if (expression[i] == ')') {
                pDepth--;
            }
        }
        if (pDepth<=0) {

            return true;
        } else {

            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.



    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;

    found = findFirstOrOutsideParenth(expression);
    if (found==std::string::npos) { //no or conditions outside parentheses found, so we look for AND conditions
        currentOperator = 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] == ')')) {

            expression = expression.substr(1,expression.length()-2);
            removedParenth = true;
        }
        if (removedParenth) { //we removed parentheses, so try again
            textDisplay.debug("Condition: parenth removed\r\n");
            return parseConditions(expression);
        } else {
            singleCondition = true; //we assume that the condition is non-compound, i.e., a>b
        }
    }

    if (singleCondition) { //no compound conditions found
        textDisplay.debug("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 = "==";
            textDisplay.debug("==\r\n");
        } else if ((equalStringInd == std::string::npos) && (greaterOrEqualStringInd != std::string::npos) &&
                   (lessThanOrEqualStringInd == std::string::npos) && (notEqualStringInd == std::string::npos)){

            generalCompareStringInd = greaterOrEqualStringInd;
            compareString = ">=";
            textDisplay.debug(">=\r\n");
        } else if ((equalStringInd == std::string::npos) && (greaterOrEqualStringInd == std::string::npos) &&
                   (lessThanOrEqualStringInd != std::string::npos) && (notEqualStringInd == std::string::npos)){

            generalCompareStringInd = lessThanOrEqualStringInd;
            compareString = "<=";
            textDisplay.debug("<=\r\n");
        } else if ((equalStringInd == std::string::npos) && (greaterOrEqualStringInd == std::string::npos) &&
                   (lessThanOrEqualStringInd == std::string::npos) && (notEqualStringInd != std::string::npos)){

            generalCompareStringInd = notEqualStringInd;
            compareString = "!=";
            textDisplay.debug("!=\r\n");
        } 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;
            textDisplay.debug(">\r\n");
        } 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;
            textDisplay.debug("<\r\n");

        }else {
            textDisplay << "Condition not understood: " << expression << "\r\n";
            return 0;
        }
        textDisplay.debug("Allocating memory for condition...");
        intCompare* newCompare = findFirstUnUsed(intCompareBlock, NUMINTCOMPARE);

        if (newCompare == NULL) {
            textDisplay << "Error: No memory slots available.";
            return NULL;
        }
        newCondition = findFirstUnUsed(conditionBlock, NUMCONDITIONS);
        if (newCondition == NULL) {
            textDisplay << "Error: No memory slots available.";
            return NULL;
        }
        textDisplay.debug("success.\r\n");
        beforeComparator.reserve(tmpCondition.length());
        textDisplay << beforeComparator.capacity();
        textDisplay.flush();

        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));
                textDisplay.debug("Compare variable to variable\r\n");
                newCompare->set(tmpVar,compareString.data(),tmpVar2);
                newCondition->set(newCompare);


            } else if (isNumber(afterComparator)) {
                //intCompare* newCompare = new intCompare(tmpVar,compareString.data(),atoi(afterComparator.data()));
                //currentEvent->addCondition(new condition(newCompare));
                textDisplay.debug("Compare variable to number\r\n");
                newCompare->set(tmpVar,compareString.data(),atoi(afterComparator.data()));
                newCondition->set(newCompare);


            } //more here

        } else {
            textDisplay << "Condition not understood: " << expression << "\r\n";

            return NULL;
        }

    } else { //this is a compound condition (with either && or ||)
        textDisplay.debug("Compound condition\r\n");
        afterComparator = expression.substr(found+2,std::string::npos);
        beforeComparator = expression.substr(0,found);
        newCondition = findFirstUnUsed(conditionBlock, NUMCONDITIONS);
        if (newCondition == NULL) {
            textDisplay << "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::isOutsideParenth(const char* expression,int foundItem,int start, int end) {

    int pDepth = 0;  // How many nested parentheses

    if ((foundItem >= start)&&(foundItem<=end)&&(foundItem < strlen(expression))&&(end < strlen(expression))&&(start <= end)&&(start>=0)) {
        for (int i = start; i <= foundItem; i++) {
            if (expression[i] == '(') {
                pDepth++;
            } else if (expression[i] == ')') {
                pDepth--;
            }
        }
        if (pDepth<=0) {

            return true;
        } else {

            return false;
        }
    } else {
        //error handling defaults in a true condition
        return true;
    }

}

int scriptStream::findFirstOrOutsideParenth(const char* expression,int start, int end) {

    int foundItem = findStringLoc(expression,"||",start,end);
    while (foundItem != -1) {
        if (isOutsideParenth(expression,foundItem,start,end)) {
            //it's out side of ()
            break;
        }
        //not outside ()
        foundItem = findStringLoc(expression,"||",foundItem+1,end);
    }
    return foundItem;
}

int scriptStream::findFirstAndOutsideParenth(const char* expression,int start, int end) {

    int foundItem = findStringLoc(expression,"&&",start,end);
    while (foundItem != -1) {
        if (isOutsideParenth(expression,foundItem,start,end)){
            break;
        }
        foundItem = findStringLoc(expression,"||",foundItem+1,end);
    }
    return foundItem;
}


condition* scriptStream::parseConditions(const char* expression,int start, int end) {


    //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.



    condition* newCondition = NULL;
    bool singleCondition = false; //no compound conditions
    //string afterComparator;
    //string beforeComparator;
    int afterComparatorLoc;
    int beforeComparatorLoc;



    int 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;

    found = findFirstOrOutsideParenth(expression,start,end);
    if (found==-1) { //no or conditions outside parentheses found, so we look for AND conditions
        currentOperator = AND_CONDITION;

        found = findFirstAndOutsideParenth(expression,start,end);
    }
    if (found==-1) { //no or/and conditions outside parentheses found
        //if the expression is encapsulated in parentheses, remove the parentheses
        bool removedParenth = false;
        if ((expression[start] == '(') && (expression[end] == ')')) {

            start++;
            end--;

            //expression = expression.substr(1,expression.length()-2);
            removedParenth = true;
        }
        if (removedParenth) { //we removed parentheses, so try again
            textDisplay.debug("Condition: parenth removed\r\n");
            return parseConditions(expression,start,end);
        } else {
            singleCondition = true; //we assume that the condition is non-compound, i.e., a>b
        }
    }

    if (singleCondition) { //no compound conditions found
        textDisplay.debug("Single condition: ");
        int equalStringInd;
        int greaterOrEqualStringInd;
        int lessThanOrEqualStringInd;
        int notEqualStringInd;
        int greaterThanStringInd;
        int lessThanStringInd;
        int generalCompareStringInd;


        //string tmpCondition = expression;
        char compareString[3];
        //The expression might have up to three variables
        int* tmpVar;
        int* tmpVar2;
        //int* tmpVar3;

        int offset = 0;
        equalStringInd = findStringLoc(expression,"==",start,end);  //location of comparator
        greaterOrEqualStringInd = findStringLoc(expression,">=",start,end); //location of comparator
        lessThanOrEqualStringInd = findStringLoc(expression,"<=",start,end); //location of comparator
        notEqualStringInd = findStringLoc(expression,"!=",start,end); //location of comparator
        greaterThanStringInd = findStringLoc(expression,">",start,end); //location of comparator
        lessThanStringInd = findStringLoc(expression,"<",start,end); //location of comparator

        if ((equalStringInd != -1) && (greaterOrEqualStringInd == -1) &&
            (lessThanOrEqualStringInd == -1) && (notEqualStringInd == -1)){

            generalCompareStringInd = equalStringInd;
            strcpy(compareString,"==");
            //compareString = "==";
            textDisplay.debug("==\r\n");
        } else if ((equalStringInd == -1) && (greaterOrEqualStringInd != -1) &&
                   (lessThanOrEqualStringInd == -1) && (notEqualStringInd == -1)){

            generalCompareStringInd = greaterOrEqualStringInd;
            strcpy(compareString,">=");
            //compareString = ">=";
            textDisplay.debug(">=\r\n");
        } else if ((equalStringInd == -1) && (greaterOrEqualStringInd == -1) &&
                   (lessThanOrEqualStringInd != -1) && (notEqualStringInd == -1)){

            generalCompareStringInd = lessThanOrEqualStringInd;
            strcpy(compareString,"<=");
            //compareString = "<=";
            textDisplay.debug("<=\r\n");
        } else if ((equalStringInd == -1) && (greaterOrEqualStringInd == -1) &&
                   (lessThanOrEqualStringInd == -1) && (notEqualStringInd != -1)){

            generalCompareStringInd = notEqualStringInd;
            strcpy(compareString,"!=");
            //compareString = "!=";
            textDisplay.debug("!=\r\n");
        } else if ((equalStringInd == -1) && (greaterOrEqualStringInd == -1) &&
                   (lessThanOrEqualStringInd == -1) && (notEqualStringInd == -1) &&
                   (greaterThanStringInd != -1) && (lessThanStringInd == -1)){

            generalCompareStringInd = greaterThanStringInd;
            strcpy(compareString,">");
            //compareString = ">";
            offset = 1;
            textDisplay.debug(">\r\n");
        } else if ((equalStringInd == -1) && (greaterOrEqualStringInd == -1) &&
                   (lessThanOrEqualStringInd == -1) && (notEqualStringInd == -1) &&
                   (greaterThanStringInd == -1) && (lessThanStringInd != -1)){

            generalCompareStringInd = lessThanStringInd;
            strcpy(compareString,"<");
            //compareString = "<";
            offset = 1;
            textDisplay.debug("<\r\n");

        }else {
            textDisplay << "Condition not understood: " << expression << "\r\n";
            return 0;
        }
        textDisplay.debug("Allocating memory for condition...");
        intCompare* newCompare = findFirstUnUsed(intCompareBlock, NUMINTCOMPARE);

        if (newCompare == NULL) {
            textDisplay << "Error: No memory slots available.";
            return NULL;
        }
        newCondition = findFirstUnUsed(conditionBlock, NUMCONDITIONS);
        if (newCondition == NULL) {
            textDisplay << "Error: No memory slots available.";
            return NULL;
        }
        textDisplay.debug("success.\r\n");
        //beforeComparator.reserve(tmpCondition.length());
        //textDisplay << beforeComparator.capacity();
        //textDisplay.flush();

        afterComparatorLoc = generalCompareStringInd+2-offset;
        beforeComparatorLoc = generalCompareStringInd-1;

        //afterComparator = tmpCondition.substr(generalCompareStringInd+2-offset,std::string::npos);
        //beforeComparator = tmpCondition.substr(0,generalCompareStringInd);

        //tmpVar = findIntVariable(beforeComparator); //returns pointer to the variable
        tmpVar = findIntVariable(expression,start,beforeComparatorLoc);

        if (tmpVar != NULL) { //before the comparator is a single variable
            tmpVar2 = findIntVariable(expression, afterComparatorLoc, end); //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));
                textDisplay.debug("Compare variable to variable\r\n");
                newCompare->set(tmpVar,compareString,tmpVar2);
                newCondition->set(newCompare);


            } else if (isNum(expression, afterComparatorLoc, end)) {
                //intCompare* newCompare = new intCompare(tmpVar,compareString.data(),atoi(afterComparator.data()));
                //currentEvent->addCondition(new condition(newCompare));
                textDisplay.debug("Compare variable to number\r\n");
                newCompare->set(tmpVar,compareString,atoi(expression+afterComparatorLoc));
                newCondition->set(newCompare);


            } else {
                textDisplay << "Condition not understood: " << expression << "\r\n";
                return NULL;
            }//more here

        } else {
            textDisplay << "Condition not understood: " << expression << "\r\n";

            return NULL;
        }

    } else { //this is a compound condition (with either && or ||)
        textDisplay.debug("Compound condition\r\n");
        afterComparatorLoc = found+2;
        beforeComparatorLoc = found-1;
        //afterComparator = expression.substr(found+2,std::string::npos);
        //beforeComparator = expression.substr(0,found);
        newCondition = findFirstUnUsed(conditionBlock, NUMCONDITIONS);
        if (newCondition == NULL) {
            textDisplay << "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(expression,start,beforeComparatorLoc);
        if (cond1 == NULL) {
            newCondition->release();
            return NULL;
        }
        condition* cond2 = parseConditions(expression,afterComparatorLoc,end);
        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);
    newCondition = parseConditions(expression.data(),0,expression.length()-1);
    if (newCondition == NULL) {
        return false;
    } else {
        currentEvent->addCondition(newCondition);
        return true;
    }
}

int scriptStream::getRandomParam(const char* expression,int start, int end) {

    int pos1 = findStringLoc(expression,"random(",start,end)+7;
    int pos2 = findStringLoc(expression,")",pos1,end);
    if (pos2 == -1) {
        textDisplay << "Error: bad syntax\r\n";
        return 0;
    }

    int highVal = atoi(expression+pos1);

    if ((highVal > 0)) {
        return highVal;
    } else {
        textDisplay << "Error: random parameter must be 1 or more\r\n";
        return 0;
    }
}

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 {
        textDisplay << "Error: random parameter must be 1 or more\r\n";
        return 0;
    }
}

int scriptStream::findStringLoc(const char *refString, const char *findString,int start,int end) {
    //look for 'findString' inside 'refString', only considering characters in between 'start' and 'end'
    //return -1 if not found

    if ((start < strlen(refString))&&(end < strlen(refString))&&(end >= start)) {
        const char* charPtr = strstr(refString+start,findString);
        //if found, make sure it was containted within the start and end bounds
        if ((charPtr != NULL) && ((int)(charPtr-refString) <= (end-strlen(findString)+1))) {
            return (int)(charPtr-refString);
        }
    }
    return -1;
}

bool scriptStream::isNum(const char *expression, int start, int end) {

    if ((start>0)&&(end<strlen(expression))&&(start<=end)) {

        bool outcome = true;
        while (start <= end) {
            //look for any digit, or a - sign
            if (!((expression[start] >= 45) && (expression[start] <= 57) && (expression[start] != 46) && (expression[start] != 47))) {
                outcome = false;
                break;
            }
            start++;
        }
        return outcome;
    }
    return false;
}

bool scriptStream::areStringsSame(const char *str1, const char *str2, int start, int end) {
    if ((findStringLoc(str1,str2,start,end) != -1) && (strlen(str2)==(end-start+1))) {
        return true;
    } else {
        return false;
    }


}

void scriptStream::clearEnvironmentVariables(int clearMode) {
    //Modes:

    //clear callbacks, functions, and queue
    if (clearMode & BLOCKMEMORYTYPES) {
        for (int pNum = 0; pNum < NUMDIGINPORTS+NUMDIGOUTPORTS+NUMANINPORTS+NUMANOUTPORTS; 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;

        }
        for (int i = 0; i < NUMFUNCTIONS; i++) {
            functionSpotTaken[i] = false;
            functionEventArray[i] = NULL;
        }
        for (int i = 0; i < NUMEVENTS; i++) {
            eventBlock[i].release();
        }
        for (int i = 0; i < NUMCONDITIONS; i++) {
            conditionBlock[i].release();
        }
        for (int i = 0; i < NUMINTCOMPARE; i++) {
            intCompareBlock[i].release();
        }
        for (int i = 0; i < NUMACTIONS; i++) {
            actionBlock[i].release();
        }
        for (int i = 0; i < NUMPORTMESSAGES; i++) {
            portMessageBlock[i].release();
        }
        for (int i = 0; i < NUMINTOPERATIONS; i++) {
            intOperationBlock[i].release();
        }
        for (int i = 0; i < NUMDISPLAYACTIONS; i++) {
            displayActionBlock[i].release();
        }
        for (int i = 0; i <NUMTRIGGERACTIONS; i++) {
            triggerFunctionActionBlock[i].release();
        }

        queuePtr->eraseQueue();
    }

    if (clearMode & VARIABLEMEMORYTYPES) {
        while (!globalVariables.empty()) {
            delete globalVariables.back();
            globalVariables.pop_back();
        }
    }

    if (clearMode & ENVSETTINGSMEMORYTYPES) {
        //set all environment settings to default values
        broadCastStateChanges = false;
        for (int i=0;i<NUMDIGINPORTS;i++) {
            //system->setPortUpdatesOff(i);
            digInPortVector[i]->setReportUpdates(false);
        }
        system->reset();
    }



}