From 2b70547227e5442b77c9ea269e160438316e2b5b Mon Sep 17 00:00:00 2001
From: egorguslyan <egorguslyan@gmail.com>
Date: Wed, 8 Dec 2021 20:58:13 +0300
Subject: [PATCH] Text now works (eng + rus)

---
 Dashboard/Dashboard.ino |   6 +-
 Dashboard/font.h        |   7 +-
 Dashboard/textbox.h     | 443 +++++++++++++++++++---------------------
 3 files changed, 217 insertions(+), 239 deletions(-)

diff --git a/Dashboard/Dashboard.ino b/Dashboard/Dashboard.ino
index 9fe3b50..303914c 100644
--- a/Dashboard/Dashboard.ino
+++ b/Dashboard/Dashboard.ino
@@ -62,7 +62,7 @@ void setup()
   co2.begin(CO2TX, CO2RX);
   co2.setAutoCalibration(false);
   delay(500);
-  tb.setup("Ghbdtn vbh!", 0xFFFF, COLOR1, TB_BOUNCE, 1, 1, 14, 500, 2000);
+  tb.setup("Ghbdtn vbh!", 0xFFFF, COLOR1, TB_LOOP_WITH_DELAY, 1, 1, 14, 100, 2000);
 }
 
 void loop()
@@ -103,6 +103,8 @@ void loop()
     }
   }
 
-  tb.render();
+  static uint64_t timer1 = 0;
+  timer(timer1, 99)
+    if(tb.render()) timer1 = millis();
   matrix.show();
 }
diff --git a/Dashboard/font.h b/Dashboard/font.h
index da2cf0c..fbfb5c9 100644
--- a/Dashboard/font.h
+++ b/Dashboard/font.h
@@ -8,7 +8,7 @@
 const uint8_t font_null[]   PROGMEM =       {0};
 const uint8_t font_notdef[] PROGMEM =       {cords(5, 0, 5), 0b11111110, 0b11110111, 0b01011101, 0b11101111, 0b11100000};
 const uint8_t font_space[] PROGMEM =        {cords(1, 6, 1), 0b00000000};
-const uint8_t font_exclamation[] PROGMEM =  {cords(1, 0, 1), 0b11110100};
+const uint8_t font_exclamation[] PROGMEM =  {cords(1, 1, 1), 0b11110100};
 const uint8_t font_quote[] PROGMEM =        {cords(3, 0, 1), 0b10110100};
 const uint8_t font_hashtag[] PROGMEM =      {cords(5, 2, 3), 0b01010111, 0b11010101, 0b11110101};
 const uint8_t font_promt[] PROGMEM =        {cords(5, 0, 5), 0b00100011, 0b10101000, 0b11100010, 0b10111000, 0b10000000};
