diff --git a/DisplayESP32.ino b/DisplayESP32.ino index 60f0153..c494bbf 100644 --- a/DisplayESP32.ino +++ b/DisplayESP32.ino @@ -1,6 +1,6 @@ #define MAX_OPTIONS 10 //Maximum number of options for each menu -#define MAX_MENUS 10 -#define MAX_GRAPH 10 +#define MAX_MENUS 3 +#define MAX_GRAPH 3 #define __DEBUG__ #include @@ -8,8 +8,6 @@ #include #include #include -#include - #define DISP_WIDTH 128 // OLED display width #define DISP_HEIGHT 64 // OLED display height @@ -23,28 +21,27 @@ void setDisp(bool fullsetting){ Serial.begin(115200); if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { #ifdef __DEBUG__ - Serial.println("No se encuentra la pantalla OLED"); + Serial.println("Display not found!"); #endif while (true); } } display.clearDisplay(); - // Tamaño del texto + // Text size display.setTextSize(2); - // Color del texto + // Text color display.setTextColor(SSD1306_WHITE); - // Posición del texto - display.setCursor(0, 16); - // Escribir texto - display.println("Hola"); - display.display(); + // Text position - display.setCursor(0, 32); - - display.println("mundo!!"); + display.setCursor(0, 20); + display.println("Bienvenido"); + + + display.setTextSize(1); display.display(); + delay(5000); } class Option{ @@ -54,87 +51,97 @@ class Option{ int sizey; String content; int pos; + int textSpacing; bool fill = false; bool disp = false; - void (*f)(void); + bool destinationTypeMenu; + int destinationIndex; public: //Option(){} - void configure(String content, int sizex, int sizey, int pos){ + void configure(String content, int sizex, int sizey, int pos, bool destinationTypeMenu, int destinationIndex){ this->sizex = sizex; this->sizey = sizey; this->content = content; this->pos = pos; + this->destinationTypeMenu = destinationTypeMenu; + this->destinationIndex = destinationIndex; this->disp = true; + this->textSpacing = ((sizey - 7)/2) + 7; + } + + bool getDestinationTypeMenu(){ + bool destinationType = this->destinationTypeMenu; + return destinationType; } - void drawopt(int page, int pos){ + int getDestinationIndex(){ + int destinationIndex = this->destinationIndex; + return destinationIndex; + } + + void drawopt(int page, int pos, int optPPage){ if(this->disp){ if(this->pos == pos){ - display.fillRect(0, (this->sizey)*(this->pos) - (page*DISP_WIDTH), this->sizex, this->sizey, WHITE); + display.fillRect(0, (this->sizey)*(this->pos) + pos - (page*optPPage*this->sizey), this->sizex, this->sizey, WHITE); display.setTextColor(SSD1306_BLACK); - display.setCursor((this->sizex) + 3, (this->sizey) - 3); - display.println(this->content); + display.setCursor(5, (this->sizey)*(this->pos + 1) - (page*optPPage*this->sizey) - this->textSpacing); + display.print(this->content); display.setTextColor(SSD1306_WHITE); } else{ - display.drawRect(0, (this->sizey)*(this->pos), this->sizex, this->sizey, WHITE); - display.setCursor((this->sizex) + 3, (this->sizey) - 3 - (DISP_WIDTH*128)); - display.println(this->content); + display.drawRect(0, (this->sizey)*(this->pos) + pos - (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); } } } - - void task(void (*f)(void)){ - this->f = f; - } }; -class Menu{ +class Menu{ //ContentTypeMenu true, it is a menu private: - int id; int sizex; - int sizey; + 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 previousScreen = 0; + int optPPage; + bool previousContentTypeMenu = true; public: - void configure(int id, int sizex, int sizey){ - this->id = id; + void configure(int sizex, int sizey){ this->sizex = sizex; this->sizey = sizey; + this->optPPage = DISP_HEIGHT / this->sizey; } - void createOption(String content){ - this->opt[this->options].configure(content, this->sizex, this->sizey, this->options++); + void createOption(String content, bool destinationTypeMenu, int destinationIndex){ + this->opt[this->options].configure(content, this->sizex, this->sizey, this->options++, destinationTypeMenu, destinationIndex); } - void function(int optionindex, void (*f)(void)){ //Defines functions for each option - this->opt[optionindex].task(f); + bool extractDestinationTypeMenu(){ + bool destinationTypeMenu = this->opt[this->pos].getDestinationTypeMenu(); + return destinationTypeMenu; + } + + int extractDestinationIndex(){ + int destinationIndex = this->opt[this->pos].getDestinationIndex(); + return destinationIndex; } void drawMenu(){ - int dir; - this->page = pos/3; + display.clearDisplay(); + this->page = pos/this->optPPage; for(int i = 0; i < options; i++){ - this->opt[i].drawopt(this->page, this->pos); + this->opt[i].drawopt(this->page, this->pos, this->optPPage); } - } - - int getid(){ - int id = this->id; - return id; - } - - int getoptions(){ - int options = this->options; - return options; + display.display(); } void increasePos(){ @@ -144,42 +151,372 @@ class Menu{ void decreasePos(){ this->pos--; } + + void setPreviousScreen(int prev){ + this->previousScreen = prev; + } + + void setPreviousContentTypeMenu(bool prev){ + this->previousContentTypeMenu = prev; + } + + int getPreviousScreen(){ + int prev = this->previousScreen; + return prev; + } + + bool getPreviousContentTypeMenu(){ + bool prev = this->previousContentTypeMenu; + return prev; + } +}; + +class Graph{ //ContentTypeMenu false, it is not a menu + 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 + double digit; //For: Vertical Bar + double x; + double yrange; + double xrange; + double xorigin; + double yorigin; + double graphScale; + bool redraw = true; + + int previousScreen = 0; + bool previousContentTypeMenu = true; + + public: + + 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, double digit){ + this->title = title; + this->graphType = graphType; + this->yminimum = yminimum; + this->ymaximum = ymaximum; + this->xminimum = xminimum; + this->xmaximum = xmaximum; + this->height = height; + this->width = width; + this->yStepSize = yStepSize; + this->xStepSize = xStepSize; + this->digit = digit; + 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) { + 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': + double mx; + + 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, ox, oy; + int rot, newrot; + + 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); + ox = (this->x - this->xminimum) * (this->width) / (this->xrange) + this->xpos; + oy = (this->value - this->yminimum) * (this->ypos - this->height - this->ypos) / (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->ypos - this->height - this->ypos) / (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->x - this->xminimum) * (this->width) / (this->xrange) + this->xpos; + this->value = (this->value - this->yminimum) * (this->ypos - this->height - this->ypos) / (this->yrange) + this->ypos; + display.drawLine(ox, oy, this->x, this->value, SSD1306_WHITE); + display.drawLine(ox, oy - 1, this->x, this->value - 1, SSD1306_WHITE); + ox = this->x; + oy = this->value; + + if(ox == this->xpos + this->width) + this->redraw = true; + this->x = 0; + + // up until now print sends data to a video buffer NOT the screen + // this call sends the data to the screen + display.display(); + this->x++; + } + } + + void redrawFlag(){ + this->redraw = true; + } + + void setPreviousScreen(int prev){ + this->previousScreen = prev; + } + + void setPreviousContentTypeMenu(bool prev){ + this->previousContentTypeMenu = prev; + } + + int getPreviousScreen(){ + int prev = this->previousScreen; + return prev; + } + + bool getPreviousContentTypeMenu(){ + bool prev = this->previousContentTypeMenu; + return prev; + } + + void assignValue(double value){ + this->value = value; + } }; + class Screen{ - private: Menu menu[MAX_MENUS]; - int ids[MAX_MENUS]; - int counter = 0; - int actualScreen; + Graph graph[MAX_GRAPH]; + int counterM = 0; + int counterG = 0; + int currentScreen = 0; + bool redraw = true; + bool contentTypeMenu = true; public: - void createMenu(int id, int sizex, int sizey){ - this->menu[counter].configure(id, sizex, sizey); - counter++; + void createMenu(int sizex, int sizey){ + this->menu[counterM].configure(sizex, sizey); + counterM++; } - void createOption(int idMenu, String content){ - int mem = 0; - for(int i = 0; i < counter; i++){ - if(this->ids[i] == idMenu) - mem = i; - break; - } - this->menu[mem].createOption(content); + void createOption(int menuIndex, String content, bool destinationTypeMenu, int destinationIndex){ + this->menu[menuIndex].createOption(content, destinationTypeMenu, destinationIndex); + } + + void createGraph(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){ + this->graph[counterG].configure(title, graphType, xpos, ypos, width, height, yminimum, ymaximum, xminimum, xmaximum, yStepSize, xStepSize, digit); + counterG++; + } + + void redrawFlag(){ + this->redraw = true; + } + + void graphAssignValue(int graphIndex, double value){ + this->graph[graphIndex].assignValue(value); + this->redraw = true; } void control(){ - + if (redraw){ + if (contentTypeMenu){ + menu[currentScreen].drawMenu(); + } + else{ + graph[currentScreen].drawGraph(); + } + this->redraw = false; + } + } + + void increasePos(){ + this->menu[this->currentScreen].increasePos(); + } + + void decreasePos(){ + this->menu[this->currentScreen].decreasePos(); + } + + void goTo(){ + int newScreen = this->menu[this->currentScreen].extractDestinationIndex(); + bool newContentTypeMenu = this->menu[this->currentScreen].extractDestinationTypeMenu(); + if (contentTypeMenu){ + this->menu[newScreen].setPreviousScreen(this->currentScreen); + this->menu[newScreen].setPreviousContentTypeMenu(this->contentTypeMenu); + } + else{ + this->graph[newScreen].setPreviousScreen(this->currentScreen); + this->graph[newScreen].setPreviousContentTypeMenu(this->contentTypeMenu); + } + this->contentTypeMenu = newContentTypeMenu; + this->currentScreen = newScreen; + this->redraw = true; + } + + void goBack(){ + if (contentTypeMenu){ + this->currentScreen = this->menu[this->currentScreen].getPreviousScreen(); + this->contentTypeMenu = this->menu[this->currentScreen].getPreviousContentTypeMenu(); + } + else{ + this->graph[this->currentScreen].redrawFlag(); + this->currentScreen = this->graph[this->currentScreen].getPreviousScreen(); + this->contentTypeMenu = this->graph[this->currentScreen].getPreviousContentTypeMenu(); + } } + }; +Screen screen; + void setup(){ + setDisp(true); + + screen.createMenu(128, 9); + + /*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.createGraph("Grafica 1", 'a', 25, 60, 40, 40, 0, 100, 0, 0, 10, 0, 0); + screen.createGraph("Grafica 2", 'b', 10, 60, 100, 20, 0, 0, 0, 100, 0, 10, 0); + screen.createGraph("Grafica 3", 'c', 30, 50, 75, 30, 0, 1024, 0, 10, 100, 10, 0); + + screen.createOption(0, "Grafica vertical", false, 0); + screen.createOption(0, "Grafica horizontal", false, 1); + screen.createOption(0, "Grafica cartesiana", false, 2); } void loop(){ + screen.control(); + delay(10); }