Component Test's Software to work with "Universal Controller Box" - Software is an interpreter or "compiler" for programs to be done with a .txt file and read off of the SD Card

Dependencies:   BridgeDriver FrontPanelButtons MCP23017 SDFileSystem TextLCD mbed

Revision:
11:bc9cd2869f95
Parent:
10:e8db892fbc52
Child:
12:2e3e86714243
--- a/main.cpp	Wed Sep 24 22:54:36 2014 +0000
+++ b/main.cpp	Wed Oct 01 18:11:38 2014 +0000
@@ -18,14 +18,6 @@
 
 //extern "C" void mbed_reset(); //enable software reset of code
 
-    
-int cyclePrograms(vector<string>, int, int, int);
-
-void resetLineData(LineData &); //reset and all variables of the Line Data Struct
-
-int interpretCommand(FILE *, LineData &);
-
-int loopCommand(FILE *, LineData &);
 
 /******************************************************************************/
 /***                      <Function: resetLineData>                         ***/
@@ -66,8 +58,10 @@
     }
 
     //Output file on Display 
+    lcd.setAddress(0,0);
+    lcd.printf("                    "); // Clear the Line using Spaces (Emptyness) - Note one line is 20 Characters
     lcd.setAddress(0,3);
-    lcd.printf("                   "); // Clear the Line using Spaces (Emptyness) - Note one line is 20 Characters
+    lcd.printf("                    "); // Clear the Line using Spaces (Emptyness) - Note one line is 20 Characters
     wait(.2);
     lcd.setAddress(0,3);
     lcd.printf("%s", files[nextIndex]);
@@ -94,9 +88,8 @@
 int conditionCommand(FILE *selectedFile, LineData &lineData){
                 
     //Initialize variables    
-    LineData param[15];
+    LineData param[15]; // assume no more than 15 conditions will be needed
     vector<ConditionOp> paramCondition;
- 
     
     //Fill the param Vector with Line structs of each individual device, this way we can send the Line struct to the appropriate interpret function without modification within the function itself
     //this line reads: Condition, data_for_param1, CONDTITION_OP1, data_for_param2, CONDTITION_OP2, data_for_param3......
@@ -114,11 +107,17 @@
             
             //if this is the last word in the line....
             if(i == (lineData.numWords - 1)){
+
                 param[numParam].numWords = paramNumWords;
+                
+                //if numParam = 0 at this point, it means there's only one condition to check... need to add a member to the vector since none have been added yet
+                if (numParam == 0)
+                    paramCondition.push_back(ConditionOp());
+                    
                 paramCondition[numParam].op = NONE;
+
                 numParam++;
-            }
-            
+            }            
         }
             
         // if the word is an AND or an OR, it must mean the last function has been completely identified
@@ -143,12 +142,12 @@
         }    
     }
     
