mirror of
https://github.com/letscontrolit/ESPEasy.git
synced 2026-09-12 17:45:49 +00:00
476 lines
17 KiB
C++
476 lines
17 KiB
C++
#include "../PluginStructs/P116_data_struct.h"
|
|
|
|
#ifdef USES_P116
|
|
|
|
# include "../Helpers/Hardware.h"
|
|
|
|
/****************************************************************************
|
|
* ST77xx_type_toString: Display-value for the device selected
|
|
***************************************************************************/
|
|
const __FlashStringHelper* ST77xx_type_toString(ST77xx_type_e device) {
|
|
switch (device) {
|
|
case ST77xx_type_e::ST7735s_128x128: return F("ST7735 128 x 128px");
|
|
case ST77xx_type_e::ST7735s_128x160: return F("ST7735 128 x 160px");
|
|
case ST77xx_type_e::ST7735s_80x160: return F("ST7735 80 x 160px");
|
|
case ST77xx_type_e::ST7735s_80x160_M5: return F("ST7735 80 x 160px (Color inverted)");
|
|
case ST77xx_type_e::ST7789vw_240x320: return F("ST7789 240 x 320px");
|
|
case ST77xx_type_e::ST7789vw_240x240: return F("ST7789 240 x 240px");
|
|
case ST77xx_type_e::ST7789vw_240x280: return F("ST7789 240 x 280px");
|
|
case ST77xx_type_e::ST7789vw_135x240: return F("ST7789 135 x 240px");
|
|
case ST77xx_type_e::ST7796s_320x480: return F("ST7796 320 x 480px");
|
|
case ST77xx_type_e::ST77xx_MAX: break;
|
|
}
|
|
return F("Unsupported type!");
|
|
}
|
|
|
|
/****************************************************************************
|
|
* ST77xx_type_toResolution: X and Y resolution for the selected type
|
|
***************************************************************************/
|
|
void ST77xx_type_toResolution(ST77xx_type_e device, uint16_t& x, uint16_t& y) {
|
|
switch (device) {
|
|
case ST77xx_type_e::ST7735s_128x128:
|
|
x = 128;
|
|
y = 128;
|
|
break;
|
|
case ST77xx_type_e::ST7735s_128x160:
|
|
x = 128;
|
|
y = 160;
|
|
break;
|
|
case ST77xx_type_e::ST7735s_80x160_M5:
|
|
case ST77xx_type_e::ST7735s_80x160:
|
|
x = 80;
|
|
y = 160;
|
|
break;
|
|
case ST77xx_type_e::ST7789vw_240x320:
|
|
x = 240;
|
|
y = 320;
|
|
break;
|
|
case ST77xx_type_e::ST7789vw_240x240:
|
|
x = 240;
|
|
y = 240;
|
|
break;
|
|
case ST77xx_type_e::ST7789vw_240x280:
|
|
x = 240;
|
|
y = 280;
|
|
break;
|
|
case ST77xx_type_e::ST7789vw_135x240:
|
|
x = 135;
|
|
y = 240;
|
|
break;
|
|
case ST77xx_type_e::ST7796s_320x480:
|
|
x = 320;
|
|
y = 480;
|
|
break;
|
|
case ST77xx_type_e::ST77xx_MAX:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* P116_CommandTrigger_toString: return the command string selected
|
|
***************************************************************************/
|
|
const __FlashStringHelper* P116_CommandTrigger_toString(P116_CommandTrigger cmd) {
|
|
switch (cmd) {
|
|
case P116_CommandTrigger::tft: return F("tft");
|
|
case P116_CommandTrigger::st7735: return F("st7735");
|
|
case P116_CommandTrigger::st7789: return F("st7789");
|
|
case P116_CommandTrigger::st7796: return F("st7796");
|
|
case P116_CommandTrigger::MAX: return F("None");
|
|
case P116_CommandTrigger::st77xx: break;
|
|
}
|
|
return F("st77xx"); // Default command trigger
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Constructor
|
|
***************************************************************************/
|
|
P116_data_struct::P116_data_struct(ST77xx_type_e device,
|
|
uint8_t rotation,
|
|
uint8_t fontscaling,
|
|
AdaGFXTextPrintMode textmode,
|
|
int8_t backlightPin,
|
|
uint8_t backlightPercentage,
|
|
uint32_t displayTimer,
|
|
String commandTrigger,
|
|
uint16_t fgcolor,
|
|
uint16_t bgcolor,
|
|
bool textBackFill)
|
|
: _device(device), _rotation(rotation), _fontscaling(fontscaling), _textmode(textmode), _backlightPin(backlightPin),
|
|
_backlightPercentage(backlightPercentage), _displayTimer(displayTimer), _displayTimeout(displayTimer),
|
|
_commandTrigger(commandTrigger), _fgcolor(fgcolor), _bgcolor(bgcolor), _textBackFill(textBackFill)
|
|
{
|
|
ST77xx_type_toResolution(_device, _xpix, _ypix);
|
|
|
|
updateFontMetrics();
|
|
_commandTrigger.toLowerCase();
|
|
_commandTriggerCmd = _commandTrigger;
|
|
_commandTriggerCmd += F("cmd");
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Destructor
|
|
***************************************************************************/
|
|
P116_data_struct::~P116_data_struct() {
|
|
cleanup();
|
|
}
|
|
|
|
/****************************************************************************
|
|
* plugin_init: Initialize display
|
|
***************************************************************************/
|
|
bool P116_data_struct::plugin_init(struct EventStruct *event) {
|
|
bool success = false;
|
|
|
|
ButtonState = false; // button not touched
|
|
ButtonLastState = 0xFF; // Last state checked (debouncing in progress)
|
|
DebounceCounter = 0; // debounce counter
|
|
|
|
if (nullptr == st77xx) {
|
|
addLog(LOG_LEVEL_INFO, F("ST77xx: Init start."));
|
|
uint8_t initRoptions = 0xFF;
|
|
|
|
switch (_device) {
|
|
case ST77xx_type_e::ST7735s_128x128:
|
|
|
|
if (initRoptions == 0xFF) {
|
|
initRoptions = INITR_144GREENTAB; // 128x128px
|
|
}
|
|
|
|
// fall through
|
|
case ST77xx_type_e::ST7735s_128x160:
|
|
|
|
if (initRoptions == 0xFF) {
|
|
initRoptions = INITR_BLACKTAB; // 128x160px
|
|
}
|
|
|
|
// fall through
|
|
case ST77xx_type_e::ST7735s_80x160_M5:
|
|
|
|
if (initRoptions == 0xFF) {
|
|
initRoptions = INITR_GREENTAB160x80; // 80x160px ST7735sv, inverted (M5Stack StickC)
|
|
}
|
|
|
|
// fall through
|
|
case ST77xx_type_e::ST7735s_80x160:
|
|
{
|
|
if (initRoptions == 0xFF) {
|
|
initRoptions = INITR_MINI160x80; // 80x160px
|
|
}
|
|
|
|
st7735 = new (std::nothrow) Adafruit_ST7735(PIN(0), PIN(1), PIN(2));
|
|
|
|
if (nullptr != st7735) {
|
|
st7735->initR(initRoptions); // initialize a ST7735s chip
|
|
st77xx = st7735; // pass pointer after initialization
|
|
}
|
|
break;
|
|
}
|
|
case ST77xx_type_e::ST7789vw_240x320: // Fall through
|
|
case ST77xx_type_e::ST7789vw_240x240:
|
|
case ST77xx_type_e::ST7789vw_240x280:
|
|
case ST77xx_type_e::ST7789vw_135x240:
|
|
{
|
|
st7789 = new (std::nothrow) Adafruit_ST7789(PIN(0), PIN(1), PIN(2));
|
|
|
|
if (nullptr != st7789) {
|
|
st7789->init(_xpix, _ypix, SPI_MODE2);
|
|
st77xx = st7789;
|
|
}
|
|
break;
|
|
}
|
|
case ST77xx_type_e::ST7796s_320x480:
|
|
{
|
|
st7796 = new (std::nothrow) Adafruit_ST7796S_kbv(PIN(0), PIN(1), PIN(2));
|
|
|
|
if (nullptr != st7796) {
|
|
st7796->begin();
|
|
st77xx = st7796;
|
|
}
|
|
break;
|
|
}
|
|
case ST77xx_type_e::ST77xx_MAX:
|
|
break;
|
|
}
|
|
|
|
# ifndef BUILD_NO_DEBUG
|
|
|
|
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
|
|
String log;
|
|
log.reserve(90);
|
|
log += F("ST77xx: Init done, address: 0x");
|
|
log += String(reinterpret_cast<ulong>(st77xx), HEX);
|
|
log += ' ';
|
|
|
|
if (nullptr == st77xx) {
|
|
log += F("in");
|
|
}
|
|
log += F("valid, commands: ");
|
|
log += _commandTrigger;
|
|
log += F(", display: ");
|
|
log += ST77xx_type_toString(_device);
|
|
addLogMove(LOG_LEVEL_INFO, log);
|
|
}
|
|
# endif // ifndef BUILD_NO_DEBUG
|
|
} else {
|
|
addLog(LOG_LEVEL_INFO, F("ST77xx: No init?"));
|
|
}
|
|
|
|
if (nullptr != st77xx) {
|
|
gfxHelper = new (std::nothrow) AdafruitGFX_helper(st77xx,
|
|
_commandTrigger,
|
|
_xpix,
|
|
_ypix,
|
|
AdaGFXColorDepth::FullColor,
|
|
_textmode,
|
|
_fontscaling,
|
|
_fgcolor,
|
|
_bgcolor,
|
|
true,
|
|
_textBackFill);
|
|
|
|
displayOnOff(true);
|
|
|
|
gfxHelper->setRotation(_rotation);
|
|
st77xx->fillScreen(_bgcolor); // fill screen with black color
|
|
st77xx->setTextColor(_fgcolor, _bgcolor); // set text color to white and black background
|
|
|
|
# ifdef P116_SHOW_SPLASH
|
|
uint16_t yPos = 0;
|
|
gfxHelper->printText(String(F("ESPEasy")).c_str(), 0, yPos, 3, ST77XX_WHITE, ST77XX_BLUE);
|
|
yPos += (3 * _fontheight);
|
|
gfxHelper->printText(String(F("ST77xx")).c_str(), 0, yPos, 2, ST77XX_BLUE, ST77XX_WHITE);
|
|
delay(100); // Splash
|
|
# endif // ifdef P116_SHOW_SPLASH
|
|
|
|
gfxHelper->setColumnRowMode(bitRead(P116_CONFIG_FLAGS, P116_CONFIG_FLAG_USE_COL_ROW));
|
|
st77xx->setTextSize(_fontscaling); // Handles 0 properly, text size, default 1 = very small
|
|
st77xx->setCursor(0, 0); // move cursor to position (0, 0) pixel
|
|
updateFontMetrics();
|
|
|
|
|
|
if (P116_CONFIG_BUTTON_PIN != -1) {
|
|
pinMode(P116_CONFIG_BUTTON_PIN, INPUT_PULLUP);
|
|
}
|
|
success = true;
|
|
}
|
|
return success;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* updateFontMetrics: recalculate x and y columns, based on font size and font scale
|
|
***************************************************************************/
|
|
void P116_data_struct::updateFontMetrics() {
|
|
if (nullptr != gfxHelper) {
|
|
gfxHelper->getTextMetrics(_textcols, _textrows, _fontwidth, _fontheight, _fontscaling, _heightOffset, _xpix, _ypix);
|
|
gfxHelper->getColors(_fgcolor, _bgcolor);
|
|
} else {
|
|
_textcols = _xpix / (_fontwidth * _fontscaling);
|
|
_textrows = _ypix / (_fontheight * _fontscaling);
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* plugin_exit: De-initialize before destruction
|
|
***************************************************************************/
|
|
bool P116_data_struct::plugin_exit(struct EventStruct *event) {
|
|
addLog(LOG_LEVEL_INFO, F("ST77xx: Exit."));
|
|
|
|
if ((nullptr != st77xx) && bitRead(P116_CONFIG_FLAGS, P116_CONFIG_FLAG_CLEAR_ON_EXIT)) {
|
|
st77xx->fillScreen(ADAGFX_BLACK); // fill screen with black color
|
|
displayOnOff(false);
|
|
}
|
|
cleanup();
|
|
return true;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* cleanup: De-initialize pointers
|
|
***************************************************************************/
|
|
void P116_data_struct::cleanup() {
|
|
if (nullptr != gfxHelper) { delete gfxHelper; }
|
|
gfxHelper = nullptr;
|
|
|
|
if (nullptr != st7735) { delete st7735; }
|
|
st7735 = nullptr;
|
|
|
|
if (nullptr != st7789) { delete st7789; }
|
|
st7789 = nullptr;
|
|
st77xx = nullptr; // Only used as a proxy
|
|
}
|
|
|
|
/****************************************************************************
|
|
* plugin_read: Re-draw the default content
|
|
***************************************************************************/
|
|
bool P116_data_struct::plugin_read(struct EventStruct *event) {
|
|
if (nullptr != st77xx) {
|
|
String strings[P116_Nlines];
|
|
LoadCustomTaskSettings(event->TaskIndex, strings, P116_Nlines, 0);
|
|
|
|
bool hasContent = false;
|
|
|
|
for (uint8_t x = 0; x < P116_Nlines && !hasContent; x++) {
|
|
hasContent = !strings[x].isEmpty();
|
|
}
|
|
|
|
if (hasContent) {
|
|
gfxHelper->setColumnRowMode(false); // Turn off column mode
|
|
|
|
int yPos = 0;
|
|
|
|
for (uint8_t x = 0; x < P116_Nlines; x++) {
|
|
String newString = AdaGFXparseTemplate(strings[x], _textcols, gfxHelper);
|
|
|
|
# if ADAGFX_PARSE_SUBCOMMAND
|
|
updateFontMetrics();
|
|
# endif // if ADAGFX_PARSE_SUBCOMMAND
|
|
|
|
if (yPos < _ypix) {
|
|
gfxHelper->printText(newString.c_str(), 0, yPos, _fontscaling, _fgcolor, _bgcolor);
|
|
}
|
|
delay(0);
|
|
yPos += (_fontheight * _fontscaling);
|
|
}
|
|
gfxHelper->setColumnRowMode(bitRead(P116_CONFIG_FLAGS, P116_CONFIG_FLAG_USE_COL_ROW)); // Restore column mode
|
|
int16_t curX, curY;
|
|
gfxHelper->getCursorXY(curX, curY); // Get current X and Y coordinates,
|
|
UserVar[event->BaseVarIndex] = curX; // and put into Values
|
|
UserVar[event->BaseVarIndex + 1] = curY;
|
|
}
|
|
}
|
|
return false; // Always return false, so no attempt to send to
|
|
// Controllers or generate events is started
|
|
}
|
|
|
|
/****************************************************************************
|
|
* plugin_ten_per_second: check button, if any, that wakes up the display
|
|
***************************************************************************/
|
|
bool P116_data_struct::plugin_ten_per_second(struct EventStruct *event) {
|
|
if ((P116_CONFIG_BUTTON_PIN != -1) && (getButtonState()) && (nullptr != st77xx)) {
|
|
displayOnOff(true);
|
|
markButtonStateProcessed();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* plugin_once_a_second: Count down display timer, if any, and turn display off if countdown reached
|
|
***************************************************************************/
|
|
bool P116_data_struct::plugin_once_a_second(struct EventStruct *event) {
|
|
if (_displayTimer > 0) {
|
|
_displayTimer--;
|
|
|
|
if ((nullptr != st77xx) && (_displayTimer == 0)) {
|
|
displayOnOff(false);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* plugin_write: Handle commands
|
|
***************************************************************************/
|
|
bool P116_data_struct::plugin_write(struct EventStruct *event, const String& string) {
|
|
bool success = false;
|
|
String cmd = parseString(string, 1);
|
|
|
|
if ((nullptr != st77xx) && cmd.equals(_commandTriggerCmd)) {
|
|
String arg1 = parseString(string, 2);
|
|
success = true;
|
|
|
|
if (arg1.equals(F("off"))) {
|
|
displayOnOff(false);
|
|
}
|
|
else if (arg1.equals(F("on"))) {
|
|
displayOnOff(true);
|
|
}
|
|
else if (arg1.equals(F("clear"))) {
|
|
st77xx->fillScreen(_bgcolor);
|
|
}
|
|
else if (arg1.equals(F("backlight"))) {
|
|
String arg2 = parseString(string, 3);
|
|
int nArg2;
|
|
|
|
if ((P116_CONFIG_BACKLIGHT_PIN != -1) && // All is valid?
|
|
validIntFromString(arg2, nArg2) &&
|
|
(nArg2 > 0) &&
|
|
(nArg2 <= 100)) {
|
|
P116_CONFIG_BACKLIGHT_PERCENT = nArg2; // Set but don't store
|
|
displayOnOff(true);
|
|
} else {
|
|
success = false;
|
|
}
|
|
} else {
|
|
success = false;
|
|
}
|
|
}
|
|
else if (st77xx && (cmd.equals(_commandTrigger) ||
|
|
(gfxHelper && gfxHelper->isAdaGFXTrigger(cmd)))) {
|
|
success = true;
|
|
|
|
if (!bitRead(P116_CONFIG_FLAGS, P116_CONFIG_FLAG_NO_WAKE)) { // Wake display?
|
|
displayOnOff(true);
|
|
}
|
|
|
|
if (nullptr != gfxHelper) {
|
|
String tmp = string;
|
|
|
|
// Hand it over after replacing variables
|
|
success = gfxHelper->processCommand(AdaGFXparseTemplate(tmp, _textcols, gfxHelper));
|
|
|
|
updateFontMetrics(); // Font or color may have changed
|
|
|
|
if (success) {
|
|
int16_t curX, curY;
|
|
gfxHelper->getCursorXY(curX, curY); // Get current X and Y coordinates, and put into Values
|
|
UserVar[event->BaseVarIndex] = curX;
|
|
UserVar[event->BaseVarIndex + 1] = curY;
|
|
}
|
|
}
|
|
}
|
|
return success;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* displayOnOff: Turn display on or off
|
|
***************************************************************************/
|
|
void P116_data_struct::displayOnOff(bool state) {
|
|
if (_backlightPin != -1) {
|
|
# if defined(ESP8266)
|
|
analogWrite(_backlightPin, state ? ((1024 / 100) * _backlightPercentage) : 0);
|
|
# endif // if defined(ESP8266)
|
|
# if defined(ESP32)
|
|
analogWriteESP32(_backlightPin, state ? ((1024 / 100) * _backlightPercentage) : 0, 0);
|
|
# endif // if defined(ESP32)
|
|
}
|
|
st77xx->enableDisplay(state); // Display on
|
|
_displayTimer = (state ? _displayTimeout : 0);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* registerButtonState: the button has been pressed, apply some debouncing
|
|
***************************************************************************/
|
|
void P116_data_struct::registerButtonState(uint8_t newButtonState, bool bPin3Invers) {
|
|
if ((ButtonLastState == 0xFF) || (bPin3Invers != (!!newButtonState))) {
|
|
ButtonLastState = newButtonState;
|
|
DebounceCounter++;
|
|
} else {
|
|
ButtonLastState = 0xFF; // Reset
|
|
DebounceCounter = 0;
|
|
ButtonState = false;
|
|
}
|
|
|
|
if ((ButtonLastState == newButtonState) &&
|
|
(DebounceCounter >= P116_DebounceTreshold)) {
|
|
ButtonState = true;
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* markButtonStateProcessed: reset the button state
|
|
***************************************************************************/
|
|
void P116_data_struct::markButtonStateProcessed() {
|
|
ButtonState = false;
|
|
DebounceCounter = 0;
|
|
}
|
|
|
|
#endif // ifdef USES_P116
|