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
- Committer:
- mehatfie
- Date:
- 2014-10-01
- Revision:
- 12:2e3e86714243
- Parent:
- 11:bc9cd2869f95
- Child:
- 13:899db9d635e5
File content as of revision 12:2e3e86714243:
#include "mbed.h"
#include "LocalPinNames.h"
#include "BridgeDriver.h"
#include "FrontPanelButtons.h"
#include "TextLCD.h"
#include "SDFileSystem.h"
#include "Initialization.hpp"
//#include "mainFunctions.hpp"
#include "TextFile.h"
#include <stdio.h>
#include <string>
#include <stdlib.h>
#include <fstream>
#include <vector>
using std::string;
FrontPanelButtons buttons(&i2c);
//extern "C" void mbed_reset(); //enable software reset of code
/******************************************************************************/
/*** <Function: resetLineData> ***/
/******************************************************************************/
void resetLineData(LineData &lineData){
lineData.lineNumber = 0;
lineData.numWords = 0;
lineData.lineAddress = 0;
}
/**********************************************************************************************************************************/
/**********************************************************************************************************************************/
/************************ <FUNCTION: cyclePrograms> *****************************/
/**********************************************************************************************************************************/
/**********************************************************************************************************************************/
int cyclePrograms(vector<string> files, int SIZE, int currIndex, int direction){
int nextIndex = 0;
switch(direction){
case 0: //Cycle Back one File
if ((currIndex - 1) < 0)
nextIndex = SIZE - 1;
else
nextIndex = currIndex - 1;
break;
case 1: //Cycle Forward one File
if ((currIndex + 1) >= SIZE)
nextIndex = 0;
else
nextIndex = currIndex + 1;
break;
case -1: //set the selectedFile to the currIndex (used for initialization)
nextIndex = currIndex;
break;
}
//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
wait(.2);
lcd.setAddress(0,3);
lcd.printf("%s", files[nextIndex]);
return nextIndex; // Return the file index in the Array
}
/**********************************************************************************************************************************/
/**********************************************************************************************************************************/
/************************** <FUNCTION: conditionCommand> *****************************/
/**********************************************************************************************************************************/
/**********************************************************************************************************************************/
//Create an enum map of the positble conditions
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
};
int conditionCommand(FILE *selectedFile, LineData &lineData){
//Initialize variables
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......
//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"){
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;
//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
// set the parameters number of Words value to the calculated value
// 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){
param[numParam].numWords = paramNumWords;
paramCondition.push_back(ConditionOp());
if (lineData.word[i].compare("AND") == 0)
paramCondition[numParam].op = AND;
else if (lineData.word[i].compare("xAND") == 0)
paramCondition[numParam].op = xAND;
else if (lineData.word[i].compare("OR") == 0)
paramCondition[numParam].op = OR;
else if (lineData.word[i].compare("xOR") == 0)
paramCondition[numParam].op = xOR;
numParam++; // increase the index of param
paramNumWords = 0; // reset the number of words
}
}
//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(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++){
if (k == numParam - 1)
last = 1;
//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;
}
}
// 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;
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
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++;
}
}
}
// 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
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
int conditionSuccess = combinedCondition.back().value; //value is the success(1) or failure(0) of the condition statement
int checkEnd = 0, returnValue;
if (!conditionSuccess){
while (checkEnd != 4){
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;
}
}
// 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 0; //Function operated successfully but doesn't return a value
}
/**********************************************************************************************************************************/
/**********************************************************************************************************************************/
/************************** <FUNCTION: cycleCommand> *****************************/
/**********************************************************************************************************************************/
/**********************************************************************************************************************************/
Timer cycleTimer;
CycleWatch cycleWatch;
int cycleCommand(LineData &lineData, int cycleState){
// if cycleState is 1, then initialize the cycle
if (cycleState == 1){
//Get the Condition value for number of times to loop
string numCycles = lineData.word[1];
int numValuesFound = sscanf(numCycles.c_str(), "%d", &cycleWatch.numCycles);
if (numValuesFound < 1){
ErrorOut("Parameter Unknown, loopCondition Value can't be converted", lineData.lineNumber);
return -1;
}
//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
//****************//
//Get the person to dynamically select what number of cycles they'd like to do, starting with the read value as the base value
//****************//
lcd.cls(); //clear the display
lcd.setAddress ( 0, 2 );
lcd.printf( "<<ACTION REQUIRED>>" );
lcd.setAddress ( 0, 3 );
lcd.printf( "<Press Sel to start>" );
while (!buttons.readSel()){
if(buttons.readUp() && cycleWatch.numCycles < 999999 ){
cycleWatch.numCycles++;
wait(0.05); //so that the speed of changing the numbers is more controllable, should mean you can move 20 digits per second
}
else if (buttons.readDown() && cycleWatch.numCycles > 0 ){
cycleWatch.numCycles--;
wait(0.05); //so that the speed of changing the numbers is more controllable, should mean you can move 20 digits per second
}
lcd.setAddress ( 0, 0 );
lcd.printf( "<Num Cycles: %d >" , cycleWatch.numCycles );
}
//Initialize the counter variable of the struct, and start the cycle timer
cycleWatch.counter = 0;
cycleTimer.start();
//Update the LCD to display the desired data
lcd.cls(); //clear the display
//Output the Avg Cycle Time
cycleTimer.stop();
cycleWatch.totalCycleTime += cycleTimer.read();
lcd.setAddress(0,1);
lcd.printf("Avg t(sec): 0.000");
//Output Cycle Number
cycleWatch.counter++;
lcd.setAddress(0,0);
lcd.printf("Cycle %d of %d", cycleWatch.counter, cycleWatch.numCycles);
//get the next line in order to get the line address to return to
int returnValue = getNextLine(selectedFile, lineData);
//if getNextLine returned an error, then error out
if (returnValue == -1)
return -1;
//save the staring location of this cycle loop
cycleWatch.startAddress = lineData.lineAddress;
cycleWatch.startLineNumber = lineData.lineNumber;
//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
lineData.lineNumber = cycleWatch.startLineNumber - 1;
int seekFailure = fseek(selectedFile, cycleWatch.startAddress, SEEK_SET); //fseek returns 0 on success
if (seekFailure){
ErrorOut("Init Cycle Failed to seek line", lineData.lineNumber); //Spaces make it look nice on the LCD
return -1;
}
}
// if cycleState is 1, then check for ending conditions
else if (cycleState == 0){
//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();
cycleWatch.totalCycleTime += cycleTimer.read();
lcd.setAddress(0,1);
lcd.printf("Avg t(sec): %1.3f", (cycleWatch.totalCycleTime / cycleWatch.counter));
//Output Cycle Number
cycleWatch.counter++;
lcd.setAddress(0,0);
lcd.printf("Cycle %d of %d", cycleWatch.counter, cycleWatch.numCycles);
if (cycleWatch.counter <= cycleWatch.numCycles){
//seek back to the start of the cycle loop
lineData.lineNumber = cycleWatch.startLineNumber - 1;
int seekFailure = fseek(selectedFile, cycleWatch.startAddress, SEEK_SET); //fseek returns 0 on success
if (seekFailure){
ErrorOut("In Cycle Failed to seek line", lineData.lineNumber); //Spaces make it look nice on the LCD
return -1;
}
//Restart the timer for the next cycle
cycleTimer.reset();
cycleTimer.start();
}
}
return 0; //Return Success, no value is being sent so don't return 1
}
/**********************************************************************************************************************************/
/**********************************************************************************************************************************/
/************************** <FUNCTION: loopCommand> *****************************/
/**********************************************************************************************************************************/
/**********************************************************************************************************************************/
int loopCommand(LineData &lineData){
//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;
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
//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;
}
else if (checkEnd == -1) //if interpretCommand returned an error, then return error out
return -1;
}
return 0; //Return Success, no value is being sent so don't return 1
}
/**********************************************************************************************************************************/
/**********************************************************************************************************************************/
/************************* <FUNCTION: interpretCommand> *************************/
/**********************************************************************************************************************************/
/**********************************************************************************************************************************/
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] = "errorWatch! 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();
cycleTimer.stop(); //pause the cycle timer
//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();
cycleTimer.start(); //start the cycle timer
lcd.cls(); //clear the display
}
}
/******************************************************************************/
/*** <Functionality: device> ***/
/******************************************************************************/
if (lineData.word[0].compare("device") == 0){
int i = 0, deviceFound = -1;
for (i = 0; i < numDevices; i++){
if (lineData.word[2].compare(DeviceNames[i]) == 0){
deviceFound = i;
}
}
//if the device type does not match any known type, error out
if (deviceFound == -1){
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];
//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;
}
}
}
/******************************************************************************/
/*** <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){
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);
if (numValuesFound < 1){
ErrorOut("Parameter Unknown, Duration Value can't be converted", lineData.lineNumber);
return -1;
}
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 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(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(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)
return 2;
else if (lineData.word[1].compare("loop") == 0)
return 3;
else if (lineData.word[1].compare("condition") == 0)
return 4;
else if (lineData.word[1].compare("cycle") == 0){
cycleCommand(lineData, 0); //Sending 0 means it's checking for the ending
return 5;
}
else{
ErrorOut("Unknown function ending", lineData.lineNumber);
return -1;
}
}
/******************************************************************************/
/*** <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)
deviceFound = i;
}
//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){
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
return devices[deviceFound]->interpret(lineData); //call the device specific interpret command, and return the value it returns
}
return 0; //Return Success, no value is being sent so don't return 1
}
/**********************************************************************************************************************************/
/**********************************************************************************************************************************/
/****************************** <FUNCTION: main> ********************************/
/**********************************************************************************************************************************/
/**********************************************************************************************************************************/
int main() {
fullInit(); //Initialize anything that's required to run the code (LCD)
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");
//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);
//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()
}
/******************************************************************************/
/*** <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);
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) {
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");
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> ***/
/******************************************************************************/
resetLineData(lineData); //Reset the values in the struct that holds the File / Line Data
lcd.cls(); //clear the display
int endOfFile = 0, error = 0, returnValue, checkEnd;
DummyMode = 1; //set Dummy Mode equal to 1 to simulate the first run through of the code
while (!endOfFile){
//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(lineData); //interpret the line data
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;
//Before erroring out, turn all devices off so that they power down
if (error){
if (!DummyMode){ //if it is Dummy Mode, then no functionality has actually been turned on, so no need to shut anything off
for(vector<Device*>::iterator it=devices.begin(); it < devices.end(); it++)
(*it)->off();
}
return -1;
}
}
//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");
lcd.setAddress(0,2);
lcd.printf("To Restart...");
lcd.setAddress(0,3);
lcd.printf("Press BACK");
while(!buttons.readBack());
lcd.setAddress(0,1);
//rewind(selectedFile);
}