2019-05-05 23:43:18 +02:00
|
|
|
#ifdef HAS_MATRIX_DISPLAY
|
|
|
|
|
|
|
|
#include "globals.h"
|
|
|
|
|
2019-05-31 13:20:11 +02:00
|
|
|
#define MATRIX_DISPLAY_PAGES (2) // number of display pages
|
2019-08-17 18:45:00 +02:00
|
|
|
#define LINE_DIAGRAM_DIVIDER (2) // scales pax numbers to led rows
|
2019-05-05 23:43:18 +02:00
|
|
|
|
|
|
|
// local Tag for logging
|
|
|
|
static const char TAG[] = __FILE__;
|
|
|
|
|
2019-08-18 22:16:35 +02:00
|
|
|
uint8_t MatrixDisplayIsOn = 0;
|
|
|
|
static uint8_t displaybuf[LED_MATRIX_WIDTH * LED_MATRIX_HEIGHT / 8] = {0};
|
2019-05-07 21:17:06 +02:00
|
|
|
static unsigned long ulLastNumMacs = 0;
|
2019-05-31 13:20:11 +02:00
|
|
|
static time_t ulLastTime = myTZ.toLocal(now());
|
2019-05-05 23:43:18 +02:00
|
|
|
|
|
|
|
LEDMatrix matrix(LED_MATRIX_LA_74138, LED_MATRIX_LB_74138, LED_MATRIX_LC_74138,
|
|
|
|
LED_MATRIX_LD_74138, LED_MATRIX_EN_74138, LED_MATRIX_DATA_R1,
|
|
|
|
LED_MATRIX_LATCHPIN, LED_MATRIX_CLOCKPIN);
|
|
|
|
|
2019-05-31 13:20:11 +02:00
|
|
|
// --- SELECT YOUR FONT HERE ---
|
2019-05-05 23:43:18 +02:00
|
|
|
const FONT_INFO *ActiveFontInfo = &digital7_18ptFontInfo;
|
2019-07-15 22:19:06 +02:00
|
|
|
// const FONT_INFO *ActiveFontInfo = &arialNarrow_17ptFontInfo;
|
|
|
|
// const FONT_INFO *ActiveFontInfo = &gillSansMTCondensed_18ptFontInfo;
|
|
|
|
// const FONT_INFO *ActiveFontInfo = &gillSansMTCondensed_16ptFontInfo;
|
2019-05-31 13:20:11 +02:00
|
|
|
|
2019-05-05 23:43:18 +02:00
|
|
|
const uint8_t *iaActiveFont = ActiveFontInfo->Bitmap;
|
|
|
|
const FONT_CHAR_INFO *ActiveFontCharInfo = ActiveFontInfo->Descriptors;
|
|
|
|
|
2019-05-30 13:00:24 +02:00
|
|
|
void init_matrix_display(bool reverse) {
|
2019-05-05 23:43:18 +02:00
|
|
|
ESP_LOGI(TAG, "Initializing LED Matrix display");
|
|
|
|
matrix.begin(displaybuf, LED_MATRIX_WIDTH, LED_MATRIX_HEIGHT);
|
2019-08-18 16:55:43 +02:00
|
|
|
|
|
|
|
if (MatrixDisplayIsOn)
|
|
|
|
matrix.on();
|
|
|
|
else
|
|
|
|
matrix.off();
|
|
|
|
|
2019-05-30 13:00:24 +02:00
|
|
|
if (reverse)
|
|
|
|
matrix.reverse();
|
2019-05-05 23:43:18 +02:00
|
|
|
matrix.clear();
|
2019-08-18 22:16:35 +02:00
|
|
|
matrix.drawPoint(0, LED_MATRIX_HEIGHT - 1, 1);
|
2019-05-05 23:43:18 +02:00
|
|
|
} // init_display
|
|
|
|
|
2019-05-31 13:20:11 +02:00
|
|
|
void refreshTheMatrixDisplay(bool nextPage) {
|
2019-08-17 18:30:45 +02:00
|
|
|
static uint8_t DisplayPage = 0, col = 0, row = 0;
|
2019-08-18 16:47:28 +02:00
|
|
|
uint8_t level;
|
2019-05-31 13:20:11 +02:00
|
|
|
char buff[16];
|
2019-05-05 23:43:18 +02:00
|
|
|
|
2019-05-07 21:17:06 +02:00
|
|
|
// if Matrixdisplay is switched off we don't refresh it to relax cpu
|
|
|
|
if (!MatrixDisplayIsOn && (MatrixDisplayIsOn == cfg.screenon))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// set display on/off according to current device configuration
|
|
|
|
if (MatrixDisplayIsOn != cfg.screenon) {
|
|
|
|
MatrixDisplayIsOn = cfg.screenon;
|
2019-08-18 16:55:43 +02:00
|
|
|
if (MatrixDisplayIsOn)
|
|
|
|
matrix.on();
|
|
|
|
else
|
|
|
|
matrix.off();
|
2019-05-07 21:17:06 +02:00
|
|
|
}
|
|
|
|
|
2019-05-31 13:20:11 +02:00
|
|
|
if (nextPage) {
|
|
|
|
DisplayPage =
|
|
|
|
(DisplayPage >= MATRIX_DISPLAY_PAGES - 1) ? 0 : (DisplayPage + 1);
|
2019-05-05 23:43:18 +02:00
|
|
|
matrix.clear();
|
2019-08-17 18:30:45 +02:00
|
|
|
col = 0;
|
2019-05-05 23:43:18 +02:00
|
|
|
}
|
|
|
|
|
2019-05-31 13:20:11 +02:00
|
|
|
switch (DisplayPage % MATRIX_DISPLAY_PAGES) {
|
|
|
|
|
2019-08-17 18:30:45 +02:00
|
|
|
// page 0: number of current pax OR footfall line diagram
|
|
|
|
// page 1: time of day
|
2019-05-31 13:20:11 +02:00
|
|
|
|
|
|
|
case 0:
|
|
|
|
|
2019-08-17 18:30:45 +02:00
|
|
|
if (cfg.countermode == 1)
|
|
|
|
|
|
|
|
{ // cumulative counter mode -> display total number of pax
|
|
|
|
if (ulLastNumMacs != macs.size()) {
|
|
|
|
ulLastNumMacs = macs.size();
|
|
|
|
matrix.clear();
|
|
|
|
DrawNumber(String(ulLastNumMacs));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
else { // cyclic counter mode -> plot a line diagram
|
|
|
|
|
|
|
|
if (ulLastNumMacs != macs.size()) {
|
|
|
|
|
|
|
|
// next count cycle?
|
|
|
|
if (macs.size() == 0) {
|
2019-08-18 16:47:28 +02:00
|
|
|
|
|
|
|
// matrix full? then scroll left 1 dot, else increment column
|
2019-08-18 22:16:35 +02:00
|
|
|
if (col < (LED_MATRIX_WIDTH - 1))
|
2019-08-18 16:47:28 +02:00
|
|
|
col++;
|
|
|
|
else
|
2019-08-18 22:16:35 +02:00
|
|
|
ScrollLeft(displaybuf, LED_MATRIX_WIDTH, LED_MATRIX_HEIGHT);
|
2019-08-18 16:47:28 +02:00
|
|
|
|
|
|
|
} else
|
|
|
|
matrix.drawPoint(col, row, 0); // clear current dot
|
|
|
|
|
|
|
|
// scale and set new dot
|
2019-08-17 18:30:45 +02:00
|
|
|
ulLastNumMacs = macs.size();
|
2019-08-18 16:47:28 +02:00
|
|
|
level = ulLastNumMacs / LINE_DIAGRAM_DIVIDER;
|
2019-08-18 22:16:35 +02:00
|
|
|
row = level <= LED_MATRIX_HEIGHT
|
|
|
|
? LED_MATRIX_HEIGHT - 1 - level % LED_MATRIX_HEIGHT
|
|
|
|
: 0;
|
2019-08-17 18:30:45 +02:00
|
|
|
matrix.drawPoint(col, row, 1);
|
|
|
|
}
|
2019-05-31 13:20:11 +02:00
|
|
|
}
|
2019-07-15 22:19:06 +02:00
|
|
|
break;
|
2019-05-31 13:20:11 +02:00
|
|
|
|
|
|
|
case 1:
|
|
|
|
|
|
|
|
const time_t t = myTZ.toLocal(now());
|
|
|
|
if (ulLastTime != t) {
|
|
|
|
ulLastTime = t;
|
|
|
|
matrix.clear();
|
|
|
|
snprintf(buff, sizeof(buff), "%02d:%02d:%02d", hour(t), minute(t),
|
|
|
|
second(t));
|
|
|
|
DrawNumber(String(buff));
|
|
|
|
}
|
2019-07-15 22:19:06 +02:00
|
|
|
break;
|
2019-05-31 13:20:11 +02:00
|
|
|
|
|
|
|
} // switch page
|
|
|
|
|
2019-05-05 23:43:18 +02:00
|
|
|
matrix.scan();
|
|
|
|
}
|
|
|
|
|
|
|
|
// (x, y) top-left position, x should be multiple of 8
|
|
|
|
void DrawChar(uint16_t x, uint16_t y, char cChar) {
|
|
|
|
// Get address of char in font char descriptor from font descriptor
|
|
|
|
auto CharDescAddress = (cChar - ActiveFontInfo->StartChar);
|
|
|
|
// Get offset of char into font bitmap
|
|
|
|
uint16_t FontBitmapOffset = ActiveFontCharInfo[CharDescAddress].offset;
|
|
|
|
// Check font height, if it's less than matrix height we need to
|
|
|
|
// add some empty lines to font does not stick to the top
|
|
|
|
if (ActiveFontInfo->CharHeight < (LED_MATRIX_HEIGHT - y)) {
|
|
|
|
uint8_t FillerLines = (LED_MATRIX_HEIGHT - y) - ActiveFontInfo->CharHeight;
|
|
|
|
if (FillerLines % 2 == 0) {
|
|
|
|
// Use floor (round down) to get heighest possible divider
|
|
|
|
// for missing lines
|
|
|
|
y = floor(FillerLines / 2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int iDst = (x / 8) + (y * 8);
|
|
|
|
int Shift = x % 8;
|
|
|
|
for (uint8_t i = 0; i < ActiveFontCharInfo[CharDescAddress].height; i++) {
|
|
|
|
int iDigitA = iaActiveFont[FontBitmapOffset];
|
|
|
|
|
|
|
|
int Left = iDigitA >> Shift;
|
|
|
|
int Right = iDigitA << (8 - Shift);
|
|
|
|
|
|
|
|
displaybuf[iDst] |= Left;
|
|
|
|
displaybuf[iDst + 1] |= Right;
|
|
|
|
|
|
|
|
if (ActiveFontCharInfo[CharDescAddress].width > 8) {
|
|
|
|
int iDigitB = iaActiveFont[FontBitmapOffset + 1];
|
|
|
|
Left = iDigitB >> Shift;
|
|
|
|
Right = iDigitB << (8 - Shift);
|
|
|
|
|
|
|
|
displaybuf[iDst + 1] |= Left;
|
|
|
|
displaybuf[iDst + 2] |= Right;
|
|
|
|
FontBitmapOffset++;
|
|
|
|
}
|
|
|
|
|
|
|
|
FontBitmapOffset++;
|
|
|
|
iDst += 8;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void DrawNumber(String strNum, uint8_t iDotPos) {
|
|
|
|
uint8_t iNumLength = strNum.length();
|
|
|
|
uint8_t iDigitPos = 0;
|
|
|
|
|
|
|
|
for (int i = 0; i < iNumLength; i++) {
|
|
|
|
DrawChar(iDigitPos, 0, strNum.charAt(i));
|
|
|
|
if (i + 1 == iDotPos) {
|
|
|
|
iDigitPos = iDigitPos + GetCharWidth(strNum.charAt(i)) +
|
|
|
|
ActiveFontInfo->SpaceWidth;
|
|
|
|
DrawChar(iDigitPos, 0, '.');
|
|
|
|
iDigitPos = iDigitPos + GetCharWidth('.') + ActiveFontInfo->SpaceWidth;
|
|
|
|
} else {
|
|
|
|
iDigitPos = iDigitPos + GetCharWidth(strNum.charAt(i)) +
|
|
|
|
ActiveFontInfo->SpaceWidth;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t GetCharFromFont(char cChar) {
|
|
|
|
auto cStartChar = ActiveFontInfo->StartChar;
|
|
|
|
auto iCharLocation = cChar - cStartChar;
|
|
|
|
auto iCharBitmap = iaActiveFont[iCharLocation];
|
|
|
|
|
|
|
|
return iCharBitmap;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t GetCharWidth(char cChar) {
|
|
|
|
// Get address of char in font char descriptor from font descriptor
|
|
|
|
auto CharDescAddress = (cChar - ActiveFontInfo->StartChar);
|
|
|
|
// Get offset of char into font bitmap
|
|
|
|
auto CharDescriptor = ActiveFontCharInfo[CharDescAddress];
|
|
|
|
return CharDescriptor.width;
|
|
|
|
}
|
|
|
|
|
2019-08-19 21:48:11 +02:00
|
|
|
void ScrollLeft(uint8_t *buf, const uint16_t cols, const uint16_t rows) {
|
2019-08-18 22:16:35 +02:00
|
|
|
uint32_t i, k, idx;
|
2019-08-19 21:48:11 +02:00
|
|
|
const uint32_t x = cols / 8;
|
2019-08-18 22:16:35 +02:00
|
|
|
|
|
|
|
for (k = 0; k < rows; k++) {
|
|
|
|
// scroll a line with x bytes one dot to the left
|
2019-08-19 21:48:11 +02:00
|
|
|
for (i = 0; i < x - 1; ++i) {
|
|
|
|
idx = i + k * x;
|
2019-08-18 22:16:35 +02:00
|
|
|
buf[idx] = (buf[idx] << 1) | ((buf[idx + 1] >> 7) & 1);
|
|
|
|
}
|
|
|
|
buf[idx + 1] <<= 1;
|
2019-08-18 16:47:28 +02:00
|
|
|
}
|
|
|
|
}
|
2019-08-18 16:58:29 +02:00
|
|
|
|
2019-05-05 23:43:18 +02:00
|
|
|
#endif // HAS_MATRIX_DISPLAY
|