acidportal

- 😈 Worlds smallest Evil Portal on a LilyGo T-QT
git clone git://git.acid.vegas/acidportal.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 }