From f2ce84a002b351a36b079451b4b391efdf156f51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20Ha=C3=9Fel?= Date: Thu, 23 Jan 2025 14:37:46 +0100 Subject: [PATCH] Adafruit_NeoPixel integration --- library.json | 3 +- platformio.ini | 1 + src/demo/NodeTest.h | 16 ++++- src/library.json | 47 --------------- src/patrix/display/DisplayMatrix.h | 59 ++++++++++++++++--- src/patrix/display/DisplayMatrix_FontCommon.h | 2 +- .../display/DisplayMatrix_FontSpecial.cpp | 14 ++--- .../display/DisplayMatrix_FontSpecial.h | 4 +- src/patrix/display/DisplayMatrix_common.cpp | 20 +++---- src/patrix/display/DisplayMatrix_common.h | 46 +++++++++------ src/patrix/display/DisplayMatrix_draw.h | 20 +++++-- src/patrix/display/DisplayMatrix_print.h | 12 ++-- 12 files changed, 134 insertions(+), 110 deletions(-) delete mode 100644 src/library.json diff --git a/library.json b/library.json index 10c8459..11e2ede 100644 --- a/library.json +++ b/library.json @@ -16,7 +16,8 @@ "dependencies": { "knolleary/pubsubclient": "2.8", "bblanchon/ArduinoJson": "7.3.0", - "me-no-dev/ESPAsyncWebServer": "1.2.4" + "me-no-dev/ESPAsyncWebServer": "1.2.4", + "adafruit/Adafruit NeoPixel": "1.12.4" }, "export": { "include": "src/patrix" diff --git a/platformio.ini b/platformio.ini index ecfd4b7..e43f4d4 100644 --- a/platformio.ini +++ b/platformio.ini @@ -6,4 +6,5 @@ board_build.filesystem = littlefs lib_deps = knolleary/pubsubclient@2.8 bblanchon/ArduinoJson@7.3.0 me-no-dev/ESPAsyncWebServer@1.2.4 + https://github.com/adafruit/Adafruit_NeoPixel build_flags = -DWIFI_SSID=\"HappyNet\" -DWIFI_PKEY=\"1Grausame!Sackratte7\" -DWIFI_HOST=\"PatrixTest\" \ No newline at end of file diff --git a/src/demo/NodeTest.h b/src/demo/NodeTest.h index daa4d98..2bb41eb 100644 --- a/src/demo/NodeTest.h +++ b/src/demo/NodeTest.h @@ -5,10 +5,10 @@ #include #include -DisplayMatrix<32, 8> display; - Config config("/test.json"); +DisplayMatrix<32, 8> display(27); + class NodeTest final : public PatrixNode { public: @@ -19,11 +19,23 @@ public: void setup() override { config.read(); + display.setup(); + display.setBrightness(6); + + display.clear(); + + display.foreground = Blue; display.printf("Test"); + + display.foreground = Red; + display.cursorX = 0; + display.cursorY = 7; + display.drawLine(32, 0); } void loop() override { config.loop(); + display.loop(); } }; diff --git a/src/library.json b/src/library.json deleted file mode 100644 index 771753c..0000000 --- a/src/library.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "name": "Patrix", - "version": "0.1.0", - "authors": [ - { - "name": "Patrick Haßel", - "email": "development@patrick-hassel.de", - "maintainer": true, - "url": "https://patrick-hassel.de/" - } - ], - "description": "Patrix library", - "homepage": "https://patrick-hassel.de/", - "license": "MIT", - "dependencies": [ - { - "owner": "knolleary", - "name": "pubsubclient", - "version": "2.8" - }, - { - "owner": "bblanchon", - "name": "ArduinoJson", - "version": "7.3.0" - }, - { - "owner": "me-no-dev", - "name": "ESPAsyncWebServer", - "version": "1.2.4" - } - ], - "export": { - "exclude": [ - "src/demo/**" - ] - }, - "keywords": [ - "patrix" - ], - "platforms": [ - "espressif8266", - "espressif32" - ], - "frameworks": [ - "arduino" - ] -} \ No newline at end of file diff --git a/src/patrix/display/DisplayMatrix.h b/src/patrix/display/DisplayMatrix.h index afc903d..c9cc990 100644 --- a/src/patrix/display/DisplayMatrix.h +++ b/src/patrix/display/DisplayMatrix.h @@ -1,18 +1,26 @@ #ifndef DISPLAY_MATRIX_H #define DISPLAY_MATRIX_H +#include + #include "DisplayMatrix_FontCommon.h" template class DisplayMatrix { - Color matrix[H][W] = {}; + Adafruit_NeoPixel leds; + + RGB matrix[H][W] = {}; + + bool dirty = true; public: - Color foreground = White; + RGBA foreground = White; - Color background = Transparent; + RGBA background = Transparent; + + uint8_t brightness = 10; uint8_t alpha = 255; @@ -20,13 +28,45 @@ public: int cursorY = 0; + // basic ---------------------------------------------------------------------------------------- + + explicit DisplayMatrix(const int pin): leds(W * H, pin) { + // + } + + void setup() { + leds.begin(); + leds.setBrightness(brightness); + clear(); + } + + void loop() { + if (dirty) { + for (auto y = 0; y < H; y++) { + for (auto x = 0; x < W; x++) { + auto rgb = matrix[y][x]; + leds.setPixelColor(y * W + x, rgb.r, rgb.g, rgb.b); + } + } + leds.show(); + dirty = false; + } + } + + void setBrightness(const uint8_t brightness) { + if (leds.getBrightness() != brightness) { + leds.setBrightness(brightness); + dirty = true; + } + } + // draw ----------------------------------------------------------------------------------------- void clear(); - void fillRect(int w = W, int h = H) const; + void fillRect(int w = W, int h = H); - void drawLine(int w = W, int h = H, int thickness = 1) const; + void drawLine(int w, int h, int thickness = 1); // print ---------------------------------------------------------------------------------------- @@ -48,15 +88,16 @@ public: void print(bool **s, size_t w, size_t h); - void print(SymbolRGB8x8 s); + void print(SymbolRGBA8x8 s); - void print(Color **s, size_t w, size_t h); + void print(RGBA **s, size_t w, size_t h); }; -// ReSharper disable CppUnusedIncludeDirective +// ReSharper disable once CppUnusedIncludeDirective #include + +// ReSharper disable once CppUnusedIncludeDirective #include -// ReSharper restore CppUnusedIncludeDirective #endif diff --git a/src/patrix/display/DisplayMatrix_FontCommon.h b/src/patrix/display/DisplayMatrix_FontCommon.h index a081be6..445082f 100644 --- a/src/patrix/display/DisplayMatrix_FontCommon.h +++ b/src/patrix/display/DisplayMatrix_FontCommon.h @@ -8,6 +8,6 @@ typedef bool Symbol2[5][2]; typedef bool Symbol3[5][3]; typedef bool Symbol4[5][4]; typedef bool Symbol5[5][5]; -typedef Color SymbolRGB8x8[8][8]; +typedef RGBA SymbolRGBA8x8[8][8]; #endif diff --git a/src/patrix/display/DisplayMatrix_FontSpecial.cpp b/src/patrix/display/DisplayMatrix_FontSpecial.cpp index a09f78b..559960e 100644 --- a/src/patrix/display/DisplayMatrix_FontSpecial.cpp +++ b/src/patrix/display/DisplayMatrix_FontSpecial.cpp @@ -246,14 +246,14 @@ Symbol5 FONT_CHAR_PERCENT = { //@formatter:off const auto B = Black; -Color M{204, 0, 250}; -Color m{224, 121, 250}; -Color g{130, 213, 0}; -Color G{ 48, 89, 55}; -Color F{ 75, 202, 0}; +RGBA M{204, 0, 250}; +RGBA m{224, 121, 250}; +RGBA g{130, 213, 0}; +RGBA G{ 48, 89, 55}; +RGBA F{ 75, 202, 0}; //@formatter:on -SymbolRGB8x8 FONT_CREEPER = { +SymbolRGBA8x8 FONT_CREEPER = { {g, F, F, F, g, g, g, F}, {F, F, F, F, F, g, F, F}, {F, G, G, g, g, G, G, F}, @@ -264,7 +264,7 @@ SymbolRGB8x8 FONT_CREEPER = { {F, g, G, g, g, G, F, F}, }; -SymbolRGB8x8 FONT_ENDERMAN = { +SymbolRGBA8x8 FONT_ENDERMAN = { {B, B, B, B, B, B, B, B}, {B, B, B, B, B, B, B, B}, {B, B, B, B, B, B, B, B}, diff --git a/src/patrix/display/DisplayMatrix_FontSpecial.h b/src/patrix/display/DisplayMatrix_FontSpecial.h index e725d40..0c7d7e3 100644 --- a/src/patrix/display/DisplayMatrix_FontSpecial.h +++ b/src/patrix/display/DisplayMatrix_FontSpecial.h @@ -37,7 +37,7 @@ extern Symbol2 FONT_CHAR_LT; extern Symbol2 FONT_CHAR_GT; extern Symbol4 FONT_ERROR_; extern Symbol5 FONT_CHAR_PERCENT; -extern SymbolRGB8x8 FONT_CREEPER; -extern SymbolRGB8x8 FONT_ENDERMAN; +extern SymbolRGBA8x8 FONT_CREEPER; +extern SymbolRGBA8x8 FONT_ENDERMAN; #endif diff --git a/src/patrix/display/DisplayMatrix_common.cpp b/src/patrix/display/DisplayMatrix_common.cpp index c3f9670..7a808a0 100644 --- a/src/patrix/display/DisplayMatrix_common.cpp +++ b/src/patrix/display/DisplayMatrix_common.cpp @@ -1,14 +1,14 @@ #include "DisplayMatrix_common.h" //@formatter:off -const Color Transparent { 0, 0, 0, 0}; -const Color Black { 0, 0, 0, 255}; -const Color Red {255, 0, 0, 255}; -const Color Yellow {255, 255, 0, 255}; -const Color Green { 0, 255, 0, 255}; -const Color Cyan { 0, 255, 255, 255}; -const Color Blue { 0, 0, 255, 255}; -const Color Magenta {255, 0, 255, 255}; -const Color Gray {127, 127, 127, 255}; -const Color White {255, 255, 255, 255}; +const RGBA Transparent { 0, 0, 0, 0}; +const RGBA Black { 0, 0, 0, 255}; +const RGBA Red {255, 0, 0, 255}; +const RGBA Yellow {255, 255, 0, 255}; +const RGBA Green { 0, 255, 0, 255}; +const RGBA Cyan { 0, 255, 255, 255}; +const RGBA Blue { 0, 0, 255, 255}; +const RGBA Magenta {255, 0, 255, 255}; +const RGBA Gray {127, 127, 127, 255}; +const RGBA White {255, 255, 255, 255}; //@formatter:on diff --git a/src/patrix/display/DisplayMatrix_common.h b/src/patrix/display/DisplayMatrix_common.h index ff59700..8ef3f55 100644 --- a/src/patrix/display/DisplayMatrix_common.h +++ b/src/patrix/display/DisplayMatrix_common.h @@ -8,35 +8,43 @@ #define countof(a) (sizeof(a)/sizeof(a[0])) -struct Color { +struct RGBA { uint8_t r; uint8_t g; uint8_t b; uint8_t a; +}; - void blend(const Color other, const uint8_t alpha) { - const auto thisFactor = other.a * alpha / (255.0 * 255.0); - const auto otherFactor = 1.0 - thisFactor; - blend(&this->r, thisFactor, other.r, otherFactor); - blend(&this->g, thisFactor, other.g, otherFactor); - blend(&this->b, thisFactor, other.b, otherFactor); +struct RGB { + uint8_t r; + uint8_t g; + uint8_t b; + + void operator =(const RGBA& color) { + blend(&this->r, color.r, color.a); + blend(&this->g, color.g, color.a); + blend(&this->b, color.b, color.a); } - static void blend(uint8_t *thisValue, const double thisFactor, const uint8_t otherValue, const double otherFactor) { - *thisValue = static_cast(round(max(0.0, min(255.0, (*thisValue * thisFactor + otherValue * otherFactor) / 2.0)))); +private: + + static void blend(uint8_t *target, const uint8_t color, const uint8_t alpha) { + const auto factor = alpha / 255.0; + const auto newValue = (*target * (1 - factor) + color * factor) / 2.0; + *target = static_cast(round(max(0.0, min(255.0, newValue)))); } }; -extern const Color Transparent; -extern const Color Black; -extern const Color Red; -extern const Color Yellow; -extern const Color Green; -extern const Color Cyan; -extern const Color Blue; -extern const Color Magenta; -extern const Color Gray; -extern const Color White; +extern const RGBA Transparent; +extern const RGBA Black; +extern const RGBA Red; +extern const RGBA Yellow; +extern const RGBA Green; +extern const RGBA Cyan; +extern const RGBA Blue; +extern const RGBA Magenta; +extern const RGBA Gray; +extern const RGBA White; #endif diff --git a/src/patrix/display/DisplayMatrix_draw.h b/src/patrix/display/DisplayMatrix_draw.h index c50caa0..610c579 100644 --- a/src/patrix/display/DisplayMatrix_draw.h +++ b/src/patrix/display/DisplayMatrix_draw.h @@ -5,28 +5,35 @@ template void DisplayMatrix::clear() { const auto backup = foreground; foreground = Black; - this->fillRect(); + fillRect(); foreground = backup; } template -void DisplayMatrix::fillRect(const int w, const int h) const { +void DisplayMatrix::fillRect(const int w, const int h) { + if (w < 1 || h < 1) { + return; + } for (auto y = cursorY; y < cursorY + h; ++y) { for (auto x = cursorX; x < cursorX + w; ++x) { - matrix[y][x].blend(foreground, alpha); + matrix[y][x] = foreground; } } + dirty = true; } template -void DisplayMatrix::drawLine(const int w, const int h, const int thickness) const { +void DisplayMatrix::drawLine(const int w, const int h, const int thickness) { + if (w < 1 && h < 1) { + return; + } if (w >= h) { const auto m = static_cast(h) / w; for (auto t = 0; t < thickness; ++t) { const auto offset = t % 2 == 0 ? t / 2 : -t / 2; for (auto x = 0; x < w; ++x) { const auto y = static_cast(round(offset + x * m)); - matrix[cursorY + y][cursorX + x].blend(foreground, alpha); + matrix[cursorY + y][cursorX + x] = foreground; } } } else { @@ -35,10 +42,11 @@ void DisplayMatrix::drawLine(const int w, const int h, const int thickness const auto offset = t % 2 == 0 ? t / 2 : -t / 2; for (auto y = 0; y < w; ++y) { const auto x = static_cast(round(offset + y * m)); - matrix[cursorY + y][cursorX + x].blend(foreground, alpha); + matrix[cursorY + y][cursorX + x] = foreground; } } } + dirty = true; } #endif diff --git a/src/patrix/display/DisplayMatrix_print.h b/src/patrix/display/DisplayMatrix_print.h index 8843ff5..7a6dfe1 100644 --- a/src/patrix/display/DisplayMatrix_print.h +++ b/src/patrix/display/DisplayMatrix_print.h @@ -125,10 +125,10 @@ void DisplayMatrix::print(bool **s, const size_t w, const size_t h) { for (auto x = 0; x < w; x++) { const auto c = s[y][x]; if (c) { - matrix[y][x].blend(foreground, alpha); + matrix[y][x] = foreground; xMax = x > xMax ? x : xMax; } else { - matrix[y][x].blend(background, alpha); + matrix[y][x] = background; } } } @@ -136,16 +136,16 @@ void DisplayMatrix::print(bool **s, const size_t w, const size_t h) { } template -void DisplayMatrix::print(SymbolRGB8x8 s) { - print(reinterpret_cast(s),countof(SymbolRGB8x8),countof(SymbolRGB8x8[0])); +void DisplayMatrix::print(SymbolRGBA8x8 s) { + print(reinterpret_cast(s),countof(SymbolRGBA8x8),countof(SymbolRGBA8x8[0])); } template -void DisplayMatrix::print(Color **s, const size_t w, const size_t h) { +void DisplayMatrix::print(RGBA **s, const size_t w, const size_t h) { for (auto y = 0; y < h; y++) { for (auto x = 0; x < w; x++) { const auto color = s[y][x]; - matrix[y][x].blend(color, alpha); + matrix[y][x] = color; } } cursorX += w;