From 02a0bfee2b644b5e992269dd7672425a2e0f97cd Mon Sep 17 00:00:00 2001 From: Bradley Bickford Date: Sun, 9 Aug 2026 21:47:17 -0400 Subject: [PATCH] The beginnings of a rework --- diagram.json | 83 ++++++++++++++++ include/Action.h | 33 ------- include/CLEDControllerPhysicalMatrix.h | 34 +------ include/CLEDControllerPhysicalStrip.h | 2 +- include/GULLSManager.h | 41 -------- include/ILEDArrangement.h | 15 +++ include/ScanArrangement.h | 24 +++++ include/SerpentineArrangement.h | 31 ++++++ include/TiledSerpentineArrangement.h | 46 +++++++++ platformio.ini | 12 ++- src/GULLSManager.cpp | 127 ------------------------- src/main.cpp | 65 ++++++------- wokwi.toml | 5 + 13 files changed, 251 insertions(+), 267 deletions(-) create mode 100644 diagram.json delete mode 100644 include/Action.h delete mode 100644 include/GULLSManager.h create mode 100644 include/ILEDArrangement.h create mode 100644 include/ScanArrangement.h create mode 100644 include/SerpentineArrangement.h create mode 100644 include/TiledSerpentineArrangement.h delete mode 100644 src/GULLSManager.cpp create mode 100644 wokwi.toml diff --git a/diagram.json b/diagram.json new file mode 100644 index 0000000..fb0f37a --- /dev/null +++ b/diagram.json @@ -0,0 +1,83 @@ +{ + "version": 1, + "author": "Uri Shaked", + "editor": "wokwi", + "parts": [ + { + "type": "wokwi-arduino-uno", + "id": "uno", + "top": 100, + "left": 100.78, + "attrs": { + } + }, + { + "id": "neopixels", + "type": "wokwi-led-strip", + "top": 0, + "left": 0, + "attrs": { + "pixels": "6" + } + }, + { + "id": "matrix", + "type": "wokwi-led-matrix", + "top": -200, + "left": 500, + "attrs": { + "rows": "6", + "cols": "6", + "layout": "serpentine", + "pixelShape": "square" + } + }, + { + "id": "matrix2", + "type": "wokwi-led-matrix", + "top": -350, + "left": 500, + "attrs": { + "rows": "6", + "cols": "6", + "layout": "serpentine", + "pixelShape": "square" + } + }, + { + "id": "matrix3", + "type": "wokwi-led-matrix", + "top": -500, + "left": 500, + "attrs": { + "rows": "6", + "cols": "6", + "layout": "serpentine", + "pixelShape": "square" + } + } + ], + "connections": [ + ["uno:0", "$serialMonitor:TX", ""], + ["uno:1", "$serialMonitor:RX", ""], + ["uno:GND.2", "neopixels:VSS", "black"], + ["uno:6", "neopixels:DIN", "green"], + ["uno:5V", "neopixels:VDD", "red"], + ["uno:7", "matrix:DIN", "yellow"], + ["uno:5V", "matrix:VDD", "red"], + ["uno:GND.3", "matrix:VSS", "black"], + ["matrix:DOUT", "matrix2:DIN", "blue"], + ["uno:5V", "matrix2:VDD", "red"], + ["uno:GND.3", "matrix2:VSS", "black"], + ["matrix2:DOUT", "matrix3:DIN", "blue"], + ["uno:5V", "matrix3:VDD", "red"], + ["uno:GND.3", "matrix3:VSS", "black"] + ], + "dependencies": {}, + "serialMonitor": { + "collapse": false, + "convertEol": false, + "display": "always", + "newline": "lf" + } +} \ No newline at end of file diff --git a/include/Action.h b/include/Action.h deleted file mode 100644 index 7ec83fa..0000000 --- a/include/Action.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef ACTION_H -#define ACTION_H - -#include "Arduino.h" -#include "functional" -#include "StreamEvent.h" - -template -class Action { - public: - Action(function _funcEventMatchesAction, function _funcInvokeAction, - function _funcDescribeAction) : funcEventMatchesAction(_funcEventMatchesAction), - funcInvokeAction(_funcInvokeAction), funcDescribeAction(_funcDescribeAction) {} - - bool eventMatchesAction(StreamEvent* event) { - return funcEventMatchesAction(event); - } - - void describeAction(Print* printStream) { - funcDescribeAction(printStream); - } - - T* invokeAction(StreamEvent* event) { - return funcInvokeAction(event); - } - - private: - function funcEventMatchesAction; - function funcInvokeAction; - function funcDescribeAction; -}; - -#endif \ No newline at end of file diff --git a/include/CLEDControllerPhysicalMatrix.h b/include/CLEDControllerPhysicalMatrix.h index c9f3f29..9a43692 100644 --- a/include/CLEDControllerPhysicalMatrix.h +++ b/include/CLEDControllerPhysicalMatrix.h @@ -2,17 +2,11 @@ #define CLEDCONTROLLERPHYSICALMATRIX_H #include "LEDHAL2D.h" - -enum ArrangementType { - HORIZONTALSCAN, - HORIZONTALSERPENTINE, - COLUMNSCAN, - COLUMNSERPENTINE -}; +#include "ILEDArrangement.h" class CLEDControllerPhysicalMatrix : public LEDHAL2D { public: - CLEDControllerPhysicalMatrix(CLEDController* _controller, char* ledName, ArrangementType _arrangement, + CLEDControllerPhysicalMatrix(CLEDController* _controller, char* ledName, ILEDArrangement& _arrangement, int16_t width, int16_t height): LEDHAL2D(width, height, ledName, true), controller(_controller), arrangement(_arrangement) {} virtual ~CLEDControllerPhysicalMatrix() {} @@ -33,25 +27,7 @@ class CLEDControllerPhysicalMatrix : public LEDHAL2D { } int16_t XY(int16_t x, int16_t y) { - if(arrangement == ArrangementType::HORIZONTALSCAN) { - return getWidth() * y + x; - } else if(arrangement == ArrangementType::COLUMNSCAN) { - return getHeight() * x + y; - } else if(arrangement == ArrangementType::HORIZONTALSERPENTINE) { - if(y & 0x1) { - return y * getWidth() + (getWidth() - 1 - x); - } else { - return y * getWidth() + x; - } - } else if(arrangement == ArrangementType::COLUMNSERPENTINE) { - if(x & 0x1) { - return x * getHeight() + (getHeight() - 1 - y); - } else { - return x * getHeight() + y; - } - } else { - return 0; //How did you get here? - } + return arrangement.XY(x, y, getWidth(), getHeight()); } uint16_t getNumLEDs() { @@ -60,13 +36,13 @@ class CLEDControllerPhysicalMatrix : public LEDHAL2D { protected: void updateLEDs() { - controller->showLeds(); + controller->showLeds(255); } private: CLEDController* controller; - ArrangementType + ILEDArrangement& arrangement; }; diff --git a/include/CLEDControllerPhysicalStrip.h b/include/CLEDControllerPhysicalStrip.h index 2427c7e..4863663 100644 --- a/include/CLEDControllerPhysicalStrip.h +++ b/include/CLEDControllerPhysicalStrip.h @@ -13,7 +13,7 @@ class CLEDControllerPhysicalStrip : public LEDHAL { void setColor(int16_t pixel, CRGB color) { controller->leds()[pixel] = color; } protected: - void updateLEDs() { controller->showLeds(); } + void updateLEDs() { controller->showLeds(255); } private: diff --git a/include/GULLSManager.h b/include/GULLSManager.h deleted file mode 100644 index 39875c2..0000000 --- a/include/GULLSManager.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef GULLSMANAGER_H -#define GULLSMANAGER_H - -#include "Arduino.h" -#include "Action.h" -#include "LEDHAL.h" -#include "AnimationBase.h" - -class GULLSManager { - public: - GULLSManager(Stream* _stream, uint16_t _maxHALs, uint16_t _maxAnimations, - uint16_t _maxResponseActions, uint16_t _maxAnimationBuilderActions); - - bool addLEDHAL(LEDHAL* hal); - - bool addAnimation(AnimationBase* animation); - - bool addResponseAction(Action* action); - - bool addAnimationBuilderAction(Action* action); - - void update(); - private: - uint16_t - maxHALs, - maxAnimations, - maxResponseActions, - maxAnimationBuilderActions; - Stream* - stream; - LEDHAL** - hals; - AnimationBase** - animations; - Action** - responseActions; - Action** - animationBuilderActions; -}; - -#endif \ No newline at end of file diff --git a/include/ILEDArrangement.h b/include/ILEDArrangement.h new file mode 100644 index 0000000..e403566 --- /dev/null +++ b/include/ILEDArrangement.h @@ -0,0 +1,15 @@ +#ifndef ILEDARRANGEMENT_H +#define ILEDARRANGEMENT_H + +#include + +// Interface is not pure virtual +class ILEDArrangement { + public: + ILEDArrangement() {} + virtual ~ILEDArrangement() {} + + virtual int16_t XY(int16_t x, int16_t y, int16_t width, int16_t height) = 0; +}; + +#endif \ No newline at end of file diff --git a/include/ScanArrangement.h b/include/ScanArrangement.h new file mode 100644 index 0000000..c45a847 --- /dev/null +++ b/include/ScanArrangement.h @@ -0,0 +1,24 @@ +#ifndef SCANARRANGEMENT_H +#define SCANARRANGEMENT_H + +#include "ILEDArrangement.h" + +class ScanArrangement : public ILEDArrangement { + public: + ScanArrangement(bool _isColumnScan) : isColumnScan(_isColumnScan) {} + virtual ~ScanArrangement() {} + + int16_t XY(int16_t x, int16_t y, int16_t width, int16_t height) { + if(isColumnScan) { + return height * x + y; + } else { + return width * y + x; + } + } + + private: + bool + isColumnScan; +}; + +#endif \ No newline at end of file diff --git a/include/SerpentineArrangement.h b/include/SerpentineArrangement.h new file mode 100644 index 0000000..568ca6d --- /dev/null +++ b/include/SerpentineArrangement.h @@ -0,0 +1,31 @@ +#ifndef SERPENTINEARRANGEMENT_H +#define SERPENTINEARRANGEMENT_H + +#include "ILEDArrangement.h" + +class SerpentineArrangement : public ILEDArrangement { + public: + SerpentineArrangement(bool _isColumnSerpentine) : isColumnSerpentine(_isColumnSerpentine) {} + virtual ~SerpentineArrangement() {} + + int16_t XY(int16_t x, int16_t y, int16_t width, int16_t height) { + if(isColumnSerpentine) { + if(x & 0x1) { + return x * height + (height - 1 - y); + } else { + return x * height + y; + } + } else { + if(y & 0x1) { + return y * width + (width - 1 - x); + } else { + return y * width + x; + } + } + } + private: + bool + isColumnSerpentine; +}; + +#endif \ No newline at end of file diff --git a/include/TiledSerpentineArrangement.h b/include/TiledSerpentineArrangement.h new file mode 100644 index 0000000..36cbe42 --- /dev/null +++ b/include/TiledSerpentineArrangement.h @@ -0,0 +1,46 @@ +#ifndef TILEDSERPENTINEARRANGEMENT_H +#define TILEDSERPENTINEARRANGEMENT_H + +#include "ILEDArrangement.h" + +class TiledSerpentineArrangement : public ILEDArrangement { + public: + TiledSerpentineArrangement(bool _isColumnSerpentine, bool _isVerticallyTiled, + int16_t _tileWidth, int16_t _tileHeight) : isColumnSerpentine(_isColumnSerpentine), + isVerticallyTiled(_isVerticallyTiled), tileWidth(_tileWidth), tileHeight(_tileHeight) {} + virtual ~TiledSerpentineArrangement() {} + + int16_t XY(int16_t x, int16_t y, int16_t width, int16_t height) { + int16_t tileNumber = isVerticallyTiled ? y / tileHeight : x / tileHeight; + + int16_t modX = x % tileWidth; + int16_t modY = y % tileHeight; + + int16_t tilePosition = 0; + + if(isColumnSerpentine) { + if (x & 0x1) { + tilePosition = modX * tileHeight + (tileHeight - 1 - modY); + } else { + tilePosition = modX * tileHeight + modY; + } + } else { + if (y & 0x1) { + tilePosition = modY * tileWidth + (tileWidth - 1 - modX); + } else { + tilePosition = modY * tileWidth + modX; + } + } + + return tileWidth * tileHeight * tileNumber + tilePosition; + } + private: + bool + isColumnSerpentine, + isVerticallyTiled; + int16_t + tileWidth, + tileHeight; +}; + +#endif \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index c797682..a8a8730 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,7 +9,17 @@ ; https://docs.platformio.org/page/projectconf.html [platformio] -default_envs = teensy36 +default_envs = uno + +[env:uno] +platform = atmelavr +board = uno +framework = arduino +lib_deps = + fastled/FastLED@3.10.1 + pfeerick/elapsedMillis@^1.0.6 + adafruit/Adafruit GFX Library@^1.11.9 + arduino-libraries/SD@^1.3.0 [common] diff --git a/src/GULLSManager.cpp b/src/GULLSManager.cpp deleted file mode 100644 index 99a7588..0000000 --- a/src/GULLSManager.cpp +++ /dev/null @@ -1,127 +0,0 @@ -#include "GULLSManager.h" - -GULLSManager::GULLSManager(Stream* _stream, uint16_t _maxHALs, uint16_t _maxAnimations, - uint16_t _maxResponseActions, uint16_t _maxAnimationBuilderActions) { - - stream = _stream; - maxHALs = _maxHALs; - maxAnimations = _maxAnimations; - maxResponseActions = _maxResponseActions; - maxAnimationBuilderActions = _maxAnimationBuilderActions; - - hals = new LEDHAL*[maxHALs]; - - for(uint16_t i = 0; i < maxHALs; i++) { - hals[i] = nullptr; - } - - animations = new AnimationBase*[maxAnimations]; - - for(uint16_t i = 0; i < maxAnimations; i++) { - animations[i] = nullptr; - } - - responseActions = new Action*[maxResponseActions]; - - for(uint16_t i = 0; i < maxResponseActions; i++) { - responseActions[i] = nullptr; - } - - animationBuilderActions = new Action*[maxAnimationBuilderActions]; - - for(uint16_t i = 0; i < maxAnimationBuilderActions; i++) { - animationBuilderActions[i] = nullptr; - } -} - -bool GULLSManager::addLEDHAL(LEDHAL* hal) { - for(uint16_t i = 0; i < maxHALs; i++) { - if(hals[i] == nullptr) { - hals[i] = hal; - return true; - } - } - - return false; -} - -bool GULLSManager::addAnimation(AnimationBase* animation) { - for(uint16_t i = 0; i < maxAnimations; i++) { - if(animations[i] == nullptr) { - animations[i] = animation; - return true; - } - } - - return false; -} - -bool GULLSManager::addResponseAction(Action* action) { - for(uint16_t i = 0; i < maxResponseActions; i++) { - if(responseActions[i] == nullptr) { - responseActions[i] = action; - return true; - } - } - - return false; -} - -bool GULLSManager::addAnimationBuilderAction(Action* action) { - for(uint16_t i = 0; i < maxAnimationBuilderActions; i++) { - if(animationBuilderActions[i] == nullptr) { - animationBuilderActions[i] = action; - return true; - } - } - - return false; -} - -void GULLSManager::update() { - if(stream->available()) { - StreamEvent event(stream); - - for(uint16_t i = 0; i < maxResponseActions; i++) { - if(responseActions[i] != nullptr) { - if(responseActions[i]->eventMatchesAction(&event)) { - stream->write(responseActions[i]->invokeAction(&event)); - - event.markHandled(); - break; - } - } - } - - if(!event.isHandled()) { - for(uint16_t i = 0; i < maxAnimationBuilderActions; i++) { - if(animationBuilderActions[i] != nullptr) { - if(animationBuilderActions[i]->eventMatchesAction(&event)) { - this->addAnimation(animationBuilderActions[i]->invokeAction(&event)); - - event.markHandled(); - break; - } - } - } - } - - if(!event.isHandled()) { - stream->print(F("ERROR: An event with code ")); - stream->print(event.getCode()); - stream->println(F(" was registered but went unprocessed by any actions!")); - } - } - - for(uint16_t i = 0; i < maxAnimations; i++) { - if(animations[i] != nullptr) { - animations[i]->update(); - } - } - - for(uint16_t i = 0; i < maxHALs; i++) { - if(hals[i] != nullptr) { - hals[i]->show(); - } - } -} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 00c54e8..ca49cab 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,59 +1,54 @@ #include - -#include "MatrixHardware_Teensy3_ShieldV1toV3.h" -#include "SmartMatrix.h" - #include "FastLED.h" #include "LEDHAL.h" #include "LEDHAL2D.h" #include "CLEDControllerPhysicalStrip.h" #include "CLEDControllerPhysicalMatrix.h" -#include "SmartMatrixPhysicalMatrix.h" - -#define NUMLEDS 24 - -#define COLOR_DEPTH 24 // known working: 24, 48 - If the sketch uses type `rgb24` directly, COLOR_DEPTH must be 24 - -const uint8_t kMatrixWidth = 96; // known working: 32, 64, 96, 128 -const uint8_t kMatrixHeight = 64; // known working: 16, 32, 48, 64 -const uint8_t kRefreshDepth = 36; // known working: 24, 36, 48 -const uint8_t kDmaBufferRows = 4; // known working: 2-4, use 2 to save memory, more to keep from dropping frames and automatically lowering refresh rate -const uint8_t kPanelType = SMARTMATRIX_HUB75_32ROW_MOD16SCAN; // use SMARTMATRIX_HUB75_16ROW_MOD8SCAN for common 16x32 panels -const uint8_t kMatrixOptions = SMARTMATRIX_OPTIONS_BOTTOM_TO_TOP_STACKING; // see http://docs.pixelmatix.com/SmartMatrix for options -const uint8_t kBackgroundLayerOptions = (SM_BACKGROUND_OPTIONS_NONE); -const uint8_t kScrollingLayerOptions = (SM_SCROLLING_OPTIONS_NONE); - -SMARTMATRIX_ALLOCATE_BUFFERS(matrix, kMatrixWidth, kMatrixHeight, kRefreshDepth, kDmaBufferRows, kPanelType, kMatrixOptions); -SMARTMATRIX_ALLOCATE_BACKGROUND_LAYER(backgroundLayer, kMatrixWidth, kMatrixHeight, COLOR_DEPTH, kBackgroundLayerOptions); +#include "SerpentineArrangement.h" +#include "TiledSerpentineArrangement.h" +#define NUMLEDS 6 +#define WIDTH 6 +#define HEIGHT 18 +#define TILE_WIDTH 6 +#define TILE_HEIGHT 6 CRGB leds[NUMLEDS]; -CRGB leds2[NUMLEDS]; -CRGB leds3[NUMLEDS]; +CRGB leds2D[WIDTH * HEIGHT]; -CRGB someColor(255, 255, 255); +CRGB rainbow[] = {CRGB::Red, CRGB::Orange, CRGB::Yellow, CRGB::Green, CRGB::Blue, CRGB::Purple}; LEDHAL* hal; LEDHAL2D* hal2D; -LEDHAL2D* smHAL; -rgb24 canRGB24Translate(rgb24 color) { - color.red = 0; +uint16_t shiftNumber = 0; - return color; -} +SerpentineArrangement arrangement(false); +TiledSerpentineArrangement tileArrangement(false, true, TILE_WIDTH, TILE_HEIGHT); void setup() { + Serial.begin(115200); + Serial.println("Hello World!"); CLEDController* controller = &FastLED.addLeds(leds, NUMLEDS); - CLEDController* controller2d = &FastLED.addLeds(leds2, NUMLEDS); + CLEDController* controller2D = &FastLED.addLeds(leds2D, WIDTH * HEIGHT); hal = new CLEDControllerPhysicalStrip(controller, "Test Strip"); - hal2D = new CLEDControllerPhysicalMatrix(controller2d, "Test Matrix", ArrangementType::COLUMNSERPENTINE, 6, 4); - smHAL = new SmartMatrixPhysicalMatrix(&backgroundLayer, "Test SM Matrix", kMatrixWidth, kMatrixHeight); - - canRGB24Translate(someColor); + hal2D = new CLEDControllerPhysicalMatrix(controller2D, "Test Matrix", arrangement, WIDTH, HEIGHT); } void loop() { - // put your main code here, to run repeatedly: + for(uint8_t i = 0; i < 6; i++) { + hal->setColor(i, rainbow[(i + shiftNumber) % 6]); + } + + for(uint8_t i = 0; i < HEIGHT; i++) { + hal2D->drawFastHLine(0, i, WIDTH, rainbow[(i + shiftNumber) % 6]); + } + + hal->requestShow(); + hal->show(); + hal2D->requestShow(); + hal2D->show(); + shiftNumber++; + delay(300); } diff --git a/wokwi.toml b/wokwi.toml new file mode 100644 index 0000000..91af336 --- /dev/null +++ b/wokwi.toml @@ -0,0 +1,5 @@ +[wokwi] +version = 1 +firmware = '.pio/build/uno/firmware.hex' +elf = '.pio/build/uno/firmware.elf' +gdbServerPort=3333 \ No newline at end of file