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:
9:5a0c4c6e39c7
Parent:
8:e9f836163229
Child:
10:e8db892fbc52
--- a/main.cpp	Wed Sep 24 01:46:02 2014 +0000
+++ b/main.cpp	Wed Sep 24 22:23:00 2014 +0000
@@ -5,6 +5,7 @@
 #include "TextLCD.h"
 #include "SDFileSystem.h"
 #include "Initialization.hpp"
+//#include "mainFunctions.hpp"
 #include "TextFile.h"
 #include <stdio.h>
 #include <string>
@@ -17,26 +18,26 @@
 
 //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>                            **************************/
-/**********************************************************************************************************************************/
-/**********************************************************************************************************************************/
+/******************************************************************************/
+/***                      <Function: resetLineData>                         ***/
+/******************************************************************************/
+
 void resetLineData(LineData &lineData){
     
-    //lineData.fullLine.clear();
     lineData.lineNumber = 0;
     lineData.numWords = 0;
     lineData.lineAddress = 0;
 }
 
-    
-
 /**********************************************************************************************************************************/
 /**********************************************************************************************************************************/
 /************************                        <FUNCTION: cyclePrograms>                            *****************************/
@@ -82,45 +83,39 @@
 /**********************************************************************************************************************************/
 
 //Create an enum map of the positble conditions
-enum  ConditionType{xAND, AND, xOR, OR, NONE};                              
-//static const enum ConditionType Condition_Map[] = {xAND, AND, xOR, OR};    
+enum  ConditionType{xAND, AND, xOR, OR, NONE};                                  
 
 struct ConditionOp{
     
     int value;          //returned value of the interpret function: 1 = meets criteria, 0 = criteria not met, -1 = failed to interpret
-    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
+    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
 };
 
 int conditionCommand(FILE *selectedFile, LineData &lineData){
         
-    //Get the number of condition parameters 
-    string numConditionVals = lineData.word[1];
-    int numConditionValues = 0;
-    sscanf(numConditionVals.c_str(), "%d", &numConditionValues);
-    
-    //LineData tempLineData;
+    //Initialize variables    
     LineData param[15];
-    //vector<LineData> param;
     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
-    int i = 2, numParam = 0, paramNumWords = 0;
-    for (i = 2; i < lineData.numWords; i++){
+    //this line reads: Condition, data_for_param1, CONDTITION_OP1, data_for_param2, CONDTITION_OP2, data_for_param3......
+    //Staring index of first data parameter is the 2nd word, therefore 1
+    int i = 1, numParam = 0, paramNumWords = 0;
+    for (i = 1; i < lineData.numWords; i++){
                        
         // if the word is not an AND or an OR, it must mean it's for the specific function
         // set the current parameter's next word to be equal to the current word we're checking
         // increase number of words that the parameter has
         if (lineData.word[i] != "AND" && lineData.word[i] != "xAND" && lineData.word[i] != "OR" && lineData.word[i] != "xOR"){
 
-            //tempLineData.word[paramNumWords] = lineData.word[i];
             param[numParam].word[paramNumWords] = lineData.word[i];
             paramNumWords++;
             
             //if this is the last word in the line....
             if(i == (lineData.numWords - 1)){
                 param[numParam].numWords = paramNumWords;
-                 paramCondition[numParam].op = NONE;
+                paramCondition[numParam].op = NONE;
                 numParam++;
             }
             
@@ -131,7 +126,6 @@
         // increase the number of Parameters (the current parameter function we're filling)
         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){
             
-            //tempLineData.numWords = paramNumWords;
             param[numParam].numWords = paramNumWords;
             
             paramCondition.push_back(ConditionOp());
@@ -144,26 +138,29 @@
             else if (lineData.word[i].compare("xOR") == 0)
                 paramCondition[numParam].op = xOR;
 
-            //param.push_back(LineData()); 
-            //param[numParam] = tempLineData;
-            //param.push_back(tempLineData); //add it to the vector list of parameters
-            //tempLineData = LineData(); //reset
             numParam++; // increase the index of param
             paramNumWords = 0; // reset the number of words
         }    
     }
     
-
-    vector<ConditionOp> combinedCondition;
-    ConditionOp tempCombinedCondition;
+    
+    //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]);
+        
+        //error out if the interpretted command returned an error
+        if (paramCondition[j].value == -1)
+            return -1;
     }
 
+
     //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)
     //this should make the xAND's / xOR's into a single member of the combinedCondition vector
     enum ConditionType prevCondition = NONE; 
+    vector<ConditionOp> combinedCondition;
+    ConditionOp tempCombinedCondition;
     int first = 1, last = 0;
     for (k = 0; k < numParam; k++){
 
@@ -289,26 +286,32 @@
 
     int conditionSuccess = combinedCondition.back().value; //value is the success(1) or failure(0) of the condition statement
 
-    int checkEnd = 0;
+    int checkEnd = 0, returnValue;
     if (!conditionSuccess){
 
         while (checkEnd != 4){
             
-            getNextLine(selectedFile, lineData);
+            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(selectedFile, lineData);
         
             if (checkEnd == 4) // custom return value for this function
-                return 0;
+                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;
         }
     }
     
     // Return success as the function either met the condition and will continue from the next line, or
     // failed to meet the condition and ran through the lines inside the condition until "end condition" was found, therefore
     // the program will proceed from the line after the "end condition" line
-    return 1;
+    return 0; //Function operated successfully but doesn't return a value
 }      
    
 
@@ -323,23 +326,32 @@
     //Get the Condition value for number of times to loop
     string loopCondition = lineData.word[1];
     int loopConditionValue = 0;
-    sscanf(loopCondition.c_str(), "%d", &loopConditionValue);
+    
+    int numValuesFound = sscanf(loopCondition.c_str(), "%d", &loopConditionValue);
+    if (numValuesFound < 1){
+        ErrorOut("Parameter Unknown, loopCondition Value can't be converted", lineData.lineNumber);
+        return -1;
+    }
     
     int loopStartAddress = 0, loopLineNumber = 0, firstLineOfLoop = 1;
         
     lcd.setAddress(0,0);
     lcd.printf("Cycle 1 of %d", loopConditionValue);
         
+    float totalLoopTime = 0;
     Timer cycleTimer;
-    float totalLoopTime = 0;
     cycleTimer.reset();
     cycleTimer.start();
        
-    int counter = 1, checkEnd = 0;
+    int counter = 1, checkEnd = 0, returnValue;
     while (counter <= loopConditionValue){
         
-        getNextLine(selectedFile, lineData); 
+        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
@@ -367,17 +379,24 @@
             lcd.setAddress(0,0);
             lcd.printf("Cycle %d of %d", counter, loopConditionValue);
             
-            fseek(selectedFile, loopStartAddress, SEEK_SET);
-            lineData.lineNumber = loopLineNumber - 2;
+            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;
     }
                 
-    return 1;
+    return 0; //Return Success, no value is being sent so don't return 1
  }   
 
 /**********************************************************************************************************************************/
