#include <SD.h>
#include <Arduino.h>
#define DEBUG_ENABLED
#define MAX_SCENE_LENGTH 512
#define DMX_PACKET_SIZE 512
#define MAX_SCENES 10
#ifdef DEBUG_ENABLED
#define MAX_UNIVERSE 3
#define DEBUG_PRINT(value) Serial.print(value)
#define DEBUG_PRINTLN(value) Serial.println(value)
#else
#define MAX_UNIVERSE 4
#define DEBUG_PRINT(value)
#define DEBUG_PRINTLN(value)
#endif
// DMX Universe ports
#define U1 Serial1
#define U2 Serial2
#define U3 Serial3
#define U4 Serial
#define CS_PIN 53
struct SceneInfo {
String name;
uint16_t startLine;
uint16_t size;
};
class DMX {
public:
uint8_t universeCount = 0;
uint8_t dmxPacket[MAX_UNIVERSE][DMX_PACKET_SIZE];
File config[MAX_UNIVERSE];
int sceneIndex[MAX_UNIVERSE];
// Current Animation Variables
void init()
{
initSD();
initDmxPacket();
//TODO: ADD DEINIT OF VARIABLES
for (int i = 0; i < MAX_UNIVERSE; i++)
{
loadFile(i+1, ("u" + String(i+1) + "_sc.txt").c_str());
universeCount++;
}
}
void initSD()
{
if (!SD.begin(CS_PIN))
{
while (true);
}
DEBUG_PRINTLN("DMX_CTRL: SD CARD INITIALIZED");
}
void switchUniverse(int universe, bool state = true)
{
switch (universe)
{
case 1:
U1.end();
DEBUG_PRINTLN("DMX_CTRL: Stopping UART 1.");
if (state)
{
U1.begin(250000);
DEBUG_PRINTLN("DMX_CTRL: UART 1 initialized to DMX speed.");
}
break;
case 2:
U2.end();
DEBUG_PRINTLN("DMX_CTRL: Stopping UART 2.");
if (state)
{
U2.begin(250000);
DEBUG_PRINTLN("DMX_CTRL: UART 2 initialized to DMX speed.");
}
break;
case 3:
U3.end();
DEBUG_PRINTLN("DMX_CTRL: Stopping UART 3.");
if (state)
{
U3.begin(250000);
DEBUG_PRINTLN("DMX_CTRL: UART 3 initialized to DMX speed.");
}
break;
#ifndef DEBUG_ENABLED
case 4:
U3.end();
if (state)
{
U4.begin(250000);
}
break;
#endif
}
}
void loadFile(int universe, const char* configFile)
{
File file = SD.open(configFile);
if (file)
{
config[universe-1] = file;
switchUniverse(universe);
}
else
{
switchUniverse(universe,false);
}
file.close();
}
void printFile(File file)
{
if (file) {
file.seek(0);
while (file.available()) {
String line = file.readStringUntil('\n');
DEBUG_PRINTLN(line);
}
}
}
void loadConfiguration(int universe, const char* configFile)
{
File file = SD.open(configFile);
if (file)
{
switch (universe)
{
case 1:
U1.begin(250000);
DEBUG_PRINTLN("DMX_CTRL: UART 1 initialized to DMX speed.");
break;
case 2:
U2.begin(250000);
DEBUG_PRINTLN("DMX_CTRL: UART 2 initialized to DMX speed.");
break;
case 3:
U3.begin(250000);
DEBUG_PRINTLN("DMX_CTRL: UART 3 initialized to DMX speed.");
break;
#ifndef DEBUG_ENABLED
case 4:
U4.begin(250000);
break;
#endif
}
DEBUG_PRINTLN("Configuration file opened successfully");
// Variables to store current scene and DMX packet
String currentScene;
String currentPacket;
// Variables to store DMX data
uint8_t* dmxData = nullptr;
int dmxDataSize = 0;
while (file.available()) {
String line = file.readStringUntil('\n');
//DEBUG_PRINTLN("Read line: " + line);
// Check if the line starts with "SCENE:"
if (line.startsWith("SCENE:"))
{
currentScene = line.substring(6);
DEBUG_PRINTLN("Scene: " + currentScene);
// Reset DMX data for the new scene
delete[] dmxData;
dmxData = nullptr;
dmxDataSize = 0;
}
else if (line.startsWith("[") && line.endsWith("]") && line.indexOf(",") )
{
// Parse DMX packet
currentPacket = line.substring(1, line.length() - 1);
//DEBUG_PRINTLN("DMX Packet: " + currentPacket);
// Tokenize the packet and convert to integers
char* value = strtok(const_cast<char*>(currentPacket.c_str()), ",");
int index = 0;
while (value != nullptr && index < 512) {
uint8_t intValue = atoi(value);
DEBUG_PRINT("[CH " + String(index + 1) + "]: " + String(intValue) + " ");
// Resize the DMX data array if necessary
if (index >= dmxDataSize) {
int newSize = dmxDataSize + 10; // Adjust the resizing factor as needed
uint8_t* newDmxData = new uint8_t[newSize];
memcpy(newDmxData, dmxData, dmxDataSize * sizeof(int));
delete[] dmxData;
dmxData = newDmxData;
dmxDataSize = newSize;
}
// Store the value in the array
dmxData[index] = intValue;
value = strtok(nullptr, ",");
index++;
}
DEBUG_PRINTLN();
while (index < 512) {
dmxData[index] = 0;
index++;
}
}
else
{
DEBUG_PRINTLN("Skipping invalid line: " + line);
}
}
file.close();
delete[] dmxData;
}
else {
DEBUG_PRINTLN("Error opening configuration file");
}
}
void printDmxPacket(int universe, int mn = 1, int mx = DMX_PACKET_SIZE)
{
DEBUG_PRINT("DMX UNIVERSE ");
DEBUG_PRINTLN(universe);
for(int j = mn; j <= mx; j++)
{
DEBUG_PRINT(j);
DEBUG_PRINT(":");
DEBUG_PRINTLN(dmxPacket[universe-1][j-1]);
}
}
void initDmxPacket()
{
for (int i = 1; i <= MAX_UNIVERSE; i++)
{
fillDmxPacket(i,0);
}
}
void fillDmxPacket(int universe, int value)
{
for(int i = 0; i < DMX_PACKET_SIZE ;i++)
{
dmxPacket[universe-1][i] = value;
}
}
};
File root;
DMX mainConfig;
void setup() {
#ifdef DEBUG_ENABLED
Serial.begin(115200);
#endif
mainConfig.init();
mainConfig.printFile(mainConfig.config[3-1]);
}
char* readFile(const char *fileName) {
File configFile = SD.open(fileName);
if (configFile)
{
int fileSize = configFile.size();
char *config = (char*)malloc(fileSize + 1); // +1 for the null terminator
if (config == NULL) {
DEBUG_PRINTLN("Memory allocation failed.");
while (1);
}
int bytesRead = configFile.readBytes(config, fileSize);
config[bytesRead] = '\0';
configFile.close();
return config;
}
else
{
DEBUG_PRINTLN("Error opening file. Check if the file exists and is accessible.");
return NULL;
}
}
void loop() {
}