#include <MD_MAX72xx.h>
#include <SPI.h>
#include <EEPROM.h>
#define IMMEDIATE_NEW 0
#define USE_POT_CONTROL 1
#define PRINT_CALLBACK 0
#define PRINT(s, v) { Serial.print(F(s)); Serial.print(v); }
#define HARDWARE_TYPE MD_MAX72XX::GENERIC_HW
#define MAX_DEVICES 11
#define CLK_PIN 13
#define DATA_PIN 11
#define CS_PIN 10
MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
#define SPEED_IN A5
#define CHAR_SPACING 1 // Define the spacing between characters
#define BUF_SIZE 75
uint8_t curMessage[BUF_SIZE];
uint8_t newMessage[BUF_SIZE];
bool newMessageAvailable = false;
uint16_t scrollDelay;
void readSerial() {
static uint8_t putIndex = 0;
while (Serial.available()) {
newMessage[putIndex] = (char)Serial.read();
if ((newMessage[putIndex] == '\n') || (putIndex >= BUF_SIZE - 3)) {
newMessage[putIndex++] = ' ';
newMessage[putIndex] = '\0';
EEPROM.put(0, newMessage);
putIndex = 0;
newMessageAvailable = true;
} else if (newMessage[putIndex] != '\r')
putIndex++;
}
}
void readMessageFromEEPROM() {
EEPROM.get(0, curMessage);
}
void scrollDataSink(uint8_t dev, MD_MAX72XX::transformType_t t, uint8_t col) {
#if PRINT_CALLBACK
Serial.print("\n cb ");
Serial.print(dev);
Serial.print(' ');
Serial.print(t);
Serial.print(' ');
Serial.println(col);
#endif
}
uint8_t scrollDataSource(uint8_t dev, MD_MAX72XX::transformType_t t) {
static uint8_t* p = curMessage;
static enum { NEW_MESSAGE, LOAD_CHAR, SHOW_CHAR, BETWEEN_CHAR } state = LOAD_CHAR;
static uint8_t curLen, showLen;
static uint8_t cBuf[15];
uint8_t colData = 0;
#if IMMEDIATE_NEW
if (newMessageAvailable) {
state = NEW_MESSAGE;
mx.clear();
}
#endif
switch (state) {
case NEW_MESSAGE:
memcpy(curMessage, newMessage, BUF_SIZE);
newMessageAvailable = false;
p = curMessage;
state = LOAD_CHAR;
break;
case LOAD_CHAR:
showLen = mx.getChar(*p++, sizeof(cBuf) / sizeof(cBuf[0]), cBuf);
curLen = 0;
state = SHOW_CHAR;
if (*p == '\0') {
p = curMessage;
#if !IMMEDIATE_NEW
if (newMessageAvailable) {
state = NEW_MESSAGE;
break;
}
#endif
}
case SHOW_CHAR:
colData = cBuf[curLen++];
if (curLen == showLen) {
showLen = CHAR_SPACING;
curLen = 0;
state = BETWEEN_CHAR;
}
break;
case BETWEEN_CHAR:
colData = 0;
curLen++;
if (curLen == showLen)
state = LOAD_CHAR;
break;
default:
state = LOAD_CHAR;
}
return(colData);
}
void scrollText() {
static uint32_t prevTime = 0;
if (millis() - prevTime >= scrollDelay) {
mx.transform(MD_MAX72XX::TSL);
prevTime = millis();
}
}
uint16_t getScrollDelay() {
#if USE_POT_CONTROL
uint16_t t;
t = analogRead(SPEED_IN);
t = map(t, 0, 1023, 25, 250);
return(t);
#else
return(SCROLL_DELAY);
#endif
}
void setup() {
mx.begin();
mx.setShiftDataInCallback(scrollDataSource);
mx.setShiftDataOutCallback(scrollDataSink);
#if USE_POT_CONTROL
pinMode(SPEED_IN, INPUT);
#else
scrollDelay = SCROLL_DELAY;
#endif
Serial.begin(57600);
// Read the message from EEPROM
readMessageFromEEPROM();
}
void loop() {
scrollDelay = getScrollDelay();
readSerial();
scrollText();
}