G.U.L.L.S. rebuilt to use PlatformIO

This commit is contained in:
Bradley Bickford 2024-07-01 19:18:45 -04:00
commit f934849576
55 changed files with 4082 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch

10
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,10 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
],
"unwantedRecommendations": [
"ms-vscode.cpptools-extension-pack"
]
}

40
README.md Normal file
View File

@ -0,0 +1,40 @@
<img src="/images/terrible logo.png" width="300" height="175"/><h1>Grand Unified LED Logic Software (G.U.L.L.S.)</h1>
*I need to write something here*
##### LED Hardware Development Status
| Hardware Support | Written? | Tested? |
| ---------------- | ------------------ | ------------------ |
| FastLED Strip | :heavy_check_mark: | |
| FastLED Matrix | :heavy_check_mark: | |
| SmartMatrix | :heavy_check_mark: | :heavy_check_mark: |
##### Animations Development Status (Some will require both 1D and 2D implementations)
| Animation Name | New? | Written? | Tested? |
| --------------------- | ------------------ | ------------------ | ------------------ |
| AlternateMatrix | | :heavy_check_mark: | :heavy_check_mark: |
| AlternateStrip | | :heavy_check_mark: | :heavy_check_mark: |
| CollisionMatrix | | :heavy_check_mark: | |
| CollisionStrip | | :heavy_check_mark: | |
| CycleLightMatrix | | :heavy_check_mark: | |
| CycleLightStrip | | :heavy_check_mark: | |
| FireworksMatrix | | :heavy_check_mark: | |
| FluidColorMatrix | | :heavy_check_mark: | |
| ColorRandomizerMatrix | | :heavy_check_mark: | |
| ColorRandomizerStrip | | :heavy_check_mark: | |
| PlasmaMatrix | | :heavy_check_mark: | |
| RicochetMatrix | | :heavy_check_mark: | |
| TextMatrix | :heavy_check_mark: | | |
| TripCyclingMatrix | | | |
| TripCyclingStrip | | | |
| GIFMatrix | :heavy_check_mark: | | |
| FlameMatrix | :heavy_check_mark: | | |
| RainfallMatrix | :heavy_check_mark: | | |
| Conway'sMatrix | :heavy_check_mark: | | |
| CycloneMatrix | :heavy_check_mark: | :heavy_check_mark: | |
##### Notes / Extra To Do's:
- CycloneMatrix (specifically CycloneHelper, a component of this animation) is liable to have a ton of problems as it had to be mostly rewritten from the original Java version because dynamically expanding arrays aren't available to make the job easy (or at the very least, implementing dynamically expanding arrays is a lot of work and adds an amount of memory overhead I'm not comfortable with). More than just surface level "does the animation display properly" testing needs to be done to make sure nothings going to get all corrupted and nasty.

BIN
images/terrible logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 543 KiB

46
include/AlternateMatrix.h Normal file
View File

@ -0,0 +1,46 @@
#ifndef ALTERNATEMATRIX_H
#define ALTERNATEMATRIX_H
#include "LEDHAL2D.h"
#include "MatrixAnimation.h"
enum AlternateType {
HORIZONTAL_ALTERNATE,
VERTICAL_ALTERNATE
};
class AlternateMatrix : public MatrixAnimation {
public:
AlternateMatrix(LEDHAL2D* _matrix, char* _refName, long _updateTime, CRGB* _colors,
uint8_t _numColors, AlternateType _type) : MatrixAnimation(_matrix, _refName, _updateTime),
numColors(_numColors), colors(new CRGB[_numColors]), alternateInt(0), type(_type) {
for(uint8_t i = 0; i < _numColors; i++) {
colors[i] = _colors[i];
}
}
virtual ~AlternateMatrix() { delete colors; }
void initialize() {
alternateInt = 0;
resetTimer();
}
void execute();
AlternateType getType() {
return type;
}
private:
uint16_t
alternateInt;
CRGB*
colors;
uint8_t
numColors;
AlternateType
type;
};
#endif

34
include/AlternateStrip.h Normal file
View File

@ -0,0 +1,34 @@
#ifndef ALTERNATESTRIP_H
#define ALTERNATESTRIP_H
#include "LEDHAL.h"
#include "StripAnimation.h"
class AlternateStrip : public StripAnimation {
public:
AlternateStrip(LEDHAL* _strip, char* _refName, long _updateTime, CRGB* _colors,
uint8_t _numColors) : StripAnimation(_strip, _refName, _updateTime),
numColors(_numColors), colors(new CRGB[_numColors]), alternateInt(0) {
for(uint8_t i = 0; i < _numColors; i++) {
colors[i] = _colors[i];
}
}
virtual ~AlternateStrip() { delete colors; }
void initialize() {
alternateInt = 0;
resetTimer();
}
void execute();
private:
uint16_t
alternateInt;
CRGB*
colors;
uint8_t
numColors;
};
#endif

75
include/AnimationBase.h Normal file
View File

@ -0,0 +1,75 @@
#ifndef ANIMATIONBASE_H
#define ANIMATIONBASE_H
#include "elapsedMillis.h"
class AnimationBase {
public:
AnimationBase(char* _refName, long _updateTime)
: refName(_refName), updateTime(_updateTime),
enabled(false), initialized(false), timer(0) {}
virtual ~AnimationBase() {
delete refName;
}
virtual void initialize() {}
virtual void execute() {}
virtual bool isFinished() {
return false;
}
void update() {
if (enabled) {
if (timer >= updateTime) {
if (!initialized) {
initialize();
initialized = true;
}
if (!isFinished()) {
execute();
}
resetTimer();
}
}
}
void enable() {
enabled = true;
}
void disable() {
enabled = false;
}
void reinitialize() {
initialized = false;
}
bool isEnabled() {
return enabled;
}
char* getReferenceName() {
return refName;
}
protected:
void resetTimer() {
timer = 0;
}
private:
char*
refName;
long
updateTime;
bool
enabled,
initialized;
elapsedMillis
timer;
};
#endif

View File

@ -0,0 +1,73 @@
#ifndef CLEDCONTROLLERPHYSICALMATRIX_H
#define CLEDCONTROLLERPHYSICALMATRIX_H
#include "LEDHAL2D.h"
enum ArrangementType {
HORIZONTALSCAN,
HORIZONTALSERPENTINE,
COLUMNSCAN,
COLUMNSERPENTINE
};
class CLEDControllerPhysicalMatrix : public LEDHAL2D {
public:
CLEDControllerPhysicalMatrix(CLEDController* _controller, char* ledName, ArrangementType _arrangement,
int16_t width, int16_t height): LEDHAL2D(width, height, ledName, true), controller(_controller), arrangement(_arrangement) {}
virtual ~CLEDControllerPhysicalMatrix() {}
void drawPixel(int16_t x, int16_t y, CRGB color) {
controller->leds()[XY(x, y)] = color;
}
void setColor(int16_t pixel, CRGB color) {
controller->leds()[pixel] = color;
}
CRGB getColor(int16_t pixel) {
return controller->leds()[pixel];
}
CRGB getColor(int16_t x, int16_t y) {
return getColor(XY(x, y));
}
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?
}
}
uint16_t getNumLEDs() {
return getWidth() * getHeight();
}
protected:
void updateLEDs() {
controller->showLeds();
}
private:
CLEDController*
controller;
ArrangementType
arrangement;
};
#endif

View File

@ -0,0 +1,24 @@
#ifndef CLEDCONTROLLERPHYSICALSTRIP_H
#define CLEDCONTROLLERPHYSICALSTRIP_H
#include "LEDHAL.h"
class CLEDControllerPhysicalStrip : public LEDHAL {
public:
CLEDControllerPhysicalStrip(CLEDController* _controller, char* _ledName) :
LEDHAL(_ledName, true), controller(_controller) {}
uint16_t getNumLEDs() { return controller->size(); }
CRGB getColor(int16_t pixel) { return controller->leds()[pixel]; }
void setColor(int16_t pixel, CRGB color) { controller->leds()[pixel] = color; }
protected:
void updateLEDs() { controller->showLeds(); }
private:
CLEDController*
controller;
};
#endif

39
include/CollisionMatrix.h Normal file
View File

