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
behave.cpp
- Committer:
- mkarlsso
- Date:
- 2016-06-10
- Revision:
- 6:6a6761a47951
- Parent:
- 5:67d67d452545
- Child:
- 7:5fe7329751d4
File content as of revision 6:6a6761a47951:
#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; bool *ignoreUpdatePorts = hardware->getIgnoreUpdates(); uint32_t changeTime; timeKeeper = 0; //set main clock to 0; int bufferPos = 0; //ostringstream timeConvert; // stream used for the conversion //ostringstream stateConvert; int tmpChar; int junkChar; uint16_t shortcutTriggers[PENDINGTRIGGERBUFFERSIZE]; int numTriggersToProcess; while (pc->readable()) { junkChar = pc->readChar(); } #ifdef MBEDHARDWARE LocalFileSystem local("local"); FILE *fp = fopen("/local/STARTUP.TXT", "r"); if (fp != NULL) { textDisplay.send("Executing startup script...\r\n"); do { tmpChar = fgetc(fp); if ((tmpChar >= 32) && (tmpChar <= 126)) { buffer[bufferPos] = tmpChar; bufferPos++; } if ((tmpChar == 13) || (tmpChar == 10)) { //carrriage return parser->addLineToCurrentBlock(buffer); bufferPos = 0; eraseBuffer(); } //pc.putc(tmpChar); } while (tmpChar != EOF); buffer[bufferPos] = 59; parser->addLineToCurrentBlock(buffer); eraseBuffer(); fclose(fp); } else { textDisplay.send("No startup script found.\r\n"); } #endif //Get the initial state of all input pins for (int i = 0; i < 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()) { if (!ignoreUpdatePorts[i]) { //Only trigger an output update to the serial port if ignore is false digitalInChanged = true; } changeTime = min(changeTime,ports[i].lastChangeTime); //The input state of all the ports in condensed into one number (each bit contains the info) if (ports[i].getLastChangeState() == 1) { currentDIOstate[0] |= (1 << i); } else { currentDIOstate[0] &= ~(1 << i); } } if (ports[i].outStateChanged) { if (!ignoreUpdatePorts[i]) { //Only trigger an output update to the serial port if ignore is false digitalOutChanged = true; } changeTime = min(changeTime,ports[i].lastOutChangeTime); //The out state of all the ports is condensed into one number (each bit contains the info) if (ports[i].outState == 1) { currentDIOstate[1] |= (1 << i); } else { currentDIOstate[1] &= ~(1 << i); } ports[i].outStateChanged = false; } } //If anything changed, 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++) { textDisplay << "Trigger function " << shortcutTriggers[i]+1 << "\r\n"; if ((shortcutTriggers[i] < NUMTRIGGERACTIONS) && functionSpotTaken[shortcutTriggers[i]] && functionEventArray[i]->isUsed) { //textDisplay << "Executing function array index " << shortcutTriggers[i] << "\r\n"; functionEventArray[shortcutTriggers[i]]->execute(); } } } } void mainLoop::eraseBuffer() { for (int i = 0; i < 256; i++) { buffer[i] = NULL; } } //------------------------------------------------- //used to find the first available object in the staticly defined pools of memory template<class T> T* findFirstUnUsed(T a[], const int arrayLength) { T* returnPtr = NULL; for (int i = 0; i < arrayLength; i++) { if (!a[i].isUsed) { returnPtr = &a[i]; break; } } return returnPtr; } //used to count the number of available objects in the memory pool template<class T> int countUnUsed(T a[], const int arrayLength) { int count = 0; for (int i = 0; i < arrayLength; i++) { if (!a[i].isUsed) { count++; } } return count; } void displayMemoryLeft(void) { textDisplay << "Available slots left in memory\r\n"; textDisplay << " Blocks: " << countUnUsed(eventBlock, NUMEVENTS) << "\r\n"; textDisplay << " Condition containers: " << countUnUsed(conditionBlock, NUMCONDITIONS) << "\r\n"; textDisplay << " Int compare conditions: " << countUnUsed(intCompareBlock, NUMINTCOMPARE) << "\r\n"; textDisplay << " Command containers: " << countUnUsed(actionBlock, NUMACTIONS) << "\r\n"; textDisplay << " Port commands: "<< countUnUsed(portMessageBlock, NUMPORTMESSAGES) << "\r\n"; textDisplay << " Integer operater commands: " << countUnUsed(intOperationBlock, NUMINTOPERATIONS) << "\r\n"; textDisplay << " Text display commands: " << countUnUsed(displayActionBlock, NUMDISPLAYACTIONS) << "\r\n"; } bool isNumber(const std::string& s) { std::string::const_iterator it = s.begin(); while (it != s.end() && isdigit(*it)) ++it; return !s.empty() && it == s.end(); } void tokenize(const string& str, vector<string>& tokens, const string& delimiters = " ") { // Skip delimiters at beginning. string::size_type lastPos = str.find_first_not_of(delimiters, 0); // Find first "non-delimiter". string::size_type pos = str.find_first_of(delimiters, lastPos); while (string::npos != pos || string::npos != lastPos) { // Found a token, add it to the vector. tokens.push_back(str.substr(lastPos, pos - lastPos)); // Skip delimiters. Note the "not_of" lastPos = str.find_first_not_of(delimiters, pos); // Find next "non-delimiter" pos = str.find_first_of(delimiters, lastPos); } } digitalPort::digitalPort(): outPin(NULL), inPin(NULL), outState(0){ } void digitalPort::init(sDigitalOut *DOP, sDigitalIn *DIP) { outPin = DOP; inPin = DIP; lastInState = getDigitalIn(); inState = getDigitalIn(); lastChangeTime = 0; lastOutChangeTime = 0; lastChangeInterval = 0; triggerUpEventPtr = NULL; triggerDownEventPtr = NULL; outStateChanged = false; } void digitalPort::setTriggerUpEvent(event* eventInput) { if (triggerUpEventPtr != NULL) { //delete triggerUpEventPtr; triggerUpEventPtr->release(); } triggerUpEventPtr = eventInput; } void digitalPort::setTriggerDownEvent(event* eventInput) { if (triggerDownEventPtr != NULL) { //delete triggerDownEventPtr; triggerDownEventPtr->release(); } triggerDownEventPtr = eventInput; } int digitalPort::getDigitalIn() { return inPin->read(); } void digitalPort::setDigitalOut(int outVal) { if (outVal == -1) { outVal = 1-outState; } outPin->write(outVal); if (outState != outVal) { outStateChanged = true; lastOutChangeTime = timeKeeper; } outState = outVal; } //called when a digital in gets triggered /* void digitalPort::addStateChange(int newState, uint32_t timeStamp) { if ((newState == 0) && (!lastDownEvent.triggered)){ lastDownEvent.timeStamp = timeStamp; lastDownEvent.triggered = true; } else if ((newState == 1) && (!lastUpEvent.triggered)) { lastUpEvent.timeStamp = timeStamp; lastUpEvent.triggered = true; } }*/ bool digitalPort::update() { bool changed = false; bool execUp = false; bool execDown = false; if ((timeKeeper - lastChangeTime) > 1) { //prevents flutter triggers when button is pressed //changed = (lastInState != inState); inPin->setUpdate(true); //Once we get the state of the pin, we buffer any pin changes until we are done checking //Every ms, we first check if a hardware trigger occured //in the opposite direction of the last remembered state if (lastInState == 0) { changed = inPin->lastUpEvent.triggered; if (changed) inState = 1; } else if (lastInState == 1) { changed = inPin->lastDownEvent.triggered; if (changed) inState = 0; } //if not, then we read the pin state to see if it is different than the //remembered state. This is important in order to report both edges of a //fast up-down event. if (!changed) { inState = getDigitalIn(); changed = (lastInState != inState); } //changed = (inPin->lastUpEvent.triggered || inPin->lastDownEvent.triggered); if (changed) { if (inState == 1) { lastChangeInterval = inPin->lastUpEvent.timeStamp - lastChangeTime; lastChangeTime = inPin->lastUpEvent.timeStamp; if (triggerUpEventPtr != NULL && triggerUpEventPtr->isUsed) {triggerUpEventPtr->execute();} } else if (inState == 0) { lastChangeInterval = inPin->lastDownEvent.timeStamp - lastChangeTime; lastChangeTime = inPin->lastDownEvent.timeStamp; if (triggerDownEventPtr != NULL && triggerDownEventPtr->isUsed){triggerDownEventPtr->execute();} } //inPin->setUpdate(true); //Once we get the state of the pin, we buffer any pin changes until we are done checking //inState = getDigitalIn(); //We need to ignore flutter when levers/beam breaks are triggered. So //if the current state if different than the last logged state, we only //consider the first edge that brough us to the current state /* if (lastInState != inState) { if (inState == 1) { lastChangeInterval = inPin->lastUpEvent.timeStamp - lastChangeTime; lastChangeTime = inPin->lastUpEvent.timeStamp; if (triggerUpEventPtr != NULL && triggerUpEventPtr->isUsed) {triggerUpEventPtr->execute();} } else if (inState == 0) { lastChangeInterval = inPin->lastDownEvent.timeStamp - lastChangeTime; lastChangeTime = inPin->lastDownEvent.timeStamp; if (triggerDownEventPtr != NULL && triggerDownEventPtr->isUsed){triggerDownEventPtr->execute();} } } else if (lastInState == inState) { //Both up and down triggers must have happened, so we consider both if (inState == 1) { lastChangeInterval = inPin->lastUpEvent.timeStamp - inPin->lastDownEvent.timeStamp; lastChangeTime = inPin->lastUpEvent.timeStamp; if (triggerDownEventPtr != NULL && triggerDownEventPtr->isUsed) {triggerDownEventPtr->execute();} if (triggerUpEventPtr != NULL && triggerUpEventPtr->isUsed) {triggerUpEventPtr->execute();} } else if (inState == 0) { lastChangeInterval = inPin->lastDownEvent.timeStamp - inPin->lastUpEvent.timeStamp; lastChangeTime = inPin->lastDownEvent.timeStamp; if (triggerUpEventPtr != NULL && triggerUpEventPtr->isUsed) {triggerUpEventPtr->execute();} if (triggerDownEventPtr != NULL && triggerDownEventPtr->isUsed) {triggerDownEventPtr->execute();} } } */ lastInState = inState; inPin->lastUpEvent.triggered = false; inPin->lastDownEvent.triggered = false; //inPin->setUpdate(false); //This also checks if there were any buffered changes that occured } inPin->setUpdate(false); //This also checks if there were any buffered changes that occured } return changed; } int digitalPort::getLastChangeState() { return lastInState; } uint32_t digitalPort::getTimeSinceLastChange() { return lastChangeInterval; } intVariable::intVariable(): value(0) { isUsed = false; } intVariable::intVariable(std::string& tagInput, int initialValue): value(initialValue) { strncpy(tag,tagInput.data(),MAXVARNAMESIZE); isUsed = true; } void intVariable::set(std::string& tagInput, int initialValue) { value = initialValue; //tag = string(tagInput); strncpy(tag,tagInput.data(),MAXVARNAMESIZE); isUsed = true; } displayAction::displayAction(): dText(string("--------------------------------------------------")){ dVariable = NULL; isUsed = false; } void displayAction::release() { dText = "--------------------------------------------------"; dVariable = NULL; isUsed = false; } void displayAction::set(int* variable, string varNameInput) { dVariable = variable; dText = varNameInput; isUsed = true; } void displayAction::set(string text) { dText = text; dVariable = NULL; isUsed = true; } void displayAction::execute() { if (dVariable != NULL) { textDisplay << timeKeeper << " " << dText.c_str() << " = " << *dVariable << "\r\n"; } else { textDisplay << timeKeeper << " " << dText.c_str() << "\r\n"; } } triggerFunctionAction::triggerFunctionAction(): functionNum(0) { isUsed = false; } triggerFunctionAction::triggerFunctionAction(int funcNum): functionNum(funcNum) { isUsed = true; } void triggerFunctionAction::set(int funcNum) { functionNum = funcNum; isUsed = true; } void triggerFunctionAction::execute() { if (functionSpotTaken[functionNum] && functionEventArray[functionNum]->isUsed) { functionEventArray[functionNum]->execute(); } } void triggerFunctionAction::release() { isUsed = false; } intCompare::intCompare(): port(NULL) { cmpVal = NULL; cmpValGlobal = false; intVal = NULL; intOp = NULL; portValPtr = NULL; isUsed = false; } intCompare::intCompare(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() { tmpEvent = NULL; lineError = false; blockDepth = 0; ifBlockInit = false; whileBlockInit = false; expectingDoStatement = false; elseFlag = false; thenFlag = false; currentDelay = 0; std::size_t stringInd = 0; bool wholeLineEvaluated = false; while (!currentBlock.empty()) { wholeLineEvaluated = false; //tmpLine = currentBlock.back(); tmpLine = currentBlock.getNextLine(); lineError = false; //remove tabs std::size_t found = tmpLine.find_first_of(9); //tab while (found!=std::string::npos) { tmpLine[found]= ' '; found=tmpLine.find_first_of(9,found+1); } found = tmpLine.find_first_of(37); //% for commenting if (found!=std::string::npos) { for (int p=found; p<tmpLine.size() ;p++) { tmpLine[p]= ' '; } } //break up the line into tokens separated by spaces tokenize(tmpLine,tokens," ;"); std::vector<string>::size_type sz = tokens.size(); for (unsigned i = 0; i < sz; i++) { //end statement signals the end of a block----------------------------------------- if (tokens[i].compare("end") == 0) { //ends the current block if (ifBlockInit || whileBlockInit || expectingDoStatement) { textDisplay << "Error: expected a 'do' statement\r\n"; lineError = true; } ifBlockInit = false; whileBlockInit = false; expectingDoStatement = false; elseFlag = false; if (blockDepth > 0) { textDisplay.debug("End statement\r\n"); if (blockDepth == 1) { currentTriggerPort = -1; currentFunction = -1; blockDepth = 0; } else if (blockDepth > 1) { blockDepth = blockDepth - 1; } while ((tmpEventPtrArray.back()->blockType == 3) || (tmpEventPtrArray.back()->blockType == 4) || (tmpEventPtrArray.back()->blockType == 6) || (tmpEventPtrArray.back()->blockType == 7) || (tmpEventPtrArray.back()->blockType == 8)){ tmpEventPtrArray.pop_back(); //recursively remove the pointers to all else blocks } tmpEventPtrArray.pop_back(); //remove the pointer to the finished block } else { textDisplay << "Error: End statement without block\r\n"; lineError = true; } //sound statement used to play wave files------------------------------------------------ //example: sound('soundfile') // sound(stop) } else if (tokens[i].find("sound(") != std::string::npos) { if (ifBlockInit || whileBlockInit || elseFlag || expectingDoStatement) { textDisplay << "Error: expected a 'do' statement\r\n"; lineError = true; } wholeLineEvaluated = true; int pos1 = tmpLine.find("sound(")+6; int pos2 = tmpLine.find_first_of(")",pos1); if (pos2 == std::string::npos) { textDisplay << "Syntax error: expected a ')'\r\n"; lineError = true; } if (!lineError) { string dispVar = tmpLine.substr(pos1,pos2-pos1); int* tmpVar = findIntVariable(dispVar); bool isText = false; bool stopSignal = false; bool resetSignal = false; if (tmpVar == NULL) { if ((tmpLine.compare(pos1,1,"'")==0) && (tmpLine.compare(pos2-1,1,"'")==0)) { isText = true; } else if (dispVar.compare("stop") == 0) { stopSignal = true; } else if (dispVar.compare("reset") == 0) { resetSignal = true; } else { textDisplay << "Error: variable input to sound() does not exist\r\n"; lineError = true; } } action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS); if (tmpAction == NULL) { textDisplay << "Error: no memory slots available.\r\n"; lineError = true; } if (!lineError && (blockDepth == 0)) { //we are not inside a block structure, so play sound now if (stopSignal) { sSound* S = system->createNewSoundAction(); S->setPlayback(false); S->execute(); delete S; } else if (resetSignal) { sSound* S = system->createNewSoundAction(); S->setReset(); S->execute(); delete S; } else if (isText) { if (pos2-pos1-2 <= 20) { sSound* S = system->createNewSoundAction(); S->setFile(tmpLine.substr(pos1+1,pos2-pos1-2)); S->execute(); delete S; } else { textDisplay << "Error: sound file names must be 20 characters or less.\r\n"; lineError = true; } } else { textDisplay << "Error: variable input to sound() not yet supported. Enter a string in single quotes.\r\n"; lineError = true; } } else if (!lineError && (blockDepth > 0) ){ //the disp function was put inside a block textDisplay.debug("Sound statement\r\n"); if (stopSignal) { sSound* sPtr = system->createNewSoundAction(); sPtr->setPlayback(false); //action* tmpAction = new action(sPtr); tmpAction->set(sPtr); tmpEventPtrArray.back()->addAction(tmpAction); } else if (resetSignal) { sSound* sPtr = system->createNewSoundAction(); sPtr->setReset(); //action* tmpAction = new action(sPtr); tmpAction->set(sPtr); tmpEventPtrArray.back()->addAction(tmpAction); } else if (isText) { if (pos2-pos1-2 <= 20) { sSound* sPtr = system->createNewSoundAction(); sPtr->setFile(tmpLine.substr(pos1+1,pos2-pos1-2)); //action* tmpAction = new action(sPtr); tmpAction->set(sPtr); tmpEventPtrArray.back()->addAction(tmpAction); } else { textDisplay << "Error: sound file names must be 20 characters or less.\r\n"; lineError = true; } } else { textDisplay << "Error: variable input to sound() not yet supported. Enter a string in single quotes.\r\n"; lineError = true; } } } } else if (tokens[i].find("volume(") != std::string::npos) { if (ifBlockInit || whileBlockInit || elseFlag || expectingDoStatement) { textDisplay << "Error: expected a 'do' statement\r\n"; lineError = true; } wholeLineEvaluated = true; int pos1 = tmpLine.find("volume(")+7; int pos2 = tmpLine.find_first_of(")",pos1); if (pos2 == std::string::npos) { textDisplay << "Syntax error: expected a ')'\r\n"; lineError = true; } if (!lineError) { string dispVar = tmpLine.substr(pos1,pos2-pos1); int* tmpVar = findIntVariable(dispVar); bool isText = false; if (tmpVar == NULL) { if (isNumber(dispVar)) { isText = true; } else { textDisplay << "Error: variable input to volume() does not exist\r\n"; lineError = true; } } action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS); if (tmpAction == NULL) { textDisplay << "Error: no memory slots available.\r\n"; lineError = true; } if (!lineError && (blockDepth == 0)) { //we are not inside a block structure, so play sound now if (isText) { int newVolume = atoi(dispVar.data()); if ((newVolume >=0)&&(newVolume <= 255)) { sSound* S = system->createNewSoundAction(); S->setVolume(newVolume); S->execute(); delete S; } else { textDisplay << "Error: sound volume must be between 0 and 255 .\r\n"; lineError = true; } } else { sSound* S = system->createNewSoundAction(); S->setVolume(tmpVar); S->execute(); delete S; } } else if (!lineError && (blockDepth > 0) ){ //the disp function was put inside a block textDisplay.debug("Volume statement\r\n"); if (isText) { int newVolume = atoi(dispVar.data()); sSound* sPtr = system->createNewSoundAction(); sPtr->setVolume(newVolume); //action* tmpAction = new action(sPtr); tmpAction->set(sPtr); tmpEventPtrArray.back()->addAction(tmpAction); } else { sSound* sPtr = system->createNewSoundAction(); sPtr->setVolume(tmpVar); //action* tmpAction = new action(sPtr); tmpAction->set(sPtr); tmpEventPtrArray.back()->addAction(tmpAction); } } } //clock statement used to is used to control the clock------------------------- //example: clock(reset); clock(slave); clock(standalone) } else if (tokens[i].find("clock(") != std::string::npos) { //clock commands if (ifBlockInit || whileBlockInit || elseFlag || expectingDoStatement) { textDisplay << "Error: expected a 'do' statement\r\n"; lineError = true; } if (blockDepth > 0) { textDisplay << "Error: clock commands only allowed outside of block structure\r\n"; lineError = true; } int pos1 = tmpLine.find("clock(")+6; int pos2 = tmpLine.find_first_of(")",pos1); if (pos2 == std::string::npos) { textDisplay << "Syntax Error: expected a ')'\r\n"; lineError = true; } if (!lineError) { //int pos1 = tmpLine.find("clock(")+6; //int pos2 = tmpLine.find_first_of(")",pos1); string dispVar = tmpLine.substr(pos1,pos2-pos1); if (blockDepth == 0) { if (dispVar.compare("reset") == 0) { resetTimer = true; queuePtr->eraseQueue(); textDisplay.send(string("Clock reset to 0\r\n")); } else if (dispVar.compare("slave") == 0) { if (!clockSlave) { changeToSlave = true; textDisplay.send(string("Slave mode\r\n")); } } else if (dispVar.compare("standalone") == 0) { if (clockSlave) { changeToStandAlone = true; textDisplay.send(string("Standalone mode\r\n")); } } else if (dispVar.compare("") == 0) { //The user needs the current time displayed. //textDisplay.send(string("Current Clock\r\n")); textDisplay << timeKeeper << " current time\r\n"; } else { textDisplay << "Error: Clock control statement not understood\r\n"; lineError = true; } } } //disp command used to display text via serial--------------------------------------- //example: disp('hello'); disp(myVar) } else if (tokens[i].find("disp(") != std::string::npos) { //display value of variable if (ifBlockInit || whileBlockInit || elseFlag || expectingDoStatement) { textDisplay <<"Error: expected a 'do' statement\r\n"; lineError = true; } //int pos1 = tokens[i].find("disp(")+5; //int pos2 = tokens[i].find_first_of(")",pos1); //string dispVar = tokens[i].substr(pos1,pos2-pos1); wholeLineEvaluated = true; int pos1 = tmpLine.find("disp(")+5; int pos2 = tmpLine.find_first_of(")",pos1); if (pos2 == std::string::npos) { textDisplay <<"Syntax error: expected a ')'\r\n"; lineError = true; } if (!lineError) { string dispVar = tmpLine.substr(pos1,pos2-pos1); int* tmpVar = findIntVariable(dispVar); bool isText = false; if (tmpVar == NULL) { if ((tmpLine.compare(pos1,1,"'")==0) && (tmpLine.compare(pos2-1,1,"'")==0)) { isText = true; } else { textDisplay << "Error: variable to display does not exist\r\n"; lineError = true; } } displayAction* dPtr = findFirstUnUsed(displayActionBlock, NUMDISPLAYACTIONS); if (dPtr == NULL) { textDisplay << "Error: no memory slots available.\r\n"; lineError = true; } if (!lineError && (blockDepth == 0)) { //we are not inside a block structure, so display now if (isText) { //displayAction* dPtr = new displayAction(tmpLine.substr(pos1+1,pos2-pos1-2), pcPtr); dPtr->set(tmpLine.substr(pos1+1,pos2-pos1-2)); dPtr->execute(); //delete dPtr; dPtr->release(); } else { //displayAction* dPtr = new displayAction(tmpVar, dispVar, pcPtr); dPtr->set(tmpVar, dispVar); dPtr->execute(); //delete dPtr; dPtr->release(); } } else if (!lineError && (blockDepth > 0) ){ //the disp function was put inside a block textDisplay.debug("Display statement\r\n"); action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS); if (tmpAction == NULL) { textDisplay <<"Error: no memory slots available.\r\n"; lineError = true; } if (!lineError && isText) { //displayAction* dPtr = new displayAction(tmpLine.substr(pos1+1,pos2-pos1-2), pcPtr); dPtr->set(tmpLine.substr(pos1+1,pos2-pos1-2)); tmpAction->set(dPtr); //action* tmpAction = new action(dPtr); tmpEventPtrArray.back()->addAction(tmpAction); } else if (!lineError) { //displayAction* dPtr = new displayAction(tmpVar, dispVar, pcPtr); dPtr->set(tmpVar, dispVar); tmpAction->set(dPtr); //action* tmpAction = new action(dPtr); tmpEventPtrArray.back()->addAction(tmpAction); } } } //---------------------------------------------- //The trigger command is used like this: //trigger(n) //Where n is an integer corresponding to a "function n" block //When "trigger" is called, the corresponding function is executed. } else if (tokens[i].find("trigger(") != std::string::npos) { //trigger a function if (ifBlockInit || whileBlockInit || elseFlag || expectingDoStatement) { textDisplay << "Error: expected a 'do' statement\r\n"; lineError = true; } wholeLineEvaluated = true; int pos1 = tmpLine.find("trigger(")+8; int pos2 = tmpLine.find_first_of(")",pos1); if (pos2 == std::string::npos) { textDisplay << "Syntax error: expected a ')'\r\n"; lineError = true; } if (!lineError) { int funcNum = atoi(tmpLine.substr(pos1,pos2-pos1).data()); if ((funcNum > 0) && (funcNum < NUMFUNCTIONS+1)) { if (functionSpotTaken[funcNum-1] && functionEventArray[funcNum]->isUsed) { } else { textDisplay << "Error: function number does not exist\r\n"; lineError = true; } } else { textDisplay << "Error: not a valid function number\r\n"; lineError = true; } funcNum--; //change to 0-based index if (!lineError && (blockDepth == 0)) { //we are not inside a block structure, so execute function now //textDisplay << "Exectuting function"; //textDisplay.flush(); functionEventArray[funcNum]->execute(); } else if (!lineError && (blockDepth > 0) ){ //the trigger function was put inside a block, so we need to create a new action textDisplay.debug("Trigger statement\r\n"); triggerFunctionAction* tPtr = findFirstUnUsed(triggerFunctionActionBlock, NUMTRIGGERACTIONS); if (tPtr == NULL) { textDisplay << "Error: no memory slots available.\r\n"; lineError = true; } if (!lineError) { //we only give provide it the function number, instead //of a pointer to the event. That way, if the user modifies //the function (which would change the pointer), all callbacks //still using that function number will use the new function. tPtr->set(funcNum); action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS); if (tmpAction == NULL) { textDisplay << "Error: no memory slots available.\r\n"; lineError = true; } if (!lineError) { tmpAction->set(tPtr); tmpEventPtrArray.back()->addAction(tmpAction); } } } } //int is used to decalar new variables. Only allowed outside of callbacks------------------- //example: int a; int b = 9 } else if (tokens[i].compare("int") == 0) { //define a new integer variable textDisplay.debug("Int statement\r\n"); if (ifBlockInit || whileBlockInit || expectingDoStatement) { textDisplay << "Error: expected a 'do' statement\r\n"; lineError = true; } tmpString = ""; wholeLineEvaluated = true; int spacesBeforeEqualSign = 0; bool countSpaces = true; //combine the tokens without whitespaces for (unsigned j = i+1; j < sz; j++) { tmpString.append(tokens[j]); if (tokens[j].find_first_of("=") != std::string::npos) { if (tokens[j].find_first_of("=") > 0) spacesBeforeEqualSign++; countSpaces = false; } else if (countSpaces) { spacesBeforeEqualSign++; } } if (blockDepth > 0) { textDisplay << "Error: Variables can only be first declared outside of callbacks.\r\n"; lineError = true; } if ((!lineError) && (spacesBeforeEqualSign > 1)) { textDisplay << "Error: Variable can't have a space in it.\r\n"; lineError = true; } stringInd = tmpString.find_first_of("="); bool variableCreated = false; if (!lineError) { if (((stringInd == std::string::npos) && (sz == 2)) || (stringInd != std::string::npos)) { if ((stringInd != std::string::npos) && (stringInd > MAXVARNAMESIZE)) { textDisplay << "Error: variable names must be under 30 characters.\r\n"; lineError = true; } else if (createIntVariable(tmpString.substr(0,stringInd))) { textDisplay.debug("Created new variable\r\n"); variableCreated = true; } else { textDisplay.debug("Attempting to use existing variable\r\n"); int* tmpVar = findIntVariable(tmpString.substr(0,stringInd)); *tmpVar = 0; //lineError = true; } } else { textDisplay << "Error: variable declaration not understood.\r\n"; lineError = true; } } if ((!lineError) && (stringInd != std::string::npos)) { //evaluate the expression //action* tmpAction = evaluateAssignmentForAction(tmpString); action* tmpAction = evaluateAssignmentForAction(tmpString.data()); if (tmpAction != NULL) { tmpAction->execute(); //delete tmpAction; tmpAction->release(); } else { lineError = true; if (variableCreated) { delete globalVariables.back(); globalVariables.pop_back(); } } } //serial command is used to toggle whether or not to buffer up output text---------------- //examples: serial buffer; serial send } else if (tokens[i].compare("serial") == 0) { if (ifBlockInit || whileBlockInit || elseFlag || expectingDoStatement) { textDisplay << "Error: expected a 'do' statement\r\n"; lineError = true; } bool stream = true; if ((!lineError)&&(i+1 < sz)){ if (tokens[i+1].compare("buffer") == 0) { stream = false; } else if (tokens[i+1].compare("send") == 0) { stream = true; } else { textDisplay << "Error: 'serial' useage: 'serial buffer' or 'serial send'\r\n"; lineError = true; } } i++; if ((!lineError) && (blockDepth == 0)) { if (stream) { textStreaming = true; } else { textStreaming = false; } } else if ((!lineError) && (blockDepth > 0)) { if (stream) { //action* tmpAction = new action(1); //code 1 = turn on text streaming action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS); if (tmpAction == NULL) { textDisplay << "Error: no memory slots available.\r\n"; lineError = true; } else { tmpAction->set(1); tmpEventPtrArray.back()->addAction(tmpAction); } } else { //action* tmpAction = new action(2); //code 2 = turn on text buffering action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS); if (tmpAction == NULL) { textDisplay << "Error: no memory slots available.\r\n"; lineError = true; } else { tmpAction->set(2); tmpEventPtrArray.back()->addAction(tmpAction); } } } //updates command toggles the DIO update messages upon a change------------------ //examples: updates on; updates off //examples: updates on 3; updates off 3 } else if (tokens[i].compare("updates") == 0) { if (ifBlockInit || whileBlockInit || elseFlag || expectingDoStatement) { textDisplay << "Error: expected a 'do' statement\r\n"; lineError = true; } bool stream = true; int specifiedPort = -1; if ((!lineError)&&(i+1 < sz)){ if (tokens[i+1].compare("on") == 0) { stream = true; } else if (tokens[i+1].compare("off") == 0) { stream = false; } else { textDisplay << "Error: 'updates' useage: 'updates on' or 'updates off'\r\n"; lineError = true; } } if ((!lineError) && (i+2 < sz)) { //There is a port specified //int pos1 = tmpLine.find("trigger(")+8; //int pos2 = tmpLine.find_first_of(")",pos1); int tempPort = atoi(tokens[i+2].data()); if (tempPort > 0) { specifiedPort = tempPort-1; } else { textDisplay << "Error: 'updates' useage: 'updates on [port]' or 'updates off [port]'\r\n"; lineError = true; } i++; } i++; if ((!lineError) && (blockDepth == 0)) { if (stream) { //applies to all; broadCastStateChanges = true; if (specifiedPort > -1) { system->setPortUpdatesOn(specifiedPort); } else { for (int i=0;i<NUMPORTS;i++) { system->setPortUpdatesOn(i); } } } else { if (specifiedPort > -1) { system->setPortUpdatesOff(specifiedPort); } else { //applies to all //broadCastStateChanges = false; for (int i=0;i<NUMPORTS;i++) { system->setPortUpdatesOff(i); } } } } else if ((!lineError) && (blockDepth > 0)) { //Inside a block-- current no support here to specify a port if (stream) { //action* tmpAction = new action(3); //code 3 = turn on updates action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS); if (tmpAction == NULL) { textDisplay << "Error: no memory slots available.\r\n"; lineError = true; } else { tmpAction->set(3); tmpEventPtrArray.back()->addAction(tmpAction); } } else { //action* tmpAction = new action(4); //code 4 = turn off updates action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS); if (tmpAction == NULL) { textDisplay << "Error: no memory slots available.\r\n"; lineError = true; } else { tmpAction->set(4); tmpEventPtrArray.back()->addAction(tmpAction); } } } } else if (tokens[i].compare("memory") == 0) { if (ifBlockInit || whileBlockInit || elseFlag || expectingDoStatement) { textDisplay << "Error: expected a 'do' statement\r\n"; lineError = true; } if ((!lineError) && (blockDepth > 0)) { textDisplay << "Error: memory statement is not allowed inside a block.\r\n"; lineError = true; } if (!lineError) { displayMemoryLeft(); } //clear is used to clear things from memory--------------------------------- //examples: clear all; clear callbacks; clear queue } else if (tokens[i].compare("clear") == 0) { //delete all created events and variables if (ifBlockInit || whileBlockInit || elseFlag || expectingDoStatement) { textDisplay << "Error: expected a 'do' statement\r\n"; lineError = true; } int clearMode = 0; if ((!lineError)&&(i+1 < sz)){ if (tokens[i+1].compare("all") == 0) { clearMode = 1; } else if (tokens[i+1].compare("blocks") == 0) { clearMode = 2; } else if (tokens[i+1].compare("queue") == 0) { clearMode = 3; } else { textDisplay << "Error: clear what: all, blocks, or queue? \r\n"; lineError = true; } } else { textDisplay << "Error: clear what: all, blocks, or queue? \r\n"; lineError = true; } if ((!lineError) && (clearMode < 3) && (blockDepth > 0)) { textDisplay << "Error: 'clear all' and 'clear blocks' only allowed outside of block structures\r\n"; lineError = true; } if (!lineError) { //i++; //clear variables if (clearMode == 1) { //Clears everything int sendClearMode = 0; sendClearMode |= BLOCKMEMORYTYPES; sendClearMode |= VARIABLEMEMORYTYPES; sendClearMode |= ENVSETTINGSMEMORYTYPES; clearEnvironmentVariables(sendClearMode); } else if (clearMode == 2) { //Clear just varaibles int sendClearMode = 0; sendClearMode |= VARIABLEMEMORYTYPES; clearEnvironmentVariables(sendClearMode); } else if (clearMode == 3) { //Clear the current event queue (can itself be a queued action) if (blockDepth > 0) { //we are inside a block action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS); if (tmpAction == NULL) { textDisplay << "Error: no memory slots available.\r\n"; lineError = true; } else { int8_t code = 0; tmpAction->set(code); //action* tmpAction = new action(code); //code 0 = clear queue tmpEventPtrArray.back()->addAction(tmpAction); } } else { //clear queue now queuePtr->eraseQueue(); } } wholeLineEvaluated = true; } //do starts a block--------------------------------------------------------- //example: do in 500 // ... // end } else if (tokens[i].compare("do") == 0) { //the start of a block if (!ifBlockInit && !whileBlockInit) { if ((currentTriggerPort > 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) { textDisplay.flush(); break; //stop parsing the rest of the line if an error was detected } if (wholeLineEvaluated) { //some of the tokens forces the whole line to be avaluated at once i = sz; //skip ahead to end of the line } } //if there was an error, we quit compiling the code if (lineError) { textDisplay << "Line text: "; /* while (!tokens.empty()) { textDisplay << tokens.front()<< " "; //tokens.erase(tokens.begin()); }*/ //Display the line with the syntax error for (int tokInd = 0; tokInd < tokens.size(); tokInd++) { textDisplay << tokens.at(tokInd) << " "; } textDisplay << "\r\n"; textDisplay.flush(); currentBlock.resetBuffer(); //Clear the line tokens while (!tokens.empty()) { tokens.pop_back(); } if (tmpEventPtrArray.size() > 0) { tmpEventPtrArray.at(0)->release(); //release the unfinished block (and all children) } while (tmpEventPtrArray.size() > 0){ tmpEventPtrArray.pop_back(); } //delete tmpEvent; /* if (tmpEvent != NULL) { tmpEvent->release(); } */ } else { //Clear the line tokens while (!tokens.empty()) { tokens.pop_back(); } //currentBlock.pop_back(); } } //make sure that all blocks have a matching end statement if ((!lineError)&&(blockDepth > 0)) { textDisplay << "Error: Missing 1 or more end statements\r\n"; lineError = true; currentBlock.resetBuffer(); } if ((!lineError)&&(blockDepth == 0)) { textDisplay.send("~~~\r\n"); } //displayMemoryLeft(); //DisplayRAMBanks(); } //used to return a pointer to a variable, if it exists int* scriptStream::findIntVariable(string nameInput) { textDisplay.debug("Finding variable: "); textDisplay.debug(nameInput.data()); int* outPtr = NULL; bool foundIt = false; 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; } } void scriptStream::clearEnvironmentVariables(int clearMode) { //Modes: //clear callbacks, functions, and queue if (clearMode & BLOCKMEMORYTYPES) { 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; } for (int i = 0; i < NUMFUNCTIONS; i++) { functionSpotTaken[i] = false; functionEventArray[i] = NULL; } for (int i = 0; i < NUMEVENTS; i++) { eventBlock[i].release(); } for (int i = 0; i < NUMCONDITIONS; i++) { conditionBlock[i].release(); } for (int i = 0; i < NUMINTCOMPARE; i++) { intCompareBlock[i].release(); } for (int i = 0; i < NUMACTIONS; i++) { actionBlock[i].release(); } for (int i = 0; i < NUMPORTMESSAGES; i++) { portMessageBlock[i].release(); } for (int i = 0; i < NUMINTOPERATIONS; i++) { intOperationBlock[i].release(); } for (int i = 0; i < NUMDISPLAYACTIONS; i++) { displayActionBlock[i].release(); } for (int i = 0; i <NUMTRIGGERACTIONS; i++) { triggerFunctionActionBlock[i].release(); } queuePtr->eraseQueue(); } if (clearMode & VARIABLEMEMORYTYPES) { while (!globalVariables.empty()) { delete globalVariables.back(); globalVariables.pop_back(); } } if (clearMode & ENVSETTINGSMEMORYTYPES) { //set all environment settings to default values broadCastStateChanges = true; for (int i=0;i<NUMPORTS;i++) { system->setPortUpdatesOn(i); } } }