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
Diff: main.cpp
- Revision:
- 11:bc9cd2869f95
- Parent:
- 10:e8db892fbc52
- Child:
- 12:2e3e86714243
diff -r e8db892fbc52 -r bc9cd2869f95 main.cpp --- 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");