@ -0,0 +1,39 @@
#ifndef COLLISIONMATRIX_H
#define COLLISIONMATRIX_H
#include "MatrixAnimation.h"
enum CollisionType {
HORIZONTAL_COLLISION,
VERTICAL_COLLISION
};
class CollisionMatrix : public MatrixAnimation {
public:
CollisionMatrix(LEDHAL2D* _matrix, char* _refName, long _updateTime, CRGB _color1,
CRGB _color2, CollisionType _type) : MatrixAnimation(_matrix, _refName, _updateTime),
color1(_color1), color2(_color2), type(_type), collisionInt(0) {}
virtual ~CollisionMatrix() {}
void initialize() {
collisionInt = 0;
resetTimer();
}
void execute();
CollisionType getType() {
return type;
}
private:
uint16_t
collisionInt;
CRGB
color1,
color2;
CollisionType
type;
};
#endif

28
include/CollisionStrip.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef COLLISIONSTRIP_H
#define COLLISIONSTRIP_H
#include "StripAnimation.h"
#include "LEDHAL.h"
class CollisionStrip : public StripAnimation {
public:
CollisionStrip(LEDHAL* _strip, char* _refName, long _updateTime, CRGB _color1,
CRGB _color2) : StripAnimation(_strip, _refName, _updateTime), color1(_color1),
color2(_color2), collisionInt(0) {}
virtual ~CollisionStrip() {}
void initialize() {
collisionInt = 0;
resetTimer();
}
void execute();
private:
uint16_t
collisionInt;
CRGB
color1,
color2;
};
#endif

View File

@ -0,0 +1,68 @@
#ifndef COLORRANDOMIZERMATRIX_H
#define COLORRANDOMIZERMATRIX_H
#include "MatrixAnimation.h"
#include "LEDHAL2D.h"
#define DEFAULT_MATRIX_FADER 64
enum ColorRandomizerType {
HORIZONTAL_COLORRANDOMIZER,
VERTICAL_COLORRANDOMIZER
};
class ColorRandomizerMatrix : public MatrixAnimation {
public:
ColorRandomizerMatrix(LEDHAL2D* _matrix, char* _refName, long _updateTime, bool _fade,
uint8_t _numColors, CRGB* _colors, ColorRandomizerType _type) :
MatrixAnimation(_matrix, _refName, _updateTime), numColors(_numColors),
colors(new CRGB[_numColors]), fade(_fade), colorRandomizerInt(0),
scale(DEFAULT_MATRIX_FADER) {
for(uint8_t i = 0; i < _numColors; i++) {
colors[i] = _colors[i];
}
}
virtual ~ColorRandomizerMatrix() { delete colors; delete fadingValues; }
void initialize() {
colorRandomizerInt = 0;
isFading = false;
if(fadingValues != nullptr) {
delete fadingValues;
}
if(type == ColorRandomizerType::HORIZONTAL_COLORRANDOMIZER) {
fadingValues = new CRGB[matrix->getHeight()];
} else {
fadingValues = new CRGB[matrix->getWidth()];
}
}
void execute();
void setFade(bool _fade) { fade = _fade; initialize(); }
bool getFade() { return fade; }
void setFadeScale(uint8_t _scale) { scale = _scale; initialize(); }
uint8_t getFadeScale() { return scale; }
void setType(ColorRandomizerType _type) { type = _type; initialize(); }
ColorRandomizerType getType() { return type; }
private:
CRGB
*colors,
*fadingValues;
uint16_t
colorRandomizerInt;
uint8_t
scale,
numColors;
bool
isFading,
fade;
ColorRandomizerType
type;
};
#endif

View File

@ -0,0 +1,50 @@
#ifndef COLORRANDOMIZERSTRIP_H
#define COLORRANDOMIZERSTRIP_H
#include "StripAnimation.h"
#include "LEDHAL.h"
#define DEFAULT_STRIP_FADER 64
class ColorRandomizerStrip : public StripAnimation {
public:
ColorRandomizerStrip(LEDHAL* _strip, char* _refName, long _updateTime, bool _fade,
uint8_t _numColors, CRGB* _colors) : StripAnimation(_strip, _refName, _updateTime),
numColors(_numColors), colors(new CRGB[_numColors]),
fadingValues(new CRGB[_numColors]), fade(_fade), colorRandomizerInt(0),
scale(DEFAULT_STRIP_FADER) {
for(uint8_t i = 0; i < _numColors; i++) {
colors[i] = _colors[i];
}
}
virtual ~ColorRandomizerStrip() { delete colors; delete fadingValues; }
void initialize() {
colorRandomizerInt = 0;
isFading = false;
resetTimer();
}
void execute();
void setFade(bool _fade) { fade = _fade; initialize(); }
bool getFade() { return fade; }
void setFadeScale(uint8_t _scale) { scale = _scale; initialize(); }
uint8_t getFadeScale() { return scale; }
private:
CRGB
*colors,
*fadingValues;
uint16_t
colorRandomizerInt;
uint8_t
scale,
numColors;
bool
isFading,
fade;
};
#endif

View File

@ -0,0 +1,47 @@
#ifndef CYCLELIGHTMATRIX_H
#define CYCLELIGHTMATRIX_H
#include "MatrixAnimation.h"
enum CycleLightType {
HORIZONTAL_CYCLELIGHT,
VERTICAL_CYCLELIGHT
};
class CycleLightMatrix : public MatrixAnimation {
public:
CycleLightMatrix(LEDHAL2D* _matrix, char* _refName, long _updateTime, CRGB* _colors,
uint8_t _numColors, CycleLightType _type) : MatrixAnimation(_matrix, _refName,
_updateTime), numColors(_numColors), colors(new CRGB[_numColors]),
cycleLightInt(0), cycleLightColor(0), type(_type) {
for(uint8_t i = 0; i < _numColors; i++) {
colors[i] = _colors[i];
}
}
virtual ~CycleLightMatrix() { delete colors; }
void initialize() {
cycleLightInt = 0;
cycleLightColor = 0;
resetTimer();
}
void execute();
CycleLightType getType() {
return type;
}
private:
uint16_t
cycleLightInt,
cycleLightColor;
CRGB*
colors;
uint8_t
numColors;
CycleLightType
type;
};
#endif

38
include/CycleLightStrip.h Normal file
View File

@ -0,0 +1,38 @@
#ifndef CYCLELIGHTSTRIP_H
#define CYCLELIGHTSTRIP_H
#include "StripAnimation.h"
#include "LEDHAL.h"
class CycleLightStrip : public StripAnimation {
public:
CycleLightStrip(LEDHAL* _strip, char* _refName, long _updateTime, uint8_t _numColors,
CRGB* _colors) : StripAnimation(_strip, _refName, _updateTime),
numColors(_numColors), colors(new CRGB[_numColors]), cycleLightInt(0),
cycleLightColor(0) {
for(uint8_t i = 0; i < _numColors; i++) {
colors[i] = _colors[i];
}
}
virtual ~CycleLightStrip() { delete colors; }
void initialize() {
cycleLightInt = 0;
cycleLightColor = 0;
resetTimer();
}
void execute();
private:
uint16_t
cycleLightInt,
cycleLightColor;
CRGB*
colors;
uint8_t
numColors;
};
#endif

60
include/CycloneHelper.h Normal file
View File

@ -0,0 +1,60 @@
#ifndef CYCLONEHELPER_H
#define CYCLONEHELPER_H
#include "Arduino.h"
#include "Point2D.h"
#include "LEDHAL2D.h"
class CycloneHelper {
public:
CycloneHelper(CRGB _color, uint16_t _originX, uint16_t _originY,
uint8_t _radius, uint8_t _spinDirection) : color(_color), originX(_originX),
originY(_originY), radius(_radius), spinDirection(_spinDirection),
currentDrawAngle(0) {
numberOfTails = (uint8_t) round(PI * _radius * 2);
tailColors = new CRGB[numberOfTails];
tailPoints = new Point2D[numberOfTails];
float redScaler = ((float) color.red) / numberOfTails;
float greenScaler = ((float) color.green) / numberOfTails;
float blueScaler = ((float) color.blue) / numberOfTails;
for(uint8_t i = 0; i < numberOfTails; i++) {
tailColors[i] = CRGB(
min(round(redScaler * (i + 1)), color.red),
min(round(greenScaler * (i + 1)), color.green),
min(round(blueScaler * (i + 1)), color.blue)
);
}
nextPoint = Point2D(
_originX + (uint16_t) round(radius * cosf(currentDrawAngle)),
_originY + (uint16_t) round(radius * sinf(currentDrawAngle))
);
}
void updateAndRedraw(LEDHAL2D* matrix);
private:
CRGB
color;
CRGB*
tailColors;
Point2D
nextPoint;
Point2D*
tailPoints;
int8_t
spinDirection;
uint8_t
radius,
numberOfTails;
uint16_t
originX,
originY;
int16_t
currentDrawAngle;
};
#endif

63
include/CycloneMatrix.h Normal file
View File