@@ -129,7 +129,7 @@ const uint8_t font_ru_ru_Ae[] PROGMEM =        {cords(4, 0, 4), 0b11100001, 0b00
 const uint8_t font_ru_ru_Yu[] PROGMEM =        {cords(5, 0, 5), 0b10010101, 0b01101011, 0b11011010, 0b11010110, 0b01000000};
 const uint8_t font_ru_ru_Ya[] PROGMEM =        {cords(4, 0, 4), 0b01111001, 0b10010111, 0b00110101, 0b10010000};
 const uint8_t font_ru_ru_b[] PROGMEM =         {cords(3, 0, 3), 0b01110001, 0b00111011, 0b01010000};
-const uint8_t font_ru_ru_v[] PROGMEM =         {cords(3, 0, 3), 0b01010111, 0b01011010, 0b10000000};
+const uint8_t font_ru_ru_v[] PROGMEM =         {cords(3, 1, 3), 0b01010111, 0b01011010, 0b10000000};
 const uint8_t font_ru_ru_g[] PROGMEM =         {cords(3, 2, 2), 0b11110010, 0b01001000};
 const uint8_t font_ru_ru_d[] PROGMEM =         {cords(5, 2, 4), 0b00110010, 0b10010101, 0b11111000, 0b10000000};
 const uint8_t font_ru_ru_ye[] PROGMEM =        {cords(4, 0, 4), 0b10010000, 0b01101001, 0b11101000, 0b01100000};
@@ -139,6 +139,7 @@ const uint8_t font_ru_ru_i[] PROGMEM =         {cords(5, 2, 4), 0b10001100, 0b11
 const uint8_t font_ru_ru_yi[] PROGMEM =        {cords(5, 0, 5), 0b01110000, 0b00100011, 0b00111010, 0b11100110, 0b00100000};
 const uint8_t font_ru_ru_k[] PROGMEM =         {cords(4, 2, 3), 0b10011010, 0b11001010, 0b10010000};
 const uint8_t font_ru_ru_l[] PROGMEM =         {cords(4, 2, 3), 0b00110101, 0b01010101, 0b10010000};
+const uint8_t font_ru_ru_m[] PROGMEM =         {cords(5, 2, 4), 0b01010101, 0b01101011, 0b01011010, 0b10000000};
 const uint8_t font_ru_ru_n[] PROGMEM =         {cords(4, 2, 3), 0b10011001, 0b11111001, 0b10010000};
 const uint8_t font_ru_ru_p[] PROGMEM =         {cords(4, 0, 3), 0b11111001, 0b10011001, 0b10010000};
 const uint8_t font_ru_ru_t[] PROGMEM =         {cords(3, 2, 2), 0b11101001, 0b00100100};
@@ -341,7 +342,7 @@ const uint8_t* const font[] /*PROGMEM*/ =   {   font_notdef, //     NONE    NONE
                                                 font_ru_ru_y, //    Ñ‹       115     1
                                                 font_e, //          е       116     1
                                                 font_ru_ru_g, //    г       117     1
-                                                font_m, //          м       118     1
+                                                font_ru_ru_m, //    м       118     1
                                                 font_ru_ru_c, //    ц       119     1
                                                 font_ru_ru_ch, //   ч       120     1
                                                 font_ru_ru_n, //    н       121     1
diff --git a/Dashboard/textbox.h b/Dashboard/textbox.h
index 661964f..b817e16 100644
--- a/Dashboard/textbox.h
+++ b/Dashboard/textbox.h
@@ -1,234 +1,209 @@
-#pragma once
-
-#include "font.h"
-
-enum TB_MODES
-{
-    TB_DISABLED,
-    TB_STATIC,
-    TB_REPEAT,
-    TB_LOOP,
-    TB_LOOP_WITH_DELAY,
-    TB_BOUNCE,
-};
-
-class textbox
-{
-private:
-    /* data */
-    uint8_t cord_x;
-    uint8_t cord_y;
-    uint8_t w;
-    uint8_t mode;
-    uint16_t speed;
-    uint16_t delay;
-    int16_t offset;
-    bool direction;
-    bool state;
-    mData color;
-    char text[64];
-    uint8_t textlen;
-    uint16_t textwidth;
-    uint8_t letter[8];
-    uint64_t langMask;
-    bool native;
-    void getLetter(uint8_t i, bool skipBitmap = 0);
-    uint64_t timer0;
-public:
-    textbox(void);
-    void setup(     char _text[], uint64_t _langMask,
-                    mData _color,
-                    uint8_t _mode,
-                    uint8_t _x, uint8_t _y, uint8_t _w,
-                    uint8_t _reciprocal_speed = 0, uint16_t _delay = 0);
-    void render(void);
-    void disable(void);
-};
-
-textbox::textbox(void)
-{
-    cord_x = 0;
-    cord_y = 0;
-    w = 0;
-    mode = 0;
-    speed = 0;
-    delay = 0;
-    memset(text, NULL, 64 * sizeof(char));
-    langMask = 0;
-    // If 96th symbol is font_null there is no native language except for English
-    native = pgm_read_byte(font[96]) != 0;
-    uint8_t debugByte = pgm_read_byte(font[0]);
-    Serial.println(debugByte);
-    uint8_t debugCounter = 1;
-    while(debugByte != 0)
-    {
-        Serial.println(debugByte);
-        debugByte = pgm_read_byte(font[debugCounter]);
-        debugCounter++;
-    }
-}
-
-void textbox::setup(char _text[], uint64_t _langMask,
-                    mData _color,
-                    uint8_t _mode,
-                    uint8_t _x, uint8_t _y, uint8_t _w,
-                    uint8_t _reciprocal_speed = 0, uint16_t _delay = 0)
-{
-    memset(text, NULL, 64 * sizeof(char));
-    strcpy(text, _text);
-    textlen = strlen(text);
-    langMask = _langMask;
-    textwidth = 0;
-    for(uint16_t i = 0; i < textlen; i++)
-    {
-        getLetter(i, true);
-        textwidth += letter[0] + 1;
-    }
-    textwidth--;
-    color = _color;
-    mode = _mode;
-    cord_x = _x;
-    cord_y = _y;
-    w = _w;
-    offset = 0;
-    switch(mode)
-    {
-        case TB_LOOP:
-            delay = 0;
-        goto NO_DELAY;
-        case TB_REPEAT:
-        case TB_LOOP_WITH_DELAY:
-        case TB_BOUNCE:
-            delay = _delay;
-        NO_DELAY:
-            speed = _reciprocal_speed;
-        break;
-        case TB_DISABLED:
-        case TB_STATIC:
-        default:
-            speed = 0;
-            delay = 0;
-        break;
-    }
-    timer0 = 0;
-    render();
-}
-
-void textbox::render(void)
-{
-    // Do nothing if disabled
-    if(mode != TB_DISABLED) 
-    {
-        if(timer0 == 0) 
-        {
-            offset = 0 + (mode == TB_REPEAT) * w;
-            direction = 0;
-            timer0 = millis();
-        }
-        else
-        {
-            if((millis() - timer0) > (((mode != TB_LOOP) && !state) ? delay : speed))
-            {
-                state = 1;
-                timer0 = millis();
-                if(mode == TB_BOUNCE)
-                {
-                    if((!direction && offset == -textwidth + w) || (direction && offset == 0))
-                    {
-                        direction = !direction;
-                        state = 0;
-                    }
-                    else offset += direction ? 1 : -1;
-                }
-                else
-                {
-                    offset += -1;
-                    if(offset < (-textwidth - 2 * (mode == TB_LOOP || mode == TB_LOOP_WITH_DELAY) + w * (mode == TB_REPEAT)))
-                    {
-                        offset = 0 + (mode == TB_REPEAT) * w;
-                        state = 0;
-                    }
-                }
-
-            }
-            else return;
-        }
-    }
-    else return;
-    // Clear spot
-    for(uint8_t i = cord_x; (i < cord_x + w) && (i < WIDTH); i++)
-    for(uint8_t j = cord_y; (j < cord_y + 7) && (j < HEIGHT);  j++)
-        matrix.set(i, j, mBlack);
-    // Init letter counter, start X and Y
-    uint8_t index = 0;
-    int16_t positionX = cord_x + offset;
-    int16_t positionY = cord_y;
-    // Draw while in bounds
-    while((positionX < cord_x + w) && (index < textlen))
-    {
-        // Recieve letter
-        getLetter(index);
-        // Relative X and Y
-        uint8_t x = 0;
-        uint8_t y = letter[1];
-        // X bound
-        uint8_t maxX = letter[0];
-        // Run thougth bytes
-        for(uint8_t i = 0; (i < letter[2]) && (y < 7); i++)
-        {
-            // Run througth bits
-            for(int8_t j = 7; (j >= 0) && (y < 7); j--)
-            {
-                // Set pixel
-                bool state = bitRead(letter[i + 3], j);
-                int16_t mx = x + positionX;
-                int16_t my = HEIGHT - 1 - y - positionY;
-                if(state && mx >= cord_x && mx < cord_x + w && my >= cord_y && my < cord_y + 7)
-                    matrix.set(mx, my, color);
-                // Next pixel
-                x++;
-                if(x >= maxX)
-                {
-                    x = 0; y++;
-                }
-            }
-        }
-        // Shift X and index
-        positionX += maxX + 1;
-        index++;
-    }
-    
-}
-
-void textbox::disable(void)
-{
-    setup("", 0, 0, TB_DISABLED, 0, 0, 0);
-}
-
-void textbox::getLetter(uint8_t i, bool skipBitmap = 0)
-{
-    // Letter and it's position in ASCII table
-    char c = text[i];
-    uint8_t ctoi = (uint8_t)c;
-    // Language (0 - English, 1 - Native)
-    bool lang = bitRead(langMask, i);
-    // Clear place for letter in RAM
-    memset(letter, 0, 8 * sizeof(uint8_t));
-    uint8_t index;
-    // Translate ASCII index to local
-    if(ctoi >= 32 && ctoi <= 126) index = ctoi - 31 + 95 * lang * native;
-    else index = 0;
-    // Read properties from semeric number
-    uint8_t readed = pgm_read_byte(font[index]);
-    letter[0] = readed / 49 + 1;    // width
-    letter[1] = readed % 7;         // offset
-    letter[2] = readed / 7 % 7;     // bytes
-    // Read bitmaps
-    if(!skipBitmap)
-    {
-        for(uint8_t i = 0; i < letter[2]; i++)
-        {
-            letter[i + 3] = pgm_read_byte(font[index] + (i + 1) * sizeof(uint8_t));
-        }
-    }
-}
\ No newline at end of file
+#pragma once
+
+#include "font.h"
+
+enum TB_MODES {
+    TB_DISABLED,
+    TB_STATIC,
+    TB_REPEAT,
+    TB_LOOP,
+    TB_LOOP_WITH_DELAY,
+    TB_BOUNCE,
+};
+
+class textbox {
+private:
+    /* data */
+    uint8_t cord_x;
+    uint8_t cord_y;
+    uint8_t w;
+    uint8_t mode;
+    uint16_t speed;
+    uint16_t delay;
+    int16_t offset;
+    bool direction;
+    bool state;
+    mData color;
+    char text[64];
+    uint8_t textlen;
+    uint16_t textwidth;
+    uint8_t letter[8];
+    uint64_t langMask;
+    bool native;
+    void getLetter(uint8_t i, bool skipBitmap = 0);
+    uint64_t timer0;
+
+public:
+    textbox(void);
+    void setup(char _text[], uint64_t _langMask,
+        mData _color,
+        uint8_t _mode,
+        uint8_t _x, uint8_t _y, uint8_t _w,
+        uint8_t _reciprocal_speed = 0, uint16_t _delay = 0);
+    uint8_t render(void);
+    void disable(void);
+};
+
+textbox::textbox(void)
+{
+    cord_x = 0;
+    cord_y = 0;
+    w = 0;
+    mode = 0;
+    speed = 0;
+    delay = 0;
+    memset(text, NULL, 64 * sizeof(char));
+    langMask = 0;
+    // If 96th symbol is font_null there is no native language except for English
+    native = pgm_read_byte(font[96]) != 0;
+}
+
+void textbox::setup(char _text[], uint64_t _langMask,
+    mData _color,
+    uint8_t _mode,
+    uint8_t _x, uint8_t _y, uint8_t _w,
+    uint8_t _reciprocal_speed = 0, uint16_t _delay = 0)
+{
+    memset(text, NULL, 64 * sizeof(char));
+    strcpy(text, _text);
+    textlen = strlen(text);
+    langMask = _langMask;
+    textwidth = 0;
+    for (uint16_t i = 0; i < textlen; i++) {
+        getLetter(i, true);
+        textwidth += letter[0] + 1;
+    }
+    textwidth--;
+    color = _color;
+    mode = _mode;
+    cord_x = _x;
+    cord_y = _y;
+    w = _w;
+    offset = 0;
+    switch (mode) {
+    case TB_LOOP:
+        delay = 0;
+        goto NO_DELAY;
+    case TB_REPEAT:
+    case TB_LOOP_WITH_DELAY:
+    case TB_BOUNCE:
+        delay = _delay;
+    NO_DELAY:
+        speed = _reciprocal_speed;
+        break;
+    case TB_DISABLED:
+    case TB_STATIC:
+    default:
+        speed = 0;
+        delay = 0;
+        break;
+    }
+    timer0 = 0;
+    render();
+}
+
+uint8_t textbox::render(void)
+{
+    // Do nothing if disabled
+    if (mode != TB_DISABLED) {
+        if (timer0 == 0) {
+            offset = 0 + (mode == TB_REPEAT) * w + 1 * (mode == TB_LOOP);
+            direction = 0;
+            timer0 = millis();
+        } else {
+            if ((millis() - timer0) > (((mode != TB_LOOP) && !state) ? delay : speed)) {
+                state = 1;
+                timer0 = millis();
+                if (mode == TB_BOUNCE) {
+                    if ((!direction && offset == -textwidth + w) || (direction && offset == 0)) {
+                        direction = !direction;
+                        state = 0;
+                    } else
+                        offset += direction ? 1 : -1;
+                } else {
+                    offset += -1;
+                    if (offset < ((int16_t)-textwidth - 2 * (mode == TB_LOOP || mode == TB_LOOP_WITH_DELAY) - w * (mode == TB_REPEAT))) {
+                        offset = 0 + (mode == TB_REPEAT) * w;
+                        state = 0;
+                    }
+                }
+
+            } else
+                if(state != 0) return 0;
+        }
+    } else
+        return 0;
+    // Clear spot
+    for (uint8_t i = cord_x; (i < cord_x + w) && (i < WIDTH); i++)
+        for (uint8_t j = cord_y; (j < cord_y + 7) && (j < HEIGHT); j++)
+            matrix.set(i, j, mBlack);
+    // Init letter counter, start X and Y
+    uint8_t index = 0;
+    int16_t positionX = cord_x + offset;
+    int16_t positionY = cord_y;
+    // Draw while in bounds
+    while ((positionX < cord_x + w) && (index < textlen)) {
+        // Recieve letter
+        getLetter(index);
+        // Relative X and Y
+        uint8_t x = 0;
+        uint8_t y = letter[1];
+        // X bound
+        uint8_t maxX = letter[0];
+        // Run thougth bytes
+        for (uint8_t i = 0; (i < letter[2]) && (y < 7); i++) {
+            // Run througth bits
+            for (int8_t j = 7; (j >= 0) && (y < 7); j--) {
+                // Set pixel
+                bool state = bitRead(letter[i + 3], j);
+                int16_t mx = x + positionX;
+                int16_t my = HEIGHT - 1 - y - positionY;
+                if (state && mx >= cord_x && mx < cord_x + w && my >= cord_y && my < cord_y + 7)
+                    matrix.set(mx, my, color);
+                // Next pixel
+                x++;
+                if (x >= maxX) {
+                    x = 0;
+                    y++;
+                }
+            }
+        }
+        // Shift X and index
+        positionX += maxX + 1;
+        index++;
+    }
+    return 1;
+}
+
+void textbox::disable(void)
+{
+    setup("", 0, 0, TB_DISABLED, 0, 0, 0);
+}
+
+void textbox::getLetter(uint8_t i, bool skipBitmap = 0)
+{
+    // Letter and it's position in ASCII table
+    char c = text[i];
+    uint8_t ctoi = (uint8_t)c;
+    // Language (0 - English, 1 - Native)
+    bool lang = bitRead(langMask, i);
+    // Clear place for letter in RAM
+    memset(letter, 0, 8 * sizeof(uint8_t));
+    uint8_t index;
+    // Translate ASCII index to local
+    if (ctoi >= 32 && ctoi <= 126)
+        index = ctoi - 31 + 95 * lang * native;
+    else
+        index = 0;
+    // Read properties from semeric number
+    uint8_t readed = pgm_read_byte(font[index]);
+    letter[0] = readed / 49 + 1; // width
+    letter[1] = readed % 7;      // offset
+    letter[2] = readed / 7 % 7;  // bytes
+    // Read bitmaps
+    if (!skipBitmap) {
+        for (uint8_t i = 0; i < letter[2]; i++) {
+            letter[i + 3] = pgm_read_byte(font[index] + (i + 1) * sizeof(uint8_t));
+        }
+    }
+}
-- 
GitLab