#include <ArduinoJson.h>
#include <SD.h>
#include <SPI.h>
#include <FastLED.h>
#include <StreamUtils.h>
#include "gifs.h"
#include "images.h"
#define MAX_ANIMATION_FRAMES_ACCEPTED (12)
#define LED_NUM (1024)
#define RGB_NUM (3)
#define LED_DATA_SIZE (3)
#define DATA_PIN (26)
#define matrixWidth (32)
#define matrixHeight (32)
#define flashMemGifs (6)
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];
// load gifs and images from the flash memory
void loadConfigurationFromFlashMem(uint8_t index) {
switch (index) {
case 0:
showJump(leds);
break;
case 1:
showPikachu(leds);
break;
case 2:
showMario(leds);
break;
case 3:
showPokeBall(leds);
break;
case 4:
showFlower(leds);
break;
case 5:
showFish(leds);
break;
}
}
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;
uint8_t index = 0;
FastLED.addLeds<WS2812B,DATA_PIN,GRB>(leds, LED_NUM);
FastLED.setBrightness(50);
FastLED.setCorrection(TypicalLEDStrip);
FastLED.clear();
while (!SD.begin()) {
Serial.println(F("Failed to initialize SD library"));
if(index == 6) index = 0;
loadConfigurationFromFlashMem(index);
index++;
FastLED.clear();
}
index = 0;
if (SD.exists("/")) {
Serial.println("SD card is not empty.");
} else {
Serial.println("SD card is empty.");
while(1){
if(index == 6) index = 0;
loadConfigurationFromFlashMem(index);
index++;
FastLED.clear();
}
}
}
void loop() {
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();
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]));
}
}
delay(5);
FastLED.show();
delay(80);
}
}
}
gifFile.close();
gifFile = root.openNextFile();
}
root.close();
}
}