@ -0,0 +1,63 @@
#ifndef CYCLONEMATRIX_H
#define CYCLONEMATRIX_H
#include "LEDHAL2D.h"
#include "CycloneHelper.h"
#include "MatrixAnimation.h"
class CycloneMatrix : public MatrixAnimation {
public:
CycloneMatrix(LEDHAL2D* _matrix, char* _refName, long _updateTime, uint16_t originX,
uint16_t originY, uint8_t _startRadius, uint8_t _endRadius, uint8_t numColors,
CRGB* _colors) : MatrixAnimation(_matrix, _refName, _updateTime),
startRadius(_startRadius), endRadius(_endRadius) {
colors = new CRGB[numColors];
for(uint8_t i = 0; i < numColors; i++) {
colors[i] = _colors[i];
}
helpers = new CycloneHelper*[_endRadius - _startRadius];
// The colors are currently being passed in such a way that I believe
// there being taken into the CycloneHelper through value, rather than ByRef
// i.e. wasting memory
for(uint8_t i = 0; i < _endRadius - _startRadius; i++) {
helpers[i] = new CycloneHelper(
colors[random(0, numColors)],
originX, originY,
_startRadius + i,
random(0, 100000) % 2 == 0 ? 1 : -1
);
}
}
virtual ~CycloneMatrix() { delete helpers; delete colors; }
// I don't know that there is a nice, memory friendly way to
// reset this yet...
void initialize() {
resetTimer();
}
void execute() {
matrix->clearLEDs();
for(uint8_t i = 0; i < endRadius - startRadius; i++) {
helpers[i]->updateAndRedraw(matrix);
}
matrix->requestShow();
}
private:
uint8_t
startRadius,
endRadius;
CRGB*
colors;
CycloneHelper**
helpers;
};
#endif

View File

@ -0,0 +1,37 @@
#ifndef DECODINGBITSTREAM_H
#define DECODINGBITSTREAM_H
#include "SD.h"
class DecodingBitStream
{
public:
DecodingBitStream(File* _stream, uint8_t _bytesAvailable, uint16_t _numberOfBitsInCode) :
stream(_stream), bytesAvailable(_bytesAvailable), numberOfBitsInCode(_numberOfBitsInCode),
bitBuffer(0), bitsAvailable(0) {}
~DecodingBitStream() {}
void setNumberOfBitsInCode(uint16_t _numberOfBitsInCode) { numberOfBitsInCode = _numberOfBitsInCode; }
void setBytesAvailable(uint8_t _bytesAvailable) { bytesAvailable = _bytesAvailable; }
uint16_t getCode();
uint16_t getNumberOfBitsInCode() { return numberOfBitsInCode; }
bool dataRemainingInBlock() { return bytesAvailable > 0 || bitsAvailable > 0; }
static uint16_t getNumberOfBitsToRepresentValue(uint16_t value);
private:
void
verifyEnoughBits(void);
uint16_t
bitBuffer;
uint8_t
bytesAvailable,
bitsAvailable,
numberOfBitsInCode;
File*
stream;
};
#endif

42
include/FireworksMatrix.h Normal file
View File

@ -0,0 +1,42 @@
#ifndef FIREWORKSMATRIX_H
#define FIREWORKSMATRIX_H
#include "MatrixAnimation.h"
typedef struct _firework_t {
int16_t xPos;
int16_t yPos;
int16_t yMaxHeight;
uint16_t currentRadius;
uint16_t radius;
CRGB color;
bool isActive;
} Firework_t;
class FireworksMatrix : public MatrixAnimation {
public:
FireworksMatrix(LEDHAL2D* _matrix, char* _refName, long _updateTime, CRGB* _colors,
uint8_t _numColors, uint8_t _maxRadius, uint8_t _maxFireworks) :
MatrixAnimation(_matrix, _refName, _updateTime), colors(new CRGB[_numColors]),
numColors(_numColors), maxRadius(_maxRadius), maxFireworks(_maxFireworks) {
for(uint8_t i = 0; i < _numColors; i++) {
colors[i] = _colors[i];
}
}
virtual ~FireworksMatrix() { delete[] colors; delete[] fireworks; }
void initialize();
void execute();
private:
uint8_t
maxFireworks,
numColors,
maxRadius;
CRGB*
colors;
Firework_t*
fireworks;
};
#endif

View File

@ -0,0 +1,41 @@
#ifndef FLUIDCOLORMATRIX_H
#define FLUIDCOLORMATRIX_H
#include "MatrixAnimation.h"
enum FluidColorType {
PIXEL_BY_PIXEL_FLUIDCOLOR,
HORIZONTAL_FLUIDCOLOR,
VERTICAL_FLUIDCOLOR
};
enum FluidColorResolution {
FULL_FLUIDCOLOR,
HALF_FLUIDCOLOR,
QUATER_FLUIDCOLOR,
EIGHTH_FLUIDCOLOR
};
class FluidColorMatrix : public MatrixAnimation {
public:
FluidColorMatrix(LEDHAL2D* _matrix, char* _refName, long _updateTime,
FluidColorType _type, FluidColorResolution _resolution) : MatrixAnimation(_matrix,
_refName, _updateTime), type(_type), resolution(_resolution), colorShifter(0) {}
virtual ~FluidColorMatrix() { delete[] colors; }
void initialize();
void execute();
private:
uint16_t
colorShifter;
CRGB*
colors;
uint8_t
numColors;
FluidColorType
type;
FluidColorResolution
resolution;
};
#endif

89
include/GIFMatrix.h Normal file
View File

@ -0,0 +1,89 @@
#ifndef GIFMATRIX_H
#define GIFMATRIX_H
#include "SD.h"
#include "MatrixAnimation.h"
class GIFMatrix : public MatrixAnimation {
public:
GIFMatrix(LEDHAL2D* _matrix, char* _refName, long _updateTime, File* _dataFile) :
MatrixAnimation(_matrix, _refName, _updateTime), dataFile(_dataFile) {
STANDARDHEADER[0] = 0x47;
STANDARDHEADER[1] = 0x49;
STANDARDHEADER[2] = 0x46;
STANDARDHEADER[3] = 0x38;
STANDARDHEADER[4] = 0x39;
STANDARDHEADER[5] = 0x61;
if(!headerOK()) {
// I can't throw exceptions, need to do something here...
}
decodeLogicalDescriptor();
preImageDataBytes = 6 + 7 + (globalColorTableExists ? globalColorTableSize * 3 : 0);
lastCode = _dataFile->read();
}
void initialize() {
// Reinitialization needs to be tested, this may not work correctly
dataFile->seek(preImageDataBytes);
resetTimer();
}
void execute();
bool headerOK();
void decodeLogicalDescriptor();
void decodeGlobalColorTable();
void decodeGraphicControlExtension();
void decodeApplicationExtension();
void decodeImageDescriptor();
void buildCodeTable();
void drawForArray(CRGB* colorTable, uint16_t* indexes, uint16_t startingXPosition, uint16_t imageWidth);
uint16_t readWord();
private:
File*
dataFile;
uint16_t
preImageDataBytes,
currentXPosition,
currentYPosition,
gifCanvasWidth,
gitCanvasHeight,
currentImageLeft,
currentImageTop,
currentImageWidth,
currentImageHeight,
currentCCCode,
currentEOICode;
uint16_t**
currentCodeTable;
long
delayTime;
uint8_t
lastCode,
originalColorResolution,
globalColorTableSize,
globalColorTableBackgroundColorIndex,
disposalMethodValue,
userInputFlag,
transparentColorFlag,
transparentColorIndex,
localColorTableSize,
currentMinimumCodeSize;
bool
globalColorTableExists,
globalColorTableSorted,
localColorTableExists,
interlaceFlag,
localColorTableSorted;
CRGB*
globalColorTable,
localColorTable;
byte
STANDARDHEADER[6];
};
#endif

312
include/GULLS_GFX.h Normal file
View File

