A scripting environment used to define precise output/input temporal relationships.
Dependencies: SMARTWAV mbed HelloWorld
Dependents: perturbRoom_legacy
Fork of HelloWorld by
behave.cpp
- Committer:
- mkarlsso
- Date:
- 2014-07-08
- Revision:
- 2:298679fff37c
- Child:
- 3:ae33b7f5a7c1
File content as of revision 2:298679fff37c:
#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; }