@@ -396,57 +415,66 @@
                 deviceFound = i;
             }
         }
-        
+
         //if the device type does not match any known type, error out
         if (deviceFound == -1){
-            //Error Out since the device Name was not matched with anything *************************   
+            ErrorOut("No device    match found in the  system", lineData.lineNumber); //Spaces make it look nice on LCD
+            return -1;   
         }
         
         //Add device to the array of devices and initialize it
         else{
             devices.push_back(Device::newDevice(deviceFound, lineData.word[1], lineData));
-            devices.back()->name = lineData.word[1];             
+            devices.back()->name = lineData.word[1];
+            
+            //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
+            if (devices.back()->errorFlag == 1){
+                ErrorOut("Error initializing device", lineData.lineNumber);
+                return -1;   
+            }         
         }
     }
     
     else if (lineData.word[0].compare("delay") == 0){
         string duration = lineData.word[1];
         int durationValue = 0;
-        sscanf(duration.c_str(), "%d", &durationValue);
+        int numValuesFound = sscanf(duration.c_str(), "%d", &durationValue);
         
-        if (durationValue){
+        if (numValuesFound < 1){
+            ErrorOut("Parameter Unknown, Duration Value can't be converted", lineData.lineNumber);
+            return -1;
+        }
+        
+        if (durationValue > 0){
             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{
-            //Error Out
+            ErrorOut("Duration value is less than 0", lineData.lineNumber);
             return -1;
         }
     }
     
-    else if (lineData.word[0].compare("loop") == 0){
-        int checkLoopEnd = loopCommand(selectedFile, lineData);
-        if (checkLoopEnd == 1)
-            return 1;
-    }
+    else if (lineData.word[0].compare("loop") == 0)
+        return loopCommand(selectedFile, lineData); //Process the loop command and return the value that it returns
        
-    else if (lineData.word[0].compare("condition") == 0){
-        int checkLoopEnd = conditionCommand(selectedFile, lineData);
-        if (checkLoopEnd == 1)
+    else if (lineData.word[0].compare("condition") == 0)
+       return conditionCommand(selectedFile, lineData); //Process the condition command and return the value that it returns
+
+    //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)
             return 2;
-    }     
-    // end with custom return value for specific function
-    else if (lineData.word[0].compare("end") == 0){
-        if (lineData.word[1].compare("program") == 0){
-            return 2;
-        }
-        else if (lineData.word[1].compare("loop") == 0){
+        else if (lineData.word[1].compare("loop") == 0)
             return 3;
-        }
-        else if (lineData.word[1].compare("condition") == 0){
+        else if (lineData.word[1].compare("condition") == 0)
             return 4;
+        
+        else{
+            ErrorOut("Unknown function ending", lineData.lineNumber);
+            return -1;
         }
     }
     
@@ -461,19 +489,16 @@
                 
         //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
         if (deviceFound == -1){
-            lcd.setAddress(0,3);
-            lcd.printf("Final ERROR!");
-            wait(10);
+            ErrorOut("No device    match found in the  system", lineData.lineNumber); //Spaces make it look nice on LCD
+            return -1;   
         }
         
         //Local Name matches a device, send line to that device in order to process the functionality
-        else{
-            //addDevice(deviceFound);
-            return devices[deviceFound]->interpret(lineData);
-        }
+        else
+            return devices[deviceFound]->interpret(lineData); //call the device specific interpret command, and return the value it returns
     }  
     
-    return -1;
+    return 0; //Return Success, no value is being sent so don't return 1
 }
 
 
@@ -490,92 +515,119 @@
     LineData lineData;
     resetLineData(lineData);
 
-        /******************************************************************************/
-        /***                 <Get all the Potential Programs>                       ***/
-        /******************************************************************************/
-        int numTextFiles = 0;
-        vector<string> textFiles; //Assuming Maximum of 25 txt files will be on the SD Card        
-        vector<string> filenames = readFileNames("/sd");    
-        numTextFiles = getFileNamesWithoutExt(textFiles, filenames);
-            
+    /******************************************************************************/
+    /***                 <Get all the Potential Programs>                       ***/
+    /******************************************************************************/
+    int numTextFiles = 0;
+    vector<string> textFiles; //Assuming Maximum of 25 txt files will be on the SD Card        
+    vector<string> filenames = readFileNames("/sd");  
+    
+    //Error check whether the SD Card exists and was able to be accessed.... or if there's no files on the SD Card
+    if (filenames.size() == 0){
+        ErrorOut("No Files     Found, or Directory can't be accessed", 0); //Spaces make it look nice on LCD
+        return -1; //End program by returning in the main()
+    }
+    
+    numTextFiles = getFileNamesWithoutExt(textFiles, filenames);
     
-        /******************************************************************************/
-        /***                   <Select the Program txt File>                        ***/
-        /******************************************************************************/
-        int fileSelected = 0, selectedFileIndex = 0;
+    //Error check whether the SD Card has any txt files in it's first directory
+    if (numTextFiles == 0){
+        ErrorOut("No Program   (.txt) Files Found  in first Directory", 0); //Spaces make it look nice on LCD
+        return -1; //End program by returning in the main()
+    }
     
-        lcd.cls(); //clear the display
-        lcd.setAddress(0,1);
-        lcd.printf("Select Your Program");
-        lcd.setAddress(0,2);
-        lcd.printf("Num Programs = %d", numTextFiles);
-        
-        uint8_t lastButState = 0;
-        lcd.setCursor(TextLCD::CurOn_BlkOn); //turn blinking cursor on
+    /******************************************************************************/
+    /***                   <Select the Program txt File>                        ***/
+    /******************************************************************************/
+    int fileSelected = 0, selectedFileIndex = 0;
+
+    lcd.cls(); //clear the display
+    lcd.setAddress(0,1);
+    lcd.printf("Select Your Program");
+    lcd.setAddress(0,2);
+    lcd.printf("Num Programs = %d", numTextFiles);
     
-        selectedFileIndex = cyclePrograms(textFiles, numTextFiles, selectedFileIndex, -1); //Initialize the first file to the screen
-        while(!fileSelected) {
-            
-            uint8_t curButState = buttons.readBus();
-            if(curButState != lastButState){
-                lastButState = curButState;
-                if(buttons.readRight())
-                    selectedFileIndex = cyclePrograms(textFiles, numTextFiles, selectedFileIndex, 1);
-                else if(buttons.readLeft())
-                    selectedFileIndex = cyclePrograms(textFiles, numTextFiles, selectedFileIndex, 0);
-                else if(buttons.readSel())
-                    fileSelected = 1;
-            }
-        }
-               
-        char selectedFileName[50];
-        strcpy(selectedFileName, textFiles[selectedFileIndex].c_str());
+    uint8_t lastButState = 0;
+    lcd.setCursor(TextLCD::CurOn_BlkOn); //turn blinking cursor on
+
+    selectedFileIndex = cyclePrograms(textFiles, numTextFiles, selectedFileIndex, -1); //Initialize the first file to the screen
+    while(!fileSelected) {
         
-        /******************************************************************************/
-        /***                    <Open the Program txt File>                         ***/
-        /******************************************************************************/
-        
-        //Create the string of the full directory and path to the program txt file
-        char selectedFileFullName[100] = "/sd/";    //Assuming that no directory and file name will be longer than 100 characters
-        strcat(selectedFileFullName, selectedFileName);
-        strcat(selectedFileFullName, ".txt");
-        
-        FILE *selectedFile = fopen(selectedFileFullName, "r");
-
-        lcd.cls(); //clear the display 
-
-        if(selectedFile == NULL) {
-            lcd.setAddress(0,0);
-            lcd.printf("Invalid");
-            wait(10);
+        uint8_t curButState = buttons.readBus();
+        if(curButState != lastButState){
+            lastButState = curButState;
+            if(buttons.readRight())
+                selectedFileIndex = cyclePrograms(textFiles, numTextFiles, selectedFileIndex, 1);
+            else if(buttons.readLeft())
+                selectedFileIndex = cyclePrograms(textFiles, numTextFiles, selectedFileIndex, 0);
+            else if(buttons.readSel())
+                fileSelected = 1;
         }
+    }
+    
+    lcd.setCursor(TextLCD::CurOn_BlkOff); //turn blinking cursor off
+    
+    char selectedFileName[50];
+    strcpy(selectedFileName, textFiles[selectedFileIndex].c_str());
+    
+    /******************************************************************************/
+    /***                    <Open the Program txt File>                         ***/
+    /******************************************************************************/
+    
+    //Create the string of the full directory and path to the program txt file
+    char selectedFileFullName[100] = "/sd/";    //Assuming that no directory and file name will be longer than 100 characters
+    strcat(selectedFileFullName, selectedFileName);
+    strcat(selectedFileFullName, ".txt");
+    
+    FILE *selectedFile = fopen(selectedFileFullName, "r");
+    
+    //Error out of attempt to open the selected file was unsuccessful
+    if(selectedFile == NULL) {
+        ErrorOut("Unable to Open Selected File", 0); //Spaces make it look nice on LCD
+        return -1; //End program by returning in the main()
+    }
     
         
+    /******************************************************************************/
+    /***          <Start Running through the Program txt File Lines>            ***/
+    /******************************************************************************/
+    
     while(1){  
             
-        resetLineData(lineData);
-        
+        resetLineData(lineData); //Reset the values in the struct that holds the Line Data, in preparation for a new line read
         lcd.cls(); //clear the display   
-        lcd.setAddress(0,0);
-        //lcd.printf("Program: %s", selectedFileName);
 
-        
-        /******************************************************************************/
-        /***          <Start Running through the Program txt File Lines>            ***/
-        /******************************************************************************/
-  
-        int endOfFile = 0;
+        int endOfFile = 0, error = 0, returnValue, checkEnd;
         
         while (!endOfFile){
-        
-            getNextLine(selectedFile, lineData);
-            int checkEnd = interpretCommand(selectedFile, lineData);   
+            
+            //Re-initialize variables
+            returnValue = 0;
+            checkEnd = 0;
+            
+            returnValue = getNextLine(selectedFile, lineData); //get the next line of data
+            
+            //if getNextLine returned an error, then return error in main
+            if (returnValue == -1)
+                error = 1;
+                
+            checkEnd = interpretCommand(selectedFile, lineData); //interpret the line data
                     
             if (checkEnd == 2)
                 endOfFile = 1;
+            else if (checkEnd == -1) //if interpretCommand returned an error, then return error in main
+                error = 1;
+                
+            //Before erroring out, turn all devices off so that they power down
+            if (error){
+                for(vector<Device*>::iterator it=devices.begin(); it < devices.end(); it++)  
+                    (*it)->off();
+                
+                return -1;
+            }
+        
         }
         
-        
         lcd.cls(); //clear the display   
         lcd.setAddress(0,0);
         lcd.printf("END OF PROGRAM");
@@ -592,127 +644,4 @@
 
  } 
  
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
-   
-    /***** Cycle through txt lines and remember last lines ******/
-    /*
-    int running = 0, selectedFile = 0;
-    int locCount = 0, tempSpot = 0;
-    int loc[4];
-    char line[32];
-    uint8_t lastButState;
-    
-    
-    while(1){
-        lcd.setCursor(TextLCD::CurOn_BlkOn); //turn blinking cursor on
-        while(!running) {
-            uint8_t curButState = buttons.readBus();
-    
-            if(curButState != lastButState){
-                switch(lastButState = curButState){
-                    case 0x1F: //right
-                    
-                        loc[locCount] = ftell(fp);
-                        
-                        if (locCount >= 3)
-                            locCount = 0;
-                        else
-                            locCount++;
-                        
-                        //tempSpot = ftell(fp);
-                        fgets(line, 32, fp);
-                        
-                        lcd.setAddress(0,1);
-                        lcd.printf("L: %s", line);
-                        wait(0.2);
-                        break;
-                    case 0x2F: //left
-                    
-                        if (locCount == 0) {
-                            locCount = 3;
-                            fseek(fp, loc[locCount], SEEK_SET);
-                        }
-                        else {
-                            fseek(fp, loc[locCount - 1], SEEK_SET);
-                            locCount--;
-                        }
-                        fgets(line, 32, fp);
-                        lcd.setAddress(0,1);
-                        lcd.printf("L: %s", line);
-                        wait(0.2);
-                        break;
-                }
-            }
-        } 
-    } 
-        */   
-  
-    
-    
-    /******* Select the Program txt File ***********/
-    /*
-    int numTextFiles = 0;
-    string tempTextFiles[25]; //Assuming Maximum of 25 txt files will be on the SD Card
-    lcd.cls(); //clear the display
-    readFileNames("/sd");
-    numTextFiles = getFileNamesWithoutExt(tempTextFiles);
-    
-    string *textFiles = resize_StringArr(tempTextFiles, numTextFiles); //Resize Array
-    //delete [] tempTextFiles; //free previous array
-    
-
-    int running = 0, selectedFile = 0;
-
-    lcd.cls(); //clear the display
-    lcd.setAddress(0,1);
-    lcd.printf("Select Your Program");
-    lcd.setAddress(0,2);
-    lcd.printf("Num Programs = %d", numTextFiles);
-    
-    uint8_t lastButState;
-    while(1){
-        lcd.setCursor(TextLCD::CurOn_BlkOn); //turn blinking cursor on
-        while(!running) {
-            uint8_t curButState = buttons.readBus();
-    
-            if(curButState != lastButState){
-                switch(lastButState = curButState){
-                    case 0x1F: //right
-                        selectedFile = cyclePrograms(textFiles, numTextFiles, selectedFile, 1);
-                        break;
-                    case 0x2F: //left
-                        selectedFile = cyclePrograms(textFiles, numTextFiles, selectedFile, 0);
-                        break;
-                }
-            }
-        }
-    }
-    
-    */
-
-    /*float speed = 0.5;
-    while(1){
-        bridges.drive(1, -1*speed);
-        wait(2);
-        bridges.drive(1, speed);
-        wait(2);
-    }*/
-    
-//BridgeDriver::MOTOR_A
\ No newline at end of file
+ 
\ No newline at end of file