@ -0,0 +1,312 @@
#ifndef _GULLS_GFX_H
#define _GULLS_GFX_H
#if ARDUINO >= 100
#include "Arduino.h"
#include "Print.h"
#else
#include "WProgram.h"
#endif
#include "gfxfont.h"
#include "FastLED.h"
#include <Adafruit_I2CDevice.h>
#include <Adafruit_SPIDevice.h>
/// A generic graphics superclass that can handle all sorts of drawing. At a
/// minimum you can subclass and provide drawPixel(). At a maximum you can do a
/// ton of overriding to optimize. Used for any/all Adafruit displays!
class GULLS_GFX : public Print {
public:
GULLS_GFX(int16_t w, int16_t h); // Constructor
/**********************************************************************/
/*!
@brief Draw to the screen/framebuffer/etc.
Must be overridden in subclass.
@param x X coordinate in pixels
@param y Y coordinate in pixels
@param color 16-bit pixel color.
*/
/**********************************************************************/
virtual void drawPixel(int16_t x, int16_t y, CRGB color) = 0;
// TRANSACTION API / CORE DRAW API
// These MAY be overridden by the subclass to provide device-specific
// optimized code. Otherwise 'generic' versions are used.
virtual void startWrite(void);
virtual void writePixel(int16_t x, int16_t y, CRGB color);
virtual void writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h,
CRGB color);
virtual void writeFastVLine(int16_t x, int16_t y, int16_t h, CRGB color);
virtual void writeFastHLine(int16_t x, int16_t y, int16_t w, CRGB color);
virtual void writeLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
CRGB color);
virtual void endWrite(void);
// CONTROL API
// These MAY be overridden by the subclass to provide device-specific
// optimized code. Otherwise 'generic' versions are used.
virtual void setRotation(uint8_t r);
virtual void invertDisplay(bool i);
// BASIC DRAW API
// These MAY be overridden by the subclass to provide device-specific
// optimized code. Otherwise 'generic' versions are used.
// It's good to implement those, even if using transaction API
virtual void drawFastVLine(int16_t x, int16_t y, int16_t h, CRGB color);
virtual void drawFastHLine(int16_t x, int16_t y, int16_t w, CRGB color);
virtual void fillRect(int16_t x, int16_t y, int16_t w, int16_t h,
CRGB color);
virtual void fillScreen(CRGB color);
// Optional and probably not necessary to change
virtual void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
CRGB color);
virtual void drawRect(int16_t x, int16_t y, int16_t w, int16_t h,
CRGB color);
// These exist only with GULLS_GFX (no subclass overrides)
void drawCircle(int16_t x0, int16_t y0, int16_t r, CRGB color);
void drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername,
CRGB color);
void fillCircle(int16_t x0, int16_t y0, int16_t r, CRGB color);
void fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername,
int16_t delta, CRGB color);
void drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2,
int16_t y2, CRGB color);
void fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2,
int16_t y2, CRGB color);
void drawRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h,
int16_t radius, CRGB color);
void fillRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h,
int16_t radius, CRGB color);
void drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w,
int16_t h, CRGB color);
void drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w,
int16_t h, CRGB color, CRGB bg);
void drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h,
CRGB color);
void drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h,
CRGB color, CRGB bg);
void drawXBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w,
int16_t h, CRGB color);
void drawGrayscaleBitmap(int16_t x, int16_t y, const uint8_t bitmap[],
int16_t w, int16_t h);
void drawGrayscaleBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w,
int16_t h);
void drawGrayscaleBitmap(int16_t x, int16_t y, const uint8_t bitmap[],
const uint8_t mask[], int16_t w, int16_t h);
void drawGrayscaleBitmap(int16_t x, int16_t y, uint8_t *bitmap, uint8_t *mask,
int16_t w, int16_t h);
void drawRGBBitmap(int16_t x, int16_t y, const CRGB bitmap[], int16_t w,
int16_t h);
void drawRGBBitmap(int16_t x, int16_t y, CRGB *bitmap, int16_t w,
int16_t h);
void drawRGBBitmap(int16_t x, int16_t y, const CRGB bitmap[],
const uint8_t mask[], int16_t w, int16_t h);
void drawRGBBitmap(int16_t x, int16_t y, CRGB *bitmap, uint8_t *mask,
int16_t w, int16_t h);
void drawChar(int16_t x, int16_t y, unsigned char c, CRGB color,
CRGB bg, uint8_t size);
void drawChar(int16_t x, int16_t y, unsigned char c, CRGB color,
CRGB bg, uint8_t size_x, uint8_t size_y);
void getTextBounds(const char *string, int16_t x, int16_t y, int16_t *x1,
int16_t *y1, uint16_t *w, uint16_t *h);
void getTextBounds(const __FlashStringHelper *s, int16_t x, int16_t y,
int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h);
void getTextBounds(const String &str, int16_t x, int16_t y, int16_t *x1,
int16_t *y1, uint16_t *w, uint16_t *h);
void setTextSize(uint8_t s);
void setTextSize(uint8_t sx, uint8_t sy);
void setFont(const GFXfont *f = NULL);
/**********************************************************************/
/*!
@brief Set text cursor location
@param x X coordinate in pixels
@param y Y coordinate in pixels
*/
/**********************************************************************/
void setCursor(int16_t x, int16_t y) {
cursor_x = x;
cursor_y = y;
}
/**********************************************************************/
/*!
@brief Set text font color with transparant background
@param c 16-bit 5-6-5 Color to draw text with
@note For 'transparent' background, background and foreground
are set to same color rather than using a separate flag.
*/
/**********************************************************************/
void setTextColor(CRGB c) { textcolor = textbgcolor = c; }
/**********************************************************************/
/*!
@brief Set text font color with custom background color
@param c 16-bit 5-6-5 Color to draw text with
@param bg 16-bit 5-6-5 Color to draw background/fill with
*/
/**********************************************************************/
void setTextColor(CRGB c, CRGB bg) {
textcolor = c;
textbgcolor = bg;
}
/**********************************************************************/
/*!
@brief Set whether text that is too long for the screen width should
automatically wrap around to the next line (else clip right).
@param w true for wrapping, false for clipping
*/
/**********************************************************************/
void setTextWrap(bool w) { wrap = w; }
/**********************************************************************/
/*!
@brief Enable (or disable) Code Page 437-compatible charset.
There was an error in glcdfont.c for the longest time -- one
character (#176, the 'light shade' block) was missing -- this
threw off the index of every character that followed it.
But a TON of code has been written with the erroneous
character indices. By default, the library uses the original
'wrong' behavior and old sketches will still work. Pass
'true' to this function to use correct CP437 character values
in your code.
@param x true = enable (new behavior), false = disable (old behavior)
*/
/**********************************************************************/
void cp437(bool x = true) { _cp437 = x; }
using Print::write;
#if ARDUINO >= 100
virtual size_t write(uint8_t);
#else
virtual void write(uint8_t);
#endif
/************************************************************************/
/*!
@brief Get width of the display, accounting for current rotation
@returns Width in pixels
*/
/************************************************************************/
int16_t width(void) const { return _width; };
/************************************************************************/
/*!
@brief Get height of the display, accounting for current rotation
@returns Height in pixels
*/
/************************************************************************/
int16_t height(void) const { return _height; }
/************************************************************************/
/*!
@brief Get rotation setting for display
@returns 0 thru 3 corresponding to 4 cardinal rotations
*/
/************************************************************************/
uint8_t getRotation(void) const { return rotation; }
// get current cursor position (get rotation safe maximum values,
// using: width() for x, height() for y)
/************************************************************************/
/*!
@brief Get text cursor X location
@returns X coordinate in pixels
*/
/************************************************************************/
int16_t getCursorX(void) const { return cursor_x; }
/************************************************************************/
/*!
@brief Get text cursor Y location
@returns Y coordinate in pixels
*/
/************************************************************************/
int16_t getCursorY(void) const { return cursor_y; };
protected:
void charBounds(unsigned char c, int16_t *x, int16_t *y, int16_t *minx,
int16_t *miny, int16_t *maxx, int16_t *maxy);
int16_t WIDTH; ///< This is the 'raw' display width - never changes
int16_t HEIGHT; ///< This is the 'raw' display height - never changes
int16_t _width; ///< Display width as modified by current rotation
int16_t _height; ///< Display height as modified by current rotation
int16_t cursor_x; ///< x location to start print()ing text
int16_t cursor_y; ///< y location to start print()ing text
CRGB textcolor; ///< 16-bit background color for print()
CRGB textbgcolor; ///< 16-bit text color for print()
uint8_t textsize_x; ///< Desired magnification in X-axis of text to print()
uint8_t textsize_y; ///< Desired magnification in Y-axis of text to print()
uint8_t rotation; ///< Display rotation (0 thru 3)
bool wrap; ///< If set, 'wrap' text at right edge of display
bool _cp437; ///< If set, use correct CP437 charset (default is off)
GFXfont *gfxFont; ///< Pointer to special font
};
/// A simple drawn button UI element
class GULLS_GFX_Button {
public:
GULLS_GFX_Button(void);
// "Classic" initButton() uses center & size
void initButton(GULLS_GFX *gfx, int16_t x, int16_t y, uint16_t w,
uint16_t h, CRGB outline, CRGB fill,
CRGB textcolor, char *label, uint8_t textsize);
void initButton(GULLS_GFX *gfx, int16_t x, int16_t y, uint16_t w,
uint16_t h, CRGB outline, CRGB fill,
CRGB textcolor, char *label, uint8_t textsize_x,
uint8_t textsize_y);
// New/alt initButton() uses upper-left corner & size
void initButtonUL(GULLS_GFX *gfx, int16_t x1, int16_t y1, uint16_t w,
uint16_t h, CRGB outline, CRGB fill,
CRGB textcolor, char *label, uint8_t textsize);
void initButtonUL(GULLS_GFX *gfx, int16_t x1, int16_t y1, uint16_t w,
uint16_t h, CRGB outline, CRGB fill,
CRGB textcolor, char *label, uint8_t textsize_x,
uint8_t textsize_y);
void drawButton(bool inverted = false);
bool contains(int16_t x, int16_t y);
/**********************************************************************/
/*!
@brief Sets button state, should be done by some touch function
@param p True for pressed, false for not.
*/
/**********************************************************************/
void press(bool p) {
laststate = currstate;
currstate = p;
}
bool justPressed();
bool justReleased();
/**********************************************************************/
/*!
@brief Query whether the button is currently pressed
@returns True if pressed
*/
/**********************************************************************/
bool isPressed(void) { return currstate; };
private:
GULLS_GFX *_gfx;
int16_t _x1, _y1; // Coordinates of top-left corner
uint16_t _w, _h;
uint8_t _textsize_x;
uint8_t _textsize_y;
CRGB _outlinecolor, _fillcolor, _textcolor;
char _label[10];
bool currstate, laststate;
};
#endif // _GULLS_GFX_H

