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-09-23
- Revision:
- 6:d1594fd2ec5a
- Parent:
- 5:e36e0538a903
- Child:
- 7:cca801103b86
File content as of revision 6:d1594fd2ec5a:
#include "mbed.h"
#include "LocalPinNames.h"
#include "BridgeDriver.h"
#include "FrontPanelButtons.h"
#include "TextLCD.h"
#include "SDFileSystem.h"
#include "Initialization.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
int interpretCommand(FILE *, LineData &);
int loopCommand(FILE *, LineData &);
/**********************************************************************************************************************************/
/**********************************************************************************************************************************/
/*************************** <FUNCTION: resetLineData> **************************/
/**********************************************************************************************************************************/
/**********************************************************************************************************************************/
void resetLineData(LineData &lineData){
//lineData.fullLine.clear();
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,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};
//static const enum ConditionType Condition_Map[] = {xAND, AND, xOR, OR};
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){
//Get the number of condition parameters
string numConditionVals = lineData.word[1];
int numConditionValues = 0;
sscanf(numConditionVals.c_str(), "%d", &numConditionValues);
//LineData tempLineData;
LineData param[15];
//vector<LineData> param;
vector<ConditionOp> paramCondition;
//Fill the param Vector with Line structs of each individual device, this way we can send the Line struct to the appropriate interpret function without modification within the function itself
int i = 2, numParam = 0, paramNumWords = 0;
for (i = 2; i < lineData.numWords; i++){
// if the word is not an AND or an OR, it must mean it's for the specific function
// set the current parameter's next word to be equal to the current word we're checking
// increase number of words that the parameter has
if (lineData.word[i] != "AND" && lineData.word[i] != "xAND" && lineData.word[i] != "OR" && lineData.word[i] != "xOR"){
//tempLineData.word[paramNumWords] = lineData.word[i];
param[numParam].word[paramNumWords] = lineData.word[i];
paramNumWords++;
//if this is the last word in the line....
if(i == (lineData.numWords - 1)){
param[numParam].numWords = paramNumWords;
paramCondition[numParam].op = NONE;
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){
//tempLineData.numWords = paramNumWords;
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;
//param.push_back(LineData());
//param[numParam] = tempLineData;
//param.push_back(tempLineData); //add it to the vector list of parameters
//tempLineData = LineData(); //reset
numParam++; // increase the index of param
paramNumWords = 0; // reset the number of words
}
}
vector<ConditionOp> combinedCondition;
ConditionOp tempCombinedCondition;
int j = 0, k = 0;
for (j = 0; j < numParam; j++){
paramCondition[j].value = interpretCommand(selectedFile, param[j]);
}
//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;
int first = 1, last = 0;
for (k = 0; k < numParam; k++){
if (k == numParam - 1)
last = 1;
if (!last && (prevCondition != AND || prevCondition != OR)){
if (paramCondition[k].op != xAND && paramCondition[k].op != xOR && paramCondition[k + 1].op != xAND && paramCondition[k + 1].op != xOR){
lcd.setAddress(0,3);
lcd.printf("Test 0.1 ");
wait(1);
//AND
if (paramCondition[k].op == AND){
lcd.setAddress(0,3);
lcd.printf("Test 1.1 ");
wait(1);
if (!first && prevCondition != xAND && prevCondition != xOR){
lcd.setAddress(0,3);
lcd.printf("Test 1.11 ");
wait(1);
combinedCondition.back().value = combinedCondition.back().value && paramCondition[k + 1].value;
}
else if (first || prevCondition == xAND || prevCondition == xOR){
lcd.setAddress(0,3);
lcd.printf("Test 1.12 ");
wait(1);
tempCombinedCondition.value = paramCondition[k].value && paramCondition[k + 1].value;
combinedCondition.push_back(tempCombinedCondition);
first = 0;
}
prevCondition = AND;
}
//OR
else if (paramCondition[k].op == OR){
lcd.setAddress(0,3);
lcd.printf("Test 1.2 ");
wait(1);
if (!first && prevCondition != xAND && prevCondition != xOR){
lcd.setAddress(0,3);
lcd.printf("Test 1.3 ");
wait(1);
combinedCondition.back().value = combinedCondition.back().value || paramCondition[k + 1].value;
}
else if (first || prevCondition == xAND || prevCondition == xOR){
lcd.setAddress(0,3);
lcd.printf("Test 1.4 ");
wait(1);
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)){
lcd.setAddress(0,3);
lcd.printf("Test 1 ");
wait(1);
tempCombinedCondition.value = paramCondition[k].value;
tempCombinedCondition.op = paramCondition[k].op;
combinedCondition.push_back(tempCombinedCondition);
prevCondition = paramCondition[k].op;
first = 0;
lcd.setAddress(0,3);
lcd.printf("1cCval: %d ", combinedCondition.back().value);
wait(1);
}
else{
/*lcd.setAddress(0,3);
lcd.printf("Test 0.2 ");
wait(1);*/
//xAND
if (paramCondition[k].op == xAND && prevCondition == xAND){
lcd.setAddress(0,3);
lcd.printf("Test 2.1 ");
wait(1);
combinedCondition.back().value = combinedCondition.back().value && paramCondition[k + 1].value;
prevCondition = xAND;
}
else if (paramCondition[k].op == xAND && prevCondition != xAND){
lcd.setAddress(0,3);
lcd.printf("Test 2.2 ");
wait(1);
tempCombinedCondition.value = paramCondition[k].value && paramCondition[k + 1].value;
combinedCondition.push_back(tempCombinedCondition);
prevCondition = xAND;
}
//xOR
else if (paramCondition[k].op == xOR && prevCondition == xOR){
lcd.setAddress(0,3);
lcd.printf("Test 2.3 ");
wait(1);
combinedCondition.back().value = combinedCondition.back().value || paramCondition[k + 1].value;
prevCondition = xOR;
lcd.setAddress(0,3);
lcd.printf("2.3cCval: %d ", combinedCondition.back().value);
wait(1);
}
else if (paramCondition[k].op == xOR && prevCondition != xOR){
lcd.setAddress(0,3);
lcd.printf("Test 2.4 ");
wait(1);
tempCombinedCondition.value = paramCondition[k].value || paramCondition[k + 1].value;
combinedCondition.push_back(tempCombinedCondition);
prevCondition = xOR;
lcd.setAddress(0,3);
lcd.printf("2.4cCval: %d ", combinedCondition.back().value);
wait(1);
}
// 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++;
}
}
}
//else if (last && (prevCondition != AND || prevCondition != OR)){
//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
else if (last && (prevCondition != AND || prevCondition != OR)){
tempCombinedCondition.value = paramCondition[k].value;
tempCombinedCondition.op = NONE;
combinedCondition.push_back(tempCombinedCondition);
}
//reset the tempCombinedCondition variable
tempCombinedCondition = ConditionOp();
}
lcd.setAddress(0,3);
lcd.printf("cCsize: %d ", combinedCondition.size());
wait(1);
// 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;
}
int conditionSuccess = combinedCondition.back().value; //value is the success(1) or failure(0) of the condition statement
int checkEnd = 0;
if (!conditionSuccess){
while (checkEnd != 4){
getNextLine(selectedFile, lineData);
// check if the first word is an end command (avoids interpreting functions that perform actions)
if (lineData.word[0].compare("end") == 0)
checkEnd = interpretCommand(selectedFile, lineData);
if (checkEnd == 4) // custom return value for this function
return 0;
}
}
// Return success as the function either met the condition and will continue from the next line, or
// failed to meet the condition and ran through the lines inside the condition until "end condition" was found, therefore
// the program will proceed from the line after the "end condition" line
return 1;
}
/**********************************************************************************************************************************/
/**********************************************************************************************************************************/
/************************** <FUNCTION: loopCommand> *****************************/
/**********************************************************************************************************************************/
/**********************************************************************************************************************************/
int loopCommand(FILE *selectedFile, LineData &lineData){
//Get the Condition value for number of times to loop
string loopCondition = lineData.word[1];
int loopConditionValue = 0;
sscanf(loopCondition.c_str(), "%d", &loopConditionValue);
int loopStartAddress = 0, loopLineNumber = 0, firstLineOfLoop = 1;
lcd.setAddress(0,0);
lcd.printf("Cycle 1 of %d", loopConditionValue);
Timer cycleTimer;
float totalLoopTime = 0;
cycleTimer.reset();
cycleTimer.start();
int counter = 1, checkEnd = 0;
while (counter <= loopConditionValue){
getNextLine(selectedFile, lineData);
//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(selectedFile, lineData);
//Increase the loop counter and go back to the beginning of the loop
if (checkEnd == 3){
/*cycleTimer.stop();
lcd.setAddress(0,0);
lcd.printf("tLT: %d, tR", cycleTimer.read());
wait(2);*/
//Output the Avg Cycle Time
cycleTimer.stop();
totalLoopTime += cycleTimer.read();
/* lcd.setAddress(0,0);
lcd.printf("tLT: %d, tR", cycleTimer.read());
wait(2);*/
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);
fseek(selectedFile, loopStartAddress, SEEK_SET);
lineData.lineNumber = loopLineNumber - 2;
checkEnd = 0;
//Restart the timer for the next loop
cycleTimer.reset();
cycleTimer.start();
}
}
return 1;
}
/**********************************************************************************************************************************/
/**********************************************************************************************************************************/
/************************* <FUNCTION: interpretCommand> *************************/
/**********************************************************************************************************************************/
/**********************************************************************************************************************************/
int interpretCommand(FILE *selectedFile, LineData &lineData){
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){
//Error Out since the device Name was not matched with anything *************************
}
//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];
}
}
else if (lineData.word[0].compare("delay") == 0){
string duration = lineData.word[1];
int durationValue = 0;
sscanf(duration.c_str(), "%d", &durationValue);
if (durationValue){
timer.reset();
timer.start();
while (timer.read_ms() < durationValue); //Do Nothing while the timer has not reached the duration
timer.stop(); //Stop the Timer
}
else{
//Error Out
return -1;
}
}
else if (lineData.word[0].compare("loop") == 0){
int checkLoopEnd = loopCommand(selectedFile, lineData);
if (checkLoopEnd == 1)
return 1;
}
else if (lineData.word[0].compare("condition") == 0){
int checkLoopEnd = conditionCommand(selectedFile, lineData);
if (checkLoopEnd == 1)
return 2;
}
// end with custom return value for specific function
else if (lineData.word[0].compare("end") == 0){
if (lineData.word[1].compare("program") == 0){
return 2;
}
else if (lineData.word[1].compare("loop") == 0){
return 3;
}
else if (lineData.word[1].compare("condition") == 0){
return 4;
}
}
//not a keyword so check if it's a localName for a device
else{
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){
lcd.setAddress(0,3);
lcd.printf("Final ERROR!");
wait(10);
}
//Local Name matches a device, send line to that device in order to process the functionality
else{
//addDevice(deviceFound);
return devices[deviceFound]->interpret(lineData);
}
}
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");
numTextFiles = getFileNamesWithoutExt(textFiles, filenames);
/******************************************************************************/
/*** <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;
}
}
char selectedFileName[50];
strcpy(selectedFileName, textFiles[selectedFileIndex].c_str());
/******************************************************************************/
/*** <Open the Program txt File> ***/
/******************************************************************************/
//Create the string of the full directory and path to the program txt file
char selectedFileFullName[100] = "/sd/"; //Assuming that no directory and file name will be longer than 100 characters
strcat(selectedFileFullName, selectedFileName);
strcat(selectedFileFullName, ".txt");
FILE *selectedFile = fopen(selectedFileFullName, "r");
lcd.cls(); //clear the display
if(selectedFile == NULL) {
lcd.setAddress(0,0);
lcd.printf("Invalid");
wait(10);
}
while(1){
resetLineData(lineData);
lcd.cls(); //clear the display
lcd.setAddress(0,0);
//lcd.printf("Program: %s", selectedFileName);
/******************************************************************************/
/*** <Start Running through the Program txt File Lines> ***/
/******************************************************************************/
int endOfFile = 0;
while (!endOfFile){
getNextLine(selectedFile, lineData);
int checkEnd = interpretCommand(selectedFile, lineData);
if (checkEnd == 0)
endOfFile = 1;
}
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);
}
}
/***** Cycle through txt lines and remember last lines ******/
/*
int running = 0, selectedFile = 0;
int locCount = 0, tempSpot = 0;
int loc[4];
char line[32];
uint8_t lastButState;
while(1){
lcd.setCursor(TextLCD::CurOn_BlkOn); //turn blinking cursor on
while(!running) {
uint8_t curButState = buttons.readBus();
if(curButState != lastButState){
switch(lastButState = curButState){
case 0x1F: //right
loc[locCount] = ftell(fp);
if (locCount >= 3)
locCount = 0;
else
locCount++;
//tempSpot = ftell(fp);
fgets(line, 32, fp);
lcd.setAddress(0,1);
lcd.printf("L: %s", line);
wait(0.2);
break;
case 0x2F: //left
if (locCount == 0) {
locCount = 3;
fseek(fp, loc[locCount], SEEK_SET);
}
else {
fseek(fp, loc[locCount - 1], SEEK_SET);
locCount--;
}
fgets(line, 32, fp);
lcd.setAddress(0,1);
lcd.printf("L: %s", line);
wait(0.2);
break;
}
}
}
}
*/
/******* Select the Program txt File ***********/
/*
int numTextFiles = 0;
string tempTextFiles[25]; //Assuming Maximum of 25 txt files will be on the SD Card
lcd.cls(); //clear the display
readFileNames("/sd");
numTextFiles = getFileNamesWithoutExt(tempTextFiles);
string *textFiles = resize_StringArr(tempTextFiles, numTextFiles); //Resize Array
//delete [] tempTextFiles; //free previous array
int running = 0, selectedFile = 0;
lcd.cls(); //clear the display
lcd.setAddress(0,1);
lcd.printf("Select Your Program");
lcd.setAddress(0,2);
lcd.printf("Num Programs = %d", numTextFiles);
uint8_t lastButState;
while(1){
lcd.setCursor(TextLCD::CurOn_BlkOn); //turn blinking cursor on
while(!running) {
uint8_t curButState = buttons.readBus();
if(curButState != lastButState){
switch(lastButState = curButState){
case 0x1F: //right
selectedFile = cyclePrograms(textFiles, numTextFiles, selectedFile, 1);
break;
case 0x2F: //left
selectedFile = cyclePrograms(textFiles, numTextFiles, selectedFile, 0);
break;
}
}
}
}
*/
/*float speed = 0.5;
while(1){
bridges.drive(1, -1*speed);
wait(2);
bridges.drive(1, speed);
wait(2);
}*/
//BridgeDriver::MOTOR_A