Microcontroller firmware that uses a simple, yet powerful scripting language to control the timing of input and output events with high temporal resolution. Written by Mattias Karlsson

Dependencies:   SMARTWAV mbed

Revision:
1:3a050d26d4f6
Parent:
0:8dbd6bd9167f
--- a/behave.cpp	Tue May 19 15:45:42 2015 +0000
+++ b/behave.cpp	Wed Jun 03 22:54:25 2015 +0000
@@ -41,10 +41,13 @@
 __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("AHBSRAM1"),aligned)) intVariable globalVarBlock[NUMINTVARS];
 __attribute((section("AHBSRAM0"),aligned)) intOperation intOperationBlock[NUMINTOPERATIONS];
 __attribute((section("AHBSRAM0"),aligned)) displayAction displayActionBlock[NUMDISPLAYACTIONS];
 __attribute((section("AHBSRAM0"),aligned)) triggerFunctionAction triggerFunctionActionBlock[NUMTRIGGERACTIONS];
+__attribute((section("AHBSRAM1"),aligned)) char charBuffer[INPUTCHARBUFFERSIZE];
+
+
 #endif
 
 #ifdef FPGAHARDWARE
@@ -55,9 +58,11 @@
 intCompare intCompareBlock[NUMINTCOMPARE];
 action actionBlock[NUMACTIONS];
 portMessage portMessageBlock[NUMPORTMESSAGES];
+intVariable globalVarBlock[NUMINTVARS];
 intOperation intOperationBlock[NUMINTOPERATIONS];
 displayAction displayActionBlock[NUMDISPLAYACTIONS];
 triggerFunctionAction triggerFunctionActionBlock[NUMTRIGGERACTIONS];
+char charBuffer[INPUTCHARBUFFERSIZE];
 #endif
 
 
@@ -117,6 +122,8 @@
 }
 
 void mainLoop::exec() {
+    //Start the main loop.
+
     bool digitalInChanged = false;
     bool digitalOutChanged = false;
     uint32_t changeTime;
@@ -124,8 +131,8 @@
 
     int bufferPos = 0;
 
-    ostringstream timeConvert;   // stream used for the conversion
-    ostringstream stateConvert;
+    //ostringstream timeConvert;   // stream used for the conversion
+    //ostringstream stateConvert;
     int tmpChar;
     int junkChar;
 
@@ -218,8 +225,9 @@
         digitalInChanged = false;
         digitalOutChanged = false;
         changeTime = timeKeeper;
+        //hardware->pauseInterrupts();
         for (int i = 0; i < NUMPORTS; i++) {
-
+            //hardware->pauseInterrupts();
             if (ports[i].update()) {
 
                 digitalInChanged = true;
@@ -233,6 +241,7 @@
                     currentDIOstate[0] &= ~(1 << i);
                 }
             }
+            //hardware->resumeInterrupts();
             if (ports[i].outStateChanged) {
                 digitalOutChanged = true;
                 changeTime = min(changeTime,ports[i].lastOutChangeTime);
@@ -425,28 +434,18 @@
     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);
+        changed = (inPin->lastUpEvent.triggered || inPin->lastDownEvent.triggered); //Either a down or up event happened
         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
@@ -470,7 +469,7 @@
                         lastChangeTime = timeKeeper;
                     }
                     */
-                    if (triggerUpEventPtr != NULL) {triggerUpEventPtr->execute();}
+                    if (triggerUpEventPtr != NULL) {execUp = true;}
                 } else if (inState == 0) {
 
                     lastChangeInterval = inPin->lastDownEvent.timeStamp - lastChangeTime;
@@ -485,11 +484,11 @@
                         lastChangeTime = timeKeeper;
                     }*/
 
-                    if (triggerDownEventPtr != NULL) {triggerDownEventPtr->execute();}
+                    if (triggerDownEventPtr != NULL) {execDown = true;}
                 }
             } else if (lastInState == inState) {
 
-                //Both up and down triggers must have happened, so we consider both
+                //Both up and down triggers must have happened, so we consider both (and execute in the right order)
                 if (inState == 1) {
 
                     lastChangeInterval = inPin->lastUpEvent.timeStamp - inPin->lastDownEvent.timeStamp;
@@ -507,12 +506,20 @@
                 }
             }
 
+            lastInState = inState;
+            inPin->lastUpEvent.triggered = false;
+            inPin->lastDownEvent.triggered = false;
+
+            inPin->setUpdate(false); //This also checks if there were any buffered changes that occured
+
         }
-
-        lastInState = inState;
-        inPin->lastUpEvent.triggered = false;
-        inPin->lastDownEvent.triggered = false;
-
+    }
+    if (execUp) {
+        triggerUpEventPtr->execute();
+    }
+
+    if (execDown) {
+        triggerDownEventPtr->execute();
     }
 
     return changed;
@@ -538,13 +545,17 @@
     isUsed = true;
 }
 
