diff --git a/src/_P073_7DGT.ino b/src/_P073_7DGT.ino index 8775baa2ec..f567f5a47f 100644 --- a/src/_P073_7DGT.ino +++ b/src/_P073_7DGT.ino @@ -42,6 +42,13 @@ // /** History + * 2026-08-06 tonhuisman: Move display specific code in separate derived structs from P073_data_struct, and deduplicate code where possible + * 2026-07-27 tonhuisman: Restructure plugin_struct source into separate files per supported display model for maintainability + * Some minor code optimization for 74HC595 displays + * 2026-07-25 tonhuisman: Use Arduino pin initialization as some ESPs don't properly set up their pins with DIRECT_GPIO_OUTPUT + * 2026-07-24 tonhuisman: Fix 7dn and 7dt commands for 74HC595 to show data correctly for display setups with less than 8 digits + * Improve update speed for 74HC595 by using DIRECT_GPIO library for all GPIO commands (also for TM1637 and MAX7219) + * 2026-07-21 tonhuisman: Fix wrong content displayed on 74HC595 displays (multiple fixes) * 2026-01-17 tonhuisman: Revert to using 'regular' Arduino GPIO functions for TM1637 displays on ESP8266 * 2026-01-12 tonhuisman: Fix initialization of number of digits when upgrading to 20260108 build, * formatted source with new Uncrustify config @@ -308,21 +315,28 @@ boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) case PLUGIN_INIT: { - initPluginTaskData(event->TaskIndex, new (std::nothrow) P073_data_struct()); - P073_data_struct *P073_data = - static_cast(getPluginTaskData(event->TaskIndex)); - - if (nullptr != P073_data) { - P073_data->init(event); + P073_data_struct *P073_data = nullptr; + switch (P073_CFG_DISPLAYTYPE) + { + case P073_TM1637_4DGTCOLON: + case P073_TM1637_4DGTDOTS: + case P073_TM1637_6DGT: + P073_data = new (std::nothrow) P073_TM1637(event); + break; + case P073_MAX7219_8DGT: + P073_data = new (std::nothrow) P073_MAX7219(event); + break; # if P073_USE_74HC595 - - if (P073_data->is74HC595Matrix()) { - Scheduler.setPluginTaskTimer(10, event->TaskIndex, 0); - } + case P073_74HC595_2_8DGT: + P073_data = new (std::nothrow) P073_74HC595(event); + break; # endif // if P073_USE_74HC595 + } - success = true; + if (nullptr != P073_data) { + initPluginTaskData(event->TaskIndex, P073_data); + success = P073_data->init(event); } break; } @@ -375,7 +389,7 @@ boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) success = P073_data->plugin_fifty_per_second(event); if (success) { - Scheduler.setPluginTaskTimer(0, event->TaskIndex, 0); + Scheduler.setPluginTaskTimer(5, event->TaskIndex, 0); } // success = false; // Don't send out to (not configurable) Controllers or Rules diff --git a/src/src/PluginStructs/P073_data_struct.cpp b/src/src/PluginStructs/P073_data_struct.cpp index 4f45136c21..a78e77b14c 100644 --- a/src/src/PluginStructs/P073_data_struct.cpp +++ b/src/src/PluginStructs/P073_data_struct.cpp @@ -197,7 +197,7 @@ uint8_t P073_revert7bits(uint8_t character) { return b | dpBit; // Restore dot-bit } -void P073_data_struct::init(struct EventStruct *event) +P073_data_struct::P073_data_struct(struct EventStruct *event) { ClearBuffer(); pin1 = CONFIG_PIN1; @@ -223,29 +223,10 @@ void P073_data_struct::init(struct EventStruct *event) fontset = P073_CFG_FONTSET; # endif // if P073_EXTRA_FONTS digits = P073_CFG_DIGITS; - # if P073_USE_74HC595 - if ((digits > 0) && ((digits < 4) || (5 == digits) || (7 == digits) || (9 == digits) || (10 == digits) || (11 == digits))) { - isSequential = true; - - if (1 == digits) { // 2+2 - digits = 4; - } else - if (9 == digits) { // 4 sequential - digits = 4; - } else - if (10 == digits) { // 4+4 sequential - digits = 8; - } else - if (7 == digits) { // 3+3 - digits = 6; - } else - if (11 == digits) { // 3+4/4+3 sequential - digits = 7; - } - } - # endif // if P073_USE_74HC595 +} +bool P073_data_struct::init(struct EventStruct *event) { if (0 == digits) { digits = P073_getDefaultDigits(P073_CFG_DISPLAYTYPE); } @@ -255,183 +236,12 @@ void P073_data_struct::init(struct EventStruct *event) } if (loglevelActiveFor(LOG_LEVEL_INFO)) { - addLog(LOG_LEVEL_INFO, strformat(F("P073 : Digits: %d, model: %d, pins: %d, %d, %d"), digits, displayModel, pin1, pin2, pin3)); - } - - switch (displayModel) - { - case P073_TM1637_4DGTCOLON: - case P073_TM1637_4DGTDOTS: - case P073_TM1637_6DGT: - tm1637_InitDisplay(); - tm1637_SetPowerBrightness(brightness / 2, true); - - if (output == P073_DISP_MANUAL) { - tm1637_ClearDisplay(); - } - break; - case P073_MAX7219_8DGT: - max7219_InitDisplay(); - delay(10); // small poweroff/poweron delay - max7219_SetPowerBrightness(brightness, true); - - if (output == P073_DISP_MANUAL) { - max7219_ClearDisplay(); - } - break; - # if P073_USE_74HC595 - case P073_74HC595_2_8DGT: - hc595_InitDisplay(); - - if (output == P073_DISP_MANUAL) { - ClearBuffer(); - hc595_ToOutputBuffer(); - - if (hc595_Sequential()) { // Sequential displays don't need continuous refreshing - hc595_ShowBuffer(); - } - } - break; - # endif // if P073_USE_74HC595 - } -} - -# if P073_USE_74HC595 - -bool P073_data_struct::plugin_fifty_per_second(struct EventStruct *event) { - # ifdef P073_DEBUG - counter50++; - # endif // ifdef P073_DEBUG - - if (P073_74HC595_2_8DGT == displayModel) { - if (P073_HC595_MULTIPLEX) { - hc595_ShowBuffer(); - } - return true; + addLog(LOG_LEVEL_INFO, strformat(F("P073 : Digits: %d, model: %d, output: %d, pins: %d, %d, %d"), + digits, displayModel, output, pin1, pin2, pin3)); } - return false; -} - -bool P073_data_struct::is74HC595Matrix() { return P073_74HC595_2_8DGT == displayModel && P073_HC595_MULTIPLEX; } - -// ==================================== -// ---- 74HC595 specific functions ---- -// ==================================== - -void P073_data_struct::hc595_ShowBuffer() { - # if P073_USE_74HCMULTIPLEX - const uint8_t hc595digit4[] = { - 0b00001000, // left segment - 0b00000100, - 0b00000010, - 0b00000001, // right segment - }; - - const uint8_t hc595digit8[] = { - 0b00010000, // left segment - 0b00100000, - 0b01000000, - 0b10000000, - 0b00000001, - 0b00000010, - 0b00000100, - 0b00001000, // right segment - }; - # endif // if P073_USE_74HCMULTIPLEX - - int8_t i = digits - 1; - int8_t stop = -1; - int8_t incr = -1; - - # if P073_USE_74HCMULTIPLEX - - if (P073_HC595_MULTIPLEX) { - i = dspDgt; - stop = dspDgt + 1; - incr = 1; - } - # endif // if P073_USE_74HCMULTIPLEX - - for (; i != stop && i >= 0; i += incr) { - shiftOut(pin1, pin2, MSBFIRST, outputbuffer[i]); // Digit data out - - // 2, 3 and some 4 digit modules use sequential digit values (in reversed order) - // 4, 6 and 8 digit modules use multiplexing in LTR order - # if P073_USE_74HCMULTIPLEX - uint8_t digit = 0xFF; - - if (P073_HC595_MULTIPLEX) { - if (4 == digits) { - digit = hc595digit4[i]; - } else - if (6 == digits) { - digit = hc595digit8[i + (i > 2 ? 1 : 0)]; - } else - if (8 == digits) { - digit = hc595digit8[i]; - } - } - - if (digit != 0xFF) { // Select multiplexer digit, 0xFF is invalid - shiftOut(pin1, pin2, MSBFIRST, digit); - } - # endif // if P073_USE_74HCMULTIPLEX - - if ((P073_HC595_SEQUENTIAL && (0 == i)) || P073_HC595_MULTIPLEX) { - digitalWrite(pin3, LOW); // Clock data - digitalWrite(pin3, HIGH); - } - } - - if (i >= digits) { - dspDgt = 0; - } else { - dspDgt = i; - } - - # ifdef P073_DEBUG - - // TODO disable log - // if ((counter50 % 200 == 0) || P073_HC595_SEQUENTIAL) { - // addLog(LOG_LEVEL_INFO, strformat(F("P073: hc595_ShowBuffer (end) dgt:%d i:%d stop:%d incr:%d pin1: %d pin2: %d pin3: %d"), - // digits, i, stop, incr, pin1, pin2, pin3)); - // } - # endif // ifdef P073_DEBUG -} - -void P073_data_struct::hc595_ToOutputBuffer() { - for (uint8_t i = 0; i < 8; ++i) { - uint8_t value; - - // 74HC595 uses inverted data, compared to MAX7219/TM1637 - value = ~P073_getFontChar(showbuffer[i], fontset); - - if (showperiods[i]) { - value &= 0x7F; - } - outputbuffer[i] = P073_revert7bits(value); // Rotate bits 6..0 - } -} - -void P073_data_struct::hc595_AdjustBuffer() { - if (digits < 8) { - const uint8_t delta = 8 - digits; - - for (uint8_t i = 0; i < digits; ++i) { - showbuffer[i] = showbuffer[i + delta]; - } - } -} - -void P073_data_struct::hc595_InitDisplay() { - pinMode(pin1, OUTPUT); - pinMode(pin2, OUTPUT); - pinMode(pin3, OUTPUT); - digitalWrite(pin3, HIGH); + return true; } -# endif // if P073_USE_74HC595 - void P073_data_struct::FillBufferWithTime(bool sevendgt_now, uint8_t sevendgt_hours, uint8_t sevendgt_minutes, @@ -518,13 +328,11 @@ void P073_data_struct::FillBufferWithNumber(const String& number) { } int8_t p073_index = 7; - dotpos = -1; // -1 means no dot to display - for (int i = number.length() - 1; i >= 0 && p073_index >= 0; --i) { const char p073_tmpchar = number.charAt(i); if (p073_tmpchar == '.') { // dot - dotpos = p073_index; + showperiods[p073_index] = true; } else { showbuffer[p073_index] = P073_mapCharToFontPosition(p073_tmpchar, fontset); p073_index--; @@ -541,9 +349,9 @@ void P073_data_struct::FillBufferWithTemp(int temperature) { String format; if (hideDegree) { - format = (between10and0 ? F(" %02d") : (between0andMinus10 ? F(" %03d") : F("%8d"))); + format = (between10and0 ? F(" %03d") : (between0andMinus10 ? F(" %04d") : F("%8d"))); } else { - format = (between10and0 ? F(" %02d") : (between0andMinus10 ? F(" %03d") : F("%7d"))); + format = (between10and0 ? F(" %03d") : (between0andMinus10 ? F(" %04d") : F("%7d"))); } sprintf_P(p073_digit, format.c_str(), temperature); const size_t p073_numlenght = strlen(p073_digit); @@ -561,7 +369,7 @@ void P073_data_struct::FillBufferWithTemp(int temperature) { /** * FillBufferWithDualTemp() - * leftTemperature or rightTempareature < -100.0 then shows dashes + * leftTemperature or rightTemperature < -100.0 then shows dashes */ void P073_data_struct::FillBufferWithDualTemp(int leftTemperature, bool leftWithDecimal, @@ -637,7 +445,6 @@ void P073_data_struct::FillBufferWithString(const String& textToShow, showperiods[p] = true; p++; } else { - // if (p > 0) { showperiods[p - 1] = true; // The period displays as a dot on the previous digit! } @@ -837,10 +644,7 @@ void P073_data_struct::ClearBuffer() { } } -uint8_t P073_data_struct::tm1637_getFontChar(uint8_t index, - uint8_t fontset) { return P073_revert7bits(P073_getFontChar(index, fontset)); } - -bool P073_data_struct::plugin_once_a_second(struct EventStruct *event) { +bool P073_data_struct::plugin_once_a_second(struct EventStruct *event) { if (output == P073_DISP_MANUAL) { return false; } @@ -880,38 +684,13 @@ bool P073_data_struct::plugin_once_a_second(struct EventStruct *event) { } # endif // if P073_BLINK_DOT - switch (displayModel) - { - case P073_TM1637_4DGTCOLON: - case P073_TM1637_4DGTDOTS: - tm1637_ShowTimeTemp4(timesep, 0); - break; - case P073_TM1637_6DGT: - - if (P073_CFG_OUTPUTTYPE == P073_DISP_DATE) { - tm1637_ShowDate6(); - } else { - tm1637_ShowTime6(); - } - break; - case P073_MAX7219_8DGT: - - if (P073_CFG_OUTPUTTYPE == P073_DISP_DATE) { - max7219_ShowDate(); - } else { - max7219_ShowTime(timesep); - } - break; - # if P073_USE_74HC595 - case P073_74HC595_2_8DGT: - hc595_AdjustBuffer(); - hc595_ToOutputBuffer(); + if (P073_CFG_OUTPUTTYPE == P073_DISP_DATE) { + showDate(); + } else { + showperiods[1] = timesep; - if (hc595_Sequential()) { // Sequential displays don't need continuous refreshing - hc595_ShowBuffer(); - } - break; - # endif // if P073_USE_74HC595 + if (digits > 4) { showperiods[3] = timesep; } + showTime(timesep); } return true; } @@ -924,52 +703,29 @@ bool P073_data_struct::plugin_ten_per_second(struct EventStruct *event) { } if (NextScroll()) { - switch (displayModel) - { - case P073_TM1637_4DGTCOLON: - case P073_TM1637_4DGTDOTS: - { - tm1637_ShowBuffer(0, 4 - # if P073_7DBIN_COMMAND - , binaryData - # endif // if P073_7DBIN_COMMAND - ); - break; - } - case P073_TM1637_6DGT: - { - tm1637_SwapDigitInBuffer(0); // only needed for 6-digits displays - tm1637_ShowBuffer(0, 6 - # if P073_7DBIN_COMMAND - , binaryData - # endif // if P073_7DBIN_COMMAND - ); - break; - } - case P073_MAX7219_8DGT: - { - dotpos = -1; // avoid to display the dot - max7219_ShowBuffer(); - break; - } - # if P073_USE_74HC595 - case P073_74HC595_2_8DGT: - { - hc595_ToOutputBuffer(); - - if (hc595_Sequential()) { // Sequential displays don't need continuous refreshing - hc595_ShowBuffer(); - } - break; - } - # endif // if P073_USE_74HC595 - } + toOutputBuffer(); } return true; } # endif // if P073_SCROLL_TEXT +# if P073_USE_74HC595 + +bool P073_data_struct::plugin_fifty_per_second(struct EventStruct *event) { + # ifdef P073_DEBUG + counter50++; + # endif // ifdef P073_DEBUG + + if (is74HC595Multiplex()) { + showBuffer(); // Redisplay current buffer content + return true; + } + return false; +} + +# endif // if P073_USE_74HC595 + const char p073_commands[] PROGMEM = "7dn|7dt|" # if P073_7DDT_COMMAND @@ -1129,22 +885,7 @@ bool P073_data_struct::plugin_write(struct EventStruct *event, setScrollEnabled(newScroll); # endif // if P073_SCROLL_TEXT - switch (displayModel) - { - case P073_TM1637_4DGTCOLON: - case P073_TM1637_4DGTDOTS: - case P073_TM1637_6DGT: - tm1637_SetPowerBrightness(brightness / 2, displayon); - break; - case P073_MAX7219_8DGT: - max7219_SetPowerBrightness(brightness, displayon); - break; - # if P073_USE_74HC595 - case P073_74HC595_2_8DGT: - // 74HC595 don't have a brightness setting - break; - # endif // if P073_USE_74HC595 - } + setPowerBrightness(brightness, displayon); } return success; } @@ -1187,36 +928,13 @@ bool P073_data_struct::plugin_write_7dn(struct EventStruct *event, if (!text.isEmpty()) { if ((event->Par1 > lLimit) && (event->Par1 < uLimit)) { - FillBufferWithNumber(text.c_str()); + FillBufferWithNumber(text); } else { FillBufferWithDash(); } } - switch (displayModel) - { - case P073_TM1637_4DGTCOLON: - case P073_TM1637_4DGTDOTS: - tm1637_ShowBuffer(TM1637_4DIGIT, 8); - break; - case P073_TM1637_6DGT: - tm1637_SwapDigitInBuffer(2); // only needed for 6-digits displays - tm1637_ShowBuffer(TM1637_6DIGIT, 8); - break; - case P073_MAX7219_8DGT: - max7219_ShowBuffer(); - break; - # if P073_USE_74HC595 - case P073_74HC595_2_8DGT: - hc595_AdjustBuffer(); - hc595_ToOutputBuffer(); - - if (hc595_Sequential()) { // Sequential displays don't need continuous refreshing - hc595_ShowBuffer(); - } - break; - # endif // if P073_USE_74HC595 - } + showNumber(); return true; } @@ -1225,8 +943,8 @@ bool P073_data_struct::plugin_write_7dt(const String& text) { return false; } - float p073_temptemp = 0; - bool p073_tempflagdot = false; + float p073_temptemp{}; + int8_t p073_tempflagdot = -1; if (!text.isEmpty()) { validFloatFromString(text, p073_temptemp); @@ -1256,45 +974,37 @@ bool P073_data_struct::plugin_write_7dt(const String& text) { } else { if ((p073_temptemp < uLimitDec) && (p073_temptemp > lLimitDec)) { p073_temptemp = roundf(p073_temptemp * 10.0f); - p073_tempflagdot = true; + p073_tempflagdot = digits - (hideDegree ? 2 : 3); } FillBufferWithTemp(p073_temptemp); } + # ifdef P073_DEBUG + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + addLogMove(LOG_LEVEL_INFO, strformat(F("7DGT : 7dt preprocessed = %.1f dec: %d"), p073_temptemp, p073_tempflagdot)); + } + # endif // ifdef P073_DEBUG + switch (displayModel) { case P073_TM1637_4DGTCOLON: case P073_TM1637_4DGTDOTS: case P073_TM1637_6DGT: - if ((p073_temptemp == 0) && p073_tempflagdot) { + if (essentiallyZero(p073_temptemp) && (p073_tempflagdot > -1)) { // FIXME showbuffer[5] = 0; } - if (P073_TM1637_6DGT == displayModel) { - tm1637_ShowTemp6(p073_tempflagdot); - } else { - tm1637_ShowTimeTemp4(p073_tempflagdot, 4); - } + showTemperature(p073_tempflagdot, -1); + break; case P073_MAX7219_8DGT: - # ifdef P073_DEBUG - - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - addLogMove(LOG_LEVEL_INFO, concat(F("7DGT : 7dt preprocessed ="), p073_temptemp)); - } - # endif // ifdef P073_DEBUG - - max7219_ShowTemp(hideDegree ? 6 : 5, -1); + showTemperature(hideDegree ? 6 : 5, -1); break; # if P073_USE_74HC595 case P073_74HC595_2_8DGT: - hc595_AdjustBuffer(); - hc595_ToOutputBuffer(); - - if (hc595_Sequential()) { // Sequential displays don't need continuous refreshing - hc595_ShowBuffer(); - } + showTemperature(p073_tempflagdot, -1); break; # endif // if P073_USE_74HC595 } @@ -1311,9 +1021,8 @@ bool P073_data_struct::plugin_write_7ddt(const String& text) { return false; } - float p073_lefttemp = 0.0f; - float p073_righttemp = 0.0f; - bool p073_tempflagdot = false; + float p073_lefttemp = 0.0f; + float p073_righttemp = 0.0f; if (!text.isEmpty()) { validFloatFromString(parseString(text, 1), p073_lefttemp); @@ -1338,11 +1047,7 @@ bool P073_data_struct::plugin_write_7ddt(const String& text) { { FillBufferWithDash(); - if (displayModel == P073_TM1637_6DGT) { - tm1637_ShowTemp6(p073_tempflagdot); - } else { - tm1637_ShowTimeTemp4(p073_tempflagdot, 4); - } + showTemperature(-1, -1); break; } case P073_MAX7219_8DGT: @@ -1383,22 +1088,18 @@ bool P073_data_struct::plugin_write_7ddt(const String& text) { bool alignSave = rightAlignTempMAX7219; // Save setting rightAlignTempMAX7219 = true; - max7219_ShowTemp(firstDot, secondDot); + showTemperature(firstDot, secondDot); rightAlignTempMAX7219 = alignSave; // Restore # if P073_USE_74HC595 } else - // if (P073_74HC595_2_8DGT == P073_data->displayModel) { if (digits < 8) { FillBufferWithDash(); } - hc595_ToOutputBuffer(); - if (hc595_Sequential()) { // Sequential displays don't need continuous refreshing - hc595_ShowBuffer(); - } + toOutputBuffer(); # endif // if P073_USE_74HC595 } @@ -1433,29 +1134,7 @@ bool P073_data_struct::plugin_write_7dst(struct EventStruct *event) { # endif // if P073_SUPPRESS_ZERO ); - switch (displayModel) - { - case P073_TM1637_4DGTCOLON: - case P073_TM1637_4DGTDOTS: - tm1637_ShowTimeTemp4(timesep, 0); - break; - case P073_TM1637_6DGT: - tm1637_ShowTime6(); - break; - case P073_MAX7219_8DGT: - max7219_ShowTime(timesep); - break; - # if P073_USE_74HC595 - case P073_74HC595_2_8DGT: - hc595_AdjustBuffer(); - hc595_ToOutputBuffer(); - - if (hc595_Sequential()) { // Sequential displays don't need continuous refreshing - hc595_ShowBuffer(); - } - break; - # endif // if P073_USE_74HC595 - } + showTime(timesep); return true; } @@ -1478,29 +1157,7 @@ bool P073_data_struct::plugin_write_7dsd(struct EventStruct *event) { # endif // if P073_SUPPRESS_ZERO ); - switch (displayModel) - { - case P073_TM1637_4DGTCOLON: - case P073_TM1637_4DGTDOTS: - tm1637_ShowTimeTemp4(timesep, 0); - break; - case P073_TM1637_6DGT: - tm1637_ShowDate6(); - break; - case P073_MAX7219_8DGT: - max7219_ShowDate(); - break; - # if P073_USE_74HC595 - case P073_74HC595_2_8DGT: - hc595_AdjustBuffer(); - hc595_ToOutputBuffer(); - - if (hc595_Sequential()) { // Sequential displays don't need continuous refreshing - hc595_ShowBuffer(); - } - break; - # endif // if P073_USE_74HC595 - } + showDate(); return true; } @@ -1526,30 +1183,7 @@ bool P073_data_struct::plugin_write_7dtext(const String& text) { { FillBufferWithString(text); - switch (displayModel) - { - case P073_TM1637_4DGTCOLON: - case P073_TM1637_4DGTDOTS: - tm1637_ShowBuffer(0, 4); - break; - case P073_TM1637_6DGT: - tm1637_SwapDigitInBuffer(0); // only needed for 6-digits displays - tm1637_ShowBuffer(0, 6); - break; - case P073_MAX7219_8DGT: - dotpos = -1; // avoid to display the dot - max7219_ShowBuffer(); - break; - # if P073_USE_74HC595 - case P073_74HC595_2_8DGT: - hc595_ToOutputBuffer(); - - if (hc595_Sequential()) { // Sequential displays don't need continuous refreshing - hc595_ShowBuffer(); - } - break; - # endif // if P073_USE_74HC595 - } + toOutputBuffer(); } return true; } @@ -1611,30 +1245,7 @@ bool P073_data_struct::plugin_write_7dbin(const String& text) { { FillBufferWithString(data, true); - switch (displayModel) - { - case P073_TM1637_4DGTCOLON: - case P073_TM1637_4DGTDOTS: - tm1637_ShowBuffer(0, 4); - break; - case P073_TM1637_6DGT: - tm1637_SwapDigitInBuffer(0); // only needed for 6-digits displays - tm1637_ShowBuffer(0, 6, true); - break; - case P073_MAX7219_8DGT: - dotpos = -1; // avoid to display the dot - max7219_ShowBuffer(); - break; - # if P073_USE_74HC595 - case P073_74HC595_2_8DGT: - hc595_ToOutputBuffer(); - - if (hc595_Sequential()) { // Sequential displays don't need continuous refreshing - hc595_ShowBuffer(); - } - break; - # endif // if P073_USE_74HC595 - } + toOutputBuffer(); } return true; } @@ -1644,381 +1255,32 @@ bool P073_data_struct::plugin_write_7dbin(const String& text) { # endif // if P073_7DBIN_COMMAND -// =================================== -// ---- TM1637 specific functions ---- -// =================================== - -# define CLK_HIGH() DIRECT_pinWrite(this->pin1, HIGH) -# define CLK_LOW() DIRECT_pinWrite(this->pin1, LOW) -# define DIO_HIGH() DIRECT_pinWrite(this->pin2, HIGH) -# define DIO_LOW() DIRECT_PINMODE_OUTPUT(this->pin2); DIRECT_pinWrite(this->pin2, LOW) -# define DIO_INPUT() DIRECT_PINMODE_INPUT(this->pin2) -# define DIO_OUTPUT() DIRECT_PINMODE_OUTPUT(this->pin2) - -void P073_data_struct::tm1637_i2cStart() { - # if defined(P073_DEBUG) && !defined(BUILD_NO_DEBUG) - addLog(LOG_LEVEL_DEBUG, F("7DGT : Comm Start")); - # endif // if defined(P073_DEBUG) && !defined(BUILD_NO_DEBUG) - DIO_LOW(); - delayMicroseconds(TM1637_CLOCKDELAY); -} - -void P073_data_struct::tm1637_i2cStop() { - # if defined(P073_DEBUG) && !defined(BUILD_NO_DEBUG) - addLog(LOG_LEVEL_DEBUG, F("7DGT : Comm Stop")); - # endif // if defined(P073_DEBUG) && !defined(BUILD_NO_DEBUG) - DIO_LOW(); - delayMicroseconds(TM1637_CLOCKDELAY); - CLK_HIGH(); - delayMicroseconds(TM1637_CLOCKDELAY); - DIO_HIGH(); - delayMicroseconds(TM1637_CLOCKDELAY); -} - -bool P073_data_struct::tm1637_i2cAck() { - CLK_LOW(); - DIO_INPUT(); - - delayMicroseconds(TM1637_CLOCKDELAY); - CLK_HIGH(); - const uint32_t start_wait = micros(); - - const bool acknowledged = -1 != - DIRECT_measureWaitForPinState_ISR(this->pin2, start_wait, TM1637_CLOCKDELAY, 0); - - const int32_t timePassed = usecPassedSince_fast(start_wait); - - if (timePassed < TM1637_CLOCKDELAY) { - delayMicroseconds(TM1637_CLOCKDELAY - timePassed); - } - - # if defined(P073_DEBUG) && !defined(BUILD_NO_DEBUG) - - if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { - String log = F("7DGT : Comm ACK="); - - if (acknowledged) { - log += F("TRUE"); - } else { - log += F("FALSE"); - } - addLogMove(LOG_LEVEL_DEBUG, log); - } - # endif // if defined(P073_DEBUG) && !defined(BUILD_NO_DEBUG) - CLK_HIGH(); - - delayMicroseconds(TM1637_CLOCKDELAY); - CLK_LOW(); - delayMicroseconds(TM1637_CLOCKDELAY); - DIO_OUTPUT(); - - return acknowledged; -} - -void P073_data_struct::tm1637_i2cWrite_ack(uint8_t bytesToPrint[], - uint8_t length) { - # ifdef P073_DEBUG - - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - addLog(LOG_LEVEL_INFO, concat(F("7DGT : TM1637 databuffer: 0x"), formatToHex_array(bytesToPrint, length))); - } - # endif // ifdef P073_DEBUG - tm1637_i2cStart(); - - for (uint8_t i = 0; i < length; ++i) { - tm1637_i2cWriteByte_ack(bytesToPrint[i]); - } - tm1637_i2cStop(); -} - -void P073_data_struct::tm1637_i2cWriteByte_ack(uint8_t bytetoprint) { - tm1637_i2cWrite(bytetoprint); - tm1637_i2cAck(); -} - -void P073_data_struct::tm1637_i2cWrite(uint8_t bytetoprint) { - # if defined(P073_DEBUG) && !defined(BUILD_NO_DEBUG) - addLog(LOG_LEVEL_DEBUG, F("7DGT : WriteByte")); - # endif // if defined(P073_DEBUG) && !defined(BUILD_NO_DEBUG) - - for (uint8_t i = 0; i < 8; ++i) { - CLK_LOW(); - delayMicroseconds(TM1637_CLOCKDELAY >> 1); - - if (bytetoprint & 0b00000001) { - DIO_HIGH(); - } else { - DIO_LOW(); - } - delayMicroseconds(TM1637_CLOCKDELAY >> 1); - bytetoprint = bytetoprint >> 1; - CLK_HIGH(); - delayMicroseconds(TM1637_CLOCKDELAY); - } -} - -void P073_data_struct::tm1637_ClearDisplay() { - uint8_t bytesToPrint[7]{}; - - bytesToPrint[0] = 0xC0; - tm1637_i2cWrite_ack(bytesToPrint, 7); -} - -void P073_data_struct::tm1637_SetPowerBrightness(uint8_t brightlvl, - bool poweron) { - # ifdef P073_DEBUG - addLog(LOG_LEVEL_INFO, F("7DGT : Set BRIGHT")); - # endif // ifdef P073_DEBUG - brightlvl &= 0b111; - - if (poweron) { - brightlvl |= TM1637_POWER_ON; - } else { - brightlvl |= TM1637_POWER_OFF; - } - - uint8_t bytesToPrint[]{ brightlvl }; - tm1637_i2cWrite_ack(bytesToPrint, NR_ELEMENTS(bytesToPrint)); -} - -void P073_data_struct::tm1637_InitDisplay() { - pinMode(this->pin1, OUTPUT); - pinMode(this->pin2, OUTPUT); - - digitalWrite(this->pin1, HIGH); - digitalWrite(this->pin2, HIGH); - - delayMicroseconds(TM1637_CLOCKDELAY); - uint8_t bytesToPrint[]{ 0x40 }; - tm1637_i2cWrite_ack(bytesToPrint, NR_ELEMENTS(bytesToPrint)); - tm1637_ClearDisplay(); -} - -uint8_t P073_data_struct::tm1637_separator(uint8_t value, - bool sep) { - if (sep) { - value |= 0b10000000; - } - return value; -} - -void P073_data_struct::tm1637_ShowTime6() { - tm1637_ShowDate6(true); // deduplicated -} - -void P073_data_struct::tm1637_ShowDate6(bool showTime) { - uint8_t bytesToPrint[7]{}; - - bytesToPrint[0] = 0xC0; - bytesToPrint[1] = tm1637_getFontChar(showbuffer[2], fontset); - bytesToPrint[2] = tm1637_separator(tm1637_getFontChar(showbuffer[1], fontset), timesep); - bytesToPrint[3] = tm1637_getFontChar(showbuffer[0], fontset); - - if (showTime) { - bytesToPrint[4] = tm1637_getFontChar(showbuffer[5], fontset); - bytesToPrint[5] = tm1637_getFontChar(showbuffer[4], fontset); - } else { - bytesToPrint[4] = tm1637_getFontChar(showbuffer[7], fontset); - bytesToPrint[5] = tm1637_getFontChar(showbuffer[6], fontset); - } - bytesToPrint[6] = tm1637_separator(tm1637_getFontChar(showbuffer[3], fontset), timesep); - - tm1637_i2cWrite_ack(bytesToPrint, 7); -} - -void P073_data_struct::tm1637_ShowTemp6(bool sep) { - uint8_t bytesToPrint[7]{}; - - bytesToPrint[0] = 0xC0; - bytesToPrint[1] = tm1637_separator(tm1637_getFontChar(showbuffer[5], fontset), sep); - bytesToPrint[2] = tm1637_getFontChar(showbuffer[4], fontset); - bytesToPrint[3] = tm1637_getFontChar(10, fontset); - bytesToPrint[4] = tm1637_getFontChar(10, fontset); - bytesToPrint[5] = tm1637_getFontChar(showbuffer[7], fontset); - bytesToPrint[6] = tm1637_getFontChar(showbuffer[6], fontset); - - tm1637_i2cWrite_ack(bytesToPrint, 7); -} - -void P073_data_struct::tm1637_ShowTimeTemp4(bool sep, - uint8_t bufoffset) { - uint8_t bytesToPrint[5]{}; - - bytesToPrint[0] = 0xC0; - bytesToPrint[1] = tm1637_getFontChar(showbuffer[0 + bufoffset], fontset); - bytesToPrint[2] = tm1637_separator(tm1637_getFontChar(showbuffer[1 + bufoffset], fontset), sep); - bytesToPrint[3] = tm1637_getFontChar(showbuffer[2 + bufoffset], fontset); - bytesToPrint[4] = tm1637_getFontChar(showbuffer[3 + bufoffset], fontset); - - tm1637_i2cWrite_ack(bytesToPrint, 5); -} - -void P073_data_struct::tm1637_SwapDigitInBuffer(uint8_t startPos) { - std::swap(showbuffer[2 + startPos], showbuffer[0 + startPos]); - std::swap(showbuffer[3 + startPos], showbuffer[5 + startPos]); - - std::swap(showperiods[2 + startPos], showperiods[0 + startPos]); - std::swap(showperiods[3 + startPos], showperiods[5 + startPos]); - - if (dotpos > -1) { - const uint8_t dotPositionSwap[] = { 0, 1, 4, 3, 2, 7, 6, 5, 8 }; - - dotpos = dotPositionSwap[dotpos]; - } -} - -void P073_data_struct::tm1637_ShowBuffer(uint8_t firstPos, - uint8_t lastPos, - bool useBinaryData) { - uint8_t bytesToPrint[8]{}; - - bytesToPrint[0] = 0xC0; - uint8_t length = 1; - - if (dotpos > -1) { - showperiods[dotpos] = true; - } - - uint8_t p073_datashowpos1; - - for (int i = firstPos; i < lastPos; ++i) { - if (useBinaryData) { - bytesToPrint[length] = showbuffer[i]; +// Borrowed from wiring_shift.c, using DIRECT_GPIO +void P073_data_struct::DIRECT_shiftOut(uint8_t dataPin, + uint8_t clockPin, + uint8_t bitOrder, + uint8_t val) { + for (uint8_t i = 0; i < 8; i++) { + if (bitOrder == LSBFIRST) { + DIRECT_pinWrite(dataPin, !!(val & (1 << i))); } else { - p073_datashowpos1 = tm1637_separator( - tm1637_getFontChar(showbuffer[i], fontset), - showperiods[i]); - bytesToPrint[length] = p073_datashowpos1; + DIRECT_pinWrite(dataPin, !!(val & (1 << (7 - i)))); } - length++; - } - # ifdef P073_DEBUG - addLog(LOG_LEVEL_INFO, strformat(F("TM1673: Write bytes: %d buffer %d to %d"), length, firstPos, lastPos)); - # endif // ifdef P073_DEBUG - tm1637_i2cWrite_ack(bytesToPrint, length); -} - -// ==================================== -// ---- MAX7219 specific functions ---- -// ==================================== - -# define OP_DECODEMODE 9 -# define OP_INTENSITY 10 -# define OP_SCANLIMIT 11 -# define OP_SHUTDOWN 12 -# define OP_DISPLAYTEST 15 - -void P073_data_struct::max7219_spiTransfer(ESPEASY_VOLATILE(uint8_t) opcode, - ESPEASY_VOLATILE(uint8_t) data) { - spidata[1] = opcode; - spidata[0] = data; - digitalWrite(pin3, LOW); - shiftOut(pin1, pin2, MSBFIRST, spidata[1]); - shiftOut(pin1, pin2, MSBFIRST, spidata[0]); - digitalWrite(pin3, HIGH); -} - -void P073_data_struct::max7219_ClearDisplay() { - for (int i = 0; i < 8; i++) { - max7219_spiTransfer(i + 1, 0); - } -} - -void P073_data_struct::max7219_SetPowerBrightness(uint8_t brightlvl, - bool poweron) { - max7219_spiTransfer(OP_INTENSITY, brightlvl); - max7219_spiTransfer(OP_SHUTDOWN, poweron ? 1 : 0); -} - -void P073_data_struct::max7219_SetDigit(int dgtpos, - uint8_t dgtvalue, - bool showdot, - bool binaryData) { - uint8_t p073_tempvalue; - if (binaryData) { - p073_tempvalue = dgtvalue; // Overwrite if binary data - } else - { - p073_tempvalue = P073_getFontChar(dgtvalue, fontset); - - if (showdot) { - p073_tempvalue |= 0b10000000; - } + DIRECT_pinWrite(clockPin, HIGH); + DIRECT_pinWrite(clockPin, LOW); } - max7219_spiTransfer(dgtpos + 1, p073_tempvalue); -} - -void P073_data_struct::max7219_InitDisplay() { - pinMode(pin1, OUTPUT); - pinMode(pin2, OUTPUT); - pinMode(pin3, OUTPUT); - digitalWrite(pin3, HIGH); - max7219_spiTransfer(OP_DISPLAYTEST, 0); - max7219_spiTransfer(OP_SCANLIMIT, 7); // scanlimit setup to max at Init - max7219_spiTransfer(OP_DECODEMODE, 0); - max7219_ClearDisplay(); - max7219_SetPowerBrightness(0, false); } -void P073_data_struct::max7219_ShowTime(bool sep) { - const uint8_t idx_list[] = { 7, 6, 4, 3, 1, 0 }; // Digits in reversed order, as the loop is backward - - for (int8_t i = 5; i >= 0; --i) { - max7219_SetDigit(idx_list[i], showbuffer[i], false); - } - - const uint8_t sepChar = P073_mapCharToFontPosition(sep ? '-' : ' ', fontset); - - max7219_SetDigit(2, sepChar, false); - max7219_SetDigit(5, sepChar, false); -} - -void P073_data_struct::max7219_ShowTemp(int8_t firstDot, - int8_t secondDot) { - max7219_SetDigit(0, 10, false); - - if (firstDot > -1) { showperiods[firstDot] = true; } - - if (secondDot > -1) { showperiods[secondDot] = true; } - - const int alignRight = rightAlignTempMAX7219 ? 0 : 1; - - for (int i = alignRight; i < 8; ++i) { - const int bufIndex = (7 + alignRight) - i; +void P073_data_struct::shiftinView() { + if (digits < 8) { + uint8_t n = 0; - if (bufIndex < 8) { - max7219_SetDigit(i, - showbuffer[bufIndex], - showperiods[bufIndex]); + for (uint8_t i = 8 - digits; i < 8; ++i, ++n) { + showbuffer[n] = showbuffer[i]; + showperiods[n] = showperiods[i]; } } } -void P073_data_struct::max7219_ShowDate() { - const uint8_t dotflags[8] = { false, true, false, true, false, false, false, false }; - - for (int i = 0; i < 8; ++i) { - max7219_SetDigit(i, - showbuffer[7 - i], - dotflags[7 - i]); - } -} - -void P073_data_struct::max7219_ShowBuffer() { - if (dotpos > -1) { - showperiods[dotpos] = true; - } - - for (int i = 0; i < 8; i++) { - max7219_SetDigit(i, - showbuffer[7 - i], - showperiods[7 - i] - # if P073_7DBIN_COMMAND - , binaryData - # endif // if P073_7DBIN_COMMAND - ); - } -} - #endif // ifdef USES_P073 diff --git a/src/src/PluginStructs/P073_data_struct.h b/src/src/PluginStructs/P073_data_struct.h index 97bbbdba0d..1303e6cfaf 100644 --- a/src/src/PluginStructs/P073_data_struct.h +++ b/src/src/PluginStructs/P073_data_struct.h @@ -105,7 +105,7 @@ # define TM1637_POWER_ON 0b10001000 # define TM1637_POWER_OFF 0b10000000 -# define TM1637_CLOCKDELAY 10 // FIXME TD-er: Maybe lower this as we can get as low as 2 usec to remain below the max 250 kHz +# define TM1637_CLOCKDELAY 10 // FIXME TD-er: Maybe lower this as we can get as low as 2 usec to remain below the max 250 kHz # define TM1637_4DIGIT 4 # define TM1637_6DIGIT 2 @@ -225,20 +225,21 @@ uint8_t P073_revert7bits(uint8_t character); struct P073_data_struct : public PluginTaskData_base { public: - P073_data_struct() = default; + P073_data_struct() = delete; + P073_data_struct(struct EventStruct *event); virtual ~P073_data_struct() = default; - void init(struct EventStruct *event); - bool plugin_write(struct EventStruct *event, - const String & string); - bool plugin_once_a_second(struct EventStruct *event); + virtual bool init(struct EventStruct *event); + bool plugin_write(struct EventStruct *event, + const String & string); + bool plugin_once_a_second(struct EventStruct *event); # if P073_SCROLL_TEXT - bool plugin_ten_per_second(struct EventStruct *event); + bool plugin_ten_per_second(struct EventStruct *event); # endif // if P073_SCROLL_TEXT # if P073_USE_74HC595 bool plugin_fifty_per_second(struct EventStruct *event); - bool is74HC595Matrix(); + bool is74HC595Multiplex(); # endif // if P073_USE_74HC595 void FillBufferWithTime(bool sevendgt_now, uint8_t sevendgt_hours, @@ -268,32 +269,46 @@ struct P073_data_struct : public PluginTaskData_base { int rightTemperature, bool rightWithDecimal); # endif // if P073_7DDT_COMMAND - void FillBufferWithString(const String& textToShow, - bool useBinaryData = false); + void FillBufferWithString(const String& textToShow, + bool useBinaryData = false); # if P073_SCROLL_TEXT - int getEffectiveTextLength(const String& text); - bool NextScroll(); - void setTextToScroll(const String& text); - void setScrollSpeed(uint8_t speed); - bool isScrollEnabled(); - void setScrollEnabled(bool scroll); + int getEffectiveTextLength(const String& text); + bool NextScroll(); + void setTextToScroll(const String& text); + void setScrollSpeed(uint8_t speed); + bool isScrollEnabled(); + void setScrollEnabled(bool scroll); # endif // if P073_SCROLL_TEXT # if P073_7DBIN_COMMAND - void setBinaryData(const String& data); + void setBinaryData(const String& data); # endif // if P073_7DBIN_COMMAND # ifdef P073_DEBUG - void LogBufferContent(String prefix); + void LogBufferContent(String prefix); # endif // ifdef P073_DEBUG - void FillBufferWithDash(); - void ClearBuffer(); + void FillBufferWithDash(); + void ClearBuffer(); - uint8_t tm1637_getFontChar(uint8_t index, - uint8_t fontset); + // To implement in derived structs + virtual void setPowerBrightness(uint8_t brightlvl, + bool poweron) {} + + virtual void showTime(bool sep) {} + + virtual void showDate() {} + + virtual void showNumber() {} + + virtual void showTemperature(int8_t firstDot, + int8_t secondDot) {} + + virtual void toOutputBuffer() {} - int dotpos = -1; - uint8_t showbuffer[8] = { 0 }; - bool showperiods[8] = { 0 }; - uint8_t spidata[2] = { 0 }; + virtual void showBuffer() {} + +protected: + + uint8_t showbuffer[8]{}; + bool showperiods[8]{}; uint8_t pin1 = 0xFF; uint8_t pin2 = 0xFF; uint8_t pin3 = 0xFF; @@ -320,24 +335,18 @@ struct P073_data_struct : public PluginTaskData_base { uint16_t scrollCount = 0; uint16_t scrollPos = 0; bool scrollFull = false; - -private: - - uint16_t _scrollSpeed = 0; + uint16_t _scrollSpeed = 0; # endif // P073_SCROLL_TEXT # if defined(P073_SCROLL_TEXT) || defined(P073_7DBIN_COMMAND) String _textToScroll; # endif // if defined(P073_SCROLL_TEXT) || defined(P073_7DBIN_COMMAND) - # ifdef P073_DEBUG + # if defined(P073_DEBUG) && P073_USE_74HC595 uint32_t counter50 = 0; - # endif // ifdef P073_DEBUG + # endif // if defined(P073_DEBUG) && P073_USE_74HC595 # if P073_USE_74HC595 - int8_t dspDgt = 0; - bool isSequential = false; + bool isSequential = false; # endif // if P073_USE_74HC595 -private: - void getDisplayLimits(int32_t& lLimit, int32_t& uLimit, int8_t offset = 0, @@ -359,7 +368,36 @@ struct P073_data_struct : public PluginTaskData_base { bool plugin_write_7dbin(const String& text); # endif // if P073_7DBIN_COMMAND - // ---- TM1637 specific functions ---- + void DIRECT_shiftOut(uint8_t dataPin, + uint8_t clockPin, + uint8_t bitOrder, + uint8_t val); + void shiftinView(); + +}; + +struct P073_TM1637 : public P073_data_struct +{ +public: + + P073_TM1637(struct EventStruct *event); + virtual ~P073_TM1637() {} + + virtual bool init(struct EventStruct *event) override; + virtual void setPowerBrightness(uint8_t brightlvl, + bool poweron) override; + virtual void showTime(bool sep) override; + virtual void showDate() override; + virtual void showNumber() override; + virtual void showTemperature(int8_t firstDot, + int8_t secondDot) override; + virtual void toOutputBuffer() override; + virtual void showBuffer() override; + +private: + + void initDisplay(); + void clearDisplay(); void tm1637_i2cStart(); void tm1637_i2cStop(); bool tm1637_i2cAck(); @@ -367,13 +405,10 @@ struct P073_data_struct : public PluginTaskData_base { uint8_t length); void tm1637_i2cWriteByte_ack(uint8_t bytetoprint); void tm1637_i2cWrite(uint8_t bytetoprint); - void tm1637_ClearDisplay(); - void tm1637_SetPowerBrightness(uint8_t brightlvl, - bool poweron); - void tm1637_InitDisplay(); + uint8_t tm1637_getFontChar(uint8_t index, + uint8_t fontset); uint8_t tm1637_separator(uint8_t value, bool sep); - void tm1637_ShowTime6(); void tm1637_ShowDate6(bool showTime = false); void tm1637_ShowTemp6(bool sep); void tm1637_ShowTimeTemp4(bool sep, @@ -383,34 +418,72 @@ struct P073_data_struct : public PluginTaskData_base { uint8_t lastPos, bool useBinaryData = false); - // ---- MAX7219 specific functions ---- - void max7219_spiTransfer(ESPEASY_VOLATILE(uint8_t) opcode, - ESPEASY_VOLATILE(uint8_t) data); - void max7219_ClearDisplay(); - void max7219_SetPowerBrightness(uint8_t brightlvl, - bool poweron); - void max7219_SetDigit(int dgtpos, - uint8_t dgtvalue, - bool showdot, - bool binaryData = false); - void max7219_InitDisplay(); +}; // struct P073_74HC595 + +struct P073_MAX7219 : public P073_data_struct +{ +public: + + P073_MAX7219(struct EventStruct *event); + virtual ~P073_MAX7219() {} + + virtual bool init(struct EventStruct *event) override; + virtual void setPowerBrightness(uint8_t brightlvl, + bool poweron) override; + virtual void showTime(bool sep) override; + virtual void showDate() override; + virtual void showNumber() override; + virtual void showTemperature(int8_t firstDot, + int8_t secondDot) override; + virtual void toOutputBuffer() override; + virtual void showBuffer() override; + +private: + + void initDisplay(); + void clearDisplay(); + void setDigit(int dgtpos, + uint8_t dgtvalue, + bool showdot, + bool binaryData = false); void max7219_ShowTime(bool sep); void max7219_ShowTemp(int8_t firstDot, int8_t secondDot); void max7219_ShowDate(); - void max7219_ShowBuffer(); - # if P073_USE_74HC595 - void hc595_InitDisplay(); - void hc595_ShowBuffer(); - void hc595_ToOutputBuffer(); - void hc595_AdjustBuffer(); + void max7219_spiTransfer(ESPEASY_VOLATILE(uint8_t) opcode, + ESPEASY_VOLATILE(uint8_t) data); + + uint8_t spidata[2]{}; + uint8_t digitOffset = 0; + +}; // struct P073_MAX7219 + +# if P073_USE_74HC595 +struct P073_74HC595 : public P073_data_struct +{ +public: - bool hc595_Sequential() { return P073_HC595_SEQUENTIAL; } + P073_74HC595(struct EventStruct *event); + virtual ~P073_74HC595() {} + virtual bool init(struct EventStruct *event) override; + virtual void showTime(bool sep) override; + virtual void showDate() override; + virtual void showNumber() override; + virtual void showTemperature(int8_t firstDot, + int8_t secondDot) override; + virtual void toOutputBuffer() override; + virtual void showBuffer() override; + +private: + + void initDisplay(); + + int8_t dspDgt = 0; uint8_t outputbuffer[8]{}; - # endif // if P073_USE_74HC595 -}; +}; // struct P073_74HC595 +# endif // if P073_USE_74HC595 #endif // ifdef USES_P073 #endif // ifndef PLUGINSTRUCTS_P073_DATA_STRUCT_H diff --git a/src/src/PluginStructs/P073_display_74HC595.cpp b/src/src/PluginStructs/P073_display_74HC595.cpp new file mode 100644 index 0000000000..ed029b1235 --- /dev/null +++ b/src/src/PluginStructs/P073_display_74HC595.cpp @@ -0,0 +1,181 @@ +#include "../PluginStructs/P073_data_struct.h" + +#ifdef USES_P073 +# if P073_USE_74HC595 +# include + +P073_74HC595::P073_74HC595(struct EventStruct *event) : P073_data_struct(event) { + + if ((digits > 0) && ((digits < 4) || (5 == digits) || (7 == digits) || (9 == digits) || (10 == digits) || (11 == digits))) { + isSequential = true; + + if (1 == digits) { // 2+2 + digits = 4; + } else + if (9 == digits) { // 4 sequential + digits = 4; + } else + if (10 == digits) { // 4+4 sequential + digits = 8; + } else + if (7 == digits) { // 3+3 + digits = 6; + } else + if (11 == digits) { // 3+4/4+3 sequential + digits = 7; + } + } +} + +bool P073_74HC595::init(struct EventStruct *event) { + if (P073_data_struct::init(event)) { + initDisplay(); + + if (output == P073_DISP_MANUAL) { + ClearBuffer(); + toOutputBuffer(); + } + + if (is74HC595Multiplex()) { + Scheduler.setPluginTaskTimer(10, event->TaskIndex, 0); + } + return true; + } + return false; +} + +void P073_74HC595::showTime(bool sep) { toOutputBuffer(); } + +void P073_74HC595::showDate() { toOutputBuffer(); } + +void P073_74HC595::showNumber() { + shiftinView(); + toOutputBuffer(); +} + +void P073_74HC595::showTemperature(int8_t firstDot, + int8_t secondDot) { + shiftinView(); + + if (firstDot > -1) { showperiods[firstDot] = true; } + + if (secondDot > -1) { showperiods[secondDot] = true; } + + toOutputBuffer(); +} + +bool P073_data_struct::is74HC595Multiplex() { return P073_74HC595_2_8DGT == displayModel && P073_HC595_MULTIPLEX; } + +// ==================================== +// ---- 74HC595 specific functions ---- +// ==================================== + +void P073_74HC595::showBuffer() { + # if P073_USE_74HCMULTIPLEX + const uint8_t hc595digit4[] = { + 0b00001000, // left segment + 0b00000100, + 0b00000010, + 0b00000001, // right segment + }; + + const uint8_t hc595digit8[] = { + 0b00010000, // left segment + 0b00100000, + 0b01000000, + 0b10000000, + 0b00000001, + 0b00000010, + 0b00000100, + 0b00001000, // right segment + }; + # endif // if P073_USE_74HCMULTIPLEX + + int8_t i = digits - 1; + int8_t stop = -1; + int8_t incr = -1; + + # if P073_USE_74HCMULTIPLEX + + if (P073_HC595_MULTIPLEX) { + i = dspDgt; + stop = dspDgt + 1; + incr = 1; + } + # endif // if P073_USE_74HCMULTIPLEX + + for (; i != stop && i >= 0; i += incr) { + DIRECT_shiftOut(pin1, pin2, MSBFIRST, outputbuffer[i]); // Digit data out + + // 2, 3 and some 4 digit modules use sequential digit values (in reversed order) + // 4, 6 and 8 digit modules use multiplexing in LTR order + # if P073_USE_74HCMULTIPLEX + uint8_t digit = 0xFF; + + if (P073_HC595_MULTIPLEX) { + if (4 == digits) { + digit = hc595digit4[i]; + } else + if (6 == digits) { + digit = hc595digit8[i + (i > 2 ? 1 : 0)]; + } else + if (8 == digits) { + digit = hc595digit8[i]; + } + } + + if (digit != 0xFF) { // Select multiplexer digit, 0xFF is invalid + DIRECT_shiftOut(pin1, pin2, MSBFIRST, digit); + } + # endif // if P073_USE_74HCMULTIPLEX + + if ((P073_HC595_SEQUENTIAL && (0 == i)) || P073_HC595_MULTIPLEX) { + DIRECT_pinWrite(pin3, LOW); // Clock data + DIRECT_pinWrite(pin3, HIGH); + } + } + + if (i >= digits) { + dspDgt = 0; + } else { + dspDgt = i; + } + + # ifdef P073_DEBUG + + // TODO disable log + // if ((counter50 % 200 == 0) || P073_HC595_SEQUENTIAL) { + // addLog(LOG_LEVEL_INFO, strformat(F("P073: showBuffer (end) dgt:%d i:%d stop:%d incr:%d pin1: %d pin2: %d pin3: %d"), + // digits, i, stop, incr, pin1, pin2, pin3)); + // } + # endif // ifdef P073_DEBUG +} + +void P073_74HC595::toOutputBuffer() { + for (uint8_t i = 0; i < 8; ++i) { + uint8_t value; + + // 74HC595 uses inverted data, compared to MAX7219/TM1637 + value = ~P073_getFontChar(showbuffer[i], fontset); + + if (showperiods[i]) { + value &= 0x7F; + } + outputbuffer[i] = P073_revert7bits(value); // Rotate bits 6..0 + } + + if (isSequential) { // Sequential displays don't need continuous refreshing + showBuffer(); + } +} + +void P073_74HC595::initDisplay() { + pinMode(pin1, OUTPUT); // Use Arduino pin initialization as some ESPs don't properly set up their pins with DIRECT_GPIO_OUTPUT + pinMode(pin2, OUTPUT); + pinMode(pin3, OUTPUT); + DIRECT_pinWrite(pin3, HIGH); +} + +# endif // if P073_USE_74HC595 + +#endif // ifdef USES_P073 diff --git a/src/src/PluginStructs/P073_display_MAX7219.cpp b/src/src/PluginStructs/P073_display_MAX7219.cpp new file mode 100644 index 0000000000..998b6ead99 --- /dev/null +++ b/src/src/PluginStructs/P073_display_MAX7219.cpp @@ -0,0 +1,147 @@ +#include "../PluginStructs/P073_data_struct.h" + +#ifdef USES_P073 +# include + +P073_MAX7219::P073_MAX7219(struct EventStruct *event) : P073_data_struct(event) { + // +} + +bool P073_MAX7219::init(struct EventStruct *event) { + if (P073_data_struct::init(event)) { + initDisplay(); + delay(10); // small poweroff/poweron delay + setPowerBrightness(brightness, true); + + if (output == P073_DISP_MANUAL) { + clearDisplay(); + } + return true; + } + return false; +} + +void P073_MAX7219::showTime(bool sep) { max7219_ShowTime(sep); } + +void P073_MAX7219::showDate() { max7219_ShowDate(); } + +void P073_MAX7219::showNumber() { toOutputBuffer(); } + +void P073_MAX7219::showTemperature(int8_t firstDot, + int8_t secondDot) { max7219_ShowTemp(firstDot, secondDot); } + +void P073_MAX7219::showBuffer() {} // n.a. + +// ==================================== +// ---- MAX7219 specific functions ---- +// ==================================== + +# define OP_DECODEMODE 9 +# define OP_INTENSITY 10 +# define OP_SCANLIMIT 11 +# define OP_SHUTDOWN 12 +# define OP_DISPLAYTEST 15 + +void P073_MAX7219::max7219_spiTransfer(ESPEASY_VOLATILE(uint8_t) opcode, + ESPEASY_VOLATILE(uint8_t) data) { + spidata[0] = opcode; + spidata[1] = data; + DIRECT_pinWrite(pin3, LOW); + DIRECT_shiftOut(pin1, pin2, MSBFIRST, spidata[0]); + DIRECT_shiftOut(pin1, pin2, MSBFIRST, spidata[1]); + DIRECT_pinWrite(pin3, HIGH); +} + +void P073_MAX7219::clearDisplay() { + for (int i = 0; i < 8; i++) { + max7219_spiTransfer(i + 1, 0); + } +} + +void P073_MAX7219::setPowerBrightness(uint8_t brightlvl, + bool poweron) { + max7219_spiTransfer(OP_INTENSITY, brightlvl); + max7219_spiTransfer(OP_SHUTDOWN, poweron ? 1 : 0); +} + +void P073_MAX7219::setDigit(int dgtpos, + uint8_t dgtvalue, + bool showdot, + bool binaryData) { + uint8_t data; + + if (binaryData) { + data = dgtvalue; // Overwrite if binary data + } else + { + data = P073_getFontChar(dgtvalue, fontset); + + if (showdot) { + data |= 0b10000000; + } + } + max7219_spiTransfer(dgtpos + 1, data); +} + +void P073_MAX7219::initDisplay() { + pinMode(pin1, OUTPUT); // Use Arduino pin initialization as some ESPs don't properly set up their pins with DIRECT_GPIO_OUTPUT + pinMode(pin2, OUTPUT); + pinMode(pin3, OUTPUT); + DIRECT_pinWrite(pin3, HIGH); + max7219_spiTransfer(OP_DISPLAYTEST, 0); + max7219_spiTransfer(OP_SCANLIMIT, 7); // scanlimit setup to max at Init + max7219_spiTransfer(OP_DECODEMODE, 0); + clearDisplay(); + setPowerBrightness(0, false); +} + +void P073_MAX7219::max7219_ShowTime(bool sep) { + const uint8_t idx_list[] = { 7, 6, 4, 3, 1, 0 }; // Digits in reversed order, as the loop is backward + + for (int8_t i = 5; i >= 0; --i) { + setDigit(idx_list[i], showbuffer[i], false); + } + + const uint8_t sepChar = P073_mapCharToFontPosition(sep ? '-' : ' ', fontset); + + setDigit(2, sepChar, false); + setDigit(5, sepChar, false); +} + +void P073_MAX7219::max7219_ShowTemp(int8_t firstDot, + int8_t secondDot) { + setDigit(0, 10, false); // FIXME Not sure about doing this every time... + + if (firstDot > -1) { showperiods[firstDot] = true; } + + if (secondDot > -1) { showperiods[secondDot] = true; } + + digitOffset = rightAlignTempMAX7219 ? 0 : 1; + + toOutputBuffer(); +} + +void P073_MAX7219::max7219_ShowDate() { + // const uint8_t dotflags[8] = { false, true, false, true, false, false, false, false }; + + showperiods[1] = true; + showperiods[3] = true; + + toOutputBuffer(); +} + +void P073_MAX7219::toOutputBuffer() { + for (uint8_t i = digitOffset; i < 8; i++) { + const uint8_t bufIndex = (7 + digitOffset) - i; + setDigit(i, + showbuffer[bufIndex], + showperiods[bufIndex] + # if P073_7DBIN_COMMAND + , binaryData + # endif // if P073_7DBIN_COMMAND + ); + } + digitOffset = 0; // Reset every time. +} + +#endif // ifdef USES_P073 diff --git a/src/src/PluginStructs/P073_display_TM1637.cpp b/src/src/PluginStructs/P073_display_TM1637.cpp new file mode 100644 index 0000000000..dce4faa809 --- /dev/null +++ b/src/src/PluginStructs/P073_display_TM1637.cpp @@ -0,0 +1,322 @@ +#include "../PluginStructs/P073_data_struct.h" + +#ifdef USES_P073 +# include + +P073_TM1637::P073_TM1637(struct EventStruct *event) : P073_data_struct(event) { + // +} + +bool P073_TM1637::init(struct EventStruct *event) { + if (P073_data_struct::init(event)) { + initDisplay(); + setPowerBrightness(brightness / 2, true); + + if (output == P073_DISP_MANUAL) { + clearDisplay(); + } + return true; + } + return false; +} + +void P073_TM1637::showTime(bool sep) { + if (P073_TM1637_6DGT == displayModel) { + tm1637_ShowDate6(true); + } else { + tm1637_ShowTimeTemp4(sep, 0); + } +} + +void P073_TM1637::showDate() { + if (P073_TM1637_6DGT == displayModel) { + tm1637_ShowDate6(); + } else { + tm1637_ShowTimeTemp4(false, 0); + } +} + +void P073_TM1637::showNumber() { + if (P073_TM1637_6DGT == displayModel) { + tm1637_SwapDigitInBuffer(2); // only needed for 6-digits displays + tm1637_ShowBuffer(TM1637_6DIGIT, 8); + } else { + tm1637_ShowBuffer(TM1637_4DIGIT, 8); + } +} + +void P073_TM1637::showTemperature(int8_t firstDot, + int8_t secondDot) { + // if ((p073_temptemp == 0.0f) && p073_tempflagdot) { // TODO + // showbuffer[5] = 0; + // } + + if (P073_TM1637_6DGT == displayModel) { + tm1637_ShowTemp6(false); + } else { + tm1637_ShowTimeTemp4(false, 4); + } +} + +void P073_TM1637::showBuffer() {} // n.a. + +void P073_TM1637::toOutputBuffer() { + if (P073_TM1637_6DGT == displayModel) { + tm1637_SwapDigitInBuffer(0); // only needed for 6-digits displays + tm1637_ShowBuffer(0, 6 + # if P073_7DBIN_COMMAND + , binaryData + # endif // if P073_7DBIN_COMMAND + ); + } else { + tm1637_ShowBuffer(0, 4 + # if P073_7DBIN_COMMAND + , binaryData + # endif // if P073_7DBIN_COMMAND + ); + } +} + +// =================================== +// ---- TM1637 specific functions ---- +// =================================== + +# define CLK_HIGH() DIRECT_pinWrite(this->pin1, HIGH) +# define CLK_LOW() DIRECT_pinWrite(this->pin1, LOW) +# define DIO_HIGH() DIRECT_pinWrite(this->pin2, HIGH) +# define DIO_LOW() DIRECT_PINMODE_OUTPUT(this->pin2); DIRECT_pinWrite(this->pin2, LOW) +# define DIO_INPUT() DIRECT_PINMODE_INPUT(this->pin2) +# define DIO_OUTPUT() DIRECT_PINMODE_OUTPUT(this->pin2) + +void P073_TM1637::tm1637_i2cStart() { + # if defined(P073_DEBUG) && !defined(BUILD_NO_DEBUG) + addLog(LOG_LEVEL_DEBUG, F("7DGT : Comm Start")); + # endif // if defined(P073_DEBUG) && !defined(BUILD_NO_DEBUG) + DIO_LOW(); + delayMicroseconds(TM1637_CLOCKDELAY); +} + +void P073_TM1637::tm1637_i2cStop() { + # if defined(P073_DEBUG) && !defined(BUILD_NO_DEBUG) + addLog(LOG_LEVEL_DEBUG, F("7DGT : Comm Stop")); + # endif // if defined(P073_DEBUG) && !defined(BUILD_NO_DEBUG) + DIO_LOW(); + delayMicroseconds(TM1637_CLOCKDELAY); + CLK_HIGH(); + delayMicroseconds(TM1637_CLOCKDELAY); + DIO_HIGH(); + delayMicroseconds(TM1637_CLOCKDELAY); +} + +bool P073_TM1637::tm1637_i2cAck() { + CLK_LOW(); + DIO_INPUT(); + + delayMicroseconds(TM1637_CLOCKDELAY); + CLK_HIGH(); + const uint32_t start_wait = micros(); + + const bool acknowledged = -1 != + DIRECT_measureWaitForPinState_ISR(this->pin2, start_wait, TM1637_CLOCKDELAY, 0); + + const int32_t timePassed = usecPassedSince_fast(start_wait); + + if (timePassed < TM1637_CLOCKDELAY) { + delayMicroseconds(TM1637_CLOCKDELAY - timePassed); + } + + # if defined(P073_DEBUG) && !defined(BUILD_NO_DEBUG) + + if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { + String log = F("7DGT : Comm ACK="); + + if (acknowledged) { + log += F("TRUE"); + } else { + log += F("FALSE"); + } + addLogMove(LOG_LEVEL_DEBUG, log); + } + # endif // if defined(P073_DEBUG) && !defined(BUILD_NO_DEBUG) + CLK_HIGH(); + + delayMicroseconds(TM1637_CLOCKDELAY); + CLK_LOW(); + delayMicroseconds(TM1637_CLOCKDELAY); + DIO_OUTPUT(); + + return acknowledged; +} + +void P073_TM1637::tm1637_i2cWrite_ack(uint8_t bytesToPrint[], + uint8_t length) { + # ifdef P073_DEBUG + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + addLog(LOG_LEVEL_INFO, concat(F("7DGT : TM1637 databuffer: 0x"), formatToHex_array(bytesToPrint, length))); + } + # endif // ifdef P073_DEBUG + tm1637_i2cStart(); + + for (uint8_t i = 0; i < length; ++i) { + tm1637_i2cWriteByte_ack(bytesToPrint[i]); + } + tm1637_i2cStop(); +} + +void P073_TM1637::tm1637_i2cWriteByte_ack(uint8_t bytetoprint) { + tm1637_i2cWrite(bytetoprint); + tm1637_i2cAck(); +} + +void P073_TM1637::tm1637_i2cWrite(uint8_t bytetoprint) { + # if defined(P073_DEBUG) && !defined(BUILD_NO_DEBUG) + addLog(LOG_LEVEL_DEBUG, F("7DGT : WriteByte")); + # endif // if defined(P073_DEBUG) && !defined(BUILD_NO_DEBUG) + + for (uint8_t i = 0; i < 8; ++i) { + CLK_LOW(); + delayMicroseconds(TM1637_CLOCKDELAY >> 1); + + if (bytetoprint & 0b00000001) { + DIO_HIGH(); + } else { + DIO_LOW(); + } + delayMicroseconds(TM1637_CLOCKDELAY >> 1); + bytetoprint = bytetoprint >> 1; + CLK_HIGH(); + delayMicroseconds(TM1637_CLOCKDELAY); + } +} + +void P073_TM1637::clearDisplay() { + uint8_t bytesToPrint[7]{}; + + bytesToPrint[0] = 0xC0; + tm1637_i2cWrite_ack(bytesToPrint, 7); +} + +void P073_TM1637::setPowerBrightness(uint8_t brightlvl, + bool poweron) { + # ifdef P073_DEBUG + addLog(LOG_LEVEL_INFO, F("7DGT : Set BRIGHT")); + # endif // ifdef P073_DEBUG + brightlvl &= 0b111; + + if (poweron) { + brightlvl |= TM1637_POWER_ON; + } else { + brightlvl |= TM1637_POWER_OFF; + } + + uint8_t bytesToPrint[]{ brightlvl }; + tm1637_i2cWrite_ack(bytesToPrint, NR_ELEMENTS(bytesToPrint)); +} + +void P073_TM1637::initDisplay() { + pinMode(this->pin1, OUTPUT); // Use Arduino pin initialization as some ESPs don't properly set up their pins with DIRECT_GPIO_OUTPUT + pinMode(this->pin2, OUTPUT); + + DIRECT_pinWrite(this->pin1, HIGH); + DIRECT_pinWrite(this->pin2, HIGH); + + delayMicroseconds(TM1637_CLOCKDELAY); + uint8_t bytesToPrint[]{ 0x40 }; + tm1637_i2cWrite_ack(bytesToPrint, NR_ELEMENTS(bytesToPrint)); + clearDisplay(); +} + +uint8_t P073_TM1637::tm1637_separator(uint8_t value, + bool sep) { + if (sep) { + value |= 0b10000000; + } + return value; +} + +void P073_TM1637::tm1637_ShowDate6(bool showTime) { + uint8_t bytesToPrint[7]{}; + + bytesToPrint[0] = 0xC0; + bytesToPrint[1] = tm1637_getFontChar(showbuffer[2], fontset); + bytesToPrint[2] = tm1637_separator(tm1637_getFontChar(showbuffer[1], fontset), timesep); + bytesToPrint[3] = tm1637_getFontChar(showbuffer[0], fontset); + + if (showTime) { + bytesToPrint[4] = tm1637_getFontChar(showbuffer[5], fontset); + bytesToPrint[5] = tm1637_getFontChar(showbuffer[4], fontset); + } else { + bytesToPrint[4] = tm1637_getFontChar(showbuffer[7], fontset); + bytesToPrint[5] = tm1637_getFontChar(showbuffer[6], fontset); + } + bytesToPrint[6] = tm1637_separator(tm1637_getFontChar(showbuffer[3], fontset), timesep); + + tm1637_i2cWrite_ack(bytesToPrint, 7); +} + +void P073_TM1637::tm1637_ShowTemp6(bool sep) { + uint8_t bytesToPrint[7]{}; + + bytesToPrint[0] = 0xC0; + bytesToPrint[1] = tm1637_separator(tm1637_getFontChar(showbuffer[5], fontset), sep); + bytesToPrint[2] = tm1637_getFontChar(showbuffer[4], fontset); + bytesToPrint[3] = tm1637_getFontChar(showbuffer[3], fontset); // Fill first digit of display too + bytesToPrint[4] = tm1637_getFontChar(10, fontset); + bytesToPrint[5] = tm1637_getFontChar(showbuffer[7], fontset); + bytesToPrint[6] = tm1637_getFontChar(showbuffer[6], fontset); + + tm1637_i2cWrite_ack(bytesToPrint, 7); +} + +void P073_TM1637::tm1637_ShowTimeTemp4(bool sep, + uint8_t bufoffset) { + uint8_t bytesToPrint[5]{}; + + bytesToPrint[0] = 0xC0; + bytesToPrint[1] = tm1637_getFontChar(showbuffer[0 + bufoffset], fontset); + bytesToPrint[2] = tm1637_separator(tm1637_getFontChar(showbuffer[1 + bufoffset], fontset), sep); + bytesToPrint[3] = tm1637_getFontChar(showbuffer[2 + bufoffset], fontset); + bytesToPrint[4] = tm1637_getFontChar(showbuffer[3 + bufoffset], fontset); + + tm1637_i2cWrite_ack(bytesToPrint, 5); +} + +void P073_TM1637::tm1637_SwapDigitInBuffer(uint8_t startPos) { + std::swap(showbuffer[2 + startPos], showbuffer[0 + startPos]); + std::swap(showbuffer[3 + startPos], showbuffer[5 + startPos]); + + std::swap(showperiods[2 + startPos], showperiods[0 + startPos]); + std::swap(showperiods[3 + startPos], showperiods[5 + startPos]); +} + +void P073_TM1637::tm1637_ShowBuffer(uint8_t firstPos, + uint8_t lastPos, + bool useBinaryData) { + uint8_t bytesToPrint[8]{}; + + bytesToPrint[0] = 0xC0; + uint8_t length = 1; + uint8_t p073_datashowpos1; + + for (int i = firstPos; i < lastPos; ++i) { + if (useBinaryData) { + bytesToPrint[length] = showbuffer[i]; + } else { + p073_datashowpos1 = tm1637_separator( + tm1637_getFontChar(showbuffer[i], fontset), + showperiods[i]); + bytesToPrint[length] = p073_datashowpos1; + } + length++; + } + # ifdef P073_DEBUG + addLog(LOG_LEVEL_INFO, strformat(F("TM1673: Write bytes: %d buffer %d to %d"), length, firstPos, lastPos)); + # endif // ifdef P073_DEBUG + tm1637_i2cWrite_ack(bytesToPrint, length); +} + +uint8_t P073_TM1637::tm1637_getFontChar(uint8_t index, + uint8_t fontset) { return P073_revert7bits(P073_getFontChar(index, fontset)); } + +#endif // ifdef USES_P073