50
include/LEDHAL.h Normal file
View File

@ -0,0 +1,50 @@
#ifndef LEDHAL_H
#define LEDHAL_H
#include "FastLED.h"
class LEDHAL {
public:
LEDHAL(char* _ledName, bool _isPhysical) :
ledName(_ledName), isPhysical(_isPhysical), showRequested(false) {}
virtual ~LEDHAL() { delete ledName; }
virtual char* getLEDName() { return ledName; }
virtual uint16_t getNumLEDs() = 0;
virtual bool getIsPhysical() { return isPhysical; }
virtual CRGB getColor(int16_t pixel) = 0;
virtual void setColor(int16_t pixel, CRGB color) = 0;
virtual void requestShow() { showRequested = true; }
//TODO UnifiedColor should have constants
virtual void clearLEDs() {
for(uint16_t i = 0; i < getNumLEDs(); i++) {
setColor(i, CRGB(0, 0, 0));
}
};
void show() {
if(showRequested) {
updateLEDs();
showRequested = false;
}
}
protected:
virtual void updateLEDs() {};
private:
char*
ledName;
bool
isPhysical,
showRequested;
};
#endif

42
include/LEDHAL2D.h Normal file
View File

@ -0,0 +1,42 @@
#ifndef LEDHAL2D_H
#define LEDHAL2D_H
#include "LEDHAL.h"
#include "GULLS_GFX.h"
class LEDHAL2D : public LEDHAL, public GULLS_GFX {
public:
LEDHAL2D(int16_t width, int16_t height, char* ledName, bool isPhysical) :
LEDHAL(ledName, isPhysical), GULLS_GFX(width, height), _width(width), _height(height) {}
virtual uint16_t getNumLEDs() = 0;
virtual CRGB getColor(int16_t pixel) = 0;
virtual void drawPixel(int16_t x, int16_t y, CRGB color) = 0;
virtual CRGB getColor(int16_t x, int16_t y) = 0;
virtual int16_t getWidth() {
return _width;
}
virtual int16_t getHeight() {
return _height;
}
virtual void clearLEDs() {
CRGB noColor(0, 0, 0);
for(int16_t x = 0; x < getWidth(); x++) {
for(int16_t y = 0; y < getHeight(); y++) {
drawPixel(x, y, noColor);
}
}
}
private:
int16_t
_width,
_height; //TODO Really need to be getting these values from GFX
};
#endif

71
include/LogicalMatrix.h Normal file
View File

@ -0,0 +1,71 @@
#ifndef LOGICALMATRIX_H
#define LOGICALMATRIX_H
#include "LEDHAL2D.h"
#include "FastLED.h"
class LogicalMatrix : public LEDHAL2D {
public:
LogicalMatrix(char* _ledName, LEDHAL2D* _parent, int16_t _startX, int16_t _startY,
int16_t _stopX, int16_t _stopY) : LEDHAL2D(_stopX - _startX, _stopY - _startY,
_ledName, false), startX(_startX), stopX(_stopX), startY(_startY), stopY(_stopY),
parent(_parent) {}
virtual ~LogicalMatrix() {}
void drawPixel(int16_t x, int16_t y, CRGB color) {
parent->drawPixel(startX + x, startY + y, color);
}
void setColor(int16_t pixel, CRGB color) {
//This is a computationally expensive cheap trick that I'm not
//entirely convinced is necessary, it is essentially the reverse
//of pixelPos = getHeight() * y + x
//Integer division by getHeight returns y from the above
//Modulous (remainder) by getHeight returns x from the above
int16_t intDiv = pixel / getHeight(); //yPos
int16_t intMod = pixel % getHeight(); //xPos
parent->setColor((startX + intMod) * (startY + intDiv), color);
}
CRGB getColor(int16_t pixel) {
//This is a computationally expensive cheap trick that I'm not
//entirely convinced is necessary, it is essentially the reverse
//of pixelPos = getHeight() * y + x
//Integer division by getHeight returns y from the above
//Modulous (remainder) by getHeight returns x from the above
int16_t intDiv = pixel / getHeight(); //yPos
int16_t intMod = pixel % getHeight(); //xPos
return parent->getColor((startX + intMod) * (startY + intDiv));
}
CRGB getColor(int16_t x, int16_t y) {
return parent->getColor(startX + x, startY + y);
}
uint16_t getNumLEDs() {
return getWidth() * getHeight();
}
void requestShow() {
parent->requestShow();
}
protected:
void updateLEDs() {
//This does nothing, because show should never be called on
//a logical strip
}
private:
LEDHAL2D*
parent;
int16_t
startX,
stopX,
startY,
stopY;
};
#endif

42
include/LogicalStrip.h Normal file
View File

@ -0,0 +1,42 @@
#ifndef LOGICALSTRIP_H
#define LOGICALSTRIP_H
#include "LEDHAL.h"
#include "FastLED.h"
class LogicalStrip : public LEDHAL {
public:
LogicalStrip(char* _ledName, LEDHAL* _parent, int16_t _startPixel,
uint16_t _stopPixel) : LEDHAL(_ledName, false), parent(_parent),
startPixel(_startPixel), stopPixel(_stopPixel) {}
virtual ~LogicalStrip() {}
uint16_t getNumLEDs() { return stopPixel - startPixel; }
CRGB getColor(int16_t pixel) {
return parent->getColor(startPixel + pixel);
}
void setColor(uint16_t pixel, CRGB color) {
parent->setColor(startPixel + pixel, color);
}
void requestShow() {
parent->requestShow();
}
protected:
void updateLEDs() {
//This does nothing, because show should never be called on
//a logical strip
}
private:
LEDHAL*
parent;
int16_t
startPixel,
stopPixel;
};
#endif

19
include/MatrixAnimation.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef MATRIXANIMATION_H
#define MATRIXANIMATION_H
#include "AnimationBase.h"
#include "LEDHAL2D.h"
class MatrixAnimation : public AnimationBase {
public:
MatrixAnimation(LEDHAL2D* _matrix, char* _refName, long _updateTime) :
AnimationBase(_refName, _updateTime), matrix(_matrix) {}
virtual ~MatrixAnimation() {}
LEDHAL2D* getMatrix() { return matrix; }
protected:
LEDHAL2D*
matrix;
};
#endif

53
include/PlasmaMatrix.h Normal file
View File

