Added analog voltage display
This commit is contained in:
		
							parent
							
								
									df5ff1c91a
								
							
						
					
					
						commit
						0274b5d755
					
				|  | @ -180,6 +180,48 @@ String xdrDelete(String input){ | |||
|     return input; | ||||
| } | ||||
| 
 | ||||
| Point rotatePoint(const Point& origin, const Point& p, double angle) { | ||||
|     // rotate poind around origin by degrees
 | ||||
|     Point rotated; | ||||
|     double phi = angle * M_PI / 180.0; | ||||
|     double dx = p.x - origin.x; | ||||
|     double dy = p.y - origin.y; | ||||
|     rotated.x = origin.x + cos(phi) * dx - sin(phi) * dy; | ||||
|     rotated.y = origin.y + sin(phi) * dx + cos(phi) * dy; | ||||
|     return rotated; | ||||
| } | ||||
| 
 | ||||
| std::vector<Point> rotatePoints(const Point& origin, const std::vector<Point>& pts, double angle) { | ||||
|     std::vector<Point> rotatedPoints; | ||||
|     for (const auto& p : pts) { | ||||
|          rotatedPoints.push_back(rotatePoint(origin, p, angle)); | ||||
|     } | ||||
|      return rotatedPoints; | ||||
| } | ||||
| 
 | ||||
| void fillPoly4(const std::vector<Point>& p4, uint16_t color) { | ||||
|     getdisplay().fillTriangle(p4[0].x, p4[0].y, p4[1].x, p4[1].y, p4[2].x, p4[2].y, color); | ||||
|     getdisplay().fillTriangle(p4[0].x, p4[0].y, p4[2].x, p4[2].y, p4[3].x, p4[3].y, color); | ||||
| } | ||||
| 
 | ||||
| // Draw centered text
 | ||||
| void drawTextCenter(int16_t cx, int16_t cy, String text) { | ||||
|     int16_t x1, y1; | ||||
|     uint16_t w, h; | ||||
|     getdisplay().getTextBounds(text, 0, 150, &x1, &y1, &w, &h); | ||||
|     getdisplay().setCursor(cx - w / 2, cy + h / 2); | ||||
|     getdisplay().print(text); | ||||
| } | ||||
| 
 | ||||
| // Draw right aligned text
 | ||||
| void drawTextRalign(int16_t x, int16_t y, String text) { | ||||
|     int16_t x1, y1; | ||||
|     uint16_t w, h; | ||||
|     getdisplay().getTextBounds(text, 0, 150, &x1, &y1, &w, &h); | ||||
|     getdisplay().setCursor(x - w, y); | ||||
|     getdisplay().print(text); | ||||
| } | ||||
| 
 | ||||
| // Show a triangle for trend direction high (x, y is the left edge)
 | ||||
