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
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
Generated on Sun Jul 24 2022 01:49:11 by 1.7.2