#include <ArduinoJson.h>
#include <SD.h>
#include <SPI.h>
#include <FastLED.h>
#include <StreamUtils.h>
// Params for width and height
const uint8_t kMatrixWidth = 32;
const uint8_t kMatrixHeight = 32;
// Param for different pixel layouts
const bool kMatrixSerpentineLayout = true;
const bool kMatrixVertical = false;
#define MAX_ANIMATION_FRAMES_ACCEPTED 5
#define LED_NUM (kMatrixWidth * kMatrixHeight)
#define RGB_NUM 3
#define DATA_PIN 26
#define BRIGHTNESS 3
#define CHIPSET WS2812B
struct Config {
uint8_t width;
uint8_t height;
uint8_t frames;
uint8_t animation[MAX_ANIMATION_FRAMES_ACCEPTED][LED_NUM][RGB_NUM];
};
char filePath[256] = { 0 };
char fileName[256] = { 0 };
File root,gifFile;
Config config;
CRGB leds_plus_safety_pixel[ LED_NUM + 1];
CRGB* const leds( leds_plus_safety_pixel + 1);
uint16_t XY( uint8_t x, uint8_t y)
{
uint16_t i;
if( kMatrixSerpentineLayout == true) {
if (kMatrixVertical == false) {
if( y & 0x01) {
// Odd rows run backwards
uint8_t reverseX = (kMatrixWidth - 1) - x;
i = (y * kMatrixWidth) + reverseX;
} else {
// Even rows run forwards
i = (y * kMatrixWidth) + x;
}
} else { // vertical positioning
if ( x & 0x01) {
i = kMatrixHeight * (kMatrixWidth - (x+1))+y;
} else {
i = kMatrixHeight * (kMatrixWidth - x) - (y+1);
}
}
}
return i;
}
uint16_t XYsafe( uint8_t x, uint8_t y)
{
if( x >= kMatrixWidth) return -1;
if( y >= kMatrixHeight) return -1;
return XY(x,y);
}
void loadConfiguration(const char *filename, Config &config) {
File file = SD.open(filename);
StaticJsonDocument<262144> doc;
DeserializationError error = deserializeJson(doc, file);
if (error)
Serial.println(F("Failed to read file, using default configuration"));
ReadBufferingStream bufferedFile(file, 64);
deserializeJson(doc, bufferedFile);
config.width = doc["width"];
config.height = doc["height"];
config.frames = doc["frames"];
uint16_t index;
for(uint8_t j = 0; j < config.frames; j++){
JsonArray curr_frame = doc["animation"][j];
for(uint8_t j = 0; j < config.frames; j++){
JsonArray curr_frame = doc["animation"][j];
for(uint16_t x = 0; x < kMatrixWidth; x++){
for(uint16_t y = 0; y < kMatrixHeight; y++){
index = XYsafe(x,y);
JsonArray curr_led = curr_frame[index];
config.animation[j][index][0] = curr_led[0];
config.animation[j][index][1] = curr_led[1];
config.animation[j][index][2] = curr_led[2];
}
}
}
}
file.close();
}
void setup() {
Serial.begin(115200);
while (!Serial) continue;
while (!SD.begin()) {
Serial.println(F("Failed to initialize SD library"));
delay(1000);
}
FastLED.addLeds<CHIPSET,DATA_PIN,GRB>(leds, LED_NUM);
FastLED.setBrightness(BRIGHTNESS);
FastLED.setCorrection(TypicalLEDStrip);
FastLED.clear();
}
void DrawGif()
{
uint16_t index;
for(uint8_t k = 0; k < 8; k++){
for(uint8_t j = 0; j < config.frames; j++){
FastLED.clear();
for(uint16_t x = 0; x < kMatrixWidth; x++){
for(uint16_t y = 0; y < kMatrixHeight; y++){
index = XYsafe(x,y);
leds[index].r = pgm_read_dword(&(config.animation[j][index][0]));
leds[index].g = pgm_read_dword(&(config.animation[j][index][1]));
leds[index].b = pgm_read_dword(&(config.animation[j][index][2]));
}
}
FastLED.show();
delay(300);
}
}
}
void loop() {
while(1){
root = SD.open("/");
if(root){
gifFile = root.openNextFile();
while(gifFile)
{
if (!gifFile.isDirectory()) // play it
{
memset(fileName, 0x0, sizeof(fileName));
strcpy(fileName, gifFile.name());
snprintf(filePath, sizeof(filePath)+1, "/%s", fileName);
loadConfiguration(filePath, config);
DrawGif();
}
gifFile.close();
gifFile = root.openNextFile();
}
root.close();
}
}
delay(1000);
}