Here are found the blank, you need to check how it works
/*
PROJECT: MySensors / Scrolling Text display
PROGRAMMER: AWI
DATE: september 12, 2015/ last update: september 12, 2015
FILE: AWI_scroll_MAX.ino
LICENSE: Public domain
Hardware: tbd ..Ceech - ATmega328p board w/ NRF24l01
and MySensors 1.5 ()
Special:
Need to use MySensors development edition
SUMMARY:
3 S_xx devices for scrolling text
- Displays a scrolling text from a "V_TEXT" variable
- additional dimmer sensor for controlling display brightness
- 'Alarm' switch. If "On", overrides the text display to display ALARM message
- You can also input messages from the Serial monitor (testing)
Uses excellent MD_MAX72XX library
Remarks:
Fixed node-id
*/
// Enable debug prints to serial monitor
#define MY_DEBUG
// Enable and select radio type attached
#define MY_RADIO_NRF24
//#define MY_RADIO_RFM69
#define DEBUG 0 // Enable or disable (default) debugging output
// Use the MD_MAX72XX library to scroll text on the display with the use of the callback function
// to control what is scrolled on the display text.
// You need to set the used display in the library MD_MAX72XX.h
// User can enter text on the serial monitor and this will display as a
// Speed for the display is controlled by a pot on SPEED_IN analog in.
#include <MD_MAX72xx.h> // multipurpose library for MAX72xx diaplay driver https://parola.codeplex.com/
#include <MySensor.h> // Mysensor network
#include <SPI.h>
#include <Time.h> //http://playground.arduino.cc/Code/Time
#define PRINT_CALLBACK 0
// Macro to simplify serial print
#define PRINT(s, v) { Serial.print(F(s)); Serial.print(v); }
#define PRINTS(x) Serial.print(F(x))
#define PRINTD(x) Serial.println(x, DEC)
// Define the number of devices we have in the chain and the hardware interface
// need to be adapted to your setup
const int MAX_DEVICES = 8 ; // number of 8x8 displays
const int CLK_PIN = 7 ; // SPI like clock
const int DATA_PIN = 8 ; // SPI like data
const int CS_PIN = 6 ; // SPI like select
// Parola is able to use SPI hardware interface, not testted in combination with MySensors
// MD_MAX72XX mx = MD_MAX72XX(CS_PIN, MAX_DEVICES);
// now use Arbitrary pins
MD_MAX72XX mx = MD_MAX72XX(DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES); // instantiate one display chain
const int SCROLL_DELAY = 20 ; // in milliseconds
const int CHAR_SPACING = 1 ; // pixels between characters
int statetus_tame = 1;
char sdate[11];
char stime[9];
// MySensors constants & variables
//const byte nodeId = 51 ; // MySensors fixed node id
const byte messageCHILD = 8 ; // Text from ControllerLCD
const byte brightnessChild = 9 ; // Brightness of display
const byte alarmChild = 10 ; // Display Alarm text (overrides normal text)
boolean timeReceived = false ; // Flag to indicate time received
// Display constants & variables
byte textBrightness = 1 ; // brightness of display (between 0 - MAX_INTENSITY (0xF)
byte textOnOff = true ; // textOnOff = ! shutdown
boolean textAlarm = false ; // Alarm (switch S_BINARY)
// Global message buffers shared by MySensors and Scrolling functions
const int BUF_SIZE = 25 ; // max payload for MySensors(NRF24l01)
char curMessage[BUF_SIZE]; // current displayed message
char newMessage[BUF_SIZE]; // next message to be displayed if available
bool newMessageAvailable = false ; // new message available flag
uint16_t scrollDelay; // in milliseconds
// *** Definition and initialisation
// define the MySensor network (1.5)
// Initialize messages for sensor network
MyMessage textMsg(messageCHILD, V_TEXT); // message for Sending Text to Controller
/* MD_MAX72XX functions: can be found in the documentation for the library,
no need to customtize callback & scroll routines (unless you want to...)
*/
uint8_t scrollDataSource(uint8_t dev, MD_MAX72XX::transformType_t t)
// Callback function for data that is required for scrolling into the display
{
static char *p = curMessage;
static uint8_t state = 0;
static uint8_t curLen, showLen;
static uint8_t cBuf[8];
uint8_t colData;
// finite state machine to control what we do on the callback
switch (state)
{
case 0: // Load the next character from the font table
showLen = mx.getChar(*p++, sizeof(cBuf) / sizeof(cBuf[0]), cBuf);
curLen = 0;
state++;
// if we reached end of message, reset the message pointer
if (*p == '\0')
{
p = curMessage; // reset the pointer to start of message
if (newMessageAvailable) // there is a new message waiting
{
strcpy(curMessage, newMessage); // copy it in
newMessageAvailable = false;
}
}
// !! deliberately fall through to next state to start displaying
case 1: // display the next part of the character
colData = cBuf[curLen++];
if (curLen == showLen) // end of character insert interchar space
{
showLen = CHAR_SPACING;
curLen = 0;
state = 2;
}
break;
case 2: // display inter-character spacing (blank column)
colData = 0;
curLen++;
if (curLen == showLen)
state = 0;
break;
default:
state = 0;
}
return (colData);
}
void printText(uint8_t modStart, uint8_t modEnd, char *pMsg)
// Print the text string to the LED matrix modules specified.
// Message area is padded with blank columns after printing.
{
uint8_t state = 0;
uint8_t curLen;
uint16_t showLen;
uint8_t cBuf[8];
int16_t col = ((modEnd + 1) * COL_SIZE) - 1;
mx.control(modStart, modEnd, MD_MAX72XX::UPDATE, MD_MAX72XX::OFF);
do // finite state machine to print the characters in the space available
{
switch (state)
{
case 0: // Load the next character from the font table
// if we reached end of message, reset the message pointer
if (*pMsg == '\0')
{
showLen = col - (modEnd * COL_SIZE); // padding characters
state = 2;
break;
}
// retrieve the next character form the font file
showLen = mx.getChar(*pMsg++, sizeof(cBuf) / sizeof(cBuf[0]), cBuf);
curLen = 0;
state++;
// !! deliberately fall through to next state to start displaying
case 1: // display the next part of the character
mx.setColumn(col--, cBuf[curLen++]);
// done with font character, now display the space between chars
if (curLen == showLen)
{
showLen = CHAR_SPACING;
state = 2;
}
break;
case 2: // initialize state for displaying empty columns
curLen = 0;
state++;
// fall through
case 3: // display inter-character spacing or end of message padding (blank columns)
mx.setColumn(col--, 0);
curLen++;
if (curLen == showLen)
state = 0;
break;
default:
col = -1; // this definitely ends the do loop
}
} while (col >= (modStart * COL_SIZE));
mx.control(modStart, modEnd, MD_MAX72XX::UPDATE, MD_MAX72XX::ON);
}
void scrollDataSink(uint8_t dev, MD_MAX72XX::transformType_t t, uint8_t col) {
// Callback function for data that is being scrolled off the display
#if PRINT_CALLBACK
Serial.print("\n cb ");
Serial.print(dev);
Serial.print(' ');
Serial.print(t);
Serial.print(' ');
Serial.println(col);
#endif
}
// non-blocking text display to be used in loop (call frequently)
void scrollText(void) {
static uint32_t prevTime = 0;
if (millis() - prevTime >= scrollDelay) { // Is it time to scroll the text?
mx.transform(MD_MAX72XX::TSL); // scroll along - the callback will load all the data
prevTime = millis(); // starting point for next time
}
}
// sets the scroll delay (read from potentiometer if enabled)
uint16_t getScrollDelay(void) {
return (SCROLL_DELAY);
}
void setup() {
// set up the display first
mx.begin(); // initialize display chain
mx.setShiftDataInCallback(scrollDataSource); // define function to get the scrolldata (returned as int8)
//mx.setShiftDataOutCallback(scrollDataSink); // not used
mx.control(MD_MAX72XX::INTENSITY, 0x01);
scrollDelay = SCROLL_DELAY;
strcpy(curMessage, "I \x03 MySensors "); // first message on display
newMessage[0] = '\0'; // new message initialized to empty
// Setup MySensors
//Serial in Sensor network = 115200
//Send the sensor node sketch version information to the gateway
}
void presentation() {
sendSketchInfo("AWI Scroll MAX 51", "1.1");
present(messageCHILD, S_INFO, "Text line Scroll"); // new S_type 20150905 (not know by domoticz)
present(alarmChild, S_BINARY, "Alarm display"); // to display alarm text
present(brightnessChild, S_DIMMER, "Text brightness"); // new S_type 20150905 (not know by domoticz)
//send(textMsg.set("-")); // initialize the V_TEXT at controller for sensor to none (trick for Domoticz)
request(messageCHILD, V_TEXT, 0); // request value from controller
// Initializations
requestTime(); // get the time from controller (handled by receiveTime)
}
// loop only uses non-blocking functions
void loop() {
static unsigned long lastUpdate ; // Static hold the last update time
static unsigned long lastUpdate2 ; // Static hold the last update time
unsigned long now = millis();
scrollDelay = getScrollDelay(); // update scroll delay from potentiometer
readSerial();
// Check for new conditions & ask for new information from controller every 10 seconds
if (now - lastUpdate > 30000 && statetus_tame == 0) {
statetus_tame = 0;
sprintf(sdate, "%02d-%02d-%d", day(), month(), year());
printText(0, MAX_DEVICES - 1, sdate);
lastUpdate = now;
}
if (textAlarm) { // if alarmstatus: override all text and set max intensity
//strcpy(curMessage, " ALARM ");
mx.control(MD_MAX72XX::INTENSITY, MAX_INTENSITY); // set current brightness
mx.control(MD_MAX72XX::SHUTDOWN, false) ;
} else { // standard (non Alarm actions)
/*
mx.control(MD_MAX72XX::INTENSITY, textBrightness); // set current brightness
mx.control(MD_MAX72XX::SHUTDOWN, textOnOff) ;
request(messageCHILD, V_TEXT, 0); // request new value from controller
*/
}
if (textAlarm) {
scrollText();
} else {
//sprintf(stime, "%02d:%02d:%02d", hour(), minute(), second());
if (statetus_tame == 1) {
sprintf(stime, "%02d:%02d:%02d", hour(), minute(), second());
printText(0, MAX_DEVICES - 3, stime);
mx.setShiftDataOutCallback(scrollDataSink);
}
mx.control(MD_MAX72XX::INTENSITY, textBrightness); // set current brightness
}
if (now - lastUpdate2 > 32000) {
statetus_tame = 1;
mx.clear();
lastUpdate2 = now;
}
if (now - lastUpdate >33000 ){
requestTime();
lastUpdate = now;
}
}
// This is called when a new time value was received
void receiveTime(unsigned long controllerTime) {
Serial.print("Time value received: ");
Serial.println(controllerTime);
setTime(controllerTime); // time from controller
timeReceived = true;
}
// This is called when a message is received
void receive(const MyMessage &message) {
Serial.print("Message: "); Serial.print(message.sensor); Serial.print(", Message: "); Serial.println(message.getString());
if (message.sensor == messageCHILD) {
if (message.type == V_TEXT) { // Text content
strcpy(newMessage, message.getString()); // copy it in
newMessageAvailable = true ;
}
} else if (message.sensor == alarmChild) {
if (message.type == V_STATUS) { // True/ false content
textAlarm = message.getBool() ? true : false ; // set alarmflag
Serial.print("TextAlarm: ");
Serial.println(textAlarm);
}
} else if (message.sensor == brightnessChild) {
if (message.type == V_PERCENTAGE) { // Level 0..100 content
textBrightness = map(message.getInt(), 0, 100, 0, MAX_INTENSITY ) ; // map to brightnesslevel
Serial.print("TextBrightness: ");
Serial.println(textBrightness);
} else if (message.type == V_STATUS) { // Display on/off
textOnOff = message.getBool() ? false : true ; // set shutdown/ !on/off
Serial.print("Text on/off: ");
Serial.println(textOnOff);
}
}
}
// Testing purposes: input routine character buffer. Reads serial characters in buffer newMessage.
// sets flag newMessageAvailable to true if completed
void readSerial(void)
{
static uint8_t putIndex = 0;
while (Serial.available())
{
newMessage[putIndex] = (char)Serial.read();
if ((newMessage[putIndex] == '\n') || (putIndex >= BUF_SIZE - 3)) // end of message character or full buffer
{
// put in a message separator and end the string
newMessage[putIndex++] = ' ';
newMessage[putIndex] = '\0';
// restart the index for next filling spree and flag we have a message waiting
putIndex = 0;
newMessageAvailable = true;
}
else
// Just save the next char in next location
newMessage[putIndex++];
}
}