#include <ArduinoJson.h>
#include <SD.h>
#include <SPI.h>
#include <FastLED.h>
#include <StreamUtils.h>
#include "gifs.h"
#define MAX_ANIMATION_FRAMES_ACCEPTED (10)
#define LED_NUM (1024)
#define RGB_NUM (3)
#define LED_DATA_SIZE (3)
#define DATA_PIN (26)
#define matrixWidth (32)
#define matrixHeight (32)
struct Config {
uint8_t width;
uint8_t height;
uint8_t frames;
uint16_t colors;
uint8_t colors_palette[LED_NUM][RGB_NUM];
uint16_t frame_sizes[MAX_ANIMATION_FRAMES_ACCEPTED];
uint16_t animation[MAX_ANIMATION_FRAMES_ACCEPTED][LED_NUM][LED_DATA_SIZE];
};
char filePath[256] = { 0 };
char fileName[256] = { 0 };
File root,gifFile;
Config config;
CRGB leds[LED_NUM];
void loadConfiguration(const char *filename, Config &config) {
File file = SD.open(filename);
//simpler because we dont need to specify doc size but still not the most stable, but fastest.
JsonDocument doc;
ReadBufferingStream bufferedFile(file, 64);
DeserializationError error = deserializeJson(doc, bufferedFile);
// this is slower but more stable with no flares mostly.
// DynamicJsonDocument doc(262144);
// DeserializationError error = deserializeJson(doc, file);
// DynamicJsonDocument doc(262144);
// ReadBufferingStream bufferedFile(file, 256);
// DeserializationError error = deserializeJson(doc, bufferedFile);
if (error)
Serial.println(F("Failed to read file, using default configuration"));
config.width = doc["width"];
config.height = doc["height"];
config.frames = doc["frames"];
config.colors = doc["colors"];
for(uint16_t j = 0; j < config.colors; j++){
JsonArray curr_color = doc["colors_palette"][j];
config.colors_palette[j][0] = curr_color[0];
config.colors_palette[j][1] = curr_color[1];
config.colors_palette[j][2] = curr_color[2];
}
for(uint8_t j = 0; j < config.frames; j++){
config.frame_sizes[j] = doc["frame_sizes"][j];
JsonArray curr_frame = doc["animation"][j];
for(uint16_t i = 0; i < config.frame_sizes[j]; i++){
JsonArray curr_led = curr_frame[i];
config.animation[j][i][0] = curr_led[0];
config.animation[j][i][1] = curr_led[1];
config.animation[j][i][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<WS2812B,DATA_PIN,GRB>(leds, LED_NUM);
FastLED.setBrightness(100);
FastLED.setCorrection(TypicalLEDStrip);
FastLED.clear();
}
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);
FastLED.clear();
// fill_solid(leds, LED_NUM, CRGB::Black);
for(uint8_t k = 0; k < 8; k++){
for(uint8_t j = 0; j < config.frames; j++){
for(uint16_t i = 0; i < config.frame_sizes[j]; i++) {
uint16_t color = config.animation[j][i][0];
uint16_t index = config.animation[j][i][1];
uint16_t length = config.animation[j][i][2];
for(uint16_t m = index; m < index+length; m++){
leds[m].r = pgm_read_dword(&(config.colors_palette[color][0]));
leds[m].g = pgm_read_dword(&(config.colors_palette[color][1]));
leds[m].b = pgm_read_dword(&(config.colors_palette[color][2]));
}
}
FastLED.show();
delay(100);
}
}
}
gifFile.close();
gifFile = root.openNextFile();
}
root.close();
}
// delay(1000);
}
}