![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
Microcontroller firmware that uses a simple, yet powerful scripting language to control the timing of input and output events with high temporal resolution. Written by Mattias Karlsson
Diff: behave.cpp
- Revision:
- 0:8dbd6bd9167f
- Child:
- 1:3a050d26d4f6
- Child:
- 2:35266b266eaa
diff -r 000000000000 -r 8dbd6bd9167f behave.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/behave.cpp Tue May 19 15:45:42 2015 +0000 @@ -0,0 +1,5434 @@ +#include "behave.h" +#include "hardwareInterface.h" +#include <ctype.h> +#include <sstream> +#include <string.h> +#include <cstdlib> + +using namespace std; + +int16_t randomSeedCounter; //used for seeding random numbers + +//digitalPort* portVector[NUMPORTS+1]; //a list of pointers to the digital ports + +//Main event queue +eventQueue mainQueue; + +//The script parser +//scriptStream parser(portVector, NUMPORTS, &mainQueue); + +//globals defined in hardwareInterface.cpp +extern uint32_t timeKeeper; //the master clock +extern bool resetTimer; +extern bool clockSlave; +extern bool changeToSlave; +extern bool changeToStandAlone; +extern outputStream textDisplay; + +//extern int currentDIOstate[2]; +bool broadCastStateChanges; +bool textStreaming; + + + +//These items may be placed in hardware-specific parts of memory + +#ifdef MBEDHARDWARE +//__attribute((section("AHBSRAM0"),aligned)) outputStream textDisplay(512); +__attribute((section("AHBSRAM0"),aligned)) char buffer[256]; +__attribute((section("AHBSRAM1"),aligned)) event eventBlock[NUMEVENTS]; +__attribute((section("AHBSRAM1"),aligned)) condition conditionBlock[NUMCONDITIONS]; +__attribute((section("AHBSRAM1"),aligned)) intCompare intCompareBlock[NUMINTCOMPARE]; +__attribute((section("AHBSRAM0"),aligned)) action actionBlock[NUMACTIONS]; +__attribute((section("AHBSRAM0"),aligned)) portMessage portMessageBlock[NUMPORTMESSAGES]; +//__attribute((section("AHBSRAM1"),aligned)) intVariable intVariableBlock[10]; +__attribute((section("AHBSRAM0"),aligned)) intOperation intOperationBlock[NUMINTOPERATIONS]; +__attribute((section("AHBSRAM0"),aligned)) displayAction displayActionBlock[NUMDISPLAYACTIONS]; +__attribute((section("AHBSRAM0"),aligned)) triggerFunctionAction triggerFunctionActionBlock[NUMTRIGGERACTIONS]; +#endif + +#ifdef FPGAHARDWARE + +char buffer[256]; +event eventBlock[NUMEVENTS]; +condition conditionBlock[NUMCONDITIONS]; +intCompare intCompareBlock[NUMINTCOMPARE]; +action actionBlock[NUMACTIONS]; +portMessage portMessageBlock[NUMPORTMESSAGES]; +intOperation intOperationBlock[NUMINTOPERATIONS]; +displayAction displayActionBlock[NUMDISPLAYACTIONS]; +triggerFunctionAction triggerFunctionActionBlock[NUMTRIGGERACTIONS]; +#endif + + +event* functionEventArray[NUMFUNCTIONS]; +bool functionSpotTaken[NUMFUNCTIONS]; + + +//----------------------------------------------- +//This is the main loop of the program +mainLoop::mainLoop(){ + + +} + +void mainLoop::init() { + currentDIOstate[0] = 0; + currentDIOstate[1] = 0; + digitalInChanged = false; + digitalOutChanged = false; + textStreaming = true; + eraseBuffer(); + broadCastStateChanges = true; + + + +//section for MBED hardware +#ifdef MBEDHARDWARE + hardware = new MBEDSystem(); + hardware->timerinit(); + pc = new MBEDSerialPort(); + pc->init(); + textDisplay.setSerial(pc); + +#endif + +#ifdef FPGAHARDWARE + pc = new FPGASerialPort(); + pc->init(); + + hardware = new FPGASystem(); + hardware->timerinit(); + + textDisplay.setSerial(pc); + + DIO_DCR = DIO_DCR_IE; // enable DIO edge interrupts +#endif + + for (int i = 0; i < NUMPORTS; i++) { + //Set up the ports. Each has two pointers to the harware implementations + //of a digital out and digital in. + ports[i].init(hardware->getDigitalOutPtr(i),hardware->getDigitalInPtr(i)); + } + + + parser = new scriptStream(ports, NUMPORTS, &mainQueue, hardware); + +} + +void mainLoop::exec() { + bool digitalInChanged = false; + bool digitalOutChanged = false; + uint32_t changeTime; + timeKeeper = 0; //set main clock to 0; + + int bufferPos = 0; + + ostringstream timeConvert; // stream used for the conversion + ostringstream stateConvert; + int tmpChar; + int junkChar; + + uint16_t shortcutTriggers[PENDINGTRIGGERBUFFERSIZE]; + int numTriggersToProcess; + + while (pc->readable()) { + junkChar = pc->readChar(); + } + +#ifdef MBEDHARDWARE + LocalFileSystem local("local"); + + FILE *fp = fopen("/local/STARTUP.TXT", "r"); + if (fp != NULL) { + + textDisplay.send("Executing startup script...\r\n"); + + do { + tmpChar = fgetc(fp); + if ((tmpChar >= 32) && (tmpChar <= 126)) { + buffer[bufferPos] = tmpChar; + bufferPos++; + } + if ((tmpChar == 13) || (tmpChar == 10)) { //carrriage return + parser->addLineToCurrentBlock(buffer); + bufferPos = 0; + eraseBuffer(); + } + //pc.putc(tmpChar); + } while (tmpChar != EOF); + + buffer[bufferPos] = 59; + parser->addLineToCurrentBlock(buffer); + eraseBuffer(); + fclose(fp); + } else { + textDisplay.send("No startup script found.\r\n"); + } +#endif + + //Get the initial state of all input pins + for (int i = 0; i < NUMPORTS; i++) { + + if (ports[i].getDigitalIn() == 1) { + currentDIOstate[0] |= (1 << i); + } else { + currentDIOstate[0] &= ~(1 << i); + } + } + + + //main loop + while(1) { + //check the main event queue to see if anything needs to be done + + mainQueue.check(); + + //check if anything has been written to the serial input + while (pc->readable()) { + + buffer[bufferPos] = pc->readChar(); + bufferPos++; + + + //'Return' key pressed + if ((buffer[bufferPos-1] == 13) || (buffer[bufferPos-1] == 10)) { + + buffer[bufferPos-1] = '\0'; + + parser->addLineToCurrentBlock(buffer); + bufferPos = 0; + eraseBuffer(); + + } else { + + //Backspace was pressed + if (((buffer[bufferPos-1] == 127)||(buffer[bufferPos-1] == 8))) { + if (bufferPos > 1) { + bufferPos = bufferPos-2; //erase the backspace char plus the one before + } else { + bufferPos = bufferPos-1; //beginning of line, so nothing to erase + } + } + } + } + + //Check all the digital ports to see if anything has changed. In the update routine, the port's + //script callbacks are called if the port was triggered + digitalInChanged = false; + digitalOutChanged = false; + changeTime = timeKeeper; + for (int i = 0; i < NUMPORTS; i++) { + + if (ports[i].update()) { + + digitalInChanged = true; + changeTime = min(changeTime,ports[i].lastChangeTime); + + + //The input state of all the ports in condensed into one number (each bit contains the info) + if (ports[i].getLastChangeState() == 1) { + currentDIOstate[0] |= (1 << i); + } else { + currentDIOstate[0] &= ~(1 << i); + } + } + if (ports[i].outStateChanged) { + digitalOutChanged = true; + changeTime = min(changeTime,ports[i].lastOutChangeTime); + //The out state of all the ports is condensed into one number (each bit contains the info) + if (ports[i].outState == 1) { + currentDIOstate[1] |= (1 << i); + } else { + currentDIOstate[1] &= ~(1 << i); + } + ports[i].outStateChanged = false; + } + } + + //If anything changed, we write the new values to the serial port (this can be turned off + //with broadCastStateChanges) + if ( (digitalInChanged||digitalOutChanged) && broadCastStateChanges) { + textDisplay << changeTime << " " << currentDIOstate[0] << " " << currentDIOstate[1] << "\r\n"; + + /* + timeConvert << changeTime; //broadcast the earliest timestamp when a change occured + //stateConvert << currentDIOstate[0] << " " << currentDIOstate[1]; + stateConvert << currentDIOstate[0] << " " << currentDIOstate[1] << " "; + + textDisplay.send(timeConvert.str() + " " + stateConvert.str() + "\r\n"); + timeConvert.clear(); + timeConvert.seekp(0); + stateConvert.clear(); + stateConvert.seekp(0); + */ + digitalInChanged = false; + digitalOutChanged = false; + } + + //We use a buffer to send text via the serial port. For every loop + //in the main loop, we send one character if there is enything to send. + //This way, outputting text to serial does not hold up other time-sensitive + //things in the event queue + if ((textDisplay.unsentData) && (textStreaming)) { + pc->writeChar(textDisplay.getNextChar()); + } + + //Here is how we toggle between standalone and slave mode for the clock updating. + if (changeToSlave) { + hardware->setSlaveClock(); + } else if (changeToStandAlone) { + hardware->setStandAloneClock(); + } + + //anything extra to do, defined by the hardware + hardware->mainLoopToDo(); + + //check for shortcut triggers + numTriggersToProcess = hardware->getPendingFunctionTriggers(shortcutTriggers); + for (int i = 0; i < numTriggersToProcess; i++) { + if (shortcutTriggers[i] < NUMTRIGGERACTIONS && functionSpotTaken[i]) { + functionEventArray[i]->execute(); + } + } + + } + +} + +void mainLoop::eraseBuffer() { + for (int i = 0; i < 256; i++) { + buffer[i] = NULL; + } +} + +//------------------------------------------------- + +//used to find the first available object in the staticly defined pools of memory +template<class T> T* findFirstUnUsed(T a[], const int arrayLength) { + + T* returnPtr = NULL; + for (int i = 0; i < arrayLength; i++) { + if (!a[i].isUsed) { + returnPtr = &a[i]; + break; + } + } + return returnPtr; +} + +//used to count the number of available objects in the memory pool +template<class T> int countUnUsed(T a[], const int arrayLength) { + + int count = 0; + for (int i = 0; i < arrayLength; i++) { + if (!a[i].isUsed) { + count++; + } + } + return count; +} + + +void displayMemoryLeft(void) { + textDisplay << "Available slots left in memory\r\n"; + textDisplay << " Blocks: " << countUnUsed(eventBlock, NUMEVENTS) << "\r\n"; + textDisplay << " Condition containers: " << countUnUsed(conditionBlock, NUMCONDITIONS) << "\r\n"; + textDisplay << " Int compare conditions: " << countUnUsed(intCompareBlock, NUMINTCOMPARE) << "\r\n"; + textDisplay << " Command containers: " << countUnUsed(actionBlock, NUMACTIONS) << "\r\n"; + textDisplay << " Port commands: "<< countUnUsed(portMessageBlock, NUMPORTMESSAGES) << "\r\n"; + textDisplay << " Integer operater commands: " << countUnUsed(intOperationBlock, NUMINTOPERATIONS) << "\r\n"; + textDisplay << " Text display commands: " << countUnUsed(displayActionBlock, NUMDISPLAYACTIONS) << "\r\n"; +} + +bool isNumber(const std::string& s) { + std::string::const_iterator it = s.begin(); + while (it != s.end() && isdigit(*it)) ++it; + return !s.empty() && it == s.end(); +} + +void tokenize(const string& str, + vector<string>& tokens, + const string& delimiters = " ") +{ + // Skip delimiters at beginning. + string::size_type lastPos = str.find_first_not_of(delimiters, 0); + // Find first "non-delimiter". + string::size_type pos = str.find_first_of(delimiters, lastPos); + + while (string::npos != pos || string::npos != lastPos) + { + // Found a token, add it to the vector. + tokens.push_back(str.substr(lastPos, pos - lastPos)); + // Skip delimiters. Note the "not_of" + lastPos = str.find_first_not_of(delimiters, pos); + // Find next "non-delimiter" + pos = str.find_first_of(delimiters, lastPos); + } +} + + +digitalPort::digitalPort(): +outPin(NULL), +inPin(NULL), +outState(0){ + +} + +void digitalPort::init(sDigitalOut *DOP, sDigitalIn *DIP) { + outPin = DOP; + inPin = DIP; + lastInState = getDigitalIn(); + inState = getDigitalIn(); + lastChangeTime = 0; + lastOutChangeTime = 0; + lastChangeInterval = 0; + triggerUpEventPtr = NULL; + triggerDownEventPtr = NULL; + outStateChanged = false; + +} + + +void digitalPort::setTriggerUpEvent(event* eventInput) { + if (triggerUpEventPtr != NULL) { + //delete triggerUpEventPtr; + triggerUpEventPtr->release(); + } + triggerUpEventPtr = eventInput; +} + +void digitalPort::setTriggerDownEvent(event* eventInput) { + if (triggerDownEventPtr != NULL) { + //delete triggerDownEventPtr; + triggerDownEventPtr->release(); + + } + triggerDownEventPtr = eventInput; +} + + +int digitalPort::getDigitalIn() { + return inPin->read(); +} + + +void digitalPort::setDigitalOut(int outVal) { + if (outVal == -1) { + outVal = 1-outState; + } + outPin->write(outVal); + if (outState != outVal) { + outStateChanged = true; + lastOutChangeTime = timeKeeper; + } + outState = outVal; +} + +//called when a digital in gets triggered +/* +void digitalPort::addStateChange(int newState, uint32_t timeStamp) { + + if ((newState == 0) && (!lastDownEvent.triggered)){ + lastDownEvent.timeStamp = timeStamp; + lastDownEvent.triggered = true; + } else if ((newState == 1) && (!lastUpEvent.triggered)) { + lastUpEvent.timeStamp = timeStamp; + lastUpEvent.triggered = true; + } +}*/ + +bool digitalPort::update() { + + bool changed = false; + if ((timeKeeper - lastChangeTime) > 1) { //prevents flutter triggers when button is pressed + + //changed = (lastInState != inState); + + changed = (inPin->lastUpEvent.triggered || inPin->lastDownEvent.triggered); + if (changed) { + inState = getDigitalIn(); + + //We need to ignore flutter when levers/beam breaks are triggered. So + //if the current state if different than the last logged state, we only + //consider the first edge that brough us to the current state + if (lastInState != inState) { + + if (inState == 1) { + + lastChangeInterval = inPin->lastUpEvent.timeStamp - lastChangeTime; + lastChangeTime = inPin->lastUpEvent.timeStamp; + + /* + if (inPin->lastUpEvent.triggered) { + //there were hardware triggers since the last main loop. We use that time + lastChangeInterval = inPin->lastUpEvent.timeStamp - lastChangeTime; + lastChangeTime = inPin->lastUpEvent.timeStamp; + } else { + //otherwise we use the current time + lastChangeInterval = timeKeeper - lastChangeTime; + lastChangeTime = timeKeeper; + } + */ + if (triggerUpEventPtr != NULL) {triggerUpEventPtr->execute();} + } else if (inState == 0) { + + lastChangeInterval = inPin->lastDownEvent.timeStamp - lastChangeTime; + lastChangeTime = inPin->lastDownEvent.timeStamp; + + /* + if (inPin->lastDownEvent.triggered) { + lastChangeInterval = inPin->lastDownEvent.timeStamp - lastChangeTime; + lastChangeTime = inPin->lastDownEvent.timeStamp; + } else { + lastChangeInterval = timeKeeper - lastChangeTime; + lastChangeTime = timeKeeper; + }*/ + + if (triggerDownEventPtr != NULL) {triggerDownEventPtr->execute();} + } + } else if (lastInState == inState) { + + //Both up and down triggers must have happened, so we consider both + if (inState == 1) { + + lastChangeInterval = inPin->lastUpEvent.timeStamp - inPin->lastDownEvent.timeStamp; + lastChangeTime = inPin->lastUpEvent.timeStamp; + + if (triggerDownEventPtr != NULL) {triggerDownEventPtr->execute();} + if (triggerUpEventPtr != NULL) {triggerUpEventPtr->execute();} + } else if (inState == 0) { + + lastChangeInterval = inPin->lastDownEvent.timeStamp - inPin->lastUpEvent.timeStamp; + lastChangeTime = inPin->lastDownEvent.timeStamp; + + if (triggerUpEventPtr != NULL) {triggerUpEventPtr->execute();} + if (triggerDownEventPtr != NULL) {triggerDownEventPtr->execute();} + } + } + + } + + lastInState = inState; + inPin->lastUpEvent.triggered = false; + inPin->lastDownEvent.triggered = false; + + } + + return changed; +} + +int digitalPort::getLastChangeState() { + return lastInState; +} +uint32_t digitalPort::getTimeSinceLastChange() { + return lastChangeInterval; + +} + +intVariable::intVariable(): +value(0) { + isUsed = false; +} + +intVariable::intVariable(std::string& tagInput, int initialValue): +value(initialValue) +{ + strncpy(tag,tagInput.data(),MAXVARNAMESIZE); + isUsed = true; +} + +void intVariable::set(std::string& tagInput, int initialValue) { + value = initialValue; + //tag = string(tagInput); + strncpy(tag,tagInput.data(),MAXVARNAMESIZE); + isUsed = true; +} + +displayAction::displayAction(): +dText(string("--------------------------------------------------")){ + dVariable = NULL; + isUsed = false; +} + +void displayAction::release() { + dText = "--------------------------------------------------"; + dVariable = NULL; + isUsed = false; +} + + +void displayAction::set(int* variable, string varNameInput) { + dVariable = variable; + dText = varNameInput; + isUsed = true; + +} + +void displayAction::set(string text) { + dText = text; + dVariable = NULL; + isUsed = true; +} + +void displayAction::execute() { + + if (dVariable != NULL) { + textDisplay << timeKeeper << " " << dText << " = " << *dVariable << "\r\n"; + } else { + textDisplay << timeKeeper << " " << dText << "\r\n"; + } +} + +triggerFunctionAction::triggerFunctionAction(): +functionNum(0) { + isUsed = false; +} + +triggerFunctionAction::triggerFunctionAction(int funcNum): +functionNum(funcNum) { + + isUsed = true; + +} + +void triggerFunctionAction::set(int funcNum) { + functionNum = funcNum; + isUsed = true; +} + +void triggerFunctionAction::execute() { + + if (functionSpotTaken[functionNum]) { + functionEventArray[functionNum]->execute(); + } + +} + +void triggerFunctionAction::release() { + isUsed = false; +} + + + +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; + isClockAssign = false; + inputsFlipped = false; + +} + +/* + intOperation::intOperation(int randParam, const char* cmpString, int cmpValInput): + randHigh(randParam) { + cmpVal = new int(cmpValInput); + intVal = NULL; + opPtr = NULL; + cmpValGlobal = false; + isUsed = true; + if (strcmp(cmpString, "+") == 0) { + executePtr = &intOperation::add; + }else if (strcmp(cmpString, "-") == 0) { + executePtr = &intOperation::subtract; + }else if (strcmp(cmpString, "+=") == 0) { + executePtr = &intOperation::addAndStore; + }else if (strcmp(cmpString, "-=") == 0) { + executePtr = &intOperation::subtractAndStore; + }else if (strcmp(cmpString, "=") == 0) { + executePtr = &intOperation::equals; + } + + } + + intOperation::intOperation(int randParam, const char* cmpString, int* cmpIntVarInput): + randHigh(randParam), + cmpVal(cmpIntVarInput) { + intVal = NULL; + opPtr = NULL; + cmpValGlobal = true; + isUsed = true; + if (strcmp(cmpString, "+") == 0) { + executePtr = &intOperation::add; + }else if (strcmp(cmpString, "-") == 0) { + executePtr = &intOperation::subtract; + }else if (strcmp(cmpString, "+=") == 0) { + executePtr = &intOperation::addAndStore; + }else if (strcmp(cmpString, "-=") == 0) { + executePtr = &intOperation::subtractAndStore; + }else if (strcmp(cmpString, "=") == 0) { + executePtr = &intOperation::equals; + } + } + + intOperation::intOperation(int* intVarInput, const char* cmpString, int cmpValInput): + intVal(intVarInput) { + cmpVal = new int(cmpValInput); + randHigh = -1; + opPtr = NULL; + cmpValGlobal = false; + isUsed = true; + if (strcmp(cmpString, "+") == 0) { + executePtr = &intOperation::add; + }else if (strcmp(cmpString, "-") == 0) { + executePtr = &intOperation::subtract; + }else if (strcmp(cmpString, "+=") == 0) { + executePtr = &intOperation::addAndStore; + }else if (strcmp(cmpString, "-=") == 0) { + executePtr = &intOperation::subtractAndStore; + }else if (strcmp(cmpString, "=") == 0) { + executePtr = &intOperation::equals; + } + } + + intOperation::intOperation(int* intVarInput, const char* cmpString, int* cmpIntVarInput): + cmpVal(cmpIntVarInput), + intVal(intVarInput) { + randHigh = -1; + opPtr = NULL; + cmpValGlobal = true; + isUsed = true; + if (strcmp(cmpString, "+") == 0) { + executePtr = &intOperation::add; + }else if (strcmp(cmpString, "-") == 0) { + executePtr = &intOperation::subtract; + }else if (strcmp(cmpString, "+=") == 0) { + executePtr = &intOperation::addAndStore; + }else if (strcmp(cmpString, "-=") == 0) { + executePtr = &intOperation::subtractAndStore; + }else if (strcmp(cmpString, "=") == 0) { + executePtr = &intOperation::equals; + } + } + + intOperation::intOperation(int* intVarInput, intOperation* operationInput): + intVal(intVarInput) { + cmpVal = NULL; + randHigh = -1; + opPtr = operationInput; + executePtr = &intOperation::equals; + isUsed = true; + } + */ + +void intOperation::setRandOp(int randParam, const char* cmpString, int cmpValInput, bool flipped) { + randHigh = randParam; + cmpVal = new int(cmpValInput); + intVal = NULL; + opPtr = NULL; + cmpValGlobal = false; + isUsed = true; + inputsFlipped = flipped; + if (strcmp(cmpString, "+") == 0) { + executePtr = &intOperation::add; + }else if (strcmp(cmpString, "-") == 0) { + executePtr = &intOperation::subtract; + }else if (strcmp(cmpString, "=") == 0) { + executePtr = &intOperation::equals; + } + +} + +void intOperation::setRandOp(int randParam, const char* cmpString, int* cmpIntVarInput, bool flipped) { + randHigh = randParam; + cmpVal = cmpIntVarInput; + intVal = NULL; + opPtr = NULL; + cmpValGlobal = true; + isUsed = true; + inputsFlipped = flipped; + if (strcmp(cmpString, "+") == 0) { + executePtr = &intOperation::add; + }else if (strcmp(cmpString, "-") == 0) { + executePtr = &intOperation::subtract; + }else if (strcmp(cmpString, "=") == 0) { + executePtr = &intOperation::equals; + } +} + +void intOperation::set(int* intVarInput, const char* cmpString, int cmpValInput) { + + intVal = intVarInput; + cmpVal = new int(cmpValInput); + randHigh = -1; + opPtr = NULL; + cmpValGlobal = false; + isUsed = true; + if (strcmp(cmpString, "+") == 0) { + executePtr = &intOperation::add; + }else if (strcmp(cmpString, "-") == 0) { + executePtr = &intOperation::subtract; + }else if (strcmp(cmpString, "+=") == 0) { + executePtr = &intOperation::addAndStore; + }else if (strcmp(cmpString, "-=") == 0) { + executePtr = &intOperation::subtractAndStore; + }else if (strcmp(cmpString, "=") == 0) { + executePtr = &intOperation::equals; + } +} + +void intOperation::set(int* intVarInput, const char* cmpString, int* cmpIntVarInput) { + cmpVal = cmpIntVarInput; + intVal =intVarInput; + randHigh = -1; + opPtr = NULL; + cmpValGlobal = true; + isUsed = true; + if (strcmp(cmpString, "+") == 0) { + executePtr = &intOperation::add; + }else if (strcmp(cmpString, "-") == 0) { + executePtr = &intOperation::subtract; + }else if (strcmp(cmpString, "+=") == 0) { + executePtr = &intOperation::addAndStore; + }else if (strcmp(cmpString, "-=") == 0) { + executePtr = &intOperation::subtractAndStore; + }else if (strcmp(cmpString, "=") == 0) { + executePtr = &intOperation::equals; + } +} + +void intOperation::set(int* intVarInput, intOperation* operationInput) { + + intVal = intVarInput; + cmpVal = NULL; + randHigh = -1; + opPtr = operationInput; + executePtr = &intOperation::equals; + isUsed = true; + +} + +void intOperation::setClockOp(int* intVarInput) { + //used to assign current clock to variable + intVal = intVarInput; + cmpVal = NULL; + randHigh = -1; + opPtr = NULL; + cmpValGlobal = false; + isUsed = true; + isClockAssign = true; + executePtr = &intOperation::equals; + +} + +void intOperation::setClockOp(const char* cmpString, int cmpValInput, bool flip) { + //used to add an integer to the current clock value + + intVal = NULL; + cmpVal = new int(cmpValInput); + randHigh = -1; + opPtr = NULL; + cmpValGlobal = false; + isUsed = true; + isClockAssign = true; + inputsFlipped = flip; + if (strcmp(cmpString, "+") == 0) { + executePtr = &intOperation::add; + }else if (strcmp(cmpString, "-") == 0) { + executePtr = &intOperation::subtract; + } +} + +void intOperation::setClockOp(const char* cmpString, int* cmpIntVarInput, bool flip) { + //used to add a variable to the current clock value + + cmpVal = cmpIntVarInput; + intVal = NULL; + randHigh = -1; + opPtr = NULL; + isClockAssign = true; + cmpValGlobal = true; + isUsed = true; + inputsFlipped = flip; + if (strcmp(cmpString, "+") == 0) { + executePtr = &intOperation::add; + }else if (strcmp(cmpString, "-") == 0) { + executePtr = &intOperation::subtract; + } +} + + +intOperation::~intOperation() { + if (!cmpValGlobal) delete cmpVal; + delete opPtr; +} + +void intOperation::release() { + if (!cmpValGlobal) delete cmpVal; + if (opPtr != NULL) { + opPtr->release(); + } + randHigh = -1; + cmpVal = NULL; + intVal = NULL; + opPtr = NULL; + executePtr = NULL; + isClockAssign = false; + cmpValGlobal = false; + isUsed = false; +} + + +int intOperation::execute() { + + return (this->*executePtr)(); + + +} + +int intOperation::add() { + + if ((intVal != NULL) && (!isClockAssign)) { + return (*intVal + *cmpVal); + } else if ((intVal == NULL) && (isClockAssign)) { + return (timeKeeper + *cmpVal); + } else { + //srand(time(NULL)); + srand(timeKeeper); + return (rand() % (randHigh+1)) + *cmpVal; + //return (port->getState() + *cmpVal); + } +} + +int intOperation::subtract() { + if ((intVal != NULL) && (!isClockAssign)) { + return (*intVal - *cmpVal); + } else if ((intVal == NULL) && (isClockAssign)) { + if (inputsFlipped) { + return (*cmpVal-timeKeeper); + } else { + return (timeKeeper - *cmpVal); + } + } else { + srand(timeKeeper); + if (inputsFlipped) { + return (*cmpVal-(rand() % (randHigh+1))); + } else { + return (rand() % (randHigh+1)) - *cmpVal; + } + //return (port->getState() - *cmpVal); + } +} + +int intOperation::addAndStore() { + if (intVal != NULL) { + *intVal = *intVal + *cmpVal; + return *intVal; + } + else { + + //Doesn't happen + return 0; + //port->setState(port->getState() + *cmpVal); + //return port->getState(); + } + +} + +int intOperation::subtractAndStore() { + if (intVal != NULL) { + *intVal = *intVal - *cmpVal; + return *intVal; + } else { + //doesn't happen + return 0; + //port->setState(port->getState() - *cmpVal); + //return port->getState(); + } +} + +int intOperation::equals() { + if ((intVal != NULL) && (opPtr == NULL) && (!isClockAssign)) { + *intVal = *cmpVal; + return *intVal; + } else if ((intVal != NULL) && (opPtr != NULL)) { + + *intVal = opPtr->execute(); + return *intVal; + } else if ((intVal != NULL) && (opPtr == NULL) && (isClockAssign)) { + *intVal = timeKeeper; //assign the current time to the variable + return *intVal; + } else if ((cmpVal != NULL)&& (!isClockAssign)){ + + srand(timeKeeper+randomSeedCounter); + randomSeedCounter++; //for seeding the next rand call, just in case it happens before the clock advances + *cmpVal = (rand() % (randHigh+1)); //this is how we assign a random number to variable + return *cmpVal; + + } + return -1; +} + +condition::condition() { + intCmp = NULL; + conditionPtrs[0] = NULL; + conditionPtrs[1] = NULL; + isUsed = false; + conditionType = ARITHMATIC_CONDITION; +} + +condition::condition(intCompare* compareInput) { + + intCmp = compareInput; + conditionPtrs[0] = NULL; + conditionPtrs[1] = NULL; + + isUsed = true; + conditionType = ARITHMATIC_CONDITION; + +} + +condition::condition(condition* condition1, char condType, condition* condition2) { + intCmp = NULL; + conditionPtrs[0] = condition1; + conditionPtrs[1] = condition2; + isUsed = true; + conditionType = condType; +} + +condition::~condition() { + if (intCmp != NULL) { + delete intCmp; + } +} + +void condition::release() { + if (intCmp != NULL) { + intCmp->release(); + intCmp=NULL; + } + if (conditionPtrs[0] != NULL) { + conditionPtrs[0]->release(); + conditionPtrs[1]->release(); + conditionPtrs[0]=NULL; + conditionPtrs[1]=NULL; + } + isUsed = false; +} + +void condition::set(intCompare* compareInput) { + release(); + intCmp = compareInput; + conditionPtrs[0] = NULL; + conditionPtrs[1] = NULL; + isUsed = true; + conditionType = ARITHMATIC_CONDITION; +} + +void condition::set(condition* condition1, char condType, condition* condition2) { + release(); + intCmp = NULL; + conditionPtrs[0] = condition1; + conditionPtrs[1] = condition2; + isUsed = true; + conditionType = condType; +} + +bool condition::isTrue() { + + + bool result = true; + if (conditionType == ARITHMATIC_CONDITION) { + + result = (intCmp->isTrue)(); + } else if (conditionType == AND_CONDITION) { + + result = conditionPtrs[0]->isTrue() && conditionPtrs[1]->isTrue(); + } else if (conditionType == OR_CONDITION) { + + result = conditionPtrs[0]->isTrue() || conditionPtrs[1]->isTrue(); + } + return result; + +} + +portMessage::portMessage(): +whichToSet(0), +value(0), +port(NULL) { + isUsed = false; +} + +void portMessage::release() { + + whichToSet = 0; + value = 0; + port = NULL; + isUsed = false; +} + +/* + 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, digitalPort* portVectorIn) { + whichToSet = whichToSetIn; + value = valueIn; + port = portIn; + portVector = portVectorIn; + isUsed = true; +} + +void portMessage::execute() { + + if (port != NULL) { + if ((*port > 0) && (*port <= NUMPORTS)) { + portVector[*port-1].setDigitalOut(value); + } else { + textDisplay << "Error: port index assigned by variable does not exist.\r\n"; + } + } else { + portVector[whichToSet-1].setDigitalOut(value); + } + +} + +action::action(): +actionType(0) { + op = NULL; + message = NULL; + eventToCreate = NULL; + displayActionPtr = NULL; + //eventDelay = 0; + sound = NULL; + triggerFunc = NULL; + sysCommand = -1; + isUsed = false; + +} + +action::~action() { + if (eventToCreate != NULL) delete eventToCreate; + if (op != NULL) delete op; + if (message != NULL) delete message; + delete displayActionPtr; + delete sound; +} + +void action::release() { + if (eventToCreate != NULL) eventToCreate->release(); + if (op != NULL) op->release(); + if (message != NULL) message->release(); + if (displayActionPtr != NULL) displayActionPtr->release(); + if (triggerFunc != NULL) triggerFunc->release(); + delete sound; //still need to make a static soundControl array + + actionType = 0; + op = NULL; + message = NULL; + eventToCreate = NULL; + displayActionPtr = NULL; + //eventDelay = 0; + sound = NULL; + triggerFunc = NULL; + sysCommand = -1; + isUsed = false; +} + +action::action(intOperation* opInput): +actionType(1) { + op = opInput; + message = NULL; + eventToCreate = NULL; + displayActionPtr= NULL; + //eventDelay = 0; + sound = NULL; + triggerFunc = NULL; + sysCommand = -1; + isUsed = true; +} + +action::action(portMessage* messageInput): +actionType(2) { + op = NULL; + eventToCreate = NULL; + message = messageInput; + displayActionPtr= NULL; + //eventDelay = 0; + sound = NULL; + triggerFunc = NULL; + sysCommand = -1; + isUsed = true; + +} + +action::action(event* eventInput): +actionType(3) { + op = NULL; + message = NULL; + eventToCreate = eventInput; + displayActionPtr= NULL; + sound = NULL; + triggerFunc = NULL; + + //eventDelay = eventInput->timeLag; + + + sysCommand = -1; + isUsed = true; +} + +/* + action::action(event* eventInput, uint32_t delay): + actionType(3) { + op = NULL; + message = NULL; + eventToCreate = eventInput; + displayActionPtr= NULL; + sound = NULL; + eventDelay = delay; + sysCommand = -1; + isUsed = true; + + }*/ + + + +action::action(displayAction* displayInput): +actionType(4) { + op = NULL; + message = NULL; + eventToCreate = NULL; + sound = NULL; + triggerFunc = NULL; + displayActionPtr = displayInput; + //eventDelay = 0; + sysCommand = -1; + isUsed = true; +} + +action::action(sSound* soundInput): +actionType(5) { + op = NULL; + message = NULL; + eventToCreate = NULL; + sound = soundInput; + triggerFunc = NULL; + displayActionPtr = NULL; + //eventDelay = 0; + sysCommand = -1; + isUsed = true; +} + +action::action(triggerFunctionAction* triggerFuncInput): +actionType(7) { + op = NULL; + message = NULL; + eventToCreate = NULL; + sound = NULL; + triggerFunc = triggerFuncInput; + displayActionPtr = NULL; + //eventDelay = 0; + sysCommand = -1; + isUsed = true; +} + +action::action(int8_t sysCommandInput): +actionType(6) { + op = NULL; + message = NULL; + eventToCreate = NULL; + sound = NULL; + displayActionPtr = NULL; + //eventDelay = 0; + sysCommand = sysCommandInput; + isUsed = true; +} + +void action::set(intOperation* opInput) { + actionType = 1; + op = opInput; + //eventDelay = 0; + isUsed = true; + +} + +void action::set(portMessage* messageInput) { + actionType = 2; + message = messageInput; + //eventDelay = 0; + isUsed = true; + +} + +void action::set(event* eventInput) { + actionType = 3; + eventToCreate = eventInput; + //eventDelay = eventInput->timeLag; + + isUsed = true; + +} + +/* + void action::set(event* eventInput, uint32_t delay) { + actionType = 3; + eventToCreate = eventInput; + eventDelay = delay; + isUsed = true; + + }*/ + + + +void action::set(displayAction* displayInput) { + actionType = 4; + displayActionPtr = displayInput; + isUsed = true; +} + +void action::set(sSound* soundInput) { + actionType = 5; + sound = soundInput; + isUsed = true; +} + +void action::set(triggerFunctionAction* triggerFuncInput) { + + actionType = 7; + triggerFunc = triggerFuncInput; + isUsed = true; +} + +void action::set(int8_t sysCommandInput) { + actionType = 6; + sysCommand = sysCommandInput; + isUsed = true; +} + +void action::execute() { + + if (actionType == 1) { + op->execute(); + } else if (actionType == 2) { + message->execute(); + } else if (actionType == 3) { + this->execute(timeKeeper); //route to the other overloaded method + } else if (actionType == 4) { + displayActionPtr->execute(); //send text via serial + } else if (actionType == 5) { + sound->execute(); //operate sound device + } else if (actionType == 6) { + switch(sysCommand) { + case 0: + mainQueue.eraseQueue(); + break; + case 1: + textStreaming = true; + break; + case 2: + textStreaming = false; + break; + case 3: + broadCastStateChanges = true; + break; + case 4: + broadCastStateChanges = false; + break; + } + + } else if (actionType == 7) { + triggerFunc->execute(); //execute function + } +} + +void action::execute(uint32_t blockExecTime) { + + if (actionType == 1) { + op->execute(); + } else if (actionType == 2) { + message->execute(); + } else if (actionType == 3) { //an event block + //Because time will pass from the begining of the block, any defined delays should be updated + + //int newDelay = eventDelay-(*globalTimeKeeperPtr-blockExecTime); + int newDelay; + if (eventToCreate->timeLagIsConstant) { + newDelay = eventToCreate->timeLag - (timeKeeper-blockExecTime); + } else { + newDelay = *eventToCreate->timeLagVar - (timeKeeper-blockExecTime); + } + if (newDelay < 0) {newDelay = 0;} + eventToCreate->addToQueue(newDelay); //add the event to the queue to be executed later + + if (eventToCreate->hasWhileLoop) { //this is a while loop + if (eventToCreate->isConditionTrue()) { + //newDelay = (blockExecTime + eventToCreate->whileLoopPeriod) - *globalTimeKeeperPtr; + int tmpPeriod; + if (eventToCreate->whileLoopPeriodIsConstant) { //constant while loop period + newDelay = (blockExecTime + eventToCreate->whileLoopPeriod); + tmpPeriod = eventToCreate->whileLoopPeriod; + } else { + tmpPeriod = *eventToCreate->whileLoopPeriodVar; + if (tmpPeriod < 0) { + tmpPeriod = 0; + } + newDelay = (blockExecTime + tmpPeriod); + } + while ( (newDelay-timeKeeper < 0) && (eventToCreate->isConditionTrue()) ) { + eventToCreate->execute(); + newDelay = newDelay + tmpPeriod; + + } + newDelay = newDelay-timeKeeper; + if (newDelay > 0) { + eventToCreate->addToQueue(newDelay); + } else { + eventToCreate->addToQueue(1); + } + } else if (eventToCreate->nextElseEventPtr != NULL) { + eventToCreate->nextElseEventPtr->addToQueue(); + + } + } + } else if (actionType == 4) { + displayActionPtr->execute(); //send text via serial + } else if (actionType == 5) { + sound->execute(); //operate sound device + } else if (actionType == 6) { + switch(sysCommand) { + case 0: + mainQueue.eraseQueue(); + break; + case 1: + textStreaming = true; + break; + case 2: + textStreaming = false; + break; + case 3: + broadCastStateChanges = true; + break; + case 4: + broadCastStateChanges = false; + break; + } + } else if (actionType == 7) { + + textDisplay.flush(); + triggerFunc->execute(); //operate sound device + } +} + +eventQueue::eventQueue() { + + queueItem blankEvent; + blankEvent.timeToExecute = 0; + blankEvent.eventPtr = NULL; + queueSize = 100; + events.resize(queueSize,blankEvent); + + +} + +void eventQueue::addEventToQueue(event* eventInput, uint32_t delay) { + //*updateSlavePtr = false; + uint32_t eventTime = timeKeeper + delay; + //*updateSlavePtr = true; + //std::vector<queueItem>::size_type sz = events.size(); + //Look for the first empty slot in the queue and place the event there. + //This means that the events in the queue are out of order, but + //it prevents us from having to push_pack and pop off all the time. + for (unsigned i = 0; i < queueSize; i++) { + if (events[i].eventPtr == NULL) { + events[i].eventPtr = eventInput; + events[i].timeToExecute = eventTime; + break; + } + } +} + +void eventQueue::eraseQueue() { + //Erase all events in the queue + std::vector<queueItem>::size_type sz = events.size(); + for (unsigned i = 0; i < sz; i++) { + events[i].eventPtr = NULL; + + } +} + + +//check if any of the events in the queue are up for execution +void eventQueue::check(void) { + + //*updateSlavePtr = false; + uint32_t currentTime = timeKeeper; + //*updateSlavePtr = true; + //std::vector<queueItem>::size_type sz = events.size(); + for (unsigned i = 0; i < queueSize; i++) { + if (events[i].eventPtr != NULL) { + if(events[i].timeToExecute <= currentTime) { + if (!events[i].eventPtr->hasWhileLoop) { + //this is not a while loop, so no need to check if the condition is still true + events[i].eventPtr->execute(); + } else if (events[i].eventPtr->isConditionTrue()){ + //The event is part of a while loop, so recheck the condition before executing + events[i].eventPtr->execute(); + //if (events[i].eventPtr->isConditionTrue()) { //is the condition still true? + int nextTime; + int tmpPeriod; + if (events[i].eventPtr->whileLoopPeriodIsConstant) { + nextTime = (events[i].timeToExecute + events[i].eventPtr->whileLoopPeriod); + tmpPeriod = events[i].eventPtr->whileLoopPeriod; + } else { + tmpPeriod = *events[i].eventPtr->whileLoopPeriodVar; + if (tmpPeriod < 0) { + tmpPeriod = 0; + } + nextTime = (events[i].timeToExecute + tmpPeriod); + + } + //Just in case we are not keeping up, execute the event until we have cought up + while ((nextTime-timeKeeper <= 0) && (events[i].eventPtr->isConditionTrue())) { + events[i].eventPtr->execute(); + nextTime = nextTime+tmpPeriod; + + } + nextTime = nextTime - timeKeeper; + if (nextTime > 0) { + //we add the event to the queue (but the condition is rechecked first) + //if the condition is false, the 'then' statement is added to the queue instead + events[i].eventPtr->addToQueue(nextTime); + } else { + //if we are having trouble keeping up, just add the next event in 1 ms + events[i].eventPtr->addToQueue(1); + } + /* + } else { + if (events[i].eventPtr->nextElseEventPtr != NULL) { + events[i].eventPtr->nextElseEventPtr->addToQueue(); + } + }*/ + + } else { + if (events[i].eventPtr->nextElseEventPtr != NULL) { + events[i].eventPtr->nextElseEventPtr->addToQueue(); + } + } + events[i].eventPtr = NULL; + } + } + } +} + + +event::event(): + timeLag(0), + queuePtr(&mainQueue) { + + nextElseEventPtr = NULL; + conditionToCheck = NULL; + blockType = 0; + whileLoopPeriod = 0; + numConditions = 0; + numActions = 0; + isUsed = false; + timeLagVar = NULL; + timeLagIsConstant = true; + whileLoopPeriodIsConstant = true; + hasWhileLoop = false; + whileLoopPeriodVar = NULL; + +} + +event::event(eventQueue* queueInput): + timeLag(0), + queuePtr(&mainQueue) { + + nextElseEventPtr = NULL; + conditionToCheck = NULL; + blockType = 0; + whileLoopPeriod = 0; + numConditions = 0; + numActions = 0; + isUsed = true; + timeLagVar = NULL; + timeLagIsConstant = true; + whileLoopPeriodIsConstant = true; + hasWhileLoop = false; + whileLoopPeriodVar = NULL; + +} + +event::~event() { + /* + while (!conditionArray.empty()) + { + delete conditionArray.back(); + conditionArray.pop_back(); + } + + while (!actionArray.empty()) + { + delete actionArray.back(); + actionArray.pop_back(); + } + + delete nextElseEventPtr; + */ + +} + +void event::release() { + + for (int i = 0; i < numActions; i++) { + actionArray[i]->release(); + } + + if (conditionToCheck != NULL) { + conditionToCheck->release(); + conditionToCheck = NULL; + } + + if (nextElseEventPtr != NULL) { + nextElseEventPtr->release(); + } + timeLag = 0; + nextElseEventPtr = NULL; + blockType = 0; + whileLoopPeriod = 0; + numConditions = 0; + numActions = 0; + isUsed = false; + timeLagVar = NULL; + timeLagIsConstant = true; + whileLoopPeriodIsConstant = true; + hasWhileLoop = false; + whileLoopPeriodVar = NULL; +} + +void event::setTimeLag(uint32_t timeLagInput) { + timeLag = timeLagInput; + timeLagIsConstant = true; +} + +void event::setTimeLag(int* timeLagInput) { + timeLagVar = timeLagInput; + timeLagIsConstant = false; //time lag is not defined by a constant +} + +void event::setWhileLoopPeriod(uint32_t period) { + whileLoopPeriodIsConstant = true; + hasWhileLoop = true; + whileLoopPeriod = period; + +} + +void event::setWhileLoopPeriod(int* period) { + whileLoopPeriodIsConstant = false; + hasWhileLoop = true; + whileLoopPeriodVar = period; + +} + +void event::addCondition(condition* conditionInput) { + if (conditionToCheck != NULL) { + conditionToCheck->release(); + } + conditionToCheck = conditionInput; + + //conditionArray.push_back(conditionInput); +} + +void event::addAction(action* actionInput) { + actionArray[numActions] = actionInput; + numActions++; + //actionArray.push_back(actionInput); +} + +bool event::isConditionTrue(void) { + //if statement (can be left empty, which is interpreted as 'true') + bool result = true; + + if ((conditionToCheck!=NULL)&&(!conditionToCheck->isTrue())) { + result = false; + } + + return result; +} + +void event::execute(void) { + //called from the event queue. The condition is bypassed because it was already checked + + uint32_t timeAtStartExec = timeKeeper; + for (unsigned i = 0; i < numActions; i++) { + actionArray[i]->execute(timeAtStartExec); + + } + +} + +//Attach an 'else' statement to the event +void event::setNextElseEvent(event* eventInput) { + nextElseEventPtr = eventInput; +} + + +//When we we call addToQueue() the condition is checked. If true, the event is added +//to the queue, otherwise we check if there was an 'else' statement attached to the event. +void event::addToQueue(void) { + if (isConditionTrue()) { + if ((timeLagIsConstant)&&(timeLag == 0)) { + execute(); + + } else if (timeLagIsConstant) { + queuePtr->addEventToQueue(this, this->timeLag); + } else if ((!timeLagIsConstant)&&(*timeLagVar <= 0)) { + execute(); + } else { + queuePtr->addEventToQueue(this, *timeLagVar); + } + } else if ((this->nextElseEventPtr != NULL)&&(whileLoopPeriod == 0)) { + this->nextElseEventPtr->addToQueue(); + } +} + +//We can override the timeLag field and use another delay +void event::addToQueue(uint32_t delay) { + if (this->isConditionTrue()) { + //if ((delay == 0) && (whileLoopPeriod == 0)) { + if ((delay == 0)) { + this->execute(); + } else { + queuePtr->addEventToQueue(this, delay); + } + } else if ((this->nextElseEventPtr != NULL)) { //&&(!hasWhileLoop)) { + this->nextElseEventPtr->addToQueue(); + } +} + + + +functionItem::functionItem(action* actionInput, string tagInput): +tag(tagInput), +actionPtr(actionInput) { +} + +functionItem::~functionItem() { + delete actionPtr; +} + +blockBuffer::blockBuffer() { + bufferWritePos = 0; + bufferReadPos = 0; + _linesAvailable = 0; + +} + +bool blockBuffer::addLine(char *input, int numChars) { + + if (bufferWritePos+numChars >= INPUTCHARBUFFERSIZE) { + return false; + } + for(int i=0;i<numChars;i++) { + charBuffer[bufferWritePos] = input[i]; + bufferWritePos++; + } + _linesAvailable++; + return true; +} + +string blockBuffer::getNextLine() { + + string outputLine; + int endOfLinePos = bufferReadPos; + bool endOfLineFound = false; + + if (_linesAvailable > 0) { + //Find the end of the next line + + while (endOfLinePos < INPUTCHARBUFFERSIZE) { + + if (charBuffer[endOfLinePos] == '\0') { + endOfLineFound = true; + break; + } + endOfLinePos++; + } + + //If the end was found, copy to output string + if (endOfLineFound) { + + outputLine.append(charBuffer+bufferReadPos,endOfLinePos-bufferReadPos); + bufferReadPos = endOfLinePos+1; + _linesAvailable--; + } else { + textDisplay << "Error: No end of line found!"; + textDisplay.flush(); + } + } + if (_linesAvailable == 0) { + //we have read out all of the lines, so reset the buffer for the next block. + resetBuffer(); + } + return outputLine; + +} + +int16_t blockBuffer::linesAvailable() { + return _linesAvailable; +} + +void blockBuffer::resetBuffer() { + _linesAvailable = 0; + bufferReadPos = 0; + bufferWritePos = 0; +} + +bool blockBuffer::empty() { + return (_linesAvailable == 0); +} + + +scriptStream::scriptStream(digitalPort* portVectorInput, int numPortsInput, eventQueue* queueInput, sSystem *system): + portVector(portVectorInput), + numPorts(numPortsInput), + queuePtr(queueInput), + system(system) { + + currentPort = -1; + currentTriggerPort = -1; + currentTriggerDir = 1; + currentFunction = -1; + + randomSeedCounter = 0; //used for seeding random numbers + + lineError = false; + blockDepth = 0; + ifBlockInit = false; + whileBlockInit = false; + expectingDoStatement = false; + elseFlag = false; + thenFlag = false; + currentDelay = 0; + + for (int i = 0; i < NUMFUNCTIONS; i++) { + functionSpotTaken[i] = false; + functionEventArray[i] = NULL; + } + + +} + + +void scriptStream::addLineToCurrentBlock(char* lineInput) { + + bool compile = false; + bool keep = false; + int numCharInLine = 0; + //A line ending with ';' then carriage return initiates the compile sequence + //Otherwise, add the line to the buffer and compile later + for (int i = 0; i < 256; i++) { + numCharInLine++; + if (lineInput[i] == ';') { + compile = true; + } else if (lineInput[i] == ' ') { + continue; + } else if (lineInput[i] == '\0') { + break; + } else { + keep = true; + compile = false; + } + + } + + //if (keep) currentBlock.insert(currentBlock.begin(),string(lineInput)); + if (keep) { + if (!currentBlock.addLine(lineInput,numCharInLine)) { + textDisplay << "Error: script input buffer full. The block is too long.\r\n"; + currentBlock.resetBuffer(); + compile = false; + } + } + if (compile) { + parseBlock(); + } + +} + + +//SCRIPT PARSING - all script commands are defined here. +//------------------------------------------------------- +void scriptStream::parseBlock() { + + + lineError = false; + blockDepth = 0; + ifBlockInit = false; + whileBlockInit = false; + expectingDoStatement = false; + elseFlag = false; + thenFlag = false; + currentDelay = 0; + + + std::size_t stringInd = 0; + + bool wholeLineEvaluated = false; + + while (!currentBlock.empty()) { + + wholeLineEvaluated = false; + //tmpLine = currentBlock.back(); + tmpLine = currentBlock.getNextLine(); + + lineError = false; + //remove tabs + std::size_t found = tmpLine.find_first_of(9); //tab + while (found!=std::string::npos) { + tmpLine[found]= ' '; + found=tmpLine.find_first_of(9,found+1); + } + + found = tmpLine.find_first_of(37); //% for commenting + if (found!=std::string::npos) { + for (int p=found; p<tmpLine.size() ;p++) { + tmpLine[p]= ' '; + } + } + + //break up the line into tokens separated by spaces + tokenize(tmpLine,tokens," ;"); + + std::vector<string>::size_type sz = tokens.size(); + + for (unsigned i = 0; i < sz; i++) { + + + + //end statement signals the end of a block----------------------------------------- + if (tokens[i].compare("end") == 0) { //ends the current block + + if (ifBlockInit || whileBlockInit || expectingDoStatement) { + textDisplay << "Error: expected a 'do' statement\r\n"; + lineError = true; + } + + ifBlockInit = false; + whileBlockInit = false; + expectingDoStatement = false; + elseFlag = false; + + if (blockDepth > 0) { + textDisplay.debug("End statement\r\n"); + if (blockDepth == 1) { + + + currentTriggerPort = -1; + currentFunction = -1; + + + + blockDepth = 0; + } else if (blockDepth > 1) { + blockDepth = blockDepth - 1; + } + + while ((tmpEventPtrArray.back()->blockType == 3) || (tmpEventPtrArray.back()->blockType == 4)){ + tmpEventPtrArray.pop_back(); //recursively remove the pointers to all else blocks + } + tmpEventPtrArray.pop_back(); //remove the pointer to the finished block + + } else { + textDisplay << "Error: End statement without block\r\n"; + lineError = true; + } + + + + //sound statement used to play wave files------------------------------------------------ + //example: sound('soundfile') + // sound(stop) + } else if (tokens[i].find("sound(") != std::string::npos) { + if (ifBlockInit || whileBlockInit || elseFlag || expectingDoStatement) { + textDisplay << "Error: expected a 'do' statement\r\n"; + lineError = true; + } + wholeLineEvaluated = true; + int pos1 = tmpLine.find("sound(")+6; + int pos2 = tmpLine.find_first_of(")",pos1); + string dispVar = tmpLine.substr(pos1,pos2-pos1); + + int* tmpVar = findIntVariable(dispVar); + bool isText = false; + bool stopSignal = false; + bool resetSignal = false; + if (tmpVar == NULL) { + if ((tmpLine.compare(pos1,1,"'")==0) && (tmpLine.compare(pos2-1,1,"'")==0)) { + isText = true; + } else if (dispVar.compare("stop") == 0) { + stopSignal = true; + } else if (dispVar.compare("reset") == 0) { + resetSignal = true; + } else { + textDisplay << "Error: variable input to sound() does not exist\r\n"; + lineError = true; + } + } + action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS); + if (tmpAction == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + lineError = true; + } + if (!lineError && (blockDepth == 0)) { + //we are not inside a block structure, so play sound now + if (stopSignal) { + sSound* S = system->createNewSoundAction(); + S->setPlayback(false); + S->execute(); + delete S; + } else if (resetSignal) { + sSound* S = system->createNewSoundAction(); + S->setReset(); + S->execute(); + delete S; + } else if (isText) { + + if (pos2-pos1-2 <= 20) { + + sSound* S = system->createNewSoundAction(); + S->setFile(tmpLine.substr(pos1+1,pos2-pos1-2)); + S->execute(); + delete S; + } else { + textDisplay << "Error: sound file names must be 20 characters or less.\r\n"; + lineError = true; + } + } else { + textDisplay << "Error: variable input to sound() not yet supported. Enter a string in single quotes.\r\n"; + lineError = true; + } + + } else if (!lineError && (blockDepth > 0) ){ + //the disp function was put inside a block + textDisplay.debug("Sound statement\r\n"); + if (stopSignal) { + sSound* sPtr = system->createNewSoundAction(); + sPtr->setPlayback(false); + //action* tmpAction = new action(sPtr); + tmpAction->set(sPtr); + tmpEventPtrArray.back()->addAction(tmpAction); + } else if (resetSignal) { + sSound* sPtr = system->createNewSoundAction(); + sPtr->setReset(); + //action* tmpAction = new action(sPtr); + tmpAction->set(sPtr); + tmpEventPtrArray.back()->addAction(tmpAction); + } else if (isText) { + + if (pos2-pos1-2 <= 20) { + sSound* sPtr = system->createNewSoundAction(); + sPtr->setFile(tmpLine.substr(pos1+1,pos2-pos1-2)); + //action* tmpAction = new action(sPtr); + tmpAction->set(sPtr); + tmpEventPtrArray.back()->addAction(tmpAction); + } else { + textDisplay << "Error: sound file names must be 20 characters or less.\r\n"; + lineError = true; + } + } else { + textDisplay << "Error: variable input to sound() not yet supported. Enter a string in single quotes.\r\n"; + lineError = true; + } + + + } + + } else if (tokens[i].find("volume(") != std::string::npos) { + if (ifBlockInit || whileBlockInit || elseFlag || expectingDoStatement) { + textDisplay << "Error: expected a 'do' statement\r\n"; + lineError = true; + } + wholeLineEvaluated = true; + int pos1 = tmpLine.find("volume(")+7; + int pos2 = tmpLine.find_first_of(")",pos1); + string dispVar = tmpLine.substr(pos1,pos2-pos1); + + int* tmpVar = findIntVariable(dispVar); + bool isText = false; + if (tmpVar == NULL) { + if (isNumber(dispVar)) { + isText = true; + } else { + textDisplay << "Error: variable input to volume() does not exist\r\n"; + lineError = true; + } + } + action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS); + if (tmpAction == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + lineError = true; + } + if (!lineError && (blockDepth == 0)) { + //we are not inside a block structure, so play sound now + if (isText) { + int newVolume = atoi(dispVar.data()); + if ((newVolume >=0)&&(newVolume <= 255)) { + sSound* S = system->createNewSoundAction(); + S->setVolume(newVolume); + S->execute(); + delete S; + } else { + textDisplay << "Error: sound volume must be between 0 and 255 .\r\n"; + lineError = true; + } + } else { + sSound* S = system->createNewSoundAction(); + S->setVolume(tmpVar); + S->execute(); + delete S; + } + + } else if (!lineError && (blockDepth > 0) ){ + //the disp function was put inside a block + textDisplay.debug("Volume statement\r\n"); + if (isText) { + int newVolume = atoi(dispVar.data()); + + sSound* sPtr = system->createNewSoundAction(); + sPtr->setVolume(newVolume); + + //action* tmpAction = new action(sPtr); + tmpAction->set(sPtr); + tmpEventPtrArray.back()->addAction(tmpAction); + + } else { + sSound* sPtr = system->createNewSoundAction(); + sPtr->setVolume(tmpVar); + //action* tmpAction = new action(sPtr); + tmpAction->set(sPtr); + tmpEventPtrArray.back()->addAction(tmpAction); + } + + + } + //clock statement used to is used to control the clock------------------------- + //example: clock(reset); clock(slave); clock(standalone) + } else if (tokens[i].find("clock(") != std::string::npos) { //clock commands + if (ifBlockInit || whileBlockInit || elseFlag || expectingDoStatement) { + textDisplay << "Error: expected a 'do' statement\r\n"; + lineError = true; + } + if (blockDepth > 0) { + textDisplay << "Error: clock commands only allowed outside of block structure\r\n"; + lineError = true; + } + + if (!lineError) { + int pos1 = tmpLine.find("clock(")+6; + int pos2 = tmpLine.find_first_of(")",pos1); + string dispVar = tmpLine.substr(pos1,pos2-pos1); + + + if (blockDepth == 0) { + if (dispVar.compare("reset") == 0) { + resetTimer = true; + queuePtr->eraseQueue(); + textDisplay.send(string("Clock reset to 0\r\n")); + + } else if (dispVar.compare("slave") == 0) { + if (!clockSlave) { + changeToSlave = true; + textDisplay.send(string("Slave mode\r\n")); + + } + } else if (dispVar.compare("standalone") == 0) { + if (clockSlave) { + changeToStandAlone = true; + textDisplay.send(string("Standalone mode\r\n")); + + } + } else if (dispVar.compare("") == 0) { + //The user needs the current time displayed. + + //textDisplay.send(string("Current Clock\r\n")); + textDisplay << timeKeeper << " current time\r\n"; + } else { + textDisplay << "Error: Clock control statement not understood\r\n"; + lineError = true; + } + } + } + + //disp command used to display text via serial--------------------------------------- + //example: disp('hello'); disp(myVar) + } else if (tokens[i].find("disp(") != std::string::npos) { //display value of variable + + if (ifBlockInit || whileBlockInit || elseFlag || expectingDoStatement) { + textDisplay <<"Error: expected a 'do' statement\r\n"; + lineError = true; + } + + //int pos1 = tokens[i].find("disp(")+5; + //int pos2 = tokens[i].find_first_of(")",pos1); + //string dispVar = tokens[i].substr(pos1,pos2-pos1); + + wholeLineEvaluated = true; + int pos1 = tmpLine.find("disp(")+5; + int pos2 = tmpLine.find_first_of(")",pos1); + if (pos2 == std::string::npos) { + textDisplay <<"Error: expected a ) character\r\n"; + lineError = true; + } + + if (!lineError) { + string dispVar = tmpLine.substr(pos1,pos2-pos1); + + int* tmpVar = findIntVariable(dispVar); + bool isText = false; + if (tmpVar == NULL) { + if ((tmpLine.compare(pos1,1,"'")==0) && (tmpLine.compare(pos2-1,1,"'")==0)) { + isText = true; + } else { + textDisplay << "Error: variable to display does not exist\r\n"; + lineError = true; + } + } + displayAction* dPtr = findFirstUnUsed(displayActionBlock, NUMDISPLAYACTIONS); + if (dPtr == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + lineError = true; + } + + if (!lineError && (blockDepth == 0)) { + //we are not inside a block structure, so display now + + if (isText) { + //displayAction* dPtr = new displayAction(tmpLine.substr(pos1+1,pos2-pos1-2), pcPtr); + dPtr->set(tmpLine.substr(pos1+1,pos2-pos1-2)); + dPtr->execute(); + //delete dPtr; + dPtr->release(); + } else { + //displayAction* dPtr = new displayAction(tmpVar, dispVar, pcPtr); + dPtr->set(tmpVar, dispVar); + dPtr->execute(); + //delete dPtr; + dPtr->release(); + } + + } else if (!lineError && (blockDepth > 0) ){ + //the disp function was put inside a block + textDisplay.debug("Display statement\r\n"); + action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS); + if (tmpAction == NULL) { + textDisplay <<"Error: no memory slots available.\r\n"; + lineError = true; + } + if (!lineError && isText) { + //displayAction* dPtr = new displayAction(tmpLine.substr(pos1+1,pos2-pos1-2), pcPtr); + dPtr->set(tmpLine.substr(pos1+1,pos2-pos1-2)); + tmpAction->set(dPtr); + //action* tmpAction = new action(dPtr); + tmpEventPtrArray.back()->addAction(tmpAction); + } else if (!lineError) { + //displayAction* dPtr = new displayAction(tmpVar, dispVar, pcPtr); + dPtr->set(tmpVar, dispVar); + tmpAction->set(dPtr); + //action* tmpAction = new action(dPtr); + tmpEventPtrArray.back()->addAction(tmpAction); + } + + + } + } + //---------------------------------------------- + //The trigger command is used like this: + //trigger(n) + //Where n is an integer corresponding to a "function n" block + //When "trigger" is called, the corresponding function is executed. + } else if (tokens[i].find("trigger(") != std::string::npos) { //trigger a function + + if (ifBlockInit || whileBlockInit || elseFlag || expectingDoStatement) { + textDisplay << "Error: expected a 'do' statement\r\n"; + lineError = true; + } + + + wholeLineEvaluated = true; + int pos1 = tmpLine.find("trigger(")+8; + int pos2 = tmpLine.find_first_of(")",pos1); + int funcNum = atoi(tmpLine.substr(pos1,pos2-pos1).data()); + if ((funcNum > 0) && (funcNum < NUMFUNCTIONS+1)) { + if (functionSpotTaken[funcNum-1]) { + + + } else { + textDisplay << "Error: function number does not exist\r\n"; + lineError = true; + } + } else { + textDisplay << "Error: not a valid function number\r\n"; + lineError = true; + } + + funcNum--; //change to 0-based index + if (!lineError && (blockDepth == 0)) { + //we are not inside a block structure, so execute function now + //textDisplay << "Exectuting function"; + //textDisplay.flush(); + + functionEventArray[funcNum]->execute(); + + } else if (!lineError && (blockDepth > 0) ){ + //the trigger function was put inside a block, so we need to create a new action + textDisplay.debug("Trigger statement\r\n"); + triggerFunctionAction* tPtr = findFirstUnUsed(triggerFunctionActionBlock, NUMTRIGGERACTIONS); + if (tPtr == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + lineError = true; + } + + if (!lineError) { + //we only give provide it the function number, instead + //of a pointer to the event. That way, if the user modifies + //the function (which would change the pointer), all callbacks + //still using that function number will use the new function. + tPtr->set(funcNum); + action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS); + if (tmpAction == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + lineError = true; + } + if (!lineError) { + + tmpAction->set(tPtr); + tmpEventPtrArray.back()->addAction(tmpAction); + } + } + + + } + + + + + //int is used to decalar new variables. Only allowed outside of callbacks------------------- + //example: int a; int b = 9 + } else if (tokens[i].compare("int") == 0) { //define a new integer variable + textDisplay.debug("Int statement\r\n"); + if (ifBlockInit || whileBlockInit || expectingDoStatement) { + textDisplay << "Error: expected a 'do' statement\r\n"; + lineError = true; + } + tmpString = ""; + wholeLineEvaluated = true; + int spacesBeforeEqualSign = 0; + bool countSpaces = true; + //combine the tokens without whitespaces + for (unsigned j = i+1; j < sz; j++) { + tmpString.append(tokens[j]); + if (tokens[j].find_first_of("=") != std::string::npos) { + if (tokens[j].find_first_of("=") > 0) spacesBeforeEqualSign++; + countSpaces = false; + } else if (countSpaces) { + spacesBeforeEqualSign++; + } + } + + if (blockDepth > 0) { + textDisplay << "Error: Variables can only be first declared outside of callbacks.\r\n"; + lineError = true; + } + + if ((!lineError) && (spacesBeforeEqualSign > 1)) { + textDisplay << "Error: Variable can't have a space in it.\r\n"; + lineError = true; + } + stringInd = tmpString.find_first_of("="); + + bool variableCreated = false; + if (!lineError) { + if (((stringInd == std::string::npos) && (sz == 2)) || (stringInd != std::string::npos)) { + + if ((stringInd != std::string::npos) && (stringInd > MAXVARNAMESIZE)) { + textDisplay << "Error: variable names must be under 30 characters.\r\n"; + lineError = true; + } else if (createIntVariable(tmpString.substr(0,stringInd))) { + textDisplay.debug("Created new variable\r\n"); + variableCreated = true; + } else { + textDisplay.debug("Attempting to use existing variable\r\n"); + int* tmpVar = findIntVariable(tmpString.substr(0,stringInd)); + *tmpVar = 0; + //lineError = true; + } + } else { + textDisplay << "Error: variable declaration not understood.\r\n"; + lineError = true; + } + } + if ((!lineError) && (stringInd != std::string::npos)) { //evaluate the expression + //action* tmpAction = evaluateAssignmentForAction(tmpString); + action* tmpAction = evaluateAssignmentForAction(tmpString.data()); + if (tmpAction != NULL) { + tmpAction->execute(); + //delete tmpAction; + tmpAction->release(); + } else { + lineError = true; + if (variableCreated) { + delete globalVariables.back(); + globalVariables.pop_back(); + } + } + } + + //serial command is used to toggle whether or not to buffer up output text---------------- + //examples: serial buffer; serial send + } else if (tokens[i].compare("serial") == 0) { + if (ifBlockInit || whileBlockInit || elseFlag || expectingDoStatement) { + textDisplay << "Error: expected a 'do' statement\r\n"; + lineError = true; + } + bool stream = true; + if ((!lineError)&&(i+1 < sz)){ + if (tokens[i+1].compare("buffer") == 0) { + stream = false; + } else if (tokens[i+1].compare("send") == 0) { + stream = true; + } else { + textDisplay << "Error: 'serial' useage: 'serial buffer' or 'serial send'\r\n"; + lineError = true; + } + } + i++; + if ((!lineError) && (blockDepth == 0)) { + if (stream) { + textStreaming = true; + } else { + textStreaming = false; + } + } else if ((!lineError) && (blockDepth > 0)) { + if (stream) { + //action* tmpAction = new action(1); //code 1 = turn on text streaming + action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS); + if (tmpAction == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + lineError = true; + } else { + tmpAction->set(1); + tmpEventPtrArray.back()->addAction(tmpAction); + } + + } else { + //action* tmpAction = new action(2); //code 2 = turn on text buffering + action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS); + if (tmpAction == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + lineError = true; + } else { + tmpAction->set(2); + tmpEventPtrArray.back()->addAction(tmpAction); + } + } + } + + //updates command toggles the DIO update messages upon a change------------------ + //examples: updates on; updates off + } else if (tokens[i].compare("updates") == 0) { + if (ifBlockInit || whileBlockInit || elseFlag || expectingDoStatement) { + textDisplay << "Error: expected a 'do' statement\r\n"; + lineError = true; + } + bool stream = true; + if ((!lineError)&&(i+1 < sz)){ + if (tokens[i+1].compare("on") == 0) { + stream = true; + } else if (tokens[i+1].compare("off") == 0) { + stream = false; + } else { + textDisplay << "Error: 'updates' 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) { + textDisplay << "Error: no memory slots available.\r\n"; + lineError = true; + } else { + tmpAction->set(3); + tmpEventPtrArray.back()->addAction(tmpAction); + } + } else { + //action* tmpAction = new action(4); //code 4 = turn off updates + action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS); + if (tmpAction == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + lineError = true; + } else { + tmpAction->set(4); + tmpEventPtrArray.back()->addAction(tmpAction); + } + + } + } + + } else if (tokens[i].compare("memory") == 0) { + if (ifBlockInit || whileBlockInit || elseFlag || expectingDoStatement) { + textDisplay << "Error: expected a 'do' statement\r\n"; + lineError = true; + } + if ((!lineError) && (blockDepth > 0)) { + textDisplay << "Error: memory statement is not allowed inside a block.\r\n"; + lineError = true; + } + if (!lineError) { + displayMemoryLeft(); + } + + + //clear is used to clear things from memory--------------------------------- + //examples: clear all; clear callbacks; clear queue + + } else if (tokens[i].compare("clear") == 0) { //delete all created events and variables + if (ifBlockInit || whileBlockInit || elseFlag || expectingDoStatement) { + textDisplay << "Error: expected a 'do' statement\r\n"; + lineError = true; + } + int clearMode = 0; + if ((!lineError)&&(i+1 < sz)){ + if (tokens[i+1].compare("all") == 0) { + clearMode = 1; + } else if (tokens[i+1].compare("blocks") == 0) { + clearMode = 2; + } else if (tokens[i+1].compare("queue") == 0) { + clearMode = 3; + } else { + textDisplay << "Error: clear what: all, blocks, or queue? \r\n"; + lineError = true; + } + } else { + textDisplay << "Error: clear what: all, blocks, or queue? \r\n"; + lineError = true; + } + + + if ((!lineError) && (clearMode < 3) && (blockDepth > 0)) { + textDisplay << "Error: 'clear all' and 'clear blocks' only allowed outside of block structures\r\n"; + lineError = true; + } + if (!lineError) { + //i++; + //clear variables + if (clearMode == 1) { + while (!globalVariables.empty()) { + delete globalVariables.back(); + globalVariables.pop_back(); + } + } + + //clear callbacks, functions, and queue + if (clearMode < 3) { + for (int pNum = 0; 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(); + } */ + } + for (int i = 0; i < NUMFUNCTIONS; i++) { + functionSpotTaken[i] = false; + functionEventArray[i] = NULL; + } + for (int i = 0; i < NUMEVENTS; i++) { + eventBlock[i].release(); + } + for (int i = 0; i < NUMCONDITIONS; i++) { + conditionBlock[i].release(); + } + for (int i = 0; i < NUMINTCOMPARE; i++) { + intCompareBlock[i].release(); + } + for (int i = 0; i < NUMACTIONS; i++) { + actionBlock[i].release(); + } + for (int i = 0; i < NUMPORTMESSAGES; i++) { + portMessageBlock[i].release(); + } + for (int i = 0; i < NUMINTOPERATIONS; i++) { + intOperationBlock[i].release(); + } + for (int i = 0; i < NUMDISPLAYACTIONS; i++) { + displayActionBlock[i].release(); + } + for (int i = 0; i <NUMTRIGGERACTIONS; i++) { + triggerFunctionActionBlock[i].release(); + } + + queuePtr->eraseQueue(); + } + + if (clearMode == 4) { + if (blockDepth > 0) { //we are inside a block + action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS); + if (tmpAction == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + lineError = true; + } else { + + int8_t code = 0; + tmpAction->set(code); + //action* tmpAction = new action(code); //code 0 = clear queue + tmpEventPtrArray.back()->addAction(tmpAction); + } + } else { + //clear queue now + queuePtr->eraseQueue(); + } + } + wholeLineEvaluated = true; + + + } + + //do starts a block--------------------------------------------------------- + //example: do in 500 + // ... + // end + + } else if (tokens[i].compare("do") == 0) { //the start of a block + + if (!ifBlockInit && !whileBlockInit) { + + if ((currentTriggerPort > 0) || (currentFunction > -1)) { //check to make sure we are inside a trigger block + + + } else { + textDisplay << "Error: a statement block must be placed inside a callback or function.\r\n"; + lineError = true; + } + + } + expectingDoStatement = false; + tmpEvent = findFirstUnUsed(eventBlock, NUMEVENTS); + action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS); + bool eventReserved = false; + if ((tmpEvent == NULL)||(tmpAction == NULL)) { + textDisplay << "Error: no memory slots available.\r\n"; + lineError = true; + + } else { + + + } + + if (i+2 < sz) { //a time delay in the block + + if ((!lineError) && (tokens[i+1].compare("in") == 0) && (isNumber(tokens[i+2]))) { + textDisplay.debug("Do in number statement\r\n"); + currentDelay = atoi(tokens[i+2].data()); + if (currentDelay < 0) { + textDisplay <<"Error: block delay time must be a positive integer\r\n"; + lineError = true; + } else if (!ifBlockInit) { //a standalone do block + //tmpEvent = new event(queuePtr); + tmpEvent->isUsed = true; + eventReserved = true; + tmpEvent->setTimeLag(currentDelay); + + if ((!elseFlag) && ((!thenFlag))) { + //tmpEventPtrArray.back()->addAction(new action(tmpEvent)); + tmpAction->set(tmpEvent); + tmpEventPtrArray.back()->addAction(tmpAction); + tmpEventPtrArray.push_back(tmpEvent); + tmpEventPtrArray.back()->blockType = 2; //this is a do block + blockDepth = blockDepth+1; + } else if (elseFlag) { + tmpEventPtrArray.back()->setNextElseEvent(tmpEvent); + tmpEventPtrArray.push_back(tmpEvent); + tmpEventPtrArray.back()->blockType = 4; //an else block + } else if (thenFlag) { + + tmpEventPtrArray.back()->setNextElseEvent(tmpEvent); + tmpEventPtrArray.push_back(tmpEvent); + tmpEventPtrArray.back()->blockType = 8; //a then block + } + + } else { //an if block + tmpEventPtrArray.back()->setTimeLag(currentDelay); + + if (!elseFlag && !thenFlag) { + if (blockDepth > 1) { //this is a nested block, so add it as an action to the parent block + tmpAction->set(tmpEventPtrArray.back()); + tmpEventPtrArray.at(tmpEventPtrArray.size()-2)->addAction(tmpAction); + //tmpEventPtrArray.at(tmpEventPtrArray.size()-2)->addAction(new action(tmpEventPtrArray.back())); + } + } else if (elseFlag){ + tmpEventPtrArray.at(tmpEventPtrArray.size()-2)->setNextElseEvent(tmpEventPtrArray.back()); + } else if (thenFlag){ + tmpEventPtrArray.at(tmpEventPtrArray.size()-2)->setNextElseEvent(tmpEventPtrArray.back()); + + } + + + } + + } else if ((!lineError) && (tokens[i+1].compare("in") == 0) && (findIntVariable(tokens[i+2])!=NULL)) { + textDisplay.debug("Do in VAR statement\r\n"); + int* delayVar = findIntVariable(tokens[i+2]); + //currentDelay = atoi(tokens[i+2].data()); + if (!ifBlockInit) { //a standalone do block + //tmpEvent = new event(queuePtr); + tmpEvent->isUsed = true; + eventReserved = true; + tmpEvent->setTimeLag(delayVar); + + if ((!elseFlag) && ((!thenFlag))) { + //tmpEventPtrArray.back()->addAction(new action(tmpEvent)); + tmpAction->set(tmpEvent); + tmpEventPtrArray.back()->addAction(tmpAction); + tmpEventPtrArray.push_back(tmpEvent); + tmpEventPtrArray.back()->blockType = 2; //this is a do block + blockDepth = blockDepth+1; + } else if (elseFlag) { + tmpEventPtrArray.back()->setNextElseEvent(tmpEvent); + tmpEventPtrArray.push_back(tmpEvent); + tmpEventPtrArray.back()->blockType = 4; //an else block + } else if (thenFlag) { + + tmpEventPtrArray.back()->setNextElseEvent(tmpEvent); + tmpEventPtrArray.push_back(tmpEvent); + tmpEventPtrArray.back()->blockType = 8; //a then block + } + + } else { //an if block + tmpEventPtrArray.back()->setTimeLag(delayVar); + + if (!elseFlag && !thenFlag) { + if (blockDepth > 1) { //this is a nested block, so add it as an action to the parent block + tmpAction->set(tmpEventPtrArray.back()); + tmpEventPtrArray.at(tmpEventPtrArray.size()-2)->addAction(tmpAction); + //tmpEventPtrArray.at(tmpEventPtrArray.size()-2)->addAction(new action(tmpEventPtrArray.back())); + } + } else if (elseFlag){ + tmpEventPtrArray.at(tmpEventPtrArray.size()-2)->setNextElseEvent(tmpEventPtrArray.back()); + } else if (thenFlag){ + tmpEventPtrArray.at(tmpEventPtrArray.size()-2)->setNextElseEvent(tmpEventPtrArray.back()); + + } + + + } + + } else { + textDisplay << "Error: block delay time must be a positive integer or a variable\r\n"; + lineError = true; + } + } else if (!lineError && !ifBlockInit) { //no time delay given, standalone do + textDisplay.debug("Do statement\r\n"); + currentDelay = 0; + //tmpEvent = new event(queuePtr); + tmpEvent->isUsed = true; + eventReserved = true; + tmpEvent->setTimeLag(currentDelay); + if (!elseFlag && !thenFlag) { + tmpAction->set(tmpEvent); + tmpEventPtrArray.back()->addAction(tmpAction); + //tmpEventPtrArray.back()->addAction(new action(tmpEvent)); + tmpEventPtrArray.push_back(tmpEvent); + blockDepth = blockDepth+1; + } else if (elseFlag) { + tmpEventPtrArray.back()->setNextElseEvent(tmpEvent); + tmpEventPtrArray.push_back(tmpEvent); + tmpEventPtrArray.back()->blockType = 4; //an else block + } else if (thenFlag) { + tmpEventPtrArray.back()->setNextElseEvent(tmpEvent); + tmpEventPtrArray.push_back(tmpEvent); + tmpEventPtrArray.back()->blockType = 8; //a then block + } + + } else if (!lineError) { //no time delay, if block + + currentDelay = 0; + tmpEventPtrArray.back()->setTimeLag(currentDelay); + + + if (!elseFlag && !thenFlag) { + if (blockDepth > 1) { + tmpAction->set(tmpEventPtrArray.back()); + tmpEventPtrArray.at(tmpEventPtrArray.size()-2)->addAction(tmpAction); + //tmpEventPtrArray.at(tmpEventPtrArray.size()-2)->addAction(new action(tmpEventPtrArray.back())); + } + } else { + tmpEventPtrArray.at(tmpEventPtrArray.size()-2)->setNextElseEvent(tmpEventPtrArray.back()); + } + + } + if (lineError && eventReserved) { + tmpEvent->release(); + } + //close block initiation + ifBlockInit = false; + whileBlockInit = false; + wholeLineEvaluated = true; + elseFlag = false; + thenFlag = false; + + //currently, there are two types of root-level blocks: functions and callbacks + // + //A function can be triggered with a command, a callback is tied to a hardware event + } else if (tokens[i].compare("function") == 0) { //a new function block + if (ifBlockInit || whileBlockInit || elseFlag || expectingDoStatement) { + textDisplay << "Error: expected a 'do' statement\r\n"; + lineError = true; + } + if (blockDepth != 0) { + textDisplay <<"Error: Can't declare a function block within another block\r\n"; + lineError = true; + } + if (!lineError) { + textDisplay.debug("Function statement\r\n"); + wholeLineEvaluated = true; + if (i+1 < sz) { + int tempFuncNum = atoi(tokens[i+1].data()); + if ((tempFuncNum > 0) && (tempFuncNum < NUMFUNCTIONS+1)) { + currentFunction = tempFuncNum-1; + } else { + textDisplay << "Error: not a valid function number\r\n"; + lineError = true; + } + } else { + if (!lineError) textDisplay << "Error: Not enough arguments for function statement\r\n"; + lineError = true; + } + if (sz > 2) { + if (!((sz == 3) && (tokens[i+2].compare("do") == 0))) { + textDisplay << "Error: Too many arguments in function statement\r\n"; + lineError = true; + } + } + + tmpEvent = findFirstUnUsed(eventBlock, NUMEVENTS); + if (tmpEvent != NULL) { + tmpEvent->isUsed = true; + + } else { + textDisplay << "Error: no memory slots available.\r\n"; + lineError = true; + } + if (!lineError) { + + blockDepth = 1; + i = i+2; + //create new event and attach it to the port + //tmpEventPtrArray.push_back(new event(queuePtr)); + tmpEventPtrArray.push_back(tmpEvent); + + if (functionSpotTaken[currentFunction]) { + functionEventArray[currentFunction]->release(); + } + functionEventArray[currentFunction] = tmpEvent; + functionSpotTaken[currentFunction] = true; + + } + } + + + //callback starts a callback block------------------------------------------ + //exmaple: callback portin(1) down + // ... + // end + } else if (tokens[i].compare("callback") == 0) { //a new callback block + if (ifBlockInit || whileBlockInit || elseFlag || expectingDoStatement) { + textDisplay << "Error: expected a 'do' statement\r\n"; + lineError = true; + } + if (blockDepth != 0) { + textDisplay << "Error: Can't declare a callback block within another block\r\n"; + lineError = true; + } + if (!lineError) { + textDisplay.debug("Callback statement\r\n"); + wholeLineEvaluated = true; + if (i+2 < sz) { + if ((tokens[i+1].find("portin[") != std::string::npos) && (tokens[i+1].size() > 8) ) { //callback for a digital port + int pos1 = tokens[i+1].find("portin[")+7; + int pos2 = tokens[i+1].find_first_of("]",pos1); + currentTriggerPort = atoi(tokens[i+1].substr(pos1,pos2-pos1).data()); + + if (currentTriggerPort <= 0) { + currentTriggerPort = -1; + textDisplay << "Error: Not a valid port number\r\n"; + lineError = true; + } + } else { + textDisplay << "Error: Not a valid callback input\r\n"; + lineError = true; + } + if (tokens[i+2].compare("up") == 0) { + currentTriggerDir = 1; + } else if (tokens[i+2].compare("down") == 0) { + currentTriggerDir = -1; + } else { + textDisplay << "Error: No trigger direction given\r\n"; + lineError = true; + } + + } else { + if (!lineError) textDisplay << "Error: Not enough arguments for callback statement\r\n"; + lineError = true; + } + if (sz > 3) { + if (!((sz == 4) && (tokens[i+3].compare("do") == 0))) { + textDisplay << "Error: Too many arguments in callback statement\r\n"; + lineError = true; + } + } + + tmpEvent = findFirstUnUsed(eventBlock, NUMEVENTS); + if (tmpEvent != NULL) { + tmpEvent->isUsed = true; + + } else { + textDisplay << "Error: no memory slots available.\r\n"; + lineError = true; + } + if (!lineError) { + + blockDepth = 1; + i = i+2; + //create new event and attach it to the port + //tmpEventPtrArray.push_back(new event(queuePtr)); + tmpEventPtrArray.push_back(tmpEvent); + if (currentTriggerDir == 1) { + + portVector[currentTriggerPort-1].setTriggerUpEvent(tmpEventPtrArray.back()); + } else { + + portVector[currentTriggerPort-1].setTriggerDownEvent(tmpEventPtrArray.back()); + } + + } + } + + //if starts an if block---------------------------------------------- + //examples: if x < 10 && y == 1 do; if a==1 do in 1000 + } else if (tokens[i].compare("if") == 0) { //a new if block + if (ifBlockInit || whileBlockInit) { + textDisplay << "Error: expected a 'do' statement\r\n"; + lineError = true; + } + + ifBlockInit = true; + currentDelay = 0; + bool eventDefined = false; + tmpEvent = findFirstUnUsed(eventBlock, NUMEVENTS); + if (tmpEvent != NULL) { + tmpEvent->isUsed = true; + eventDefined = true; + } else { + textDisplay << "Error: no memory slots available.\r\n"; + lineError = true; + } + if (!lineError) { + textDisplay.debug("If statement\r\n"); + //this is a regular event + //tmpEventPtrArray.push_back(new event(queuePtr)); + tmpEventPtrArray.push_back(tmpEvent); + + if ((!elseFlag) && ((!thenFlag))) { + tmpEventPtrArray.back()->blockType = 1; //this is an if block + blockDepth = blockDepth + 1; + } else if (elseFlag) { + tmpEventPtrArray.back()->blockType = 3; //this is an else if block + } else if (thenFlag) { + tmpEventPtrArray.back()->blockType = 7; //this is a then if block + } + } + + if (!lineError) { + //combine the condition tokens without whitespaces + tmpString = ""; + for (unsigned j = i+1; j < sz; j++) { + if (tokens[j].compare("do") != 0) { + i++; + tmpString.append(tokens[j]); + } else { + break; + } + } + //adds the conditions to the current event + + if (!evaluateConditions(tmpString, tmpEventPtrArray.back())) lineError = true; + } + + if (lineError && eventDefined) { + tmpEvent->release(); + } + + + //else starts an else block------------------------------------- + //examples: else do in 500; else if x==7 do + } else if (tokens[i].compare("else") == 0) { //an else block + if (ifBlockInit || whileBlockInit || expectingDoStatement) { + textDisplay << "Error: expected a 'do' statement\r\n"; + lineError = true; + } + textDisplay.debug("Else statement\r\n"); + //callbacks can't have else conditions + if ((!lineError) && (blockDepth < 2) && ((currentTriggerPort > -1)||(currentFunction > -1))) { + textDisplay << "Error: else statement can not occur after a trigger block or outside a block\r\n"; + lineError = true; + } + + //check to make sure we are in an 'if' block + if ((!lineError) && (tmpEventPtrArray.back()->blockType != 1) && (tmpEventPtrArray.back()->blockType != 3)) { //not currently in an 'if' or 'else if' block + textDisplay << "Error: else statement can only occur in an 'if' block\r\n"; + lineError = true; + } + if (!lineError) { + elseFlag = true; + expectingDoStatement = true; + + } + } else if (tokens[i].compare("then") == 0) { //a then block + if (ifBlockInit || whileBlockInit) { + textDisplay << "Error: expected a 'do' statement\r\n"; + lineError = true; + } + + //trigger blocks can't have else conditions + if ((!lineError) && (blockDepth < 2) && (currentTriggerPort > -1)) { + textDisplay << "Error: 'then' statement can only occur after a 'while' block\r\n"; + lineError = true; + } + + //check to make sure we are in a 'while' block + if ((!lineError) && (tmpEventPtrArray.back()->blockType != 5)) { //not currently in a while block + textDisplay << "Error: 'then' statement can only occur in a 'while' block\r\n"; + lineError = true; + } + if (!lineError) { + thenFlag = true; + expectingDoStatement = true; + + } + //while starts a while block---------------------------------------- + //example: while x<10 do every 100 + // ... + // end + } else if (tokens[i].compare("while") == 0) { //a new while block + if (ifBlockInit || whileBlockInit) { + textDisplay << "Error: expected a 'do' statement\r\n"; + lineError = true; + } + textDisplay.debug("While statement\r\n"); + + if ((currentTriggerPort > 0) || (currentFunction > -1)) { //check to make sure we are inside a trigger block + + + } else { + textDisplay << "Error: a statement block must be placed inside a callback or function.\r\n"; + lineError = true; + } + //whileBlockInit = true; + currentDelay = 0; + + tmpEvent = findFirstUnUsed(eventBlock, NUMEVENTS); + if (tmpEvent != NULL) { + tmpEvent->isUsed = true; + tmpEvent->setTimeLag(currentDelay); + } else { + textDisplay << "Error: no memory slots available.\r\n"; + lineError = true; + } + + //tmpEvent = new event(queuePtr); + + + if (!lineError) { + //combine the condition tokens without whitespaces + tmpString = ""; + for (unsigned j = i+1; j < sz; j++) { + if (tokens[j].compare("do") != 0) { + i++; + tmpString.append(tokens[j]); + } else { + break; + } + } + //adds the conditions to the current event + if (!evaluateConditions(tmpString, tmpEvent)) lineError = true; + } + + if (!lineError) { + if ((i+3) < sz) { + if ((tokens[i+1].compare("do") == 0) && (tokens[i+2].compare("every") == 0)) { + + if (isNumber(tokens[i+3])) { + uint32_t period = atoi(tokens[i+3].data()); + if (period > 0) { + + + //tmpEvent->whileLoopPeriod = period; + tmpEvent->setWhileLoopPeriod(period); + if (!elseFlag) { + tmpEvent->blockType = 5; //this is a while block + + action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS); + if (tmpAction == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + lineError = true; + } else { + tmpAction->set(tmpEvent); + } + //tmpEventPtrArray.back()->addAction(new action(tmpEvent)); + tmpEventPtrArray.back()->addAction(tmpAction); + + tmpEventPtrArray.push_back(tmpEvent); + blockDepth = blockDepth+1; + } else { + tmpEvent->blockType = 6; //this is an else while block + tmpEventPtrArray.back()->setNextElseEvent(tmpEvent); + tmpEventPtrArray.push_back(tmpEvent); + } + wholeLineEvaluated = true; + } else { + textDisplay << "Error: loop period must be a positive integer.\r\n"; + lineError = true; + } + } else if (findIntVariable(tokens[i+3])!=NULL) { + + int* period = findIntVariable(tokens[i+3]); + //tmpEvent->whileLoopPeriodVar = period; + tmpEvent->setWhileLoopPeriod(period); + if (!elseFlag) { + tmpEvent->blockType = 5; //this is a while block + + action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS); + if (tmpAction == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + lineError = true; + } else { + tmpAction->set(tmpEvent); + } + //tmpEventPtrArray.back()->addAction(new action(tmpEvent)); + tmpEventPtrArray.back()->addAction(tmpAction); + + tmpEventPtrArray.push_back(tmpEvent); + blockDepth = blockDepth+1; + } else { + tmpEvent->blockType = 6; //this is an else while block + tmpEventPtrArray.back()->setNextElseEvent(tmpEvent); + tmpEventPtrArray.push_back(tmpEvent); + } + wholeLineEvaluated = true; + } + } else { + textDisplay << "Error: expected a 'do every' statement\r\n"; + lineError = true; + } + } else { + textDisplay << "Error: expected a 'do every' statement\r\n"; + lineError = true; + } + } + + //if the line contains an '=' sign,the equality is evaulated------------------------- + //examples: a = 1; a = b + 5; a = random(100); portout[2] = 1; portout[2] = flip + } else if ((tmpLine.find_first_of("=") != std::string::npos) ) { //an expression + if (ifBlockInit || whileBlockInit || elseFlag || expectingDoStatement) { + textDisplay << "Error: expected a 'do' statement\r\n"; + lineError = true; + } + + wholeLineEvaluated = true; + tmpString = ""; + int spacesBeforeEqualSign = 0; + bool countSpaces = true; + //combine the tokens without whitespaces + for (unsigned j = i; j < sz; j++) { + tmpString.append(tokens[j]); + if (tokens[j].find_first_of("=") != std::string::npos) { + if (tokens[j].find_first_of("=") > 0) spacesBeforeEqualSign++; + countSpaces = false; + } else if (countSpaces) { + spacesBeforeEqualSign++; + } + } + if (!lineError && spacesBeforeEqualSign > 1) { + textDisplay << "Error: Variable can't have a space in it.\r\n"; + lineError = true; + } + + if (!lineError) { + if (blockDepth > 0) { + textDisplay.debug("Variable assignment statement\r\n"); + //action* tmpAction = evaluateAssignmentForAction(tmpString); + action* tmpAction = evaluateAssignmentForAction(tmpString.data()); + if (tmpAction != NULL) { + tmpEventPtrArray.back()->addAction(tmpAction); + + } else { + lineError = true; + } + + } else { //assignment was written outside of any block structure, so execute now + + + //action* tmpAction = evaluateAssignmentForAction(tmpString); + action* tmpAction = evaluateAssignmentForAction(tmpString.data()); + + if (tmpAction != NULL) { + tmpAction->execute(); + + //delete tmpAction; + tmpAction->release(); + } else { + lineError = true; + } + } + } + } else { + //if there was no match to any of the above, an error is given + textDisplay << "Error: statement not understood.\r\n"; + lineError = true; + } + + if (lineError) { + break; //stop parsing the rest of the line if an error was detected + } + if (wholeLineEvaluated) { //some of the tokens forces the whole line to be avaluated at once + i = sz; //skip ahead to end of the line + } + + } + + //if there was an error, we quit compiling the code + if (lineError) { + textDisplay << "Line text: "; + while (!tokens.empty()) { + textDisplay << tokens.front()<< " "; + tokens.erase(tokens.begin()); + } + textDisplay << "\r\n"; + currentBlock.resetBuffer(); + while (!tokens.empty()) { + tokens.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)) { + textDisplay << "Error: Missing 1 or more end statements\r\n"; + lineError = true; + currentBlock.resetBuffer(); + } + + if ((!lineError)&&(blockDepth == 0)) { + textDisplay.send("~~~\r\n"); + } + + //displayMemoryLeft(); + //DisplayRAMBanks(); + +} + + +//used to return a pointer to a variable, if it exists +int* scriptStream::findIntVariable(string nameInput) { + + textDisplay.debug("Finding variable: "); + textDisplay.debug(nameInput.data()); + int* outPtr = NULL; + bool foundIt = false; + 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-1].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-1].inState; + foundIt = true; + } + } + + if (!foundIt) { + std::vector<intVariable*>::size_type sz = globalVariables.size(); + int start = 0; + int end = nameInput.length()-1; + + for (unsigned i = 0; i < sz; i++) { + + + if ((findStringLoc(nameInput.data(),globalVariables[i]->tag,start,end) != -1) && (strlen(globalVariables[i]->tag)==(end-start+1))) { + outPtr = &globalVariables[i]->value; + break; + } + /* + if (nameInput.compare(globalVariables[i]->tag) == 0) { + outPtr = &globalVariables[i]->value; + break; + }*/ + } + } + textDisplay.debug("...done\r\n"); + + return outPtr; +} + + +//used to return a pointer to a variable, if it exists +int* scriptStream::findIntVariable(const char* nameInput, int start, int end) { + + textDisplay.debug("Finding variable..."); + int* outPtr = NULL; + bool foundIt = false; + + if (findStringLoc(nameInput,"portout[",start,end) != -1) { + int pos1 = findStringLoc(nameInput,"portout[",start,end)+8; + int pos2 = findStringLoc(nameInput, "]",pos1,end); + if ((pos1 == -1)||(pos2 == -1)) { + //syntax error + return NULL; + } + + //int portnum = atoi(nameInput.substr(pos1,pos2-pos1).data()); + long int portnum = strtol(nameInput+pos1,NULL,10); + if ((portnum > 0) && (portnum <= numPorts)) { + outPtr = &portVector[(int)portnum-1].outState; + foundIt = true; + } + } else if (findStringLoc(nameInput,"portin[",start,end) != -1) { + int pos1 = findStringLoc(nameInput,"portin[",start,end)+7; + int pos2 = findStringLoc(nameInput, "]",pos1,end); + if ((pos1 == -1)||(pos2 == -1)) { + //syntax error + return NULL; + } + long int portnum = strtol(nameInput+pos1,NULL,10); + + if ((portnum > 0) && (portnum <= numPorts)) { + outPtr = &portVector[(int)portnum-1].inState; + foundIt = true; + } + } + + if (!foundIt) { + std::vector<intVariable*>::size_type sz = globalVariables.size(); + for (unsigned i = 0; i < sz; i++) { + //const char* varName = globalVariables[i]->tag.data(); + if ((findStringLoc(nameInput,globalVariables[i]->tag,start,end) != -1) && (strlen(globalVariables[i]->tag)==(end-start+1))) { + outPtr = &globalVariables[i]->value; + break; + } + } + } + textDisplay.debug("done\r\n"); + + return outPtr; +} + +bool scriptStream::createIntVariable(string nameInput) { + if (findIntVariable(nameInput) == NULL) { + globalVariables.push_back(new intVariable(nameInput, 0)); + return true; + } else { + return false; + } +} + +action* scriptStream::evaluateAssignmentForAction(const char* expression) { + + //action* tmpAction = new action(); //create a new action + action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS); + if (tmpAction == NULL) { + textDisplay << "Error: no action memory slots available.\r\n"; + return NULL; + } + int stringInd; + int stringInd2; + int afterEqualLoc; + int beforeEqualLoc; + int lastCharLoc = strlen(expression)-1; + int multiplierInt = 1; + //string afterEqual; + //string beforeEqual; + //The expression might have up to three variables + int* tmpVar; + int* tmpVar2; + int* tmpVar3; + + stringInd = findStringLoc(expression,"=",0,strlen(expression)-1); //location of = sign, if it exists + if (stringInd == -1) { + //Make sure there is an equal sign + return NULL; + } + + beforeEqualLoc = stringInd-1; + afterEqualLoc = stringInd+1; + + //location of +/- sign (only one allowed) + stringInd2 = findStringLoc(expression,"+",afterEqualLoc,strlen(expression)-1); + if (stringInd2 == -1) { + stringInd2 = findStringLoc(expression,"-",afterEqualLoc,strlen(expression)-1); + multiplierInt = -1; + + } + + tmpVar = findIntVariable(expression,0,beforeEqualLoc); //returns pointer to the variable + if (findStringLoc(expression,"portout[",0,beforeEqualLoc) != -1) { //set the output of a digital port + textDisplay.debug("Portout assignment\r\n"); + int pos1 = findStringLoc(expression,"portout[",0,beforeEqualLoc)+8; + int pos2 = findStringLoc(expression,"]",pos1,beforeEqualLoc)-1; + if (pos2 < pos1) { + textDisplay << "Error: expected a ] character\r\n"; + return NULL; + } + + int portnum = -1; + if (isNum(expression,pos1,pos2)) { + portnum = atoi(expression+pos1); + } + int* tmpVar = findIntVariable(expression, pos1,pos2); //returns pointer to the variable, if given + int portVal = 0; + if ((tmpVar != NULL)||((portnum > 0) && (portnum <= numPorts))) { + if (isNum(expression,afterEqualLoc,lastCharLoc)) { //a simple numeric assign + portVal = atoi(expression+afterEqualLoc); + if ((portVal == 0) || (portVal == 1)) { + //portMessage* tmpMessage = new portMessage(portVector[portnum],1,portVal); + portMessage* tmpMessage = findFirstUnUsed(portMessageBlock, NUMPORTMESSAGES); + if (tmpMessage == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + //tmpMessage->setMessage(portVector[portnum],1,portVal); + if (tmpVar == NULL) { //a constant port number was given + tmpMessage->setMessage(NULL,portnum,portVal,portVector); + } else { + tmpMessage->setMessage(tmpVar,0,portVal,portVector); + } + } + + + tmpAction->set(tmpMessage); + + } else { + textDisplay << "Error: portouts can only be directly assigned a 1, 0 or 'flip'\r\n"; + //delete tmpAction; + tmpAction->release(); + return NULL; + } + } else if (findStringLoc(expression,"flip",afterEqualLoc,lastCharLoc)!=-1) { + //portMessage* tmpMessage = new portMessage(portVector[portnum],1,-1); + portMessage* tmpMessage = findFirstUnUsed(portMessageBlock, NUMPORTMESSAGES); + if (tmpMessage == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + //tmpMessage->setMessage(portVector[portnum],1,-1); + if (tmpVar == NULL) { //a constant port number was given + tmpMessage->setMessage(NULL,portnum,-1,portVector); + } else { + tmpMessage->setMessage(tmpVar,0,-1,portVector); + } + } + tmpAction->set(tmpMessage); + } else { + textDisplay << "Error: portouts can only be directly assigned a 1, 0, or 'flip'\r\n"; + //delete tmpAction; + tmpAction->release(); + return NULL; + } + } else { + textDisplay << "Port number not found (must be between 1 and " << numPorts << " or an existing variable)\r\n"; + //delete tmpAction; + tmpAction->release(); + return NULL; + } + } else if (findStringLoc(expression,"portin",0,stringInd)!=-1) { + textDisplay << "Error: portins can not be set\r\n"; + //delete tmpAction; + tmpAction->release(); + return NULL; + } else if (tmpVar != NULL) { + intOperation* tmpOp; + intOperation* tmpOp2; + if (isNum(expression,afterEqualLoc,lastCharLoc)) { //a simple numeric assign + textDisplay.debug("Numeric assignment\r\n"); + //tmpOp = new intOperation(tmpVar, "=", atoi(afterEqual.data())); + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + tmpOp->set(tmpVar, "=", atoi(expression+afterEqualLoc)); + } + tmpAction->set(tmpOp); + + } else if ((stringInd2 == -1)&&(findStringLoc(expression,"random",afterEqualLoc,lastCharLoc)!=-1)) { + //assign random number + //no +/- detected, so its a simple assign + textDisplay.debug("Random number assignment\r\n"); + int highVal = getRandomParam(expression,afterEqualLoc,lastCharLoc); + + if (highVal > 0) { + //tmpOp = new intOperation(highVal, "=", tmpVar); //for random assignment, we reverse the input order (because of overloading uniqueness) + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + tmpOp->setRandOp(highVal, "=", tmpVar, false); + } + tmpAction->set(tmpOp); + + } else { + //delete tmpAction; + tmpAction->release(); + return NULL; + } + } else if ((stringInd2 == -1)&&(findStringLoc(expression,"clock()",afterEqualLoc,lastCharLoc)!=-1)) { + //assign clock value + //no +/- detected, so its a simple assign + textDisplay.debug("Clock assignment to variable\r\n"); + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + tmpOp->setClockOp(tmpVar); //assigns the current clock value to tmpVar + } + tmpAction->set(tmpOp); + + } else if (stringInd2 != -1) { //a +/- operation is there + textDisplay.debug("equation assignment\r\n"); + //string multiplier("+"); + char multiplier[3]; + if (multiplierInt==1) { + strcpy(multiplier,"+"); + } else { + strcpy(multiplier,"-"); + } + + /* + if (afterEqual[stringInd2] == '-') { + multiplier = "-"; + multiplierInt = -1; + }*/ + tmpVar2 = findIntVariable(expression,afterEqualLoc,stringInd2-1); //before the +/- sign + tmpVar3 = findIntVariable(expression,stringInd2+1,lastCharLoc); //after the +/- sign + + if ((tmpVar2 != NULL) && isNum(expression,stringInd2+1,lastCharLoc)) { //variable +/- number + if (tmpVar2 == tmpVar) { + //final sign is += or -= + if (multiplierInt==1) { + strcpy(multiplier,"+="); + } else { + strcpy(multiplier,"-="); + } + + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + tmpOp->set(tmpVar, multiplier, atoi(expression+stringInd2+1)); + } + tmpAction->set(tmpOp); + + } else { + + tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp2 == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + + tmpOp2->set(tmpVar2,multiplier, atoi(expression+stringInd2+1)); + //tmpOp->set(tmpVar, tmpOp2); + } + + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpOp2->release(); + tmpAction->release(); + return NULL; + } else { + tmpOp->set(tmpVar, tmpOp2); + } + + tmpAction->set(tmpOp); + + } + + } else if ((tmpVar3 != NULL) && isNum(expression,afterEqualLoc,stringInd2-1)) { //number +/- variable + if (tmpVar3 == tmpVar) { + //final sign is += or -= + if (multiplierInt==1) { + strcpy(multiplier,"+="); + } else { + strcpy(multiplier,"-="); + } + + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + tmpOp->set(tmpVar, multiplier, atoi(expression+afterEqualLoc)); + } + tmpAction->set(tmpOp); + + } else { + + tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp2 == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + tmpOp2->set(tmpVar3, multiplier, atoi(expression+afterEqualLoc)); + } + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + + if (tmpOp == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpOp2->release(); + tmpAction->release(); + return NULL; + } else { + tmpOp->set(tmpVar, tmpOp2); + } + tmpAction->set(tmpOp); + + } + + } else if ((tmpVar2 != NULL) && (tmpVar3 != NULL)) { //variable +/- variable + + tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp2 == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + tmpOp2->set(tmpVar2, multiplier, tmpVar3); + } + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + + if (tmpOp == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpOp2->release(); + tmpAction->release(); + return NULL; + } else { + + tmpOp->set(tmpVar, tmpOp2); + } + tmpAction->set(tmpOp); + + } else if ( isNum(expression,stringInd2+1,lastCharLoc) && isNum(expression,afterEqualLoc,stringInd2-1) ) { //number +/- number + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + tmpOp->set(tmpVar, "=", atoi(expression+afterEqualLoc) + (multiplierInt * atoi(expression+stringInd2+1)) ); + } + tmpAction->set(tmpOp); + + } else if ((findStringLoc(expression,"random", afterEqualLoc,stringInd2-1)!=-1) && isNum(expression,stringInd2+1,lastCharLoc)) { //random +/- number + int highVal = getRandomParam(expression,afterEqualLoc,stringInd2-1); + + if (highVal > 0) { + + + tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp2 == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + tmpOp2->setRandOp(highVal, multiplier, atoi(expression+stringInd2+1),false); + } + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + + if (tmpOp == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpOp2->release(); + tmpAction->release(); + return NULL; + } else { + tmpOp->set(tmpVar, tmpOp2); + } + tmpAction->set(tmpOp); + + } else { + //delete tmpAction; + tmpAction->release(); + return NULL; + } + } else if ((findStringLoc(expression,"random",afterEqualLoc,stringInd2-1)!=-1) && (tmpVar3 != NULL)) { //random +/- variable + int highVal = getRandomParam(expression,afterEqualLoc,stringInd2-1); + + if (highVal > 0) { + + + tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp2 == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + tmpOp2->setRandOp(highVal, multiplier, tmpVar3, false); + } + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpOp2->release(); + tmpAction->release(); + return NULL; + } else { + tmpOp->set(tmpVar, tmpOp2); + } + tmpAction->set(tmpOp); + + } else { + //delete tmpAction; + tmpAction->release(); + return NULL; + } + + + } else if ((findStringLoc(expression,"random",stringInd2+1,lastCharLoc)!=-1) && isNum(expression,afterEqualLoc,stringInd2-1)) { //number +/- random + int highVal = getRandomParam(expression,stringInd2+1,lastCharLoc); + + if (highVal > 0) { + + + tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp2 == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + + tmpOp2->setRandOp(highVal, multiplier, atoi(expression+afterEqualLoc),true); //the "true" signifies that the rand value came last + } + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpOp2->release(); + tmpAction->release(); + return NULL; + } else { + tmpOp->set(tmpVar, tmpOp2); + } + tmpAction->set(tmpOp); + + } else { + //delete tmpAction; + tmpAction->release(); + return NULL; + } + } else if ((findStringLoc(expression,"random",stringInd2+1,lastCharLoc)!=-1) && (tmpVar2 != NULL)) { //variable +/- random + int highVal = getRandomParam(expression,stringInd2+1,lastCharLoc); + + if (highVal > 0) { + + + tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp2 == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + + tmpOp2->setRandOp(highVal, multiplier, tmpVar2, true); //the "true" signifies that the rand value came last + } + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpOp2->release(); + tmpAction->release(); + return NULL; + } else { + tmpOp->set(tmpVar, tmpOp2); + } + tmpAction->set(tmpOp); + + } else { + //delete tmpAction; + tmpAction->release(); + return NULL; + } + } + + + else if ((findStringLoc(expression,"clock()",afterEqualLoc,stringInd2-1)!=-1) && isNum(expression,stringInd2+1,lastCharLoc)) { //clock() +/- number + + tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp2 == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + tmpOp2->setClockOp(multiplier, atoi(expression+stringInd2+1),false); + } + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + + if (tmpOp == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpOp2->release(); + tmpAction->release(); + return NULL; + } else { + tmpOp->set(tmpVar, tmpOp2); + } + tmpAction->set(tmpOp); + + + } else if ((findStringLoc(expression,"clock()",afterEqualLoc,stringInd2-1)!=-1) && (tmpVar3 != NULL)) { //clock() +/- variable + + + + tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp2 == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + tmpOp2->setClockOp(multiplier, tmpVar3, false); + } + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpOp2->release(); + tmpAction->release(); + return NULL; + } else { + tmpOp->set(tmpVar, tmpOp2); + } + tmpAction->set(tmpOp); + + } else if ((findStringLoc(expression,"clock()",stringInd2+1,lastCharLoc)!=-1) && isNum(expression,afterEqualLoc,lastCharLoc)) { //number +/- clock() + + tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp2 == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + + tmpOp2->setClockOp(multiplier, atoi(expression+afterEqualLoc), true); //the "true" signifies that clock() came last + } + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpOp2->release(); + tmpAction->release(); + return NULL; + } else { + tmpOp->set(tmpVar, tmpOp2); + } + tmpAction->set(tmpOp); + + + } else if ((findStringLoc(expression,"clock()",stringInd2+1,lastCharLoc)!=-1) && (tmpVar2 != NULL)) { //variable +/- clock() + + + tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp2 == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + + tmpOp2->setClockOp(multiplier, tmpVar2, true); //the "true" signifies that clock() came last + } + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpOp2->release(); + tmpAction->release(); + return NULL; + } else { + tmpOp->set(tmpVar, tmpOp2); + } + tmpAction->set(tmpOp); + + + } + + else { + textDisplay << "Expression not understood: " << expression << "\r\n"; + //delete tmpAction; + tmpAction->release(); + return NULL; + } + + } else if (findIntVariable(expression,afterEqualLoc,lastCharLoc) != NULL) { //assign value of another variable + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + tmpOp->set(tmpVar, "=", findIntVariable(expression,afterEqualLoc,lastCharLoc)); + } + tmpAction->set(tmpOp); + + } else { + textDisplay << "Variable not found: " << expression+afterEqualLoc << "\r\n"; + tmpAction->release(); + return NULL; + } + + } else { + textDisplay << "Variable not found\r\n"; + tmpAction->release(); + return NULL; + } + textDisplay.debug("Assignment successful\r\n"); + return tmpAction; +} + +action* scriptStream::evaluateAssignmentForAction(string expression) { + + //action* tmpAction = new action(); //create a new action + action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS); + if (tmpAction == NULL) { + textDisplay << "Error: no action memory slots available.\r\n"; + return NULL; + } + std::size_t stringInd; + std::size_t stringInd2; + string afterEqual; + string beforeEqual; + //The expression might have up to three variables + int* tmpVar; + int* tmpVar2; + int* tmpVar3; + stringInd = expression.find_first_of("="); //location of = sign, if it exists + beforeEqual = expression.substr(0,stringInd); // the string after the = sign + afterEqual = expression.substr(stringInd+1,std::string::npos); // the string after the = sign + stringInd2 = afterEqual.find_first_of("+-"); //location of +/- sign (only one allowed) + tmpVar = findIntVariable(expression.substr(0,stringInd)); //returns pointer to the variable + + if (beforeEqual.find("portout[") != std::string::npos) { //set the output of a digital port + textDisplay.debug("Portout assignment\r\n"); + int pos1 = beforeEqual.find("portout[")+8; + int pos2 = beforeEqual.find_first_of("]",pos1); + int portnum = atoi(beforeEqual.substr(pos1,pos2-pos1).data()); + int* tmpVar = findIntVariable(beforeEqual.substr(pos1,pos2-pos1)); //returns pointer to the variable, if given + int portVal = 0; + if ((tmpVar != NULL)||((portnum > 0) && (portnum <= 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) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + //tmpMessage->setMessage(portVector[portnum],1,portVal); + if (tmpVar == NULL) { //a constant port number was given + tmpMessage->setMessage(NULL,portnum,portVal,portVector); + } else { + tmpMessage->setMessage(tmpVar,0,portVal,portVector); + } + } + + + tmpAction->set(tmpMessage); + + } else { + textDisplay << "Error: portouts can only be directly assigned a 1, 0 or 'flip'\r\n"; + //delete tmpAction; + tmpAction->release(); + return NULL; + } + } else if (afterEqual.compare("flip") == 0) { + //portMessage* tmpMessage = new portMessage(portVector[portnum],1,-1); + portMessage* tmpMessage = findFirstUnUsed(portMessageBlock, NUMPORTMESSAGES); + if (tmpMessage == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + //tmpMessage->setMessage(portVector[portnum],1,-1); + if (tmpVar == NULL) { //a constant port number was given + tmpMessage->setMessage(NULL,portnum,-1,portVector); + } else { + tmpMessage->setMessage(tmpVar,0,-1,portVector); + } + } + tmpAction->set(tmpMessage); + } else { + textDisplay << "Error: portouts can only be directly assigned a 1, 0, or 'flip'\r\n"; + //delete tmpAction; + tmpAction->release(); + return NULL; + } + } else { + textDisplay << "Port number not found (must be between 1 and " << numPorts << " or an existing variable)\r\n"; + //delete tmpAction; + tmpAction->release(); + return NULL; + } + } else if (beforeEqual.find("portin") != std::string::npos) { + textDisplay << "Error: portins can not be set\r\n"; + //delete tmpAction; + tmpAction->release(); + return NULL; + } else if (tmpVar != NULL) { + intOperation* tmpOp; + intOperation* tmpOp2; + if (isNumber(afterEqual)) { //a simple numeric assign + textDisplay.debug("Numeric assignment\r\n"); + //tmpOp = new intOperation(tmpVar, "=", atoi(afterEqual.data())); + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + tmpOp->set(tmpVar, "=", atoi(afterEqual.data())); + } + tmpAction->set(tmpOp); + + } else if ((stringInd2 == std::string::npos)&&(afterEqual.find("random") != std::string::npos)) { + //assign random number + //no +/- detected, so its a simple assign + textDisplay.debug("Random number assignment\r\n"); + int highVal = getRandomParam(afterEqual); + + if (highVal > 0) { + //tmpOp = new intOperation(highVal, "=", tmpVar); //for random assignment, we reverse the input order (because of overloading uniqueness) + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + tmpOp->setRandOp(highVal, "=", tmpVar, false); + } + tmpAction->set(tmpOp); + + } else { + //delete tmpAction; + tmpAction->release(); + return NULL; + } + } else if ((stringInd2 == std::string::npos)&&(afterEqual.find("clock()") != std::string::npos)) { + //assign clock value + //no +/- detected, so its a simple assign + textDisplay.debug("Clock assignment to variable\r\n"); + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + tmpOp->setClockOp(tmpVar); //assigns the current clock value to tmpVar + } + tmpAction->set(tmpOp); + + } else if (stringInd2 != std::string::npos) { //a +/- operation is there + textDisplay.debug("equation assignment\r\n"); + string multiplier("+"); + int multiplierInt = 1; + if (afterEqual[stringInd2] == '-') { + multiplier = "-"; + multiplierInt = -1; + } + tmpVar2 = findIntVariable(afterEqual.substr(0,stringInd2)); //before the +/- sign + tmpVar3 = findIntVariable(afterEqual.substr(stringInd2+1,std::string::npos)); //after the +/- sign + + if ((tmpVar2 != NULL) && isNumber(afterEqual.substr(stringInd2+1,std::string::npos))) { //variable +/- number + if (tmpVar2 == tmpVar) { + multiplier.append("="); //final sign is += or -= + //tmpOp = new intOperation(tmpVar, multiplier.data(), atoi(afterEqual.substr(stringInd2+1,std::string::npos).data())); + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + tmpOp->set(tmpVar, multiplier.data(), atoi(afterEqual.substr(stringInd2+1,std::string::npos).data())); + } + tmpAction->set(tmpOp); + + } else { + + tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp2 == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + + tmpOp2->set(tmpVar2,multiplier.data(), atoi(afterEqual.substr(stringInd2+1,std::string::npos).data())); + //tmpOp->set(tmpVar, tmpOp2); + } + + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpOp2->release(); + tmpAction->release(); + return NULL; + } else { + tmpOp->set(tmpVar, tmpOp2); + } + + tmpAction->set(tmpOp); + + } + + } else if ((tmpVar3 != NULL) && isNumber(afterEqual.substr(0,stringInd2))) { //number +/- variable + if (tmpVar3 == tmpVar) { + multiplier.append("="); //makes "+=" or "-=" + //tmpOp = new intOperation(tmpVar, multiplier.data(), atoi(afterEqual.substr(0,stringInd2).data())); + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + tmpOp->set(tmpVar, multiplier.data(), atoi(afterEqual.substr(0,stringInd2).data())); + } + tmpAction->set(tmpOp); + + } else { + + tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp2 == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + tmpOp2->set(tmpVar3, multiplier.data(), atoi(afterEqual.substr(0, stringInd2).data())); + } + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + + if (tmpOp == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpOp2->release(); + tmpAction->release(); + return NULL; + } else { + tmpOp->set(tmpVar, tmpOp2); + } + tmpAction->set(tmpOp); + + } + + } else if ((tmpVar2 != NULL) && (tmpVar3 != NULL)) { //variable +/- variable + + tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp2 == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + tmpOp2->set(tmpVar2, multiplier.data(), tmpVar3); + } + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + + if (tmpOp == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpOp2->release(); + tmpAction->release(); + return NULL; + } else { + + tmpOp->set(tmpVar, tmpOp2); + } + tmpAction->set(tmpOp); + + } else if ( isNumber(afterEqual.substr(stringInd2+1,std::string::npos)) && isNumber(afterEqual.substr(0,stringInd2)) ) { //number +/- number + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + tmpOp->set(tmpVar, "=", atoi(afterEqual.substr(0,stringInd2).data()) + (multiplierInt * atoi(afterEqual.substr(stringInd2+1,std::string::npos).data()))); + } + tmpAction->set(tmpOp); + + } else if ((afterEqual.substr(0,stringInd2).find("random") != std::string::npos) && isNumber(afterEqual.substr(stringInd2+1,std::string::npos))) { //random +/- number + int highVal = getRandomParam(afterEqual.substr(0,stringInd2)); + + if (highVal > 0) { + + + tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp2 == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + tmpOp2->setRandOp(highVal, multiplier.data(), atoi(afterEqual.substr(stringInd2+1,std::string::npos).data()),false); + } + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + + if (tmpOp == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpOp2->release(); + tmpAction->release(); + return NULL; + } else { + tmpOp->set(tmpVar, tmpOp2); + } + tmpAction->set(tmpOp); + + } else { + //delete tmpAction; + tmpAction->release(); + return NULL; + } + } else if ((afterEqual.substr(0,stringInd2).find("random") != std::string::npos) && (tmpVar3 != NULL)) { //random +/- variable + int highVal = getRandomParam(afterEqual.substr(0,stringInd2)); + + if (highVal > 0) { + + + tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp2 == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + tmpOp2->setRandOp(highVal, multiplier.data(), tmpVar3, false); + } + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpOp2->release(); + tmpAction->release(); + return NULL; + } else { + tmpOp->set(tmpVar, tmpOp2); + } + tmpAction->set(tmpOp); + + } else { + //delete tmpAction; + tmpAction->release(); + return NULL; + } + + + } else if ((afterEqual.substr(stringInd2+1,std::string::npos).find("random") != std::string::npos) && isNumber(afterEqual.substr(0,stringInd2))) { //number +/- random + int highVal = getRandomParam(afterEqual.substr(stringInd2+1,std::string::npos)); + + if (highVal > 0) { + + + tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp2 == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + + tmpOp2->setRandOp(highVal, multiplier.data(), atoi(afterEqual.substr(0, stringInd2).data()),true); //the "true" signifies that the rand value came last + } + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpOp2->release(); + tmpAction->release(); + return NULL; + } else { + tmpOp->set(tmpVar, tmpOp2); + } + tmpAction->set(tmpOp); + + } else { + //delete tmpAction; + tmpAction->release(); + return NULL; + } + } else if ((afterEqual.substr(stringInd2+1,std::string::npos).find("random") != std::string::npos) && (tmpVar2 != NULL)) { //variable +/- random + int highVal = getRandomParam(afterEqual.substr(stringInd2+1,std::string::npos)); + + if (highVal > 0) { + + + tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp2 == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + + tmpOp2->setRandOp(highVal, multiplier.data(), tmpVar2, true); //the "true" signifies that the rand value came last + } + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpOp2->release(); + tmpAction->release(); + return NULL; + } else { + tmpOp->set(tmpVar, tmpOp2); + } + tmpAction->set(tmpOp); + + } else { + //delete tmpAction; + tmpAction->release(); + return NULL; + } + } + + + + + + else if ((afterEqual.substr(0,stringInd2).find("clock()") != std::string::npos) && isNumber(afterEqual.substr(stringInd2+1,std::string::npos))) { //clock() +/- number + + + + tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp2 == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + tmpOp2->setClockOp(multiplier.data(), atoi(afterEqual.substr(stringInd2+1,std::string::npos).data()),false); + } + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + + if (tmpOp == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpOp2->release(); + tmpAction->release(); + return NULL; + } else { + tmpOp->set(tmpVar, tmpOp2); + } + tmpAction->set(tmpOp); + + + } else if ((afterEqual.substr(0,stringInd2).find("clock()") != std::string::npos) && (tmpVar3 != NULL)) { //clock() +/- variable + + + + tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp2 == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + tmpOp2->setClockOp(multiplier.data(), tmpVar3, false); + } + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpOp2->release(); + tmpAction->release(); + return NULL; + } else { + tmpOp->set(tmpVar, tmpOp2); + } + tmpAction->set(tmpOp); + + + + + } else if ((afterEqual.substr(stringInd2+1,std::string::npos).find("clock()") != std::string::npos) && isNumber(afterEqual.substr(0,stringInd2))) { //number +/- clock() + + + + tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp2 == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + + tmpOp2->setClockOp(multiplier.data(), atoi(afterEqual.substr(0, stringInd2).data()),true); //the "true" signifies that clock() came last + } + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpOp2->release(); + tmpAction->release(); + return NULL; + } else { + tmpOp->set(tmpVar, tmpOp2); + } + tmpAction->set(tmpOp); + + + } else if ((afterEqual.substr(stringInd2+1,std::string::npos).find("clock()") != std::string::npos) && (tmpVar2 != NULL)) { //variable +/- clock() + + + tmpOp2 = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp2 == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + + tmpOp2->setClockOp(multiplier.data(), tmpVar2, true); //the "true" signifies that clock() came last + } + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpOp2->release(); + tmpAction->release(); + return NULL; + } else { + tmpOp->set(tmpVar, tmpOp2); + } + tmpAction->set(tmpOp); + + + } + + else { + textDisplay << "Expression not understood: " << afterEqual << "\r\n"; + //delete tmpAction; + tmpAction->release(); + return NULL; + } + + } else if (findIntVariable(afterEqual) != NULL) { //assign value of another variable + //tmpOp = new intOperation(tmpVar, "=", findIntVariable(afterEqual)); + tmpOp = findFirstUnUsed(intOperationBlock, NUMINTOPERATIONS); + if (tmpOp == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + tmpAction->release(); + return NULL; + } else { + tmpOp->set(tmpVar, "=", findIntVariable(afterEqual)); + } + tmpAction->set(tmpOp); + + } else { + textDisplay << "Variable not found: " << afterEqual << "\r\n"; + //delete tmpAction; + tmpAction->release(); + return NULL; + } + + } else { + textDisplay << "Variable not found\r\n"; + //delete tmpAction; + tmpAction->release(); + return NULL; + } + textDisplay.debug("Assignment successful\r\n"); + return tmpAction; +} + +/* +bool scriptStream::isOutsideParenth(string& expression,std::size_t foundItem) { + + int pDepth = 0; // How many nested parentheses + + if (foundItem < expression.length()) { + for (int i = 0; i <= foundItem; i++) { + if (expression[i] == '(') { + pDepth++; + } else if (expression[i] == ')') { + pDepth--; + } + } + if (pDepth<=0) { + + return true; + } else { + + return false; + } + } else { + return true; + } + +} + +std::size_t scriptStream::findFirstOrOutsideParenth(string& expression) { + + std::size_t foundItem = expression.find("||"); + while (foundItem != std::string::npos) { + if (isOutsideParenth(expression,foundItem)) { + break; + } + foundItem = expression.find("||",foundItem+1); + } + return foundItem; +} + +std::size_t scriptStream::findFirstAndOutsideParenth(string& expression) { + + std::size_t foundItem = expression.find("&&"); + while (foundItem != std::string::npos) { + if (isOutsideParenth(expression,foundItem)){ + break; + } + foundItem = expression.find("&&",foundItem+1); + } + return foundItem; +} + +condition* scriptStream::parseConditions(string& expression) { + //This function is used to parse a condition string + //such as (x < y && x != z) || (y == 2) + //This function first identifies the root node of the logic tree + //based on operator precedence ( () > && > || ), and then recursively calls itself + //to find the nodes of the branches. The basic building blocks of + //the final condition object are arithmatic comparitors (a > b) and + //other condition objects. + + + + condition* newCondition = NULL; + bool singleCondition = false; //no compound conditions + string afterComparator; + string beforeComparator; + + std::size_t found; + + //To make a parse tree, we start by looking for operators with the lowest precendence + //so we look for OR conditions first + char currentOperator = OR_CONDITION; + + found = findFirstOrOutsideParenth(expression); + if (found==std::string::npos) { //no or conditions outside parentheses found, so we look for AND conditions + currentOperator = AND_CONDITION; + + found = findFirstAndOutsideParenth(expression); + } + if (found==std::string::npos) { //no or/and conditions outside parentheses found + //if the expression is encapsulated in parentheses, remove the parentheses + bool removedParenth = false; + if ((expression[0] == '(') && (expression[expression.length()-1] == ')')) { + + expression = expression.substr(1,expression.length()-2); + removedParenth = true; + } + if (removedParenth) { //we removed parentheses, so try again + textDisplay.debug("Condition: parenth removed\r\n"); + return parseConditions(expression); + } else { + singleCondition = true; //we assume that the condition is non-compound, i.e., a>b + } + } + + if (singleCondition) { //no compound conditions found + textDisplay.debug("Single condition: "); + std::size_t equalStringInd; + std::size_t greaterOrEqualStringInd; + std::size_t lessThanOrEqualStringInd; + std::size_t notEqualStringInd; + std::size_t greaterThanStringInd; + std::size_t lessThanStringInd; + std::size_t generalCompareStringInd; + + + string tmpCondition = expression; + string compareString; + //The expression might have up to three variables + int* tmpVar; + int* tmpVar2; + int* tmpVar3; + + int offset = 0; + equalStringInd = tmpCondition.find("=="); //location of comparator + greaterOrEqualStringInd = tmpCondition.find(">="); //location of comparator + lessThanOrEqualStringInd = tmpCondition.find("<="); //location of comparator + notEqualStringInd = tmpCondition.find("!="); //location of comparator + greaterThanStringInd = tmpCondition.find_first_of(">"); //location of comparator + lessThanStringInd = tmpCondition.find_first_of("<"); //location of comparator + + if ((equalStringInd != std::string::npos) && (greaterOrEqualStringInd == std::string::npos) && + (lessThanOrEqualStringInd == std::string::npos) && (notEqualStringInd == std::string::npos)){ + + generalCompareStringInd = equalStringInd; + compareString = "=="; + textDisplay.debug("==\r\n"); + } else if ((equalStringInd == std::string::npos) && (greaterOrEqualStringInd != std::string::npos) && + (lessThanOrEqualStringInd == std::string::npos) && (notEqualStringInd == std::string::npos)){ + + generalCompareStringInd = greaterOrEqualStringInd; + compareString = ">="; + textDisplay.debug(">=\r\n"); + } else if ((equalStringInd == std::string::npos) && (greaterOrEqualStringInd == std::string::npos) && + (lessThanOrEqualStringInd != std::string::npos) && (notEqualStringInd == std::string::npos)){ + + generalCompareStringInd = lessThanOrEqualStringInd; + compareString = "<="; + textDisplay.debug("<=\r\n"); + } else if ((equalStringInd == std::string::npos) && (greaterOrEqualStringInd == std::string::npos) && + (lessThanOrEqualStringInd == std::string::npos) && (notEqualStringInd != std::string::npos)){ + + generalCompareStringInd = notEqualStringInd; + compareString = "!="; + textDisplay.debug("!=\r\n"); + } else if ((equalStringInd == std::string::npos) && (greaterOrEqualStringInd == std::string::npos) && + (lessThanOrEqualStringInd == std::string::npos) && (notEqualStringInd == std::string::npos) && + (greaterThanStringInd != std::string::npos) && (lessThanStringInd == std::string::npos)){ + + generalCompareStringInd = greaterThanStringInd; + compareString = ">"; + offset = 1; + textDisplay.debug(">\r\n"); + } else if ((equalStringInd == std::string::npos) && (greaterOrEqualStringInd == std::string::npos) && + (lessThanOrEqualStringInd == std::string::npos) && (notEqualStringInd == std::string::npos) && + (greaterThanStringInd == std::string::npos) && (lessThanStringInd != std::string::npos)){ + + generalCompareStringInd = lessThanStringInd; + compareString = "<"; + offset = 1; + textDisplay.debug("<\r\n"); + + }else { + textDisplay << "Condition not understood: " << expression << "\r\n"; + return 0; + } + textDisplay.debug("Allocating memory for condition..."); + intCompare* newCompare = findFirstUnUsed(intCompareBlock, NUMINTCOMPARE); + + if (newCompare == NULL) { + textDisplay << "Error: No memory slots available."; + return NULL; + } + newCondition = findFirstUnUsed(conditionBlock, NUMCONDITIONS); + if (newCondition == NULL) { + textDisplay << "Error: No memory slots available."; + return NULL; + } + textDisplay.debug("success.\r\n"); + beforeComparator.reserve(tmpCondition.length()); + textDisplay << beforeComparator.capacity(); + textDisplay.flush(); + + afterComparator = tmpCondition.substr(generalCompareStringInd+2-offset,std::string::npos); + + beforeComparator = tmpCondition.substr(0,generalCompareStringInd); + + tmpVar = findIntVariable(beforeComparator); //returns pointer to the variable + if (tmpVar != NULL) { //before the comparator is a single variable + tmpVar2 = findIntVariable(afterComparator); //returns pointer to the variable + if (tmpVar2 != NULL) { //we are comapring a single variable to another + //intCompare* newCompare = new intCompare(tmpVar,compareString.data(),tmpVar2); + //currentEvent->addCondition(new condition(newCompare)); + textDisplay.debug("Compare variable to variable\r\n"); + newCompare->set(tmpVar,compareString.data(),tmpVar2); + newCondition->set(newCompare); + + + } else if (isNumber(afterComparator)) { + //intCompare* newCompare = new intCompare(tmpVar,compareString.data(),atoi(afterComparator.data())); + //currentEvent->addCondition(new condition(newCompare)); + textDisplay.debug("Compare variable to number\r\n"); + newCompare->set(tmpVar,compareString.data(),atoi(afterComparator.data())); + newCondition->set(newCompare); + + + } //more here + + } else { + textDisplay << "Condition not understood: " << expression << "\r\n"; + + return NULL; + } + + } else { //this is a compound condition (with either && or ||) + textDisplay.debug("Compound condition\r\n"); + afterComparator = expression.substr(found+2,std::string::npos); + beforeComparator = expression.substr(0,found); + newCondition = findFirstUnUsed(conditionBlock, NUMCONDITIONS); + if (newCondition == NULL) { + textDisplay << "Error: No memory slots available."; + return NULL; + } else { + newCondition->isUsed = true; //reserve the condition slot; + } + //recursively call this function to parse the sub conditions + condition* cond1 = parseConditions(beforeComparator); + if (cond1 == NULL) { + newCondition->release(); + return NULL; + } + condition* cond2 = parseConditions(afterComparator); + if (cond2 == NULL) { + newCondition->release(); + cond1->release(); + return NULL; + } + newCondition->set(cond1,currentOperator, cond2); + + } + + return newCondition; //all went well, so return the newly made condition + +}*/ + + +bool scriptStream::isOutsideParenth(const char* expression,int foundItem,int start, int end) { + + int pDepth = 0; // How many nested parentheses + + if ((foundItem >= start)&&(foundItem<=end)&&(foundItem < strlen(expression))&&(end < strlen(expression))&&(start <= end)&&(start>=0)) { + for (int i = start; i <= foundItem; i++) { + if (expression[i] == '(') { + pDepth++; + } else if (expression[i] == ')') { + pDepth--; + } + } + if (pDepth<=0) { + + return true; + } else { + + return false; + } + } else { + //error handling defaults in a true condition + return true; + } + +} + +int scriptStream::findFirstOrOutsideParenth(const char* expression,int start, int end) { + + int foundItem = findStringLoc(expression,"||",start,end); + while (foundItem != -1) { + if (isOutsideParenth(expression,foundItem,start,end)) { + //it's out side of () + break; + } + //not outside () + foundItem = findStringLoc(expression,"||",foundItem+1,end); + } + return foundItem; +} + +int scriptStream::findFirstAndOutsideParenth(const char* expression,int start, int end) { + + int foundItem = findStringLoc(expression,"&&",start,end); + while (foundItem != -1) { + if (isOutsideParenth(expression,foundItem,start,end)){ + break; + } + foundItem = findStringLoc(expression,"||",foundItem+1,end); + } + return foundItem; +} + + +condition* scriptStream::parseConditions(const char* expression,int start, int end) { + + + //This function is used to parse a condition string + //such as (x < y && x != z) || (y == 2) + //This function first identifies the root node of the logic tree + //based on operator precedence ( () > && > || ), and then recursively calls itself + //to find the nodes of the branches. The basic building blocks of + //the final condition object are arithmatic comparitors (a > b) and + //other condition objects. + + + + condition* newCondition = NULL; + bool singleCondition = false; //no compound conditions + //string afterComparator; + //string beforeComparator; + int afterComparatorLoc; + int beforeComparatorLoc; + + + + int found; + + //To make a parse tree, we start by looking for operators with the lowest precendence + //so we look for OR conditions first + char currentOperator = OR_CONDITION; + + found = findFirstOrOutsideParenth(expression,start,end); + if (found==-1) { //no or conditions outside parentheses found, so we look for AND conditions + currentOperator = AND_CONDITION; + + found = findFirstAndOutsideParenth(expression,start,end); + } + if (found==-1) { //no or/and conditions outside parentheses found + //if the expression is encapsulated in parentheses, remove the parentheses + bool removedParenth = false; + if ((expression[start] == '(') && (expression[end] == ')')) { + + start++; + end--; + + //expression = expression.substr(1,expression.length()-2); + removedParenth = true; + } + if (removedParenth) { //we removed parentheses, so try again + textDisplay.debug("Condition: parenth removed\r\n"); + return parseConditions(expression,start,end); + } else { + singleCondition = true; //we assume that the condition is non-compound, i.e., a>b + } + } + + if (singleCondition) { //no compound conditions found + textDisplay.debug("Single condition: "); + int equalStringInd; + int greaterOrEqualStringInd; + int lessThanOrEqualStringInd; + int notEqualStringInd; + int greaterThanStringInd; + int lessThanStringInd; + int generalCompareStringInd; + + + //string tmpCondition = expression; + char compareString[3]; + //The expression might have up to three variables + int* tmpVar; + int* tmpVar2; + //int* tmpVar3; + + int offset = 0; + equalStringInd = findStringLoc(expression,"==",start,end); //location of comparator + greaterOrEqualStringInd = findStringLoc(expression,">=",start,end); //location of comparator + lessThanOrEqualStringInd = findStringLoc(expression,"<=",start,end); //location of comparator + notEqualStringInd = findStringLoc(expression,"!=",start,end); //location of comparator + greaterThanStringInd = findStringLoc(expression,">",start,end); //location of comparator + lessThanStringInd = findStringLoc(expression,"<",start,end); //location of comparator + + if ((equalStringInd != -1) && (greaterOrEqualStringInd == -1) && + (lessThanOrEqualStringInd == -1) && (notEqualStringInd == -1)){ + + generalCompareStringInd = equalStringInd; + strcpy(compareString,"=="); + //compareString = "=="; + textDisplay.debug("==\r\n"); + } else if ((equalStringInd == -1) && (greaterOrEqualStringInd != -1) && + (lessThanOrEqualStringInd == -1) && (notEqualStringInd == -1)){ + + generalCompareStringInd = greaterOrEqualStringInd; + strcpy(compareString,">="); + //compareString = ">="; + textDisplay.debug(">=\r\n"); + } else if ((equalStringInd == -1) && (greaterOrEqualStringInd == -1) && + (lessThanOrEqualStringInd != -1) && (notEqualStringInd == -1)){ + + generalCompareStringInd = lessThanOrEqualStringInd; + strcpy(compareString,"<="); + //compareString = "<="; + textDisplay.debug("<=\r\n"); + } else if ((equalStringInd == -1) && (greaterOrEqualStringInd == -1) && + (lessThanOrEqualStringInd == -1) && (notEqualStringInd != -1)){ + + generalCompareStringInd = notEqualStringInd; + strcpy(compareString,"!="); + //compareString = "!="; + textDisplay.debug("!=\r\n"); + } else if ((equalStringInd == -1) && (greaterOrEqualStringInd == -1) && + (lessThanOrEqualStringInd == -1) && (notEqualStringInd == -1) && + (greaterThanStringInd != -1) && (lessThanStringInd == -1)){ + + generalCompareStringInd = greaterThanStringInd; + strcpy(compareString,">"); + //compareString = ">"; + offset = 1; + textDisplay.debug(">\r\n"); + } else if ((equalStringInd == -1) && (greaterOrEqualStringInd == -1) && + (lessThanOrEqualStringInd == -1) && (notEqualStringInd == -1) && + (greaterThanStringInd == -1) && (lessThanStringInd != -1)){ + + generalCompareStringInd = lessThanStringInd; + strcpy(compareString,"<"); + //compareString = "<"; + offset = 1; + textDisplay.debug("<\r\n"); + + }else { + textDisplay << "Condition not understood: " << expression << "\r\n"; + return 0; + } + textDisplay.debug("Allocating memory for condition..."); + intCompare* newCompare = findFirstUnUsed(intCompareBlock, NUMINTCOMPARE); + + if (newCompare == NULL) { + textDisplay << "Error: No memory slots available."; + return NULL; + } + newCondition = findFirstUnUsed(conditionBlock, NUMCONDITIONS); + if (newCondition == NULL) { + textDisplay << "Error: No memory slots available."; + return NULL; + } + textDisplay.debug("success.\r\n"); + //beforeComparator.reserve(tmpCondition.length()); + //textDisplay << beforeComparator.capacity(); + //textDisplay.flush(); + + afterComparatorLoc = generalCompareStringInd+2-offset; + beforeComparatorLoc = generalCompareStringInd-1; + + //afterComparator = tmpCondition.substr(generalCompareStringInd+2-offset,std::string::npos); + //beforeComparator = tmpCondition.substr(0,generalCompareStringInd); + + //tmpVar = findIntVariable(beforeComparator); //returns pointer to the variable + tmpVar = findIntVariable(expression,start,beforeComparatorLoc); + + if (tmpVar != NULL) { //before the comparator is a single variable + tmpVar2 = findIntVariable(expression, afterComparatorLoc, end); //returns pointer to the variable + if (tmpVar2 != NULL) { //we are comapring a single variable to another + //intCompare* newCompare = new intCompare(tmpVar,compareString.data(),tmpVar2); + //currentEvent->addCondition(new condition(newCompare)); + textDisplay.debug("Compare variable to variable\r\n"); + newCompare->set(tmpVar,compareString,tmpVar2); + newCondition->set(newCompare); + + + } else if (isNum(expression, afterComparatorLoc, end)) { + //intCompare* newCompare = new intCompare(tmpVar,compareString.data(),atoi(afterComparator.data())); + //currentEvent->addCondition(new condition(newCompare)); + textDisplay.debug("Compare variable to number\r\n"); + newCompare->set(tmpVar,compareString,atoi(expression+afterComparatorLoc)); + newCondition->set(newCompare); + + + } else { + textDisplay << "Condition not understood: " << expression << "\r\n"; + return NULL; + }//more here + + } else { + textDisplay << "Condition not understood: " << expression << "\r\n"; + + return NULL; + } + + } else { //this is a compound condition (with either && or ||) + textDisplay.debug("Compound condition\r\n"); + afterComparatorLoc = found+2; + beforeComparatorLoc = found-1; + //afterComparator = expression.substr(found+2,std::string::npos); + //beforeComparator = expression.substr(0,found); + newCondition = findFirstUnUsed(conditionBlock, NUMCONDITIONS); + if (newCondition == NULL) { + textDisplay << "Error: No memory slots available."; + return NULL; + } else { + newCondition->isUsed = true; //reserve the condition slot; + } + //recursively call this function to parse the sub conditions + condition* cond1 = parseConditions(expression,start,beforeComparatorLoc); + if (cond1 == NULL) { + newCondition->release(); + return NULL; + } + condition* cond2 = parseConditions(expression,afterComparatorLoc,end); + if (cond2 == NULL) { + newCondition->release(); + cond1->release(); + return NULL; + } + newCondition->set(cond1,currentOperator, cond2); + + } + + return newCondition; //all went well, so return the newly made condition + + +} + + + + +bool scriptStream::evaluateConditions(string& expression, event* currentEvent) { + //calls the function to parse the condition string. The condition pointer is then + //attached to the event + + condition* newCondition = NULL; + //newCondition = parseConditions(expression); + newCondition = parseConditions(expression.data(),0,expression.length()-1); + if (newCondition == NULL) { + return false; + } else { + currentEvent->addCondition(newCondition); + return true; + } +} + +int scriptStream::getRandomParam(const char* expression,int start, int end) { + + int pos1 = findStringLoc(expression,"random(",start,end)+7; + int pos2 = findStringLoc(expression,")",pos1,end); + if (pos2 == -1) { + textDisplay << "Error: bad syntax\r\n"; + return 0; + } + + int highVal = atoi(expression+pos1); + + if ((highVal > 0)) { + return highVal; + } else { + textDisplay << "Error: random parameter must be 1 or more\r\n"; + return 0; + } +} + +int scriptStream::getRandomParam(string expression) { + + int pos1 = expression.find("random(")+7; + int pos2 = expression.find_first_of(")",pos1); + int highVal = atoi(expression.substr(pos1,pos2-pos1).data()); + + if ((highVal > 0)) { + return highVal; + } else { + textDisplay << "Error: random parameter must be 1 or more\r\n"; + return 0; + } +} + +int scriptStream::findStringLoc(const char *refString, const char *findString,int start,int end) { + //look for 'findString' inside 'refString', only considering characters in between 'start' and 'end' + //return -1 if not found + + if ((start < strlen(refString))&&(end < strlen(refString))&&(end >= start)) { + const char* charPtr = strstr(refString+start,findString); + //if found, make sure it was containted within the start and end bounds + if ((charPtr != NULL) && ((int)(charPtr-refString) <= (end-strlen(findString)+1))) { + return (int)(charPtr-refString); + } + } + return -1; +} + +bool scriptStream::isNum(const char *expression, int start, int end) { + + if ((start>0)&&(end<strlen(expression))&&(start<=end)) { + + bool outcome = true; + while (start <= end) { + //look for any digit, or a - sign + if (!((expression[start] >= 45) && (expression[start] <= 57) && (expression[start] != 46) && (expression[start] != 47))) { + outcome = false; + break; + } + start++; + } + return outcome; + } + return false; +} + +bool scriptStream::areStringsSame(const char *str1, const char *str2, int start, int end) { + if ((findStringLoc(str1,str2,start,end) != -1) && (strlen(str2)==(end-start+1))) { + return true; + } else { + return false; + } + + +} +