Component Test's Software to work with "Universal Controller Box" - Software is an interpreter or "compiler" for programs to be done with a .txt file and read off of the SD Card
Dependencies: BridgeDriver FrontPanelButtons MCP23017 SDFileSystem TextLCD mbed
Revision 11:bc9cd2869f95, committed 2014-10-01
- Comitter:
- mehatfie
- Date:
- Wed Oct 01 18:11:38 2014 +0000
- Parent:
- 10:e8db892fbc52
- Child:
- 12:2e3e86714243
- Commit message:
- - Latest revision is not a working copy, simply publishing all previous working copies to the server
Changed in this revision
--- a/BridgeDriver.lib Wed Sep 24 22:54:36 2014 +0000 +++ b/BridgeDriver.lib Wed Oct 01 18:11:38 2014 +0000 @@ -1,1 +1,1 @@ -http://mbed.org/users/jason701802/code/BridgeDriver/#397718f9300a +http://developer.mbed.org/users/mehatfie/code/BridgeDriver/#397718f9300a
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Devices/CAN_Device.cpp Wed Oct 01 18:11:38 2014 +0000
@@ -0,0 +1,177 @@
+//#include "CAN_Device.hpp"
+//
+////Constructor
+//CAN_Device::CAN_Device(LineData lineData){
+//
+// //Order of Line: Command, Local_Name, CAN_DEVICE, selectedCAN(1,2), freq
+// //Since we can't return from a constructor, instead we'll flip a flag, and check it after we've added the device in interpretCommand
+// if (lineData.numWords != 5)
+// this->errorFlag = 1;
+//
+// string channelstr = lineData.word[3], freqstr = lineData.word[4]; //Parameters are numbers
+// int tempChannel = -1, tempFreq = -1;
+// int numValuesFound = sscanf(channelstr.c_str(), "%d", &tempChannel);
+// if (numValuesFound < 1)
+// this->errorFlag = 1;
+//
+// numValuesFound = sscanf(freqstr.c_str(), "%d", &tempFreq);
+// if (numValuesFound < 1)
+// this->errorFlag = 1;
+//
+// //channel must be either CAN1 or CAN2
+// if (tempChannel == 1 || tempChannel == 2){
+// this->selectedCAN = tempChannel;
+// else
+// this->errorFlag = 1;
+//
+// //should have a frequency greater than 0
+// if (tempFreq > 0)
+// this->freq = tempFreq;
+// else
+// this->errorFlag = 1;
+//}
+//
+//
+//int CAN_Device::getSelectedCAN(){
+// return this->selectedCAN;
+//}
+//
+//int CAN_Device::getFreq(){
+// return this->freq;
+//}
+//
+////A line consists of [ __(Local_Name)__ __(function)__ __(parameter1)__ __(parameter2)__ __(parameter3)__ ... and so on]
+//int CAN_Device::CAN_Device(LineData &lineData){
+//
+// //Order of Line: Local_Name, Function_Name, Param1, Param2, Param3,.......
+// string func = lineData.word[1];
+//
+// /******************************************************************************/
+// /*** <Func: enableBrake> ***/
+// /******************************************************************************/
+// if (func.compare("write") == 0){
+// //line looks like: Local_Name, write, ID_val, byte
+// if (lineData.numWords > 5){
+// ErrorOut("Incorrect number of parameters", lineData.lineNumber);
+// return -1;
+// }
+//
+// //Initialize and Convert Parameters
+// string enable = lineData.word[2];
+// int enableValue = 0;
+//
+// int numValuesFound = sscanf(enable.c_str(), "%d", &enableValue);
+// if (numValuesFound < 1){
+// ErrorOut("Parameter Unknown, enableBrake 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 perform functionality
+// if (DummyMode)
+// return 0; //Function operated successfully but doesn't return a value
+//
+// bridges.enableBraking(getMotor(), enableValue);
+// }
+//
+// /******************************************************************************/
+// /*** <Func: forceBrake> ***/
+// /******************************************************************************/
+// else if (func.compare("forceBrake") == 0){
+//
+// 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, no need to perform functionality
+// if (DummyMode)
+// return 0; //Function operated successfully but doesn't return a value
+//
+// bridges.forceBrake(getMotor());
+// }
+//
+//
+// /******************************************************************************/
+// /*** <Func: drive> ***/
+// /******************************************************************************/
+// else if (func.compare("drive") == 0){
+//
+// if (lineData.numWords != 4){
+// ErrorOut("Incorrect number of parameters", lineData.lineNumber);
+// return -1;
+// }
+//
+// //Initialize Parameters
+// string speed = lineData.word[2];
+// string dir = lineData.word[3];
+//
+// //Initialize Convertion Variables if needed
+// float speedValue;
+// int dirValue = 0;
+//
+// //Convert string to usable values
+// int numValuesFound = sscanf(speed.c_str(), "%f", &speedValue);
+// if (numValuesFound < 1){
+// ErrorOut("Parameter Unknown, speed value can't be converted", lineData.lineNumber);
+// return -1;
+// }
+//
+// //Speed is given as a percentage of 100, so convert it to the value needed for the bridge.drive function
+// speedValue = speedValue / 100;
+//
+//
+// if (speedValue <= 0 && speedValue > 1.0){
+// ErrorOut("Speed Value must be between 0 - 100", lineData.lineNumber);
+// return -1;
+// }
+//
+// if (dir.compare("CC") == 0 || dir.compare("cc") == 0)
+// dirValue = -1; //Turn Clockwise
+// else if (dir.compare("C") == 0 || dir.compare("c") == 0)
+// dirValue = 1; //Turn CounterClockwise
+//
+// else{
+// ErrorOut("Direction Value must be C or CC", 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 perform functionality
+// if (DummyMode)
+// return 0; //Function operated successfully but doesn't return a value
+//
+// bridges.drive(getMotor(), dirValue, speedValue); //Turn on the Motor
+// }
+//
+//
+// /******************************************************************************/
+// /**** <Func: off> ****/
+// /******************************************************************************/
+// else if (func.compare("off") == 0){
+//
+// 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, no need to perform functionality
+// if (DummyMode)
+// return 0; //Function operated successfully but doesn't return a value
+//
+// off();
+// }
+//
+// else {
+// ErrorOut("Unknown Command for Motor Class", lineData.lineNumber);
+// return -1;
+// }
+//
+// return 0; //Return success as 0 since no condition had to be met
+//}
+//
+//
+//
+////For stopping the entire system if an error occurs, can be called from main
+//int CAN_Device::off(void){
+// bridges.drive(getMotor(), 0, 0); //Turn off the Motor
+// return 0;
+//}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Devices/CAN_Device.hpp Wed Oct 01 18:11:38 2014 +0000
@@ -0,0 +1,21 @@
+#ifndef CANDEVICE_HPP
+#define CANDEVICE_HPP
+
+#include "Initialization.hpp"
+
+class CAN_Device: public Device{
+
+ private:
+ int selectedCAN;
+ int freq;
+ vector<CANMessage> messages;
+
+ public:
+ CAN_Device(LineData);
+ int interpret(LineData&);
+ int off();
+ int getSelectedCAN();
+ int getFreq();
+};
+
+#endif
\ No newline at end of file
--- a/Devices/Motor.cpp Wed Sep 24 22:54:36 2014 +0000
+++ b/Devices/Motor.cpp Wed Oct 01 18:11:38 2014 +0000
@@ -79,6 +79,10 @@
return 0; //Function operated successfully but doesn't return a value
bridges.forceBrake(getMotor());
+
+ //Record the settings for Pause and Resume
+ currDir = 0;
+ currSpeed = 0;
}
@@ -131,6 +135,10 @@
return 0; //Function operated successfully but doesn't return a value
bridges.drive(getMotor(), dirValue, speedValue); //Turn on the Motor
+
+ //Record the settings for Pause and Resume
+ currDir = dirValue;
+ currSpeed = speedValue;
}
@@ -164,75 +172,22 @@
//For stopping the entire system if an error occurs, can be called from main
int Motor::off(void){
bridges.drive(getMotor(), 0, 0); //Turn off the Motor
+
+ //Record the settings for Pause and Resume, and exit
+ currDir = 0;
+ currSpeed = 0;
return 0;
}
-/*
-int Motor::enableBrake(){
-
- if (lineData.numWords != 4){
- //Error Check, incorrect number of parameter, error out
- return 0;
- }
-
- //Initialize and Convert Parameters
- char *enable = lineData.word[2];
- int enableValue = atoi(enable);
-
- //If the atoi returned anything besides 0, it worked properly
- if (enableValue)
- bridges.enableBraking(getMotor(), enableValue);
- else{
- //Error Check, incorrect number of parameter, error out
- return 0;
- }
-
- return 1;
+//Stop the motor without changing the previous known settings, so that it will be saved on resume
+int Motor::pause(void){
+ bridges.drive(getMotor(), 0, 0); //Turn off the Motor
+ return 0;
}
-int Motor::forceBrake(){
-
- if (lineData.numWords != 3){
- //Error Check, incorrect number of parameter, error out
- return 0;
- }
-
- bridges.forceBrake(getMotor());
+//Resume the motor using its previously known settings
+int Motor::resume(void){
+ bridges.drive(getMotor(), this->currDir, this->currSpeed); //Resume Motor from it's last known state
+ return 0;
}
-
-int Motor::drive(){
-
- if (lineData.numWords != 4){
- //Error Check, incorrect number of parameter, error out
- return 0;
- }
-
- //Initialize Parameters
- char *speed = lineData.word[2];
- char *dir = lineData.word[3];
-
- //Initialize Convertion Variables if needed
- float speedValue;
- int dirValue = 0;
-
- //Convert string to usable values
- //NOTE both atof and atoi functions return 0 if no valid conversion could be performed
- speedValue = atof(speed) / 100;
-
- if (speedValue <= 0)
- return 0; //Error Out because a value gives no functionality or is wrong
-
- if (strncmp(dir,"CC", 2) == 0 || strncmp(dir,"cc", 2) == 0)
- dirValue = -1; //Turn Clockwise
- else if (strncmp(dir,"C", 1) == 0 || strncmp(dir,"c", 1) == 0)
- dirValue = 1; //Turn CounterClockwise
- else
- return 0; //Error Out since the parameter is incorrect
-
- bridges.drive(getMotor(), dirValue, speedValue); //Turn on the Motor
-}
-*/
-
-
-
\ No newline at end of file
--- a/Devices/Motor.hpp Wed Sep 24 22:54:36 2014 +0000
+++ b/Devices/Motor.hpp Wed Oct 01 18:11:38 2014 +0000
@@ -6,13 +6,16 @@
class Motor: public Device{
private:
- enum BridgeDriver::Motors motor;
-
+ enum BridgeDriver::Motors motor; //Keeps track of which Motor Enum the Motor was initialized to
+ int currDir; //Keeps track of what the current direction of the motor is
+ float currSpeed; //Keeps track of what the current speed of the motor is
public:
Motor(LineData);
int interpret(LineData&);
int off();
enum BridgeDriver::Motors getMotor();
+ int pause();
+ int resume();
//void enableBrake();
//int forceBrake();
//int forceFloat();
--- a/Devices/PinIN.cpp Wed Sep 24 22:54:36 2014 +0000
+++ b/Devices/PinIN.cpp Wed Oct 01 18:11:38 2014 +0000
@@ -143,8 +143,19 @@
return 0; //Function operated successfully but doesn't return a value
//Return one if value meets the wanted pin value, return 0 if it doesn't
- if(signal.read() == checkValue_Value)
- return 1;
+ if(signal.read() == checkValue_Value){
+ //Debounce check to ensure the value is still correct, if incorrect after debounce time, return 0, since it's a false truth
+ if (signal.read() == checkValue_Value){
+ Timer debounceTimer;
+ debounceTimer.reset();
+ debounceTimer.start();
+ while (debounceTimer.read_ms() < 40);
+ if (signal.read() == checkValue_Value)
+ return 1;
+ else
+ return 0;
+ }
+ }
else
return 0;
}
@@ -156,8 +167,3 @@
return 0; //Return success as 0 since no condition had to be met
}
-
-int PinIN::off(void){
- //Do Nothing as you don't need to turn a Pin off
- return 0;
-}
\ No newline at end of file
--- a/Devices/PinIN.hpp Wed Sep 24 22:54:36 2014 +0000
+++ b/Devices/PinIN.hpp Wed Oct 01 18:11:38 2014 +0000
@@ -12,7 +12,9 @@
public:
PinIN(LineData);
int interpret(LineData&);
- int off();
+ int off(){return 0;} //Do Nothing as you don't need to turn a Pin off
+ int pause(){return 0;} //Do Nothing as you don't need to pause a Pin
+ int resume(){return 0;} //Do Nothing as you don't need to resume a Pin
};
#endif
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Devices/TimerDevice.cpp Wed Oct 01 18:11:38 2014 +0000
@@ -0,0 +1,146 @@
+#include "TimerDevice.hpp"
+
+//Constructor
+TimerDevice::TimerDevice(LineData lineData){
+ //No Constructor needed... functionality already exists in mBed library
+}
+
+
+//A line consists of [ __(Local_Name)__ __(function)__ __(parameter1)__ __(parameter2)__ __(parameter3)__ ... and so on]
+int TimerDevice::interpret(LineData &lineData){
+
+
+
+ //Order of line: local_name, function_name, param1, param2, param3,.......
+ string func = lineData.word[1];
+
+ /******************************************************************************/
+ /*** <func: start> ***/
+ /******************************************************************************/
+ if (func.compare("start") == 0){
+
+ 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, no need to perform functionality
+ if (DummyMode)
+ return 0; //Function operated successfully but doesn't return a value
+
+ this->Timer.start();
+ }
+
+
+ /******************************************************************************/
+ /*** <func: stop> ***/
+ /******************************************************************************/
+ else if (func.compare("stop") == 0){
+
+ 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, no need to perform functionality
+ if (DummyMode)
+ return 0; //Function operated successfully but doesn't return a value
+
+ this->Timer.stop();
+ }
+
+ /******************************************************************************/
+ /*** <func: reset> ***/
+ /******************************************************************************/
+ else if (func.compare("reset") == 0){
+
+ 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, no need to perform functionality
+ if (DummyMode)
+ return 0; //Function operated successfully but doesn't return a value
+
+ this->Timer.stop();
+ this->Timer.reset();
+ this->Timer.start();
+ }
+
+ /******************************************************************************/
+ /**** <func: val> ****/
+ /******************************************************************************/
+ else if (func.compare("val") == 0){
+
+ //line looks like: local_name, val, comparison_characteristics (<, >, =)
+ if (lineData.numWords != 4){
+ ErrorOut("Incorrect number of parameters", lineData.lineNumber);
+ return -1;
+ }
+
+ string cmpChar = lineData.word[2]; //Get the comparison characteristic value
+
+ string timestr = lineData.word[3]; //Parameter is a number
+ int timeValue = 0; //Time value to compare in ms
+ int numValuesFound = sscanf(timestr.c_str(), "%d", &timeValue);
+ if (numValuesFound < 1){
+ ErrorOut("Parameter Unknown, time value can't be converted", lineData.lineNumber);
+ return -1;
+ }
+
+ //Error check comparision characteristic
+ if (cmpChar.compare("<") != 0 && cmpChar.compare(">") != 0 && cmpChar.compare("=") != 0){
+ ErrorOut("Parameter Unknown, comparison character 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 perform functionality
+ if (DummyMode)
+ return 0; //Function operated successfully but doesn't return a value
+
+ if (cmpChar.compare("<") == 0){
+ if (this->Timer.read_ms() < timeValue)
+ return 1; //met condition
+ }
+ else if (cmpChar.compare(">") == 0){
+ if (this->Timer.read_ms() > timeValue)
+ return 1; //met condition
+ }
+ else if (cmpChar.compare("=") == 0){
+ if (this->Timer.read_ms() == timeValue)
+ return 1; //met condition
+ }
+
+ }
+
+
+ else {
+ ErrorOut("Unknown Command for Voltage Driver Class", lineData.lineNumber);
+ return -1;
+ }
+
+ return 0; //Return success as 0 since no condition had to be met
+}
+
+
+//For stopping the entire system if an error occurs, can be called from main
+int TimerDevice::off(void){
+ this->Timer.stop();
+ return 0;
+}
+
+
+//Pause the timer
+int TimerDevice::pause(void){
+ this->Timer.stop();
+ return 0;
+}
+
+//Resume the timer
+int TimerDevice::resume(void){
+ this->Timer.start();
+ return 0;
+}
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Devices/TimerDevice.hpp Wed Oct 01 18:11:38 2014 +0000
@@ -0,0 +1,24 @@
+#ifndef TIMERDEVICE_HPP
+#define TIMERDEVICE_HPP
+
+#include "Initialization.hpp"
+
+class TimerDevice: public Device{
+
+ private:
+ Timer Timer;
+
+ public:
+ TimerDevice(LineData);
+ int interpret(LineData&);
+ int off();
+ int getChannel();
+ int pause();
+ int resume();
+ //void enableBrake();
+ //int forceBrake();
+ //int forceFloat();
+ //float drive();
+};
+
+#endif
\ No newline at end of file
--- a/Devices/VoltageDriver.cpp Wed Sep 24 22:54:36 2014 +0000
+++ b/Devices/VoltageDriver.cpp Wed Oct 01 18:11:38 2014 +0000
@@ -1,7 +1,4 @@
#include "VoltageDriver.hpp"
-//#include "mbed.h"
-//#include "LocalPinNames.h"
-//#include "BridgeDriver.h"
//Constructor
VoltageDriver::VoltageDriver(LineData lineData){
@@ -51,7 +48,7 @@
//A line consists of [ __(Local_Name)__ __(function)__ __(parameter1)__ __(parameter2)__ __(parameter3)__ ... and so on]
int VoltageDriver::interpret(LineData &lineData){
-
+
//Order of line: local_name, function_name, param1, param2, param3,.......
string func = lineData.word[1];
@@ -70,6 +67,9 @@
return 0; //Function operated successfully but doesn't return a value
bridges.forceBrake(channel);
+
+ //Record the settings for Pause and Resume
+ currState = 0;
}
@@ -78,17 +78,20 @@
/******************************************************************************/
else if (func.compare("drive") == 0){
//order of line: local_name, drive
-
+
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, no need to perform functionality
if (DummyMode)
return 0; //Function operated successfully but doesn't return a value
-
+
bridges.drive(channel, 1); //turn channel on
+
+ //Record the settings for Pause and Resume
+ currState = 1;
}
@@ -122,6 +125,23 @@
//For stopping the entire system if an error occurs, can be called from main
int VoltageDriver::off(void){
bridges.drive(getChannel(), 0); //turn channel off
+
+ //Record the settings for Pause and Resume, and exit
+ currState = 0;
return 0;
}
+
+//Stop the driver without changing the previous known settings, so that it will be saved on resume
+int VoltageDriver::pause(void){
+ bridges.drive(getChannel(), 0); //turn channel off
+ return 0;
+}
+
+//Resume the driver using its previously known settings
+int VoltageDriver::resume(void){
+ bridges.drive(getChannel(), this->currState); //turn channel off
+ return 0;
+}
+
+
--- a/Devices/VoltageDriver.hpp Wed Sep 24 22:54:36 2014 +0000
+++ b/Devices/VoltageDriver.hpp Wed Oct 01 18:11:38 2014 +0000
@@ -7,12 +7,15 @@
private:
int channel;
+ int currState;
public:
VoltageDriver(LineData);
int interpret(LineData&);
int off();
int getChannel();
+ int pause();
+ int resume();
//void enableBrake();
//int forceBrake();
//int forceFloat();
--- a/Initialization.cpp Wed Sep 24 22:54:36 2014 +0000
+++ b/Initialization.cpp Wed Oct 01 18:11:38 2014 +0000
@@ -2,6 +2,7 @@
#include "Motor.hpp"
#include "VoltageDriver.hpp"
#include "PinIN.hpp"
+#include "TimerDevice.hpp"
/**********************************************************************************************************************************/
@@ -12,7 +13,7 @@
// ADD YOUR DEVICE NAME THE \\EXACT SAME WAY\\ AS THE ENUM NAME YOU DECLARED IN THE.hpp
// Must Declare names in reverse order for some reason...., it's the way they're indexed I believe
-const string DeviceNames[] = {"MOTOR", "VOLTAGE_DRIVER", "PIN_IN"};
+const string DeviceNames[] = {"MOTOR", "VOLTAGE_DRIVER", "PIN_IN", "TIMER_DEVICE", "CAN_DEVICE"};
// ADD YOUR DEVICE TO THE LIST BELOW, CALLING YOUR DEVICE CLASS AS SHOWN
Device* Device::newDevice(int deviceFound, string _name, LineData lineData){
@@ -21,6 +22,7 @@
case MOTOR: return new Motor(lineData); break;
case VOLTAGE_DRIVER: return new VoltageDriver(lineData); break;
case PIN_IN: return new PinIN(lineData); break;
+ case TIMER_DEVICE: return new TimerDevice(lineData); break;
//********** ADD NEXT DEVICE ABOVE **************//
default: break;
@@ -46,8 +48,15 @@
DigitalIn killSw(KILL);
+//Ticker errorWatcher;
+
const int MAX_LINE_LENGTH = 100;
int DummyMode = 0; // run through the code without performing actions
+FILE *selectedFile;
+int errorFLAG = 0;
+
+vector<GoToLabel> GoToLabels; //Initialize vector of struct for GoTo Labels
+CycleWatch cycleWatch;
/******************************************************************************/
/*** <Function Initializations> ***/
@@ -57,6 +66,10 @@
killSw.mode(PullUp);
initLCD();
+
+ //Initialize the Error Watcher Interrupt / Ticker
+ //errorWatcher.attach(&ErrorMonitor, 0.5);
+
}
void initLCD(void) {
@@ -87,4 +100,48 @@
int numDevices = sizeof(DeviceNames)/sizeof(DeviceNames[0]);
int currNumDevices = 0;
-vector<Device*> devices; //create a vector to hold all of the devices
\ No newline at end of file
+vector<Device*> devices; //create a vector to hold all of the devices
+
+
+/******************************************************************************/
+/*** <Error Monitor Initializations> ***/
+/******************************************************************************/
+
+//vector<ErrorCondition> errorMonitors; //Initialize vector of errors to monitor
+//ErrorCondition errorMonitors[15];
+//int numErrorMonitors = 0;
+/*
+//Monitors the conditions to watch for erroring, and pauses system if any of the conditions turn out to be true
+void ErrorMonitor(){
+
+ int i = 0, error = -1, numError = 0;
+ for(i = 0; i < errorMonitors.size(); i++){
+ int checkCondition = 0;
+ checkCondition = interpretCommand(errorMonitors[i].errorToWatch);
+
+ //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[i].hasFix){
+ int returnValue;
+ interpretCommand(errorMonitors[i].errorFix); //Fix / Reset the error based on how the user justified to do so
+ }
+
+ error = i; //Record index of error, will display only one error, but error will be last error that was true in the list
+ }
+ }
+
+ if (numError){
+ char errorMsg[100] = "Error Occurred!!! 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
+ }
+ else
+ errorFLAG = 0; //set error flag equal to 0 if no errors occurred
+
+}
+*/
+
--- a/Initialization.hpp Wed Sep 24 22:54:36 2014 +0000
+++ b/Initialization.hpp Wed Oct 01 18:11:38 2014 +0000
@@ -17,8 +17,8 @@
/**********************************************************************************************************************************/
/**********************************************************************************************************************************/
-enum DeviceType{MOTOR, VOLTAGE_DRIVER, PIN_IN}; //ADD DEVICE NAME
-static const enum DeviceType Device_Map[] = {MOTOR, VOLTAGE_DRIVER, PIN_IN}; //AND HERE ***NOTE TO KEEP SAME ORDER
+enum DeviceType{MOTOR, VOLTAGE_DRIVER, PIN_IN, TIMER_DEVICE, CAN_DEVICE}; //ADD DEVICE NAME
+static const enum DeviceType Device_Map[] = {MOTOR, VOLTAGE_DRIVER, PIN_IN, TIMER_DEVICE, CAN_DEVICE}; //AND HERE ***NOTE TO KEEP SAME ORDER
/************************** <MUST MODIFY> *************************/
/**********************************************************************************************************************************/
@@ -39,8 +39,25 @@
extern DigitalIn killSw;
+//extern Ticker errorWatcher;
+
extern const int MAX_LINE_LENGTH;
extern int DummyMode;
+extern FILE *selectedFile;
+extern int errorFLAG;
+
+/******************************************************************************/
+/*** <Line Data Struct Initializations> ***/
+/******************************************************************************/
+
+struct LineData{
+
+ int lineNumber; //current line number in the program txt file that is running
+ string word[50]; //array of words from the line of text, assuming no more than 50 words will be in any given line
+ //in this initialization there are 15 string (pointers) of size MAX_LINE_LENGTH each
+ int numWords; //Number of words in the given line
+ int lineAddress; //current line address in the SD Card
+};
/******************************************************************************/
/*** <Function Initializations> ***/
@@ -52,25 +69,38 @@
void ErrorOut(string, int); //Outputs error message, line number, and formatting to LCD
+int cyclePrograms(vector<string>, int, int, int);
+
+void resetLineData(LineData &); //reset and all variables of the Line Data Struct
+
+int interpretCommand(LineData &);
+
+int loopCommand(LineData &);
+
/******************************************************************************/
-/*** <Line Data Struct Initializations> ***/
+/*** <GoTo Label Initializations> ***/
/******************************************************************************/
-struct LineData{
-
- //string fullLine; //full line, starting from the beginning
- int lineNumber; //current line number in the program txt file that is running
- //vector<string> word;
- string word[50]; //array of words from the line of text, assuming no more than 50 words will be in any given line
- //in this initialization there are 15 string (pointers) of size MAX_LINE_LENGTH each
- int numWords; //Number of words in the given line
- int lineAddress;
+struct GoToLabel{
+
+ string name; //name of the GoTo Label
+ int lineNumber; //line number of the GoTo Label
+ int lineAddress; //line address of the GoTo Label
};
-//
-//extern struct Line lineData;
+extern vector<GoToLabel> GoToLabels;
+/******************************************************************************/
+/*** <Cycle Struct Initializations> ***/
+/******************************************************************************/
+
+struct CycleWatch{
+
+ int numCycles; //number of cycles to go to
+ int startAddress; //starting address to seek back to on loop
+ int startLineNumber; //starting line number to reset to
+};
/******************************************************************************/
/*** <Parent Device Class Initializations> ***/
@@ -90,9 +120,27 @@
static Device* newDevice(int, string, LineData);
virtual int interpret(LineData&) = 0;
virtual int off() = 0;
+ virtual int pause() = 0;
+ virtual int resume() = 0;
};
-extern vector<Device*> devices; //Initialize array of devices, initially assume 15 devices will be used (will expand as needed)
+extern vector<Device*> devices; //Initialize vector of devices
+/******************************************************************************/
+/*** <Error Monitor Initializations> ***/
+/******************************************************************************/
+/*
+struct ErrorCondition{
+
+ LineData errorToWatch;
+ LineData errorFix;
+ int hasFix;
+};
+
+//extern vector<ErrorCondition> errorMonitors; //Initialize vector of errors to monitor
+extern ErrorCondition errorMonitors[15];
+extern int numErrorMonitors;*/
+//void ErrorMonitor(); //Monitors the conditions to watch for erroring, and pauses system if any of the conditions turn out to be true
+
#endif
\ No newline at end of file
--- a/TextFile.h Wed Sep 24 22:54:36 2014 +0000
+++ b/TextFile.h Wed Oct 01 18:11:38 2014 +0000
@@ -61,8 +61,7 @@
//Cycle through all files listed in the directoy (strings in the vector list)
int n = 0;
- for(vector<string>::iterator it=filenames.begin(); it < filenames.end(); it++)
- {
+ for(vector<string>::iterator it=filenames.begin(); it < filenames.end(); it++){
vector<string> fileName; //filename[0] = filename, filename[1] = extension
@@ -92,39 +91,47 @@
int getNextLine(FILE *selectedFile, LineData &lineData) {
- lineData.lineAddress = ftell(selectedFile);
-
- if (lineData.lineAddress == -1L){
- ErrorOut("Unable to get address of line, SD Card Removed?", lineData.lineNumber + 1);
- return -1;
- }
-
- //char *newLine;
- //getline(selectedFile, newLine);
- char newLine[MAX_LINE_LENGTH];
-
- fgets(newLine, MAX_LINE_LENGTH, selectedFile);
+ int validLine = 0;
+ while (!validLine){
+
+ lineData.lineAddress = ftell(selectedFile);
+
+ if (lineData.lineAddress == -1L){
+ ErrorOut("Unable to get address of line, SD Card Removed?", lineData.lineNumber + 1);
+ return -1;
+ }
+
+ //char *newLine;
+ //getline(selectedFile, newLine);
+ char newLine[MAX_LINE_LENGTH];
+
+ fgets(newLine, MAX_LINE_LENGTH, selectedFile);
+
+ if (newLine == NULL){
+ ErrorOut("Unable to get the next line, SD Card Removed?", lineData.lineNumber + 1);
+ return -1;
+ }
+
+ lineData.lineNumber++; // new line successfully found, increase lineNumber
+
+ //pull out each individual word (separated by any white space), and place it in the vector
+ stringstream newLineStrm(newLine);
+ istream_iterator<string> it(newLineStrm);
+ istream_iterator<string> end;
+ vector<string> results(it, end);
+
+ //Get the size of the results vector, if it is 0 then while loop will loop again,
+ //if it has a value, then it will accept the line and end looping cycles
+ validLine = results.size();
- if (newLine == NULL){
- ErrorOut("Unable to get the next line, SD Card Removed?", lineData.lineNumber + 1);
- return -1;
+ //copy the vector of results into the array of words
+ copy(results.begin(), results.end(), lineData.word);
+
+ lineData.numWords = results.size(); //Record the number of words in the line
+
+ results.erase(results.begin(), results.end()); //remove the results vector from memory
}
- lineData.lineNumber++; // new line successfully found, increase lineNumber
-
- //pull out each individual word (separated by any white space), and place it in the vector
- stringstream newLineStrm(newLine);
- istream_iterator<string> it(newLineStrm);
- istream_iterator<string> end;
- vector<string> results(it, end);
-
- //copy the vector of results into the array of words
- copy(results.begin(), results.end(), lineData.word);
-
- lineData.numWords = results.size(); //Record the number of words in the line
-
- results.erase(results.begin(), results.end()); //remove the results vector from memory
-
//Update the Current Line Number
lcd.setAddress(0,2);
lcd.printf("Current Line#: %d ", lineData.lineNumber);
@@ -134,7 +141,7 @@
lcd.printf(" "); // Clear the Line using Spaces (Emptyness) - Note one line is 20 Characters
lcd.setAddress(0,3);
lcd.printf("cmd/dvc: %s", lineData.word[0]);
-
+
/*
lcd.cls(); //clear the display
lcd.setAddress(0,0);
@@ -145,7 +152,7 @@
lcd.printf("wrd3: %s", lineData.word[2]);
lcd.setAddress(0,3);
lcd.printf("wrd4: %s", lineData.word[3]);
- wait(2);*/
+ wait(1);*/
}
--- 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");