acid-drop- Hacking the planet from a LilyGo T-Deck using custom firmware |
git clone git://git.acid.vegas/acid-drop.git |
Log | Files | Refs | Archive | README | LICENSE |
Arc_meter_demo.ino (7173B)
1 // This is a test sketch being developed for a new arc based meter widget 2 // The meter graphic is fully anti-aliased to avoid jaggy pixelated edges 3 4 // For this demo randomly sized meters are drawn, cycled and redrawn a random size. 5 // The meter is ramped up and down 0-100 and 100-0, then pauses before a new 6 // random sized meter is drawn 7 8 // If the radius is > 25 then the value is drawn in the middle 9 10 // The outer ring of the meter uses the drawSmoothCircle function (which draws 11 // a narrow full circle smooth arc) 12 13 // Uncomment to draw meter digits and label text 14 //#define DRAW_DIGITS 15 16 // If DRAW_DIGITS is defined the OpenFontRender library must be loaded since 17 // the sketch uses a scaleable TrueType font for the text and numerals. 18 // https://github.com/Bodmer/OpenFontRender 19 20 #define LOOP_DELAY 0 // This controls how frequently the meter is updated 21 // for test purposes this is set to 0 22 23 24 #include <SPI.h> 25 #include <TFT_eSPI.h> // Hardware-specific library 26 27 #ifdef DRAW_DIGITS 28 #include "NotoSans_Bold.h" 29 #include "OpenFontRender.h" 30 #define TTF_FONT NotoSans_Bold 31 #endif 32 33 34 TFT_eSPI tft = TFT_eSPI(); // Invoke custom library with default width and height 35 TFT_eSprite spr = TFT_eSprite(&tft); // Declare Sprite object "spr" with pointer to "tft" object 36 37 #ifdef DRAW_DIGITS 38 OpenFontRender ofr; 39 #endif 40 41 #define DARKER_GREY 0x18E3 42 43 uint32_t runTime = 0; // time for next update 44 45 int reading = 0; // Value to be displayed 46 int d = 0; // Variable used for the sinewave test waveform 47 bool range_error = 0; 48 int8_t ramp = 1; 49 50 bool initMeter = true; 51 52 void setup(void) { 53 Serial.begin(115200); 54 tft.begin(); 55 tft.setRotation(1); 56 tft.fillScreen(TFT_NAVY); 57 //tft.setViewport(0, 0, 240, 320); 58 } 59 60 61 void loop() { 62 static uint16_t maxRadius = 0; 63 int8_t ramp = 1; 64 static uint8_t radius = 0; 65 static int16_t xpos = tft.width() / 2; 66 static int16_t ypos = tft.height() / 2; 67 bool newMeter = false; 68 69 if (maxRadius == 0) { 70 maxRadius = tft.width(); 71 if (tft.height() < maxRadius) maxRadius = tft.height(); 72 maxRadius = (0.6 * maxRadius) / 2; 73 radius = maxRadius; 74 } 75 76 // Choose a random meter radius for test purposes and draw for one range cycle 77 // Clear old meter first 78 tft.fillCircle(xpos, ypos, radius + 1, TFT_NAVY); 79 radius = random(20, maxRadius); // Random radius 80 initMeter = true; 81 82 #ifdef DRAW_DIGITS 83 // Loading a font takes a few milliseconds, so for test purposes it is done outside the test loop 84 if (ofr.loadFont(TTF_FONT, sizeof(TTF_FONT))) { 85 Serial.println("Render initialize error"); 86 return; 87 } 88 #endif 89 90 initMeter = true; 91 reading = 0; 92 ramp = 1; 93 while (!newMeter) { 94 if (millis() - runTime >= LOOP_DELAY) { 95 runTime = millis(); 96 97 reading += ramp; 98 ringMeter(xpos, ypos, radius, reading, "Watts"); // Draw analogue meter 99 100 if (reading > 99) ramp = -1; 101 if (reading <= 0) ramp = 1; 102 103 if (reading > 99) delay(1000); 104 if (reading <= 0) { 105 delay(1000); 106 newMeter = true; 107 } 108 } 109 } 110 111 #ifdef DRAW_DIGITS 112 ofr.unloadFont(); // Recover space used by font metrics etc 113 #endif 114 } 115 116 // ######################################################################### 117 // Draw the meter on the screen, returns x coord of righthand side 118 // ######################################################################### 119 // x,y is centre of meter, r the radius, val a number in range 0-100 120 // units is the meter scale label 121 void ringMeter(int x, int y, int r, int val, const char *units) 122 { 123 static uint16_t last_angle = 30; 124 125 if (initMeter) { 126 initMeter = false; 127 last_angle = 30; 128 tft.fillCircle(x, y, r, DARKER_GREY); 129 tft.drawSmoothCircle(x, y, r, TFT_SILVER, DARKER_GREY); 130 uint16_t tmp = r - 3; 131 tft.drawArc(x, y, tmp, tmp - tmp / 5, last_angle, 330, TFT_BLACK, DARKER_GREY); 132 } 133 134 r -= 3; 135 136 // Range here is 0-100 so value is scaled to an angle 30-330 137 int val_angle = map(val, 0, 100, 30, 330); 138 139 140 if (last_angle != val_angle) { 141 // Could load the required font here 142 //if (ofr.loadFont(TTF_FONT, sizeof(TTF_FONT))) { 143 // Serial.println("Render initialize error"); 144 // return; 145 //} 146 #ifdef DRAW_DIGITS 147 ofr.setDrawer(spr); // Link renderer to sprite (font will be rendered in sprite spr) 148 149 // Add value in centre if radius is a reasonable size 150 if ( r >= 25 ) { 151 // This code gets the font dimensions in pixels to determine the required the sprite size 152 ofr.setFontSize((6 * r) / 4); 153 ofr.setFontColor(TFT_WHITE, DARKER_GREY); 154 155 156 // The OpenFontRender library only has simple print functions... 157 // Digit jiggle for chaging values often happens with proportional fonts because 158 // digit glyph width varies ( 1 narrower that 4 for example). This code prints up to 159 // 3 digits with even spacing. 160 // A few experiemntal fudge factors are used here to position the 161 // digits in the sprite... 162 // Create a sprite to draw the digits into 163 uint8_t w = ofr.getTextWidth("444"); 164 uint8_t h = ofr.getTextHeight("4") + 4; 165 spr.createSprite(w, h + 2); 166 spr.fillSprite(DARKER_GREY); // (TFT_BLUE); // (DARKER_GREY); 167 char str_buf[8]; // Buffed for string 168 itoa (val, str_buf, 10); // Convert value to string (null terminated) 169 uint8_t ptr = 0; // Pointer to a digit character 170 uint8_t dx = 4; // x offfset for cursor position 171 if (val < 100) dx = ofr.getTextWidth("4") / 2; // Adjust cursor x for 2 digits 172 if (val < 10) dx = ofr.getTextWidth("4"); // Adjust cursor x for 1 digit 173 while ((uint8_t)str_buf[ptr] != 0) ptr++; // Count the characters 174 while (ptr) { 175 ofr.setCursor(w - dx - w / 20, -h / 2.5); // Offset cursor position in sprtie 176 ofr.rprintf(str_buf + ptr - 1); // Draw a character 177 str_buf[ptr - 1] = 0; // Replace character with a null 178 dx += 1 + w / 3; // Adjust cursor for next character 179 ptr--; // Decrement character pointer 180 } 181 spr.pushSprite(x - w / 2, y - h / 2); // Push sprite containing the val number 182 spr.deleteSprite(); // Recover used memory 183 184 // Make the TFT the print destination, print the units label direct to the TFT 185 ofr.setDrawer(tft); 186 ofr.setFontColor(TFT_GOLD, DARKER_GREY); 187 ofr.setFontSize(r / 2.0); 188 ofr.setCursor(x, y + (r * 0.4)); 189 ofr.cprintf("Watts"); 190 } 191 #endif 192 193 //ofr.unloadFont(); // Recover space used by font metrics etc 194 195 // Allocate a value to the arc thickness dependant of radius 196 uint8_t thickness = r / 5; 197 if ( r < 25 ) thickness = r / 3; 198 199 // Update the arc, only the zone between last_angle and new val_angle is updated 200 if (val_angle > last_angle) { 201 tft.drawArc(x, y, r, r - thickness, last_angle, val_angle, TFT_SKYBLUE, TFT_BLACK); // TFT_SKYBLUE random(0x10000) 202 } 203 else { 204 tft.drawArc(x, y, r, r - thickness, val_angle, last_angle, TFT_BLACK, DARKER_GREY); 205 } 206 last_angle = val_angle; // Store meter arc position for next redraw 207 } 208 }