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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 #include "mbed.h"
00002 #include "LocalPinNames.h"
00003 #include "BridgeDriver.h"
00004 #include "FrontPanelButtons.h"
00005 #include "TextLCD.h"
00006 #include "SDFileSystem.h"
00007 #include "Initialization.hpp"
00008 //#include "mainFunctions.hpp"
00009 #include "TextFile.h"
00010 #include <stdio.h>
00011 #include <string>
00012 #include <stdlib.h>
00013 #include <fstream>
00014 #include <vector>
00015 using std::string;
00016 
00017 FrontPanelButtons buttons(&i2c);
00018 Timer cycleTimer;
00019 CycleWatch cycleWatch;
00020 
00021 //extern "C" void mbed_reset(); //enable software reset of code
00022 
00023 
00024 /******************************************************************************/
00025 /***                      <Function: resetLineData>                         ***/
00026 /******************************************************************************/
00027 
00028 void resetLineData(LineData &lineData){
00029     
00030     lineData.lineNumber = 0;
00031     lineData.numWords = 0;
00032     lineData.lineAddress = 0;
00033 }
00034 
00035 /**********************************************************************************************************************************/
00036 /**********************************************************************************************************************************/
00037 /************************                        <FUNCTION: cyclePrograms>                            *****************************/
00038 /**********************************************************************************************************************************/
00039 /**********************************************************************************************************************************/
00040    
00041 int cyclePrograms(vector<string> files, int SIZE, int currIndex, int direction){
00042     
00043     int nextIndex = 0;
00044     switch(direction){
00045         case 0: //Cycle Back one File
00046             if ((currIndex - 1) < 0)
00047                 nextIndex = SIZE - 1;
00048             else
00049                 nextIndex = currIndex - 1;
00050             break;
00051         case 1: //Cycle Forward one File
00052             if ((currIndex + 1) >= SIZE)
00053                 nextIndex = 0; 
00054             else
00055                 nextIndex = currIndex + 1;
00056             break;
00057         case -1: //set the selectedFile to the currIndex (used for initialization)
00058             nextIndex = currIndex;
00059             break;
00060     }
00061 
00062     //Output file on Display 
00063     lcd.setAddress(0,0);
00064     lcd.printf("                    "); // Clear the Line using Spaces (Emptyness) - Note one line is 20 Characters
00065     lcd.setAddress(0,3);
00066     lcd.printf("                    "); // Clear the Line using Spaces (Emptyness) - Note one line is 20 Characters
00067     wait(.2);
00068     lcd.setAddress(0,3);
00069     lcd.printf("%s", files[nextIndex]);
00070     
00071     return nextIndex; // Return the file index in the Array         
00072 }
00073             
00074     
00075 /**********************************************************************************************************************************/
00076 /**********************************************************************************************************************************/
00077 /**************************                        <FUNCTION: conditionCommand>                            *****************************/
00078 /**********************************************************************************************************************************/
00079 /**********************************************************************************************************************************/
00080 
00081 //Create an enum map of the positble conditions
00082 enum  ConditionType{xAND, AND, xOR, OR, NONE};                                  
00083 
00084 struct ConditionOp{
00085     
00086     int value;          //returned value of the interpret function: 1 = meets criteria, 0 = criteria not met, -1 = failed to interpret
00087     ConditionType op;   //operator that follows the given parameter: x val 2 AND y val 3, if this ConditionOp is for x, then the value will be AND
00088 };
00089 
00090 int conditionCommand(FILE *selectedFile, LineData &lineData){
00091                 
00092     //Initialize variables    
00093     LineData param[15]; // assume no more than 15 conditions will be needed
00094     vector<ConditionOp> paramCondition;
00095     
00096     //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
00097     //this line reads: Condition, data_for_param1, CONDTITION_OP1, data_for_param2, CONDTITION_OP2, data_for_param3......
00098     //Staring index of first data parameter is the 2nd word, therefore 1
00099     int i = 1, numParam = 0, paramNumWords = 0;
00100     for (i = 1; i < lineData.numWords; i++){
00101                        
00102         // if the word is not an AND or an OR, it must mean it's for the specific function
00103         // set the current parameter's next word to be equal to the current word we're checking
00104         // increase number of words that the parameter has
00105         if (lineData.word[i] != "AND" && lineData.word[i] != "xAND" && lineData.word[i] != "OR" && lineData.word[i] != "xOR"){
00106 
00107             param[numParam].word[paramNumWords] = lineData.word[i];
00108             paramNumWords++;
00109             
00110             //if this is the last word in the line....
00111             if(i == (lineData.numWords - 1)){
00112 
00113                 param[numParam].numWords = paramNumWords;
00114                 
00115                 //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
00116                 if (numParam == 0)
00117                     paramCondition.push_back(ConditionOp());
00118                     
00119                 paramCondition[numParam].op = NONE;
00120 
00121                 numParam++;
00122             }            
00123         }
00124             
00125         // if the word is an AND or an OR, it must mean the last function has been completely identified
00126         // set the parameters number of Words value to the calculated value
00127         // increase the number of Parameters (the current parameter function we're filling)
00128         else if (lineData.word[i].compare("AND") == 0 || lineData.word[i].compare("xAND") == 0 || lineData.word[i].compare("OR") == 0 || lineData.word[i].compare("xOR") == 0){
00129             
00130             param[numParam].numWords = paramNumWords;
00131             
00132             paramCondition.push_back(ConditionOp());
00133             if (lineData.word[i].compare("AND") == 0)
00134                 paramCondition[numParam].op = AND;
00135             else if (lineData.word[i].compare("xAND") == 0)
00136                 paramCondition[numParam].op = xAND;
00137             else if (lineData.word[i].compare("OR") == 0)
00138                 paramCondition[numParam].op = OR;
00139             else if (lineData.word[i].compare("xOR") == 0)
00140                 paramCondition[numParam].op = xOR;
00141 
00142             numParam++; // increase the index of param
00143             paramNumWords = 0; // reset the number of words
00144         }    
00145     }
00146     
00147         
00148     //send the data parameters in order to get them interpreted by the appropriate device
00149     //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
00150     int j = 0, k = 0;
00151     for (j = 0; j < numParam; j++){
00152         paramCondition[j].value = interpretCommand(param[j]);
00153         
00154         //error out if the interpretted command returned an error
00155         if (paramCondition[j].value == -1)
00156             return -1;
00157     }
00158 
00159 
00160     //create the combined Condition vector (take care of this xAND and xOR statements and combine them into one so that the whole vector is just AND's and OR's)
00161     //this should make the xAND's / xOR's into a single member of the combinedCondition vector
00162     enum ConditionType prevCondition = NONE; 
00163     vector<ConditionOp> combinedCondition;
00164     ConditionOp tempCombinedCondition;
00165     int first = 1, last = 0;
00166     for (k = 0; k < numParam; k++){
00167 
00168         if (k == numParam - 1)
00169             last = 1;
00170             
00171         //Only one condition to check
00172         if (numParam == 1){
00173             tempCombinedCondition.value = paramCondition[k].value;
00174             tempCombinedCondition.op = NONE; 
00175             combinedCondition.push_back(tempCombinedCondition);        
00176         }
00177         
00178         else{
00179             if (!last){
00180                 if (paramCondition[k].op != xAND && paramCondition[k].op != xOR && paramCondition[k + 1].op != xAND && paramCondition[k + 1].op != xOR){
00181                     //AND
00182                     if (paramCondition[k].op == AND){
00183                         if (!first && prevCondition != xAND && prevCondition != xOR)
00184                             combinedCondition.back().value = combinedCondition.back().value && paramCondition[k + 1].value;
00185                         else if (first || prevCondition == xAND || prevCondition == xOR){
00186                             tempCombinedCondition.value = paramCondition[k].value && paramCondition[k + 1].value; 
00187                             combinedCondition.push_back(tempCombinedCondition);
00188                             first = 0;
00189                         }    
00190                         prevCondition = AND;
00191                     }
00192                     
00193                     //OR
00194                     else if (paramCondition[k].op == OR){
00195                         if (!first && prevCondition != xAND && prevCondition != xOR)
00196                             combinedCondition.back().value = combinedCondition.back().value || paramCondition[k + 1].value;
00197                         else if (first || prevCondition == xAND || prevCondition == xOR){
00198                             tempCombinedCondition.value = paramCondition[k].value || paramCondition[k + 1].value; 
00199                             combinedCondition.push_back(tempCombinedCondition);
00200                             first = 0;
00201                         }    
00202                         prevCondition = OR;
00203                     }
00204                 }
00205                 
00206                 // first value is something, not exclusive, but next values are exclusive
00207                 else if (first && (paramCondition[k].op == AND || paramCondition[k].op == OR) && (paramCondition[k + 1].op == xAND || paramCondition[k + 1].op == xOR)){
00208                     tempCombinedCondition.value = paramCondition[k].value;
00209                     tempCombinedCondition.op = paramCondition[k].op;
00210                     combinedCondition.push_back(tempCombinedCondition);
00211                     prevCondition = paramCondition[k].op;
00212                     first = 0;
00213                 }
00214                 
00215                 else{   
00216                     //xAND
00217                     if (paramCondition[k].op == xAND){
00218                         if (combinedCondition.size() == 0){ // No values so start a new combinedCondition
00219                             tempCombinedCondition.value = paramCondition[k].value && paramCondition[k + 1].value;
00220                             tempCombinedCondition.op = xAND;
00221                             combinedCondition.push_back(tempCombinedCondition);
00222                             prevCondition = xAND;
00223                         }
00224                         else{
00225                              if (combinedCondition.back().op == xAND){ // AND the value to the back most combinedCondition
00226                                 combinedCondition.back().value = combinedCondition.back().value && paramCondition[k + 1].value;
00227                                 prevCondition = xAND;
00228                             }
00229                             else if (combinedCondition.back().op != xAND){ // Start a new combinedCondition
00230                                 tempCombinedCondition.value = paramCondition[k].value && paramCondition[k + 1].value; 
00231                                 tempCombinedCondition.op = xAND;
00232                                 combinedCondition.push_back(tempCombinedCondition);
00233                                 prevCondition = xAND;
00234                             }
00235                         }
00236                             
00237                     }
00238                     
00239                     //xOR
00240                     else if (paramCondition[k].op == xOR){
00241                         if (combinedCondition.size() == 0){ // No values so start a new combinedCondition
00242                             tempCombinedCondition.value = paramCondition[k].value || paramCondition[k + 1].value; 
00243                             tempCombinedCondition.op = xOR;
00244                             combinedCondition.push_back(tempCombinedCondition);
00245                             prevCondition = xOR;
00246                         }
00247                         else{
00248                              if (combinedCondition.back().op == xOR){ // OR the value to the back most combinedCondition
00249                                 combinedCondition.back().value = combinedCondition.back().value || paramCondition[k + 1].value;
00250                                 prevCondition = xOR;
00251                             }
00252                             else if (combinedCondition.back().op != xOR){ // Start a new combinedCondition
00253                                 tempCombinedCondition.value = paramCondition[k].value || paramCondition[k + 1].value; 
00254                                 tempCombinedCondition.op = xOR;
00255                                 combinedCondition.push_back(tempCombinedCondition);
00256                                 prevCondition = xOR;
00257                             }
00258                         }
00259                             
00260                     }
00261                     
00262                     // 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
00263                     // operator of this exclusive xAND / xOR set
00264                     if ((paramCondition[k + 1].op == AND || paramCondition[k + 1].op == OR) && (prevCondition == xAND || prevCondition == xOR)){
00265                         combinedCondition.back().op = paramCondition[k + 1].op;
00266                         k++;
00267                     }
00268                     
00269                 }
00270            }            
00271             
00272             // the last value was not included in any combination, since directly before the last value was an xAND / xOR set that
00273             // 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
00274             // to be AND /OR to the exclusive xAND / xOR set
00275             else if (last && (prevCondition == xAND || prevCondition == xOR) && (combinedCondition.back().op == AND || combinedCondition.back().op == OR)){
00276                 tempCombinedCondition.value = paramCondition[k].value;
00277                 tempCombinedCondition.op = NONE; 
00278                 combinedCondition.push_back(tempCombinedCondition);
00279             }
00280         }
00281         
00282         //reset the tempCombinedCondition variable
00283         tempCombinedCondition = ConditionOp();
00284     }
00285         
00286           
00287                 
00288     // run through all values in the combined Condition vector, AND'ing / OR'ing as appropriate
00289     // in the end, the last value in the array should be the final condition of the Condition statement... whether it was successful or failed
00290     if (numParam > 1){
00291         for (i = 0; i < (combinedCondition.size() - 1); i++){
00292             if (combinedCondition[i].op == AND)
00293                 combinedCondition[i + 1].value = combinedCondition[i].value && combinedCondition[i + 1].value;
00294             else if (combinedCondition[i].op == OR)
00295                 combinedCondition[i + 1].value = combinedCondition[i].value || combinedCondition[i + 1].value;
00296         }
00297     }
00298     
00299     //All syntax checking done by this point, if Dummy then return success in order to check the code within the Condition
00300     if (DummyMode)
00301         return 0; //Function operated successfully but doesn't return a value
00302         
00303         
00304     int conditionSuccess = combinedCondition.back().value; //value is the success(1) or failure(0) of the condition statement
00305 
00306     int checkEnd = 0, returnValue;
00307     if (!conditionSuccess){
00308 
00309         while (checkEnd != 4){
00310             
00311             returnValue = getNextLine(selectedFile, lineData);
00312             
00313             //if getNextLine returned an error, then error out
00314             if (returnValue == -1)
00315                 return -1;
00316             
00317             // check if the first word is an end command (avoids interpreting functions that perform actions)
00318             if (lineData.word[0].compare("end") == 0)   
00319                 checkEnd = interpretCommand(lineData);
00320         
00321             if (checkEnd == 4) // custom return value for this function
00322                 return 0; //Function operated successfully but doesn't return a value
00323             else if (checkEnd == -1) //if interpretCommand returned an error, then error out
00324                 return -1;
00325         }
00326     }
00327     
00328     // Return success as the function either met the condition and will continue from the next line, or
00329     // failed to meet the condition and ran through the lines inside the condition until "end condition" was found, therefore
00330     // the program will proceed from the line after the "end condition" line
00331     return 0; //Function operated successfully but doesn't return a value
00332 }      
00333 
00334 
00335    
00336 /**********************************************************************************************************************************/
00337 /**********************************************************************************************************************************/
00338 /**************************                       <FUNCTION: cycleCommand>                            *****************************/
00339 /**********************************************************************************************************************************/
00340 /**********************************************************************************************************************************/
00341 
00342 int cycleCommand(LineData &lineData, int cycleState){
00343 
00344     // if cycleState is 1, then initialize the cycle
00345     if (cycleState == 1){
00346                 
00347         //Get the Condition value for number of times to loop
00348         string numCycles = lineData.word[1];
00349         int numValuesFound = sscanf(numCycles.c_str(), "%d", &cycleWatch.numCycles);
00350         if (numValuesFound < 1){
00351             ErrorOut("Parameter Unknown, loopCondition Value can't be converted", lineData.lineNumber);
00352             return -1;
00353         }
00354         
00355         
00356         //All syntax checking done by this point, if Dummy then return success in order to check the code, no need to loop again
00357         if (DummyMode)
00358             return 0; //Function operated successfully but doesn't return a value
00359             
00360             
00361         //****************//
00362         //Get the person to dynamically select what number of cycles they'd like to do, starting with the read value as the base value
00363         //****************//
00364         lcd.cls(); //clear the display
00365         lcd.setAddress ( 0, 2 );
00366         lcd.printf( "<<ACTION REQUIRED>>" );
00367         lcd.setAddress ( 0, 3 );
00368         lcd.printf( "<Press Sel to start>" );
00369         while (!buttons.readSel()){
00370             if(buttons.readUp() && cycleWatch.numCycles < 999999 ){
00371                 cycleWatch.numCycles++;
00372                 wait(0.05); //so that the speed of changing the numbers is more controllable, should mean you can move 20 digits per second
00373             }
00374             else if (buttons.readDown() && cycleWatch.numCycles > 0 ){
00375                 cycleWatch.numCycles--;
00376                 wait(0.05); //so that the speed of changing the numbers is more controllable, should mean you can move 20 digits per second
00377             }
00378             lcd.setAddress ( 0, 0 );
00379             lcd.printf( "<Num Cycles: %d >" , cycleWatch.numCycles );
00380         }
00381         
00382         //Initialize the counter variable of the struct, and start the cycle timer
00383         cycleWatch.counter = 0;
00384         cycleTimer.start();
00385         
00386         //Update the LCD to display the desired data
00387         lcd.cls(); //clear the display            
00388         //Output the Avg Cycle Time
00389         cycleTimer.stop(); 
00390         cycleWatch.totalCycleTime += cycleTimer.read();
00391         lcd.setAddress(0,1);
00392         lcd.printf("Avg t(sec): 0.000");
00393         
00394         //Output Cycle Number
00395         cycleWatch.counter++;
00396         lcd.setAddress(0,0);
00397         lcd.printf("Cycle %d of %d", cycleWatch.counter, cycleWatch.numCycles);
00398 
00399 
00400         //get the next line in order to get the line address to return to 
00401         int returnValue = getNextLine(selectedFile, lineData);     
00402         //if getNextLine returned an error, then error out
00403         if (returnValue == -1)
00404             return -1;
00405         
00406         //save the staring location of this cycle loop 
00407         cycleWatch.startAddress = lineData.lineAddress;
00408         cycleWatch.startLineNumber = lineData.lineNumber; 
00409         
00410         //seek back a line, so once this function returns, the next line reteived is that of the next line that should be processed.... basically... so we don't skip a line
00411         lineData.lineNumber = cycleWatch.startLineNumber - 1;
00412         int seekFailure = fseek(selectedFile, cycleWatch.startAddress, SEEK_SET); //fseek returns 0 on success
00413         if (seekFailure){
00414             ErrorOut("Init Cycle    Failed to seek line", lineData.lineNumber); //Spaces make it look nice on the LCD
00415             return -1;
00416         }
00417         
00418         //Restart the timer for the cycle
00419         cycleTimer.reset();
00420         cycleTimer.start();
00421     }
00422     
00423     
00424     
00425     
00426     // if cycleState is 1, then check for ending conditions
00427     else if (cycleState == 0){
00428     
00429         //All syntax checking done by this point, if Dummy then return success in order to check the code, no need to loop again
00430         if (DummyMode)
00431             return 0; //Function operated successfully but doesn't return a value
00432             
00433         //Output the Avg Cycle Time
00434         cycleTimer.stop(); 
00435         cycleWatch.totalCycleTime += cycleTimer.read();
00436         lcd.setAddress(0,1);
00437         lcd.printf("Avg t(sec): %1.3f", (cycleWatch.totalCycleTime / cycleWatch.counter));
00438         
00439         //Output Cycle Number
00440         cycleWatch.counter++;
00441         lcd.setAddress(0,0);
00442         lcd.printf("Cycle %d of %d", cycleWatch.counter, cycleWatch.numCycles);
00443 
00444         
00445         if (cycleWatch.counter <= cycleWatch.numCycles){
00446             
00447             //seek back to the start of the cycle loop
00448             lineData.lineNumber = cycleWatch.startLineNumber - 1;
00449             int seekFailure = fseek(selectedFile, cycleWatch.startAddress, SEEK_SET); //fseek returns 0 on success
00450             if (seekFailure){
00451                 ErrorOut("In Cycle      Failed to seek line", lineData.lineNumber); //Spaces make it look nice on the LCD
00452                 return -1;
00453             }
00454                 
00455             //Restart the timer for the next cycle
00456             cycleTimer.reset();
00457             cycleTimer.start();
00458         }
00459     }
00460     
00461     return 0; //Return Success, no value is being sent so don't return 1
00462  }   
00463  
00464  
00465  
00466 /**********************************************************************************************************************************/
00467 /**********************************************************************************************************************************/
00468 /**************************                        <FUNCTION: loopCommand>                            *****************************/
00469 /**********************************************************************************************************************************/
00470 /**********************************************************************************************************************************/
00471 
00472 int loopCommand(LineData &lineData){
00473     
00474     //Get the Condition value for number of times to loop
00475     string loopCondition = lineData.word[1];
00476     int loopConditionValue = 0;
00477     int loopConditionState = 0; //State 1 = device condtition, State 2 = numerical condition
00478     
00479     LineData conditionLine;
00480     //if the loop is supposed to happen under specific device conditions
00481     if (loopCondition.compare("condition") == 0){
00482                 
00483         loopConditionState = 1;
00484         
00485         //extract the command condition to be checked each loop
00486         int i = 2, funcNumWords = 0;
00487         for(i = 2; i < lineData.numWords; i++){
00488             conditionLine.word[funcNumWords] = lineData.word[i];
00489             funcNumWords++;
00490         }
00491 
00492         conditionLine.numWords = funcNumWords;
00493         conditionLine.lineAddress = lineData.lineAddress;
00494         conditionLine.lineNumber = lineData.lineNumber;  
00495     }
00496     
00497     //if the second word isn't condition, it means it's a number
00498     else{
00499         loopConditionState = 2;
00500         
00501         int numValuesFound = sscanf(loopCondition.c_str(), "%d", &loopConditionValue);
00502         if (numValuesFound < 1){
00503             ErrorOut("Parameter Unknown, loopCondition Value can't be converted", lineData.lineNumber);
00504             return -1;
00505         }
00506         
00507         //loop condition must be greater than 0
00508         if (loopConditionValue <= 0){
00509             ErrorOut("Loop Condition must be greater than 0", lineData.lineNumber);
00510             return -1;
00511         }
00512     }
00513     
00514     
00515     int loopStartAddress = 0, loopLineNumber = 0, firstLineOfLoop = 1;
00516     int counter = 1, checkEnd = 0, returnValue, conditionMet = 0;
00517     
00518 
00519     //Before starting the loop, get the state of the device conditions
00520     if (loopConditionState == 1){
00521         conditionMet = interpretCommand(conditionLine);
00522         if (conditionMet == -1)
00523             return -1; //if the interpretCommand returned an error, then error out
00524             
00525         //condition met, so skip to end of loop
00526         if (conditionMet == 1){
00527             int checkEnd = 0, returnValue = 0;
00528             while (checkEnd != 3){
00529             
00530             returnValue = getNextLine(selectedFile, lineData);
00531             
00532             //if getNextLine returned an error, then error out
00533             if (returnValue == -1)
00534                 return -1;
00535             
00536             // check if the first word is an end command (avoids interpreting functions that perform actions)
00537             if (lineData.word[0].compare("end") == 0)   
00538                 checkEnd = interpretCommand(lineData);
00539         
00540             if (checkEnd == 4) // custom return value for this function
00541                 return 0; //Function operated successfully but doesn't return a value
00542             else if (checkEnd == -1) //if interpretCommand returned an error, then error out
00543                 return -1;
00544             }
00545         }
00546     }
00547 
00548     
00549     while (!conditionMet){
00550         
00551         returnValue = getNextLine(selectedFile, lineData); 
00552 
00553         //if getNextLine returned an error, then return error out
00554         if (returnValue == -1)
00555             return -1;
00556 
00557         //Must get the address before entering the interpret command
00558         // if a Condition command is immediately after, and the condition fails, then
00559         // the interpret command will return the line at the "end condition" line, and therefore
00560         // set the loop's first line to be the "end condition" line, if interpretCommand is called BEFORE setting the first loop line address
00561         if (firstLineOfLoop){               
00562             loopStartAddress = lineData.lineAddress; //Save the Line Address
00563             loopLineNumber = lineData.lineNumber;    //Save the Line Number
00564             firstLineOfLoop = 0;
00565         }
00566 
00567         checkEnd = interpretCommand(lineData);
00568 
00569         //Increase the loop counter and go back to the beginning of the loop
00570         if (checkEnd == 3){
00571 
00572             //All syntax checking done by this point, if Dummy then return success in order to check the code, no need to loop again
00573             if (DummyMode)
00574                 return 0; //Function operated successfully but doesn't return a value
00575                 
00576             //Check whether the we should stop looping based on the state that the loop is based on (device conditional / numerical conditional)
00577             if (loopConditionState == 1){
00578                 conditionMet = interpretCommand(conditionLine);
00579                 if (conditionMet == -1)
00580                     return -1; //if the interpretCommand returned an error, then error out
00581             }
00582             else if (loopConditionState == 2){                
00583                 if (counter >= loopConditionValue)
00584                      conditionMet = 1;
00585             }
00586             
00587             //if the condition has not been met, then seek back to the beginning of the loop
00588             if (!conditionMet){
00589                 int seekFailure = fseek(selectedFile, loopStartAddress, SEEK_SET); //fseek returns 0 on success
00590                 if (seekFailure){
00591                     ErrorOut("In Loop      Failed to seek line", lineData.lineNumber); //Spaces make it look nice on the LCD
00592                     return -1;
00593                 }
00594             }
00595 
00596             lineData.lineNumber = loopLineNumber - 1;
00597             checkEnd = 0;    
00598         }
00599         
00600         else if (checkEnd == -1)  //if interpretCommand returned an error, then return error out
00601                 return -1;
00602     }
00603       
00604     return 0; //Return Success, no value is being sent so don't return 1
00605  }   
00606 
00607 /**********************************************************************************************************************************/
00608 /**********************************************************************************************************************************/
00609 /*************************                        <FUNCTION: interpretCommand>                            *************************/
00610 /**********************************************************************************************************************************/
00611 /**********************************************************************************************************************************/
00612 
00613 int interprettingErrorFlag = 0;
00614 int enableErrors = 0;
00615 
00616 class ErrorCondition{
00617     
00618     public:
00619         LineData errorToWatch;
00620         LineData errorFix;    
00621         int hasFix;
00622 };
00623 
00624 //vector<ErrorCondition> errorMonitors; //Initialize vector of errors to monitor
00625 ErrorCondition errorMonitors[5];
00626 int numErrorsConditions = 0;
00627 
00628 
00629 int interpretCommand(LineData &lineData){
00630         
00631     //Monitor the Kill Switch, pause the system as needed
00632     if(killSw == 1){
00633         //place all devices into the pause functionality
00634         int i = 0;
00635         for(i = 0; i < devices.size(); i++)
00636             devices[i]->pause();
00637         
00638         cycleTimer.stop(); //pause the cycle timer
00639         
00640         //Notify the User of the System Kill
00641         lcd.setAddress(0,3);
00642         lcd.printf("      Killed!       ");
00643     
00644         int flag = 0;
00645         while (flag == 0){
00646             while(killSw == 1);
00647             wait(0.04);
00648             if (killSw == 0)
00649                 flag = 1;
00650         }
00651          
00652         //place all devices into the resume functionality
00653         for(i = 0; i < devices.size(); i++)
00654             devices[i]->resume();
00655         
00656         lcd.setAddress(0,3);
00657         lcd.printf("                    "); // Clear the Line using Spaces (Emptyness) - Note one line is 20 Characters
00658         cycleTimer.start(); //start the cycle timer
00659     }
00660     
00661     
00662     //Monitors the conditions to watch for erroring, and pauses system if any of the conditions turn out to be true
00663     if (!interprettingErrorFlag && enableErrors){
00664         int j = 0, error = -1, numError = 0;
00665         for(j = 0; j < numErrorsConditions; j++){
00666             int checkCondition = 0;
00667             
00668             interprettingErrorFlag = 1;   
00669             checkCondition = interpretCommand(errorMonitors[j].errorToWatch);
00670             interprettingErrorFlag = 0;
00671 
00672             //if Condition is true, that means the error occurred
00673             if (checkCondition == 1){
00674                 numError++;
00675 
00676                 //if the error has a Fix / Reset command, do it
00677                 if (errorMonitors[j].hasFix){
00678                     interprettingErrorFlag = 1;
00679                     int returnValue = interpretCommand(errorMonitors[j].errorFix); //Fix / Reset the error based on how the user justified to do so
00680                     interprettingErrorFlag = 0;
00681                     if (returnValue == -1)
00682                         return -1;
00683                 }
00684                     
00685                 error = j; //Record index of error, will display only one error, but error will be last error that was true in the list
00686             }
00687             
00688             else if (checkCondition == -1)
00689                 return -1;
00690         }
00691       
00692         if (numError){
00693             char errorMsg[100] = "errorWatch!  Item: ";
00694             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
00695             ErrorOut(errorMsg, numError);
00696 
00697             //place all devices into the pause functionality
00698             int i = 0;
00699             for(i = 0; i < devices.size(); i++)
00700                 devices[i]->pause();
00701             
00702             cycleTimer.stop(); //pause the cycle timer
00703             
00704             //LCD has already been adjusted with the ErrorMonitor function
00705             //Simply wait for the user to press select in order to acknowledge the issue and try to fix it
00706             while(!buttons.readSel());
00707                         
00708             //place all devices into the resume functionality
00709             for(i = 0; i < devices.size(); i++)
00710                 devices[i]->resume();
00711             
00712             cycleTimer.start(); //start the cycle timer
00713             
00714             lcd.cls(); //clear the display  
00715         }
00716     }
00717 
00718         
00719     
00720     /******************************************************************************/
00721     /***                        <Functionality: device>                         ***/
00722     /******************************************************************************/
00723     
00724     if (lineData.word[0].compare("device") == 0){
00725 
00726         int i = 0, deviceFound = -1;
00727         for (i = 0; i < numDevices; i++){
00728             if (lineData.word[2].compare(DeviceNames[i]) == 0){
00729                 deviceFound = i;
00730             }
00731         }
00732 
00733         //if the device type does not match any known type, error out
00734         if (deviceFound == -1){
00735             ErrorOut("No device    match found in the  system", lineData.lineNumber); //Spaces make it look nice on LCD
00736             return -1;   
00737         }
00738         
00739         //Add device to the array of devices and initialize it
00740         else{
00741             devices.push_back(Device::newDevice(deviceFound, lineData.word[1], lineData));
00742             devices.back()->name = lineData.word[1];
00743             
00744             //since the constructor cannot return a value, it will trip the error Flag if something is wrong, check that flag, and return error if it has been tripped
00745             if (devices.back()->errorFlag == 1){
00746                 ErrorOut("Error        initializing device", lineData.lineNumber);
00747                 return -1;   
00748             }         
00749         }
00750     }
00751     
00752     
00753     
00754     /******************************************************************************/
00755     /***                     <Functionality: errorWatch>                        ***/
00756     /******************************************************************************/
00757 
00758     else if (lineData.word[0].compare("errorWatch") == 0){
00759         //line looks like: error, _Condition_, FIX(?), _Command_
00760         //create a temp LineData variable to store the correct information of the error Condition (discluding the first "error" keyword  
00761         ErrorCondition tempError = ErrorCondition();
00762         LineData tempLine;
00763  
00764         int i = 1, funcNumWords = 0;
00765         for (i = 1; i < lineData.numWords; i++){    
00766             
00767             //if the keyword FIX is not this word, than add it to the LineData
00768             if (lineData.word[i].compare("FIX") != 0){
00769                 tempLine.word[funcNumWords] = lineData.word[i];  
00770                 funcNumWords++;   
00771             }     
00772             
00773             //if the keyword FIX was found, this means there's a FIX / Reset command if the specified error being monitored occurs
00774             else if (lineData.word[i].compare("FIX") == 0){
00775                 tempError.hasFix = 1;
00776                 
00777                 //Save the line as the "Error to Watch" value
00778                 tempLine.numWords = funcNumWords;
00779                 tempLine.lineAddress = lineData.lineAddress;
00780                 tempLine.lineNumber = lineData.lineNumber;
00781                 tempError.errorToWatch = tempLine;
00782                 
00783                 //reset lineData and num words for the command / function in order to process the FIX command into the error condition
00784                 funcNumWords = 0;
00785                 tempLine = LineData(); //reset tempLine
00786             }                
00787         }
00788         
00789         //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
00790         if (tempError.hasFix == 1){
00791             //Save the line as the "Error Fix" value
00792             tempLine.numWords = funcNumWords;
00793             tempLine.lineAddress = lineData.lineAddress;
00794             tempLine.lineNumber = lineData.lineNumber;
00795             tempError.errorFix = tempLine;
00796         }
00797         
00798         //if the error does not have a fix, that means it still has to process the "Error to Watch" into the error condition
00799         else{
00800             //Save the line as the "Error to Watch" value
00801             tempLine.numWords = funcNumWords;
00802             tempLine.lineAddress = lineData.lineAddress;
00803             tempLine.lineNumber = lineData.lineNumber;
00804             tempError.errorToWatch = tempLine;
00805         }
00806 
00807         //if DummyMode, send error Condition to the interpretCommand so that we can check the syntax
00808         if (DummyMode){
00809             int returnValue1 = interpretCommand(tempError.errorToWatch);
00810 
00811             //if this error has a fix then check the syntax
00812             int returnValue2 = 0;
00813             if (tempError.hasFix)
00814                 returnValue2 = interpretCommand(tempError.errorFix);
00815 
00816             if (returnValue1 == -1 || returnValue2 == -1)
00817                 return -1;
00818         }
00819   
00820         errorMonitors[numErrorsConditions] = tempError;
00821         numErrorsConditions++;
00822     }
00823     
00824     
00825     /******************************************************************************/
00826     /***                        <Functionality: delay>                          ***/
00827     /******************************************************************************/
00828     
00829     else if (lineData.word[0].compare("delay") == 0){
00830         
00831         if (lineData.numWords != 2){
00832             ErrorOut("Incorrect number of parameters", lineData.lineNumber);
00833             return -1;
00834         }
00835         
00836         string duration = lineData.word[1];
00837         int durationValue = 0;
00838         int numValuesFound = sscanf(duration.c_str(), "%d", &durationValue);
00839         
00840         if (numValuesFound < 1){
00841             ErrorOut("Parameter Unknown, Duration Value can't be converted", lineData.lineNumber);
00842             return -1;
00843         }
00844         
00845         if (durationValue > 0){
00846             
00847             //All syntax checking done by this point, if Dummy then return success in order to check the code, no need wait for a delay
00848             if (DummyMode)
00849                 return 0; //Function operated successfully but doesn't return a value
00850             
00851             timer.reset();
00852             timer.start();
00853             while (timer.read_ms() < durationValue); //Do Nothing while the timer has not reached the duration
00854             timer.stop(); //Stop the Timer
00855         }
00856         else{
00857             ErrorOut("Duration value is less than or equal to 0", lineData.lineNumber);
00858             return -1;
00859         }
00860     }
00861     
00862     /******************************************************************************/
00863     /***                        <Functionality: pause>                          ***/
00864     /******************************************************************************/
00865     
00866     else if (lineData.word[0].compare("pause") == 0){
00867         
00868         if (lineData.numWords != 1){
00869             ErrorOut("Incorrect number of parameters", lineData.lineNumber);
00870             return -1;
00871         }
00872         
00873         lcd.cls(); //clear the display
00874         lcd.setAddress(0,0);
00875         lcd.printf("System Pause");
00876         lcd.setAddress(0,2);
00877         lcd.printf("Line Number: %d", lineData.lineNumber);
00878         lcd.setAddress(0,3);
00879         lcd.printf("Press Sel to Resume");
00880         while(!buttons.readSel());
00881     }
00882     
00883     /******************************************************************************/
00884     /***                         <Functionality: GoTo>                          ***/
00885     /******************************************************************************/
00886     
00887     else if (lineData.word[0].compare("GoTo") == 0){
00888         
00889         if (lineData.word[1].compare("label") == 0){
00890             
00891             if (lineData.numWords != 3){
00892                 ErrorOut("Incorrect number of parameters", lineData.lineNumber);
00893                 return -1;
00894             }
00895         
00896             int labelExists = 0;
00897             for(vector<GoToLabel>::iterator it=GoToLabels.begin(); it < GoToLabels.end(); it++){
00898                 if (lineData.word[1].compare((*it).name) == 0)
00899                     labelExists = 1;
00900             }
00901 
00902             //if the label does not exist then add it to the vector
00903             //if it turned out to exist then do nothing
00904             if (!labelExists){
00905                 GoToLabel tempLabel;
00906                 tempLabel.name = lineData.word[2];              //Save the Label Name
00907                 tempLabel.lineAddress = lineData.lineAddress;   //Save the Line Address
00908                 tempLabel.lineNumber = lineData.lineNumber;     //Save the Line Number
00909                 GoToLabels.push_back(tempLabel);
00910             }
00911         }
00912         
00913         //if the second word was not "label," then it means the word should correspond to an already created GoTo Label
00914         else{
00915             
00916             if (lineData.numWords != 2){
00917                 ErrorOut("Incorrect number of parameters", lineData.lineNumber);
00918                 return -1;
00919             }  
00920             
00921             //All syntax checking done by this point, if Dummy then return success in order to check the code
00922             //Unable to continue further checking since an aspect of DummyMode run through is to collect the GoTo Label Locations
00923             //so that we have them in address
00924             if (DummyMode)
00925                 return 0; //Function operated successfully but doesn't return a value
00926                     
00927             int i = 0, labelFound = -1;
00928             for(i = 0; i < GoToLabels.size(); i++){
00929                 if (lineData.word[1].compare(GoToLabels[i].name) == 0){
00930                     labelFound = i;
00931                 }
00932             }
00933             
00934             //if the label was not found then error out
00935             if (labelFound == -1){
00936                 ErrorOut("No label     match found in the  system", lineData.lineNumber); //Spaces make it look nice on LCD
00937                 return -1;   
00938             }
00939             
00940             //if the label was found, then seek to that GoTo position
00941             else{
00942                                     
00943                 int seekFailure = fseek(selectedFile, GoToLabels[labelFound].lineAddress, SEEK_SET); //fseek returns 0 on success
00944                 if (seekFailure){
00945                     ErrorOut("In Loop      Failed to seek line", lineData.lineNumber); //Spaces make it look nice on the LCD
00946                     return -1;
00947                 }
00948 
00949                 lineData.lineNumber = GoToLabels[labelFound].lineNumber - 1; //set the lineNumber value                
00950             }
00951         }
00952     }
00953     
00954     /******************************************************************************/
00955     /***                         <Functionality: loop>                          ***/
00956     /******************************************************************************/
00957     
00958     else if (lineData.word[0].compare("loop") == 0){
00959         enableErrors = 1;
00960         return loopCommand(lineData); //Process the loop command and return the value that it returns
00961    }
00962        
00963     /******************************************************************************/
00964     /***                     <Functionality: condition>                         ***/
00965     /******************************************************************************/
00966     else if (lineData.word[0].compare("condition") == 0){
00967         enableErrors = 1;
00968        return conditionCommand(selectedFile, lineData); //Process the condition command and return the value that it returns
00969     }
00970 
00971     /******************************************************************************/
00972     /***                       <Functionality: cycle>                           ***/
00973     /******************************************************************************/
00974     else if (lineData.word[0].compare("cycle") == 0){
00975         enableErrors = 1;
00976        return cycleCommand(lineData, 1); //Sending 1 means it's initializing
00977    }
00978        
00979     /******************************************************************************/
00980     /***                         <Functionality: end>                           ***/
00981     /******************************************************************************/
00982     //end has custom return value for specific functions, since "end" is a common keyword amongst functions
00983     else if (lineData.word[0].compare("end") == 0){
00984         if (lineData.word[1].compare("program") == 0)
00985             return 2;
00986         else if (lineData.word[1].compare("loop") == 0)
00987             return 3;
00988         else if (lineData.word[1].compare("condition") == 0)
00989             return 4;
00990         else if (lineData.word[1].compare("cycle") == 0){
00991             cycleCommand(lineData, 0); //Sending 0 means it's checking for the ending
00992             return 5;
00993         } 
00994         
00995         else{
00996             ErrorOut("Unknown function ending", lineData.lineNumber);
00997             return -1;
00998         }
00999     }
01000     
01001     /******************************************************************************/
01002     /***                 <Functionality: local_name Checking>                   ***/
01003     /******************************************************************************/
01004     
01005     //not a keyword so check if it's a localName for a device
01006     else{
01007 
01008         int i = 0, deviceFound = -1;
01009         for (i = 0; i < devices.size(); i++){        
01010             if (lineData.word[0].compare(devices[i]->name) == 0)
01011                 deviceFound = i;
01012         }
01013                 
01014         //no device was found that matched the local name, and this is also the last error check, meaning it can match no other potential keywords
01015         if (deviceFound == -1){
01016             ErrorOut("No device    match found in the  system", lineData.lineNumber); //Spaces make it look nice on LCD
01017             return -1;   
01018         }    
01019         
01020         //Local Name matches a device, send line to that device in order to process the functionality
01021         else
01022             return devices[deviceFound]->interpret(lineData); //call the device specific interpret command, and return the value it returns
01023     }  
01024     
01025     return 0; //Return Success, no value is being sent so don't return 1
01026 }
01027 
01028 
01029 
01030 
01031 /**********************************************************************************************************************************/
01032 /**********************************************************************************************************************************/
01033 /******************************                        <FUNCTION: main>                            ********************************/
01034 /**********************************************************************************************************************************/
01035 /**********************************************************************************************************************************/
01036 
01037 int main() {
01038 
01039     fullInit(); //Initialize anything that's required to run the code (LCD)
01040     
01041     LineData lineData;
01042     resetLineData(lineData);
01043 
01044     /******************************************************************************/
01045     /***                 <Get all the Potential Programs>                       ***/
01046     /******************************************************************************/
01047     int numTextFiles = 0;
01048     mkdir("/sd", 0777);
01049     vector<string> textFiles; //Assuming Maximum of 25 txt files will be on the SD Card        
01050     vector<string> filenames = readFileNames("/sd");  
01051     
01052     //Error check whether the SD Card exists and was able to be accessed.... or if there's no files on the SD Card
01053     if (filenames.size() == 0){
01054         ErrorOut("No Files     Found, or Directory can't be accessed", 0); //Spaces make it look nice on LCD
01055         return -1; //End program by returning in the main()
01056     }
01057     
01058     numTextFiles = getFileNamesWithoutExt(textFiles, filenames);
01059     
01060     //Error check whether the SD Card has any txt files in it's first directory
01061     if (numTextFiles == 0){
01062         ErrorOut("No Program   (.txt) Files Found  in first Directory", 0); //Spaces make it look nice on LCD
01063         return -1; //End program by returning in the main()
01064     }
01065     
01066     /******************************************************************************/
01067     /***                   <Select the Program txt File>                        ***/
01068     /******************************************************************************/
01069     int fileSelected = 0, selectedFileIndex = 0;
01070 
01071     lcd.cls(); //clear the display
01072     lcd.setAddress(0,1);
01073     lcd.printf("Select Your Program");
01074     lcd.setAddress(0,2);
01075     lcd.printf("Num Programs = %d", numTextFiles);
01076     
01077     uint8_t lastButState = 0;
01078     lcd.setCursor(TextLCD::CurOn_BlkOn); //turn blinking cursor on
01079 
01080     selectedFileIndex = cyclePrograms(textFiles, numTextFiles, selectedFileIndex, -1); //Initialize the first file to the screen
01081     while(!fileSelected) {
01082         
01083         uint8_t curButState = buttons.readBus();
01084         if(curButState != lastButState){
01085             lastButState = curButState;
01086             if(buttons.readRight())
01087                 selectedFileIndex = cyclePrograms(textFiles, numTextFiles, selectedFileIndex, 1);
01088             else if(buttons.readLeft())
01089                 selectedFileIndex = cyclePrograms(textFiles, numTextFiles, selectedFileIndex, 0);
01090             else if(buttons.readSel())
01091                 fileSelected = 1;
01092         }
01093     }
01094     
01095     lcd.setCursor(TextLCD::CurOn_BlkOff); //turn blinking cursor off
01096     
01097     char selectedFileName[50];
01098     strcpy(selectedFileName, textFiles[selectedFileIndex].c_str());
01099     
01100     /******************************************************************************/
01101     /***                    <Open the Program txt File>                         ***/
01102     /******************************************************************************/
01103     
01104     //Create the string of the full directory and path to the program txt file
01105     char selectedFileFullName[100] = "/sd/";    //Assuming that no directory and file name will be longer than 100 characters
01106     strcat(selectedFileFullName, selectedFileName);
01107     strcat(selectedFileFullName, ".txt");
01108     
01109     selectedFile = fopen(selectedFileFullName, "r");
01110     
01111     //Error out of attempt to open the selected file was unsuccessful
01112     if(selectedFile == NULL) {
01113         ErrorOut("Unable to Open Selected File", 0); //Spaces make it look nice on LCD
01114         return -1; //End program by returning in the main()
01115     }
01116     
01117         
01118     /******************************************************************************/
01119     /***          <Start Running through the Program txt File Lines>            ***/
01120     /******************************************************************************/
01121 while(1){
01122     resetLineData(lineData); //Reset the values in the struct that holds the File / Line Data
01123     lcd.cls(); //clear the display   
01124 
01125     int endOfFile = 0, error = 0, returnValue, checkEnd;
01126     DummyMode = 1; //set Dummy Mode equal to 1 to simulate the first run through of the code 
01127     while (!endOfFile){
01128         
01129         //Re-initialize variables
01130         returnValue = 0;
01131         checkEnd = 0;
01132         
01133         returnValue = getNextLine(selectedFile, lineData); //get the next line of data
01134         
01135         //if getNextLine returned an error, then return error in main
01136         if (returnValue == -1)
01137             error = 1;
01138             
01139         checkEnd = interpretCommand(lineData); //interpret the line data
01140                 
01141         if (checkEnd == 2){            
01142             //Dummy Mode will be turned on for the first run through, set it to 0 after the first run through,
01143             //as the syntax will be checked without erroring, and therefore it is possible to try and run the .txt file
01144             //Seek back to beginning of file
01145             if (DummyMode){
01146                 DummyMode = 0;
01147                 rewind(selectedFile); //seek to the beginning of the file
01148                 resetLineData(lineData); //Reset the values in the struct that holds the File / Line Data
01149                 devices.erase(devices.begin(), devices.end()); //remove the devices vector from memory so that we don't duplicate items on the real run through
01150                 int k = 0;
01151                 for (k = 0; k < numErrorsConditions; k++)
01152                     errorMonitors[k] = ErrorCondition();
01153                 numErrorsConditions = 0;
01154             }
01155             else
01156                 endOfFile = 1;
01157         }
01158         else if (checkEnd == -1) //if interpretCommand returned an error, then return error in main
01159             error = 1;
01160             
01161         //Before erroring out, turn all devices off so that they power down
01162         if (error){
01163             if (!DummyMode){ //if it is Dummy Mode, then no functionality has actually been turned on, so no need to shut anything off
01164                 for(vector<Device*>::iterator it=devices.begin(); it < devices.end(); it++)  
01165                     (*it)->off();
01166             }
01167             
01168             return -1;
01169         }        
01170     }
01171     
01172     //Exit the program and remove needed items from memory
01173     GoToLabels.erase(GoToLabels.begin(), GoToLabels.end()); //remove the GoToLabels vector from memory
01174     devices.erase(devices.begin(), devices.end()); //remove the devices vector from memory
01175     
01176     lcd.cls(); //clear the display   
01177     lcd.setAddress(0,0);
01178     lcd.printf("END OF PROGRAM");
01179     lcd.setAddress(0,2);
01180     lcd.printf("To Restart...");
01181     lcd.setAddress(0,3);
01182     lcd.printf("Cycle Power");
01183     
01184     fclose(selectedFile);
01185     return 1;
01186     
01187     /*while(!buttons.readBack());
01188     rewind(selectedFile);*/
01189 }
01190  } 
01191  
01192