-void intVariable::set(std::string& tagInput, int initialValue) {
+void intVariable::set(const char* tagInput, int initialValue) {
     value = initialValue;
     //tag = string(tagInput);
-    strncpy(tag,tagInput.data(),MAXVARNAMESIZE);
+    strncpy(tag,tagInput,MAXVARNAMESIZE);
     isUsed = true;
 }
 
+void intVariable::release() {
+    isUsed = false;
+}
+
 displayAction::displayAction():
 dText(string("--------------------------------------------------")){
     dVariable = NULL;
@@ -2060,10 +2071,31 @@
     bufferReadPos = 0;
     _linesAvailable = 0;
 
+    writeLine = 0;
+    readLine = 0;
+    for (int i=0; i < 200; i++) {
+        lines[i] = NULL;
+    }
+
 }
 
 bool blockBuffer::addLine(char *input, int numChars) {
 
+    if (writeLine < 200) {
+        lines[writeLine] = (char*) malloc (numChars+1);
+        if (lines[writeLine] == NULL) {
+              textDisplay << "Could noy allocate memory for line.";
+              textDisplay.flush();
+              return false;
+        }
+        strcpy(lines[writeLine],input);
+        writeLine++;
+        _linesAvailable++;
+    } else {
+        return false;
+    }
+
+    /*
     if (bufferWritePos+numChars >= INPUTCHARBUFFERSIZE) {
         return false;
     }
@@ -2073,11 +2105,28 @@
     }
     _linesAvailable++;
     return true;
+    */
 }
 
+char* blockBuffer::getNextLine() {
+
+    if (readLine < writeLine) {
+
+        readLine++;
+        _linesAvailable--;
+
+        return lines[readLine-1];
+    } else {
+        return NULL;
+    }
+
+}
+
+/*
 string blockBuffer::getNextLine() {
 
     string outputLine;
+
     int endOfLinePos = bufferReadPos;
     bool endOfLineFound = false;
 
@@ -2110,7 +2159,9 @@
     }
     return outputLine;
 
+
 }
+*/
 
 int16_t blockBuffer::linesAvailable() {
     return _linesAvailable;
@@ -2120,6 +2171,14 @@
     _linesAvailable = 0;
     bufferReadPos = 0;
     bufferWritePos = 0;
+
+    writeLine = 0;
+    readLine = 0;
+    for (int i=0; i< 200; i++) {
+            //delete [] lines[i];
+            free (lines[i]);
+            lines[i] = NULL;
+    }
 }
 
 bool blockBuffer::empty() {
@@ -2154,7 +2213,6 @@
         functionEventArray[i] = NULL;
     }
 
-
 }
 
 
@@ -2190,6 +2248,7 @@
     }
     if (compile) {
         parseBlock();
+        currentBlock.resetBuffer();
     }
 
 }
@@ -2217,8 +2276,11 @@
     while (!currentBlock.empty()) {
 
         wholeLineEvaluated = false;
-        //tmpLine = currentBlock.back();
-        tmpLine = currentBlock.getNextLine();
+
+        //tmpLine = currentBlock.getNextLine();
+
+        tmpLine.assign(currentBlock.getNextLine());
+
 
         lineError = false;
         //remove tabs
@@ -2296,8 +2358,9 @@
                 int pos1 = tmpLine.find("sound(")+6;
                 int pos2 = tmpLine.find_first_of(")",pos1);
                 string dispVar = tmpLine.substr(pos1,pos2-pos1);
-
-                int* tmpVar = findIntVariable(dispVar);
+                //int* tmpVar = findIntVariable(dispVar);
+                int* tmpVar = findIntVariable(tmpLine.data(),pos1,pos2-1);
+
                 bool isText = false;
                 bool stopSignal = false;
                 bool resetSignal = false;
@@ -2391,8 +2454,8 @@
                 int pos1 = tmpLine.find("volume(")+7;
                 int pos2 = tmpLine.find_first_of(")",pos1);
                 string dispVar = tmpLine.substr(pos1,pos2-pos1);
-
-                int* tmpVar = findIntVariable(dispVar);
+                //int* tmpVar = findIntVariable(dispVar);
+                int* tmpVar = findIntVariable(tmpLine.data(),pos1,pos2-1);
                 bool isText = false;
                 if (tmpVar == NULL) {
                     if (isNumber(dispVar)) {
@@ -2518,11 +2581,11 @@
                     textDisplay <<"Error: expected a ) character\r\n";
                     lineError = true;
                 }
-                
+
                 if (!lineError) {
                     string dispVar = tmpLine.substr(pos1,pos2-pos1);
-                    
-                    int* tmpVar = findIntVariable(dispVar);
+                    //int* tmpVar = findIntVariable(dispVar);
+                    int* tmpVar = findIntVariable(tmpLine.data(),pos1,pos2-1);
                     bool isText = false;
                     if (tmpVar == NULL) {
                         if ((tmpLine.compare(pos1,1,"'")==0) && (tmpLine.compare(pos2-1,1,"'")==0)) {
@@ -2537,10 +2600,10 @@
                         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));
@@ -2554,7 +2617,7 @@
                             //delete dPtr;
                             dPtr->release();
                         }
-                        
+
                     } else if (!lineError && (blockDepth > 0) ){
                         //the disp function was put inside a block
                         textDisplay.debug("Display statement\r\n");
@@ -2576,8 +2639,8 @@
                             //action* tmpAction = new action(dPtr);
                             tmpEventPtrArray.back()->addAction(tmpAction);
                         }
-                        
-                        
+
+
                     }
                 }
                 //----------------------------------------------
