From acafbec2938f92fe91628a2116801736e35923fd Mon Sep 17 00:00:00 2001 From: aquazx20 Date: Wed, 3 May 2023 21:04:40 -0600 Subject: [PATCH] New implementation example added, in which an interface is created to display the graph from a experiment and modify some variables within it. Libray is now independent from the rest of the code and each class has its own header file, in order to make it more legible. It would be a good idea to make the x axis of the cartesian chart modifiable according to the changes in the samples number by a Modifier object. Perhaps using pointers. --- DisplayESP32_SSD1306.h | 23 ++++ Simple_Implementation.ino | 65 ++++++++++ Singleshot_Graph.ino | 57 +++++++++ resources/Graph.h | 245 ++++++++++++++++++++++++++++++++++++++ resources/Keyboard.h | 82 +++++++++++++ resources/Menu.h | 85 +++++++++++++ resources/Modifier.h | 70 +++++++++++ resources/Option.h | 58 +++++++++ resources/Screen.h | 192 +++++++++++++++++++++++++++++ 9 files changed, 877 insertions(+) create mode 100644 DisplayESP32_SSD1306.h create mode 100644 Simple_Implementation.ino create mode 100644 Singleshot_Graph.ino create mode 100644 resources/Graph.h create mode 100644 resources/Keyboard.h create mode 100644 resources/Menu.h create mode 100644 resources/Modifier.h create mode 100644 resources/Option.h create mode 100644 resources/Screen.h diff --git a/DisplayESP32_SSD1306.h b/DisplayESP32_SSD1306.h new file mode 100644 index 0000000..b7d27a3 --- /dev/null +++ b/DisplayESP32_SSD1306.h @@ -0,0 +1,23 @@ +#define MAX_OPTIONS 10 //Maximum number of options for each menu +#define MAX_MENUS 3 +#define MAX_GRAPHS 3 +#define MAX_MODIFIERS 3 +#define DISP_WIDTH 128 // OLED display width +#define DISP_HEIGHT 64 // OLED display height +#define REFRESH 10 //Refresh time in ms + +//The following constants are used to configure the behaviour of the interface +// MAX_OPTIONS defines the maximum number of options a menu can hold +// MAX_MENUS declares the maximum number of menu screens in the interface +// MAX_GRAPHS is the maximum number of graphs to create +// DISP_WIDTH and DISP_HEIGHT are hardware specific (SSD1306) +// REFRESH: is the time in miliseconds the interface will take in refreshing (this time affects the loop, keep that in mind) + +Adafruit_SSD1306 display(DISP_WIDTH, DISP_HEIGHT, &Wire, -1); + +#include "resources/Option.h" +#include "resources/Menu.h" +#include "resources/Graph.h" +#include "resources/Modifier.h" +#include "resources/Screen.h" +#include "resources/Keyboard.h" diff --git a/Simple_Implementation.ino b/Simple_Implementation.ino new file mode 100644 index 0000000..1ecee55 --- /dev/null +++ b/Simple_Implementation.ino @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#define __DEBUG__ + + +#include "DisplayESP32_SSD1306.h" + +int i = 0; +int multiplier = 1; + +Screen screen; +Keyboard keyboard(13, 12, 14, 27, 30, &screen); + +void setup(){ + screen.configure(true, 0x3C); + + screen.createMenu(128, 13); //Menu 0 + screen.createMenu(128, 13); //Menu 1 + + /*String title, char graphType, double xpos, double ypos, double width, double height, + double yminimum, double ymaximum, double xminimum, double xmaximum, double yStepSize, double xStepSize, double digit*/ + + screen.createVGraph("Grafica 1", 25, 60, 40, 40, 0, 100, 10, 0); //Graph 0 + screen.createHGraph("Grafica 2", 10, 40, 100, 20, 0, 100, 10, 0); //Graph 1 + screen.createCGraph("Grafica 3", 30, 50, 75, 30, 0, 100, 0, 1000, 25, 250, 0); //Graph 2 + + screen.createModifier("Modify variable", &multiplier, 5, 1, 1); + + screen.createOption(0, "Vertical graph", 1, 0); + //Creates the first option in Menu 0, directing to a graph (contentType = 1 (Graph)), 0 (Graph 0) + screen.createOption(0, "Horizontal graph", 1, 1); + screen.createOption(0, "Cartesian graph", 1, 2); + screen.createOption(0, "Extra option", 0, 1); + + screen.createOption(1, "Test", 1, 3); + screen.createOption(1, "Working?", 2, 2); + screen.createOption(1, "Modify variable", 2, 0); + +// screen.increasePos(); +// screen.increasePos(); +// screen.goTo(); +// screen.graphAssignValue(2, 50); +// screen.goBack(); +// screen.increasePos(); +// screen.goTo(); +// screen.goBack(); +// screen.decreasePos(); +} + +void loop(){ + screen.control(); //Controls the screen and redraws if needed + keyboard.control(); + + if(i <= 100){ + screen.graphAssignValue(1, i); //Assigning a demo value to Graph 1 + screen.graphAssignValue(2, i); //Assigning a demo value to Graph 2 + i += multiplier; + } + else + i = 0; + + delay(REFRESH); //Refresh time (approx) +} \ No newline at end of file diff --git a/Singleshot_Graph.ino b/Singleshot_Graph.ino new file mode 100644 index 0000000..f560fe2 --- /dev/null +++ b/Singleshot_Graph.ino @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#define __DEBUG__ + + +#include "DisplayESP32_SSD1306.h" + +int i = 0; +int multiplier = 1; +int samples = 1000; + +Screen screen; +Keyboard keyboard(13, 12, 14, 27, 30, &screen); + +void setup(){ + screen.configure(true, 0x3C); + + screen.createMenu(128, 13); //Menu 0 + + screen.createCGraph("Test", 30, 50, 75, 30, 0, 100, 0, 1000, 25, 250, 0); //Graph 0 + + screen.createModifier("Multiplier", &multiplier, 5, 1, 1); //Modifier 0 + screen.createModifier("Samples number", &samples, 1000, 500, 10); //Modifier 1 + + screen.createOption(0, "Adjust multiplier", 2, 0); + screen.createOption(0, "Adjust samples #", 2, 1); + + screen.createOption(0, "Run test", 1, 0); +} + +void loop(){ + while(screen.getCurrentScreen() != 0 || screen.getContentType() != 1){ + screen.control(); //Controls the screen and redraws if needed while not in the test's graph + keyboard.control(); + delay(REFRESH); + } + + for(int j = 0; j <= samples; j++){ + if(i <= 100){ + screen.graphAssignValue(0, i); //Assigning a demo value to Graph 0 + i += multiplier; + } + else + i = 0; + screen.control(); + Serial.println(samples); + delay(REFRESH); + } + + while(screen.getCurrentScreen() == 0 && screen.getContentType() == 1){ + screen.control(); //Controls the screen and redraws if needed while not in the test's graph + keyboard.control(); + delay(REFRESH); + } +} \ No newline at end of file diff --git a/resources/Graph.h b/resources/Graph.h new file mode 100644 index 0000000..b36b623 --- /dev/null +++ b/resources/Graph.h @@ -0,0 +1,245 @@ +class Graph{ //ContentType (1) + private: + + String title; + char graphType; //'a' Vertical Bar, 'b' Horizontal Bar, 'c' Cartesian Graph + + //Assign whatever value in "configure(..." if a parameter is not required for the specified graphType + + double value; //For: Vertical Bar Horizontal Bar Cartesian + double xpos; //For: Vertical Bar Horizontal Bar Cartesian + double ypos; //For: Vertical Bar Horizontal Bar Cartesian + double height; //For: Vertical Bar Horizontal Bar Cartesian + double width; //For: Vertical Bar Horizontal Bar Cartesian + double yminimum; //For: Vertical Bar Cartesian + double ymaximum; //For: Vertical Bar Cartesian + double xminimum; //For: Horizontal Bar Cartesian + double xmaximum; //For: Horizontal Bar Cartesian + double yStepSize; //For: Vertical Bar Cartesian + double xStepSize; //For: Horizontal Bar Cartesian + int digit; //For: Vertical Bar Horizontal Bar Cartesian + double x; + double yrange; + double xrange; + double ox; + double oy; + double count; + double graphScale; + bool redraw = true; + + int previousScreen = 0; + int previousContentType = 0; + + public: + +//This method configures the graph created, defines its parameters according the type of graph selected. + void configure(String title, char graphType, double xpos, double ypos, double width, double height, + double yminimum, double ymaximum, double xminimum, double xmaximum, double yStepSize, double xStepSize, int digit){ + this->title = title; + this->graphType = graphType; + this->yminimum = yminimum; + this->ymaximum = ymaximum; + this->xminimum = xminimum; + this->count = xminimum; + this->xmaximum = xmaximum; + this->height = height; + this->width = width; + this->yStepSize = yStepSize; + this->xStepSize = xStepSize; + this->digit = digit; + this->xpos = xpos; + this->ypos = ypos; + switch(graphType){ + case 'a': + this->yrange = ymaximum - yminimum; + this->graphScale = (yStepSize) * (height / this->yrange) - .001; //Adjusts the scale of the graph, according to the range and the size of the step + break; + + case 'b': + this->xrange = xmaximum - xminimum; + this->graphScale = (xStepSize) * (width / this->xrange) - .001; //Adjusts the scale of the graph, according to the range and the size of the step + break; + + case 'c': + this->yrange = ymaximum - yminimum; + this->xrange = xmaximum - xminimum; + break; + } + } + + void drawGraph(){ + double level, data, i; + switch(graphType){ + case 'a': + double my; + + if (this->redraw) { //Prints the labels + display.clearDisplay(); + this->redraw = false; + display.fillRect(0, 0, 127 , 14, SSD1306_WHITE); + display.setTextColor(SSD1306_BLACK, SSD1306_WHITE); + display.setTextSize(1); + display.setCursor(2, 4); + display.println(this->title); + + for (i = 0; i <= this->height; i += this->graphScale) { + my = this->ypos - this->height + i; + display.drawFastHLine(this->xpos + this->width + 1, my, 5, SSD1306_WHITE); + // draw lables + display.setTextSize(1); + display.setTextColor(SSD1306_WHITE, SSD1306_BLACK); + display.setCursor(this->xpos + this->width + 12, my - 3 ); + data = this->ymaximum - ( i * (this->yStepSize / this->graphScale)); + display.print(data, this->digit); + } + } + // compute level of bar graph that is scaled to the height and the hi and low vals + // this is needed to accompdate for +/- range + level = (this->height * (((this->value - this->yminimum) / (this->yrange)))); + // draw the bar graph + // write a upper and lower bar to minimize flicker cause by blanking out bar and redraw on update + display.drawRect(this->xpos, this->ypos - this->height, this->width, this->height, SSD1306_WHITE); + display.fillRect(this->xpos, this->ypos - this->height, this->width, this->height - level, SSD1306_BLACK); + display.drawRect(this->xpos, this->ypos - this->height, this->width, this->height, SSD1306_WHITE); + display.fillRect(this->xpos, this->ypos - level, this->width, level, SSD1306_WHITE); + // up until now print sends data to a video buffer NOT the screen + // this call sends the data to the screen + display.display(); + break; + + case 'b': + + if (this->redraw) { + display.clearDisplay(); + this->redraw = false; + display.fillRect(0, 0, 127 , 16, SSD1306_WHITE); + display.setTextColor(SSD1306_BLACK, SSD1306_WHITE); + display.setTextSize(1); + display.setCursor(2, 4); + display.println(this->title); + // draw the text + + for (i = 0; i <= this->width; i += this->graphScale) { + display.drawFastVLine(i + this->xpos , this->ypos , 5, SSD1306_WHITE); + // draw lables + display.setTextSize(1); + display.setTextColor(SSD1306_WHITE, SSD1306_BLACK); + display.setCursor(i + this->xpos , this->ypos + 10); + // addling a small value to eliminate round off errors + // this val may need to be adjusted + data = ( i * (this->xStepSize / this->graphScale)) + this->xminimum + 0.00001; + display.print(data, this->digit); + } + } + // compute level of bar graph that is scaled to the width and the hi and low vals + // this is needed to accompdate for +/- range capability + // draw the bar graph + // write a upper and lower bar to minimize flicker cause by blanking out bar and redraw on update + level = (this->width * (((this->value - this->xminimum) / (this->xmaximum - this->xminimum)))); + display.fillRect(this->xpos + level, this->ypos - this->height, this->width - level, this->height, SSD1306_BLACK); + display.drawRect(this->xpos, this->ypos - this->height, this->width, this->height, SSD1306_WHITE); + display.fillRect(this->xpos, this->ypos - this->height, level, this->height, SSD1306_WHITE); + // up until now print sends data to a video buffer NOT the screen + // this call sends the data to the screen + display.display(); + break; + + case 'c': + double temp; + + if (this->redraw == true) { + this->redraw = false; + display.clearDisplay(); + display.fillRect(0, 0, 127 , 16, SSD1306_WHITE); + display.setTextColor(SSD1306_BLACK, SSD1306_WHITE); + display.setTextSize(1); + display.setCursor(2, 4); + display.println(title); + this->ox = (this->count - this->xminimum) * (this->width) / (this->xrange) + this->xpos; + this->oy = (this->value - this->yminimum) * (- this->height) / (this->yrange) + this->ypos; + // draw y scale + display.setTextSize(1); + display.setTextColor(SSD1306_WHITE, SSD1306_BLACK); + for ( i = this->yminimum; i <= this->ymaximum; i += this->yStepSize) { + // compute the transform + // note my transform funcition is the same as the map function, except the map uses long and we need doubles + temp = (i - this->yminimum) * (- this->height) / (this->ymaximum - this->yminimum) + this->ypos; + if (i == 0) { + display.drawFastHLine(this->xpos - 3, temp, this->width + 3, SSD1306_WHITE); + } + else { + display.drawFastHLine(this->xpos - 3, temp, 3, SSD1306_WHITE); + } + display.setCursor(this->xpos - 27, temp - 3); + display.println(i, this->digit); + } + // draw x scale + for (i = this->xminimum; i <= this->xmaximum; i += this->xStepSize) { + // compute the transform + display.setTextSize(1); + display.setTextColor(SSD1306_WHITE, SSD1306_BLACK); + temp = (i - this->xminimum) * (this->width) / (this->xrange) + this->xpos; + if (i == 0) { + display.drawFastVLine(temp, this->ypos - this->height, this->height + 3, SSD1306_WHITE); + } + else { + display.drawFastVLine(temp, this->ypos, 3, SSD1306_WHITE); + } + display.setCursor(temp, this->ypos + 6); + display.println(i, this->digit); + } + } + + // graph drawn now plot the data + // the entire plotting code are these few lines... + + this->x = (this->count - this->xminimum) * (this->width) / (this->xrange) + this->xpos; + this->value = (this->value - this->yminimum) * (- this->height) / (this->yrange) + this->ypos; + display.drawLine(this->ox, this->oy, this->x, this->value, SSD1306_WHITE); + display.drawLine(this->ox, this->oy - 1, this->x, this->value - 1, SSD1306_WHITE); + this->ox = this->x; + this->oy = this->value; + + // up until now print sends data to a video buffer NOT the screen + // this call sends the data to the screen + display.display(); + this->count += 1; + if(this->ox >= (this->xpos + this->width)){ + this->redraw = true; + this->count = xminimum; + } + } + } + + void redrawFlag(){ // Activates the redraw bool to get the graph printed correctly + this->redraw = true; + this->count = xminimum; + } + + void setPreviousScreen(int prev){ + this->previousScreen = prev; + } + + void setPreviousContentType(int prev){ + this->previousContentType = prev; + } + + int getPreviousScreen(){ + int prev = this->previousScreen; + return prev; + } + + int getPreviousContentType(){ + int prev = this->previousContentType; + return prev; + } + + void assignValue(double value){ + this->value = value; + } + + void reset(){ + this->x = 0; + } + +}; diff --git a/resources/Keyboard.h b/resources/Keyboard.h new file mode 100644 index 0000000..77c5929 --- /dev/null +++ b/resources/Keyboard.h @@ -0,0 +1,82 @@ +class Keyboard{ + private: + + byte goTo; + byte goBack; + byte plus; + byte minus; + byte debounceTime; + + Screen *screen; + + public: + +//Keyboard constructor + Keyboard(byte goTo, byte goBack, byte plus, byte minus, byte debounceTime, Screen * screen){ + this->goTo = goTo; + this->goBack = goBack; + this->plus = plus; + this->minus = minus; + this->debounceTime = debounceTime; + + this->screen = screen; + + pinMode(goTo, INPUT_PULLUP); + pinMode(goBack, INPUT_PULLUP); + pinMode(plus, INPUT_PULLUP); + pinMode(minus, INPUT_PULLUP); + } +//Debouncing functions + void checkGoTo(){ + static char cont; + if(digitalRead(this->goTo) == LOW) + cont++; + else + cont = 0; + if(cont == debounceTime/REFRESH){ + this->screen->goTo(); + } + } + + void checkGoBack(){ + static char cont; + if(digitalRead(this->goBack) == LOW){ + cont++; + } + else + cont = 0; + if(cont == debounceTime/REFRESH){ + this->screen->goBack(); + } + } + + void checkPlus(){ + static char cont; + if(digitalRead(this->plus) == LOW) + cont++; + else + cont = 0; + if(cont == debounceTime/REFRESH){ + this->screen->plusAction(); + } + } + + void checkMinus(){ + static char cont; + if(digitalRead(this->minus) == LOW) + cont++; + else + cont = 0; + if(cont == debounceTime/REFRESH){ + this->screen->minusAction(); + } + } + +// All buttons are checked with this method + void control(){ + this->checkGoTo(); + this->checkGoBack(); + this->checkPlus(); + this->checkMinus(); + } +}; diff --git a/resources/Menu.h b/resources/Menu.h new file mode 100644 index 0000000..235cde8 --- /dev/null +++ b/resources/Menu.h @@ -0,0 +1,85 @@ +class Menu{ //ContentType (0) + private: + + int sizex; //X size for each option in the menu + int sizey; //Y size of each option in the menu + int options = 0; //This indicates the number of options created + int pos = 0; //This indicates the position of the cursor + int page = 0; //If the menu is too long, this indicates the page that is being displayed + Option opt[MAX_OPTIONS]; + int optPPage; + + int previousScreen = 0; + int previousContentType = 0; + + public: + + void configure(int sizex, int sizey){ //This method configures the menu created from Screen + this->sizex = sizex; + this->sizey = sizey; + this->optPPage = DISP_HEIGHT / this->sizey; + } + + //The following method is used to created an option for the menu + void createOption(String content, int destinationType, int destinationIndex){ + //The option takes the place in the array defined by the options number variable (options), which is later increased. + this->opt[this->options].configure(content, this->sizex, this->sizey, this->options++, destinationType, destinationIndex); + } + + int extractDestinationType(){ + int destinationType = this->opt[this->pos].getDestinationType(); + return destinationType; + } + + int extractDestinationIndex(){ + int destinationIndex = this->opt[this->pos].getDestinationIndex(); + return destinationIndex; + } + +//The following method draws the whole menu by drawing every option configured within it + void drawMenu(){ + display.clearDisplay(); + this->page = pos/this->optPPage; //The current page is obtained by dividing the position by the number of options per page (only integer) + for(int i = 0; i < options; i++){ + this->opt[i].drawopt(this->page, this->pos, this->optPPage); + } + display.display(); + } + //Methods used by Screen + int extractPos(){ //Gets the current position of the cursor + return(this->pos); + } + + int extractOptNumber(){ //Gets the number of options in the menu + return(this->options); + } + + void increasePos(){ //Increases the position of the cursor + this->pos++; + } + + void decreasePos(){ //Decreases the position of the cursor + this->pos--; + } + +//Both of the following methods store the values of the previous screen passed as parameters by Screen + + void setPreviousScreen(int prev){ + this->previousScreen = prev; + } + + void setPreviousContentType(int prev){ + this->previousContentType = prev; + } + +//Both of the following methods retrieve the values of the screen previous to the menu containing these data. + int getPreviousScreen(){ + int prev = this->previousScreen; + return prev; + } + + int getPreviousContentType(){ + int prev = this->previousContentType; + return prev; + } +}; diff --git a/resources/Modifier.h b/resources/Modifier.h new file mode 100644 index 0000000..bafbc7c --- /dev/null +++ b/resources/Modifier.h @@ -0,0 +1,70 @@ +class Modifier{ //ContentType (2) + private: + + String title; + int *value; + int max; + int min; + int step; + + int previousScreen = 0; + int previousContentType = 0; + + public: + + void configure(String title, int *value, int max, int min, int step){ + this->title = title; + this->value = value; + this->max = max; + this->min = min; + this->step = step; + } + + void drawModifier(){ + display.clearDisplay(); + display.fillRect(0, 0, 127 , 16, SSD1306_WHITE); + display.setTextColor(SSD1306_BLACK, SSD1306_WHITE); + display.setTextSize(1); + display.setCursor(2, 4); + display.println(this->title); + + display.setTextColor(SSD1306_WHITE); + display.setTextSize(3); + display.setCursor(2, ((DISP_HEIGHT - 16 - 15)/2) + 16); + display.println(*this->value); + + display.display(); + + display.setTextSize(1); + } + + void increaseValue(){ + if((*this->value + this->step) <= this->max){ + *this->value += this->step; + } + } + + void decreaseValue(){ + if((*this->value - this->step) >= this->min){ + *this->value -= this->step; + } + } + + void setPreviousScreen(int prev){ + this->previousScreen = prev; + } + + void setPreviousContentType(int prev){ + this->previousContentType = prev; + } + + int getPreviousScreen(){ + int prev = this->previousScreen; + return prev; + } + + int getPreviousContentType(){ + int prev = this->previousContentType; + return prev; + } +}; diff --git a/resources/Option.h b/resources/Option.h new file mode 100644 index 0000000..a284eb4 --- /dev/null +++ b/resources/Option.h @@ -0,0 +1,58 @@ +class Option{ + private: + + int sizex; //Defines the size it will occupy in the x axis (width), this value is gotten from the menu + int sizey; //Defines the height of the option (this value is gotten from the menu it belongs to) + String content; //Text of the option + int pos; //Defines the position it has in the menu + int textSpacing; //According to the height, defines the space for the text, so that it's vertically centered + bool fill = false; //In case an option is not selected this should be false + bool disp = false; //In case an option is not configured, it should be false and, thus hidden + int destinationType; //Defines what the option leads to (another menu, graph, something else) + int destinationIndex; //Defines where the option leads to (index of the destination) + + public: + + //Option(){} + + //Method to configure an option, all attributes are assigned, and disp is true, so the option can be displayed + void configure(String content, int sizex, int sizey, int pos, int destinationType, int destinationIndex){ + this->sizex = sizex; + this->sizey = sizey; + this->content = content; + this->pos = pos; + this->destinationType = destinationType; + this->destinationIndex = destinationIndex; + this->disp = true; + this->textSpacing = ((sizey - 7)/2) + 7; + } + + int getDestinationType(){ + int destinationType = this->destinationType; + return destinationType; + } + + int getDestinationIndex(){ + int destinationIndex = this->destinationIndex; + return destinationIndex; + } + +//This method draws each option + + void drawopt(int page, int pos, int optPPage){ + if(this->disp){ //Checks if the option was configured and, as a result, is displayable + if(this->pos == pos){ //If the position of the option corresponds to the position passed to the function, then it should be selected + display.fillRect(0, (this->sizey)*(this->pos) + 1 - (page*optPPage*this->sizey), this->sizex, this->sizey, WHITE); + display.setTextColor(SSD1306_BLACK); + display.setCursor(5, (this->sizey)*(this->pos + 1) - (page*optPPage*this->sizey) - this->textSpacing); + display.print(this->content); + display.setTextColor(SSD1306_WHITE); + } + else{ //If the option is not selected, the rectangle containing it shouldn't be filled + display.drawRect(0, (this->sizey)*(this->pos) + 1 - (page*optPPage*this->sizey), this->sizex, this->sizey, WHITE); + display.setCursor(5, (this->sizey)*(this->pos + 1) - (page*optPPage*this->sizey) - this->textSpacing); + display.print(this->content); + } + } + } +}; diff --git a/resources/Screen.h b/resources/Screen.h new file mode 100644 index 0000000..15f86b7 --- /dev/null +++ b/resources/Screen.h @@ -0,0 +1,192 @@ +class Screen{ + private: + + Menu menu[MAX_MENUS]; //Array of menus to use + Graph graph[MAX_GRAPHS]; //Array of graphs to use + Modifier modifier[MAX_MODIFIERS]; //Array of modifiers to use + + int counterM = 0; //Number of menus created + int counterG = 0; //Number of graphs created + int counterMod = 0; + bool redraw = true; //Redraw interface for when there is a change of screen + int currentScreen = 0; + int contentType = 0; + + public: + + + void configure(bool fullsetting, char address){ //This method allows the configuration of the display when the parameter is true. Otherwise only prints a greeting message. + if(fullsetting){ + //Adafruit_SSD1306 display(DISP_WIDTH, DISP_HEIGHT, &Wire, -1); + Serial.begin(115200); + if (!display.begin(SSD1306_SWITCHCAPVCC, address)) { + #ifdef __DEBUG__ + Serial.println("Display not found!"); + #endif + while (true); + } + } + display.clearDisplay(); + + // Text size + display.setTextSize(2); + // Text color + display.setTextColor(SSD1306_WHITE); + // Text position + + display.setCursor(25, 20); + display.println("Welcome"); + + + display.setTextSize(1); + + display.display(); + delay(5000); + } + + void createMenu(int sizex, int sizey){ //This method is used for the creation of a menu + this->menu[counterM].configure(sizex, sizey); + this->counterM++; + } + + void createOption(int menuIndex, String content, int destinationType, int destinationIndex){ //this method should be used for creating an option in a menu + this->menu[menuIndex].createOption(content, destinationType, destinationIndex); + } + + void createVGraph(String title, double xpos, double ypos, double width, double height, + double yminimum, double ymaximum, double yStepSize, int digit){ //this method calls the configure() of graph for a vertical graph + this->graph[counterG].configure(title, 'a', xpos, ypos, width, height, yminimum, ymaximum, 0, 0, yStepSize, 0, digit); + this->counterG++; + } + + void createHGraph(String title, double xpos, double ypos, double width, double height, + double xminimum, double xmaximum, double xStepSize, int digit){ //this method calls the configure() of graph for a horizontal graph + this->graph[counterG].configure(title, 'b', xpos, ypos, width, height, 0, 0, xminimum, xmaximum, 0, xStepSize, digit); + counterG++; + } + + void createCGraph(String title, double xpos, double ypos, double width, double height, + double yminimum, double ymaximum, double xminimum, double xmaximum, double yStepSize, double xStepSize, int digit){ //this method calls the configure() of graph for a cartesian chart + this->graph[counterG].configure(title, 'c', xpos, ypos, width, height, yminimum, ymaximum, xminimum, xmaximum, yStepSize, xStepSize, digit); + counterG++; + } + + void createModifier(String title, int *value, int max, int min, int step){ //This method is used for the creation of a menu + this->modifier[counterMod].configure(title, value, max, min, step); + this->counterMod++; + } + +/* + void redrawFlag(){ + this->redraw = true; + } +*/ + +//The following method is used for assingning a value to a graph +//This can be avoided using pointers to the variable to plot in the graph + void graphAssignValue(int graphIndex, double value){ + this->graph[graphIndex].assignValue(value); + if(this->currentScreen == graphIndex && this->contentType == 1) + this->redraw = true; + } + +//This method controls the whole interface, it needs to be called within a loop + void control(){ + if (redraw){ + if (contentType == 0){ + menu[currentScreen].drawMenu(); + } + else if (contentType == 1){ + graph[currentScreen].drawGraph(); + } + else if (contentType == 2){ + modifier[currentScreen].drawModifier(); + } + this->redraw = false; + } + } + +//The following two methods allow the change in position of the cursor + void increasePos(){ + if(this->menu[this->currentScreen].extractPos() < this->menu[this->currentScreen].extractOptNumber() - 1) + this->menu[this->currentScreen].increasePos(); + } + + void decreasePos(){ + if(this->menu[this->currentScreen].extractPos() > 0) + this->menu[this->currentScreen].decreasePos(); + } + +//This method lets the user go into another screen by selecting an option + void goTo(){ + if(this->contentType == 0){ + int newScreen = this->menu[this->currentScreen].extractDestinationIndex(); + int newContentType = this->menu[this->currentScreen].extractDestinationType(); + if (newContentType == 0){ + this->menu[newScreen].setPreviousScreen(this->currentScreen); + this->menu[newScreen].setPreviousContentType(this->contentType); + } + else if(newContentType == 1){ + this->graph[newScreen].setPreviousScreen(this->currentScreen); + this->graph[newScreen].setPreviousContentType(this->contentType); + this->graph[newScreen].reset(); + this->graph[newScreen].redrawFlag(); + } + else if(newContentType == 2){ + this->modifier[newScreen].setPreviousScreen(this->currentScreen); + this->modifier[newScreen].setPreviousContentType(this->contentType); + } + this->contentType = newContentType; + this->currentScreen = newScreen; + this->redraw = true; + } + } + + void goBack(){ + if(contentType == 0){ + //Gets indexes from previous screen saved in actual screen if it is a menu, and sets them as the current indexes + this->currentScreen = this->menu[this->currentScreen].getPreviousScreen(); + this->contentType = this->menu[this->currentScreen].getPreviousContentType(); + } + else if(contentType == 1){ + //Gets indexes from previous screen saved in actual screen if it is a graph, and sets them as the current indexes + this->currentScreen = this->graph[this->currentScreen].getPreviousScreen(); + this->contentType = this->graph[this->currentScreen].getPreviousContentType(); + } + else if(contentType == 2){ + this->currentScreen = this->modifier[this->currentScreen].getPreviousScreen(); + this->contentType = this->modifier[this->currentScreen].getPreviousContentType(); + } + this->redraw = true; + } + +//These methods control the plus and minus button actions + void plusAction(){ + if(contentType == 0){ + increasePos(); + } + else if(contentType == 2){ + this->modifier[currentScreen].increaseValue(); + } + this->redraw = true; + } + + void minusAction(){ + if(contentType == 0){ + decreasePos(); + } + else if(contentType == 2){ + this->modifier[currentScreen].decreaseValue(); + } + this->redraw = true; + } + + int getCurrentScreen(){ + return this->currentScreen; + } + + int getContentType(){ + return this->contentType; + } + +};