| void displayTrendHigh(int16_t x, int16_t y, uint16_t size, uint16_t color){ | ||||
|     getdisplay().fillTriangle(x, y, x+size*2, y, x+size, y-size*2, color); | ||||
|  |  | |||
|  | @ -39,6 +39,14 @@ GxEPD2_BW<GxEPD2_420_GYE042A87, GxEPD2_420_GYE042A87::HEIGHT> & getdisplay(); | |||
| GxEPD2_BW<GxEPD2_420_SE0420NQ04, GxEPD2_420_SE0420NQ04::HEIGHT> & getdisplay(); | ||||
| #endif | ||||
| 
 | ||||
| struct Point { | ||||
|     double x; | ||||
|     double y; | ||||
| }; | ||||
| Point rotatePoint(const Point& origin, const Point& p, double angle); | ||||
| std::vector<Point> rotatePoints(const Point& origin, const std::vector<Point>& pts, double angle); | ||||
| void fillPoly4(const std::vector<Point>& p4, uint16_t color); | ||||
| 
 | ||||
| void hardwareInit(); | ||||
| 
 | ||||
| void setPortPin(uint pin, bool value);          // Set port pin for extension port
 | ||||
|  | @ -58,6 +66,9 @@ void setBuzzerPower(uint power);                // Set buzzer power | |||
| 
 | ||||
| String xdrDelete(String input);                 // Delete xdr prefix from string
 | ||||
| 
 | ||||
| void drawTextCenter(int16_t cx, int16_t cy, String text); | ||||
| void drawTextRalign(int16_t x, int16_t y, String text); | ||||
| 
 | ||||
| void displayTrendHigh(int16_t x, int16_t y, uint16_t size, uint16_t color); | ||||
| void displayTrendLow(int16_t x, int16_t y, uint16_t size, uint16_t color); | ||||
| 
 | ||||
|  |  | |||
|  | @ -22,43 +22,6 @@ TODO | |||
| 
 | ||||
| */ | ||||
| 
 | ||||
| struct Point { | ||||
|     double x; | ||||
|     double y; | ||||
| }; | ||||
| 
 | ||||
| Point rotatePoint(const Point& origin, const Point& p, double angle) { | ||||
|     // rotate poind around origin by degrees
 | ||||
|     Point rotated; | ||||
|     double phi = angle * M_PI / 180.0; | ||||
|     double dx = p.x - origin.x; | ||||
|     double dy = p.y - origin.y; | ||||
|     rotated.x = origin.x + cos(phi) * dx - sin(phi) * dy; | ||||
|     rotated.y = origin.y + sin(phi) * dx + cos(phi) * dy; | ||||
|     return rotated; | ||||
| } | ||||
| 
 | ||||
| std::vector<Point> rotatePoints(const Point& origin, const std::vector<Point>& pts, double angle) { | ||||
|     std::vector<Point> rotatedPoints; | ||||
|     for (const auto& p : pts) { | ||||
|          rotatedPoints.push_back(rotatePoint(origin, p, angle)); | ||||
|     } | ||||
|      return rotatedPoints; | ||||
| } | ||||
| 
 | ||||
| void fillPoly4(const std::vector<Point>& p4, uint16_t color) { | ||||
|     getdisplay().fillTriangle(p4[0].x, p4[0].y, p4[1].x, p4[1].y, p4[2].x, p4[2].y, color); | ||||
|     getdisplay().fillTriangle(p4[0].x, p4[0].y, p4[2].x, p4[2].y, p4[3].x, p4[3].y, color); | ||||
| } | ||||
| 
 | ||||
| void drawTextCentered(int16_t tx, int16_t ty, String text) { | ||||
|     int16_t x, y; | ||||
|     uint16_t w, h; | ||||
|     getdisplay().getTextBounds(text, 0, 0, &x, &y, &w, &h); | ||||
|     getdisplay().setCursor(tx - w / 2, ty + h / 2); | ||||
|     getdisplay().print(text); | ||||
| } | ||||
| 
 | ||||
| #define fuel_width 16 | ||||
| #define fuel_height 16 | ||||
| static unsigned char fuel_bits[] = { | ||||
|  | @ -171,7 +134,7 @@ class PageFluid : public Page{ | |||
|         } else { | ||||
|             strcpy(buffer, "---"); | ||||
|         } | ||||
|         drawTextCentered(c.x, c.y + r - 20, String(buffer)); | ||||
|         drawTextCenter(c.x, c.y + r - 20, String(buffer)); | ||||
| 
 | ||||
|         // draw symbol (as bitmap)
 | ||||
|         switch (fluidtype) { | ||||
|  | @ -197,18 +160,18 @@ class PageFluid : public Page{ | |||
|         // scale texts
 | ||||
|         getdisplay().setFont(&Ubuntu_Bold8pt7b); | ||||
|         p = {c.x, c.y - r + 30}; | ||||
|         drawTextCentered(p.x, p.y, "1/2"); | ||||
|         drawTextCenter(p.x, p.y, "1/2"); | ||||
|         pr = rotatePoint(c, p, -60); | ||||
|         drawTextCentered(pr.x, pr.y, "1/4"); | ||||
|         drawTextCenter(pr.x, pr.y, "1/4"); | ||||
|         pr = rotatePoint(c, p, 60); | ||||
|         drawTextCentered(pr.x, pr.y, "3/4"); | ||||
|         drawTextCenter(pr.x, pr.y, "3/4"); | ||||
| 
 | ||||
|         // empty and full
 | ||||
|         getdisplay().setFont(&Ubuntu_Bold12pt7b); | ||||
|         p = rotatePoint(c, {c.x, c.y - r + 30}, -130); | ||||
|         drawTextCentered(p.x, p.y, "E"); | ||||
|         drawTextCenter(p.x, p.y, "E"); | ||||
|         p = rotatePoint(c, {c.x, c.y - r + 30}, 130); | ||||
|         drawTextCentered(p.x, p.y, "F"); | ||||
|         drawTextCenter(p.x, p.y, "F"); | ||||
| 
 | ||||
|         // lines
 | ||||
|         std::vector<Point> pts = { | ||||
|  |  | |||
|  | @ -11,6 +11,7 @@ bool keylock = false;               // Keylock | |||
| int average = 0;                    // Average type [0...3], 0=off, 1=10s, 2=60s, 3=300s
 | ||||
| bool trend = true;                  // Trend indicator [0|1], 0=off, 1=on
 | ||||
| double raw = 0; | ||||
| char mode = 'D';                    // display mode (A)nalog | (D)igital
 | ||||
| 
 | ||||
| public: | ||||
|     PageVoltage(CommonData &common){ | ||||
|  | @ -24,6 +25,16 @@ public: | |||
|             return 0;                   // Commit the key
 | ||||
|         } | ||||
| 
 | ||||
|         // Switch display mode
 | ||||
|         if (key == 2) { | ||||
|             if (mode == 'A') { | ||||
|                 mode = 'D'; | ||||
|             } else { | ||||
|                 mode = 'A'; | ||||
|             } | ||||
|             return 0; | ||||
|         } | ||||
| 
 | ||||
|         // Trend indicator
 | ||||
|         if(key == 5){ | ||||
|             trend = !trend; | ||||
|  | @ -38,6 +49,41 @@ public: | |||
|         return key; | ||||
|     } | ||||
| 
 | ||||
|     void printAvg(int avg, uint16_t x, uint16_t y, bool prefix) { | ||||
|         getdisplay().setFont(&Ubuntu_Bold8pt7b); | ||||
|         getdisplay().setCursor(x, y); | ||||
|         if (prefix) { | ||||
|             getdisplay().print("Avg: "); | ||||
|         } | ||||
|         switch (average) { | ||||
|             case 0: | ||||
|                 getdisplay().print("1s"); | ||||
|                 break; | ||||
|             case 1: | ||||
|                 getdisplay().print("10s"); | ||||
|                 break; | ||||
|             case 2: | ||||
|                 getdisplay().print("60s"); | ||||
|                 break; | ||||
|             case 3: | ||||
|                 getdisplay().print("300s"); | ||||
|                 break; | ||||
|             default: | ||||
|                 getdisplay().print("1s"); | ||||
|                 break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void printVoltageSymbol(uint16_t x, uint16_t y, uint16_t color) { | ||||
|         getdisplay().setFont(&Ubuntu_Bold16pt7b); | ||||
|         getdisplay().setCursor(x, y); | ||||
|         getdisplay().print("V"); | ||||
|         getdisplay().fillRect(x, y + 6, 22, 3, color); | ||||
|         getdisplay().fillRect(x, y + 11, 6, 3, color); | ||||
|         getdisplay().fillRect(x + 8, y + 11, 6, 3, color); | ||||
|         getdisplay().fillRect(x + 16, y + 11, 6, 3, color); | ||||
|     } | ||||
| 
 | ||||
|     virtual void displayPage(CommonData &commonData, PageData &pageData) | ||||
|     { | ||||
|         GwConfigHandler *config = commonData.config; | ||||
|  | @ -135,92 +181,177 @@ public: | |||
|         // Set display in partial refresh mode
 | ||||
|         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
 | ||||
| 
 | ||||
|         // Show name
 | ||||
|         getdisplay().setTextColor(commonData.fgcolor); | ||||
|         getdisplay().setFont(&Ubuntu_Bold32pt7b); | ||||
|         getdisplay().setCursor(20, 100); | ||||
|         getdisplay().print(name1);                           // Value name
 | ||||
|         if (mode == 'D') { | ||||
|             // Display mode digital
 | ||||
| 
 | ||||
|         // Show unit
 | ||||
|         getdisplay().setFont(&Ubuntu_Bold20pt7b); | ||||
|         getdisplay().setCursor(270, 100); | ||||
|         getdisplay().print("V"); | ||||
|             // Show name
 | ||||
|             getdisplay().setTextColor(commonData.fgcolor); | ||||
|             getdisplay().setFont(&Ubuntu_Bold32pt7b); | ||||
|             getdisplay().setCursor(20, 100); | ||||
|             getdisplay().print(name1);                           // Value name
 | ||||
| 
 | ||||
|         // Show battery type
 | ||||
|         getdisplay().setFont(&Ubuntu_Bold8pt7b); | ||||
|         getdisplay().setCursor(295, 100); | ||||
|         getdisplay().print(batType); | ||||
|             // Show unit
 | ||||
|             getdisplay().setFont(&Ubuntu_Bold20pt7b); | ||||
|             getdisplay().setCursor(270, 100); | ||||
|             getdisplay().print("V"); | ||||
| 
 | ||||
|         // Show average settings
 | ||||
|         getdisplay().setFont(&Ubuntu_Bold8pt7b); | ||||
|         getdisplay().setCursor(320, 84); | ||||
|         switch (average) { | ||||
|             case 0: | ||||
|                 getdisplay().print("Avg: 1s"); | ||||
|                 break; | ||||
|             case 1: | ||||
|                 getdisplay().print("Avg: 10s"); | ||||
|                 break; | ||||
|             case 2: | ||||
|                 getdisplay().print("Avg: 60s"); | ||||
|                 break; | ||||
|             case 3: | ||||
|                 getdisplay().print("Avg: 300s"); | ||||
|                 break; | ||||
|             default: | ||||
|                 getdisplay().print("Avg: 1s"); | ||||
|                 break; | ||||
|         }  | ||||
|             // Show battery type
 | ||||
|             getdisplay().setFont(&Ubuntu_Bold8pt7b); | ||||
|             getdisplay().setCursor(295, 100); | ||||
|             getdisplay().print(batType); | ||||
| 
 | ||||
|         // Reading bus data or using simulation data
 | ||||
|         getdisplay().setFont(&DSEG7Classic_BoldItalic60pt7b); | ||||
|         getdisplay().setCursor(20, 240); | ||||
|         if(simulation == true){ | ||||
|             if(batVoltage == "12V"){ | ||||
|                 value1 = 12.0; | ||||
|             } | ||||
|             if(batVoltage == "24V"){ | ||||
|                 value1 = 24.0; | ||||
|             } | ||||
|             value1 += float(random(0, 5)) / 10;         // Simulation data
 | ||||
|             getdisplay().print(value1,1); | ||||
|         } | ||||
|         else{ | ||||
|             // Check for valid real data, display also if hold values activated
 | ||||
|             if(valid1 == true || holdvalues == true){ | ||||
|                 // Resolution switching
 | ||||
|                 if(value1 < 10){ | ||||
|                     getdisplay().print(value1,2); | ||||
|             // Show average settings
 | ||||
|             printAvg(average, 320, 84, true); | ||||
| 
 | ||||
|             // Reading bus data or using simulation data
 | ||||
|             getdisplay().setFont(&DSEG7Classic_BoldItalic60pt7b); | ||||
|             getdisplay().setCursor(20, 240); | ||||
|             if(simulation == true){ | ||||
|                 if(batVoltage == "12V"){ | ||||
|                     value1 = 12.0; | ||||
|                 } | ||||
|                 if(value1 >= 10 && value1 < 100){ | ||||
|                     getdisplay().print(value1,1); | ||||
|                 } | ||||
|                 if(value1 >= 100){ | ||||
|                     getdisplay().print(value1,0); | ||||
|                 if(batVoltage == "24V"){ | ||||
|                     value1 = 24.0; | ||||
|                 } | ||||
|                 value1 += float(random(0, 5)) / 10;         // Simulation data
 | ||||
|                 getdisplay().print(value1,1); | ||||
|             } | ||||
|             else{ | ||||
|             getdisplay().print("---");                       // Missing bus data
 | ||||
|             }   | ||||
|         } | ||||
| 
 | ||||
|         // Trend indicator
 | ||||
|         // Show trend indicator
 | ||||
|         if(trend == true){ | ||||
|             getdisplay().fillRect(310, 240, 40, 120, commonData.bgcolor);   // Clear area
 | ||||
|             getdisplay().fillRect(315, 183, 35, 4, commonData.fgcolor);   // Draw separator
 | ||||
|             if(int(raw * 10) > int(valueTrend * 10)){ | ||||
|                 displayTrendHigh(320, 174, 11, commonData.fgcolor);  // Show high indicator
 | ||||
|                 // Check for valid real data, display also if hold values activated
 | ||||
|                 if(valid1 == true || holdvalues == true){ | ||||
|                     // Resolution switching
 | ||||
|                     if(value1 < 10){ | ||||
|                         getdisplay().print(value1,2); | ||||
|                     } | ||||
|                     if(value1 >= 10 && value1 < 100){ | ||||
|                         getdisplay().print(value1,1); | ||||
|                     } | ||||
|                     if(value1 >= 100){ | ||||
|                         getdisplay().print(value1,0); | ||||
|                     } | ||||
|                 } | ||||
|                 else{ | ||||
|                 getdisplay().print("---");                       // Missing bus data
 | ||||
|                 } | ||||
|             } | ||||
|             if(int(raw * 10) < int(valueTrend * 10)){ | ||||
|                 displayTrendLow(320, 195, 11, commonData.fgcolor);   // Show low indicator
 | ||||
|             } | ||||
|         } | ||||
|         // No trend indicator
 | ||||
|         else{ | ||||
|             getdisplay().fillRect(310, 240, 40, 120, commonData.bgcolor);   // Clear area
 | ||||
|         } | ||||
| 
 | ||||
|             // Trend indicator
 | ||||
|             // Show trend indicator
 | ||||
|             if(trend == true){ | ||||
|                 getdisplay().fillRect(310, 240, 40, 120, commonData.bgcolor);   // Clear area
 | ||||
|                 getdisplay().fillRect(315, 183, 35, 4, commonData.fgcolor);   // Draw separator
 | ||||
|                 if(int(raw * 10) > int(valueTrend * 10)){ | ||||
|                     displayTrendHigh(320, 174, 11, commonData.fgcolor);  // Show high indicator
 | ||||
|                 } | ||||
|                 if(int(raw * 10) < int(valueTrend * 10)){ | ||||
|                     displayTrendLow(320, 195, 11, commonData.fgcolor);   // Show low indicator
 | ||||
|                 } | ||||
|             } | ||||
|             // No trend indicator
 | ||||
|             else{ | ||||
|                 getdisplay().fillRect(310, 240, 40, 120, commonData.bgcolor);   // Clear area
 | ||||
|             } | ||||
| 
 | ||||
|         } | ||||
|         else { | ||||
|             // Display mode analog
 | ||||
| 
 | ||||
|             // center
 | ||||
|             Point c = {260, 270}; | ||||
|             uint8_t r = 240; | ||||
| 
 | ||||
|             Point p1, p2; | ||||
|             std::vector<Point> pts; | ||||
| 
 | ||||
|             // Instrument
 | ||||
|             getdisplay().drawCircleHelper(c.x, c.y, r + 2, 0x01, commonData.fgcolor); | ||||
|             getdisplay().drawCircleHelper(c.x, c.y, r + 1, 0x01, commonData.fgcolor); | ||||
|             getdisplay().drawCircleHelper(c.x, c.y, r    , 0x01, commonData.fgcolor); | ||||
| 
 | ||||
|             // Scale
 | ||||
|             // angle to voltage scale mapping
 | ||||
|             std::map<int, String> mapping = { | ||||
|                 {15, "10"}, {30, "11"}, {45, "12"}, {60, "13"}, {75, "14"} | ||||
|             }; | ||||
|             pts = { | ||||
|                 {c.x - r, c.y - 1}, | ||||
|                 {c.x - r + 12, c.y - 1}, | ||||
|                 {c.x - r + 12, c.y + 1}, | ||||
|                 {c.x - r, c.y + 1} | ||||
|             }; | ||||
|             getdisplay().setFont(&Ubuntu_Bold10pt7b); | ||||
|             for (int angle = 3; angle < 90; angle += 3) { | ||||
|                 if (angle % 15 == 0) { | ||||
|                     fillPoly4(rotatePoints(c, pts, angle), commonData.fgcolor); | ||||
|                     p1 = rotatePoint(c, {c.x - r + 30, c.y}, angle); | ||||
|                     drawTextCenter(p1.x, p1.y, mapping[angle]); | ||||
|                 } | ||||
|                 else { | ||||
|                     p1 = rotatePoint(c, {c.x - r, c.y}, angle); | ||||
|                     p2 = rotatePoint(c, {c.x - r + 6, c.y}, angle); | ||||
|                     getdisplay().drawLine(p1.x, p1.y, p2.x, p2.y, commonData.fgcolor); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             // Pointer rotation and limits
 | ||||
|             double angle; | ||||
|             if (not valid1) { | ||||
|                 angle = -0.5; | ||||
|             } | ||||
|             else { | ||||
|                 if (value1 > 15.0) { | ||||
|                     angle = 91; | ||||
|                 } | ||||
|                 else if (value1 <= 9) { | ||||
|                     angle = -0.5; | ||||
|                 } | ||||
|                 else { | ||||
|                     angle = (value1 - 9) * 15; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             // Pointer
 | ||||
|             // thick part
 | ||||
|             pts = { | ||||
|                 {c.x - 2, c.y + 3}, | ||||
|                 {c.x - r + 38, c.y + 2}, | ||||
|                 {c.x - r + 38, c.y - 2}, | ||||
|                 {c.x - 2, c.y - 3} | ||||
|             }; | ||||
|             fillPoly4(rotatePoints(c, pts, angle), commonData.fgcolor); | ||||
|             // thin part
 | ||||
|             pts = { | ||||
|                 {c.x - r + 40, c.y + 1}, | ||||
|                 {c.x - r + 5, c.y + 1}, | ||||
|                 {c.x - r + 5, c.y -1}, | ||||
|                 {c.x - r + 40, c.y - 1}, | ||||
|             }; | ||||
|             fillPoly4(rotatePoints(c, pts, angle), commonData.fgcolor); | ||||
| 
 | ||||
|             // base
 | ||||
|             getdisplay().fillCircle(c.x, c.y, 8, commonData.fgcolor); | ||||
|             getdisplay().fillCircle(c.x, c.y, 6, commonData.bgcolor); | ||||
| 
 | ||||
|             // Symbol
 | ||||
|             printVoltageSymbol(40, 60, commonData.fgcolor); | ||||
| 
 | ||||
|             // Additional informatio at right side
 | ||||
|             getdisplay().setFont(&Ubuntu_Bold8pt7b); | ||||
|             getdisplay().setCursor(300, 60); | ||||
|             getdisplay().print("Source:"); | ||||
|             getdisplay().setCursor(300, 80); | ||||
|             getdisplay().print(name1); | ||||
| 
 | ||||
|             getdisplay().setCursor(300, 110); | ||||
|             getdisplay().print("Type:"); | ||||
|             getdisplay().setCursor(300, 130); | ||||
|             getdisplay().print(batType); | ||||
| 
 | ||||
|             getdisplay().setCursor(300, 160); | ||||
|             getdisplay().print("Avg:"); | ||||
|             printAvg(average, 300, 180, false); | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         // Key Layout
 | ||||
|         getdisplay().setTextColor(commonData.fgcolor); | ||||
|  | @ -228,6 +359,8 @@ public: | |||
|         if(keylock == false){ | ||||
|             getdisplay().setCursor(10, 290); | ||||
|             getdisplay().print("[AVG]"); | ||||
|             getdisplay().setCursor(62, 290); | ||||
|             getdisplay().print("[MODE]"); | ||||
|             getdisplay().setCursor(130, 290); | ||||
|             getdisplay().print("[  <<<<  " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + "  >>>>  ]"); | ||||
|             getdisplay().setCursor(293, 290); | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue