mirror of
https://github.com/gunner47/GyverLamp.git
synced 2025-08-06 16:47:17 +03:00
270 lines
9.3 KiB
C++
270 lines
9.3 KiB
C++
// работа с бегущим текстом
|
||
|
||
// --- НАСТРОЙКИ -----------------------
|
||
#define TEXT_DIRECTION (1U) // 1 - по горизонтали, 0 - по вертикали
|
||
#define MIRR_V (0U) // отразить текст по вертикали (0 / 1)
|
||
#define MIRR_H (0U) // отразить текст по горизонтали (0 / 1)
|
||
|
||
#define TEXT_HEIGHT (0U) // высота, на которой бежит текст (от низа матрицы)
|
||
#define LET_WIDTH (5U) // ширина буквы шрифта
|
||
#define LET_HEIGHT (8U) // высота буквы шрифта
|
||
#define SPACE (1U) // пробел
|
||
#define LETTER_COLOR (CRGB::White) // цвет букв по умолчанию
|
||
|
||
|
||
// --- ДЛЯ РАЗРАБОТЧИКОВ ---------------
|
||
|
||
int16_t offset = WIDTH;
|
||
uint32_t scrollTimer = 0LL;
|
||
|
||
|
||
bool fillString(const char* text, CRGB letterColor)
|
||
{
|
||
if (!text || !strlen(text))
|
||
{
|
||
return true;
|
||
}
|
||
|
||
if (loadingFlag)
|
||
{
|
||
offset = WIDTH; // перемотка в правый край
|
||
loadingFlag = false;
|
||
}
|
||
|
||
if (millis() - scrollTimer >= 100)
|
||
{
|
||
scrollTimer = millis();
|
||
FastLED.clear();
|
||
uint8_t i = 0, j = 0;
|
||
while (text[i] != '\0')
|
||
{
|
||
if ((uint8_t)text[i] > 191) // работаем с русскими буквами
|
||
{
|
||
i++;
|
||
}
|
||
else
|
||
{
|
||
drawLetter(text[i], offset + j * (LET_WIDTH + SPACE), letterColor);
|
||
i++;
|
||
j++;
|
||
}
|
||
}
|
||
|
||
offset--;
|
||
if (offset < (int16_t)(-j * (LET_WIDTH + SPACE))) // строка убежала
|
||
{
|
||
offset = WIDTH + 3;
|
||
return true;
|
||
}
|
||
FastLED.show();
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
|
||
void printTime(uint32_t thisTime, bool onDemand, bool ONflag) // периодический вывод времени бегущей строкой; onDemand - по требованию, вывод текущего времени; иначе - вывод времени по расписанию
|
||
{
|
||
#if defined(USE_NTP) && defined(PRINT_TIME) // вывод, только если используется синхронизация времени и если заказан его вывод бегущей строкой
|
||
|
||
if (espMode != 1U || !ntpServerAddressResolved || !timeSynched) // вывод только в режиме WiFi клиента и только, если имя сервера времени разрезолвлено
|
||
{
|
||
showWarning(CRGB::Red, 4000U, 500U); // мигание красным цветом 4 секунды - смена рабочего режима лампы, перезагрузка
|
||
return;
|
||
}
|
||
|
||
CRGB letterColor = CRGB::Black;
|
||
bool needToPrint = false;
|
||
|
||
#if (PRINT_TIME >= 1U) // вывод только каждый час (красным цветом)
|
||
if (thisTime % 60U == 0U)
|
||
{
|
||
needToPrint = true;
|
||
letterColor = CRGB::Red;
|
||
}
|
||
#endif
|
||
|
||
#if (PRINT_TIME == 2U) // вывод каждый час (красным цветом) + каждые 30 минут (синим цветом)
|
||
if (thisTime % 60U != 0U && thisTime % 30U == 0U)
|
||
{
|
||
needToPrint = true;
|
||
letterColor = CRGB::Blue;
|
||
}
|
||
#endif
|
||
|
||
#if (PRINT_TIME == 3U) // вывод каждый час (красным цветом) + каждые 15 минут (синим цветом)
|
||
if (thisTime % 60U != 0U && thisTime % 15U == 0U)
|
||
{
|
||
needToPrint = true;
|
||
letterColor = CRGB::Blue;
|
||
}
|
||
#endif
|
||
|
||
#if (PRINT_TIME == 4U) // вывод каждый час (красным цветом) + каждые 10 минут (синим цветом)
|
||
if (thisTime % 60U != 0U && thisTime % 10U == 0U)
|
||
{
|
||
needToPrint = true;
|
||
letterColor = CRGB::Blue;
|
||
}
|
||
#endif
|
||
|
||
#if (PRINT_TIME == 5U) // вывод каждый час (красным цветом) + каждые 5 минут (синим цветом)
|
||
if (thisTime % 60U != 0U && thisTime % 5U == 0U)
|
||
{
|
||
needToPrint = true;
|
||
letterColor = CRGB::Blue;
|
||
}
|
||
#endif
|
||
|
||
#if (PRINT_TIME == 6U) // вывод каждый час (красным цветом) + каждую минуту (синим цветом)
|
||
if (thisTime % 60U != 0U)
|
||
{
|
||
needToPrint = true;
|
||
letterColor = CRGB::Blue;
|
||
}
|
||
#endif
|
||
|
||
if (onDemand)
|
||
{
|
||
letterColor = CRGB::White;
|
||
}
|
||
|
||
if ((needToPrint && thisTime != lastTimePrinted) || onDemand)
|
||
{
|
||
lastTimePrinted = thisTime;
|
||
char stringTime[10U]; // буффер для выводимого текста, его длина должна быть НЕ МЕНЬШЕ, чем длина текста + 1
|
||
sprintf_P(stringTime, PSTR("-> %u:%02u"), (uint8_t)((thisTime - thisTime % 60U) / 60U), (uint8_t)(thisTime % 60U));
|
||
loadingFlag = true;
|
||
FastLED.setBrightness(getBrightnessForPrintTime(thisTime, ONflag));
|
||
delay(1);
|
||
while (!fillString(stringTime, letterColor)) { delay(1); ESP.wdtFeed(); }
|
||
loadingFlag = true;
|
||
}
|
||
|
||
#endif
|
||
}
|
||
|
||
|
||
uint8_t getBrightnessForPrintTime(uint32_t thisTime, bool ONflag) // определение яркости для вывода времени бегущей строкой в зависимости от ESP_MODE, USE_NTP, успешности синхронизации времени,
|
||
// текущего времени суток, настроек дневного/ночного времени и того, включена ли сейчас матрица
|
||
{
|
||
#if defined(USE_NTP) && defined(PRINT_TIME)
|
||
|
||
if (espMode != 1U || !ntpServerAddressResolved || ONflag)
|
||
{
|
||
return modes[currentMode].Brightness;
|
||
}
|
||
|
||
if (NIGHT_HOURS_START >= NIGHT_HOURS_STOP) // ночное время включает переход через полночь
|
||
{
|
||
if (thisTime >= NIGHT_HOURS_START || thisTime <= NIGHT_HOURS_STOP)// период действия ночного времени
|
||
{
|
||
return (NIGHT_HOURS_BRIGHTNESS >= 0)
|
||
? NIGHT_HOURS_BRIGHTNESS
|
||
: modes[currentMode].Brightness;
|
||
}
|
||
}
|
||
else // ночное время не включает переход через полночь
|
||
{
|
||
if (thisTime >= NIGHT_HOURS_START && thisTime <= NIGHT_HOURS_STOP)// период действия ночного времени
|
||
{
|
||
return (NIGHT_HOURS_BRIGHTNESS >= 0)
|
||
? NIGHT_HOURS_BRIGHTNESS
|
||
: modes[currentMode].Brightness;
|
||
}
|
||
}
|
||
|
||
return (DAY_HOURS_BRIGHTNESS >= 0) // дневное время
|
||
? DAY_HOURS_BRIGHTNESS
|
||
: modes[currentMode].Brightness;
|
||
|
||
#endif
|
||
|
||
return modes[currentMode].Brightness;
|
||
}
|
||
|
||
|
||
void drawLetter(uint8_t letter, int8_t offset, CRGB letterColor)
|
||
{
|
||
uint8_t start_pos = 0, finish_pos = LET_WIDTH;
|
||
|
||
if (offset < (int8_t)-LET_WIDTH || offset > (int8_t)WIDTH)
|
||
{
|
||
return;
|
||
}
|
||
if (offset < 0)
|
||
{
|
||
start_pos = (uint8_t)-offset;
|
||
}
|
||
if (offset > (int8_t)(WIDTH - LET_WIDTH))
|
||
{
|
||
finish_pos = (uint8_t)(WIDTH - offset);
|
||
}
|
||
|
||
for (uint8_t i = start_pos; i < finish_pos; i++)
|
||
{
|
||
uint8_t thisByte;
|
||
if (MIRR_V)
|
||
{
|
||
thisByte = getFont(letter, (uint8_t)(LET_WIDTH - 1 - i));
|
||
}
|
||
else
|
||
{
|
||
thisByte = getFont(letter, i);
|
||
}
|
||
|
||
for (uint8_t j = 0; j < LET_HEIGHT; j++)
|
||
{
|
||
bool thisBit = MIRR_H
|
||
? thisByte & (1 << j)
|
||
: thisByte & (1 << (LET_HEIGHT - 1 - j));
|
||
|
||
// рисуем столбец (i - горизонтальная позиция, j - вертикальная)
|
||
if (TEXT_DIRECTION)
|
||
{
|
||
if (thisBit)
|
||
{
|
||
leds[getPixelNumber(offset + i, TEXT_HEIGHT + j)] = letterColor;
|
||
}
|
||
else
|
||
{
|
||
drawPixelXY(offset + i, TEXT_HEIGHT + j, 0x000000);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (thisBit)
|
||
{
|
||
leds[getPixelNumber(i, offset + TEXT_HEIGHT + j)] = letterColor;
|
||
}
|
||
else
|
||
{
|
||
drawPixelXY(i, offset + TEXT_HEIGHT + j, 0x000000);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
// --- СЛУЖЕБНЫЕ ФУНКЦИИ ---------------
|
||
uint8_t getFont(uint8_t asciiCode, uint8_t row) // интерпретатор кода символа в массиве fontHEX (для Arduino IDE 1.8.* и выше)
|
||
{
|
||
asciiCode = asciiCode - '0' + 16; // перевод код символа из таблицы ASCII в номер согласно нумерации массива
|
||
|
||
if (asciiCode <= 90) // печатаемые символы и английские буквы
|
||
{
|
||
return pgm_read_byte(&fontHEX[asciiCode][row]);
|
||
}
|
||
else if (asciiCode >= 112 && asciiCode <= 159)
|
||
{
|
||
return pgm_read_byte(&fontHEX[asciiCode - 17][row]);
|
||
}
|
||
else if (asciiCode >= 96 && asciiCode <= 111)
|
||
{
|
||
return pgm_read_byte(&fontHEX[asciiCode + 47][row]);
|
||
}
|
||
|
||
return 0;
|
||
}
|