-    
+        
     //send the data parameters in order to get them interpreted by the appropriate device
     //if the value it's checking for meets the criteria you want, the device should return 1, if it doesn't meet the criteria the device should return 0
     int j = 0, k = 0;
     for (j = 0; j < numParam; j++){
-        paramCondition[j].value = interpretCommand(selectedFile, param[j]);
+        paramCondition[j].value = interpretCommand(param[j]);
         
         //error out if the interpretted command returned an error
         if (paramCondition[j].value == -1)
@@ -167,124 +166,134 @@
         if (k == numParam - 1)
             last = 1;
             
-       if (!last){
-            if (paramCondition[k].op != xAND && paramCondition[k].op != xOR && paramCondition[k + 1].op != xAND && paramCondition[k + 1].op != xOR){
-                //AND
-                if (paramCondition[k].op == AND){
-                    if (!first && prevCondition != xAND && prevCondition != xOR)
-                        combinedCondition.back().value = combinedCondition.back().value && paramCondition[k + 1].value;
-                    else if (first || prevCondition == xAND || prevCondition == xOR){
-                        tempCombinedCondition.value = paramCondition[k].value && paramCondition[k + 1].value; 
-                        combinedCondition.push_back(tempCombinedCondition);
-                        first = 0;
-                    }    
-                    prevCondition = AND;
+        //Only one condition to check
+        if (numParam == 1){
+            tempCombinedCondition.value = paramCondition[k].value;
+            tempCombinedCondition.op = NONE; 
+            combinedCondition.push_back(tempCombinedCondition);        
+        }
+        
+        else{
+            if (!last){
+                if (paramCondition[k].op != xAND && paramCondition[k].op != xOR && paramCondition[k + 1].op != xAND && paramCondition[k + 1].op != xOR){
+                    //AND
+                    if (paramCondition[k].op == AND){
+                        if (!first && prevCondition != xAND && prevCondition != xOR)
+                            combinedCondition.back().value = combinedCondition.back().value && paramCondition[k + 1].value;
+                        else if (first || prevCondition == xAND || prevCondition == xOR){
+                            tempCombinedCondition.value = paramCondition[k].value && paramCondition[k + 1].value; 
+                            combinedCondition.push_back(tempCombinedCondition);
+                            first = 0;
+                        }    
+                        prevCondition = AND;
+                    }
+                    
+                    //OR
+                    else if (paramCondition[k].op == OR){
+                        if (!first && prevCondition != xAND && prevCondition != xOR)
+                            combinedCondition.back().value = combinedCondition.back().value || paramCondition[k + 1].value;
+                        else if (first || prevCondition == xAND || prevCondition == xOR){
+                            tempCombinedCondition.value = paramCondition[k].value || paramCondition[k + 1].value; 
+                            combinedCondition.push_back(tempCombinedCondition);
+                            first = 0;
+                        }    
+                        prevCondition = OR;
+                    }
                 }
                 
-                //OR
-                else if (paramCondition[k].op == OR){
-                    if (!first && prevCondition != xAND && prevCondition != xOR)
-                        combinedCondition.back().value = combinedCondition.back().value || paramCondition[k + 1].value;
-                    else if (first || prevCondition == xAND || prevCondition == xOR){
-                        tempCombinedCondition.value = paramCondition[k].value || paramCondition[k + 1].value; 
-                        combinedCondition.push_back(tempCombinedCondition);
-                        first = 0;
-                    }    
-                    prevCondition = OR;
+                // first value is something, not exclusive, but next values are exclusive
+                else if (first && (paramCondition[k].op == AND || paramCondition[k].op == OR) && (paramCondition[k + 1].op == xAND || paramCondition[k + 1].op == xOR)){
+                    tempCombinedCondition.value = paramCondition[k].value;
+                    tempCombinedCondition.op = paramCondition[k].op;
+                    combinedCondition.push_back(tempCombinedCondition);
+                    prevCondition = paramCondition[k].op;
+                    first = 0;
                 }
-            }
-            
-            // first value is something, not exclusive, but next values are exclusive
-            else if (first && (paramCondition[k].op == AND || paramCondition[k].op == OR) && (paramCondition[k + 1].op == xAND || paramCondition[k + 1].op == xOR)){
-                tempCombinedCondition.value = paramCondition[k].value;
-                tempCombinedCondition.op = paramCondition[k].op;
-                combinedCondition.push_back(tempCombinedCondition);
-                prevCondition = paramCondition[k].op;
-                first = 0;
-            }
-            
-            else{   
-                //xAND
-                if (paramCondition[k].op == xAND){
-                    if (combinedCondition.size() == 0){ // No values so start a new combinedCondition
-                        tempCombinedCondition.value = paramCondition[k].value && paramCondition[k + 1].value;
-                        tempCombinedCondition.op = xAND;
-                        combinedCondition.push_back(tempCombinedCondition);
-                        prevCondition = xAND;
-                    }
-                    else{
-                         if (combinedCondition.back().op == xAND){ // AND the value to the back most combinedCondition
-                            combinedCondition.back().value = combinedCondition.back().value && paramCondition[k + 1].value;
-                            prevCondition = xAND;
-                        }
-                        else if (combinedCondition.back().op != xAND){ // Start a new combinedCondition
-                            tempCombinedCondition.value = paramCondition[k].value && paramCondition[k + 1].value; 
+                
+                else{   
+                    //xAND
+                    if (paramCondition[k].op == xAND){
+                        if (combinedCondition.size() == 0){ // No values so start a new combinedCondition
+                            tempCombinedCondition.value = paramCondition[k].value && paramCondition[k + 1].value;
                             tempCombinedCondition.op = xAND;
                             combinedCondition.push_back(tempCombinedCondition);
                             prevCondition = xAND;
                         }
+                        else{
+                             if (combinedCondition.back().op == xAND){ // AND the value to the back most combinedCondition
+                                combinedCondition.back().value = combinedCondition.back().value && paramCondition[k + 1].value;
+                                prevCondition = xAND;
+                            }
+                            else if (combinedCondition.back().op != xAND){ // Start a new combinedCondition
+                                tempCombinedCondition.value = paramCondition[k].value && paramCondition[k + 1].value; 
+                                tempCombinedCondition.op = xAND;
+                                combinedCondition.push_back(tempCombinedCondition);
+                                prevCondition = xAND;
+                            }
+                        }
+                            
                     }
-                        
-                }
-                
-                //xOR
-                else if (paramCondition[k].op == xOR){
-                    if (combinedCondition.size() == 0){ // No values so start a new combinedCondition
-                        tempCombinedCondition.value = paramCondition[k].value || paramCondition[k + 1].value; 
-                        tempCombinedCondition.op = xOR;
-                        combinedCondition.push_back(tempCombinedCondition);
-                        prevCondition = xOR;
-                    }
-                    else{
-                         if (combinedCondition.back().op == xOR){ // OR the value to the back most combinedCondition
-                            combinedCondition.back().value = combinedCondition.back().value || paramCondition[k + 1].value;
-                            prevCondition = xOR;
-                        }
-                        else if (combinedCondition.back().op != xOR){ // Start a new combinedCondition
+                    
+                    //xOR
+                    else if (paramCondition[k].op == xOR){
+                        if (combinedCondition.size() == 0){ // No values so start a new combinedCondition
                             tempCombinedCondition.value = paramCondition[k].value || paramCondition[k + 1].value; 
                             tempCombinedCondition.op = xOR;
                             combinedCondition.push_back(tempCombinedCondition);
                             prevCondition = xOR;
                         }
+                        else{
+                             if (combinedCondition.back().op == xOR){ // OR the value to the back most combinedCondition
+                                combinedCondition.back().value = combinedCondition.back().value || paramCondition[k + 1].value;
+                                prevCondition = xOR;
+                            }
+                            else if (combinedCondition.back().op != xOR){ // Start a new combinedCondition
+                                tempCombinedCondition.value = paramCondition[k].value || paramCondition[k + 1].value; 
+                                tempCombinedCondition.op = xOR;
+                                combinedCondition.push_back(tempCombinedCondition);
+                                prevCondition = xOR;
+                            }
+                        }
+                            
                     }
-                        
-                }
-                
-                // Since the k + 1 value is included in the xAND or xOR exclusively, skip checking that value, and add the appropriate AND / OR as the
-                // operator of this exclusive xAND / xOR set
-                if ((paramCondition[k + 1].op == AND || paramCondition[k + 1].op == OR) && (prevCondition == xAND || prevCondition == xOR)){
-                    combinedCondition.back().op = paramCondition[k + 1].op;
-                    k++;
+                    
+                    // Since the k + 1 value is included in the xAND or xOR exclusively, skip checking that value, and add the appropriate AND / OR as the
+                    // operator of this exclusive xAND / xOR set
+                    if ((paramCondition[k + 1].op == AND || paramCondition[k + 1].op == OR) && (prevCondition == xAND || prevCondition == xOR)){
+                        combinedCondition.back().op = paramCondition[k + 1].op;
+                        k++;
+                    }
+                    
                 }
-                
-            }
-       }
+           }            
             
-        
-        // the last value was not included in any combination, since directly before the last value was an xAND / xOR set that
-        // included the very last AND / OR as the set's operator, yet there is still another value that has not been combined, as it is supposed
-        // to be AND /OR to the exclusive xAND / xOR set
-        else if (last && (prevCondition == xAND || prevCondition == xOR) && (combinedCondition.back().op == AND || combinedCondition.back().op == OR)){
-            tempCombinedCondition.value = paramCondition[k].value;
-            tempCombinedCondition.op = NONE; 
-            combinedCondition.push_back(tempCombinedCondition);
+            // the last value was not included in any combination, since directly before the last value was an xAND / xOR set that
+            // included the very last AND / OR as the set's operator, yet there is still another value that has not been combined, as it is supposed
+            // to be AND /OR to the exclusive xAND / xOR set
+            else if (last && (prevCondition == xAND || prevCondition == xOR) && (combinedCondition.back().op == AND || combinedCondition.back().op == OR)){
+                tempCombinedCondition.value = paramCondition[k].value;
+                tempCombinedCondition.op = NONE; 
+                combinedCondition.push_back(tempCombinedCondition);
+            }
         }
         
         //reset the tempCombinedCondition variable
         tempCombinedCondition = ConditionOp();
     }
         
+          
                 
     // run through all values in the combined Condition vector, AND'ing / OR'ing as appropriate
     // in the end, the last value in the array should be the final condition of the Condition statement... whether it was successful or failed
-    for (i = 0; i < (combinedCondition.size() - 1); i++){
-        if (combinedCondition[i].op == AND)
-            combinedCondition[i + 1].value = combinedCondition[i].value && combinedCondition[i + 1].value;
-        else if (combinedCondition[i].op == OR)
-            combinedCondition[i + 1].value = combinedCondition[i].value || combinedCondition[i + 1].value;
+    if (numParam > 1){
+        for (i = 0; i < (combinedCondition.size() - 1); i++){
+            if (combinedCondition[i].op == AND)
+                combinedCondition[i + 1].value = combinedCondition[i].value && combinedCondition[i + 1].value;
+            else if (combinedCondition[i].op == OR)
+                combinedCondition[i + 1].value = combinedCondition[i].value || combinedCondition[i + 1].value;
+        }
     }
     
-    
     //All syntax checking done by this point, if Dummy then return success in order to check the code within the Condition
     if (DummyMode)
         return 0; //Function operated successfully but doesn't return a value
@@ -305,7 +314,7 @@
             
             // check if the first word is an end command (avoids interpreting functions that perform actions)
             if (lineData.word[0].compare("end") == 0)   
-                checkEnd = interpretCommand(selectedFile, lineData);
+                checkEnd = interpretCommand(lineData);
         
             if (checkEnd == 4) // custom return value for this function
                 return 0; //Function operated successfully but doesn't return a value
@@ -319,60 +328,132 @@
     // the program will proceed from the line after the "end condition" line
     return 0; //Function operated successfully but doesn't return a value
 }      
-   
+
 
+   cycleWatch
 /**********************************************************************************************************************************/
 /**********************************************************************************************************************************/
-/**************************                        <FUNCTION: loopCommand>                            *****************************/
+/**************************                       <FUNCTION: cycleCommand>                            *****************************/
 /**********************************************************************************************************************************/
 /**********************************************************************************************************************************/
 
-int loopCommand(FILE *selectedFile, LineData &lineData){
-        
+int loopCommand(LineData &lineData){
+    
+    int thisLoopMain = 0;
+    if (mainLoopFlag == 0){
+        thisLoopMain = 1;
+        mainLoopFlag = 1;
+    }
+    
     //Get the Condition value for number of times to loop
     string loopCondition = lineData.word[1];
     int loopConditionValue = 0;
+    int loopConditionState = 0; //State 1 = device condtition, State 2 = numerical condition
     
-    int numValuesFound = sscanf(loopCondition.c_str(), "%d", &loopConditionValue);
-    if (numValuesFound < 1){
-        ErrorOut("Parameter Unknown, loopCondition Value can't be converted", lineData.lineNumber);
-        return -1;
+    LineData conditionLine;
+    //if the loop is supposed to happen under specific device conditions
+    if (loopCondition.compare("condition") == 0){
+                
+        loopConditionState = 1;
+        
+        //extract the command condition to be checked each loop
+        int i = 2, funcNumWords = 0;
+        for(i = 2; i < lineData.numWords; i++){
+            conditionLine.word[funcNumWords] = lineData.word[i];
+            funcNumWords++;
+        }
+
+        conditionLine.numWords = funcNumWords;
+        conditionLine.lineAddress = lineData.lineAddress;
+        conditionLine.lineNumber = lineData.lineNumber;  
     }
     
+    //if the second word isn't condition, it means it's a number
+    else{
+        loopConditionState = 2;
+        
+        int numValuesFound = sscanf(loopCondition.c_str(), "%d", &loopConditionValue);
+        if (numValuesFound < 1){
+            ErrorOut("Parameter Unknown, loopCondition Value can't be converted", lineData.lineNumber);
+            return -1;
+        }
+        
+        //loop condition must be greater than 0
+        if (loopConditionValue <= 0){
+            ErrorOut("Loop Condition must be greater than 0", lineData.lineNumber);
+            return -1;
+        }
+    }
+    
+
     int loopStartAddress = 0, loopLineNumber = 0, firstLineOfLoop = 1;
         
-    lcd.setAddress(0,0);
-    lcd.printf("Cycle 1 of %d", loopConditionValue);
-        
+    if (thisLoopMain){
+        lcd.setAddress(0,0);
+        lcd.printf("Cycle 1 of %d", loopConditionValue);
+    }
+    
     float totalLoopTime = 0;
     Timer cycleTimer;
     cycleTimer.reset();
     cycleTimer.start();
        
-    int counter = 1, checkEnd = 0, returnValue;
-    while (counter <= loopConditionValue){
+    int counter = 1, checkEnd = 0, returnValue, conditionMet = 0;
+    
+
+    //Before starting the loop, get the state of the device conditions
+    if (loopConditionState == 1){
+        conditionMet = interpretCommand(conditionLine);
+        if (conditionMet == -1)
+            return -1; //if the interpretCommand returned an error, then error out
+            
+        //condition met, so skip to end of loop
+        if (conditionMet == 1){
+            int checkEnd = 0, returnValue = 0;
+            while (checkEnd != 3){
+            
+            returnValue = getNextLine(selectedFile, lineData);
+            
+            //if getNextLine returned an error, then error out
+            if (returnValue == -1)
+                return -1;
+            
+            // check if the first word is an end command (avoids interpreting functions that perform actions)
+            if (lineData.word[0].compare("end") == 0)   
+                checkEnd = interpretCommand(lineData);
+        
+            if (checkEnd == 4) // custom return value for this function
+                return 0; //Function operated successfully but doesn't return a value
+            else if (checkEnd == -1) //if interpretCommand returned an error, then error out
+                return -1;
+            }
+        }
+    }
+
+    
+    while (!conditionMet){
         
         returnValue = getNextLine(selectedFile, lineData); 
-        
+
         //if getNextLine returned an error, then return error out
         if (returnValue == -1)
             return -1;
-                
+
         //Must get the address before entering the interpret command
         // if a Condition command is immediately after, and the condition fails, then
         // the interpret command will return the line at the "end condition" line, and therefore
         // set the loop's first line to be the "end condition" line, if interpretCommand is called BEFORE setting the first loop line address
-        if (firstLineOfLoop){
+        if (firstLineOfLoop){               
             loopStartAddress = lineData.lineAddress; //Save the Line Address
             loopLineNumber = lineData.lineNumber;    //Save the Line Number
             firstLineOfLoop = 0;
         }
-           
-        checkEnd = interpretCommand(selectedFile, lineData);
+
+        checkEnd = interpretCommand(lineData);
 
         //Increase the loop counter and go back to the beginning of the loop
         if (checkEnd == 3){
-            
+
             //All syntax checking done by this point, if Dummy then return success in order to check the code, no need to loop again
             if (DummyMode)
                 return 0; //Function operated successfully but doesn't return a value
@@ -380,32 +461,259 @@
             //Output the Avg Cycle Time
             cycleTimer.stop(); 
             totalLoopTime += cycleTimer.read();
-            
-            lcd.setAddress(0,1);
-            lcd.printf("Avg t(sec): %1.3f", (totalLoopTime / counter));
-            
-            //Output Cycle Number
-            counter++;
-            lcd.setAddress(0,0);
-            lcd.printf("Cycle %d of %d", counter, loopConditionValue);
-            
-            int seekFailure = fseek(selectedFile, loopStartAddress, SEEK_SET); //fseek returns 0 on success
-            if (seekFailure){
-                ErrorOut("In Loop      Failed to seek line", lineData.lineNumber); //Spaces make it look nice on the LCD
-                return -1;
+                  
+                /*  lcd.setAddress(0,2);
+                lcd.printf("TEST: %d", thisLoopMain);
+                wait(2);*/
+                
+            //if (thisLoopMain == 1){
+                
+                lcd.setAddress(0,1);
+                lcd.printf("Avg t(sec): %1.3f", (totalLoopTime / counter));
+                
+                //Output Cycle Number
+                counter++;
+                lcd.setAddress(0,0);
+                lcd.printf("Cycle %d of %d", counter, loopConditionValue);
+                wait(2);
+            //}
+               
+               
+            //Check whether the we should stop looping based on the state that the loop is based on (device conditional / numerical conditional)
+            if (loopConditionState == 1){
+                conditionMet = interpretCommand(conditionLine);
+                if (conditionMet == -1)
+                    return -1; //if the interpretCommand returned an error, then error out
+            }
+            else if (loopConditionState == 2){                
+                if (counter >= loopConditionValue)
+                     conditionMet = 1;
             }
             
+            //if the condition has not been met, then seek back to the beginning of the loop
+            if (!conditionMet){
+                int seekFailure = fseek(selectedFile, loopStartAddress, SEEK_SET); //fseek returns 0 on success
+                if (seekFailure){
+                    ErrorOut("In Loop      Failed to seek line", lineData.lineNumber); //Spaces make it look nice on the LCD
+                    return -1;
+                }
+            }
+
             lineData.lineNumber = loopLineNumber - 1;
             checkEnd = 0;
-            
+        
             //Restart the timer for the next loop
             cycleTimer.reset();
             cycleTimer.start();
+    
         }
-        else if (checkEnd == -1) //if interpretCommand returned an error, then return error out
+        else if (checkEnd == -1){ //if interpretCommand returned an error, then return error out
                 return -1;
+        }
     }
+      
+      
+    //give the "main loop" classification up to the next loop that wants it
+    if (thisLoopMain == 1){
+        thisLoopMain = 0;
+        mainLoopFlag = 0;
+    }
+    
+    return 0; //Return Success, no value is being sent so don't return 1
+ }   
+ 
+ 
+ 
+/**********************************************************************************************************************************/
+/**********************************************************************************************************************************/
+/**************************                        <FUNCTION: loopCommand>                            *****************************/
+/**********************************************************************************************************************************/
+/**********************************************************************************************************************************/
+
+int mainLoopFlag = 0; //so that we only show cycle count for the main loop
+
+int loopCommand(LineData &lineData){
+    
+    int thisLoopMain = 0;
+    if (mainLoopFlag == 0){
+        thisLoopMain = 1;
+        mainLoopFlag = 1;
+    }
+    
+    //Get the Condition value for number of times to loop
+    string loopCondition = lineData.word[1];
+    int loopConditionValue = 0;
+    int loopConditionState = 0; //State 1 = device condtition, State 2 = numerical condition
+    
+    LineData conditionLine;
+    //if the loop is supposed to happen under specific device conditions
+    if (loopCondition.compare("condition") == 0){
                 
+        loopConditionState = 1;
+        
+        //extract the command condition to be checked each loop
+        int i = 2, funcNumWords = 0;
+        for(i = 2; i < lineData.numWords; i++){
+            conditionLine.word[funcNumWords] = lineData.word[i];
+            funcNumWords++;
+        }
+
+        conditionLine.numWords = funcNumWords;
+        conditionLine.lineAddress = lineData.lineAddress;
+        conditionLine.lineNumber = lineData.lineNumber;  
+    }
+    
+    //if the second word isn't condition, it means it's a number
+    else{
+        loopConditionState = 2;
+        
+        int numValuesFound = sscanf(loopCondition.c_str(), "%d", &loopConditionValue);
+        if (numValuesFound < 1){
+            ErrorOut("Parameter Unknown, loopCondition Value can't be converted", lineData.lineNumber);
+            return -1;
+        }
+        
+        //loop condition must be greater than 0
+        if (loopConditionValue <= 0){
+            ErrorOut("Loop Condition must be greater than 0", lineData.lineNumber);
+            return -1;
+        }
+    }
+    
+
+    int loopStartAddress = 0, loopLineNumber = 0, firstLineOfLoop = 1;
+        
+    if (thisLoopMain){
+        lcd.setAddress(0,0);
+        lcd.printf("Cycle 1 of %d", loopConditionValue);
+    }
+    
+    float totalLoopTime = 0;
+    Timer cycleTimer;
+    cycleTimer.reset();
+    cycleTimer.start();
+       
+    int counter = 1, checkEnd = 0, returnValue, conditionMet = 0;
+    
+
+    //Before starting the loop, get the state of the device conditions
+    if (loopConditionState == 1){
+        conditionMet = interpretCommand(conditionLine);
+        if (conditionMet == -1)
+            return -1; //if the interpretCommand returned an error, then error out
+            
+        //condition met, so skip to end of loop
+        if (conditionMet == 1){
+            int checkEnd = 0, returnValue = 0;
+            while (checkEnd != 3){
+            
+            returnValue = getNextLine(selectedFile, lineData);
+            
+            //if getNextLine returned an error, then error out
+            if (returnValue == -1)
+                return -1;
+            
+            // check if the first word is an end command (avoids interpreting functions that perform actions)
+            if (lineData.word[0].compare("end") == 0)   
+                checkEnd = interpretCommand(lineData);
+        
+            if (checkEnd == 4) // custom return value for this function
+                return 0; //Function operated successfully but doesn't return a value
+            else if (checkEnd == -1) //if interpretCommand returned an error, then error out
+                return -1;
+            }
+        }
+    }
+
+    
+    while (!conditionMet){
+        
+        returnValue = getNextLine(selectedFile, lineData); 
+
+        //if getNextLine returned an error, then return error out
+        if (returnValue == -1)
+            return -1;
+
+        //Must get the address before entering the interpret command
+        // if a Condition command is immediately after, and the condition fails, then
+        // the interpret command will return the line at the "end condition" line, and therefore
+        // set the loop's first line to be the "end condition" line, if interpretCommand is called BEFORE setting the first loop line address
+        if (firstLineOfLoop){               
+            loopStartAddress = lineData.lineAddress; //Save the Line Address
+            loopLineNumber = lineData.lineNumber;    //Save the Line Number
+            firstLineOfLoop = 0;
+        }
+
+        checkEnd = interpretCommand(lineData);
+
+        //Increase the loop counter and go back to the beginning of the loop
+        if (checkEnd == 3){
+
+            //All syntax checking done by this point, if Dummy then return success in order to check the code, no need to loop again
+            if (DummyMode)
+                return 0; //Function operated successfully but doesn't return a value
+                
+            //Output the Avg Cycle Time
+            cycleTimer.stop(); 
+            totalLoopTime += cycleTimer.read();
+                  
+                /*  lcd.setAddress(0,2);
+                lcd.printf("TEST: %d", thisLoopMain);
+                wait(2);*/
+                
+            //if (thisLoopMain == 1){
+                
+                lcd.setAddress(0,1);
+                lcd.printf("Avg t(sec): %1.3f", (totalLoopTime / counter));
+                
+                //Output Cycle Number
+                counter++;
+                lcd.setAddress(0,0);
+                lcd.printf("Cycle %d of %d", counter, loopConditionValue);
+                wait(2);
+            //}
+               
+               
+            //Check whether the we should stop looping based on the state that the loop is based on (device conditional / numerical conditional)
+            if (loopConditionState == 1){
+                conditionMet = interpretCommand(conditionLine);
+                if (conditionMet == -1)
+                    return -1; //if the interpretCommand returned an error, then error out
+            }
+            else if (loopConditionState == 2){                
+                if (counter >= loopConditionValue)
+                     conditionMet = 1;
+            }
+            
+            //if the condition has not been met, then seek back to the beginning of the loop
+            if (!conditionMet){
+                int seekFailure = fseek(selectedFile, loopStartAddress, SEEK_SET); //fseek returns 0 on success
+                if (seekFailure){
+                    ErrorOut("In Loop      Failed to seek line", lineData.lineNumber); //Spaces make it look nice on the LCD
+                    return -1;
+                }
+            }
+
+            lineData.lineNumber = loopLineNumber - 1;
+            checkEnd = 0;
+        
+            //Restart the timer for the next loop
+            cycleTimer.reset();
+            cycleTimer.start();
+    
+        }
+        else if (checkEnd == -1){ //if interpretCommand returned an error, then return error out
+                return -1;
+        }
+    }
+      
+      
+    //give the "main loop" classification up to the next loop that wants it
+    if (thisLoopMain == 1){
+        thisLoopMain = 0;
+        mainLoopFlag = 0;
+    }
+    
     return 0; //Return Success, no value is being sent so don't return 1
  }   
 
@@ -415,8 +723,83 @@
 /**********************************************************************************************************************************/
 /**********************************************************************************************************************************/
 
-int interpretCommand(FILE *selectedFile, LineData &lineData){
+int interprettingErrorFlag = 0;
+
+class ErrorCondition{
+    
+    public:
+        LineData errorToWatch;
+        LineData errorFix;    
+        int hasFix;
+};
+
+//vector<ErrorCondition> errorMonitors; //Initialize vector of errors to monitor
+ErrorCondition errorMonitors[5];
+int numErrorsConditions = 0;
+
+
+int interpretCommand(LineData &lineData){
+
+    //Monitors the conditions to watch for erroring, and pauses system if any of the conditions turn out to be true
+    if (!interprettingErrorFlag){
+        int j = 0, error = -1, numError = 0;
+        for(j = 0; j < numErrorsConditions; j++){
+            int checkCondition = 0;
+            
+            interprettingErrorFlag = 1;   
+            checkCondition = interpretCommand(errorMonitors[j].errorToWatch);
+            interprettingErrorFlag = 0;
+
+            //if Condition is true, that means the error occurred
+            if (checkCondition == 1){
+                numError++;
+
+                //if the error has a Fix / Reset command, do it
+                if (errorMonitors[j].hasFix){
+                    int returnValue;
+                    interprettingErrorFlag = 1;
+                    returnValue = interpretCommand(errorMonitors[j].errorFix); //Fix / Reset the error based on how the user justified to do so
+                    interprettingErrorFlag = 0;
+                    if (returnValue == -1)
+                        return -1;
+                }
+                    
+                error = j; //Record index of error, will display only one error, but error will be last error that was true in the list
+            }
+            
+            else if (checkCondition == -1)
+                return -1;
+        }
+      
+        if (numError){
+            char errorMsg[100] = "ERROR!!!       Item: ";
+            strcat(errorMsg, errorMonitors[error].errorToWatch.word[0].c_str()); //Send the first word of the error condition to help find out what the error was
+            ErrorOut(errorMsg, numError);
+            //errorFLAG = 1; //set error flag equal to 1 if error occurred
+
+            //place all devices into the pause functionality
+            int i = 0;
+            for(i = 0; i < devices.size(); i++)
+                devices[i]->pause();
+            
+            //LCD has already been adjusted with the ErrorMonitor function
+            //Simply wait for the user to press select in order to acknowledge the issue and try to fix it
+            while(!buttons.readSel());
+
+            //place all devices into the resume functionality
+            for(i = 0; i < devices.size(); i++)
+                devices[i]->resume();
+            
+            lcd.cls(); //clear the display  
+        }
+    }
+
         
+    
+    /******************************************************************************/
+    /***                        <Functionality: device>                         ***/
+    /******************************************************************************/
+    
     if (lineData.word[0].compare("device") == 0){
 
         int i = 0, deviceFound = -1;
@@ -445,12 +828,85 @@
         }
     }
     
+    
+    
+    /******************************************************************************/
+    /***                     <Functionality: errorWatch>                        ***/
+    /******************************************************************************/
+
+    else if (lineData.word[0].compare("errorWatch") == 0){
+        //line looks like: error, _Condition_, FIX(?), _Command_
+        //create a temp LineData variable to store the correct information of the error Condition (discluding the first "error" keyword  
+        ErrorCondition tempError;
+        LineData tempLine;
+ 
+        int i = 1, funcNumWords = 0;
+        for (i = 1; i < lineData.numWords; i++){    
+            
+            //if the keyword FIX is not this word, than add it to the LineData
+            if (lineData.word[i].compare("FIX") != 0){
+                tempLine.word[funcNumWords] = lineData.word[i];  
+                funcNumWords++;   
+            }     
+            
+            //if the keyword FIX was found, this means there's a FIX / Reset command if the specified error being monitored occurs
+            else if (lineData.word[i].compare("FIX") == 0){
+                tempError.hasFix = 1;
+                
+                //Save the line as the "Error to Watch" value
+                tempLine.numWords = funcNumWords;
+                tempLine.lineAddress = lineData.lineAddress;
+                tempLine.lineNumber = lineData.lineNumber;
+                tempError.errorToWatch = tempLine;
+                
+                //reset lineData and num words for the command / function in order to process the FIX command into the error condition
+                funcNumWords = 0;
+                tempLine = LineData(); //reset tempLine
+            }                
+        }
+        
+        //if the error has a fix, it means that it already process the "Error to Watch" but needs to process the "Error Fix" into the error condition
+        if (tempError.hasFix){
+            //Save the line as the "Error Fix" value
+            tempLine.numWords = funcNumWords;
+            tempLine.lineAddress = lineData.lineAddress;
+            tempLine.lineNumber = lineData.lineNumber;
+            tempError.errorFix = tempLine;
+        }
+        
+        //if the error does not have a fix, that means it still has to process the "Error to Watch" into the error condition
+        else{
+            //Save the line as the "Error to Watch" value
+            tempLine.numWords = funcNumWords;
+            tempLine.lineAddress = lineData.lineAddress;
+            tempLine.lineNumber = lineData.lineNumber;
+            tempError.errorToWatch = tempLine;
+        }
+
+        //if DummyMode, send error Condition to the interpretCommand so that we can check the syntax
+        if (DummyMode){
+            int returnValue1 = interpretCommand(tempError.errorToWatch);
+            int returnValue2 = interpretCommand(tempError.errorFix);
+            if (returnValue1 == -1 || returnValue2 == -1)
+                return -1;
+        }
+  
+        errorMonitors[numErrorsConditions] = tempError;
+        numErrorsConditions++;
+    }
+    
+    
+    /******************************************************************************/
+    /***                        <Functionality: delay>                          ***/
+    /******************************************************************************/
+    
     else if (lineData.word[0].compare("delay") == 0){
         
-        //All syntax checking done by this point, if Dummy then return success in order to check the code, no need wait for a delay
-        if (DummyMode)
-            return 0; //Function operated successfully but doesn't return a value
-            
+        if (lineData.numWords != 2){
+            ErrorOut("Incorrect number of parameters", lineData.lineNumber);
+            return -1;
+        }
+        
         string duration = lineData.word[1];
         int durationValue = 0;
         int numValuesFound = sscanf(duration.c_str(), "%d", &durationValue);
@@ -461,23 +917,139 @@
         }
         
         if (durationValue > 0){
+            
+            //All syntax checking done by this point, if Dummy then return success in order to check the code, no need wait for a delay
+            if (DummyMode)
+                return 0; //Function operated successfully but doesn't return a value
+            
             timer.reset();
             timer.start();
             while (timer.read_ms() < durationValue); //Do Nothing while the timer has not reached the duration
             timer.stop(); //Stop the Timer
         }
         else{
-            ErrorOut("Duration value is less than 0", lineData.lineNumber);
+            ErrorOut("Duration value is less than or equal to 0", lineData.lineNumber);
             return -1;
         }
     }
     
+    /******************************************************************************/
+    /***                        <Functionality: pause>                          ***/
+    /******************************************************************************/
+    
+    else if (lineData.word[0].compare("pause") == 0){
+        
+        if (lineData.numWords != 1){
+            ErrorOut("Incorrect number of parameters", lineData.lineNumber);
+            return -1;
+        }
+        
+        lcd.cls(); //clear the display
+        lcd.setAddress(0,0);
+        lcd.printf("System Pause");
+        lcd.setAddress(0,2);
+        lcd.printf("Line Number: %d", lineData.lineNumber);
+        lcd.setAddress(0,3);
+        lcd.printf("Press Sel to Resume");
+        while(!buttons.readSel());
+    }
+    
+    /******************************************************************************/
+    /***                         <Functionality: GoTo>                          ***/
+    /******************************************************************************/
+    
+    else if (lineData.word[0].compare("GoTo") == 0){
+        
+        if (lineData.word[1].compare("label") == 0){
+            
+            if (lineData.numWords != 3){
+                ErrorOut("Incorrect number of parameters", lineData.lineNumber);
+                return -1;
+            }
+        
+            int labelExists = 0;
+            for(vector<GoToLabel>::iterator it=GoToLabels.begin(); it < GoToLabels.end(); it++){
+                if (lineData.word[1].compare((*it).name) == 0)
+                    labelExists = 1;
+            }
+
+            //if the label does not exist then add it to the vector
+            //if it turned out to exist then do nothing
+            if (!labelExists){
+                GoToLabel tempLabel;
+                tempLabel.name = lineData.word[2];              //Save the Label Name
+                tempLabel.lineAddress = lineData.lineAddress;   //Save the Line Address
+                tempLabel.lineNumber = lineData.lineNumber;     //Save the Line Number
+                GoToLabels.push_back(tempLabel);
+            }
+        }
+        
+        //if the second word was not "label," then it means the word should correspond to an already created GoTo Label
+        else{
+            
+            if (lineData.numWords != 2){
+                ErrorOut("Incorrect number of parameters", lineData.lineNumber);
+                return -1;
+            }  
+            
+            //All syntax checking done by this point, if Dummy then return success in order to check the code
+            //Unable to continue further checking since an aspect of DummyMode run through is to collect the GoTo Label Locations
+            //so that we have them in address
+            if (DummyMode)
+                return 0; //Function operated successfully but doesn't return a value
+                    
+            int i = 0, labelFound = -1;
+            for(i = 0; i < GoToLabels.size(); i++){
+                if (lineData.word[1].compare(GoToLabels[i].name) == 0){
+                    labelFound = i;
+                }
+            }
+            
+            //if the label was not found then error out
+            if (labelFound == -1){
+                ErrorOut("No label     match found in the  system", lineData.lineNumber); //Spaces make it look nice on LCD
+                return -1;   
+            }
+            
+            //if the label was found, then seek to that GoTo position
+            else{
+                                    
+                int seekFailure = fseek(selectedFile, GoToLabels[labelFound].lineAddress, SEEK_SET); //fseek returns 0 on success
+                if (seekFailure){
+                    ErrorOut("In Loop      Failed to seek line", lineData.lineNumber); //Spaces make it look nice on the LCD
+                    return -1;
+                }
+
+                lineData.lineNumber = GoToLabels[labelFound].lineNumber - 1; //set the lineNumber value                
+            }
+        }
+    }
+    
+    /******************************************************************************/
+    /***                         <Functionality: loop>                          ***/
+    /******************************************************************************/
+    
     else if (lineData.word[0].compare("loop") == 0)
-        return loopCommand(selectedFile, lineData); //Process the loop command and return the value that it returns
+        return loopCommand(lineData); //Process the loop command and return the value that it returns
+       
        
+    /******************************************************************************/
+    /***                     <Functionality: condition>                         ***/
+    /******************************************************************************/
     else if (lineData.word[0].compare("condition") == 0)
        return conditionCommand(selectedFile, lineData); //Process the condition command and return the value that it returns
 
+
+    /******************************************************************************/
+    /***                       <Functionality: cycle>                           ***/
+    /******************************************************************************/
+    else if (lineData.word[0].compare("cycle") == 0)
+       return cycleCommand(selectedFile, lineData, 1); //Sending 1 means it's initializing
+       
+       
+    /******************************************************************************/
+    /***                         <Functionality: end>                           ***/
+    /******************************************************************************/
     //end has custom return value for specific functions, since "end" is a common keyword amongst functions
     else if (lineData.word[0].compare("end") == 0){
         if (lineData.word[1].compare("program") == 0)
@@ -486,6 +1058,10 @@
             return 3;
         else if (lineData.word[1].compare("condition") == 0)
             return 4;
+        else if (lineData.word[1].compare("cycle") == 0){
+            checkCycle(selectedFile, lineData, 0) //Sending 0 means it's checking for the ending
+            return 5;
+        } 
         
         else{
             ErrorOut("Unknown function ending", lineData.lineNumber);
@@ -493,9 +1069,18 @@
         }
     }
     
+    /******************************************************************************/
+    /***                 <Functionality: local_name Checking>                   ***/
+    /******************************************************************************/
+    
     //not a keyword so check if it's a localName for a device
     else{
+
     
+//     lcd.setAddress(0,1);
+//            lcd.printf("wrd1: %s", lineData.word[0]);
+//            wait(1);
+            
         int i = 0, deviceFound = -1;
         for (i = 0; i < devices.size(); i++){
             if (lineData.word[0].compare(devices[i]->name) == 0)
@@ -508,6 +1093,8 @@
             return -1;   
         }
         
+        
+        
         //Local Name matches a device, send line to that device in order to process the functionality
         else
             return devices[deviceFound]->interpret(lineData); //call the device specific interpret command, and return the value it returns
@@ -517,6 +1104,8 @@
 }
 
 
+
+
 /**********************************************************************************************************************************/
 /**********************************************************************************************************************************/
 /******************************                        <FUNCTION: main>                            ********************************/
@@ -594,7 +1183,7 @@
     strcat(selectedFileFullName, selectedFileName);
     strcat(selectedFileFullName, ".txt");
     
-    FILE *selectedFile = fopen(selectedFileFullName, "r");
+    selectedFile = fopen(selectedFileFullName, "r");
     
     //Error out of attempt to open the selected file was unsuccessful
     if(selectedFile == NULL) {
@@ -624,10 +1213,25 @@
         if (returnValue == -1)
             error = 1;
             
-        checkEnd = interpretCommand(selectedFile, lineData); //interpret the line data
+        checkEnd = interpretCommand(lineData); //interpret the line data
                 
-        if (checkEnd == 2)
-            endOfFile = 1;
+        if (checkEnd == 2){            
+            //Dummy Mode will be turned on for the first run through, set it to 0 after the first run through,
+            //as the syntax will be checked without erroring, and therefore it is possible to try and run the .txt file
+            //Seek back to beginning of file
+            if (DummyMode){
+                DummyMode = 0;
+                rewind(selectedFile); //seek to the beginning of the file
+                resetLineData(lineData); //Reset the values in the struct that holds the File / Line Data
+                devices.erase(devices.begin(), devices.end()); //remove the devices vector from memory so that we don't duplicate items on the real run through
+                int k = 0;
+                for (k = 0; k < numErrorsConditions; k++)
+                    errorMonitors[k] = ErrorCondition();
+                numErrorsConditions = 0;
+            }
+            else
+                endOfFile = 1;
+        }
         else if (checkEnd == -1) //if interpretCommand returned an error, then return error in main
             error = 1;
             
@@ -639,18 +1243,13 @@
             }
             
             return -1;
-        }
+        }        
+    }
     
-        //Dummy Mode will be turned on for the first run through, set it to 0 after the first run through,
-        //as the syntax will be checked without erroring, and therefore it is possible to try and run the .txt file
-        //Seek back to beginning of file
-        if (DummyMode){
-            DummyMode = 0;
-            rewind(selectedFile); //seek to the beginning of the file
-            resetLineData(lineData); //Reset the values in the struct that holds the File / Line Data
-        }
-    }
-                
+    //Exit the program and remove needed items from memory
+    GoToLabels.erase(GoToLabels.begin(), GoToLabels.end()); //remove the GoToLabels vector from memory
+    devices.erase(devices.begin(), devices.end()); //remove the devices vector from memory
+    
     lcd.cls(); //clear the display   
     lcd.setAddress(0,0);
     lcd.printf("END OF PROGRAM");