Merge pull request #5594 from tonhuisman/bugfix/P073-wrong-content-on-74hc595-displays

[P073] Correct wrong content shown on 74HC595 displays
This commit is contained in:
TD-er
2026-08-19 16:59:23 +02:00
committed by GitHub
6 changed files with 892 additions and 893 deletions
+28 -14
View File
@@ -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<P073_data_struct *>(getPluginTaskData(event->TaskIndex));
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
case P073_74HC595_2_8DGT:
P073_data = new (std::nothrow) P073_74HC595(event);
break;
# endif // if P073_USE_74HC595
}
if (nullptr != P073_data) {
P073_data->init(event);
# if P073_USE_74HC595
if (P073_data->is74HC595Matrix()) {
Scheduler.setPluginTaskTimer(10, event->TaskIndex, 0);
}
# endif // if P073_USE_74HC595
success = true;
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
File diff suppressed because it is too large Load Diff
+135 -62
View File
@@ -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 @@ public:
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) {}
int dotpos = -1;
uint8_t showbuffer[8] = { 0 };
bool showperiods[8] = { 0 };
uint8_t spidata[2] = { 0 };
virtual void showTime(bool sep) {}
virtual void showDate() {}
virtual void showNumber() {}
virtual void showTemperature(int8_t firstDot,
int8_t secondDot) {}
virtual void toOutputBuffer() {}
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 @@ public:
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 @@ private:
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 @@ private:
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 @@ private:
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);
bool hc595_Sequential() { return P073_HC595_SEQUENTIAL; }
uint8_t spidata[2]{};
uint8_t digitOffset = 0;
}; // struct P073_MAX7219
# if P073_USE_74HC595
struct P073_74HC595 : public P073_data_struct
{
public:
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
@@ -0,0 +1,181 @@
#include "../PluginStructs/P073_data_struct.h"
#ifdef USES_P073
# if P073_USE_74HC595
# include <GPIO_Direct_Access.h>
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
@@ -0,0 +1,147 @@
#include "../PluginStructs/P073_data_struct.h"
#ifdef USES_P073
# include <GPIO_Direct_Access.h>
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
@@ -0,0 +1,322 @@
#include "../PluginStructs/P073_data_struct.h"
#ifdef USES_P073
# include <GPIO_Direct_Access.h>
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