@ -0,0 +1,53 @@
#ifndef PLASMAMATRIX_H
#define PLASMAMATRIX_H
#include "MatrixAnimation.h"
#include "LEDHAL2D.h"
class PlasmaMatrix : public MatrixAnimation {
public:
PlasmaMatrix(LEDHAL2D* _matrix, char* _refName, long _updateTime) :
MatrixAnimation(_matrix, _refName, _updateTime), paletteShift(0), palette(new CRGB[256]) {
plasma = new uint8_t*[matrix->getWidth()];
for(uint16_t i = 0; i < matrix->getWidth(); i++) {
plasma[i] = new uint8_t[matrix->getHeight()];
}
for(uint16_t x = 0; x < matrix->getWidth(); x++) {
for(uint16_t y = 0; y < matrix->getHeight(); y++) {
plasma[x][y] = (uint8_t) ((128.0 + (128 * sinf(x / 8.0)) + 128 + (128.0 * sinf(y / 8.0))) / 2);
}
}
for(uint16_t i = 0; i < 256; i++) {
palette[i] = CRGB(CHSV(i, 255, 255));
}
}
virtual ~PlasmaMatrix() {
delete[] palette;
for(uint16_t i = 0; i < matrix->getWidth(); i++) {
delete[] plasma[i];
}
delete[] plasma;
}
void initialize() {
paletteShift = 0;
}
void execute();
private:
uint16_t
paletteShift;
CRGB*
palette;
uint8_t**
plasma;
};
#endif

39
include/README Normal file
View File

