A scripting environment used to define precise output/input temporal relationships.
Dependencies: SMARTWAV mbed HelloWorld
Dependents: perturbRoom_legacy
Fork of HelloWorld by
Diff: behave.cpp
- Revision:
- 2:298679fff37c
- Child:
- 3:ae33b7f5a7c1
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/behave.cpp Tue Jul 08 21:51:16 2014 +0000 @@ -0,0 +1,3643 @@ +#include "behave.h" +#include <ctype.h> +#include <sstream> + +// These external symbols are maintained by the linker to indicate the +// location of various regions in the device's memory. They will be used by +// DisplayRAMBanks() to dump the size of each RAM bank to stdout. +extern unsigned int Image$$RW_IRAM1$$Base; +extern unsigned int Image$$RW_IRAM1$$ZI$$Limit; +extern unsigned int Image$$RW_IRAM2$$Base; +extern unsigned int Image$$RW_IRAM2$$ZI$$Limit; +extern unsigned int Image$$RW_IRAM3$$Base; +extern unsigned int Image$$RW_IRAM3$$ZI$$Limit; + +uint32_t* globalTimeKeeperPtr; //this is a pointer to the slave timer (do not change this directly) +extern eventQueue mainQueue; +extern digitalPort* portVector[]; + +extern Serial pc; +extern bool resetTimer; +extern bool clockSlave; +extern bool changeToSlave; +extern bool changeToStandAlone; +extern outputStream textDisplay; +extern int currentDIOstate[2]; +extern bool broadCastStateChanges; +extern bool textStreaming; + + +//static pools of memory for each object type +extern event eventBlock[NUMEVENTS]; +extern condition conditionBlock[NUMCONDITIONS]; +extern intCompare intCompareBlock[NUMINTCOMPARE]; +extern action actionBlock[NUMACTIONS]; +extern portMessage portMessageBlock[NUMPORTMESSAGES]; +extern intOperation intOperationBlock[NUMINTOPERATIONS]; +extern displayAction displayActionBlock[NUMDISPLAYACTIONS]; + +//used to find the first available object in the staticly defined pools of memory +template<class T> T* findFirstUnUsed(T a[], const int arrayLength) { + + T* returnPtr = NULL; + for (int i = 0; i < arrayLength; i++) { + if (!a[i].isUsed) { + returnPtr = &a[i]; + break; + } + } + return returnPtr; +} + +//used to count the number of available objects in the memory pool +template<class T> int countUnUsed(T a[], const int arrayLength) { + + int count = 0; + for (int i = 0; i < arrayLength; i++) { + if (!a[i].isUsed) { + count++; + } + } + return count; +} + + +void displayMemoryLeft(void) { + pc.printf("Available slots left in memory\r\n"); + pc.printf(" Blocks: %d\r\n", countUnUsed(eventBlock, NUMEVENTS)); + pc.printf(" Condition containers: %d\r\n", countUnUsed(conditionBlock, NUMCONDITIONS)); + pc.printf(" Int compare conditions: %d\r\n", countUnUsed(intCompareBlock, NUMINTCOMPARE)); + pc.printf(" Command containers: %d\r\n", countUnUsed(actionBlock, NUMACTIONS)); + pc.printf(" Port commands: %d\r\n", countUnUsed(portMessageBlock, NUMPORTMESSAGES)); + pc.printf(" Integer operater commands: %d\r\n", countUnUsed(intOperationBlock, NUMINTOPERATIONS)); + pc.printf(" Text display commands: %d\r\n", countUnUsed(displayActionBlock, NUMDISPLAYACTIONS)); +} + +// Displays the size of static allocations for each RAM bank as indicated by +// ARM linker to stdout. +static void DisplayRAMBanks(void) { + + pc.printf("Static RAM bank allocations\r\n"); + pc.printf(" Main RAM = %u\r\n", (unsigned int)&Image$$RW_IRAM1$$ZI$$Limit - + (unsigned int)&Image$$RW_IRAM1$$Base); + pc.printf(" RAM0 = %u\r\n", (unsigned int)&Image$$RW_IRAM2$$ZI$$Limit - + (unsigned int)&Image$$RW_IRAM2$$Base); + pc.printf(" RAM1 = %u\r\n", (unsigned int)&Image$$RW_IRAM3$$ZI$$Limit - + (unsigned int)&Image$$RW_IRAM3$$Base); +} + + +bool isNumber(const std::string& s) { + std::string::const_iterator it = s.begin(); + while (it != s.end() && isdigit(*it)) ++it; + return !s.empty() && it == s.end(); +} + +void tokenize(const string& str, + vector<string>& tokens, + const string& delimiters = " ") +{ + // Skip delimiters at beginning. + string::size_type lastPos = str.find_first_not_of(delimiters, 0); + // Find first "non-delimiter". + string::size_type pos = str.find_first_of(delimiters, lastPos); + + while (string::npos != pos || string::npos != lastPos) + { + // Found a token, add it to the vector. + tokens.push_back(str.substr(lastPos, pos - lastPos)); + // Skip delimiters. Note the "not_of" + lastPos = str.find_first_not_of(delimiters, pos); + // Find next "non-delimiter" + pos = str.find_first_of(delimiters, lastPos); + } +} + + +digitalPort::digitalPort(DigitalOut* DOP, DigitalIn* DIP): + outPin(DOP), + inPin(DIP), + outState(0){ + + lastInState = getDigitalIn(); + inState = getDigitalIn(); + lastChangeTime = 0; + lastOutChangeTime = 0; + lastChangeInterval = 0; + lastDownEvent.triggered = false; + lastUpEvent.triggered = false; + triggerUpEventPtr = NULL; + triggerDownEventPtr = NULL; + outStateChanged = false; +} + +void digitalPort::setTriggerUpEvent(event* eventInput) { + if (triggerUpEventPtr != NULL) { + //delete triggerUpEventPtr; + triggerUpEventPtr->release(); + } + triggerUpEventPtr = eventInput; +} + +void digitalPort::setTriggerDownEvent(event* eventInput) { + if (triggerDownEventPtr != NULL) { + //delete triggerDownEventPtr; + triggerDownEventPtr->release(); + + } + triggerDownEventPtr = eventInput; +} + + +int digitalPort::getDigitalIn() { + return inPin->read(); +} + + +void digitalPort::setDigitalOut(int outVal) { + if (outVal == -1) { + outVal = 1-outState; + } + outPin->write(outVal); + if (outState != outVal) { + outStateChanged = true; + lastOutChangeTime = *globalTimeKeeperPtr; + } + outState = outVal; +} + +//called when a digital in gets triggered +void digitalPort::addStateChange(int newState, uint32_t timeStamp) { + + if ((newState == 0) && (!lastDownEvent.triggered)){ + lastDownEvent.timeStamp = timeStamp; + lastDownEvent.triggered = true; + } else if ((newState == 1) && (!lastUpEvent.triggered)) { + lastUpEvent.timeStamp = timeStamp; + lastUpEvent.triggered = true; + } +} + +bool digitalPort::update() { + + bool changed = false; + if ((*globalTimeKeeperPtr - lastChangeTime) > 1) { //prevents flutter triggers when button is pressed + inState = getDigitalIn(); + changed = (lastInState != inState); + if (changed) { + if (inState == 1) { + if (lastUpEvent.triggered) { + //there were hardware triggered since the last main loop. We use that time + lastChangeInterval = lastUpEvent.timeStamp - lastChangeTime; + lastChangeTime = lastUpEvent.timeStamp; + } else { + //otherwise we use the current time + lastChangeInterval = *globalTimeKeeperPtr - lastChangeTime; + lastChangeTime = *globalTimeKeeperPtr; + } + if (triggerUpEventPtr != NULL) {triggerUpEventPtr->execute();} + } else if (inState == 0) { + if (lastDownEvent.triggered) { + lastChangeInterval = lastDownEvent.timeStamp - lastChangeTime; + lastChangeTime = lastDownEvent.timeStamp; + } else { + lastChangeInterval = *globalTimeKeeperPtr - lastChangeTime; + lastChangeTime = *globalTimeKeeperPtr; + } + if (triggerDownEventPtr != NULL) {triggerDownEventPtr->execute();} + } + + } + + lastInState = inState; + + } + lastUpEvent.triggered = false; + lastDownEvent.triggered = false; + return changed; +} + +int digitalPort::getLastChangeState() { + return lastInState; +} +uint32_t digitalPort::getTimeSinceLastChange() { + return lastChangeInterval; + +} + +intVariable::intVariable(): + value(0), + tag(string("--------------------")) { + isUsed = false; +} + +intVariable::intVariable(string tagInput, int initialValue): + value(initialValue), + tag(string(tagInput)) { + isUsed = true; +} + +void intVariable::set(string tagInput, int initialValue) { + value = initialValue; + tag = string(tagInput); + isUsed = true; +} + +displayAction::displayAction(): + dText(string("--------------------------------------------------")), + pcPtr(NULL) { + dVariable = NULL; + isUsed = false; +} + +void displayAction::release() { + dText = "--------------------------------------------------"; + pcPtr = NULL; + dVariable = NULL; + isUsed = false; +} + +displayAction::displayAction(int* variable, string varNameInput, Serial* pcPtrInput): + dVariable(variable), + dText(varNameInput), + pcPtr(pcPtrInput) { + isUsed = true; + +} + +displayAction::displayAction(string text, Serial* pcPtrInput): + dText(text), + pcPtr(pcPtrInput) { + dVariable = NULL; + isUsed = true; +} + +void displayAction::set(int* variable, string varNameInput, Serial* pcPtrInput) { + dVariable = variable; + dText = varNameInput; + pcPtr = pcPtrInput; + isUsed = true; + +} + +void displayAction::set(string text, Serial* pcPtrInput) { + dText = text; + pcPtr = pcPtrInput; + dVariable = NULL; + isUsed = true; +} + +void displayAction::execute() { + + ostringstream convert; // stream used for the conversion + convert << *globalTimeKeeperPtr; // insert the textual representation of 'Number' in the characters in the stream + + if (dVariable != NULL) { + ostringstream varConvert; + varConvert << *dVariable; + //pcPtr->printf("%d %s = %d\r\n",*globalTimeKeeperPtr, dText.data(),*dVariable); + textDisplay.send(convert.str() + " " + dText + " = " + varConvert.str() + "\r\n"); + } else { + //pcPtr->printf("%d %s\r\n",*globalTimeKeeperPtr, dText.data()); + textDisplay.send(convert.str() + " " + dText + "\r\n"); + + } +} + +intCompare::intCompare(): + port(NULL) { + cmpVal = NULL; + cmpValGlobal = false; + intVal = NULL; + intOp = NULL; + portValPtr = NULL; + isUsed = false; + +} +intCompare::intCompare(digitalPort* portInput, const char* cmpString, int cmpValInput, int whichToUse): + port(portInput) { + cmpVal = new int(cmpValInput); + cmpValGlobal = false; + intVal = NULL; + intOp = NULL; + setPointer(cmpString); + isUsed = true; + if (whichToUse == 1) { + portValPtr = &port->inState; + } else { + portValPtr = &port->outState; + } +} + +intCompare::intCompare(digitalPort* portInput, const char* cmpString, int* cmpIntVarInput, int whichToUse): + port(portInput), + cmpVal(cmpIntVarInput) { + cmpValGlobal = true; + intVal = NULL; + intOp = NULL; + setPointer(cmpString); + isUsed = true; + if (whichToUse == 1) { + portValPtr = &port->inState; + } else { + portValPtr = &port->outState; + } +} + +intCompare::intCompare(int* intVarInput, const char* cmpString, int* cmpIntVarInput): + cmpVal(cmpIntVarInput), + intVal(intVarInput) { + cmpValGlobal = true; + port = NULL; + intOp = NULL; + portValPtr = NULL; + isUsed = true; + setPointer(cmpString); +} + +intCompare::intCompare(int* intVarInput, const char* cmpString, int cmpValInput): + intVal(intVarInput){ + cmpVal = new int(cmpValInput); + cmpValGlobal = false; + port = NULL; + intOp = NULL; + portValPtr = NULL; + isUsed = true; + setPointer(cmpString); +} + +intCompare::intCompare(int* intVarInput, const char* cmpString, intOperation* cmpIntOpInput): + intVal(intVarInput) { + cmpVal = NULL; + port = NULL; + portValPtr = NULL; + cmpValGlobal = true; + intOp = cmpIntOpInput; + isUsed = true; + setPointer_operation(cmpString); +} + +intCompare::intCompare(digitalPort* portInput, const char* cmpString, intOperation* cmpIntOpInput, int whichToUse): + port(portInput) { + cmpVal = NULL; + intVal = NULL; + cmpValGlobal = true; + intOp = cmpIntOpInput; + setPointer_operation(cmpString); + isUsed = true; + if (whichToUse == 1) { + portValPtr = &port->inState; + } else { + portValPtr = &port->outState; + } +} + + + +void intCompare::set(digitalPort* portInput, const char* cmpString, int cmpValInput, int whichToUse) { + port = portInput; + cmpVal = new int(cmpValInput); + cmpValGlobal = false; + intVal = NULL; + intOp = NULL; + setPointer(cmpString); + isUsed = true; + if (whichToUse == 1) { + portValPtr = &port->inState; + } else { + portValPtr = &port->outState; + } +} + +void intCompare::set(digitalPort* portInput, const char* cmpString, int* cmpIntVarInput, int whichToUse) { + port = portInput; + cmpVal = cmpIntVarInput; + cmpValGlobal = true; + intVal = NULL; + intOp = NULL; + setPointer(cmpString); + isUsed = true; + if (whichToUse == 1) { + portValPtr = &port->inState; + } else { + portValPtr = &port->outState; + } +} + +void intCompare::set(int* intVarInput, const char* cmpString, int* cmpIntVarInput) { + cmpVal = cmpIntVarInput; + intVal = intVarInput; + cmpValGlobal = true; + port = NULL; + intOp = NULL; + portValPtr = NULL; + setPointer(cmpString); + isUsed = true; +} + +void intCompare::set(int* intVarInput, const char* cmpString, int cmpValInput) { + intVal = intVarInput; + cmpVal = new int(cmpValInput); + cmpValGlobal = false; + port = NULL; + intOp = NULL; + portValPtr = NULL; + setPointer(cmpString); + isUsed = true; +} + +void intCompare::set(int* intVarInput, const char* cmpString, intOperation* cmpIntOpInput) { + intVal = intVarInput; + cmpVal = NULL; + port = NULL; + portValPtr = NULL; + cmpValGlobal = true; + intOp = cmpIntOpInput; + setPointer_operation(cmpString); + isUsed = true; +} + +void intCompare::set(digitalPort* portInput, const char* cmpString, intOperation* cmpIntOpInput, int whichToUse) { + port = portInput; + cmpVal = NULL; + intVal = NULL; + cmpValGlobal = true; + intOp = cmpIntOpInput; + setPointer_operation(cmpString); + isUsed = true; + if (whichToUse == 1) { + portValPtr = &port->inState; + } else { + portValPtr = &port->outState; + } +} + + + +intCompare::~intCompare() { + if (!cmpValGlobal) delete cmpVal; //we only delete the intCompare object if it was created locally + delete intOp; +} + +void intCompare::release() { + if (!cmpValGlobal) delete cmpVal; //we only delete the intCompare object if it was created locally + if (intOp != NULL) { + intOp->release(); + } + port = NULL; + cmpVal = NULL; + cmpValGlobal = false; + intVal = NULL; + intOp = NULL; + portValPtr = NULL; + isUsed = false; +} + + +void intCompare::setPointer(const char* cmpString) { + if (strcmp(cmpString, ">") == 0) { + isTruePtr = &intCompare::greaterThan; + }else if (strcmp(cmpString, ">=") == 0) { + isTruePtr = &intCompare::greaterOrEqual; + }else if (strcmp(cmpString, "<") == 0) { + isTruePtr = &intCompare::lessThan; + }else if (strcmp(cmpString, "<=") == 0) { + isTruePtr = &intCompare::lessOrEqual; + }else if (strcmp(cmpString, "==") == 0) { + isTruePtr = &intCompare::equal; + }else if (strcmp(cmpString, "!=") == 0) { + isTruePtr = &intCompare::notEqual; + } +} + +void intCompare::setPointer_operation(const char* cmpString) { + if (strcmp(cmpString, ">") == 0) { + isTruePtr = &intCompare::greaterThan_op; + }else if (strcmp(cmpString, ">=") == 0) { + isTruePtr = &intCompare::greaterOrEqual_op; + }else if (strcmp(cmpString, "<") == 0) { + isTruePtr = &intCompare::lessThan_op; + }else if (strcmp(cmpString, "<=") == 0) { + isTruePtr = &intCompare::lessOrEqual_op; + }else if (strcmp(cmpString, "==") == 0) { + isTruePtr = &intCompare::equal_op; + }else if (strcmp(cmpString, "!=") == 0) { + isTruePtr = &intCompare::notEqual_op; + } +} + +bool intCompare::isTrue() { + return (this->*isTruePtr)(); + +} + +bool intCompare::notEqual() { + if (intVal != NULL) { + return (*intVal != *cmpVal); + } else { + return (*portValPtr != *cmpVal); + } +} + +bool intCompare::greaterThan() { + if (intVal != NULL) { + return (*intVal > *cmpVal); + } else { + return (*portValPtr > *cmpVal); + } +} + +bool intCompare::greaterOrEqual() { + if (intVal != NULL) { + return (*intVal >= *cmpVal); + } else { + return (*portValPtr >= *cmpVal); + } +} + +bool intCompare::lessThan() { + if (intVal != NULL) { + return (*intVal < *cmpVal); + } else { + return (*portValPtr < *cmpVal); + } +} + +bool intCompare::lessOrEqual() { + if (intVal != NULL) { + return (*intVal <= *cmpVal); + } else { + return (*portValPtr <= *cmpVal); + } +} + +bool intCompare::equal() { + if (intVal != NULL) { + return (*intVal == *cmpVal); + } else { + return (*portValPtr == *cmpVal); + } +} + +bool intCompare::notEqual_op() { + if (intVal != NULL) { + return (*intVal != intOp->execute()); + } else { + return (*portValPtr != intOp->execute()); + } +} + +bool intCompare::greaterThan_op() { + if (intVal != NULL) { + return (*intVal > intOp->execute()); + } else { + return (*portValPtr > intOp->execute()); + } +} + +bool intCompare::greaterOrEqual_op() { + if (intVal != NULL) { + return (*intVal >= intOp->execute()); + } else { + return (*portValPtr >= intOp->execute()); + } +} + +bool intCompare::lessThan_op() { + if (intVal != NULL) { + return (*intVal < intOp->execute()); + } else { + return (*portValPtr < intOp->execute()); + } +} + +bool intCompare::lessOrEqual_op() { + if (intVal != NULL) { + return (*intVal <= intOp->execute()); + } else { + return (*portValPtr <= intOp->execute()); + } +} + +bool intCompare::equal_op() { + if (intVal != NULL) { + return (*intVal == intOp->execute()); + } else { + return (*portValPtr == intOp->execute()); + } +} + +intOperation::intOperation(): + randHigh(-1) { + cmpVal = NULL; + intVal = NULL; + opPtr = NULL; + executePtr = NULL; + cmpValGlobal = false; + isUsed = false; + +} + +intOperation::intOperation(int randParam, const char* cmpString, int cmpValInput): + randHigh(randParam) { + cmpVal = new int(cmpValInput); + intVal = NULL; + opPtr = NULL; + cmpValGlobal = false; + isUsed = true; + if (strcmp(cmpString, "+") == 0) { + executePtr = &intOperation::add; + }else if (strcmp(cmpString, "-") == 0) { + executePtr = &intOperation::subtract; + }else if (strcmp(cmpString, "+=") == 0) { + executePtr = &intOperation::addAndStore; + }else if (strcmp(cmpString, "-=") == 0) { + executePtr = &intOperation::subtractAndStore; + }else if (strcmp(cmpString, "=") == 0) { + executePtr = &intOperation::equals; + } + +} + +intOperation::intOperation(int randParam, const char* cmpString, int* cmpIntVarInput): + randHigh(randParam), + cmpVal(cmpIntVarInput) { + intVal = NULL; + opPtr = NULL; + cmpValGlobal = true; + isUsed = true; + if (strcmp(cmpString, "+") == 0) { + executePtr = &intOperation::add; + }else if (strcmp(cmpString, "-") == 0) { + executePtr = &intOperation::subtract; + }else if (strcmp(cmpString, "+=") == 0) { + executePtr = &intOperation::addAndStore; + }else if (strcmp(cmpString, "-=") == 0) { + executePtr = &intOperation::subtractAndStore; + }else if (strcmp(cmpString, "=") == 0) { + executePtr = &intOperation::equals; + } +} + +intOperation::intOperation(int* intVarInput, const char* cmpString, int cmpValInput): + intVal(intVarInput) { + cmpVal = new int(cmpValInput); + randHigh = -1; + opPtr = NULL; + cmpValGlobal = false; + isUsed = true; + if (strcmp(cmpString, "+") == 0) { + executePtr = &intOperation::add; + }else if (strcmp(cmpString, "-") == 0) { + executePtr = &intOperation::subtract; + }else if (strcmp(cmpString, "+=") == 0) { + executePtr = &intOperation::addAndStore; + }else if (strcmp(cmpString, "-=") == 0) { + executePtr = &intOperation::subtractAndStore; + }else if (strcmp(cmpString, "=") == 0) { + executePtr = &intOperation::equals; + } +} + +intOperation::intOperation(int* intVarInput, const char* cmpString, int* cmpIntVarInput): + cmpVal(cmpIntVarInput), + intVal(intVarInput) { + randHigh = -1; + opPtr = NULL; + cmpValGlobal = true; + isUsed = true; + if (strcmp(cmpString, "+") == 0) { + executePtr = &intOperation::add; + }else if (strcmp(cmpString, "-") == 0) { + executePtr = &intOperation::subtract; + }else if (strcmp(cmpString, "+=") == 0) { + executePtr = &intOperation::addAndStore; + }else if (strcmp(cmpString, "-=") == 0) { + executePtr = &intOperation::subtractAndStore; + }else if (strcmp(cmpString, "=") == 0) { + executePtr = &intOperation::equals; + } +} + +intOperation::intOperation(int* intVarInput, intOperation* operationInput): + intVal(intVarInput) { + cmpVal = NULL; + randHigh = -1; + opPtr = operationInput; + executePtr = &intOperation::equals; + isUsed = true; +} + +void intOperation::set(int randParam, const char* cmpString, int cmpValInput) { + randHigh = randParam; + cmpVal = new int(cmpValInput); + intVal = NULL; + opPtr = NULL; + cmpValGlobal = false; + isUsed = true; + if (strcmp(cmpString, "+") == 0) { + executePtr = &intOperation::add; + }else if (strcmp(cmpString, "-") == 0) { + executePtr = &intOperation::subtract; + }else if (strcmp(cmpString, "+=") == 0) { + executePtr = &intOperation::addAndStore; + }else if (strcmp(cmpString, "-=") == 0) { + executePtr = &intOperation::subtractAndStore; + }else if (strcmp(cmpString, "=") == 0) { + executePtr = &intOperation::equals; + } + +} + +void intOperation::set(int randParam, const char* cmpString, int* cmpIntVarInput) { + randHigh = randParam; + cmpVal = cmpIntVarInput; + intVal = NULL; + opPtr = NULL; + cmpValGlobal = true; + isUsed = true; + if (strcmp(cmpString, "+") == 0) { + executePtr = &intOperation::add; + }else if (strcmp(cmpString, "-") == 0) { + executePtr = &intOperation::subtract; + }else if (strcmp(cmpString, "+=") == 0) { + executePtr = &intOperation::addAndStore; + }else if (strcmp(cmpString, "-=") == 0) { + executePtr = &intOperation::subtractAndStore; + }else if (strcmp(cmpString, "=") == 0) { + executePtr = &intOperation::equals; + } +} + +void intOperation::set(int* intVarInput, const char* cmpString, int cmpValInput) { + intVal = intVarInput; + cmpVal = new int(cmpValInput); + randHigh = -1; + opPtr = NULL; + cmpValGlobal = false; + isUsed = true; + if (strcmp(cmpString, "+") == 0) { + executePtr = &intOperation::add; + }else if (strcmp(cmpString, "-") == 0) { + executePtr = &intOperation::subtract; + }else if (strcmp(cmpString, "+=") == 0) { + executePtr = &intOperation::addAndStore; + }else if (strcmp(cmpString, "-=") == 0) { + executePtr = &intOperation::subtractAndStore; + }else if (strcmp(cmpString, "=") == 0) { + executePtr = &intOperation::equals; + } +} + +void intOperation::set(int* intVarInput, const char* cmpString, int* cmpIntVarInput) { + cmpVal = cmpIntVarInput; + intVal =intVarInput; + randHigh = -1; + opPtr = NULL; + cmpValGlobal = true; + isUsed = true; + if (strcmp(cmpString, "+") == 0) { + executePtr = &intOperation::add; + }else if (strcmp(cmpString, "-") == 0) { + executePtr = &intOperation::subtract; + }else if (strcmp(cmpString, "+=") == 0) { + executePtr = &intOperation::addAndStore; + }else if (strcmp(cmpString, "-=") == 0) { + executePtr = &intOperation::subtractAndStore; + }else if (strcmp(cmpString, "=") == 0) { + executePtr = &intOperation::equals; + } +} + +void intOperation::set(int* intVarInput, intOperation* operationInput) { + intVal = intVarInput; + cmpVal = NULL; + randHigh = -1; + opPtr = operationInput; + executePtr = &intOperation::equals; + isUsed = true; + +} + + +intOperation::~intOperation() { + if (!cmpValGlobal) delete cmpVal; + delete opPtr; +} + +void intOperation::release() { + if (!cmpValGlobal) delete cmpVal; + if (opPtr != NULL) { + opPtr->release(); + } + randHigh = -1; + cmpVal = NULL; + intVal = NULL; + opPtr = NULL; + executePtr = NULL; + cmpValGlobal = false; + isUsed = false; +} + + +int intOperation::execute() { + return (this->*executePtr)(); + +} + +int intOperation::add() { + if (intVal != NULL) { + return (*intVal + *cmpVal); + } + else { + //srand(time(NULL)); + srand(*globalTimeKeeperPtr); + return (rand() % (randHigh+1)) + *cmpVal; + //return (port->getState() + *cmpVal); + } +} + +int intOperation::subtract() { + if (intVal != NULL) { + return (*intVal - *cmpVal); + } + else { + srand(*globalTimeKeeperPtr); + return (rand() % (randHigh+1)) - *cmpVal; + //return (port->getState() - *cmpVal); + } +} + +int intOperation::addAndStore() { + if (intVal != NULL) { + *intVal = *intVal + *cmpVal; + return *intVal; + } + else { + + //Doesn't happen + return 0; + //port->setState(port->getState() + *cmpVal); + //return port->getState(); + } + +} + +int intOperation::subtractAndStore() { + if (intVal != NULL) { + *intVal = *intVal - *cmpVal; + return *intVal; + } else { + //doesn't happen + return 0; + //port->setState(port->getState() - *cmpVal); + //return port->getState(); + } +} + +int intOperation::equals() { + if ((intVal != NULL) && (opPtr == NULL)) { + *intVal = *cmpVal; + return *intVal; + } else if ((intVal != NULL) && (opPtr != NULL)) { + *intVal = opPtr->execute(); + return *intVal; + } else if (cmpVal != NULL){ + + srand(*globalTimeKeeperPtr); + *cmpVal = (rand() % (randHigh+1)); //this is how we assign a random number to variable + return *cmpVal; + + } + return -1; +} + +condition::condition() { + intCmp = NULL; + conditionPtrs[0] = NULL; + conditionPtrs[1] = NULL; + isUsed = false; + conditionType = ARITHMATIC_CONDITION; +} + +condition::condition(intCompare* compareInput) { + + intCmp = compareInput; + conditionPtrs[0] = NULL; + conditionPtrs[1] = NULL; + + isUsed = true; + conditionType = ARITHMATIC_CONDITION; + +} + +condition::condition(condition* condition1, char condType, condition* condition2) { + intCmp = NULL; + conditionPtrs[0] = condition1; + conditionPtrs[1] = condition2; + isUsed = true; + conditionType = condType; +} + +condition::~condition() { + if (intCmp != NULL) { + delete intCmp; + } +} + +void condition::release() { + if (intCmp != NULL) { + intCmp->release(); + intCmp=NULL; + } + if (conditionPtrs[0] != NULL) { + conditionPtrs[0]->release(); + conditionPtrs[1]->release(); + conditionPtrs[0]=NULL; + conditionPtrs[1]=NULL; + } + isUsed = false; +} + +void condition::set(intCompare* compareInput) { + release(); + intCmp = compareInput; + conditionPtrs[0] = NULL; + conditionPtrs[1] = NULL; + isUsed = true; + conditionType = ARITHMATIC_CONDITION; +} + +void condition::set(condition* condition1, char condType, condition* condition2) { + release(); + intCmp = NULL; + conditionPtrs[0] = condition1; + conditionPtrs[1] = condition2; + isUsed = true; + conditionType = condType; +} + +bool condition::isTrue() { + + + bool result = true; + if (conditionType == ARITHMATIC_CONDITION) { + //pc.printf("Evauating arithmatic condition \r\n"); + result = (intCmp->isTrue)(); + } else if (conditionType == AND_CONDITION) { + //pc.printf("Evauating AND condition \r\n"); + result = conditionPtrs[0]->isTrue() && conditionPtrs[1]->isTrue(); + } else if (conditionType == OR_CONDITION) { + //pc.printf("Evauating OR condition \r\n"); + result = conditionPtrs[0]->isTrue() || conditionPtrs[1]->isTrue(); + } + return result; + +} + +portMessage::portMessage(): + whichToSet(0), + value(0), + port(NULL) { + isUsed = false; +} + +void portMessage::release() { + + whichToSet = 0; + value = 0; + port = NULL; + isUsed = false; +} + +/* +portMessage::portMessage(digitalPort* portIn, int whichToSetIn, int valueIn): + whichToSet(whichToSetIn), + value(valueIn), + port(portIn) { + isUsed = true; +} + +void portMessage::setMessage(digitalPort* portIn, int whichToSetIn, int valueIn) { + whichToSet = whichToSetIn; + value = valueIn; + port = portIn; + isUsed = true; +}*/ + +portMessage::portMessage(int* portIn, int whichToSetIn, int valueIn): + whichToSet(whichToSetIn), + value(valueIn), + port(portIn) { + isUsed = true; +} + +void portMessage::setMessage(int* portIn, int whichToSetIn, int valueIn) { + whichToSet = whichToSetIn; + value = valueIn; + port = portIn; + isUsed = true; +} + +void portMessage::execute() { + + if (port != NULL) { + if ((*port > 0) && (*port <= NUMPORTS)) { + portVector[*port]->setDigitalOut(value); + } else { + pc.printf("Error: port index assigned by variable does not exist."); + } + } else { + portVector[whichToSet]->setDigitalOut(value); + } + + /* + if (whichToSet == 1) { + port->setDigitalOut(value); + } else if (whichToSet == 2) { + //port->setState(value); + }*/ +} + +action::action(): + actionType(0) { + op = NULL; + message = NULL; + eventToCreate = NULL; + displayActionPtr = NULL; + //eventDelay = 0; + sound = NULL; + sysCommand = -1; + isUsed = false; + +} + +action::~action() { + if (eventToCreate != NULL) delete eventToCreate; + if (op != NULL) delete op; + if (message != NULL) delete message; + delete displayActionPtr; + delete sound; +} + +void action::release() { + if (eventToCreate != NULL) eventToCreate->release(); + if (op != NULL) op->release(); + if (message != NULL) message->release(); + if (displayActionPtr != NULL) displayActionPtr->release(); + delete sound; //still need to make a static soundControl array + + actionType = 0; + op = NULL; + message = NULL; + eventToCreate = NULL; + displayActionPtr = NULL; + //eventDelay = 0; + sound = NULL; + sysCommand = -1; + isUsed = false; +} + +action::action(intOperation* opInput): + actionType(1) { + op = opInput; + message = NULL; + eventToCreate = NULL; + displayActionPtr= NULL; + //eventDelay = 0; + sound = NULL; + sysCommand = -1; + isUsed = true; +} + +action::action(portMessage* messageInput): + actionType(2) { + op = NULL; + eventToCreate = NULL; + message = messageInput; + displayActionPtr= NULL; + //eventDelay = 0; + sound = NULL; + sysCommand = -1; + isUsed = true; + +} + +action::action(event* eventInput): + actionType(3) { + op = NULL; + message = NULL; + eventToCreate = eventInput; + displayActionPtr= NULL; + sound = NULL; + + //eventDelay = eventInput->timeLag; + + + sysCommand = -1; + isUsed = true; +} + +/* +action::action(event* eventInput, uint32_t delay): + actionType(3) { + op = NULL; + message = NULL; + eventToCreate = eventInput; + displayActionPtr= NULL; + sound = NULL; + eventDelay = delay; + sysCommand = -1; + isUsed = true; + +}*/ + + + +action::action(displayAction* displayInput): + actionType(4) { + op = NULL; + message = NULL; + eventToCreate = NULL; + sound = NULL; + displayActionPtr = displayInput; + //eventDelay = 0; + sysCommand = -1; + isUsed = true; +} + +action::action(soundControl* soundInput): + actionType(5) { + op = NULL; + message = NULL; + eventToCreate = NULL; + sound = soundInput; + displayActionPtr = NULL; + //eventDelay = 0; + sysCommand = -1; + isUsed = true; +} + +action::action(int8_t sysCommandInput): + actionType(6) { + op = NULL; + message = NULL; + eventToCreate = NULL; + sound = NULL; + displayActionPtr = NULL; + //eventDelay = 0; + sysCommand = sysCommandInput; + isUsed = true; +} + +void action::set(intOperation* opInput) { + actionType = 1; + op = opInput; + //eventDelay = 0; + isUsed = true; + +} + +void action::set(portMessage* messageInput) { + actionType = 2; + message = messageInput; + //eventDelay = 0; + isUsed = true; + +} + +void action::set(event* eventInput) { + actionType = 3; + eventToCreate = eventInput; + //eventDelay = eventInput->timeLag; + + isUsed = true; + +} + +/* +void action::set(event* eventInput, uint32_t delay) { + actionType = 3; + eventToCreate = eventInput; + eventDelay = delay; + isUsed = true; + +}*/ + + + +void action::set(displayAction* displayInput) { + actionType = 4; + displayActionPtr = displayInput; + isUsed = true; +} + +void action::set(soundControl* soundInput) { + actionType = 5; + sound = soundInput; + isUsed = true; +} + +void action::set(int8_t sysCommandInput) { + actionType = 6; + sysCommand = sysCommandInput; + isUsed = true; +} + +void action::execute() { + + if (actionType == 1) { + op->execute(); + } else if (actionType == 2) { + message->execute(); + } else if (actionType == 3) { + this->execute(*globalTimeKeeperPtr); //route to the other overloaded method + } else if (actionType == 4) { + displayActionPtr->execute(); //send text via serial + } else if (actionType == 5) { + sound->execute(); //operate sound device + } else if (actionType == 6) { + switch(sysCommand) { + case 0: + mainQueue.eraseQueue(); + break; + case 1: + textStreaming = true; + break; + case 2: + textStreaming = false; + break; + case 3: + broadCastStateChanges = true; + break; + case 4: + broadCastStateChanges = false; + break; + } + + } +} + +void action::execute(uint32_t blockExecTime) { + + if (actionType == 1) { + op->execute(); + } else if (actionType == 2) { + message->execute(); + } else if (actionType == 3) { //an event block + //Because time will pass from the begining of the block, any defined delays should be updated + + //int newDelay = eventDelay-(*globalTimeKeeperPtr-blockExecTime); + int newDelay; + if (eventToCreate->timeLagIsConstant) { + newDelay = eventToCreate->timeLag - (*globalTimeKeeperPtr-blockExecTime); + } else { + newDelay = *eventToCreate->timeLagVar - (*globalTimeKeeperPtr-blockExecTime); + } + if (newDelay < 0) {newDelay = 0;} + eventToCreate->addToQueue(newDelay); //add the event to the queue to be executed later + + if (eventToCreate->hasWhileLoop) { //this is a while loop + if (eventToCreate->isConditionTrue()) { + //newDelay = (blockExecTime + eventToCreate->whileLoopPeriod) - *globalTimeKeeperPtr; + int tmpPeriod; + if (eventToCreate->whileLoopPeriodIsConstant) { //constant while loop period + newDelay = (blockExecTime + eventToCreate->whileLoopPeriod); + tmpPeriod = eventToCreate->whileLoopPeriod; + } else { + tmpPeriod = *eventToCreate->whileLoopPeriodVar; + if (tmpPeriod < 0) { + tmpPeriod = 0; + } + newDelay = (blockExecTime + tmpPeriod); + } + while ( (newDelay-*globalTimeKeeperPtr < 0) && (eventToCreate->isConditionTrue()) ) { + eventToCreate->execute(); + newDelay = newDelay + tmpPeriod; + + } + newDelay = newDelay-*globalTimeKeeperPtr; + if (newDelay > 0) { + eventToCreate->addToQueue(newDelay); + } else { + eventToCreate->addToQueue(1); + } + } else if (eventToCreate->nextElseEventPtr != NULL) { + eventToCreate->nextElseEventPtr->addToQueue(); + + } + } + } else if (actionType == 4) { + displayActionPtr->execute(); //send text via serial + } else if (actionType == 5) { + sound->execute(); //operate sound device + } else if (actionType == 6) { + switch(sysCommand) { + case 0: + mainQueue.eraseQueue(); + break; + case 1: + textStreaming = true; + break; + case 2: + textStreaming = false; + break; + case 3: + broadCastStateChanges = true; + break; + case 4: + broadCastStateChanges = false; + break; + } + } +} + +eventQueue::eventQueue(digitalPort** portVectorInput, uint32_t* timeKeeperSlaveInput): + portVector(portVectorInput), + timeKeeperPtr(timeKeeperSlaveInput){ + + globalTimeKeeperPtr = timeKeeperPtr; + queueItem blankEvent; + blankEvent.timeToExecute = 0; + blankEvent.eventPtr = NULL; + queueSize = 100; + events.resize(queueSize,blankEvent); + + +} + +void eventQueue::addEventToQueue(event* eventInput, uint32_t delay) { + //*updateSlavePtr = false; + uint32_t eventTime = *timeKeeperPtr + delay; + //*updateSlavePtr = true; + //std::vector<queueItem>::size_type sz = events.size(); + //Look for the first empty slot in the queue and place the event there. + //This means that the events in the queue are out of order, but + //it prevents us from having to push_pack and pop off all the time. + for (unsigned i = 0; i < queueSize; i++) { + if (events[i].eventPtr == NULL) { + events[i].eventPtr = eventInput; + events[i].timeToExecute = eventTime; + break; + } + } +} + +void eventQueue::eraseQueue() { + //Erase all events in the queue + std::vector<queueItem>::size_type sz = events.size(); + for (unsigned i = 0; i < sz; i++) { + events[i].eventPtr = NULL; + + } +} + + +//check if any of the events in the queue are up for execution +void eventQueue::check(void) { + + //*updateSlavePtr = false; + uint32_t currentTime = *timeKeeperPtr; + //*updateSlavePtr = true; + //std::vector<queueItem>::size_type sz = events.size(); + for (unsigned i = 0; i < queueSize; i++) { + if (events[i].eventPtr != NULL) { + if(events[i].timeToExecute <= currentTime) { + if (!events[i].eventPtr->hasWhileLoop) { + //this is not a while loop, so no need to check if the condition is still true + events[i].eventPtr->execute(); + } else if (events[i].eventPtr->isConditionTrue()){ + //The event is part of a while loop, so recheck the condition before executing + events[i].eventPtr->execute(); + //if (events[i].eventPtr->isConditionTrue()) { //is the condition still true? + int nextTime; + int tmpPeriod; + if (events[i].eventPtr->whileLoopPeriodIsConstant) { + nextTime = (events[i].timeToExecute + events[i].eventPtr->whileLoopPeriod); + tmpPeriod = events[i].eventPtr->whileLoopPeriod; + } else { + tmpPeriod = *events[i].eventPtr->whileLoopPeriodVar; + if (tmpPeriod < 0) { + tmpPeriod = 0; + } + nextTime = (events[i].timeToExecute + tmpPeriod); + + } + //Just in case we are not keeping up, execute the event until we have cought up + while ((nextTime-*timeKeeperPtr <= 0) && (events[i].eventPtr->isConditionTrue())) { + events[i].eventPtr->execute(); + nextTime = nextTime+tmpPeriod; + + } + nextTime = nextTime - *timeKeeperPtr; + if (nextTime > 0) { + //we add the event to the queue (but the condition is rechecked first) + //if the condition is false, the 'then' statement is added to the queue instead + events[i].eventPtr->addToQueue(nextTime); + } else { + //if we are having trouble keeping up, just add the next event in 1 ms + events[i].eventPtr->addToQueue(1); + } + /* + } else { + if (events[i].eventPtr->nextElseEventPtr != NULL) { + events[i].eventPtr->nextElseEventPtr->addToQueue(); + } + }*/ + + } else { + if (events[i].eventPtr->nextElseEventPtr != NULL) { + events[i].eventPtr->nextElseEventPtr->addToQueue(); + } + } + events[i].eventPtr = NULL; + } + } + } +} + + +event::event(): + timeLag(0), + queuePtr(&mainQueue) { + nextElseEventPtr = NULL; + conditionToCheck = NULL; + blockType = 0; + whileLoopPeriod = 0; + numConditions = 0; + numActions = 0; + isUsed = false; + timeLagVar = NULL; + timeLagIsConstant = true; + whileLoopPeriodIsConstant = true; + hasWhileLoop = false; + whileLoopPeriodVar = NULL; + + } + +event::event(eventQueue* queueInput): + timeLag(0), + queuePtr(&mainQueue) { + nextElseEventPtr = NULL; + conditionToCheck = NULL; + blockType = 0; + whileLoopPeriod = 0; + numConditions = 0; + numActions = 0; + isUsed = true; + timeLagVar = NULL; + timeLagIsConstant = true; + whileLoopPeriodIsConstant = true; + hasWhileLoop = false; + whileLoopPeriodVar = NULL; + + } + + event::~event() { + /* + while (!conditionArray.empty()) + { + delete conditionArray.back(); + conditionArray.pop_back(); + } + + while (!actionArray.empty()) + { + delete actionArray.back(); + actionArray.pop_back(); + } + + delete nextElseEventPtr; + */ + + } + +void event::release() { + + for (int i = 0; i < numActions; i++) { + actionArray[i]->release(); + } + + if (conditionToCheck != NULL) { + conditionToCheck->release(); + conditionToCheck = NULL; + } + + if (nextElseEventPtr != NULL) { + nextElseEventPtr->release(); + } + timeLag = 0; + nextElseEventPtr = NULL; + blockType = 0; + whileLoopPeriod = 0; + numConditions = 0; + numActions = 0; + isUsed = false; + timeLagVar = NULL; + timeLagIsConstant = true; + whileLoopPeriodIsConstant = true; + hasWhileLoop = false; + whileLoopPeriodVar = NULL; + } + + void event::setTimeLag(uint32_t timeLagInput) { + timeLag = timeLagInput; + timeLagIsConstant = true; + } + + void event::setTimeLag(int* timeLagInput) { + timeLagVar = timeLagInput; + timeLagIsConstant = false; //time lag is not defined by a constant + } + + void event::setWhileLoopPeriod(uint32_t period) { + whileLoopPeriodIsConstant = true; + hasWhileLoop = true; + whileLoopPeriod = period; + + } + + void event::setWhileLoopPeriod(int* period) { + whileLoopPeriodIsConstant = false; + hasWhileLoop = true; + whileLoopPeriodVar = period; + + } + + void event::addCondition(condition* conditionInput) { + if (conditionToCheck != NULL) { + conditionToCheck->release(); + } + conditionToCheck = conditionInput; + + //conditionArray.push_back(conditionInput); + } + + void event::addAction(action* actionInput) { + actionArray[numActions] = actionInput; + numActions++; + //actionArray.push_back(actionInput); + } + + bool event::isConditionTrue(void) { + //if statement (can be left empty, which is interpreted as 'true') + //queuePtr->pcPtr->printf("Checking condition...\r\n"); + bool result = true; + /* + std::vector<condition*>::size_type sz = conditionArray.size(); + for (unsigned i = 0; i < sz; i++) { + if (!conditionArray[i]->isTrue()) { + result = false; + //queuePtr->pcPtr->printf("Consition false\r\n"); + } //else {queuePtr->pcPtr->printf("Consition true\r\n");} + } + */ + + if ((conditionToCheck!=NULL)&&(!conditionToCheck->isTrue())) { + result = false; + } + + return result; + } + + void event::execute(void) { + //called from the event queue. The condition is bypassed because it was already checked + + + uint32_t timeAtStartExec = *globalTimeKeeperPtr; + //std::vector<action*>::size_type sz = actionArray.size(); + + /* + std::deque<action*>::size_type sz = actionArray.size(); + + for (unsigned i = 0; i < sz; i++) { + actionArray[i]->execute(timeAtStartExec); + + } + */ + for (unsigned i = 0; i < numActions; i++) { + actionArray[i]->execute(timeAtStartExec); + + } + + } + + //Attach an 'else' statement to the event + void event::setNextElseEvent(event* eventInput) { + nextElseEventPtr = eventInput; + } + + + //When we we call addToQueue() the condition is checked. If true, the event is added + //to the queue, otherwise we check if there was an 'else' statement attached to the event. + void event::addToQueue(void) { + if (isConditionTrue()) { + if ((timeLagIsConstant)&&(timeLag == 0)) { + execute(); + + } else if (timeLagIsConstant) { + queuePtr->addEventToQueue(this, this->timeLag); + } else if ((!timeLagIsConstant)&&(*timeLagVar <= 0)) { + execute(); + } else { + queuePtr->addEventToQueue(this, *timeLagVar); + } + } else if ((this->nextElseEventPtr != NULL)&&(whileLoopPeriod == 0)) { + this->nextElseEventPtr->addToQueue(); + } + } + + //We can override the timeLag field and use another delay + void event::addToQueue(uint32_t delay) { + if (this->isConditionTrue()) { + //if ((delay == 0) && (whileLoopPeriod == 0)) { + if ((delay == 0)) { + this->execute(); + } else { + queuePtr->addEventToQueue(this, delay); + } + } else if ((this->nextElseEventPtr != NULL)) { //&&(!hasWhileLoop)) { + this->nextElseEventPtr->addToQueue(); + } + } + + + + functionItem::functionItem(action* actionInput, string tagInput): + tag(tagInput), + actionPtr(actionInput) { + } + + functionItem::~functionItem() { + delete actionPtr; + } + + scriptStream::scriptStream(Serial* serialInput, digitalPort** portVectorInput, int numPortsInput, eventQueue* queueInput): + portVector(portVectorInput), + numPorts(numPortsInput), + pcPtr(serialInput), + queuePtr(queueInput) { + + currentPort = -1; + currentTriggerPort = -1; + currentTriggerDir = 1; + currentFunction = -1; + + lineError = false; + blockDepth = 0; + ifBlockInit = false; + whileBlockInit = false; + elseFlag = false; + currentDelay = 0; + + } + + void scriptStream::addLineToCurrentBlock(char* lineInput) { + + bool compile = false; + bool keep = false; + for (int i = 0; i < 128; i++) { + if (lineInput[i] == ';') { + compile = true; + } else if (lineInput[i] == ' ') { + continue; + } else if (lineInput[i] == '\0') { + break; + } else { + keep = true; + compile = false; + } + } + if (keep) currentBlock.insert(currentBlock.begin(),string(lineInput)); + if (compile) parseBlock(); + + } + + + //SCRIPT PARSING - all script commands are defined here. + //------------------------------------------------------- + void scriptStream::parseBlock() { + + lineError = false; + blockDepth = 0; + ifBlockInit = false; + whileBlockInit = false; + elseFlag = false; + thenFlag = false; + currentDelay = 0; + + std::size_t stringInd = 0; + + bool wholeLineEvaluated = false; + + //pcPtr->printf("\r\n"); + while (!currentBlock.empty()) { + wholeLineEvaluated = false; + tmpLine = currentBlock.back(); + lineError = false; + //remove tabs + std::size_t found = tmpLine.find_first_of(9); //tab + while (found!=std::string::npos) { + tmpLine[found]= ' '; + found=tmpLine.find_first_of(9,found+1); + } + + found = tmpLine.find_first_of(37); //% for commenting + if (found!=std::string::npos) { + for (int p=found; p<tmpLine.size() ;p++) { + tmpLine[p]= ' '; + } + } + + //break up the line into tokens separated by spaces + tokenize(tmpLine,tokens," ;"); + + std::vector<string>::size_type sz = tokens.size(); + + for (unsigned i = 0; i < sz; i++) { + //pcPtr->printf("%s", tokens[i].c_str()); + + + //end statement signals the end of a block----------------------------------------- + if (tokens[i].compare("end") == 0) { //ends the current block + + if (ifBlockInit || whileBlockInit) { + pcPtr->printf("Error: expected a 'do' statement\r\n"); + lineError = true; + } + + ifBlockInit = false; + whileBlockInit = false; + elseFlag = false; + + if (blockDepth > 0) { + if (blockDepth == 1) { + + + //pcPtr->printf("Close trigger block for port %d\r\n",currentTriggerPort); + currentTriggerPort = -1; + + + + blockDepth = 0; + } else if (blockDepth > 1) { + //pcPtr->printf("Close block\r\n"); + blockDepth = blockDepth - 1; + } + + while ((tmpEventPtrArray.back()->blockType == 3) || (tmpEventPtrArray.back()->blockType == 4)){ + tmpEventPtrArray.pop_back(); //recursively remove the pointers to all else blocks + } + tmpEventPtrArray.pop_back(); //remove the pointer to the finished block + } else { + pcPtr->printf("Error: End statement without block\r\n"); + lineError = true; + } + + + + //sound statement used to play wave files------------------------------------------------ + //example: sound('soundfile') + // sound(stop) + } else if (tokens[i].find("sound(") != std::string::npos) { + if (ifBlockInit || whileBlockInit || elseFlag) { + pcPtr->printf("Error: expected a 'do' statement\r\n"); + lineError = true; + } + wholeLineEvaluated = true; + int pos1 = tmpLine.find("sound(")+6; + int pos2 = tmpLine.find_first_of(")",pos1); + string dispVar = tmpLine.substr(pos1,pos2-pos1); + + int* tmpVar = findIntVariable(dispVar); + bool isText = false; + bool stopSignal = false; + bool resetSignal = false; + if (tmpVar == NULL) { + if ((tmpLine.compare(pos1,1,"'")==0) && (tmpLine.compare(pos2-1,1,"'")==0)) { + isText = true; + } else if (dispVar.compare("stop") == 0) { + stopSignal = true; + } else if (dispVar.compare("reset") == 0) { + resetSignal = true; + } else { + pcPtr->printf("Error: variable input to sound() does not exist\r\n"); + lineError = true; + } + } + action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS); + if (tmpAction == NULL) { + pcPtr->printf("Error: no memory slots available.\r\n"); + lineError = true; + } + if (!lineError && (blockDepth == 0)) { + //we are not inside a block structure, so play sound now + if (stopSignal) { + soundControl S; + S.setPlayback(false); + S.execute(); + } else if (resetSignal) { + soundControl S; + S.setReset(); + S.execute(); + } else if (isText) { + + if (pos2-pos1-2 <= 20) { + + soundControl S; + S.setFile(tmpLine.substr(pos1+1,pos2-pos1-2)); + S.execute(); + } else { + pcPtr->printf("Error: sound file names must be 20 characters or less.\r\n"); + lineError = true; + } + } else { + pcPtr->printf("Error: variable input to sound() not yet supported. Enter a string in single quotes.\r\n"); + lineError = true; + } + + } else if (!lineError && (blockDepth > 0) ){ + //the disp function was put inside a block + if (stopSignal) { + soundControl* sPtr = new soundControl(); + sPtr->setPlayback(false); + //action* tmpAction = new action(sPtr); + tmpAction->set(sPtr); + tmpEventPtrArray.back()->addAction(tmpAction); + } else if (resetSignal) { + soundControl* sPtr = new soundControl(); + sPtr->setReset(); + //action* tmpAction = new action(sPtr); + tmpAction->set(sPtr); + tmpEventPtrArray.back()->addAction(tmpAction); + } else if (isText) { + + if (pos2-pos1-2 <= 20) { + soundControl* sPtr = new soundControl(); + sPtr->setFile(tmpLine.substr(pos1+1,pos2-pos1-2)); + //action* tmpAction = new action(sPtr); + tmpAction->set(sPtr); + tmpEventPtrArray.back()->addAction(tmpAction); + } else { + pcPtr->printf("Error: sound file names must be 20 characters or less.\r\n"); + lineError = true; + } + } else { + pcPtr->printf("Error: variable input to sound() not yet supported. Enter a string in single quotes.\r\n"); + lineError = true; + } + + //pcPtr->printf("Sound action\r\n"); + } + + } else if (tokens[i].find("volume(") != std::string::npos) { + if (ifBlockInit || whileBlockInit || elseFlag) { + pcPtr->printf("Error: expected a 'do' statement\r\n"); + lineError = true; + } + wholeLineEvaluated = true; + int pos1 = tmpLine.find("volume(")+7; + int pos2 = tmpLine.find_first_of(")",pos1); + string dispVar = tmpLine.substr(pos1,pos2-pos1); + + int* tmpVar = findIntVariable(dispVar); + bool isText = false; + if (tmpVar == NULL) { + if (isNumber(dispVar)) { + isText = true; + } else { + pcPtr->printf("Error: variable input to volume() does not exist\r\n"); + lineError = true; + } + } + action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS); + if (tmpAction == NULL) { + pcPtr->printf("Error: no memory slots available.\r\n"); + lineError = true; + } + if (!lineError && (blockDepth == 0)) { + //we are not inside a block structure, so play sound now + if (isText) { + int newVolume = atoi(dispVar.data()); + if ((newVolume >=0)&&(newVolume <= 255)) { + soundControl S; + S.setVolume(newVolume); + S.execute(); + } else { + pcPtr->printf("Error: sound volume must be between 0 and 255 .\r\n"); + lineError = true; + } + } else { + soundControl S; + S.setVolume(tmpVar); + S.execute(); + } + + } else if (!lineError && (blockDepth > 0) ){ + //the disp function was put inside a block + if (isText) { + int newVolume = atoi(dispVar.data()); + + soundControl* sPtr = new soundControl(); + sPtr->setVolume(newVolume); + + //action* tmpAction = new action(sPtr); + tmpAction->set(sPtr); + tmpEventPtrArray.back()->addAction(tmpAction); + + } else { + soundControl* sPtr = new soundControl(); + sPtr->setVolume(tmpVar); + //action* tmpAction = new action(sPtr); + tmpAction->set(sPtr); + tmpEventPtrArray.back()->addAction(tmpAction); + } + + //pcPtr->printf("Volume action\r\n"); + } + //clock statement used to is used to control the clock------------------------- + //example: clock(reset); clock(slave); clock(standalone) + } else if (tokens[i].find("clock(") != std::string::npos) { //clock commands + if (ifBlockInit || whileBlockInit || elseFlag) { + pcPtr->printf("Error: expected a 'do' statement\r\n"); + lineError = true; + } + if (blockDepth > 0) { + pcPtr->printf("Error: clock commands only allowed outside of block structure\r\n"); + lineError = true; + } + + if (!lineError) { + int pos1 = tmpLine.find("clock(")+6; + int pos2 = tmpLine.find_first_of(")",pos1); + string dispVar = tmpLine.substr(pos1,pos2-pos1); + + + if (blockDepth == 0) { + if (dispVar.compare("reset") == 0) { + resetTimer = true; + queuePtr->eraseQueue(); + textDisplay.send(string("Clock reset to 0\r\n")); + //pcPtr->printf("Clock reset to 0\r\n"); + } else if (dispVar.compare("slave") == 0) { + if (!clockSlave) { + changeToSlave = true; + textDisplay.send(string("Slave mode\r\n")); + //pcPtr->printf("Slave mode\r\n"); + } + } else if (dispVar.compare("standalone") == 0) { + if (clockSlave) { + changeToStandAlone = true; + textDisplay.send(string("Standalone mode\r\n")); + //pcPtr->printf("Standalone mode\r\n"); + } + } else { + pcPtr->printf("Clock control statement not understood\r\n"); + lineError = true; + } + } + } + + //disp command used to display text via serial--------------------------------------- + //example: disp('hello'); disp(myVar) + } else if (tokens[i].find("disp(") != std::string::npos) { //display value of variable + + if (ifBlockInit || whileBlockInit || elseFlag) { + pcPtr->printf("Error: expected a 'do' statement\r\n"); + lineError = true; + } + + //int pos1 = tokens[i].find("disp(")+5; + //int pos2 = tokens[i].find_first_of(")",pos1); + //string dispVar = tokens[i].substr(pos1,pos2-pos1); + + wholeLineEvaluated = true; + int pos1 = tmpLine.find("disp(")+5; + int pos2 = tmpLine.find_first_of(")",pos1); + string dispVar = tmpLine.substr(pos1,pos2-pos1); + + int* tmpVar = findIntVariable(dispVar); + bool isText = false; + if (tmpVar == NULL) { + if ((tmpLine.compare(pos1,1,"'")==0) && (tmpLine.compare(pos2-1,1,"'")==0)) { + isText = true; + } else { + pcPtr->printf("Error: variable to display does not exist\r\n"); + lineError = true; + } + } + displayAction* dPtr = findFirstUnUsed(displayActionBlock, NUMDISPLAYACTIONS); + if (dPtr == NULL) { + pcPtr->printf("Error: no memory slots available.\r\n"); + lineError = true; + } + if (!lineError && (blockDepth == 0)) { + //we are not inside a block structure, so display now + + if (isText) { + //displayAction* dPtr = new displayAction(tmpLine.substr(pos1+1,pos2-pos1-2), pcPtr); + dPtr->set(tmpLine.substr(pos1+1,pos2-pos1-2), pcPtr); + dPtr->execute(); + //delete dPtr; + dPtr->release(); + } else { + //displayAction* dPtr = new displayAction(tmpVar, dispVar, pcPtr); + dPtr->set(tmpVar, dispVar, pcPtr); + dPtr->execute(); + //delete dPtr; + dPtr->release(); + } + + } else if (!lineError && (blockDepth > 0) ){ + //the disp function was put inside a block + action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS); + if (tmpAction == NULL) { + pcPtr->printf("Error: no memory slots available.\r\n"); + lineError = true; + } + if (!lineError && isText) { + //displayAction* dPtr = new displayAction(tmpLine.substr(pos1+1,pos2-pos1-2), pcPtr); + dPtr->set(tmpLine.substr(pos1+1,pos2-pos1-2), pcPtr); + tmpAction->set(dPtr); + //action* tmpAction = new action(dPtr); + tmpEventPtrArray.back()->addAction(tmpAction); + } else if (!lineError) { + //displayAction* dPtr = new displayAction(tmpVar, dispVar, pcPtr); + dPtr->set(tmpVar, dispVar, pcPtr); + tmpAction->set(dPtr); + //action* tmpAction = new action(dPtr); + tmpEventPtrArray.back()->addAction(tmpAction); + } + + //pcPtr->printf("Display action\r\n"); + } + + + //int is used to decalar new variables. Only allowed outside of callbacks------------------- + //example: int a; int b = 9 + } else if (tokens[i].compare("int") == 0) { //define a new integer variable + + if (ifBlockInit || whileBlockInit) { + pcPtr->printf("Error: expected a 'do' statement\r\n"); + lineError = true; + } + tmpString = ""; + wholeLineEvaluated = true; + int spacesBeforeEqualSign = 0; + bool countSpaces = true; + //combine the tokens without whitespaces + for (unsigned j = i+1; j < sz; j++) { + tmpString.append(tokens[j]); + if (tokens[j].find_first_of("=") != std::string::npos) { + if (tokens[j].find_first_of("=") > 0) spacesBeforeEqualSign++; + countSpaces = false; + } else if (countSpaces) { + spacesBeforeEqualSign++; + } + } + + if (blockDepth > 0) { + pcPtr->printf("Error: Variables can only be first declared outside of callbacks.\r\n"); + lineError = true; + } + + if ((!lineError) && (spacesBeforeEqualSign > 1)) { + pcPtr->printf("Error: Variable can't have a space in it.\r\n"); + lineError = true; + } + stringInd = tmpString.find_first_of("="); + + bool variableCreated = false; + if (!lineError) { + if (((stringInd == std::string::npos) && (sz == 2)) || (stringInd != std::string::npos)) { + if (createIntVariable(tmpString.substr(0,stringInd))) { + //pcPtr->printf("Created variable: %s\r\n", tmpString.substr(0,stringInd).data()); + variableCreated = true; + } else { + int* tmpVar = findIntVariable(tmpString.substr(0,stringInd)); + *tmpVar = 0; + //pcPtr->printf("Reset variable %s to 0\r\n", tmpString.substr(0,stringInd).data()); + //lineError = true; + } + } else { + pcPtr->printf("Error: variable declaration not understood.\r\n", tmpString.substr(0,stringInd).data()); + lineError = true; + } + } + + if ((!lineError) && (stringInd != std::string::npos)) { //evaluate the expression + action* tmpAction = evaluateAssignmentForAction(tmpString); + if (tmpAction != NULL) { + tmpAction->execute(); + //delete tmpAction; + tmpAction->release(); + } else { + lineError = true; + if (variableCreated) { + delete globalVariables.back(); + globalVariables.pop_back(); + } + } + } + + //serial command is used to toggle whether or not to buffer up output text---------------- + //examples: serial buffer; serial send + } else if (tokens[i].compare("serial") == 0) { + if (ifBlockInit || whileBlockInit || elseFlag) { + pcPtr->printf("Error: expected a 'do' statement\r\n"); + lineError = true; + } + bool stream = true; + if ((!lineError)&&(i+1 < sz)){ + if (tokens[i+1].compare("buffer") == 0) { + stream = false; + } else if (tokens[i+1].compare("send") == 0) { + stream = true; + } else { + pcPtr->printf("Error: 'serial' useage: 'serial buffer' or 'serial send'\r\n"); + lineError = true; + } + } + i++; + if ((!lineError) && (blockDepth == 0)) { + if (stream) { + textStreaming = true; + } else { + textStreaming = false; + } + } else if ((!lineError) && (blockDepth > 0)) { + if (stream) { + //action* tmpAction = new action(1); //code 1 = turn on text streaming + action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS); + if (tmpAction == NULL) { + pcPtr->printf("Error: no memory slots available.\r\n"); + lineError = true; + } else { + tmpAction->set(1); + tmpEventPtrArray.back()->addAction(tmpAction); + } + + } else { + //action* tmpAction = new action(2); //code 2 = turn on text buffering + action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS); + if (tmpAction == NULL) { + pcPtr->printf("Error: no memory slots available.\r\n"); + lineError = true; + } else { + tmpAction->set(2); + tmpEventPtrArray.back()->addAction(tmpAction); + } + } + } + + //updates command toggles the DIO update messages upon a change------------------ + //examples: updates on; updates off + } else if (tokens[i].compare("updates") == 0) { + if (ifBlockInit || whileBlockInit || elseFlag) { + pcPtr->printf("Error: expected a 'do' statement\r\n"); + lineError = true; + } + bool stream = true; + if ((!lineError)&&(i+1 < sz)){ + if (tokens[i+1].compare("on") == 0) { + stream = true; + } else if (tokens[i+1].compare("off") == 0) { + stream = false; + } else { + pcPtr->printf("Error: 'updates' useage: 'updates on' or 'updates off'\r\n"); + lineError = true; + } + } + i++; + if ((!lineError) && (blockDepth == 0)) { + if (stream) { + broadCastStateChanges = true; + } else { + broadCastStateChanges = false; + } + } else if ((!lineError) && (blockDepth > 0)) { + if (stream) { + //action* tmpAction = new action(3); //code 3 = turn on updates + action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS); + if (tmpAction == NULL) { + pcPtr->printf("Error: no memory slots available.\r\n"); + lineError = true; + } else { + tmpAction->set(3); + tmpEventPtrArray.back()->addAction(tmpAction); + } + } else { + //action* tmpAction = new action(4); //code 4 = turn off updates + action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS); + if (tmpAction == NULL) { + pcPtr->printf("Error: no memory slots available.\r\n"); + lineError = true; + } else { + tmpAction->set(4); + tmpEventPtrArray.back()->addAction(tmpAction); + } + + } + } + + //clear is used to clear things from memory--------------------------------- + //examples: clear all; clear callbacks; clear queue + } else if (tokens[i].compare("ram") == 0) { + if (ifBlockInit || whileBlockInit || elseFlag) { + pcPtr->printf("Error: expected a 'do' statement\r\n"); + lineError = true; + } + if ((!lineError) && (blockDepth > 0)) { + pcPtr->printf("Error: ram statement is not allowed inside a block.\r\n"); + lineError = true; + } + if (!lineError) { + DisplayRAMBanks(); + } + } else if (tokens[i].compare("memory") == 0) { + if (ifBlockInit || whileBlockInit || elseFlag) { + pcPtr->printf("Error: expected a 'do' statement\r\n"); + lineError = true; + } + if ((!lineError) && (blockDepth > 0)) { + pcPtr->printf("Error: memory statement is not allowed inside a block.\r\n"); + lineError = true; + } + if (!lineError) { + displayMemoryLeft(); + } + + + } else if (tokens[i].compare("clear") == 0) { //delete all created events and variables + if (ifBlockInit || whileBlockInit || elseFlag) { + pcPtr->printf("Error: expected a 'do' statement\r\n"); + lineError = true; + } + int clearMode = 0; + if ((!lineError)&&(i+1 < sz)){ + if (tokens[i+1].compare("all") == 0) { + clearMode = 1; + } else if (tokens[i+1].compare("blocks") == 0) { + clearMode = 2; + } else if (tokens[i+1].compare("queue") == 0) { + clearMode = 3; + } else { + pcPtr->printf("Error: clear what: all, blocks, or queue? \r\n"); + lineError = true; + } + } else { + pcPtr->printf("Error: clear what: all, blocks, or queue? \r\n"); + lineError = true; + } + + + if ((!lineError) && (clearMode < 3) && (blockDepth > 0)) { + pcPtr->printf("Error: 'clear all' and 'clear blocks' only allowed outside of block structures\r\n"); + lineError = true; + } + if (!lineError) { + i++; + //clear variables + if (clearMode == 1) { + while (!globalVariables.empty()) { + globalVariables.pop_back(); + } + } + + //clear callbacks, functions, and queue + if (clearMode < 3) { + for (int pNum = 1; pNum <= numPorts; pNum++) { + //delete portVector[pNum]->triggerUpEventPtr; + if (portVector[pNum]->triggerUpEventPtr != NULL) { + portVector[pNum]->triggerUpEventPtr->release(); + } + portVector[pNum]->triggerUpEventPtr = NULL; + + //delete portVector[pNum]->triggerDownEventPtr; + if (portVector[pNum]->triggerDownEventPtr != NULL) { + portVector[pNum]->triggerDownEventPtr->release(); + } + portVector[pNum]->triggerDownEventPtr = NULL; + while (!functionArray.empty()) { + delete functionArray.back(); + functionArray.pop_back(); + } + } + + queuePtr->eraseQueue(); + } + + if (clearMode == 4) { + if (blockDepth > 0) { //we are inside a block + action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS); + if (tmpAction == NULL) { + pcPtr->printf("Error: no memory slots available.\r\n"); + lineError = true; + } else { + + int8_t code = 0; + tmpAction->set(code); + //action* tmpAction = new action(code); //code 0 = clear queue + tmpEventPtrArray.back()->addAction(tmpAction); + } + } else { + //clear queue now + queuePtr->eraseQueue(); + } + } + + + } + + //do starts a block--------------------------------------------------------- + //example: do in 500 + // ... + // end + + } else if (tokens[i].compare("do") == 0) { //the start of a block + + if (!ifBlockInit && !whileBlockInit) { + + if ((currentTriggerPort > 0) || (currentFunction > 0)) { //check to make sure we are inside a trigger block + //pcPtr->printf("Start new block\r\n"); + + } else { + pcPtr->printf("Error: a statement block must be placed inside a callback or function.\r\n"); + lineError = true; + } + + } + tmpEvent = findFirstUnUsed(eventBlock, NUMEVENTS); + action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS); + bool eventReserved = false; + if ((tmpEvent == NULL)||(tmpAction == NULL)) { + pcPtr->printf("Error: no memory slots available.\r\n"); + lineError = true; + + } else { + + + } + + if (i+2 < sz) { //a time delay in the block + + if ((!lineError) && (tokens[i+1].compare("in") == 0) && (isNumber(tokens[i+2]))) { + + currentDelay = atoi(tokens[i+2].data()); + if (currentDelay < 0) { + pcPtr->printf("Error: block delay time must be a positive integer\r\n"); + lineError = true; + } else if (!ifBlockInit) { //a standalone do block + //tmpEvent = new event(queuePtr); + tmpEvent->isUsed = true; + eventReserved = true; + tmpEvent->setTimeLag(currentDelay); + + if ((!elseFlag) && ((!thenFlag))) { + //tmpEventPtrArray.back()->addAction(new action(tmpEvent)); + tmpAction->set(tmpEvent); + tmpEventPtrArray.back()->addAction(tmpAction); + tmpEventPtrArray.push_back(tmpEvent); + tmpEventPtrArray.back()->blockType = 2; //this is a do block + blockDepth = blockDepth+1; + } else if (elseFlag) { + tmpEventPtrArray.back()->setNextElseEvent(tmpEvent); + tmpEventPtrArray.push_back(tmpEvent); + tmpEventPtrArray.back()->blockType = 4; //an else block + } else if (thenFlag) { + + tmpEventPtrArray.back()->setNextElseEvent(tmpEvent); + tmpEventPtrArray.push_back(tmpEvent); + tmpEventPtrArray.back()->blockType = 8; //a then block + } + //pcPtr->printf("Block delay: %d\r\n", tmpEventPtrArray.back()->timeLag); + } else { //an if block + tmpEventPtrArray.back()->setTimeLag(currentDelay); + + if (!elseFlag && !thenFlag) { + if (blockDepth > 1) { //this is a nested block, so add it as an action to the parent block + tmpAction->set(tmpEventPtrArray.back()); + tmpEventPtrArray.at(tmpEventPtrArray.size()-2)->addAction(tmpAction); + //tmpEventPtrArray.at(tmpEventPtrArray.size()-2)->addAction(new action(tmpEventPtrArray.back())); + } + } else if (elseFlag){ + tmpEventPtrArray.at(tmpEventPtrArray.size()-2)->setNextElseEvent(tmpEventPtrArray.back()); + } else if (thenFlag){ + tmpEventPtrArray.at(tmpEventPtrArray.size()-2)->setNextElseEvent(tmpEventPtrArray.back()); + + } + //pcPtr->printf("Block delay: %d\r\n", tmpEventPtrArray.back()->timeLag); + + } + + } else if ((!lineError) && (tokens[i+1].compare("in") == 0) && (findIntVariable(tokens[i+2])!=NULL)) { + + int* delayVar = findIntVariable(tokens[i+2]); + //currentDelay = atoi(tokens[i+2].data()); + if (!ifBlockInit) { //a standalone do block + //tmpEvent = new event(queuePtr); + tmpEvent->isUsed = true; + eventReserved = true; + tmpEvent->setTimeLag(delayVar); + + if ((!elseFlag) && ((!thenFlag))) { + //tmpEventPtrArray.back()->addAction(new action(tmpEvent)); + tmpAction->set(tmpEvent); + tmpEventPtrArray.back()->addAction(tmpAction); + tmpEventPtrArray.push_back(tmpEvent); + tmpEventPtrArray.back()->blockType = 2; //this is a do block + blockDepth = blockDepth+1; + } else if (elseFlag) { + tmpEventPtrArray.back()->setNextElseEvent(tmpEvent); + tmpEventPtrArray.push_back(tmpEvent); + tmpEventPtrArray.back()->blockType = 4; //an else block + } else if (thenFlag) { + + tmpEventPtrArray.back()->setNextElseEvent(tmpEvent); + tmpEventPtrArray.push_back(tmpEvent); + tmpEventPtrArray.back()->blockType = 8; //a then block + } + //pcPtr->printf("Block delay: %d\r\n", tmpEventPtrArray.back()->timeLag); + } else { //an if block + tmpEventPtrArray.back()->setTimeLag(delayVar); + + if (!elseFlag && !thenFlag) { + if (blockDepth > 1) { //this is a nested block, so add it as an action to the parent block + tmpAction->set(tmpEventPtrArray.back()); + tmpEventPtrArray.at(tmpEventPtrArray.size()-2)->addAction(tmpAction); + //tmpEventPtrArray.at(tmpEventPtrArray.size()-2)->addAction(new action(tmpEventPtrArray.back())); + } + } else if (elseFlag){ + tmpEventPtrArray.at(tmpEventPtrArray.size()-2)->setNextElseEvent(tmpEventPtrArray.back()); + } else if (thenFlag){ + tmpEventPtrArray.at(tmpEventPtrArray.size()-2)->setNextElseEvent(tmpEventPtrArray.back()); + + } + //pcPtr->printf("Block delay: %d\r\n", tmpEventPtrArray.back()->timeLag); + + } + + } else { + pcPtr->printf("Error: block delay time must be a positive integer or a variable\r\n"); + lineError = true; + } + } else if (!lineError && !ifBlockInit) { //no time delay given, standalone do + currentDelay = 0; + //tmpEvent = new event(queuePtr); + tmpEvent->isUsed = true; + eventReserved = true; + tmpEvent->setTimeLag(currentDelay); + if (!elseFlag && !thenFlag) { + tmpAction->set(tmpEvent); + tmpEventPtrArray.back()->addAction(tmpAction); + //tmpEventPtrArray.back()->addAction(new action(tmpEvent)); + tmpEventPtrArray.push_back(tmpEvent); + blockDepth = blockDepth+1; + } else if (elseFlag) { + tmpEventPtrArray.back()->setNextElseEvent(tmpEvent); + tmpEventPtrArray.push_back(tmpEvent); + tmpEventPtrArray.back()->blockType = 4; //an else block + } else if (thenFlag) { + tmpEventPtrArray.back()->setNextElseEvent(tmpEvent); + tmpEventPtrArray.push_back(tmpEvent); + tmpEventPtrArray.back()->blockType = 8; //a then block + } + //pcPtr->printf("Block delay: %d\r\n", tmpEventPtrArray.back()->timeLag); + } else if (!lineError) { //no time delay, if block + + currentDelay = 0; + tmpEventPtrArray.back()->setTimeLag(currentDelay); + + + if (!elseFlag && !thenFlag) { + if (blockDepth > 1) { + tmpAction->set(tmpEventPtrArray.back()); + tmpEventPtrArray.at(tmpEventPtrArray.size()-2)->addAction(tmpAction); + //tmpEventPtrArray.at(tmpEventPtrArray.size()-2)->addAction(new action(tmpEventPtrArray.back())); + } + } else { + tmpEventPtrArray.at(tmpEventPtrArray.size()-2)->setNextElseEvent(tmpEventPtrArray.back()); + } + + + //pcPtr->printf("Block delay: %d\r\n", tmpEventPtrArray.back()->timeLag); + } + if (lineError && eventReserved) { + tmpEvent->release(); + } + //close block initiation + ifBlockInit = false; + whileBlockInit = false; + wholeLineEvaluated = true; + elseFlag = false; + thenFlag = false; + + //callback starts a callback block------------------------------------------ + //exmaple: callback portin(1) down + // ... + // end + } else if (tokens[i].compare("callback") == 0) { //a new callback block + if (ifBlockInit || whileBlockInit || elseFlag) { + pcPtr->printf("Error: expected a 'do' statement\r\n"); + lineError = true; + } + if (blockDepth != 0) { + pcPtr->printf("Error: Can't declare a callback block within another block\r\n"); + lineError = true; + } + if (!lineError) { + wholeLineEvaluated = true; + if (i+2 < sz) { + if ((tokens[i+1].find("portin[") != std::string::npos) && (tokens[i+1].size() > 8) ) { //callback for a digital port + int pos1 = tokens[i+1].find("portin[")+7; + int pos2 = tokens[i+1].find_first_of("]",pos1); + currentTriggerPort = atoi(tokens[i+1].substr(pos1,pos2-pos1).data()); + + if (currentTriggerPort <= 0) { + currentTriggerPort = -1; + pcPtr->printf("Error: Not a valid port number\r\n"); + lineError = true; + } + } else { + pcPtr->printf("Error: Not a valid callback input\r\n"); + lineError = true; + } + if (tokens[i+2].compare("up") == 0) { + currentTriggerDir = 1; + } else if (tokens[i+2].compare("down") == 0) { + currentTriggerDir = -1; + } else { + pcPtr->printf("Error: No trigger direction given\r\n"); + lineError = true; + } + + } else { + if (!lineError) pcPtr->printf("Error: Not enough arguments for callback statement\r\n"); + lineError = true; + } + if (sz > 3) { + if (!((sz == 4) && (tokens[i+3].compare("do") == 0))) { + pcPtr->printf("Error: Too many arguments in callback statement\r\n"); + lineError = true; + } + } + + tmpEvent = findFirstUnUsed(eventBlock, NUMEVENTS); + if (tmpEvent != NULL) { + tmpEvent->isUsed = true; + + } else { + pcPtr->printf("Error: no memory slots available.\r\n"); + lineError = true; + } + if (!lineError) { + //pcPtr->printf("Current port: %d\r\n", currentTriggerPort); + blockDepth = 1; + i = i+2; + //create new event and attach it to the port + //tmpEventPtrArray.push_back(new event(queuePtr)); + tmpEventPtrArray.push_back(tmpEvent); + if (currentTriggerDir == 1) { + + portVector[currentTriggerPort]->setTriggerUpEvent(tmpEventPtrArray.back()); + } else { + + portVector[currentTriggerPort]->setTriggerDownEvent(tmpEventPtrArray.back()); + } + + } + } + + //if starts an if block---------------------------------------------- + //examples: if x < 10 && y == 1 do; if a==1 do in 1000 + } else if (tokens[i].compare("if") == 0) { //a new if block + if (ifBlockInit || whileBlockInit) { + pcPtr->printf("Error: expected a 'do' statement\r\n"); + lineError = true; + } + + ifBlockInit = true; + currentDelay = 0; + bool eventDefined = false; + tmpEvent = findFirstUnUsed(eventBlock, NUMEVENTS); + if (tmpEvent != NULL) { + tmpEvent->isUsed = true; + eventDefined = true; + } else { + pcPtr->printf("Error: no memory slots available.\r\n"); + lineError = true; + } + if (!lineError) { + //this is a regular event + //tmpEventPtrArray.push_back(new event(queuePtr)); + tmpEventPtrArray.push_back(tmpEvent); + + if ((!elseFlag) && ((!thenFlag))) { + tmpEventPtrArray.back()->blockType = 1; //this is an if block + blockDepth = blockDepth + 1; + } else if (elseFlag) { + tmpEventPtrArray.back()->blockType = 3; //this is an else if block + } else if (thenFlag) { + tmpEventPtrArray.back()->blockType = 7; //this is a then if block + } + } + + if (!lineError) { + //combine the condition tokens without whitespaces + tmpString = ""; + for (unsigned j = i+1; j < sz; j++) { + if (tokens[j].compare("do") != 0) { + i++; + tmpString.append(tokens[j]); + } else { + break; + } + } + //adds the conditions to the current event + + if (!evaluateConditions(tmpString, tmpEventPtrArray.back())) lineError = true; + } + + if (lineError && eventDefined) { + tmpEvent->release(); + } + + + //else starts an else block------------------------------------- + //examples: else do in 500; else if x==7 do + } else if (tokens[i].compare("else") == 0) { //an else block + if (ifBlockInit || whileBlockInit) { + pcPtr->printf("Error: expected a 'do' statement\r\n"); + lineError = true; + } + + //trigger blocks can't have else conditions + if ((!lineError) && (blockDepth < 2) && (currentTriggerPort > -1)) { + pcPtr->printf("Error: else statement can not occur after a trigger block or outside a block\r\n"); + lineError = true; + } + + //check to make sure we are in an 'if' block + if ((!lineError) && (tmpEventPtrArray.back()->blockType != 1) && (tmpEventPtrArray.back()->blockType != 3)) { //not currently in an 'if' or 'else if' block + pcPtr->printf("Error: else statement can only occur in an 'if' block\r\n"); + lineError = true; + } + if (!lineError) { + elseFlag = true; + + } + } else if (tokens[i].compare("then") == 0) { //a then block + if (ifBlockInit || whileBlockInit) { + pcPtr->printf("Error: expected a 'do' statement\r\n"); + lineError = true; + } + + //trigger blocks can't have else conditions + if ((!lineError) && (blockDepth < 2) && (currentTriggerPort > -1)) { + pcPtr->printf("Error: 'then' statement can only occur after a 'while' block\r\n"); + lineError = true; + } + + //check to make sure we are in a 'while' block + if ((!lineError) && (tmpEventPtrArray.back()->blockType != 5)) { //not currently in a while block + pcPtr->printf("Error: 'then' statement can only occur in a 'while' block\r\n"); + lineError = true; + } + if (!lineError) { + thenFlag = true; + + } + //while starts a while block---------------------------------------- + //example: while x<10 do every 100 + // ... + // end + } else if (tokens[i].compare("while") == 0) { //a new while block + if (ifBlockInit || whileBlockInit) { + pcPtr->printf("Error: expected a 'do' statement\r\n"); + lineError = true; + } + + if ((currentTriggerPort > 0) || (currentFunction > 0)) { //check to make sure we are inside a trigger block + //pcPtr->printf("Start new block\r\n"); + + } else { + pcPtr->printf("Error: a statement block must be placed inside a callback or function.\r\n"); + lineError = true; + } + //whileBlockInit = true; + currentDelay = 0; + + tmpEvent = findFirstUnUsed(eventBlock, NUMEVENTS); + if (tmpEvent != NULL) { + tmpEvent->isUsed = true; + tmpEvent->setTimeLag(currentDelay); + } else { + pcPtr->printf("Error: no memory slots available.\r\n"); + lineError = true; + } + + //tmpEvent = new event(queuePtr); + + + if (!lineError) { + //combine the condition tokens without whitespaces + tmpString = ""; + for (unsigned j = i+1; j < sz; j++) { + if (tokens[j].compare("do") != 0) { + i++; + tmpString.append(tokens[j]); + } else { + break; + } + } + //adds the conditions to the current event + if (!evaluateConditions(tmpString, tmpEvent)) lineError = true; + } + + if (!lineError) { + if ((i+3) < sz) { + if ((tokens[i+1].compare("do") == 0) && (tokens[i+2].compare("every") == 0)) { + + if (isNumber(tokens[i+3])) { + uint32_t period = atoi(tokens[i+3].data()); + if (period > 0) { + //pcPtr->printf("While block\r\n"); + + //tmpEvent->whileLoopPeriod = period; + tmpEvent->setWhileLoopPeriod(period); + if (!elseFlag) { + tmpEvent->blockType = 5; //this is a while block + + action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS); + if (tmpAction == NULL) { + pcPtr->printf("Error: no memory slots available.\r\n"); + lineError = true; + } else { + tmpAction->set(tmpEvent); + } + //tmpEventPtrArray.back()->addAction(new action(tmpEvent)); + tmpEventPtrArray.back()->addAction(tmpAction); + + tmpEventPtrArray.push_back(tmpEvent); + blockDepth = blockDepth+1; + } else { + tmpEvent->blockType = 6; //this is an else while block + tmpEventPtrArray.back()->setNextElseEvent(tmpEvent); + tmpEventPtrArray.push_back(tmpEvent); + } + wholeLineEvaluated = true; + } else { + pcPtr->printf("Error: loop period must be a positive integer.\r\n"); + lineError = true; + } + } else if (findIntVariable(tokens[i+3])!=NULL) { + + int* period = findIntVariable(tokens[i+3]); + //tmpEvent->whileLoopPeriodVar = period; + tmpEvent->setWhileLoopPeriod(period); + if (!elseFlag) { + tmpEvent->blockType = 5; //this is a while block + + action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS); + if (tmpAction == NULL) { + pcPtr->printf("Error: no memory slots available.\r\n"); + lineError = true; + } else { + tmpAction->set(tmpEvent); + } + //tmpEventPtrArray.back()->addAction(new action(tmpEvent)); + tmpEventPtrArray.back()->addAction(tmpAction); + + tmpEventPtrArray.push_back(tmpEvent); + blockDepth = blockDepth+1; + } else { + tmpEvent->blockType = 6; //this is an else while block + tmpEventPtrArray.back()->setNextElseEvent(tmpEvent); + tmpEventPtrArray.push_back(tmpEvent); + } + wholeLineEvaluated = true; + } + } else { + pcPtr->printf("Error: expected a 'do every' statement\r\n"); + lineError = true; + } + } else { + pcPtr->printf("Error: expected a 'do every' statement\r\n"); + lineError = true; + } + } + + //if the line contains an '=' sign,the equality is evaulated------------------------- + //examples: a = 1; a = b + 5; a = random(100); portout[2] = 1; portout[2] = flip + } else if ((tmpLine.find_first_of("=") != std::string::npos) ) { //an expression + if (ifBlockInit || whileBlockInit || elseFlag) { + pcPtr->printf("Error: expected a 'do' statement\r\n"); + lineError = true; + } + + wholeLineEvaluated = true; + tmpString = ""; + int spacesBeforeEqualSign = 0; + bool countSpaces = true; + //combine the tokens without whitespaces + for (unsigned j = i; j < sz; j++) { + tmpString.append(tokens[j]); + if (tokens[j].find_first_of("=") != std::string::npos) { + if (tokens[j].find_first_of("=") > 0) spacesBeforeEqualSign++; + countSpaces = false; + } else if (countSpaces) { + spacesBeforeEqualSign++; + } + } + if (!lineError && spacesBeforeEqualSign > 1) { + pcPtr->printf("Error: Variable can't have a space in it.\r\n"); + lineError = true; + } + + if (!lineError) { + if (blockDepth > 0) { + action* tmpAction = evaluateAssignmentForAction(tmpString); + if (tmpAction != NULL) { + tmpEventPtrArray.back()->addAction(tmpAction); + //pcPtr->printf("Added action with delay: %d\r\n", tmpEventPtrArray.back()->timeLag); + + } else { + lineError = true; + } + + } else { //assignment was written outside of any block structure, so execute now + + + action* tmpAction = evaluateAssignmentForAction(tmpString); + + if (tmpAction != NULL) { + tmpAction->execute(); + //delete tmpAction; + tmpAction->release(); + } else { + lineError = true; + } + } + } + } else { + //if there was no match to any of the above, an error is given + pcPtr->printf("Error: statement not understood.\r\n"); + lineError = true; + } + + if (lineError) break; //stop parsing the rest of the line if an error was detected + + if (wholeLineEvaluated) { //some of the tokens forces the whole line to be avaluated at once + i = sz; //skip ahead to end of the line + } + + } + + //if there was an error, we quit compiling the code + if (lineError) { + pcPtr->printf("Line text: "); + while (!tokens.empty()) { + pcPtr->printf("%s ",tokens.front().data()); + tokens.erase(tokens.begin()); + } + pcPtr->printf("\r\n"); + while (!currentBlock.empty()) { + currentBlock.pop_back(); + } + delete tmpEvent; + } else { + + while (!tokens.empty()) { + tokens.pop_back(); + } + currentBlock.pop_back(); + } + + } + + //make sure that all blocks have a matching end statement + if ((!lineError)&&(blockDepth > 0)) { + pcPtr->printf("Error: Missing 1 or more end statements\r\n"); + lineError = true; + } + //pcPtr->printf("~~~\r\n"); //signals that the code was compiled + textDisplay.send("~~~\r\n"); + //displayMemoryLeft(); + //DisplayRAMBanks(); + +} + + +//used to return a pointer to a variable, if it exists +int* scriptStream::findIntVariable(string nameInput) { + + int* outPtr = NULL; + bool foundIt = false; + + if (nameInput.find("portout") != std::string::npos) { + int pos1 = nameInput.find("portout[")+8; + int pos2 = nameInput.find_first_of("]",pos1); + int portnum = atoi(nameInput.substr(pos1,pos2-pos1).data()); + int portVal = 0; + if ((portnum > 0) && (portnum <= numPorts)) { + outPtr = &portVector[portnum]->outState; + foundIt = true; + } + } else if (nameInput.find("portin") != std::string::npos) { + int pos1 = nameInput.find("portin[")+7; + int pos2 = nameInput.find_first_of("]",pos1); + int portnum = atoi(nameInput.substr(pos1,pos2-pos1).data()); + int portVal = 0; + if ((portnum > 0) && (portnum <= numPorts)) { + outPtr = &portVector[portnum]->inState; + foundIt = true; + } + } + + if (!foundIt) { + std::vector<intVariable*>::size_type sz = globalVariables.size(); + for (unsigned i = 0; i < sz; i++) { + if (nameInput.compare(globalVariables[i]->tag) == 0) { + outPtr = &globalVariables[i]->value; + break; + } + } + } + + return outPtr; +} + +bool scriptStream::createIntVariable(string nameInput) { + if (findIntVariable(nameInput) == NULL) { + globalVariables.push_back(new intVariable(nameInput, 0)); + return true; + } else { + return false; + } +} + + +action* scriptStream::evaluateAssignmentForAction(string expression) { + + //action* tmpAction = new action(); //create a new action + action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS); + if (tmpAction == NULL) { + pcPtr->printf("Error: no action memory slots available.\r\n"); + return NULL; + } + std::size_t stringInd; + std::size_t stringInd2; + string afterEqual; + string beforeEqual; + //The expression might have up to three variables + int* tmpVar; + int* tmpVar2; + int* tmpVar3; + stringInd = expression.find_first_of("="); //location of = sign, if it exists + beforeEqual = expression.substr(0,stringInd); // the string after the = sign + afterEqual = expression.substr(stringInd+1,std::string::npos); // the string after the = sign + stringInd2 = afterEqual.find_first_of("+-"); //location of +/- sign (only one allowed) + tmpVar = findIntVariable(expression.substr(0,stringInd)); //returns pointer to the variable + + if (beforeEqual.find("portout[") != std::string::npos) { //set the output of a digital port + int pos1 = beforeEqual.find("portout[")+8; + int pos2 = beforeEqual.find_first_of("]",pos1); + int portnum = atoi(beforeEqual.substr(pos1,pos2-pos1).data()); + int* tmpVar = findIntVariable(beforeEqual.substr(pos1,pos2-pos1)); //returns pointer to the variable, if given + int portVal = 0; + if ((tmpVar != NULL)||((portnum > 0) && (portnum <= numPorts))) { + if (isNumber(afterEqual)) { //a simple numeric assign + portVal = atoi(afterEqual.data()); + if ((portVal == 0) || (portVal == 1)) { + //portMessage* tmpMessage = new portMessage(portVector[portnum],1,portVal); + portMessage* tmpMessage = findFirstUnUsed(portMessageBlock, NUMPORTMESSAGES); + if (tmpMessage == NULL) { + pcPtr->printf("Error: no memory slots available.\r\n"); + tmpAction->release(); + return NULL; + } else { + //tmpMessage->setMessage(portVector[portnum],1,portVal); + if (tmpVar == NULL) { //a constant port number was given + tmpMessage->setMessage(NULL,portnum,portVal); + } else { + tmpMessage->setMessage(tmpVar,0,portVal); + } + } + + + tmpAction->set(tmpMessage); + //pcPtr->printf("Action: digital port %d set to %d\r\n",portnum,portVal); + } else { + pcPtr->printf("Error: portouts can only be directly assigned a 1, 0 or 'flip'\r\n"); + //delete tmpAction; + tmpAction->release(); + return NULL; + } + } else if (afterEqual.compare("flip") == 0) { + //portMessage* tmpMessage = new portMessage(portVector[portnum],1,-1); + portMessage* tmpMessage = findFirstUnUsed(portMessageBlock, NUMPORTMESSAGES); + if (tmpMessage == NULL) { + pcPtr->printf("Error: no memory slots available.\r\n"); + tmpAction->release(); + return NULL; + } else { + //tmpMessage->setMessage(portVector[portnum],1,-1); + if (tmpVar == NULL) { //a constant port number was given + tmpMessage->setMessage(NULL,portnum,portVal); + } else { + tmpMessage->setMessage(tmpVar,0,portVal); + } + } + tmpAction->set(tmpMessage); + } else { + pcPtr->printf("Error: portouts can only be directly assigned a 1, 0, or 'flip'\r\n"); + //delete tmpAction; + tmpAction->release(); + return NULL; + } + } else { + pcPtr->printf("Port number not found (must be between 1 and %d, or an existing variable)\r\n", numPorts); + //delete tmpAction; + tmpAction->release(); + return NULL; + } + } else if (beforeEqual.find("portin") != std::string::npos) { + pcPtr->printf("Error: portins can not be set\r\n"); + //delete tmpAction; + tmpAction->release(); + return NULL; + } else if (tmpVar != NULL) { + intOperation* tmpOp; + intOperation* tmpOp2; + if (isNumber(afterEqual)) { //a simple numeric assign + //tmpOp = new intOperation(tmpVar, "=", atoi(afterEqual.data())); + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp == NULL) { + pcPtr->printf("Error: no memory slots available.\r\n"); + tmpAction->release(); + return NULL; + } else { + tmpOp->set(tmpVar, "=", atoi(afterEqual.data())); + } + tmpAction->set(tmpOp); + //pcPtr->printf("Action: set variable to constant numeric value\r\n"); + } else if ((stringInd2 == std::string::npos)&&(afterEqual.find("random") != std::string::npos)) { + + int highVal = getRandomParam(afterEqual); + + if (highVal > 0) { + //tmpOp = new intOperation(highVal, "=", tmpVar); //for random assignment, we reverse the input order (because of overloading uniqueness) + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp == NULL) { + pcPtr->printf("Error: no memory slots available.\r\n"); + tmpAction->release(); + return NULL; + } else { + tmpOp->set(highVal, "=", tmpVar); //for random assignment, we reverse the input order (because of overloading uniqueness) + } + tmpAction->set(tmpOp); + //pcPtr->printf("Action: set variable to random value up to %d\r\n", highVal); + } else { + //delete tmpAction; + tmpAction->release(); + return NULL; + } + + } else if (stringInd2 != std::string::npos) { //a +/- operation is there + string multiplier("+"); + int multiplierInt = 1; + if (afterEqual[stringInd2] == '-') { + multiplier = "-"; + multiplierInt = -1; + } + tmpVar2 = findIntVariable(afterEqual.substr(0,stringInd2)); //before the +/- sign + tmpVar3 = findIntVariable(afterEqual.substr(stringInd2+1,std::string::npos)); //after the +/- sign + + if ((tmpVar2 != NULL) && isNumber(afterEqual.substr(stringInd2+1,std::string::npos))) { //variable +/- number + if (tmpVar2 == tmpVar) { + multiplier.append("="); //final sign is += or -= + //tmpOp = new intOperation(tmpVar, multiplier.data(), atoi(afterEqual.substr(stringInd2+1,std::string::npos).data())); + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp == NULL) { + pcPtr->printf("Error: no memory slots available.\r\n"); + tmpAction->release(); + return NULL; + } else { + tmpOp->set(tmpVar, multiplier.data(), atoi(afterEqual.substr(stringInd2+1,std::string::npos).data())); + } + tmpAction->set(tmpOp); + //pcPtr->printf("Action: change variable by constant amount\r\n"); + } else { + //tmpOp2 = new intOperation(tmpVar2,multiplier.data(), atoi(afterEqual.substr(stringInd2+1,std::string::npos).data())); + //tmpOp = new intOperation(tmpVar, tmpOp2); + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if ((tmpOp == NULL)||(tmpOp2 == NULL)) { + pcPtr->printf("Error: no memory slots available.\r\n"); + tmpAction->release(); + return NULL; + } else { + tmpOp2->set(tmpVar2,multiplier.data(), atoi(afterEqual.substr(stringInd2+1,std::string::npos).data())); + tmpOp->set(tmpVar, tmpOp2); + } + tmpAction->set(tmpOp); + //pcPtr->printf("Action: variable equals expression\r\n"); + } + + } else if ((tmpVar3 != NULL) && isNumber(afterEqual.substr(0,stringInd2))) { //number +/- variable + if (tmpVar3 == tmpVar) { + multiplier.append("="); + //tmpOp = new intOperation(tmpVar, multiplier.data(), atoi(afterEqual.substr(0,stringInd2).data())); + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp == NULL) { + pcPtr->printf("Error: no memory slots available.\r\n"); + tmpAction->release(); + return NULL; + } else { + tmpOp->set(tmpVar, multiplier.data(), atoi(afterEqual.substr(0,stringInd2).data())); + } + tmpAction->set(tmpOp); + //pcPtr->printf("Action: change variable by constant amount\r\n"); + } else { + //tmpOp2 = new intOperation(tmpVar3, multiplier.data(), atoi(afterEqual.substr(0, stringInd2).data())); + //tmpOp = new intOperation(tmpVar, tmpOp2); + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if ((tmpOp == NULL)||(tmpOp2 == NULL)) { + pcPtr->printf("Error: no memory slots available.\r\n"); + tmpAction->release(); + return NULL; + } else { + tmpOp2->set(tmpVar3, multiplier.data(), atoi(afterEqual.substr(0, stringInd2).data())); + tmpOp->set(tmpVar, tmpOp2); + } + tmpAction->set(tmpOp); + //pcPtr->printf("Action: variable equals expression\r\n"); + } + + } else if ((tmpVar2 != NULL) && (tmpVar3 != NULL)) { //variable +/- variable + //tmpOp2 = new intOperation(tmpVar2, multiplier.data(), tmpVar3); + //tmpOp = new intOperation(tmpVar, tmpOp2); + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if ((tmpOp == NULL)||(tmpOp2 == NULL)) { + pcPtr->printf("Error: no memory slots available.\r\n"); + tmpAction->release(); + return NULL; + } else { + tmpOp2->set(tmpVar2, multiplier.data(), tmpVar3); + tmpOp->set(tmpVar, tmpOp2); + } + tmpAction->set(tmpOp); + //pcPtr->printf("Action: set variable to operation involving two variables\r\n"); + //tmpVar->value = tmpVar2->value + (multiplier * tmpVar3->value); + } else if ( isNumber(afterEqual.substr(stringInd2+1,std::string::npos)) && isNumber(afterEqual.substr(0,stringInd2)) ) { //number +/- number + //tmpOp = new intOperation(tmpVar, "=", atoi(afterEqual.substr(0,stringInd2).data()) + (multiplierInt * atoi(afterEqual.substr(stringInd2+1,std::string::npos).data()))); + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp == NULL) { + pcPtr->printf("Error: no memory slots available.\r\n"); + tmpAction->release(); + return NULL; + } else { + tmpOp->set(tmpVar, "=", atoi(afterEqual.substr(0,stringInd2).data()) + (multiplierInt * atoi(afterEqual.substr(stringInd2+1,std::string::npos).data()))); + } + tmpAction->set(tmpOp); + //pcPtr->printf("Action: set variable to constant numeric value\r\n"); + + } else if ((afterEqual.substr(0,stringInd2).find("random") != std::string::npos) && isNumber(afterEqual.substr(stringInd2+1,std::string::npos))) { //random +/- number + int highVal = getRandomParam(afterEqual.substr(0,stringInd2)); + + if (highVal > 0) { + //tmpOp2 = new intOperation(highVal, multiplier.data(), atoi(afterEqual.substr(stringInd2+1,std::string::npos).data())); + //tmpOp = new intOperation(tmpVar, tmpOp2); + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if ((tmpOp == NULL)||(tmpOp2 == NULL)) { + pcPtr->printf("Error: no memory slots available.\r\n"); + tmpAction->release(); + return NULL; + } else { + tmpOp2->set(highVal, multiplier.data(), atoi(afterEqual.substr(stringInd2+1,std::string::npos).data())); + tmpOp->set(tmpVar, tmpOp2); + } + tmpAction->set(tmpOp); + //pcPtr->printf("Action: set variable to random value plus number %d\r\n", highVal); + } else { + //delete tmpAction; + tmpAction->release(); + return NULL; + } + } else if ((afterEqual.substr(0,stringInd2).find("random") != std::string::npos) && (tmpVar3 != NULL)) { //random +/- variable + int highVal = getRandomParam(afterEqual.substr(0,stringInd2)); + + if (highVal > 0) { + //tmpOp2 = new intOperation(highVal, multiplier.data(), tmpVar3); + //tmpOp = new intOperation(tmpVar, tmpOp2); + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if ((tmpOp == NULL)||(tmpOp2 == NULL)) { + pcPtr->printf("Error: no memory slots available.\r\n"); + tmpAction->release(); + return NULL; + } else { + tmpOp2->set(highVal, multiplier.data(), tmpVar3); + tmpOp->set(tmpVar, tmpOp2); + } + tmpAction->set(tmpOp); + //pcPtr->printf("Action: set variable to random value plus number %d\r\n", highVal); + } else { + //delete tmpAction; + tmpAction->release(); + return NULL; + } + + + } else if ((afterEqual.substr(stringInd2+1,std::string::npos).find("random") != std::string::npos) && isNumber(afterEqual.substr(0,stringInd2))) { //random +/- number + int highVal = getRandomParam(afterEqual.substr(stringInd2+1,std::string::npos)); + + if (highVal > 0) { + //tmpOp2 = new intOperation(highVal, multiplier.data(), atoi(afterEqual.substr(0, stringInd2).data())); + //tmpOp = new intOperation(tmpVar, tmpOp2); + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if ((tmpOp == NULL)||(tmpOp2 == NULL)) { + pcPtr->printf("Error: no memory slots available.\r\n"); + tmpAction->release(); + return NULL; + } else { + tmpOp2->set(highVal, multiplier.data(), atoi(afterEqual.substr(0, stringInd2).data())); + tmpOp->set(tmpVar, tmpOp2); + } + tmpAction->set(tmpOp); + //pcPtr->printf("Action: set variable to random value plus number %d\r\n", highVal); + } else { + //delete tmpAction; + tmpAction->release(); + return NULL; + } + } else if ((afterEqual.substr(stringInd2+1,std::string::npos).find("random") != std::string::npos) && (tmpVar2 != NULL)) { //random +/- number + int highVal = getRandomParam(afterEqual.substr(stringInd2+1,std::string::npos)); + + if (highVal > 0) { + //tmpOp2 = new intOperation(highVal, multiplier.data(), tmpVar2); + //tmpOp = new intOperation(tmpVar, tmpOp2); + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if ((tmpOp == NULL)||(tmpOp2 == NULL)) { + pcPtr->printf("Error: no memory slots available.\r\n"); + tmpAction->release(); + return NULL; + } else { + tmpOp2->set(highVal, multiplier.data(), tmpVar2); + tmpOp->set(tmpVar, tmpOp2); + } + tmpAction->set(tmpOp); + //pcPtr->printf("Action: set variable to random value plus number %d\r\n", highVal); + } else { + //delete tmpAction; + tmpAction->release(); + return NULL; + } + } else { + pcPtr->printf("Expression not understood: %s\r\n",afterEqual.data()); + //delete tmpAction; + tmpAction->release(); + return NULL; + } + + } else if (findIntVariable(afterEqual) != NULL) { //assign value of another variable + //tmpOp = new intOperation(tmpVar, "=", findIntVariable(afterEqual)); + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp == NULL) { + pcPtr->printf("Error: no memory slots available.\r\n"); + tmpAction->release(); + return NULL; + } else { + tmpOp->set(tmpVar, "=", findIntVariable(afterEqual)); + } + tmpAction->set(tmpOp); + //pcPtr->printf("Action: set variable to value of another\r\n"); + } else { + pcPtr->printf("Variable not found: %s\r\n",afterEqual.data()); + //delete tmpAction; + tmpAction->release(); + return NULL; + } + + } else { + pcPtr->printf("Variable not found\r\n"); + //delete tmpAction; + tmpAction->release(); + return NULL; + } + return tmpAction; +} + +bool scriptStream::isOutsideParenth(string expression,std::size_t foundItem) { + + int pDepth = 0; // How many nested parentheses + //pcPtr->printf("Check outside parentheses..."); + if (foundItem < expression.length()) { + for (int i = 0; i <= foundItem; i++) { + if (expression[i] == '(') { + pDepth++; + } else if (expression[i] == ')') { + pDepth--; + } + } + if (pDepth<=0) { + //pcPtr->printf("yes."); + return true; + } else { + //pcPtr->printf("no."); + return false; + } + } else { + return true; + } + +} + +std::size_t scriptStream::findFirstOrOutsideParenth(string expression) { + + std::size_t foundItem = expression.find("||"); + while (foundItem != std::string::npos) { + if (isOutsideParenth(expression,foundItem)) { + break; + } + foundItem = expression.find("||",foundItem+1); + } + return foundItem; +} + +std::size_t scriptStream::findFirstAndOutsideParenth(string expression) { + + std::size_t foundItem = expression.find("&&"); + while (foundItem != std::string::npos) { + if (isOutsideParenth(expression,foundItem)){ + break; + } + foundItem = expression.find("&&",foundItem+1); + } + return foundItem; +} + +condition* scriptStream::parseConditions(string expression) { + //This function is used to parse a condition string + //such as (x < y && x != z) || (y == 2) + //This function first identifies the root node of the logic tree + //based on operator precedence ( () > && > || ), and then recursively calls itself + //to find the nodes of the branches. The basic building blocks of + //the final condition object are arithmatic comparitors (a > b) and + //other condition objects. + + + //pcPtr->printf("Parsing condition: %s\r\n", expression.data()); + condition* newCondition = NULL; + bool singleCondition = false; //no compound conditions + string afterComparator; + string beforeComparator; + + std::size_t found; + + //To make a parse tree, we start by looking for operators with the lowest precendence + //so we look for OR conditions first + char currentOperator = OR_CONDITION; + //pcPtr->printf("Looking for OR condition..."); + found = findFirstOrOutsideParenth(expression); + if (found==std::string::npos) { //no or conditions outside parentheses found, so we look for AND conditions + currentOperator = AND_CONDITION; + //pcPtr->printf("Looking for AND condition..."); + found = findFirstAndOutsideParenth(expression); + } + if (found==std::string::npos) { //no or/and conditions outside parentheses found + //if the expression is encapsulated in parentheses, remove the parentheses + bool removedParenth = false; + if ((expression[0] == '(') && (expression[expression.length()-1] == ')')) { + //pcPtr->printf("Remove parentheses"); + expression = expression.substr(1,expression.length()-2); + removedParenth = true; + } + if (removedParenth) { //we removed parentheses, so try again + return parseConditions(expression); + } else { + singleCondition = true; //we assume that the condition is non-compound, i.e., a>b + } + } + + if (singleCondition) { //no compound conditions found + //pcPtr->printf("Single condition"); + std::size_t equalStringInd; + std::size_t greaterOrEqualStringInd; + std::size_t lessThanOrEqualStringInd; + std::size_t notEqualStringInd; + std::size_t greaterThanStringInd; + std::size_t lessThanStringInd; + std::size_t generalCompareStringInd; + + + string tmpCondition = expression; + string compareString; + //The expression might have up to three variables + int* tmpVar; + int* tmpVar2; + int* tmpVar3; + + int offset = 0; + equalStringInd = tmpCondition.find("=="); //location of comparator + greaterOrEqualStringInd = tmpCondition.find(">="); //location of comparator + lessThanOrEqualStringInd = tmpCondition.find("<="); //location of comparator + notEqualStringInd = tmpCondition.find("!="); //location of comparator + greaterThanStringInd = tmpCondition.find_first_of(">"); //location of comparator + lessThanStringInd = tmpCondition.find_first_of("<"); //location of comparator + + if ((equalStringInd != std::string::npos) && (greaterOrEqualStringInd == std::string::npos) && + (lessThanOrEqualStringInd == std::string::npos) && (notEqualStringInd == std::string::npos)){ + + generalCompareStringInd = equalStringInd; + compareString = "=="; + } else if ((equalStringInd == std::string::npos) && (greaterOrEqualStringInd != std::string::npos) && + (lessThanOrEqualStringInd == std::string::npos) && (notEqualStringInd == std::string::npos)){ + + generalCompareStringInd = greaterOrEqualStringInd; + compareString = ">="; + } else if ((equalStringInd == std::string::npos) && (greaterOrEqualStringInd == std::string::npos) && + (lessThanOrEqualStringInd != std::string::npos) && (notEqualStringInd == std::string::npos)){ + + generalCompareStringInd = lessThanOrEqualStringInd; + compareString = "<="; + } else if ((equalStringInd == std::string::npos) && (greaterOrEqualStringInd == std::string::npos) && + (lessThanOrEqualStringInd == std::string::npos) && (notEqualStringInd != std::string::npos)){ + + generalCompareStringInd = notEqualStringInd; + compareString = "!="; + } else if ((equalStringInd == std::string::npos) && (greaterOrEqualStringInd == std::string::npos) && + (lessThanOrEqualStringInd == std::string::npos) && (notEqualStringInd == std::string::npos) && + (greaterThanStringInd != std::string::npos) && (lessThanStringInd == std::string::npos)){ + + generalCompareStringInd = greaterThanStringInd; + compareString = ">"; + offset = 1; + } else if ((equalStringInd == std::string::npos) && (greaterOrEqualStringInd == std::string::npos) && + (lessThanOrEqualStringInd == std::string::npos) && (notEqualStringInd == std::string::npos) && + (greaterThanStringInd == std::string::npos) && (lessThanStringInd != std::string::npos)){ + + generalCompareStringInd = lessThanStringInd; + compareString = "<"; + offset = 1; + + }else { + pcPtr->printf("Condition not understood: %s\r\n", expression.data()); + return 0; + } + + intCompare* newCompare = findFirstUnUsed(intCompareBlock, NUMINTCOMPARE); + if (newCompare == NULL) { + pcPtr->printf("Error: No memory slots available."); + return NULL; + } + newCondition = findFirstUnUsed(conditionBlock, NUMCONDITIONS); + if (newCondition == NULL) { + pcPtr->printf("Error: No memory slots available."); + return NULL; + } + afterComparator = tmpCondition.substr(generalCompareStringInd+2-offset,std::string::npos); + + beforeComparator = tmpCondition.substr(0,generalCompareStringInd); + tmpVar = findIntVariable(beforeComparator); //returns pointer to the variable + if (tmpVar != NULL) { //before the comparator is a single variable + tmpVar2 = findIntVariable(afterComparator); //returns pointer to the variable + if (tmpVar2 != NULL) { //we are comapring a single variable to another + //intCompare* newCompare = new intCompare(tmpVar,compareString.data(),tmpVar2); + //currentEvent->addCondition(new condition(newCompare)); + newCompare->set(tmpVar,compareString.data(),tmpVar2); + newCondition->set(newCompare); + + //pcPtr->printf("Var vs. Var condition added: %s\r\n", tmpCondition.data()); + } else if (isNumber(afterComparator)) { + //intCompare* newCompare = new intCompare(tmpVar,compareString.data(),atoi(afterComparator.data())); + //currentEvent->addCondition(new condition(newCompare)); + newCompare->set(tmpVar,compareString.data(),atoi(afterComparator.data())); + newCondition->set(newCompare); + + //pcPtr->printf("Var vs. Int condition added: %s\r\n", tmpCondition.data()); + } //more here + + } else { + pcPtr->printf("Condition not understood: %s\r\n", expression.data()); + + return NULL; + } + + } else { //this is a compound condition (with either && or ||) + //pcPtr->printf("Compound condition"); + afterComparator = expression.substr(found+2,std::string::npos); + beforeComparator = expression.substr(0,found); + newCondition = findFirstUnUsed(conditionBlock, NUMCONDITIONS); + if (newCondition == NULL) { + pcPtr->printf("Error: No memory slots available."); + return NULL; + } else { + newCondition->isUsed = true; //reserve the condition slot; + } + //recursively call this function to parse the sub conditions + condition* cond1 = parseConditions(beforeComparator); + if (cond1 == NULL) { + newCondition->release(); + return NULL; + } + condition* cond2 = parseConditions(afterComparator); + if (cond2 == NULL) { + newCondition->release(); + cond1->release(); + return NULL; + } + newCondition->set(cond1,currentOperator, cond2); + + } + + return newCondition; //all went well, so return the newly made condition + +} + +bool scriptStream::evaluateConditions(string expression, event* currentEvent) { + //calls the function to parse the condition string. The condition pointer is then + //attached to the event + + condition* newCondition = NULL; + newCondition = parseConditions(expression); + if (newCondition == NULL) { + return false; + } else { + currentEvent->addCondition(newCondition); + return true; + } +} + +int scriptStream::getRandomParam(string expression) { + + int pos1 = expression.find("random(")+7; + int pos2 = expression.find_first_of(")",pos1); + int highVal = atoi(expression.substr(pos1,pos2-pos1).data()); + + if ((highVal > 0)) { + return highVal; + } else { + pcPtr->printf("Error: random parameter must be 1 or more\r\n"); + return 0; + } + } + + + outputStream::outputStream(int bufferSizeIn): + readHead(0), + writeHead(0), + totalWriteHead(0), + totalReadHead(0), + bufferSize(bufferSizeIn), + unsentData(false) { + + outputBuffer = new char[bufferSize]; + + } + + outputStream::~outputStream() { + delete[] outputBuffer; + } + + //adds text to the buffer + void outputStream::send(string outputString) { + int strLen = outputString.size(); + + int total = 0; + int chunk = 0; + if (!(totalWriteHead+strLen > (totalReadHead + bufferSize))) { + while (strLen - total > 0) { + chunk = min((bufferSize - writeHead), strLen - total); + outputString.copy(outputBuffer + writeHead, chunk, total); + writeHead = (writeHead + chunk) % bufferSize; + totalWriteHead += chunk; + total += chunk; + } + if (total > 0) { + unsentData = true; + } + } + } + + //the main loop gets one character per loop and write it to the serial port + char outputStream::getNextChar() { + + + if (totalReadHead < totalWriteHead) { + tmpOut = *(outputBuffer+readHead); + readHead = (readHead+1) % bufferSize; + totalReadHead++; + if (totalReadHead >= totalWriteHead) { + unsentData = false; + } + } + return tmpOut; + + } + \ No newline at end of file