Andy Lustig
/
Nucleo_statescript
stateScript for Nucleo-F401RE board
Revision 0:ecf80f0172d0, committed 2016-02-08
- Comitter:
- alustig3
- Date:
- Mon Feb 08 18:56:09 2016 +0000
- Commit message:
- initial commit
Changed in this revision
diff -r 000000000000 -r ecf80f0172d0 SOMO_II.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SOMO_II.lib Mon Feb 08 18:56:09 2016 +0000 @@ -0,0 +1,1 @@ +https://developer.mbed.org/users/alustig3/code/SOMO_II/#a4f14eadd0df
diff -r 000000000000 -r ecf80f0172d0 behave.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/behave.cpp Mon Feb 08 18:56:09 2016 +0000 @@ -0,0 +1,5592 @@ +#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 + +#if defined(FPGAHARDWARE) || defined(NUCLEOHARDWARE) + +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 + +#ifdef FPGAHARDWARE + pc = new NUCLEOSerialPort(); + pc->init(); + + hardware = new MBEDSystem(); + Ticker keeptime; + keeptime.attach_us(&hardware,&MBEDSystem::tick,1000); + + 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); + + changed = (inPin->lastUpEvent.triggered || inPin->lastDownEvent.triggered); + if (changed) { + 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 (inPin->lastUpEvent.triggered) { + //there were hardware triggers since the last main loop. We use that time + lastChangeInterval = inPin->lastUpEvent.timeStamp - lastChangeTime; + lastChangeTime = inPin->lastUpEvent.timeStamp; + } else { + //otherwise we use the current time + lastChangeInterval = timeKeeper - lastChangeTime; + lastChangeTime = timeKeeper; + } + */ + if (triggerUpEventPtr != NULL && triggerUpEventPtr->isUsed) {triggerUpEventPtr->execute();} + } else if (inState == 0) { + + lastChangeInterval = inPin->lastDownEvent.timeStamp - lastChangeTime; + lastChangeTime = inPin->lastDownEvent.timeStamp; + + /* + if (inPin->lastDownEvent.triggered) { + lastChangeInterval = inPin->lastDownEvent.timeStamp - lastChangeTime; + lastChangeTime = inPin->lastDownEvent.timeStamp; + } else { + lastChangeInterval = timeKeeper - lastChangeTime; + lastChangeTime = timeKeeper; + }*/ + + if (triggerDownEventPtr != NULL && triggerDownEventPtr->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 + + + } + + + + } + + 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) + // sound(s03) + } 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; + unsigned char sendTrack = 0; + if (tmpVar == NULL) { + if ((tmpLine.compare(pos1,1,"'")==0) && (tmpLine.compare(pos2-1,1,"'")==0)) { + isText = true; +// textDisplay <<"command= "<<tmpLine.substr(pos1+1,pos2-pos1-2)<<"\r\n"; + } else if (tmpLine.compare(pos1,1,"s")==0 && dispVar.length()==3) { + sendTrack = (dispVar[1]-48)*10 + dispVar[2]-48; + } 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 (sendTrack>0 && sendTrack<100){ //track number must be 1-99 + sSound* S = system->createNewSoundAction(); +// textDisplay<<"sent:"<<sendTrack; + S->setFile(sendTrack); + 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 (sendTrack>0 && sendTrack<100){ + sSound* sPtr = system->createNewSoundAction(); + sPtr->setFile(sendTrack); + 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)) { // for SOMO II it should be between 0 and 30, but I'm not sure how to let this code know whether the SOMO or the smartWAV is being used + sSound* S = system->createNewSoundAction(); +// textDisplay << "new vol=" <<newVolume; + S->setVolume(newVolume); + S->execute(); + delete S; + } else { + textDisplay << "Error: sound volume must be between 0 and 255 .\r\n"; + lineError = true; + } + } else { + sSound* S = system->createNewSoundAction(); + S->setVolume(tmpVar); + S->execute(); + delete S; + } + + } else if (!lineError && (blockDepth > 0) ){ + //the disp function was put inside a block + textDisplay.debug("Volume statement\r\n"); + if (isText) { + int newVolume = atoi(dispVar.data()); + + sSound* sPtr = system->createNewSoundAction(); + sPtr->setVolume(newVolume); + + //action* tmpAction = new action(sPtr); + tmpAction->set(sPtr); + tmpEventPtrArray.back()->addAction(tmpAction); + + } else { + sSound* sPtr = system->createNewSoundAction(); + sPtr->setVolume(tmpVar); + //action* tmpAction = new action(sPtr); + tmpAction->set(sPtr); + tmpEventPtrArray.back()->addAction(tmpAction); + } + + + } + } + //clock statement used to is used to control the clock------------------------- + //example: clock(reset); clock(slave); clock(standalone) + } else if (tokens[i].find("clock(") != std::string::npos) { //clock commands + if (ifBlockInit || whileBlockInit || elseFlag || expectingDoStatement) { + textDisplay << "Error: expected a 'do' statement\r\n"; + lineError = true; + } + if (blockDepth > 0) { + textDisplay << "Error: clock commands only allowed outside of block structure\r\n"; + lineError = true; + } + int pos1 = tmpLine.find("clock(")+6; + int pos2 = tmpLine.find_first_of(")",pos1); + if (pos2 == std::string::npos) { + textDisplay << "Syntax Error: expected a ')'\r\n"; + lineError = true; + } + + if (!lineError) { + //int pos1 = tmpLine.find("clock(")+6; + //int pos2 = tmpLine.find_first_of(")",pos1); + string dispVar = tmpLine.substr(pos1,pos2-pos1); + + + if (blockDepth == 0) { + if (dispVar.compare("reset") == 0) { + resetTimer = true; + queuePtr->eraseQueue(); + textDisplay.send(string("Clock reset to 0\r\n")); + + } else if (dispVar.compare("slave") == 0) { + if (!clockSlave) { + changeToSlave = true; + textDisplay.send(string("Slave mode\r\n")); + + } + } else if (dispVar.compare("standalone") == 0) { + if (clockSlave) { + changeToStandAlone = true; + textDisplay.send(string("Standalone mode\r\n")); + + } + } else if (dispVar.compare("") == 0) { + //The user needs the current time displayed. + + //textDisplay.send(string("Current Clock\r\n")); + textDisplay << timeKeeper << " current time\r\n"; + } else { + textDisplay << "Error: Clock control statement not understood\r\n"; + lineError = true; + } + } + } + + //disp command used to display text via serial--------------------------------------- + //example: disp('hello'); disp(myVar) + } else if (tokens[i].find("disp(") != std::string::npos) { //display value of variable + + if (ifBlockInit || whileBlockInit || elseFlag || expectingDoStatement) { + textDisplay <<"Error: expected a 'do' statement\r\n"; + lineError = true; + } + + //int pos1 = tokens[i].find("disp(")+5; + //int pos2 = tokens[i].find_first_of(")",pos1); + //string dispVar = tokens[i].substr(pos1,pos2-pos1); + + wholeLineEvaluated = true; + int pos1 = tmpLine.find("disp(")+5; + int pos2 = tmpLine.find_first_of(")",pos1); + if (pos2 == std::string::npos) { + textDisplay <<"Syntax error: expected a ')'\r\n"; + lineError = true; + } + + if (!lineError) { + string dispVar = tmpLine.substr(pos1,pos2-pos1); + + int* tmpVar = findIntVariable(dispVar); + bool isText = false; + if (tmpVar == NULL) { + if ((tmpLine.compare(pos1,1,"'")==0) && (tmpLine.compare(pos2-1,1,"'")==0)) { + isText = true; + } else { + textDisplay << "Error: variable to display does not exist\r\n"; + lineError = true; + } + } + displayAction* dPtr = findFirstUnUsed(displayActionBlock, NUMDISPLAYACTIONS); + if (dPtr == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + lineError = true; + } + + if (!lineError && (blockDepth == 0)) { + //we are not inside a block structure, so display now + + if (isText) { + //displayAction* dPtr = new displayAction(tmpLine.substr(pos1+1,pos2-pos1-2), pcPtr); + dPtr->set(tmpLine.substr(pos1+1,pos2-pos1-2)); + dPtr->execute(); + //delete dPtr; + dPtr->release(); + } else { + //displayAction* dPtr = new displayAction(tmpVar, dispVar, pcPtr); + dPtr->set(tmpVar, dispVar); + dPtr->execute(); + //delete dPtr; + dPtr->release(); + } + + } else if (!lineError && (blockDepth > 0) ){ + //the disp function was put inside a block + textDisplay.debug("Display statement\r\n"); + action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS); + if (tmpAction == NULL) { + textDisplay <<"Error: no memory slots available.\r\n"; + lineError = true; + } + if (!lineError && isText) { + //displayAction* dPtr = new displayAction(tmpLine.substr(pos1+1,pos2-pos1-2), pcPtr); + dPtr->set(tmpLine.substr(pos1+1,pos2-pos1-2)); + tmpAction->set(dPtr); + //action* tmpAction = new action(dPtr); + tmpEventPtrArray.back()->addAction(tmpAction); + } else if (!lineError) { + //displayAction* dPtr = new displayAction(tmpVar, dispVar, pcPtr); + dPtr->set(tmpVar, dispVar); + tmpAction->set(dPtr); + //action* tmpAction = new action(dPtr); + tmpEventPtrArray.back()->addAction(tmpAction); + } + + + } + } + //---------------------------------------------- + //The trigger command is used like this: + //trigger(n) + //Where n is an integer corresponding to a "function n" block + //When "trigger" is called, the corresponding function is executed. + } else if (tokens[i].find("trigger(") != std::string::npos) { //trigger a function + + if (ifBlockInit || whileBlockInit || elseFlag || expectingDoStatement) { + textDisplay << "Error: expected a 'do' statement\r\n"; + lineError = true; + } + + + wholeLineEvaluated = true; + int pos1 = tmpLine.find("trigger(")+8; + int pos2 = tmpLine.find_first_of(")",pos1); + if (pos2 == std::string::npos) { + textDisplay << "Syntax error: expected a ')'\r\n"; + lineError = true; + } + + if (!lineError) { + int funcNum = atoi(tmpLine.substr(pos1,pos2-pos1).data()); + if ((funcNum > 0) && (funcNum < NUMFUNCTIONS+1)) { + if (functionSpotTaken[funcNum-1] && functionEventArray[funcNum-1]->isUsed) { + + + } else { + textDisplay << "Error: function number does not exist\r\n"; + lineError = true; + } + } else { + textDisplay << "Error: not a valid function number\r\n"; + lineError = true; + } + + funcNum--; //change to 0-based index + if (!lineError && (blockDepth == 0)) { + //we are not inside a block structure, so execute function now + //textDisplay << "Exectuting function"; + //textDisplay.flush(); + + functionEventArray[funcNum]->execute(); + + } else if (!lineError && (blockDepth > 0) ){ + //the trigger function was put inside a block, so we need to create a new action + textDisplay.debug("Trigger statement\r\n"); + triggerFunctionAction* tPtr = findFirstUnUsed(triggerFunctionActionBlock, NUMTRIGGERACTIONS); + if (tPtr == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + lineError = true; + } + + if (!lineError) { + //we only give provide it the function number, instead + //of a pointer to the event. That way, if the user modifies + //the function (which would change the pointer), all callbacks + //still using that function number will use the new function. + tPtr->set(funcNum); + action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS); + if (tmpAction == NULL) { + textDisplay << "Error: no memory slots available.\r\n"; + lineError = true; + } + if (!lineError) { + + tmpAction->set(tPtr); + tmpEventPtrArray.back()->addAction(tmpAction); + } + } + + + } + + } + + + //int is used to decalar new variables. Only allowed outside of callbacks------------------- + //example: int a; int b = 9 + }else if(tokens[i].compare("kaboom") == 0){//send "kaboom;" to reset mbed +// mbed_reset(); + }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); + } + } + + + +} +
diff -r 000000000000 -r ecf80f0172d0 behave.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/behave.h Mon Feb 08 18:56:09 2016 +0000 @@ -0,0 +1,571 @@ +//#include "mbed.h" +#include <stdint.h> +#include <string.h> +#include <string> +#include <vector> +#include <list> +#include <deque> +#include <queue> +#include "hardwareInterface.h" + + +//#define MBEDHARDWARE //here is where we define which platform we are compiling for +//#define FPGAHARDWARE +#define NUCLEOHARDWARE + +#define MAXVARNAMESIZE 30 //The maximum number of characters of a variable name + +#ifdef MBEDHARDWARE + #include "mbedInterface.h" +#endif +#ifdef FPGAHARDWARE + #include "fpgaInterface.h" +#endif +#ifdef NUCLEOHARDWARE + #include "nucleoInterface.h" +#endif + +#define BLOCKMEMORYTYPES 1 +#define VARIABLEMEMORYTYPES 2 +#define ENVSETTINGSMEMORYTYPES 4 + + +/* +#define NUMEVENTS 50 +#define NUMCONDITIONS 150 +#define NUMINTCOMPARE 150 +#define NUMACTIONS 150 +#define NUMPORTMESSAGES 150 +#define NUMINTOPERATIONS 150 +#define NUMDISPLAYACTIONS 30 +#define NUMTRIGGERACTIONS 30 +#define NUMFUNCTIONS 50 +#define INPUTCHARBUFFERSIZE 3072 +*/ + +#define ARITHMATIC_CONDITION 0 +#define OR_CONDITION 1 +#define AND_CONDITION 2 + +extern "C" void mbed_reset();//reset mbed through software + + + +using namespace std; + +class event; //we foreward declare this because of class interdependencies + +//used in the digital port class to organize digital change events +/* +struct changeEvent { + uint32_t timeStamp; + bool triggered; +};*/ + + +//The digitalPort object directly controls and keeps data about the port. Each port has +//one digital out and one digital in. +class digitalPort { +public: + digitalPort(); + //digitalPort(sDigitalOut* DOP, sDigitalIn* DIP); + void init(sDigitalOut* DOP, sDigitalIn* DIP); + void setDigitalOut(int outVal); + //int getDigitalOut(); + int getDigitalIn(); + int getLastChangeState(); + uint32_t getTimeSinceLastChange(); + uint32_t lastChangeTime; + uint32_t lastOutChangeTime; + + void setTriggerUpEvent(event* eventInput); //attahces a routine to an upward change + void setTriggerDownEvent(event* eventInput); //attahces a routine to a downward change + //void addStateChange(int newState, uint32_t timeStamp); + + bool update(); //called from the main loop + + int inState; + int outState; + + bool outStateChanged; + + event* triggerUpEventPtr; + event* triggerDownEventPtr; + +private: + + sDigitalOut* outPin; + sDigitalIn* inPin; + int lastInState; + uint32_t lastChangeInterval; + + //changeEvent lastUpEvent; + //changeEvent lastDownEvent; +}; + + +//an intVariable contains an integer value and the name of that variable within the script +class intVariable { + +public: + intVariable(); + intVariable(std::string& tagInput, int initialValue); + void set(std::string& tagInput, int initialValue); + int value; + //string tag; + char tag[MAXVARNAMESIZE+1]; + bool isUsed; + +}; + + +//ACTION SECTION-- an 'action' is a command in the script. It can be a single command, +//or a block containing a set of actions +//------------------------------------------------------------------------------------ + +//display actions are used to output text messages via the serial port. The user can display +//either a static text string or the value of a single variable. +class displayAction { + +public: + displayAction(); + void set(int* variable, string varNameInput); + void set(string text); + bool isUsed; + void execute(); + void release(); + +private: + int* dVariable; + string dText; + +}; + +class triggerFunctionAction { + +public: + triggerFunctionAction(); + triggerFunctionAction(int functionNum); + void set(int functionNum); + bool isUsed; + void execute(); + void release(); +private: + int functionNum; + + +}; + +//intOpertaion is an action that does addition or subtraction of integers and returns/stores the result +//these operation are very limited so far (only + or - allowed, and only one operation per object, +//for example a = b + b works but a = b + c + d does not. The output value can also be set to a random number. +class intOperation { + +public: + intOperation(); + + /* + intOperation(int randParam, const char* cmpString, int cmpValInput); + intOperation(int randParam, const char* cmpString, int* cmpIntVarInput); + intOperation(int* intVarInput, const char* cmpString, int cmpValInput); + intOperation(int* intVarInput, const char* cmpString, int* cmpIntVarInput); + intOperation(int* intVarInput, intOperation* operationInput); + */ + + ~intOperation(); + + //Supported operations with rand: + //a = rand(x) + //a = rand(x) + 3 + //a = rand(x) + b + void setRandOp(int randParam, const char* cmpString, int cmpValInput, bool flipped); + void setRandOp(int randParam, const char* cmpString, int* cmpIntVarInput, bool flipped); + + //Supported regular operations + //a = 5 + //a = b + //a = b + 6 + //a = b + c + void set(int* intVarInput, const char* cmpString, int cmpValInput); + void set(int* intVarInput, const char* cmpString, int* cmpIntVarInput); + void set(int* intVarInput, intOperation* operationInput); + + + //Supported operations with clock() + //a = clock() + //a = clock() + 5 + //a = clock() + b + void setClockOp(int* intVarInput); + void setClockOp(const char* cmpString, int cmpValInput, bool flip); + void setClockOp(const char* cmpString, int* cmpIntVarInput, bool flip); + + void release(); + bool isUsed; + int execute(); + +private: + int randHigh; + int* cmpVal; + int* intVal; + intOperation* opPtr; + bool cmpValGlobal; + bool isClockAssign; //if the current clock value is part of the operation + bool inputsFlipped; + int (intOperation::*executePtr)(); + int addAndStore(); + int subtractAndStore(); + int add(); + int subtract(); + int equals(); + +}; + +//portMessage is an action to change a digital port. So far, You can only change the digital out (0 or 1) +class portMessage { +public: + + portMessage(); + //portMessage(digitalPort* portIn, int whichToSet, int value); //whichToSet: 1 DigitalOut; 2 State + //void setMessage(digitalPort* portIn, int whichToSet, int value); //whichToSet: 1 DigitalOut; 2 State + //portMessage(int* portIn, int whichToSet, int value); //whichToSet: + void setMessage(int* portIn, int whichToSet, int value, digitalPort* portVector); //whichToSet: + + void execute(); + void release(); + bool isUsed; + +private: + int whichToSet; //hard coded port number + int* port; //alternative variable port number + int value; + + digitalPort* portVector; + +}; + +//holder class for all possible actions. This include general system commands. +class action { +public: + + action(); + ~action(); + action(intOperation* opInput); + action(portMessage* messageInput); + action(event* eventInput); + //action(event* eventInput, uint32_t delay); + action(displayAction* displayInput); + action(sSound* soundInput); + action(triggerFunctionAction* triggerFuncInput); + action(int8_t sysCommandInput); //for general system commands + + void set(intOperation* opInput); + void set(portMessage* messageInput); + void set(event* eventInput); + //void set(event* eventInput, uint32_t delay); + + void set(displayAction* displayInput); + void set(sSound* soundInput); + void set(triggerFunctionAction* triggerFuncInput); + void set(int8_t sysCommandInput); + void execute(); + void execute(uint32_t blockExecTime); + void release(); + bool isUsed; + +private: + intOperation* op; + portMessage* message; + event* eventToCreate; + displayAction* displayActionPtr; + sSound* sound; + triggerFunctionAction* triggerFunc; + //uint32_t eventDelay; + int8_t sysCommand; + char actionType; + +}; +//----------------------------------------------------- + +//CONDITION SECTION-- a 'condition' is used in the beginning of a block (if-else blocks or while blocks) +//If the condition is true, the block is exectuted during a callback +//------------------------------------------------------------------------------------ + + +//intCompare is a condition class that compares the state value of a port or +//an integer variable to another integer variable or operation output +class intCompare { + +public: + intCompare(); + intCompare(digitalPort* portInput, const char* cmpString, int cmpValInput, int whichToUse); + intCompare(digitalPort* portInput, const char* cmpString, int* cmpIntVarInput, int whichToUse); + intCompare(int* intVarInput, const char* cmpString, int cmpValInput); + intCompare(int* intVarInput, const char* cmpString, int* cmpIntVarInput); + intCompare(int* intVarInput, const char* cmpString, intOperation* cmpIntOpInput); + intCompare(digitalPort* portInput, const char* cmpString, intOperation* cmpIntOpInput, int whichToUse); + + void set(digitalPort* portInput, const char* cmpString, int cmpValInput, int whichToUse); + void set(digitalPort* portInput, const char* cmpString, int* cmpIntVarInput, int whichToUse); + void set(int* intVarInput, const char* cmpString, int cmpValInput); + void set(int* intVarInput, const char* cmpString, int* cmpIntVarInput); + void set(int* intVarInput, const char* cmpString, intOperation* cmpIntOpInput); + void set(digitalPort* portInput, const char* cmpString, intOperation* cmpIntOpInput, int whichToUse); + + void release(); + + ~intCompare(); + bool isTrue(); + bool isUsed; + +private: + digitalPort* port; + int* portValPtr; + int* cmpVal; + int* intVal; + intOperation* intOp; + void setPointer(const char* cmpString); + void setPointer_operation(const char* cmpString); + bool (intCompare::*isTruePtr)(); + bool cmpValGlobal; + bool greaterThan(); + bool greaterOrEqual(); + bool lessThan(); + bool lessOrEqual(); + bool equal(); + bool notEqual(); + bool greaterThan_op(); + bool greaterOrEqual_op(); + bool lessThan_op(); + bool lessOrEqual_op(); + bool equal_op(); + bool notEqual_op(); +}; + + +//holder class for all possible conditions (so far only intCompare) +class condition { +public: + + condition(); + condition(intCompare* compareInput); + condition(condition* condition1, char condType, condition* condition2); + ~condition(); + void set(intCompare* compareInput); + void set(condition* condition1, char condType, condition* condition2); + bool isTrue(); + bool isUsed; + void release(); //called when the event is no longer being used; +private: + + //char conditionType; //1 for intCompare + intCompare* intCmp; + condition* conditionPtrs[2]; + char conditionType; + + +}; +//-------------------------------------------- + + +//queueItem connects a pre-defined event with an exectution time. +//They are placed in the eventQueue +struct queueItem { + uint32_t timeToExecute; + event* eventPtr; +}; + + +//Organizes events in a temporal queue. check() is called from the main loop. +//If the execution time of the event has passed, then the event is exectuted. +class eventQueue { +public: + eventQueue(); + void addEventToQueue(event* eventInput, uint32_t delay); + void eraseQueue(); //clear all future events + void check(void); + +private: + std::vector<queueItem> events; + int queueSize; + +}; + +//An 'event' is a block of 'actions' that can be gated with a boolean 'condition' set. All +//conditions in the set must be true for the block of actions to be executed. Right now, +//there is no OR logic (||), only AND (&&). +//The entire event is placed on the event queue to be executed at a given delay. +//At that future time, the condition is checked and if true, the block of actions +//is exectuted. Note: an 'action' can be another event (or even the parent event), allowing +//nested 'if' and 'while' statements. +class event { +public: + + event(); + event(eventQueue* queueInput); + ~event(); + void setTimeLag(uint32_t timeLagInput); //the event will be exectuted at this time from now + void setTimeLag(int* timeLagInput); //the event will be exectuted at this time from now + void setWhileLoopPeriod(uint32_t period); + void setWhileLoopPeriod(int* period); + void addCondition(condition* conditionInput); //contains a set of conditions to check and a truth table + bool isConditionTrue(void); //checks if the condition is true + void addAction(action* actionInput); //called during script parsing, when the block is being defined + void addToQueue(void); //places the event on the event queue with default time lag. When the time + //lag has expired, the the block is executed + void addToQueue(uint32_t delay); + void execute(void); //Execute without checking the condition. Called only from the event queue + void setNextElseEvent(event* eventInput); //allows for else event block + uint32_t timeLag; //default time from now when the event will be executed (this is ignored once placed in event queue) + int* timeLagVar; //exectution time lab defined by a variable + eventQueue* queuePtr; + void release(); //called when the event is no longer being used; + + char blockType; //0 callback + //1 if ... do block (with conditions) + //2 do block (no conditions) + //3 else if ... do block + //4 else do (no conditions) + //5 while ... do every ... block + //6 else while ... do every ... block + //7 then if ... do block + //8 then do (no conditions) + + uint32_t whileLoopPeriod; //if non-zero, the block is a while loop (executed at regular intervals) + int* whileLoopPeriodVar; + event* nextElseEventPtr; + bool isUsed; + bool timeLagIsConstant; + bool whileLoopPeriodIsConstant; + bool hasWhileLoop; + +private: + int numConditions; + int numActions; + condition* conditionToCheck; + action* actionArray[20]; + + //if statement (can be left empty, which is interpreted as 'true') + //std::vector<condition*> conditionArray; + //std::deque<action*> actionArray; + +}; + +//each functionItem help a poiter to an action, and the name of the function. Not currently in use. +class functionItem { +public: + functionItem(action* actionInput, string tagInput); + ~functionItem(); + string tag; + action* actionPtr; +}; + +class blockBuffer { + +public: + blockBuffer(); + bool addLine(char* input, int numChars); + string getNextLine(); + int16_t linesAvailable(); + bool empty(); + void resetBuffer(); + +private: +#ifdef MBEDHARDWARE + //On the MBED, we need to put this on a different memory bank + __attribute((section("AHBSRAM1"),aligned)) char charBuffer[INPUTCHARBUFFERSIZE]; +#else + char charBuffer[INPUTCHARBUFFERSIZE]; +#endif + int16_t bufferWritePos; + int16_t bufferReadPos; + int16_t _linesAvailable; + +}; + +//Parser for the incoming text. The parser is called when a line terminates with a semicolon (;). +//Only the final line in a callback block should have a semicolon. +class scriptStream { +public: + scriptStream(digitalPort* portVectorInput, int numPortsInput, eventQueue* queueInput, sSystem* system); + void parseBlock(); //Parses everything since the last semicolon was found + void addLineToCurrentBlock(char* lineInput); // if the line did not end with a semicolon, add it to the current block + +private: + + int* findIntVariable(string nameInput); //used to retrieve the pointer to the designated variable if it exists + int* findIntVariable(const char* nameInput); //used to retrieve the pointer to the designated variable if it exists + int* findIntVariable(const char* nameInput, int start, int end); //used to retrieve the pointer to the designated variable if it exists + bool createIntVariable(string nameInput); // creates a new interger variable + action* evaluateAssignmentForAction(string expression); //parses a numerical assignment or operation (a = b - c) + action* evaluateAssignmentForAction(const char* expression); //parses a numerical assignment or operation (a = b - c) + bool evaluateConditions(string& expression, event* currentEvent); //parses a condition statement (a == b && c > d) + condition* parseConditions(const char* expression,int start, int end); //parses a condition statement (a == b && c > d) + int findFirstOrOutsideParenth(const char* expression, int start, int end); + int findFirstAndOutsideParenth(const char* expression, int start, int end); + bool isOutsideParenth(const char* expression,int foundItem, int start, int end); + bool isNum(const char* expression, int start, int end); + bool areStringsSame(const char* str1, const char* str2, int start, int end); + int getRandomParam(string expression); + int getRandomParam(const char* expression,int start,int end); + int findStringLoc(const char* refString,const char* findString,int start, int end); + void clearEnvironmentVariables(int mode); + + int currentTriggerPort; + int currentTriggerDir; + int currentPort; + int currentFunction; + + string tmpLine; + vector<string> tokens; + + bool lineError; + int blockDepth; + bool ifBlockInit; + bool whileBlockInit; + bool elseFlag; + bool thenFlag; + bool expectingDoStatement; + int currentDelay; + event* tmpEvent; + string tmpString; + + vector<intVariable*> globalVariables; + vector<event*> tmpEventPtrArray; + //event* functionEventArray[NUMFUNCTIONS]; + //bool functionSpotTaken[NUMFUNCTIONS]; + + //vector<functionItem*> functionArray; //any blocks declared outsite callback blocks are stored here + //list<string> currentBlock; + blockBuffer currentBlock; + digitalPort* portVector; + sSystem* system; + + + + int numPorts; + eventQueue* queuePtr; + +}; + + +class mainLoop + +{ +public: + mainLoop(); + void init(); + void exec(); +private: + void eraseBuffer(); + uint32_t currentDIOstate[2]; + bool digitalInChanged; + bool digitalOutChanged; + scriptStream *parser; + sSystem *hardware; //hardware interface + sSerialPort *pc; //communication to computer + char buffer[256]; + digitalPort ports[NUMPORTS]; + + + +};
diff -r 000000000000 -r ecf80f0172d0 hardwareInterface.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hardwareInterface.cpp Mon Feb 08 18:56:09 2016 +0000 @@ -0,0 +1,340 @@ +#include "hardwareInterface.h" +//#include <ostream> +#include <sstream> + +using namespace std; + +//In debug mode, debug messages output to the screen +#ifdef DEBUGOUTPUT +bool debugOut = true; +#else +bool debugOut = false; +#endif + +uint32_t timeKeeper; //the main clock (updated every ms) +bool resetTimer; +bool clockSlave; +bool changeToSlave; +bool changeToStandAlone; + + +#ifdef MBEDHARDWARE + +//On the MBED, this needs to be put on a defined bank of memory, or else we run out of memory +__attribute((section("AHBSRAM0"),aligned)) outputStream textDisplay(512); + +#else +outputStream textDisplay(256); + +#endif + + +//--------------------------------------------------------- + +sSystem::sSystem() { + for (int i=0;i<32;i++) { + ignorePortUpdates[i] = false; + } +} + +//The user can toggle whether a particular port triggers a state update report every time it changes +//This is useful for inputs that toggle continuously. +void sSystem::setPortUpdatesOff(int portNum) { + ignorePortUpdates[portNum] = true; +} + +void sSystem::setPortUpdatesOn(int portNum) { + ignorePortUpdates[portNum] = false; +} + +bool* sSystem::getIgnoreUpdates() { + return ignorePortUpdates; +} + +void sSystem::immediateClockReset() { + //For external clock reset + timeKeeper = 0; + textDisplay << timeKeeper << " Clock reset\r\n"; +} + +void sSystem::mainLoopToDo() { + +} + +void sSystem::pauseInterrupts() { + +} + +void sSystem::resumeInterrupts() { + +} + +int sSystem::getPendingFunctionTriggers(uint16_t *bufferPtr) { + return 0; +} + +uint32_t sSystem::getDigitalOutputChangeFlags() { + +} + +uint32_t sSystem::getDigitalInputChangeFlags() { + +} + +//------------------------------------------------------ +sDigitalOut::sDigitalOut() { + +} + +//---------------------------------------------------- +sDigitalIn::sDigitalIn() { + lastDownEvent.triggered = false; + lastUpEvent.triggered = false; + bufferedDownEvent.triggered = false; + bufferedUpEvent.triggered = false; + updating = false; +} + +void sDigitalIn::addStateChange(int newState, uint32_t timeStamp) { + + //With levers and beam breaks, there will be flutter when triggers happen. + //The goal is to capture the initial event time, so we ignore extra triggers + //until it has been processed + if (!updating) { + if ((newState == 0) && (!lastDownEvent.triggered)){ + lastDownEvent.timeStamp = timeStamp; + lastDownEvent.triggered = true; + } else if ((newState == 1) && (!lastUpEvent.triggered)) { + lastUpEvent.timeStamp = timeStamp; + lastUpEvent.triggered = true; + } + } else { + //If we are currently checking this input, then we buffer the trigger and deal with it after + if (newState == 0){ + bufferedDownEvent.timeStamp = timeStamp; + bufferedDownEvent.triggered = true; + } else if (newState == 1) { + bufferedUpEvent.timeStamp = timeStamp; + bufferedUpEvent.triggered = true; + } + } + /* + if ((newState == 0) && (!lastDownEvent.triggered)){ + lastDownEvent.timeStamp = timeStamp; + lastDownEvent.triggered = true; + } else if ((newState == 1) && (!lastUpEvent.triggered)) { + lastUpEvent.timeStamp = timeStamp; + lastUpEvent.triggered = true; + }*/ +} + +void sDigitalIn::setUpdate(bool state) { + updating = state; //If true, then we buffer any trigger events until the update check is done. + if (!updating) { + if (bufferedUpEvent.triggered) { + lastUpEvent = bufferedUpEvent; + } + if (bufferedDownEvent.triggered) { + lastDownEvent = bufferedDownEvent; + } + bufferedDownEvent.triggered = false; + bufferedUpEvent.triggered = false; + } +} + +//----------------------------------------------------- +sSerialPort::sSerialPort() { + +} + +//------------------------------------------------------ + +sSound::sSound(void): + fileNameExists(false), + fileNum(0), + volumePtr(NULL), + volume(-1), + play(true), + reset(false) { +} + +void sSound::setFile(string fileNameIn) { + for (int i = 0; i < 20; i++) { + fileName[i] = NULL; + } + size_t length = fileNameIn.size(); + if (length <= 20) { + fileNameIn.copy(fileName, length, 0); + fileNameExists = true; + } +} + +void sSound::setFile(unsigned char filenNumIn) { //overload setFile to work with SOMO module + fileNum = filenNumIn; +} + +void sSound::setVolume(int volumeIn) { + + if ((volumeIn >= 0) && (volumeIn < 256)) { + volume = volumeIn; + volumePtr = NULL; + } +} + +void sSound::setVolume(int* volumeIn) { + + volume = -1; + volumePtr = volumeIn; + +} + +void sSound::setPlayback(bool playIn) { + play = playIn; +} + +void sSound::setReset() { + reset = true; +} + + +//----------------------------------------------------- +outputStream::outputStream(int bufferSizeIn): + readHead(0), + writeHead(0), + totalWriteHead(0), + totalReadHead(0), + bufferSize(bufferSizeIn), + unsentData(false), + serialPtr(NULL) { + + outputBuffer = new char[bufferSize]; + +} + +outputStream::~outputStream() { + delete[] outputBuffer; +} + +void outputStream::setSerial(sSerialPort *s) { + serialPtr = s; +} + +//used to immediately write to serial port +void outputStream::flush() { + if (serialPtr != NULL) { + while(unsentData) { + serialPtr->writeChar(getNextChar()); + } + } +} + +//adds text to the buffer +void outputStream::send(const string &outputString) { + int strLen = outputString.size(); + + int total = 0; + int chunk = 0; + if (totalWriteHead+strLen > (totalReadHead + bufferSize)) { + //We don't have enough space in the buffer, so flush it + flush(); + } + if (!(totalWriteHead+strLen > (totalReadHead + bufferSize))) { + while (strLen - total > 0) { + chunk = min((bufferSize - writeHead), strLen - total); + outputString.copy(outputBuffer + writeHead, chunk, total); + writeHead = (writeHead + chunk) % bufferSize; + totalWriteHead += chunk; + total += chunk; + } + if (total > 0) { + unsentData = true; + } + } +} + +//adds text to the buffer +void outputStream::send(const char *s) { + int strLen = strlen(s); + + int total = 0; + //int chunk = 0; + if (totalWriteHead+strLen > (totalReadHead + bufferSize)) { + //We don't have enough space in the buffer, so flush it + flush(); + } + if (!(totalWriteHead+strLen > (totalReadHead + bufferSize))) { + while (strLen - total > 0) { + strncpy(outputBuffer + writeHead, s+total,1); + total++; + writeHead = (writeHead + 1) % bufferSize; + totalWriteHead += 1; + + /* + chunk = min((bufferSize - writeHead), strLen - total); + strncpy(outputBuffer + writeHead,); + outputString.copy(outputBuffer + writeHead, chunk, total); + writeHead = (writeHead + chunk) % bufferSize; + totalWriteHead += chunk; + total += chunk; + */ + } + if (total > 0) { + unsentData = true; + } + } +} + +void outputStream::debug(const char *s) { + //send to serial immediately, but only if debugOut is true + if (debugOut) { + string tmpString = string(s); + send(tmpString); + flush(); + } +} + +//Overloaded << operator to for debugging output. This eliminates the +//need for printf statements +outputStream& outputStream::operator<<(const string &outputString) { + send(outputString); + + return *this; +} + +outputStream& outputStream::operator<<(const char* s) { + //string tmpString = string(s); + //send(tmpString); + send(s); + return *this; +} + +outputStream& outputStream::operator<<(int outputNum) { + ostringstream varConvert; + varConvert << outputNum; + send(varConvert.str()); + return *this; +} + +outputStream& outputStream::operator<<(uint32_t outputNum) { + ostringstream varConvert; + varConvert << outputNum; + send(varConvert.str()); + return *this; +} +//the main loop gets one character per loop and write it to the serial port +char outputStream::getNextChar() { + + + if (totalReadHead < totalWriteHead) { + tmpOut = *(outputBuffer+readHead); + readHead = (readHead+1) % bufferSize; + totalReadHead++; + if (totalReadHead >= totalWriteHead) { + unsentData = false; + } + } + return tmpOut; + +} + +
diff -r 000000000000 -r ecf80f0172d0 hardwareInterface.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hardwareInterface.h Mon Feb 08 18:56:09 2016 +0000 @@ -0,0 +1,173 @@ +#ifndef HARDWARWEINTERFACE_H +#define HARDWARWEINTERFACE_H + +#include <stdint.h> +#include <string> +#include <cstdlib> +#include <string.h> + +#define PENDINGTRIGGERBUFFERSIZE 10 + +//#define NUMPORTS 8 //the number of ports available on the hardware + +using namespace std; + +//for debugging output +//#define DEBUGOUTPUT + +//used to organize digital change events +struct changeEvent { + uint32_t timeStamp; + bool triggered; +}; + +class sDigitalOut +{ +public: + sDigitalOut(); + + virtual void init(int pin) = 0; + virtual void write(int value) = 0; + virtual int read() = 0; +protected: + +}; + +class sDigitalIn +{ +public: + sDigitalIn(); + + virtual void init(int pin) = 0; + virtual int read() = 0; + virtual void interrupt_up_callback() = 0; + virtual void interrupt_down_callback() = 0; + void setUpdate(bool); + + changeEvent lastUpEvent; + changeEvent lastDownEvent; + +protected: + + bool updating; + changeEvent bufferedUpEvent; + changeEvent bufferedDownEvent; + void addStateChange(int newState, uint32_t timeStamp); + +}; + +class sSerialPort +{ +public: + sSerialPort(); + + virtual void init() = 0; + virtual bool readable() = 0; + virtual char readChar() = 0; + virtual void writeChar(char s)= 0; + virtual int requestToWriteString(char *s, int numBytes) = 0; + +protected: + + +}; + +class sSound +{ +public: + sSound(); + void setFile(string fileNameIn); + void setFile(unsigned char fileNumIn); + void setVolume(int* volumeIn); + void setVolume(int volumeIn); + void setPlayback(bool playIn); + void setReset(); + virtual void execute() = 0; + +protected: + char fileName[21]; + bool fileNameExists; + unsigned char fileNum; + bool givenTrackNum; + int* volumePtr; + int volume; + bool play; + bool reset; +}; + +class sSystem +{ +public: + sSystem(); + virtual void timerinit() = 0; + virtual void setStandAloneClock() = 0; + virtual void setSlaveClock() = 0; + virtual sDigitalOut* getDigitalOutPtr(int portNum) = 0; + virtual sDigitalIn* getDigitalInPtr(int portNum) = 0; + virtual sSound* createNewSoundAction() = 0; + virtual void externalClockReset() = 0; //needs to reset harware timer before calling immediateClockReset(); + virtual void incrementClock() = 0; + virtual void mainLoopToDo(); + virtual void pauseInterrupts(); + virtual void resumeInterrupts(); + virtual int getPendingFunctionTriggers(uint16_t *bufferPtr); //Returns the number of pending shortcut triggers + virtual uint32_t getDigitalOutputChangeFlags(); + virtual uint32_t getDigitalInputChangeFlags(); + void setPortUpdatesOn(int portNum); + void setPortUpdatesOff(int portNum); + bool* getIgnoreUpdates(); + + + +protected: + + //virtual void timerInterrupt() = 0; + + void immediateClockReset(); + int currentDINPin; + int currentDOUTPin; + uint32_t currentDigitalOuputStates; + uint32_t currentDigitalInputStates; + bool ignorePortUpdates[32]; + + + + +}; + + +//Used to buffer output text. Used mainly for 'display' commands within the script, +//and alloed the reset of the block to execute quickly instead. The text is then streamed out +//slowly via serial (one character per main loop execution). outputStream is a simple circular +//buffer that cannot be resized after initiation. +class outputStream { + +public: + outputStream(int bufferSizeIn); + ~outputStream(); + void setSerial(sSerialPort *s); + void send(const string &outputString); + void send(const char* s); + void debug(const char* s); + outputStream &operator<<(const string &outputString); + outputStream &operator<<(int outputNum); + outputStream &operator<<(uint32_t outputNum); + outputStream &operator<<(const char* s); + char getNextChar(); + bool unsentData; + void flush(); + +private: + int readHead; + int writeHead; + int totalWriteHead; + int totalReadHead; + int bufferSize; + char tmpOut; + char* outputBuffer; + sSerialPort* serialPtr; +}; + + + +#endif // HARDWARWEINTERFACE_H
diff -r 000000000000 -r ecf80f0172d0 main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Mon Feb 08 18:56:09 2016 +0000 @@ -0,0 +1,9 @@ +#include "behave.h" + +using namespace std; + +int main() { + mainLoop m; + m.init(); + m.exec(); +}
diff -r 000000000000 -r ecf80f0172d0 mbed.bld --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Mon Feb 08 18:56:09 2016 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/f141b2784e32 \ No newline at end of file
diff -r 000000000000 -r ecf80f0172d0 nucleoInterface/nucleoInterface.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nucleoInterface/nucleoInterface.cpp Mon Feb 08 18:56:09 2016 +0000 @@ -0,0 +1,483 @@ +#include "nucleoInterface.h" +#include "mbed.h" +#define EPHYSRIG //!!!!!!make sure to change NUMPORTS, NUMINPORTS, and NUMOUTPORTS in the mbedInterface.h file!!!!!!!!! +//#define TRAINRIG //!!!!!!make sure to change NUMPORTS, NUMINPORTS, and NUMOUTPORTS in the mbedInterface.h file!!!!!!!!! + + +//-------------------------------------------------------------- +//-------------------------------------------------------------- +//This section is required for all custom harware interfaces + +//globals defined in hardwareInterface.cpp +extern uint32_t timeKeeper; //the master clock +uint32_t uSec_SinceLastClockInc = 0; +uint32_t uSec_SinceLastReset = 0; + +extern bool resetTimer; +extern bool clockSlave; +extern bool changeToSlave; +extern bool changeToStandAlone; +extern outputStream textDisplay; + +int externalIncrementMod = 1; +int externalIncrementCounter = 0; + + + +#ifdef MBED_RF +//We are listening to an RF signal for hardware syncing---------------------------------------- +//Uses DB9->RJ45 connector to map the following channels: +//1: P28 Clock Signal In +//2: P27 Data Signal In +//3: P20 FiberLED Out Signal +//4: 5V +//5: GND +//6: P6 NC +//7: P7 NC +//8: P8 NC + +DigitalOut mainLED(LED1); +DigitalOut secondaryLED(LED2); + +bool lightOn = false; +bool lightOn2 = false; +int pulseCounter = 0; +uint32_t lastPulse = 0; +uint32_t currentRFTime = 0; +uint32_t lastRFTime = 0; +uint32_t timeKeeperAtCurrentRFTime = 0; +uint32_t timeKeeperAtLastRFTime = 0; +int RFSyncCounter = 0; +bool RFSyncReadable = false; +bool RFSyncWritable = true; + +//Recieve clock signal from RF system +InterruptIn RFClock(PC_9); +DigitalIn RFData(PB_8); + + +void callback_RFClock(void) { + + //if this amount of time has passed since the last pulse, we have a new timestamp + if ((timeKeeper-lastPulse) > 4) { + + //make sure the previous timestamp was 32 pulses + //if so, update lastRFTime + //we only process every 100th stamp (once every 10 seconds with 10 Hz timestamps) + if ((pulseCounter == 31) && (RFSyncCounter == 99)){ + if (RFSyncWritable) { + lastRFTime = currentRFTime; + timeKeeperAtLastRFTime = timeKeeperAtCurrentRFTime; + RFSyncReadable = true; + RFSyncWritable = false; + } + } + + pulseCounter = 0; + currentRFTime = 0; + timeKeeperAtCurrentRFTime = timeKeeper; + RFSyncCounter = (RFSyncCounter+1)%100; + + + if (lightOn) { + mainLED = 0; + lightOn = false; + } else { + mainLED = 1; + lightOn = true; + } + } else { + if (pulseCounter < 32) { + currentRFTime = (currentRFTime | ( RFData.read() << pulseCounter)); + pulseCounter++; + } + } + lastPulse = timeKeeper; +} + +//------------------------------------------------------------ +#endif + +void externalClockIncDown() { + + //The external clock increment signal pulse has come back down. If the pulse was long + //enough, then we condsider it a valid pulse (the pulses should be 0.5 ms long) + if ((clockSlave)&&(uSec_SinceLastClockInc >= 300)) { + uSec_SinceLastClockInc = 0; + timeKeeper++; + + //Clock resets happen upon update so we dont get a partial first ms + if (resetTimer) { + uSec_SinceLastReset = 0; + timeKeeper = 0; + resetTimer = false; + } + } + +} + +void externalResetDown() { + + //The external clock reset signal pulse has come back down. If the pulse was long + //enough, then we condsider it a valid pulse (the pulses should be 1 ms long) + /* + textDisplay << uSec_SinceLastReset; + if ((clockSlave)&&(uSec_SinceLastReset >= 700)) { + uSec_SinceLastReset = 0; + timeKeeper = 1; //It has been 1ms since the reset pulse went up + textDisplay << timeKeeper << " Clock reset\r\n"; + }*/ +} + +//------------------------------------------------------------------------ +//------------------------------------------------------------------------ + +//MBED-specific stuff +//--------------------------------------------------------------------- + +//translate pin numbers to hardware pins +PinName outPins[NUMPORTS] = {PB_9,PA_5,PA_6,PA_7,PB_6,PC_7,PA_9,PA_8,PB_10}; //9 outports +PinName inPins[NUMPORTS] = {PB_4,PB_5,PB_3,PA_10,PA_2,PA_3,PC_0,PC_1,PB_0}; //9 inports + + +//The sound output uses a SmartWav device and their simple serial library +//SMARTWAV audio(p28,p27,p19); //(TX,RX,Reset); +SOMO audio(PA_4,PA_1); //(TX,RX,Reset) + +//This is the callback for the MBED timer +//extern "C" void TIMER0_IRQHandler (void) { +// +// /*if (clockSlave) { +// +// //The function is called every 100 us +// if((LPC_TIM0->IR & 0x01) == 0x01) { // if MR0 interrupt, proceed +// +// LPC_TIM0->IR |= 1 << 0; // Clear MR0 interrupt flag +// uSec_SinceLastClockInc = uSec_SinceLastClockInc+100; +// uSec_SinceLastReset = uSec_SinceLastReset+100; +// +// } +// +// +// } else {*/ +// //The function is called every 1 ms +// if((LPC_TIM0->IR & 0x01) == 0x01) { // if MR0 interrupt, proceed +// +// LPC_TIM0->IR |= 1 << 0; // Clear MR0 interrupt flag +// timeKeeper++; +// +// if (resetTimer) { +// timeKeeper = 0; +// resetTimer = false; +// } +// } +// //} +//} +//----------------------------------------------------------------------- + + + +MBEDSystem::MBEDSystem(): + clockResetInt(PA_0), + clockExternalIncrement(PD_2) { + + clockResetInt.rise(this, &MBEDSystem::externalClockReset); + clockResetInt.fall(&externalResetDown); + clockResetInt.mode(PullDown); + + clockExternalIncrement.mode(PullDown); + + #ifdef MBED_RF + //Karpova version------------- + //Set up callbacks for RF clock signal + RFClock.rise(&callback_RFClock); + RFClock.mode(PullDown); + #endif + + //------------------------------- + + for (int i=0; i < NUMPORTS; i++) { + dIn[i].init(i); + dOut[i].init(i); + } + + + audio.reset(); + +} + +void MBEDSystem::tick(){ + timeKeeper++; + if (resetTimer){ + timeKeeper = 0; + resetTimer = false; + } +} + +void MBEDSystem::timerinit() { +// //intiatiation of timer (specific to the LPC17xx chip). This is used in +// //standalone mode to increment the clock every ms. +// //---------------------------------------------------- +// //LPC_SC->PCLKSEL1 &= (3 << 12); //mask +// //LPC_SC->PCLKSEL1 |= (1 << 12); //sets it to 1*SystemCoreClock - table 42 (page 57 in user manual) +// //LPC_SC->PCLKSEL0 &= (3 << 3); //mask +// //LPC_SC->PCLKSEL0 |= (1 << 3); //sets it to 1*SystemCoreClock - table 42 (page 57 in user manual) +// LPC_SC->PCONP |=1<1; //timer0 power on +// +// +// LPC_TIM0->MR0 = 23980; //1 msec +// +// +// //LPC_TIM0->PR = (SystemCoreClock / 1000000); //microsecond steps +// //LPC_TIM0->MR0 = 1000; //100 msec +// //LPC_TIM0->MR0 = (SystemCoreClock / 1000000); //microsecond steps +// LPC_TIM0->MCR = 3; //interrupt and reset control +// //3 = Interrupt & reset timer0 on match +// //1 = Interrupt only, no reset of timer0 +// NVIC_EnableIRQ(TIMER0_IRQn); //enable timer0 interrupt +// LPC_TIM0->TCR = 1; //enable Timer0 +// //-------------------------------------------------------------- + +} + +void MBEDSystem::pauseInterrupts() { + __disable_irq(); +} + +void MBEDSystem::resumeInterrupts() { + __enable_irq(); +} + +void MBEDSystem::mainLoopToDo() { + #ifdef MBED_RF + //Karpova version-------------------------- + //Karpova lab RF addition. Print out time sync. + if (RFSyncReadable) { + /* + ostringstream RFTimeConvert; + RFTimeConvert << timeKeeperAtLastRFTime << " " << "RFsync " << lastRFTime << " "; //broadcast the earliest timestamp when a change occured + + textDisplay.send(RFTimeConvert.str() + "\r\n"); + RFTimeConvert.clear(); + RFTimeConvert.seekp(0); + */ + + textDisplay << timeKeeperAtLastRFTime << " RFsync " << lastRFTime << "\r\n"; + + RFSyncReadable = false; + RFSyncWritable = true; + } + //------------------------------------------------------------ + #endif +} + +sDigitalOut* MBEDSystem::getDigitalOutPtr(int portNum){ + if (portNum < NUMPORTS) { + return &dOut[portNum]; + } else { + return NULL; + } +} + +sDigitalIn* MBEDSystem::getDigitalInPtr(int portNum) { + if (portNum < NUMPORTS) { + return &dIn[portNum]; + } else { + return NULL; + } +} + +sSound* MBEDSystem::createNewSoundAction() { + MBEDSound *tmpSound = new MBEDSound(); + return tmpSound; +} + + +void MBEDSystem::externalClockReset() { + + //The pulse has gone high. When the pulse comes down we will check to see if it was long enough to be valid. + uSec_SinceLastReset = 0; + + + + if (clockSlave) { +// LPC_TIM0->TCR = 0x02; // reset timer //ANDY + externalIncrementCounter = 0; + + immediateClockReset(); + } + +} + +void MBEDSystem::setStandAloneClock() { + clockSlave = false; +// NVIC_DisableIRQ(TIMER0_IRQn); // Disable the interrupt //ANDY + timerinit(); //set up and enable interrupt + clockExternalIncrement.rise(NULL); //remove the callback to the external interrupt + //clockExternalIncrement.fall(NULL); + changeToSlave = false; + changeToStandAlone = false; +} + +void MBEDSystem::setSlaveClock() { + clockSlave = true; +// NVIC_DisableIRQ(TIMER0_IRQn); // Disable the interrupt //ANDY + //timerinit(); //set up and enable interrupt + clockExternalIncrement.rise(this, &MBEDSystem::incrementClock); + //clockExternalIncrement.fall(&externalClockIncDown); + clockSlave = true; + changeToSlave = false; + changeToStandAlone = false; +} + +void MBEDSystem::incrementClock() { + + if (clockSlave) { + //The pulse has gone high. When the pulse comes down we will check to see if it was long enough to be valid. + //uSec_SinceLastClockInc = 0; + + + //The clock is incremented + + externalIncrementCounter = (externalIncrementCounter+1) % externalIncrementMod; + if (externalIncrementCounter==0) { + timeKeeper++; + } + + } else { + timeKeeper++; + } + //Clock resets happen upon update so we dont get a partial first ms + /* + if (resetTimer) { + uSec_SinceLastReset = 0; + timeKeeper = 0; + resetTimer = false; + }*/ +} + +//----------------------------------------------------- + +MBEDSound::MBEDSound() { + +} + +void MBEDSound::execute() { + if (reset) { + audio.reset(); + } else if (!play) { + audio.stopTrack(); + } else if (fileNum){ + audio.playTrackNum(fileNum); + } else { + if (volume > -1) { + audio.volume(volume); + } else if (volumePtr != NULL) { + audio.volume(*volumePtr); + } + if (fileNameExists) { + audio.stopTrack(); + wait_ms(30); //without this delay, smartWAV shield tends to freeze up + audio.playTrackName(fileName); + } + } +} + +//----------------------------------------------------- +MBEDDigitalOut::MBEDDigitalOut() { + pinExists = false; +} + +void MBEDDigitalOut::init(int pin) { + if (pin < NUMOUTPORTS) { + outpin = new DigitalOut(outPins[pin]); + pinExists = true; + } +} + +int MBEDDigitalOut::read() { + if (pinExists) { + return outpin->read(); + } else { + return 0; + } +} + +void MBEDDigitalOut::write(int value) { + if (pinExists) { + + outpin->write(value); + } +} +//-------------------------------------------------------- + +MBEDDigitalIn::MBEDDigitalIn() { + pinExists = false; +} + +void MBEDDigitalIn::init(int pin) { + + if (pin < NUMINPORTS) { + inpin = new DigitalIn(inPins[pin]); + inpin_interrupt = new InterruptIn(inPins[pin]); + inpin->mode(PullDown); + //Set up callbacks for the port interrupts + inpin_interrupt->rise(this, &MBEDDigitalIn::interrupt_up_callback); + inpin_interrupt->fall(this, &MBEDDigitalIn::interrupt_down_callback); + pinExists = true; + } +} + +int MBEDDigitalIn::read() { + if (pinExists) { + return inpin->read(); + } else { + return 0; + } +} + +void MBEDDigitalIn::interrupt_up_callback() { + addStateChange(1, timeKeeper); +} + +void MBEDDigitalIn::interrupt_down_callback() { + addStateChange(0, timeKeeper); +} + +//---------------------------------------------------------- +MBEDSerialPort::MBEDSerialPort() { + +} + +void MBEDSerialPort::init() { + //Initialize serial communication + serialToPC = new Serial(USBTX, USBRX); // tx, rx + serialToPC->baud(115200); + + +} + +bool MBEDSerialPort::readable() { + return serialToPC->readable(); +} + +char MBEDSerialPort::readChar() { + return serialToPC->getc(); +} + +void MBEDSerialPort::writeChar(char s) { + serialToPC->printf("%c", s); +} + +int MBEDSerialPort::requestToWriteString(char *s, int numBytesRequested) { + //request to print a string to the serial output buffer + //function returns the number of chars actually accepted for output + int numBytesAccepted = 0; + while (numBytesAccepted < numBytesRequested) { + + writeChar(*(s+numBytesAccepted)); + numBytesAccepted++; + } + + return numBytesAccepted; +}
diff -r 000000000000 -r ecf80f0172d0 nucleoInterface/nucleoInterface.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nucleoInterface/nucleoInterface.h Mon Feb 08 18:56:09 2016 +0000 @@ -0,0 +1,149 @@ +#ifndef NUCLEOINTERFACE_H +#define NUCLEOINTERFACE_H + +#include "hardwareInterface.h" +#include "mbed.h" +#include <stdint.h> +//#include "SMARTWAV.h" +#include "SOMO.h" +#include <string.h> +#include <string> +#include <vector> +#include <queue> +#include <sstream> + + +#define MBED_RF + + +#define NUMPORTS 9 //the number of ports available on this hardware +#define NUMINPORTS 9 +#define NUMOUTPORTS 9 + +#define NUMEVENTS 50 +#define NUMCONDITIONS 150 +#define NUMINTCOMPARE 150 +#define NUMACTIONS 150 +#define NUMPORTMESSAGES 150 +#define NUMINTOPERATIONS 150 +#define NUMDISPLAYACTIONS 30 +#define NUMTRIGGERACTIONS 30 +#define NUMFUNCTIONS 50 +#define INPUTCHARBUFFERSIZE 3072 + + + +/* +class MBEDTimer : public sTimer +{ +public: + sTimer(); + virtual void init() = 0; + virtual void timeout_callback() = 0; + +}; + +class MBEDExternalSync : public sExternalSync +{ +public: + MBEDExternalSync(); + void init(); + void interrupt_callback(); + void reset_callback(); + +};*/ + + + +class MBEDDigitalOut : public sDigitalOut +{ +public: + MBEDDigitalOut(); + + void init(int pin); + void write(int value); + int read(); + +private: + DigitalOut *outpin; + bool pinExists; + +}; + +class MBEDDigitalIn : public sDigitalIn +{ +public: + MBEDDigitalIn(); + + void init(int pin); + int read(); + void interrupt_up_callback(); + void interrupt_down_callback(); +protected: + + + +private: + DigitalIn *inpin; + InterruptIn *inpin_interrupt; + bool pinExists; + +}; + +class MBEDSerialPort : public sSerialPort +{ +public: + MBEDSerialPort(); + + void init(); + bool readable(); + char readChar(); + void writeChar(char s); + int requestToWriteString(char *s, int numBytes); + Serial *serialToPC; + +private: + //Serial communication + + +}; + +class MBEDSound: public sSound +{ +public: + MBEDSound(); + void execute(); + +private: + +}; + +class MBEDSystem: public sSystem +{ +public: + MBEDSystem(); + void timerinit(); + void setStandAloneClock(); + void setSlaveClock(); + sDigitalOut* getDigitalOutPtr(int portNum); + sDigitalIn* getDigitalInPtr(int portNum); + sSound* createNewSoundAction(); + void pauseInterrupts(); + void resumeInterrupts(); + void incrementClock(); + void externalClockReset(); //needs to reset harware timer before calling immediateClockReset(); + void mainLoopToDo(); + void tick(); + +protected: + + //Pins for clock syncing + InterruptIn clockResetInt; + InterruptIn clockExternalIncrement; + +private: + MBEDDigitalIn dIn[NUMPORTS]; + MBEDDigitalOut dOut[NUMPORTS]; +}; + +#endif // MBEDINTERFACE_H