@ -0,0 +1,39 @@
This directory is intended for project header files.
A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.
```src/main.c
#include "header.h"
int main (void)
{
...
}
```
Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.
In C, the usual convention is to give header files names that end with `.h'.
It is most portable to use only letters, digits, dashes, and underscores in
header file names, and at most one dot.
Read more about using header files in official GCC documentation:
* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html

36
include/RicochetHelper.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef RICOCHETHELPER_H
#define RICOCHETHELPER_H
#include "Arduino.h"
#include "FastLED.h"
class RicochetHelper {
public:
RicochetHelper() {}
RicochetHelper(int16_t _startPosX, int16_t _startPosY, int16_t _width, int16_t _height,
CRGB _color) : currentX(_startPosX), currentY(_startPosY), width(_width),
height(_height), xDir(random(0, 101) > 51 ? -1 : 1), yDir(random(0, 100) > 51 ? -1 : 1) {}
int16_t getCurrentXPos() { return currentX; }
int16_t getCurrentYPos() { return currentY; }
CRGB getCurrentColor() { return color; }
void setCurrentColor(uint16_t _color) { color = _color; }
void updatePositions();
private:
int16_t
currentX,
currentY,
width,
height;
int8_t
xDir,
yDir;
CRGB
color;
};
#endif

32
include/RicochetMatrix.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef RICOCHETMATRIX_H
#define RICOCHETMATRIX_H
#include "MatrixAnimation.h"
#include "RicochetHelper.h"
class RicochetMatrix : public MatrixAnimation {
public:
RicochetMatrix(LEDHAL2D* _matrix, char* _refName, long _updateTime, uint16_t _numBalls,
CRGB* _colors, uint8_t _numColors) : MatrixAnimation(_matrix, _refName, _updateTime),
numBalls(_numBalls), colors(new CRGB[_numColors]), numColors(_numColors),
balls(new RicochetHelper*[_numBalls]) {
for(uint8_t i = 0; i < _numColors; i++) {
colors[i] = _colors[i];
}
}
virtual ~RicochetMatrix() { delete[] colors; delete[] balls; };
void initialize();
void execute();
private:
uint16_t
numBalls;
CRGB*
colors;
uint8_t
numColors;
RicochetHelper**
balls;
};
#endif

View File

@ -0,0 +1,46 @@
#ifndef SMARTMATRIXPHYSICALMATRIX_H
#define SMARTMATRIXPHYSICALMATRIX_H
#include "SmartMatrix.h"
#include "LEDHAL2D.h"
class SmartMatrixPhysicalMatrix : public LEDHAL2D {
public:
SmartMatrixPhysicalMatrix(SMLayerBackground<rgb24, 0>* _layer, char* ledName, int16_t width, int16_t height):
LEDHAL2D(width, height, ledName, true), layer(_layer) {}
virtual ~SmartMatrixPhysicalMatrix() {}
void drawPixel(int16_t x, int16_t y, CRGB color) {
layer->drawPixel(x, y, color);
}
void setColor(int16_t pixel, CRGB color) {
layer->drawPixel(pixel % getHeight(), (int)(pixel / getHeight()), color);
}
CRGB getColor(int16_t x, int16_t y) {
rgb24 value = layer->readPixel(x, y);
return CRGB(value.red, value.green, value.blue);
}
CRGB getColor(int16_t pixel) {
rgb24 value = layer->readPixel(pixel % getHeight(), (int)(pixel / getHeight()));
return CRGB(value.red, value.green, value.blue);
}
uint16_t getNumLEDs() {
return getWidth() * getHeight();
}
protected:
void updateLEDs() {
layer->swapBuffers();
}
private:
SMLayerBackground<rgb24, 0>* layer;
};
#endif

19
include/StripAnimation.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef STRIPANIMATION_H
#define STRIPANIMATION_H
#include "AnimationBase.h"
#include "LEDHAL.h"
class StripAnimation : public AnimationBase {
public:
StripAnimation(LEDHAL* _strip, char* _refName, long _updateTime) :
AnimationBase(_refName, _updateTime), strip(_strip) {}
virtual ~StripAnimation() {}
LEDHAL* getStrip() { return strip; }
protected:
LEDHAL*
strip;
};
#endif

46
lib/README Normal file
View File

@ -0,0 +1,46 @@
This directory is intended for project specific (private) libraries.
PlatformIO will compile them to static libraries and link into executable file.
The source code of each library should be placed in an own separate directory
("lib/your_library_name/[here are source files]").
For example, see a structure of the following two libraries `Foo` and `Bar`:
|--lib
| |
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
| |
| |--Foo
| | |- Foo.c
| | |- Foo.h
| |
| |- README --> THIS FILE
|
|- platformio.ini
|--src
|- main.c
and a contents of `src/main.c`:
```
#include <Foo.h>
#include <Bar.h>
int main (void)
{
...
}
```
PlatformIO Library Dependency Finder will find automatically dependent
libraries scanning project source files.
More information about PlatformIO Library Dependency Finder
- https://docs.platformio.org/page/librarymanager/ldf.html

24
platformio.ini Normal file
View File

@ -0,0 +1,24 @@
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[platformio]
default_envs = teensy36
[common]
[env:teensy36]
platform = teensy
framework = arduino
board = teensy36
lib_deps =
fastled/FastLED@^3.7.0
pixelmatix/SmartMatrix@^4.0.3
pfeerick/elapsedMillis@^1.0.6
adafruit/Adafruit GFX Library@^1.11.9

18
src/AlternateMatrix.cpp Normal file
View File

@ -0,0 +1,18 @@
#include "AlternateMatrix.h"
void AlternateMatrix::execute() {
if(type == AlternateType::HORIZONTAL_ALTERNATE) {
for(int16_t i = 0; i < matrix->getHeight(); i++) {
matrix->drawFastHLine(0, i, matrix->getWidth(),
colors[(i + alternateInt) % numColors]);
}
} else if(type == AlternateType::VERTICAL_ALTERNATE) {
for(int16_t i = 0; i < matrix->getWidth(); i++) {
matrix->drawFastVLine(i, 0, matrix->getHeight(),
colors[(i + alternateInt) % numColors]);
}
}
alternateInt++;
matrix->requestShow();
}

10
src/AlternateStrip.cpp Normal file
View File

@ -0,0 +1,10 @@
#include "AlternateStrip.h"
void AlternateStrip::execute() {
for(int16_t i = 0; i < strip->getNumLEDs(); i++) {
strip->setColor(i, colors[(i + alternateInt) % numColors]);
}
alternateInt++;
strip->requestShow();
}

23
src/CollisionMatrix.cpp Normal file
View File

@ -0,0 +1,23 @@
#include "CollisionMatrix.h"
void CollisionMatrix::execute() {
if(collisionInt == 0) {
matrix->clearLEDs();
}
if(type == CollisionType::HORIZONTAL_COLLISION) {
matrix->drawFastHLine(0, collisionInt, matrix->getWidth(), color1);
matrix->drawFastHLine(0, matrix->getHeight() - collisionInt - 1, matrix->getWidth(), color2);
} else if(type == CollisionType::VERTICAL_COLLISION) {
matrix->drawFastVLine(collisionInt, 0, matrix->getHeight(), color1);
matrix->drawFastVLine(matrix->getWidth() - 1 - collisionInt, 0, matrix->getHeight(), color2);
}
collisionInt++;
if(collisionInt >= (type == CollisionType::HORIZONTAL_COLLISION ? matrix->getHeight() : matrix->getWidth())) {
collisionInt = 0;
}
matrix->requestShow();
}

18
src/CollisionStrip.cpp Normal file
View File

@ -0,0 +1,18 @@
#include "CollisionStrip.h"
void CollisionStrip::execute() {
if(collisionInt == 0) {
strip->clearLEDs();
}
strip->setColor(collisionInt, color1);
strip->setColor(strip->getNumLEDs() - collisionInt - 1, color2);
collisionInt++;
if(collisionInt >= strip->getNumLEDs()) {
collisionInt = 0;
}
strip->requestShow();
}

View File

@ -0,0 +1,54 @@
#include "ColorRandomizerMatrix.h"
void ColorRandomizerMatrix::execute() {
if(fade && isFading) {
CRGB color;
if(colorRandomizerInt == 0) {
for(uint16_t i = 0; i < type == ColorRandomizerType::HORIZONTAL_COLORRANDOMIZER ? matrix->getHeight() : matrix->getWidth(); i++) {
if(type == ColorRandomizerType::HORIZONTAL_COLORRANDOMIZER) {
color = matrix->getColor(0, i);
} else {
color = matrix->getColor(i, 0);
}
fadingValues[i].red = (ceil((float)color.red/scale));
fadingValues[i].green = (ceil((float)color.green/scale));
fadingValues[i].blue = (ceil((float)color.blue/scale));
}
colorRandomizerInt++;
} else if(colorRandomizerInt > 0 && colorRandomizerInt < scale + 1) {
for(uint16_t i = 0; i < type == ColorRandomizerType::HORIZONTAL_COLORRANDOMIZER ? matrix->getHeight() : matrix->getWidth(); i++) {
if(type == ColorRandomizerType::HORIZONTAL_COLORRANDOMIZER) {
matrix->drawFastHLine(0, i, matrix->getWidth(), matrix->getColor(0, i) - fadingValues[i]);
} else {
matrix->drawFastVLine(i, 0, matrix->getHeight(), matrix->getColor(i, 0) - fadingValues[i]);
}
}
colorRandomizerInt++;
} else {
colorRandomizerInt = 0;
isFading = false;
}
} else {
uint8_t rand;
for(uint16_t i = 0; i < type == ColorRandomizerType::HORIZONTAL_COLORRANDOMIZER ? matrix->getHeight() : matrix->getWidth(); i++) {
rand = random(0, numColors);
if(type == ColorRandomizerType::HORIZONTAL_COLORRANDOMIZER) {
matrix->drawFastHLine(0, i, matrix->getWidth(), colors[rand]);
} else {
matrix->drawFastVLine(i, 0, matrix->getHeight(), colors[rand]);
}
}
if(fade) {
isFading = true;
}
}
matrix->requestShow();
}

View File

@ -0,0 +1,42 @@
#include "ColorRandomizerStrip.h"
void ColorRandomizerStrip::execute() {
if(fade && isFading) {
CRGB color;
if(colorRandomizerInt == 0) {
for(uint16_t i = 0; i < strip->getNumLEDs(); i++) {
color = strip->getColor(i);
fadingValues[i].red = (ceil((float)color.red/scale));
fadingValues[i].green = (ceil((float)color.green/scale));
fadingValues[i].blue = (ceil((float)color.blue/scale));
}
colorRandomizerInt++;
} else if(colorRandomizerInt > 0 && colorRandomizerInt < scale + 1) {
for(uint16_t i = 0; i < strip->getNumLEDs(); i++) {
strip->setColor(i, strip->getColor(i) - fadingValues[i]);
}
colorRandomizerInt++;
} else {
colorRandomizerInt = 0;
isFading = false;
}
} else {
uint8_t rand;
for(uint16_t i = 0; i < strip->getNumLEDs(); i++) {
rand = random(0, numColors);
strip->setColor(i, colors[rand]);
}
if(fade) {
isFading = true;
}
}
strip->requestShow();
}

24
src/CycleLightMatrix.cpp Normal file
View File

@ -0,0 +1,24 @@
#include "CycleLightMatrix.h"
void CycleLightMatrix::execute() {
if(cycleLightInt == 0) {
matrix->clearLEDs();
}
if(type == CycleLightType::HORIZONTAL_CYCLELIGHT) {
matrix->drawFastHLine(0, cycleLightInt, matrix->getWidth(),
colors[cycleLightColor % numColors]);
} else if(type == CycleLightType::VERTICAL_CYCLELIGHT) {
matrix->drawFastVLine(cycleLightInt, 0, matrix->getHeight(),
colors[cycleLightColor % numColors]);
}
cycleLightInt++;
if(cycleLightInt >= (type == CycleLightType::HORIZONTAL_CYCLELIGHT ? matrix->getHeight() : matrix->getWidth())) {
cycleLightInt = 0;
cycleLightColor++;
}
matrix->requestShow();
}

18
src/CycleLightStrip.cpp Normal file
View File

@ -0,0 +1,18 @@
#include "CycleLightStrip.h"
void CycleLightStrip::execute() {
if(cycleLightInt == 0) {
strip->clearLEDs();
}
strip->setColor(cycleLightInt, colors[cycleLightColor % numColors]);
cycleLightInt++;
if(cycleLightInt >= strip->getNumLEDs()) {
cycleLightInt = 0;
cycleLightColor++;
}
strip->requestShow();
}

42
src/CycloneHelper.cpp Normal file
View File

@ -0,0 +1,42 @@
#include "CycloneHelper.h"
void CycloneHelper::updateAndRedraw(LEDHAL2D* matrix) {
matrix->drawPixel(nextPoint.getX(), nextPoint.getY(), color);
// This will create an ungodly number of stack allocations and destroys
for(uint8_t i = 0; i < numberOfTails; i++) {
if(!tailPoints[i].isOrigin()) {
matrix->drawPixel(tailPoints[i].getX(), tailPoints[i].getY(), tailColors[numberOfTails - i - 1]);
}
}
Point2D tempPoint = nextPoint;
// This is risky, if the logic is wrong, this is infinite
// Find the next position on the circle that actually is different
do {
currentDrawAngle += spinDirection;
if(currentDrawAngle > 359) {
currentDrawAngle = 0;
} else if(currentDrawAngle < 0) {
currentDrawAngle = 359;
}
tempPoint = Point2D(
originX + (uint16_t) round(radius * cosf(currentDrawAngle)),
originY + (uint16_t) round(radius * sinf(currentDrawAngle))
);
} while(tempPoint == nextPoint);
//Slide all tailpoints back one
for(uint8_t i = numberOfTails - 1; i >= 1; i--) {
tailPoints[i] = tailPoints[i - 1];
}
// Point we just drew becomes the first tail point
tailPoints[0] = nextPoint;
// Point we just discovered becomes the next point to draw
nextPoint = tempPoint;
}

37
src/DecodingBitStream.cpp Normal file
View File

@ -0,0 +1,37 @@
#include "DecodingBitStream.h"
uint16_t DecodingBitStream::getCode()
{
uint16_t returnCode;
verifyEnoughBits();
returnCode = bitBuffer & (int)(pow(2, numberOfBitsInCode) - 1);
bitBuffer >>= numberOfBitsInCode;
bitsAvailable -= numberOfBitsInCode;
return returnCode;
}
void DecodingBitStream::verifyEnoughBits()
{
while(bytesAvailable != 0 && (bitsAvailable <= 8 || bitsAvailable <= numberOfBitsInCode))
{
bitBuffer |= stream->read() << bitsAvailable;
bitsAvailable += 8;
bytesAvailable--;
}
}
uint16_t DecodingBitStream::getNumberOfBitsToRepresentValue(uint16_t value)
{
uint16_t count = 0;
while(value > 0)
{
value >>= 1;
count++;
}
return count;
}

75
src/FireworksMatrix.cpp Normal file
View File

@ -0,0 +1,75 @@
#include "FireworksMatrix.h"
void FireworksMatrix::initialize() {
for(uint8_t i = 0; i < maxFireworks; i++) {
fireworks[i].isActive = false;
}
uint8_t third = maxFireworks / 6;
for(uint8_t i = 0; i < third; i++) {
randomSeed(random(0, 100000000));
fireworks[i].radius = random(1, maxRadius + 1);
fireworks[i].currentRadius = 1;
fireworks[i].xPos = random(fireworks[i].radius, matrix->getWidth() - fireworks[i].radius);
fireworks[i].yPos = matrix->getHeight();
fireworks[i].yMaxHeight = random(fireworks[i].radius, matrix->getHeight() - fireworks[i].radius);
fireworks[i].color = colors[random(0, numColors)];
fireworks[i].isActive = true;
}
resetTimer();
}
void FireworksMatrix::execute() {
matrix->clearLEDs();
uint8_t totalInactive = 0;
for(uint8_t i = 0; i < maxFireworks; i++) {
if(!fireworks[i].isActive) {
totalInactive++;
}
}
for(uint8_t i = 0; i < totalInactive; i++) {
randomSeed(random(0, 100000000));
if(random(0, 1000) > 500) {
for(uint8_t j = 0; j < maxFireworks; j++) {
if(!fireworks[j].isActive) {
fireworks[j].radius = random(1, maxRadius + 1);
fireworks[j].currentRadius = 1;
fireworks[j].xPos = random(fireworks[j].radius, matrix->getWidth() - fireworks[j].radius);
fireworks[j].yPos = matrix->getHeight();
fireworks[j].yMaxHeight = random(fireworks[j].radius, matrix->getHeight() - fireworks[j].radius);
fireworks[j].color = colors[random(0, numColors)];
fireworks[j].isActive = true;
break;
}
}
}
}
for(uint8_t i = 0; i < maxFireworks; i++) {
if(fireworks[i].isActive) {
if(fireworks[i].yMaxHeight == fireworks[i].yPos &&
fireworks[i].currentRadius == fireworks[i].radius) {
fireworks[i].isActive = false;
} else if(fireworks[i].yMaxHeight == fireworks[i].yPos &&
fireworks[i].currentRadius < fireworks[i].radius) {
matrix->drawCircle(fireworks[i].xPos, fireworks[i].yPos, fireworks[i].currentRadius,
fireworks[i].color);
fireworks[i].currentRadius++;
} else if(fireworks[i].yPos > fireworks[i].yMaxHeight) {
matrix->drawPixel(fireworks[i].xPos, fireworks[i].yPos, fireworks[i].color);
fireworks[i].yPos--;
}
}
}
matrix->requestShow();
}

59
src/FluidColorMatrix.cpp Normal file
View File

@ -0,0 +1,59 @@
#include "FluidColorMatrix.h"
void FluidColorMatrix::initialize() {
uint8_t step = 0;
switch(resolution) {
case FluidColorResolution::FULL_FLUIDCOLOR:
numColors = 255;
step = 1;
break;
case FluidColorResolution::HALF_FLUIDCOLOR:
numColors = 128;
step = 2;
break;
case FluidColorResolution::QUATER_FLUIDCOLOR:
numColors = 64;
step = 4;
break;
case FluidColorResolution::EIGHTH_FLUIDCOLOR:
default:
numColors = 32;
step = 8;
break;
}
colors = new CRGB[numColors];
for(uint16_t i = 0; i < numColors; i+=step) {
colors[i/step] = CRGB(CHSV(i, 255, 255));
}
}
void FluidColorMatrix::execute() {
switch(type) {
case FluidColorType::PIXEL_BY_PIXEL_FLUIDCOLOR:
for(int16_t x = 0; x < matrix->getWidth(); x++) {
for(int16_t y = 0; y < matrix->getHeight(); y++) {
matrix->drawPixel(x, y,
colors[((matrix->getWidth() * y + x) + colorShifter) % numColors]);
}
}
break;
case FluidColorType::HORIZONTAL_FLUIDCOLOR:
for(int16_t y = 0; y < matrix->getHeight(); y++) {
matrix->drawFastHLine(0, y, matrix->getWidth(),
colors[(y + colorShifter) % numColors]);
}
break;
case FluidColorType::VERTICAL_FLUIDCOLOR:
default:
for(int16_t x = 0; x < matrix->getWidth(); x++) {
matrix->drawFastVLine(x, 0, matrix->getHeight(),
colors[(x + colorShifter) % numColors]);
}
break;
}
colorShifter++;
matrix->requestShow();
}

36
src/GIFMatrix.cpp Normal file
View File

@ -0,0 +1,36 @@
#include "GIFMatrix.h"
void GIFMatrix::buildCodeTable() {
// I am not confident this is going to work, it's a lot of memory cleanup,
// memory that is dynamic, and I'm afraid it's going to cause destructive memory
// corruption
if(currentCodeTable != nullptr) {
for(uint16_t i = 0; i < sizeof(currentCodeTable)/sizeof(uint16_t*); i++) {
delete currentCodeTable[i];
}
delete currentCodeTable;
}
}
void GIFMatrix::drawForArray(CRGB* colorTable, uint16_t* indexes, uint16_t startingXPosition, uint16_t imageWidth) {
for(uint16_t i = 0; i < sizeof(indexes)/sizeof(uint16_t); i++) {
matrix->drawPixel(currentXPosition, currentYPosition, colorTable[indexes[i]]);
currentXPosition++;
if(currentXPosition >= (imageWidth + startingXPosition)) {
currentXPosition = startingXPosition;
currentYPosition++;
}
}
}
uint16_t GIFMatrix::readWord() {
uint16_t lsb = dataFile->read();
uint16_t msb = dataFile->read();
return (msb << 8) | lsb;
}

1730
src/GULLS_GFX.cpp Normal file

File diff suppressed because it is too large Load Diff

13
src/PlasmaMatrix.cpp Normal file
View File

@ -0,0 +1,13 @@
#include "PlasmaMatrix.h"
void PlasmaMatrix::execute() {
for(uint16_t x = 0; x < matrix->getWidth(); x++) {
for(uint16_t y = 0; y < matrix->getHeight(); y++) {
uint8_t color = (plasma[x][y] + paletteShift) % 256;
matrix->drawPixel(x, y, palette[color]);
}
}
matrix->requestShow();
}

33
src/Point2D.h Normal file
View File

@ -0,0 +1,33 @@
#ifndef POINT2D_H
#define POINT2D_H
#include "Arduino.h"
class Point2D {
public:
Point2D() : x(0), y(0) {}
Point2D(uint16_t _x, uint16_t _y) : x(_x), y(_y) {}
virtual ~Point2D() {}
void setX(uint16_t _x) { x = _x; }
void setY(uint16_t _y) { y = _y; }
uint16_t getX() { return x; }
uint16_t getY() { return y; }
bool isOrigin() { return x == 0 && y == 0; }
bool operator==(const Point2D& other) {
return this->x == other.x && this->y == other.y;
}
bool operator!=(const Point2D other) {
return this->x != other.x || this->y != other.y;
}
private:
uint16_t
x,
y;
};
#endif

14
src/RicochetHelper.cpp Normal file
View File

@ -0,0 +1,14 @@
#include "RicochetHelper.h"
void RicochetHelper::updatePositions() {
currentX += xDir;
currentY += yDir;
if(currentX >= width || currentX < 0) {
xDir *= -1;
}
if(currentY >= height || currentY < 0) {
yDir *= -1;
}
}

26
src/RicochetMatrix.cpp Normal file
View File

@ -0,0 +1,26 @@
#include "RicochetMatrix.h"
void RicochetMatrix::initialize() {
for(uint16_t i = 0; i < numBalls; i++) {
if(balls[i] != NULL) {
delete balls[i];
}
randomSeed(random(0, 10000000));
balls[i] = new RicochetHelper(random(0, matrix->getWidth()), random(0, matrix->getHeight()),
matrix->getWidth(), matrix->getHeight(), colors[random(0, numColors)]);
}
}
void RicochetMatrix::execute() {
matrix->clearLEDs();
for(uint16_t i = 0; i < numBalls; i++) {
balls[i]->updatePositions();
matrix->drawPixel(balls[i]->getCurrentXPos(), balls[i]->getCurrentYPos(),
balls[i]->getCurrentColor());
}
matrix->requestShow();
}

59
src/main.cpp Normal file
View File

@ -0,0 +1,59 @@
#include <Arduino.h>
#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);
CRGB leds[NUMLEDS];
CRGB leds2[NUMLEDS];
CRGB leds3[NUMLEDS];
CRGB someColor(255, 255, 255);
LEDHAL* hal;
LEDHAL2D* hal2D;
LEDHAL2D* smHAL;
rgb24 canRGB24Translate(rgb24 color) {
color.red = 0;
return color;
}
void setup() {
CLEDController* controller = &FastLED.addLeds<NEOPIXEL, 6>(leds, NUMLEDS);
CLEDController* controller2d = &FastLED.addLeds<NEOPIXEL, 7>(leds2, NUMLEDS);
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);
}
void loop() {
// put your main code here, to run repeatedly:
}

11
test/README Normal file
View File

@ -0,0 +1,11 @@
This directory is intended for PlatformIO Test Runner and project tests.
Unit Testing is a software testing method by which individual units of
source code, sets of one or more MCU program modules together with associated
control data, usage procedures, and operating procedures, are tested to
determine whether they are fit for use. Unit testing finds problems early
in the development cycle.
More information about PlatformIO Unit Testing:
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html