#ifndef DISPLAY_H #define DISPLAY_H #include enum Align { ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT }; enum Font { FONT5, FONT7 }; struct Color { uint8_t r, g, b; }; extern Color WHITE; extern Color BLACK; extern Color RED; extern Color GREEN; extern Color BLUE; extern Color YELLOW; extern Color CYAN; extern Color MAGENTA; extern Color ORANGE; extern Color GREY; extern const bool DOT7[][7][1]; extern const bool SPECIAL7[][7][3]; extern const bool NUM7[][7][4]; extern const bool ALPHA7[][7][4]; class Display { Adafruit_NeoPixel leds; bool pixels[8 * 32]{}; static int mapPixel(const int x, const int y) { return y * 32 + (y % 2 == 0 ? x : 31 - x); } public: explicit Display(const uint8_t pin): leds(8 * 32, pin,NEO_GRB + NEO_KHZ800) { // } void setBrightness(int i) { #if LEDS_ENABLED leds.setBrightness(max(0, min(i, 255))); #endif } void setup() { #if LEDS_ENABLED leds.begin(); #endif for (int y = 0; y < 8; y++) { for (int x = 0; x < 32; x++) { pixels[mapPixel(x, y)] = false; } } setBrightness(32); clear(); show(); } void show() { #if LEDS_ENABLED leds.show(); #endif } void setPixel(const int x, const int y, const Color &color) { const auto index = mapPixel(x, y); if (index >= 8 * 32) { Serial.printf("[ERROR] No pixel at (%d, %d) = %d >= %d\n", x, y, index, 8 * 32); return; } #if LEDS_ENABLED leds.setPixelColor(index, color.r, color.g, color.b); #endif pixels[index] = color.r > 0 || color.g > 0 || color.b > 0; } void rect(const int x0, const int y0, const int w, const int h, const Color &color) { for (int y = y0; y < y0 + h; y++) { for (int x = x0; x < x0 + w; x++) { setPixel(x, y, color); } } } void print(int x, const int y, const Align align, const Font font, const Color &color, const char *format, ...) { char text[32]; va_list args; va_start(args, format); vsnprintf(text, sizeof text, format, args); va_end(args); const auto width = measure(text, font); x = align == ALIGN_LEFT ? x : align == ALIGN_RIGHT ? x - width : x - width / 2; for (const char *c = text; *c; c++) { x += printChar(x, y, *c, font, color) + 1; } } int printChar(const int x, const int y, const char c, const Font font, const Color &color) { if (isDot(c)) { if (c == '.') { return printSymbol(x, y, 0, color, DOT7); } if (c == ',') { return printSymbol(x, y, 1, color, DOT7); } if (c == ':') { return printSymbol(x, y, 2, color, DOT7); } if (c == ';') { return printSymbol(x, y, 3, color, DOT7); } } if (isSpecial(c)) { if (c == ' ') { return printSymbol(x, y, 0, color, SPECIAL7); } if (c == '-') { return printSymbol(x, y, 1, color, SPECIAL7); } } if (isNumber(c)) { return printSymbol(x, y, c - '0', color, NUM7); } if (isLower(c)) { return printSymbol(x, y, c - 'a', color, ALPHA7); } if (isUpper(c)) { return printSymbol(x, y, c - 'A', color, ALPHA7); } Serial.printf("UNKNOWN SYMBOL '%c'\n", c); return 0; } template int printSymbol(const int x, const int y, const int index, const Color &color, const bool symbols[][symbolHeight][symbolWidth]) { for (int innerY = 0; innerY < symbolHeight; innerY++) { for (int innerX = 0; innerX < symbolWidth; innerX++) { if (symbols[index][innerY][innerX]) { setPixel(x + innerX, y + innerY, color); } } } return symbolWidth; } void clear() { rect(0, 0, 32, 8, BLACK); } void log() const { Serial.print("+"); for (int x = 0; x < 32; x++) { Serial.print("--"); } Serial.print("+\n"); for (int y = 0; y < 8; y++) { Serial.print("|"); for (int x = 0; x < 32; x++) { if (pixels[mapPixel(x, y)]) { Serial.print("##"); } else { Serial.print(" "); } } Serial.print("|\n"); } Serial.print("+"); for (int x = 0; x < 32; x++) { Serial.print("--"); } Serial.print("+\n"); Serial.print('\n'); } static uint8_t measure(const char *text, const Font font) { uint8_t width = 0; for (const char *c = text; *c; c++) { if (c != text) { width++; // space between chars } width += getWidth(*c, font); } return width; } static uint8_t getWidth(const char c, const Font font) { if (isDot(c)) { return 1; } if (isSpecial(c)) { return 3; } return font == FONT5 ? 3 : 4; } static bool isDot(const char c) { return c == ':' || c == ';' || c == '.' || c == ','; } static bool isSpecial(const char c) { return c == ' ' || c == '-'; } static bool isNumber(const char c) { return c >= '0' && c <= '9'; } static bool isLower(const char c) { return c >= 'a' && c <= 'z'; } static bool isUpper(const char c) { return c >= 'A' && c <= 'Z'; } }; #endif