@@ -2697,7 +2760,9 @@
                             variableCreated = true;
                         } else {
                             textDisplay.debug("Attempting to use existing variable\r\n");
-                            int* tmpVar = findIntVariable(tmpString.substr(0,stringInd));
+                            //int* tmpVar = findIntVariable(tmpString.substr(0,stringInd));
+                            int* tmpVar = findIntVariable(tmpString.data(),0,stringInd-1);
+
                             *tmpVar = 0;
                             //lineError = true;
                         }
@@ -2706,6 +2771,7 @@
                         lineError = true;
                     }
                 }
+
                 if ((!lineError) && (stringInd != std::string::npos)) { //evaluate the expression
                     //action* tmpAction = evaluateAssignmentForAction(tmpString);
                     action* tmpAction = evaluateAssignmentForAction(tmpString.data());
@@ -3035,9 +3101,9 @@
 
                         }
 
-                    } else if ((!lineError) && (tokens[i+1].compare("in") == 0) && (findIntVariable(tokens[i+2])!=NULL)) {
+                    } else if ((!lineError) && (tokens[i+1].compare("in") == 0) && (findIntVariable(tokens[i+2].data())!=NULL)) {
                         textDisplay.debug("Do in VAR statement\r\n");
-                        int* delayVar = findIntVariable(tokens[i+2]);
+                        int* delayVar = findIntVariable(tokens[i+2].data());
                         //currentDelay = atoi(tokens[i+2].data());
                         if (!ifBlockInit) { //a standalone do block
                             //tmpEvent = new event(queuePtr);
@@ -3459,9 +3525,9 @@
                                     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]);
+                            } else if (findIntVariable(tokens[i+3].data())!=NULL) {
+
+                                int* period = findIntVariable(tokens[i+3].data());
                                 //tmpEvent->whileLoopPeriodVar = period;
                                 tmpEvent->setWhileLoopPeriod(period);
                                 if (!elseFlag) {
@@ -3608,7 +3674,7 @@
 
 }
 
-
+/*
 //used to return a pointer to a variable, if it exists
 int* scriptStream::findIntVariable(string nameInput) {
 
@@ -3648,19 +3714,20 @@
                 outPtr = &globalVariables[i]->value;
                 break;
             }
-            /*
-            if (nameInput.compare(globalVariables[i]->tag) == 0) {
-                outPtr = &globalVariables[i]->value;
-                break;
-            }*/
+
         }
     }
     textDisplay.debug("...done\r\n");
 
     return outPtr;
 }
-
-
+*/
+
+int* scriptStream::findIntVariable(const char *nameInput) {
+    return findIntVariable(nameInput,0,strlen(nameInput)-1);
+}
+
+/*
 //used to return a pointer to a variable, if it exists
 int* scriptStream::findIntVariable(const char* nameInput, int start, int end) {
 
@@ -3710,11 +3777,71 @@
     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 < NUMINTVARS; i++) {
+            //const char* varName = globalVariables[i]->tag.data();
+            if ((findStringLoc(nameInput,globalVarBlock[i].tag,start,end) != -1) && (strlen(globalVarBlock[i].tag)==(end-start+1))) {
+                outPtr = &globalVarBlock[i].value;
+                textDisplay.debug("Variable already exists.\r\n");
+                break;
+            }
+        }
+    }
+    //textDisplay.debug("done\r\n");
+
+    return outPtr;
 }
 
-bool scriptStream::createIntVariable(string nameInput) {
-    if (findIntVariable(nameInput) == NULL) {
-        globalVariables.push_back(new intVariable(nameInput, 0));
+
+bool scriptStream::createIntVariable(const string& nameInput) {
+    if (findIntVariable(nameInput.data()) == NULL) {
+        //globalVariables.push_back(new intVariable(nameInput, 0));
+        intVariable* tmpVar = findFirstUnUsed(globalVarBlock, NUMINTVARS);
+        if (tmpVar == NULL) {
+            textDisplay << "Error: no memory slots available.\r\n";
+            return false;
+        }
+        tmpVar->set(nameInput.data(),0);
+
         return true;
     } else {
         return false;
@@ -3758,8 +3885,9 @@
         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;
@@ -4286,6 +4414,7 @@
     return tmpAction;
 }
 
+/*
 action* scriptStream::evaluateAssignmentForAction(string expression) {
 
     //action* tmpAction = new action(); //create a new action
@@ -4820,7 +4949,7 @@
     }
     textDisplay.debug("Assignment successful\r\n");
     return tmpAction;
-}
+}*/
 
 /*
 bool scriptStream::isOutsideParenth(string& expression,std::size_t foundItem) {