2021-11-19 10:45:07 +00:00
|
|
|
/*
|
2021-11-24 16:24:40 +00:00
|
|
|
xdsp_19_max7219_matrix.ino.ino - Support for MAX7219 based 8x8 dot matrix displays for Tasmota
|
2021-11-19 10:45:07 +00:00
|
|
|
|
|
|
|
Copyright (C) 2021 Michael Beuss
|
|
|
|
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef USE_DISPLAY
|
|
|
|
#ifdef USE_DISPLAY_MAX7219_MATRIX
|
|
|
|
/*********************************************************************************************\
|
2021-11-24 16:24:40 +00:00
|
|
|
This driver enables the display of ascii text on MAX7219 based 8x8 LED dot matrix modules (1088AS).
|
2021-11-19 10:45:07 +00:00
|
|
|
|
2021-11-24 16:24:40 +00:00
|
|
|
Connect the MAX7219 display module's pins to any free GPIOs of the ESP8266 or ESP32 module.
|
|
|
|
VCC should be 5V. Depending on the number of used modules and the brightness, the used current can be more than 500 mA.
|
|
|
|
|
|
|
|
Connect the 5 outgoing pins (VCC, GND, DI, CS, CLK) of the first module to the next one.
|
|
|
|
With this you can connect up to 32 modules.
|
|
|
|
To extend the display hieght, multiple rows are supported. Each module row starts from left to right.
|
|
|
|
|
|
|
|
Assign the pins as follows from Tasmota's GUI:
|
2021-11-19 10:45:07 +00:00
|
|
|
|
|
|
|
DIN hardware pin --> "MAX7219 DIN"
|
|
|
|
CS hardware pin --> "MAX7219 CS"
|
|
|
|
CLK hardware pin --> "MAX7219 CLK"
|
|
|
|
|
2021-11-24 16:24:40 +00:00
|
|
|
|
2021-11-19 10:45:07 +00:00
|
|
|
Once the GPIO configuration is saved and the ESP8266/ESP32 module restarts,
|
|
|
|
set the Display Model to 19 and Display Mode to 0
|
|
|
|
|
2021-11-24 16:24:40 +00:00
|
|
|
Depending on order oth the wired 8x8 matrix modules you have got a display of size pixel_width x pixel_height.
|
|
|
|
The size has to be set with the commands "DisplayWidth <pixel_width>" and "DisplayHeight <pixel_height>"
|
2021-11-19 10:45:07 +00:00
|
|
|
|
|
|
|
After the ESP8266/ESP32 module restarts again, turn ON the display with the command "Power 1"
|
|
|
|
|
|
|
|
|
2021-11-24 16:24:40 +00:00
|
|
|
Now, the following "Display" commands can be used:
|
2021-11-19 10:45:07 +00:00
|
|
|
|
2021-11-24 16:24:40 +00:00
|
|
|
DisplayText text
|
|
|
|
Sends the text to the display.
|
|
|
|
If the text fits into the display, it is shown in the center.
|
|
|
|
Otherwise it scrolls to the left and repeats as long it is cleared or new "DisplayText" overwrites it.
|
2021-11-19 10:45:07 +00:00
|
|
|
|
2021-11-24 16:24:40 +00:00
|
|
|
DisplayDimmer [0..100]
|
|
|
|
Sets the intensity of the display.
|
2021-11-19 10:45:07 +00:00
|
|
|
|
2021-11-24 16:24:40 +00:00
|
|
|
Power [ON|OFF]
|
|
|
|
Sitches the display on or off. When "off", the display buffer is not cleared and will be shown again when after "Power ON".
|
|
|
|
Other display commands are still active when off.
|
2021-11-19 10:45:07 +00:00
|
|
|
|
2021-11-24 16:24:40 +00:00
|
|
|
DisplayClear
|
|
|
|
Clears the display
|
2021-11-19 10:45:07 +00:00
|
|
|
|
2021-11-24 16:24:40 +00:00
|
|
|
DisplayScrollDelay [0..15] // default = 0
|
|
|
|
Sets the speed of text scroll. Smaller delay = faster scrolling.
|
|
|
|
The maximum scroll speed is 50ms per pixel on DisplayScrollDelay 0.
|
2021-11-19 10:45:07 +00:00
|
|
|
|
2021-11-24 16:24:40 +00:00
|
|
|
DisplayWidth [8..256]
|
|
|
|
Sets the pixel width of the display (8x number of modules in a row)
|
2021-11-19 10:45:07 +00:00
|
|
|
|
2021-11-24 16:24:40 +00:00
|
|
|
DisplayHeight [8..256]
|
|
|
|
Sets the pixel height of the display (8x number of module rows)
|
2021-11-19 10:45:07 +00:00
|
|
|
|
2021-11-24 16:24:40 +00:00
|
|
|
DisplayClock [0|1|2]
|
|
|
|
Displays a clock.
|
|
|
|
Commands "DisplayClock 1" // 12 hr format
|
|
|
|
"DisplayClock 2" // 24 hr format
|
|
|
|
"DisplayClock 0" // turn off clock
|
2021-11-19 10:45:07 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
\*********************************************************************************************/
|
|
|
|
|
|
|
|
#define XDSP_19 19
|
|
|
|
|
2021-11-20 16:28:38 +00:00
|
|
|
#include <LedMatrix.h>
|
2021-11-19 10:45:07 +00:00
|
|
|
|
2021-11-24 16:24:40 +00:00
|
|
|
#ifdef USE_DISPLAY_MODES1TO5
|
|
|
|
#include <time.h>
|
|
|
|
#endif
|
|
|
|
|
2021-11-23 22:08:05 +00:00
|
|
|
LedMatrix *max7219_Matrix = nullptr;
|
|
|
|
bool max2791Matrix_initDriver_done = false;
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
byte modulesPerRow = 4;
|
|
|
|
byte modulesPerCol = 1;
|
2021-11-24 16:24:40 +00:00
|
|
|
byte scroll_delay = 0;
|
|
|
|
byte scroll_iteration = 0;
|
2021-11-23 22:08:05 +00:00
|
|
|
bool show_clock = false;
|
2021-11-24 16:24:40 +00:00
|
|
|
const char *timeFormat;
|
2021-11-19 10:45:07 +00:00
|
|
|
|
2021-11-23 22:08:05 +00:00
|
|
|
} LedMatrix_settings;
|
|
|
|
|
2021-11-24 16:24:40 +00:00
|
|
|
// FUNC_DISPLAY_INIT_DRIVER
|
2021-11-23 22:08:05 +00:00
|
|
|
bool MAX7291Matrix_initDriver(void)
|
2021-11-19 10:45:07 +00:00
|
|
|
{
|
|
|
|
if (!PinUsed(GPIO_MAX7219DIN) || !PinUsed(GPIO_MAX7219CLK) || !PinUsed(GPIO_MAX7219CS))
|
|
|
|
{
|
2021-11-20 16:28:38 +00:00
|
|
|
AddLog(LOG_LEVEL_INFO, PSTR("DSP: MAX7291Matrix_init GPIO pins missing DIN:%d, CLK:%d, CS:%d"), Pin(GPIO_MAX7219DIN), Pin(GPIO_MAX7219CLK), Pin(GPIO_MAX7219CS) );
|
2021-11-19 10:45:07 +00:00
|
|
|
return false; // ensure necessariy pins are configurated
|
|
|
|
}
|
|
|
|
|
|
|
|
Settings->display_model = XDSP_19;
|
2021-11-29 14:27:55 +00:00
|
|
|
renderer = nullptr; // renderer not yet used
|
2021-11-20 16:28:38 +00:00
|
|
|
if (Settings->display_width) // [pixel]
|
2021-11-19 10:45:07 +00:00
|
|
|
{
|
2021-11-23 22:08:05 +00:00
|
|
|
LedMatrix_settings.modulesPerRow = (Settings->display_width - 1) / 8 + 1;
|
2021-11-19 10:45:07 +00:00
|
|
|
}
|
2021-11-23 22:08:05 +00:00
|
|
|
Settings->display_width = 8 * LedMatrix_settings.modulesPerRow;
|
2021-11-29 14:27:55 +00:00
|
|
|
Settings->display_cols[0] = LedMatrix_settings.modulesPerRow;
|
2021-11-20 16:28:38 +00:00
|
|
|
if (Settings->display_height) // [pixel]
|
2021-11-19 10:45:07 +00:00
|
|
|
{
|
2021-11-23 22:08:05 +00:00
|
|
|
LedMatrix_settings.modulesPerCol = (Settings->display_height - 1) / 8 + 1;
|
2021-11-19 10:45:07 +00:00
|
|
|
}
|
2021-11-29 14:27:55 +00:00
|
|
|
Settings->display_height = 8 * LedMatrix_settings.modulesPerCol;
|
|
|
|
Settings->display_rows = LedMatrix_settings.modulesPerCol;
|
|
|
|
Settings->display_cols[1] = LedMatrix_settings.modulesPerCol;
|
2021-11-23 22:08:05 +00:00
|
|
|
max7219_Matrix = new LedMatrix(Pin(GPIO_MAX7219DIN), Pin(GPIO_MAX7219CLK), Pin(GPIO_MAX7219CS), LedMatrix_settings.modulesPerRow, LedMatrix_settings.modulesPerCol);
|
|
|
|
max2791Matrix_initDriver_done = true;
|
|
|
|
|
2021-11-29 14:27:55 +00:00
|
|
|
AddLog(LOG_LEVEL_INFO, PSTR("MTX: MAX7291Matrix_initDriver DIN:%d CLK:%d CS:%d size(%dx%d)"), Pin(GPIO_MAX7219DIN), Pin(GPIO_MAX7219CLK), Pin(GPIO_MAX7219CS), LedMatrix_settings.modulesPerRow, LedMatrix_settings.modulesPerCol);
|
2021-11-23 22:08:05 +00:00
|
|
|
return MAX7291Matrix_init();
|
|
|
|
}
|
|
|
|
|
2021-11-24 16:24:40 +00:00
|
|
|
// FUNC_DISPLAY_INIT
|
2021-11-23 22:08:05 +00:00
|
|
|
bool MAX7291Matrix_init(void)
|
|
|
|
{
|
2021-12-03 15:50:55 +00:00
|
|
|
Settings->display_mode = 0; // text mode
|
|
|
|
LedMatrix_settings.show_clock = 0; // no clock
|
|
|
|
|
2021-11-20 16:28:38 +00:00
|
|
|
int intensity = GetDisplayDimmer16(); // 0..15
|
|
|
|
max7219_Matrix->setIntensity(intensity);
|
2021-12-03 15:50:55 +00:00
|
|
|
|
|
|
|
max7219_Matrix->power(true); // power on
|
2021-11-29 14:27:55 +00:00
|
|
|
if(Settings->display_rotate <= 3)
|
|
|
|
{
|
|
|
|
max7219_Matrix->setOrientation((LedMatrix::ModuleOrientation)Settings->display_rotate );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// default for most 32x8 modules
|
|
|
|
Settings->display_rotate = LedMatrix::ORIENTATION_UPSIDE_DOWN;
|
|
|
|
max7219_Matrix->setOrientation( LedMatrix::ORIENTATION_UPSIDE_DOWN );
|
|
|
|
}
|
|
|
|
AddLog(LOG_LEVEL_INFO, PSTR("MTX: MAX7291Matrix_init orientation: %d, intensity: %d"), Settings->display_rotate, intensity);
|
2021-11-23 22:08:05 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-11-24 16:24:40 +00:00
|
|
|
// FUNC_DISPLAY_SCROLLDELAY
|
|
|
|
bool MAX7291Matrix_scrollDelay(void)
|
|
|
|
{
|
|
|
|
if (ArgC() == 0)
|
|
|
|
{
|
|
|
|
XdrvMailbox.payload = LedMatrix_settings.scroll_delay;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (LedMatrix_settings.scroll_delay < 0)
|
|
|
|
LedMatrix_settings.scroll_delay = 0;
|
|
|
|
LedMatrix_settings.scroll_delay = XdrvMailbox.payload;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FUNC_DISPLAY_EVERY_50_MSECOND
|
|
|
|
bool MAX7291Matrix_scrollText(void)
|
|
|
|
{
|
|
|
|
// This function is called every 50 ms.
|
|
|
|
// scroll_delay defines the number of cycles to be ignored until the display scrolls by one pixel to the left.
|
|
|
|
// e.g. scrall_delay = 4 causes a scroll each 200 ms.
|
|
|
|
LedMatrix_settings.scroll_iteration++;
|
|
|
|
if (LedMatrix_settings.scroll_delay)
|
|
|
|
LedMatrix_settings.scroll_iteration = LedMatrix_settings.scroll_iteration % LedMatrix_settings.scroll_delay;
|
|
|
|
else
|
|
|
|
LedMatrix_settings.scroll_iteration = 0;
|
|
|
|
if (LedMatrix_settings.scroll_iteration)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return max7219_Matrix->scrollText();
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef USE_DISPLAY_MODES1TO5
|
|
|
|
// FUNC_DISPLAY_CLOCK
|
2021-11-23 22:08:05 +00:00
|
|
|
bool MAX7291Matrix_clock(void)
|
|
|
|
{
|
|
|
|
LedMatrix_settings.show_clock = XdrvMailbox.payload;
|
|
|
|
if (ArgC() == 0)
|
|
|
|
XdrvMailbox.payload = 2;
|
2021-11-29 14:27:55 +00:00
|
|
|
switch(XdrvMailbox.payload)
|
2021-11-23 22:08:05 +00:00
|
|
|
{
|
2021-11-29 14:27:55 +00:00
|
|
|
case 0:
|
|
|
|
// no clock, switch to text mode
|
|
|
|
Settings->display_mode = 0;
|
|
|
|
return true;
|
|
|
|
case 1:
|
|
|
|
// 12 h clock
|
|
|
|
LedMatrix_settings.timeFormat = "%I:%M";
|
|
|
|
if(LedMatrix_settings.modulesPerRow > 6)
|
|
|
|
{
|
|
|
|
LedMatrix_settings.timeFormat = "%I:%M:%S";
|
|
|
|
}
|
|
|
|
Settings->display_mode = 1;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
// 24 h clock
|
|
|
|
LedMatrix_settings.timeFormat = "%H:%M";
|
|
|
|
if(LedMatrix_settings.modulesPerRow > 6)
|
|
|
|
{
|
|
|
|
LedMatrix_settings.timeFormat = "%H:%M:%S";
|
|
|
|
}
|
|
|
|
Settings->display_mode = 1;
|
|
|
|
break;
|
|
|
|
default:
|
2021-12-03 15:50:55 +00:00
|
|
|
//LedMatrix_settings.timeFormat = XdrvMailbox.payload;
|
|
|
|
//Settings->display_mode = 1;
|
2021-11-29 14:27:55 +00:00
|
|
|
return false;
|
2021-11-23 22:08:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
AddLog(LOG_LEVEL_DEBUG, PSTR("MTX: LedMatrix_settings.show_clock %d, timeFormat %s"), LedMatrix_settings.show_clock, LedMatrix_settings.timeFormat);
|
2021-11-19 10:45:07 +00:00
|
|
|
|
2021-11-29 14:27:55 +00:00
|
|
|
max7219_Matrix->clearDisplay();
|
2021-11-23 22:08:05 +00:00
|
|
|
MAX7291Matrix_showTime();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-11-24 16:24:40 +00:00
|
|
|
// FUNC_DISPLAY_EVERY_SECOND
|
2021-11-23 22:08:05 +00:00
|
|
|
bool MAX7291Matrix_showTime()
|
|
|
|
{
|
|
|
|
time_t rawtime;
|
|
|
|
struct tm *timeinfo;
|
|
|
|
char timeStr[10];
|
|
|
|
|
|
|
|
time(&rawtime);
|
|
|
|
timeinfo = localtime(&rawtime);
|
|
|
|
strftime(timeStr, 10, LedMatrix_settings.timeFormat, timeinfo);
|
|
|
|
|
2021-11-29 14:27:55 +00:00
|
|
|
max7219_Matrix->drawText(timeStr, false); // false: do not clear desplay on update to prevent flicker
|
2021-11-19 10:45:07 +00:00
|
|
|
return true;
|
|
|
|
}
|
2021-11-24 16:24:40 +00:00
|
|
|
#endif // USE_DISPLAY_MODES1TO5
|
|
|
|
|
2021-11-19 10:45:07 +00:00
|
|
|
|
|
|
|
bool Xdsp19(uint8_t function)
|
|
|
|
{
|
2021-11-20 16:28:38 +00:00
|
|
|
bool result = false;
|
2021-11-19 10:45:07 +00:00
|
|
|
|
2021-11-23 22:08:05 +00:00
|
|
|
if (FUNC_DISPLAY_INIT_DRIVER == function && !max2791Matrix_initDriver_done )
|
2021-11-19 10:45:07 +00:00
|
|
|
{
|
2021-11-23 22:08:05 +00:00
|
|
|
result = MAX7291Matrix_initDriver();
|
2021-11-19 10:45:07 +00:00
|
|
|
}
|
2021-11-23 22:08:05 +00:00
|
|
|
else if (max2791Matrix_initDriver_done && max7219_Matrix && (XDSP_19 == Settings->display_model))
|
2021-11-20 16:28:38 +00:00
|
|
|
{
|
|
|
|
switch (function)
|
|
|
|
{
|
2021-11-23 22:08:05 +00:00
|
|
|
case FUNC_DISPLAY_INIT:
|
|
|
|
result = MAX7291Matrix_init();
|
|
|
|
break;
|
|
|
|
case FUNC_DISPLAY_POWER:
|
|
|
|
max7219_Matrix->power(disp_power!=0);
|
|
|
|
break;
|
2021-11-20 16:28:38 +00:00
|
|
|
case FUNC_DISPLAY_MODEL:
|
|
|
|
result = true;
|
|
|
|
break;
|
|
|
|
case FUNC_DISPLAY_CLEAR:
|
2021-11-23 13:46:19 +00:00
|
|
|
result = max7219_Matrix->clearDisplay();
|
2021-11-20 16:28:38 +00:00
|
|
|
break;
|
|
|
|
case FUNC_DISPLAY_DIM:
|
|
|
|
result = max7219_Matrix->setIntensity(GetDisplayDimmer16());
|
|
|
|
break;
|
|
|
|
case FUNC_DISPLAY_DRAW_STRING:
|
2021-11-29 14:27:55 +00:00
|
|
|
case FUNC_DISPLAY_SCROLLTEXT:
|
|
|
|
case FUNC_DISPLAY_SEVENSEG_TEXT:
|
2021-12-03 15:50:55 +00:00
|
|
|
if(Settings->display_mode != 0) MAX7291Matrix_init();
|
2021-11-29 14:27:55 +00:00
|
|
|
result = max7219_Matrix->drawText(XdrvMailbox.data, true); // true: clears display before drawing text
|
|
|
|
break;
|
|
|
|
case FUNC_DISPLAY_SEVENSEG_TEXTNC:
|
2021-12-03 15:50:55 +00:00
|
|
|
if(Settings->display_mode != 0) MAX7291Matrix_init();
|
2021-11-29 14:27:55 +00:00
|
|
|
result = max7219_Matrix->drawText(XdrvMailbox.data, false); // false: does not clear display before drawing text
|
2021-11-20 16:28:38 +00:00
|
|
|
break;
|
2021-11-24 16:24:40 +00:00
|
|
|
case FUNC_DISPLAY_SCROLLDELAY:
|
|
|
|
result = MAX7291Matrix_scrollDelay();
|
|
|
|
break;
|
|
|
|
case FUNC_DISPLAY_EVERY_50_MSECOND:
|
|
|
|
result = MAX7291Matrix_scrollText();
|
|
|
|
break;
|
|
|
|
|
|
|
|
#ifdef USE_DISPLAY_MODES1TO5
|
|
|
|
case FUNC_DISPLAY_CLOCK:
|
|
|
|
result = MAX7291Matrix_clock();
|
|
|
|
break;
|
2021-11-20 16:28:38 +00:00
|
|
|
case FUNC_DISPLAY_EVERY_SECOND:
|
2021-11-23 22:08:05 +00:00
|
|
|
if (LedMatrix_settings.show_clock)
|
|
|
|
{
|
|
|
|
result = MAX7291Matrix_showTime();
|
|
|
|
}
|
2021-11-23 13:46:19 +00:00
|
|
|
break;
|
2021-11-24 16:24:40 +00:00
|
|
|
#endif // USE_DISPLAY_MODES1TO5
|
|
|
|
|
2021-11-20 16:28:38 +00:00
|
|
|
default:
|
|
|
|
result = false;
|
2021-11-19 10:45:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // USE_DISPLAY_MAX7219_MATRIX
|
|
|
|
#endif // USE_DISPLAY
|