From 4beb589c18400f4cb9fc7bb444df920d9eb6a518 Mon Sep 17 00:00:00 2001 From: Ajith Vasudevan Date: Thu, 18 Feb 2021 22:44:15 +0530 Subject: [PATCH 01/13] Added support for TM1638 Seven-Segment Display, Buttons and LED --- lib/lib_display/TM1638plus/README.md | 276 ++++++++ lib/lib_display/TM1638plus/keywords.txt | 35 + lib/lib_display/TM1638plus/library.properties | 9 + lib/lib_display/TM1638plus/src/TM1638plus.cpp | 191 ++++++ lib/lib_display/TM1638plus/src/TM1638plus.h | 104 +++ .../TM1638plus/src/TM1638plus_common.cpp | 52 ++ .../TM1638plus/src/TM1638plus_common.h | 152 +++++ tasmota/settings.h | 3 +- tasmota/tasmota_configurations.h | 1 + tasmota/xdrv_13_display.ino | 61 +- tasmota/xdsp_15_tm1637.ino | 602 +++++++++++++----- 11 files changed, 1300 insertions(+), 186 deletions(-) create mode 100644 lib/lib_display/TM1638plus/README.md create mode 100644 lib/lib_display/TM1638plus/keywords.txt create mode 100644 lib/lib_display/TM1638plus/library.properties create mode 100644 lib/lib_display/TM1638plus/src/TM1638plus.cpp create mode 100644 lib/lib_display/TM1638plus/src/TM1638plus.h create mode 100644 lib/lib_display/TM1638plus/src/TM1638plus_common.cpp create mode 100644 lib/lib_display/TM1638plus/src/TM1638plus_common.h diff --git a/lib/lib_display/TM1638plus/README.md b/lib/lib_display/TM1638plus/README.md new file mode 100644 index 000000000..f23624b11 --- /dev/null +++ b/lib/lib_display/TM1638plus/README.md @@ -0,0 +1,276 @@ +![ module pics ](https://github.com/gavinlyonsrepo/TM1638plus/blob/master/extra/images/tm16383.jpg) + +Table of contents +--------------------------- + + * [Overview](#overview) + * [Installation](#installation) + * [Features](#features) + * [Model One](#model-one) + * [Model Two](#model-two) + * [Model Three](#model-three) + * [Notes](#notes) + * [Memory](#memory) + * [Pic Ports](#pic-port) + + +Overview +-------------------------------------------- +* Name: TM1638plus +* Description: +An Arduino library to display data on a 8-digit TM1638 seven segment module. +This library supports 3 different models, pictured above from left to right. + +1. Model 1, The (8 KEY & 8 LED) variant which has 8 LED's and 8 Push buttons. +2. Model 2, The (QYF 16 KEY) variant which has 16 pushbuttons. +3. Model 3, The (LKM1638) variant which has 8 bi-colour LED's and 8 Push buttons. + + +* Main Author: Gavin Lyons. + +* Tested on Development platforms: + +1. Arduino UNO & NANO v3 . +2. ATtiny85 . +3. ESP32. +4. STM32 STM32F103C8T6 "the blue pill". +5. ESP8266. +6. Teensy 4.0. (may not work at highest frequency see notes section) + +* History: see CHANGELOG.md in extra folder +* Contributors: [gabormay](https://github.com/gabormay) [centic9](https://github.com/centic9) [wunderbaum](https://github.com/wunderbaum) + + +Installation +------------------------------ + +The library is included in the official Arduino library manger and the optimum way to install it +is using the library manager which can be opened by the *manage libraries* option in Arduino IDE. +Search "tm1638" in search bar of library manager to find it. + +See link below for instruction for this and for the other methods too. + +[Installing Additional Arduino Libraries guide](https://www.arduino.cc/en/Guide/Libraries) + + +Features +---------------------- + +Connections to MCU: + +1. GPIO = STB = Strobe +2. GPIO = CLK = Clock +3. GPIO = DIO = Data input / output +4. GND +5. VCC 5V. + +This device is 5V if using 3.3V MCU, level shift. + +This library supports three variants of the TM1638, which for purposes of this documentation, +will be named Model 1 ,Model 2 and Model 3. + +| Model No | Module Name | LEDS | Push buttons | +| ------ | ------ | ------ | ------ | +| 1 | TM1638 LED & KEY | 8 red only | 8 | +| 2 | TM1638 KEYS, QYF | 0 | 16 | +| 3 | TM1638 V1.3 or LKM1638 | 8 bi color, red and green | 8 | + +There are two sets of files to support model 1 & 2 . I kept them separate as the models are wired quite different, Model 1 address by digit, while Model 2 address by segment. So the code is quite different for most functions. Model 3 uses same code as Model 1, just different example file and different use of LED functions. Common settings, data and functions are in the TM1638plus_common.x files. + +| Model | Header | Code file | TEST files | +| ------ | ------ | ------ | ------ | +| 1 | TM1638plus.h | TM1638plus.cpp | TM1638plus_HELLOWORLD_Model1.ino TM1638plus_TEST_Model1.ino | +| 3 | Same as model 1 | Same as model 1 | TM1638plus_TEST_Model3.ino | +| 2 | TM1638plus_Model2.h | TM1638plus_Model2.cpp | TM1638plus_HELLOWORLD_Model2 TM1638plus_TEST_Model2.ino | + +Model One +-------------------------------------- + +TM1638 Module 8 Push buttons 8 LEDS (LED & KEY) + +![ module ](https://github.com/gavinlyonsrepo/pic_16F18446_projects/blob/master/images/TM1638.jpg) + +![ sch ](https://github.com/gavinlyonsrepo/pic_16F18446_projects/blob/master/images/TM1638_2.jpg) + +This variant consist of an 8-digit seven segment display with decimal points, +8 Leds and 8 Push buttons. Two 4 digit 3461AS-1 (.34 inch, 4 digit ,common Cathode, decimal point, RED) are used in this module giving a total of 8 digits. A TM1638 controller chip drives the unit. +The unit is marked (LED & KEY). + +**Model 1 Library Functions** + +The commented functions can be found in library header file TM1638plus.h. +The library support ASCII ,text ,Hex and allows for setting individual segments, +and the decimal point of segment. +The TM1638plus_TEST.ino contains a set of tests demonstrating library functions. +For more information see the commented headers in header file. + +1. Print an ASCII character. +2. Print an ASCII character with a dot/decimal point. +3. Print a Hexadecimal digit(0-15). +4. Print a long integer number with or without leading zeros. +5. Print two integer numbers (0-9999) to each nibble with or without leading zeros. +6. Print a text string(dots are replaced and dot is turned on preceding digit), +"abc.def" becomes "abcdef" with c decimal point segment switched on. +7. Read buttons status. User may have to debounce buttons depending on application. +debouncing left out to minimise library size. +See [URL LINK](https://github.com/gavinlyonsrepo/Arduino_Clock_3) +for a practical real world example of using this library, +including a example of debouncing the key presses. It is also possible to read multiple key presses. +8. Reset and init module functions. +9. Adjust brightness of module. Support 8 degree brightness adjustment. +If user wishes to change the default brightness at start-up change, +The DEFAULT_BRIGHTNESS define in header file. +10. Manually set segments to create custom patterns. +11. Switch the 8 LEDS on and off, both a set one LED and set all LEDS methods available. + + +Model Two +----------------------------------------- + +TM1638 Module 16 Push buttons (16 KEY) (QYF). + +![ module ](https://github.com/gavinlyonsrepo/TM1638plus/blob/master/extra/images/tm16381.jpg) + +![ sch ](https://github.com/gavinlyonsrepo/TM1638plus/blob/master/extra/images/tm16382.jpg) + +They consist of an 8-digit seven segment display with decimal points, +and 16 Push buttons.Two 4 digit 3461BS-1 (.34 inch, 4 digit ,common Anode, decimal point, RED)are used in this module giving a total of 8 digits. A TM1638 controller chip drives the unit. +NB : If your display shows "56781234" for "12345678" see Notes section. Note A. + +**Model 2 Library Functions** + +The commented functions can be found in library header file TM1638plus_Model2.h. +The library support Strings,decimal ,Hex ,raw ASCII data, setting individual segments, +and the decimal point. For more detailed information on functions see commented headers in header file(.h). + +1. Print a Hexadecimal number with or without leading zeros +2. Print a decimal number with or without leading zeros +3. Manually set segments to create custom patterns. +4. Print two 4 digit decimal number(0-9999) to each nibble with or without leading zeros. +5. Print a text string, dot function supported. +6. Read buttons status. User may want to debounce buttons depending on application. +See TM1638plus_ADC_TEST_Model2.ino for debounce button example. +Two different functions to read buttons. +7. Reset and init module functions. +8. Adjust brightness of module. Support 8 degree brightness adjustment. +If user wishes to change the default brightness at start-up change, +The "DEFAULT_BRIGHTNESS" define in header file. +9. Print raw ASCII data without reference to font file. + +Model Three +----------------------------------------- + +There are different PCB's of these modules on market, +This library was tested on no 3 below. I think this software will work for all of them +and the differences in PCB are related to connectors, layout and component placement. +This module is a variant of Model 1. The differences are the LEDs are bigger and bi-color +both red and green, The seven segment display is larger and extra connectors are added for Daisy chaining. +Two 4 digit KYX-5461AS-7.3 (.54 inch, 4 digit ,common cathode, decimal point, RED)are used in this module +giving a total of 8 digits. + +1. LKM1638 v1.1 +2. LKM1638 v1.2 +3. TM1638 V1.3 + +![ module ](https://github.com/gavinlyonsrepo/TM1638plus/blob/master/extra/images/tm16384.jpg) + +**Model 3 Library Functions** + +The code is the same as model 1 and there is one unique model 3 example file. +setLED and setLEDs functions behaviour is the only difference in code base between 1 and 3. +SetLED: The difference is when you call the setLED function you pass the following to get LEDs to change colour. For more detailed information on functions see commented headers in header file(.h). + +| Model | setLED Value | result | +| ---- | ---- | ---- | +| 1 & 3 | 0 | LED off | +| 3 | 1 | Led green on | +| 3 | 2 | LED red on | +| 1 | 1 | LED on | + +SetLEDs: When you pass call the setLEDs function you can pass a word pattern where upper byte is turns LEDs green on and lower byte turns LEDs red on . Model one ignores lower byte, Set to 0x00 always. + +1. Model 3 setLEDs(word) = 0xGGRR +3. Model 1 setLEDs(word) = 0xRR00 + +Notes +-------------------------- + +1. Swapped data on Display issue on some Model 2 modules +2. Anomaly's on High frequency micro-controllers. +3. Driving multiple displays. +4. Detecting multiple buttons pressed together. + +*Note A* : Swapped display Issue: Model 2 only + +For Some users using this library the nibbles in information display byte +where swapped around. This is because there are different versions of modules on market with different wiring. See issue #3 on github called Swapped display :: "12345678" becomes "56781234". +If you test library and you see this issue, in order to fix this when you declare the +Object, set the fourth parameter "swap_nibbles" to True, The default is false. + +| PCB Model noted Label | Operation | Object constructor 4th parameter | +| ------ | ------ | ------ | +| QYF-TM1638 | default operation | false | +| QYF-TM1638 -Ver 1.0 | Swapped display Fix | true | + +*Note B* : High frequency micro-controllers. + +This library uses a software SPI-like protocol and may not work fully on +micro-controllers running at a very high frequency, without some adjustments to timing. +Its a SPI-like interface with a single bidirectional data wire DIO. +The TM1638 is basically a slow SPI device (< 500kHz) in DIO mode. The clock uses the equivalent of SPI mode 3 (normally high, clocks data on the rising edge). The problem is that the native Arduino shiftIn()/shiftOut() wire functions are simply too fast for this device (technically the clock signalling for the TM1638 is inverted but as it triggers on a rising edge still it is tolerant of that). +To make this work with fast devices, the shift clocking is slowed with a small delay (on the order of a microsecond). As of version 1.6 a new parameter *(_HIGH_FREQ)* has been introduced to constructor it is false by default. Set to true for high frequency MCU ~> 100Mhz. This will fix the issue of HF MCU not reading buttons correctly(ESP-Xs). The High_Freq parameter causes a custom shift-in function to be used. +The Teensy results have been sent to me, I don't have these MCU's them at time of writing. + +| IC | frequency | Status | +| ------ | ------ | ------ | +| ATtiny85 | 1Mhz internal | Working | +| Arduino UNO | 16 MHz | Working | +| Arduino Nano | 16 MHz | Working | +| STM32 "blue pill" STM32F103C8T6 | 72Mhz | Working | +| ESP8266 | 160Mhz | Working | +| ESP 32 | 240 MHz | Working, with high_freq set to true | +| Teensy 4.0| 150Mhz | Working model 1, no Data rest of models | +| Teensy 4.0| 396Mhz | Not working on model1 , no Data rest of models | + +*Note C* : Driving multiple displays. + +It is possible to drive multiple modules. Share the DIO and CLK lines and use a unique +STB line for each device. see issue number 10 at github for example code. + +*Note D* : Detecting multiple buttons pressed together. + +Model 1 and Model 3 CAN detect multiple buttons pressed. + +Model 3 has two different functions: + +1. ReadKey16 returns a byte with decimal value 1-16 this function cannot +detect multiple buttons pressed. + +2. ReadKey16Two returns a 16 bit integer where each bit corresponds to the 16 switch's. +However due to the wiring of the module, see SG-X lines on schematic, +Pressing Certain combinations of buttons will cause the data on Seven Segments to +change. So the simultaneous use of multiple key presses and the seven segments display +is problematic. See issue 12 on github for more details. + +Memory +------------------------------- + +Version 1.4. + +1. Model 1 memory usage NANO, basic hello world sketch. + +Sketch uses 1488 bytes (4%) of program storage space. +Global variables use 22 bytes (1%) of dynamic memory. + +2. Model 2 memory usage NANO, basic hello world sketch. + +Sketch uses 1536 bytes (5%) of program storage space. +Global variables use 23 bytes (1%) of dynamic memory. + + +Pic Port +------------------- + +MicroChip PIC XC8 port. +I have ported this library to the PIC for the XC8 compiler: +[ Link ](https://github.com/gavinlyonsrepo/pic_16F18446_projects) diff --git a/lib/lib_display/TM1638plus/keywords.txt b/lib/lib_display/TM1638plus/keywords.txt new file mode 100644 index 000000000..ae7e9bb67 --- /dev/null +++ b/lib/lib_display/TM1638plus/keywords.txt @@ -0,0 +1,35 @@ +# ----------------------------------------- +# Syntax coloring for TM1638plus library +# ----------------------------------------- + +# Datatypes (such as objects) +TM1638plus KEYWORD1 +TM1638plus_Model2 KEYWORD1 + +# Methods / functions +displayBegin KEYWORD2 +reset KEYWORD2 +brightness KEYWORD2 +DisplayDecNumNibble KEYWORD2 + +readButtons KEYWORD2 +setLED KEYWORD2 +setLEDs KEYWORD2 +displayText KEYWORD2 +displayASCIIwDot KEYWORD2 +displayASCII KEYWORD2 +display7Seg KEYWORD2 +displayHex KEYWORD2 +displayIntNum KEYWORD2 + +DisplaySegments KEYWORD2 +DisplayHexNum KEYWORD2 +DisplayDecNum KEYWORD2 +DisplayStr KEYWORD2 +ASCIItoSegment KEYWORD2 +ReadKey16 KEYWORD2 +ReadKey16Two KEYWORD2 + +# Constants + + diff --git a/lib/lib_display/TM1638plus/library.properties b/lib/lib_display/TM1638plus/library.properties new file mode 100644 index 000000000..8635f3eaf --- /dev/null +++ b/lib/lib_display/TM1638plus/library.properties @@ -0,0 +1,9 @@ +name=TM1638plus +version=1.7.0 +author=Gavin Lyons +maintainer=Gavin Lyons +sentence=TM1638plus is an Arduino library to control TM1638 seven segment modules. +paragraph=It supports Push Buttons, LEDs, ASCII, Decimal, Hexadecimal,text strings and the decimal point. Small Memory footprint. +category=Display +url=https://github.com/gavinlyonsrepo/TM1638plus +architectures=* diff --git a/lib/lib_display/TM1638plus/src/TM1638plus.cpp b/lib/lib_display/TM1638plus/src/TM1638plus.cpp new file mode 100644 index 000000000..c4076ab3a --- /dev/null +++ b/lib/lib_display/TM1638plus/src/TM1638plus.cpp @@ -0,0 +1,191 @@ +/* +* Project Name: TM1638 +* File: TM1638plus.cpp +* Description: source file arduino library for TM1638 module(LED & KEY). Model 1 & Model 3 +* Author: Gavin Lyons. +* Created May 2019 +* URL: https://github.com/gavinlyonsrepo/TM1638plus +*/ + +#include "TM1638plus.h" + + +TM1638plus::TM1638plus(uint8_t strobe, uint8_t clock, uint8_t data, bool highfreq) { + _STROBE_IO = strobe; + _DATA_IO = data; + _CLOCK_IO = clock; + _HIGH_FREQ = highfreq; +} + +void TM1638plus::displayBegin() { + pinMode(_STROBE_IO , OUTPUT); + pinMode(_DATA_IO, OUTPUT); + pinMode(_CLOCK_IO , OUTPUT); + sendCommand(TM_ACTIVATE); + brightness(TM_DEFAULT_BRIGHTNESS); + reset(); +} + + +void TM1638plus::sendCommand(uint8_t value) +{ + digitalWrite(_STROBE_IO, LOW); + sendData(value); + digitalWrite(_STROBE_IO, HIGH); +} + +void TM1638plus::sendData(uint8_t data) +{ + if (_HIGH_FREQ == false) + shiftOut(_DATA_IO, _CLOCK_IO, LSBFIRST, data); + else + TM_common.HighFreqshiftOut(_DATA_IO, _CLOCK_IO, LSBFIRST, data); +} + +void TM1638plus::reset() { + sendCommand(TM_WRITE_INC); // set auto increment mode + digitalWrite(_STROBE_IO, LOW); + sendData(TM_SEG_ADR); // set starting address to + for (uint8_t i = 0; i < 16; i++) + { + sendData(0x00); + } + digitalWrite(_STROBE_IO, HIGH); +} + +void TM1638plus::setLED(uint8_t position, uint8_t value) +{ + pinMode(_DATA_IO, OUTPUT); + sendCommand(TM_WRITE_LOC); + digitalWrite(_STROBE_IO, LOW); + sendData(TM_LEDS_ADR + (position << 1)); + sendData(value); + digitalWrite(_STROBE_IO, HIGH); +} + +void TM1638plus::setLEDs(uint16_t ledvalues) +{ + for (uint8_t LEDposition = 0; LEDposition < 8; LEDposition++) { + uint8_t colour = 0; + + if ((ledvalues & (1 << LEDposition)) != 0) { + colour |= TM_RED_LED; //scan lower byte, set Red if one + } + + if ((ledvalues & (1 << (LEDposition + 8))) != 0) { + colour |= TM_GREEN_LED; //scan upper byte, set green if one + } + + setLED(LEDposition, colour); + } +} + + +void TM1638plus::displayIntNum(unsigned long number, boolean leadingZeros) +{ + char values[TM_DISPLAY_SIZE + 1]; + snprintf(values, TM_DISPLAY_SIZE + 1, leadingZeros ? "%08ld" : "%ld", number); + displayText(values); +} + + +void TM1638plus::DisplayDecNumNibble(uint16_t numberUpper, uint16_t numberLower, boolean leadingZeros) +{ + char valuesUpper[TM_DISPLAY_SIZE + 1]; + char valuesLower[TM_DISPLAY_SIZE/2 + 1]; + snprintf(valuesUpper, TM_DISPLAY_SIZE/2 + 1, leadingZeros ? "%04d" : "%d", numberUpper); + snprintf(valuesLower, TM_DISPLAY_SIZE/2 + 1, leadingZeros ? "%04d" : "%d", numberLower); + strcat(valuesUpper ,valuesLower); + displayText(valuesUpper); +} + +void TM1638plus::displayText(const char *text) { + char c, pos; + pos = 0; + while ((c = (*text++)) && pos < TM_DISPLAY_SIZE) { + if (*text == '.' && c != '.') { + displayASCIIwDot(pos++, c); + + text++; + } else { + displayASCII(pos++, c); + } + } +} + + +void TM1638plus::displayASCIIwDot(uint8_t position, uint8_t ascii) { + // add 128 or 0x080 0b1000000 to turn on decimal point/dot in seven seg + display7Seg(position, pgm_read_byte(&SevenSeg[ascii- TM_ASCII_OFFSET]) + TM_DOT_MASK_DEC); +} + +void TM1638plus::display7Seg(uint8_t position, uint8_t value) { // call 7-segment + sendCommand(TM_WRITE_LOC); + digitalWrite(_STROBE_IO, LOW); + sendData(TM_SEG_ADR + (position << 1)); + sendData(value); + digitalWrite(_STROBE_IO, HIGH); +} + + +void TM1638plus::displayASCII(uint8_t position, uint8_t ascii) { + display7Seg(position, pgm_read_byte(&SevenSeg[ascii - TM_ASCII_OFFSET])); +} + +void TM1638plus::displayHex(uint8_t position, uint8_t hex) +{ + uint8_t offset = 0; + if (hex <= 9) + { + display7Seg(position, pgm_read_byte(&SevenSeg[hex + TM_HEX_OFFSET])); + // 16 is offset in reduced ASCII table for 0 + }else if ((hex >= 10) && (hex <=15)) + { + // Calculate offset in reduced ASCII table for AbCDeF + switch(hex) + { + case 10: offset = 'A'; break; + case 11: offset = 'b'; break; + case 12: offset = 'C'; break; + case 13: offset = 'd'; break; + case 14: offset = 'E'; break; + case 15: offset = 'F'; break; + } + display7Seg(position, pgm_read_byte(&SevenSeg[offset-TM_ASCII_OFFSET])); + } + +} + + +uint8_t TM1638plus::readButtons() +{ + uint8_t buttons = 0; + uint8_t v =0; + + digitalWrite(_STROBE_IO, LOW); + sendData(TM_BUTTONS_MODE); + pinMode(_DATA_IO, INPUT); + + for (uint8_t i = 0; i < 4; i++) + { + + if (_HIGH_FREQ == false) + v = shiftIn(_DATA_IO, _CLOCK_IO, LSBFIRST) << i; + else + v = TM_common.HighFreqshiftin(_DATA_IO, _CLOCK_IO, LSBFIRST) << i; + + buttons |= v; + } + + pinMode(_DATA_IO, OUTPUT); + digitalWrite(_STROBE_IO, HIGH); + return buttons; +} + + +void TM1638plus::brightness(uint8_t brightness) +{ + uint8_t value = 0; + value = TM_BRIGHT_ADR + (TM_BRIGHT_MASK & brightness); + sendCommand(value); +} diff --git a/lib/lib_display/TM1638plus/src/TM1638plus.h b/lib/lib_display/TM1638plus/src/TM1638plus.h new file mode 100644 index 000000000..6809a117b --- /dev/null +++ b/lib/lib_display/TM1638plus/src/TM1638plus.h @@ -0,0 +1,104 @@ +/* +* Project Name: TM1638plus +* File: TM1638plus.h +* Description: TM1638plus.h header file arduino library for TM1638 module(LED & KEY). Model 1 & Model 3 +* Author: Gavin Lyons. +* Created May 2019 +* URL: https://github.com/gavinlyonsrepo/TM1638plus +*/ + + +#ifndef TM1638PLUS_H +#define TM1638PLUS_H + +#if (ARDUINO >=100) + #include "Arduino.h" +#else + #include "WProgram.h" +#endif + +#include "TM1638plus_common.h" + +class TM1638plus { + +public: + // Constructor + //Parameters + // 1. strobe = GPIO STB pin + // 2. clock = GPIO CLK pin + // 3. data = GPIO DIO pin + // 4. higfreq Changes the value of parameter _HIGH_FREQ which is default false + // This is used when running high freq MCU CPU (~>100Mhz) because of issues with button function. + // Pass true when running high freq MCU CPU (~>100Mhz). + TM1638plus(uint8_t strobe, uint8_t clock, uint8_t data, bool highfreq = false); + + // Methods + + void displayBegin(); // Begin method , sets pinmodes , Call in setup + + void reset(void); // Reset / Clear module + + //Sets the brightness level on a scale of brightness = 0 to 7. + //0 is not turned off, it's just the lowest brightness. + //If user wishes to change the default brightness at start-up change. + //The DEFAULT_BRIGHTNESS define in header file. + void brightness(uint8_t brightness); + + //Read buttons returns a byte with value of buttons 1-8 b7b6b5b4b3b2b1b0 + // 1 pressed, zero not pressed. + //User may have to debounce buttons depending on application. + //See [URL LINK](https://github.com/gavinlyonsrepo/Arduino_Clock_3) + // for de-bonce example. + uint8_t readButtons(void); + + // Send Text to Seven segments, passed char array pointer + // dots are removed from string and dot on preceding digit switched on + // "abc.def" will be shown as "abcdef" with c decimal point turned on. + void displayText(const char *text); + + // Send ASCII value to seven segment, pass position 0-7 and ASCII value byte + void displayASCII(uint8_t position, uint8_t ascii); + + // Same as displayASCII function but turns on dot/decimal point as well + void displayASCIIwDot(uint8_t position, uint8_t ascii) ; + + // Send HEX value to seven segment, pass position 0-7 and hex value(DEC) 0-15 + void displayHex(uint8_t position, uint8_t hex); + + // Send seven segment value to seven segment + // pass position 0-7 byte of data corresponding to segments (dp)gfedcba + // i.e 0b01000001 will set g and a on. + void display7Seg(uint8_t position, uint8_t value); + + //Display an integer and leading zeros optional + void displayIntNum(unsigned long number, boolean leadingZeros = true); + + //Divides the display into two nibbles and displays a Decimal number in each. + //takes in two numbers 0-9999 for each nibble , and byte for decimal point display, + //and leading zeros optional + void DisplayDecNumNibble(uint16_t numberUpper, uint16_t numberLower, boolean leadingZeros = true); + + // Set the LEDs. passed one 16bit integer. + // MODEL 3: + //MSB byte for the green LEDs, LS byte for the red LEDs (0xgreenred) + //ie. 0xE007 1110 0000 0000 0111 results in L8-L0 GGGX XRRR, NOTE L8 is RHS on display + // MODEL 1: + // MSB byte 1 for red LED , LSB byte n/a set to 0x00 (0xleds, 0xXX) + //i.e 0xF100 1111 0000 L8-L0 RRRRXXX0 NOTE L8 is RHS on display + void setLEDs(uint16_t greenred); + + // Set an LED, pass it LED position 0-7 and value 0 or 1 , L1-L8 + void setLED(uint8_t position, uint8_t value); + +private: + uint8_t _STROBE_IO; + uint8_t _DATA_IO; + uint8_t _CLOCK_IO; + void sendCommand(uint8_t value); + void sendData(uint8_t data); + //This is used when running high freq CPU + bool _HIGH_FREQ = false; + TM1638plus_common TM_common; +}; + +#endif diff --git a/lib/lib_display/TM1638plus/src/TM1638plus_common.cpp b/lib/lib_display/TM1638plus/src/TM1638plus_common.cpp new file mode 100644 index 000000000..f0accc1fc --- /dev/null +++ b/lib/lib_display/TM1638plus/src/TM1638plus_common.cpp @@ -0,0 +1,52 @@ +/* +* Project Name: TM1638plus +* File: TM1638plus_common +* Description: cpp file for common data and functions between model 1 and 2 classes +* Arduino library TM1638plus +* Author: Gavin Lyons. +* URL: https://github.com/gavinlyonsrepo/TM1638plus +*/ + +#include "TM1638plus_common.h" + + +TM1638plus_common::TM1638plus_common() +{ + // Blank constructor +} + +uint8_t TM1638plus_common::HighFreqshiftin(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder) +{ + uint8_t value = 0; + uint8_t i = 0; + + for(i = 0; i < 8; ++i) { + if(bitOrder == LSBFIRST) + value |= digitalRead(dataPin) << i; + else + value |= digitalRead(dataPin) << (7 - i); + + digitalWrite(clockPin, HIGH); + delayMicroseconds(1); + digitalWrite(clockPin, LOW); + delayMicroseconds(1); + } + return value; +} + +void TM1638plus_common::HighFreqshiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val) +{ + uint8_t i; + + for (i = 0; i < 8; i++) { + if (bitOrder == LSBFIRST) + digitalWrite(dataPin, !!(val & (1 << i))); + else + digitalWrite(dataPin, !!(val & (1 << (7 - i)))); + + digitalWrite(clockPin, HIGH); + delayMicroseconds(1); + digitalWrite(clockPin, LOW); + delayMicroseconds(1); + } +} diff --git a/lib/lib_display/TM1638plus/src/TM1638plus_common.h b/lib/lib_display/TM1638plus/src/TM1638plus_common.h new file mode 100644 index 000000000..36a7d5408 --- /dev/null +++ b/lib/lib_display/TM1638plus/src/TM1638plus_common.h @@ -0,0 +1,152 @@ +/* +* Project Name: TM1638plus +* File: TM1638plus_common.h +* Description: header file for common data and functions between model 1 and 2 classes +* Arduino library TM1638plus +* Author: Gavin Lyons. +* URL: https://github.com/gavinlyonsrepo/TM1638plus +*/ + +#ifndef TM1638PLUS_COMMON_H +#define TM1638PLUS_COMMON_H + +#if (ARDUINO >=100) + #include "Arduino.h" +#else + #include "WProgram.h" +#endif + +#define TM_ACTIVATE 0x8F // Start up +#define TM_BUTTONS_MODE 0x42 // Buttons mode +#define TM_WRITE_LOC 0x44 // Write to a location +#define TM_WRITE_INC 0x40 // Incremental write +#define TM_SEG_ADR 0xC0 // leftmost segment Address C0 C2 C4 C6 C8 CA CC CE +#define TM_LEDS_ADR 0xC1 // Leftmost LED address C1 C3 C5 C7 C9 CB CD CF +#define TM_BRIGHT_ADR 0x88 // Brightness address +#define TM_BRIGHT_MASK 0x07 // Brightness mask +#define TM_DEFAULT_BRIGHTNESS 0x02 //can be 0x00 to 0x07 +#define TM_DISPLAY_SIZE 8 //size of display + +#define TM_ASCII_OFFSET 32 // Ascii table offset to jump over first missing 32 chars +#define TM_HEX_OFFSET 16 // Ascii table offset to reach number position +#define TM_DOT_MASK_DEC 128 // 0x80 Mask to switch on decimal point in seven seg. + +#define TM_RED_LED 0x02 // Model 3 +#define TM_GREEN_LED 0x01 // Model 3 +#define TM_OFF_LED 0x00 + +// font , map of ASCII values/table to 7-segment, offset to position 32. +const PROGMEM unsigned char SevenSeg[] = { + 0x00, /* (space) */ + 0x86, /* ! */ + 0x22, /* " */ + 0x7E, /* # */ + 0x6D, /* $ */ + 0xD2, /* % */ + 0x46, /* & */ + 0x20, /* ' */ + 0x29, /* ( */ + 0x0B, /* ) */ + 0x21, /* * */ + 0x70, /* + */ + 0x10, /* , */ + 0x40, /* - */ + 0x80, /* . */ + 0x52, /* / */ + 0x3F, /* 0 */ + 0x06, /* 1 */ + 0x5B, /* 2 */ + 0x4F, /* 3 */ + 0x66, /* 4 */ + 0x6D, /* 5 */ + 0x7D, /* 6 */ + 0x07, /* 7 */ + 0x7F, /* 8 */ + 0x6F, /* 9 */ + 0x09, /* : */ + 0x0D, /* ; */ + 0x61, /* < */ + 0x48, /* = */ + 0x43, /* > */ + 0xD3, /* ? */ + 0x5F, /* @ */ + 0x77, /* A */ + 0x7C, /* B */ + 0x39, /* C */ + 0x5E, /* D */ + 0x79, /* E */ + 0x71, /* F */ + 0x3D, /* G */ + 0x76, /* H */ + 0x30, /* I */ + 0x1E, /* J */ + 0x75, /* K */ + 0x38, /* L */ + 0x15, /* M */ + 0x37, /* N */ + 0x3F, /* O */ + 0x73, /* P */ + 0x6B, /* Q */ + 0x33, /* R */ + 0x6D, /* S */ + 0x78, /* T */ + 0x3E, /* U */ + 0x3E, /* V */ + 0x2A, /* W */ + 0x76, /* X */ + 0x6E, /* Y */ + 0x5B, /* Z */ + 0x39, /* [ */ + 0x64, /* \ */ + 0x0F, /* ] */ + 0x23, /* ^ */ + 0x08, /* _ */ + 0x02, /* ` */ + 0x5F, /* a */ + 0x7C, /* b */ + 0x58, /* c */ + 0x5E, /* d */ + 0x7B, /* e */ + 0x71, /* f */ + 0x6F, /* g */ + 0x74, /* h */ + 0x10, /* i */ + 0x0C, /* j */ + 0x75, /* k */ + 0x30, /* l */ + 0x14, /* m */ + 0x54, /* n */ + 0x5C, /* o */ + 0x73, /* p */ + 0x67, /* q */ + 0x50, /* r */ + 0x6D, /* s */ + 0x78, /* t */ + 0x1C, /* u */ + 0x1C, /* v */ + 0x14, /* w */ + 0x76, /* x */ + 0x6E, /* y */ + 0x5B, /* z */ + // Note : Removed last 4 characters to reduce program size as of v 1.3.0 +// 0x46, /* { */ +// 0x30, /* | */ +// 0x70, /* } */ +// 0x01, /* ~ */ +}; + +// Class for some common functions +class TM1638plus_common{ + +public: + // Constructor + TM1638plus_common(); + + // Used instead of arduino function "shiftin" when _HIGH_FREQ is set to true + uint8_t HighFreqshiftin(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder) ; + // Used instead of arduino function "shiftOut" when _HIGH_FREQ is set to true + void HighFreqshiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val); + +}; + +#endif diff --git a/tasmota/settings.h b/tasmota/settings.h index 5f8484ea0..6a9e60795 100644 --- a/tasmota/settings.h +++ b/tasmota/settings.h @@ -375,8 +375,9 @@ struct { uint8_t param[PARAM8_SIZE]; // 2FC SetOption32 .. SetOption49 int16_t toffset[2]; // 30E uint8_t display_font; // 312 + uint8_t display_type; // 313 - uint8_t free_313[44]; // 313 + uint8_t free_314[43]; // 314 uint8_t tuyamcu_topic; // 33F Manage tuyaSend topic. ex_energy_power_delta on 6.6.0.20, replaced on 8.5.0.1 uint16_t domoticz_update_timer; // 340 diff --git a/tasmota/tasmota_configurations.h b/tasmota/tasmota_configurations.h index e0bf0100e..c469f264a 100644 --- a/tasmota/tasmota_configurations.h +++ b/tasmota/tasmota_configurations.h @@ -321,6 +321,7 @@ #define USE_DISPLAY_RA8876 // [DisplayModel 10] #define USE_DISPLAY_ST7789 // [DisplayModel 12] Enable ST7789 module #define USE_DISPLAY_SSD1331 // [DisplayModel 14] Enable SSD1331 module + #define USE_DISPLAY_TM1637 // [DisplayModel 15] Enable TM1637, TM1638 modules #undef DEBUG_THEO // Disable debug code #undef USE_DEBUG_DRIVER // Disable debug code diff --git a/tasmota/xdrv_13_display.ino b/tasmota/xdrv_13_display.ino index c3ecd407b..fcecc087c 100755 --- a/tasmota/xdrv_13_display.ino +++ b/tasmota/xdrv_13_display.ino @@ -82,6 +82,7 @@ const uint8_t DISPLAY_LOG_ROWS = 32; // Number of lines in display log #define D_CMND_DISP_SETLED "SetLED" #define D_CMND_DISP_BUTTONS "Buttons" #define D_CMND_DISP_SCROLLTEXT "ScrollText" +#define D_CMND_DISP_TYPE "Type" @@ -99,7 +100,7 @@ enum XdspFunctions { FUNC_DISPLAY_INIT_DRIVER, FUNC_DISPLAY_INIT, FUNC_DISPLAY_E , FUNC_DISPLAY_NUMBER, FUNC_DISPLAY_FLOAT, FUNC_DISPLAY_NUMBERNC, FUNC_DISPLAY_FLOATNC, FUNC_DISPLAY_BRIGHTNESS, FUNC_DISPLAY_RAW, FUNC_DISPLAY_LEVEL, FUNC_DISPLAY_SEVENSEG_TEXT, FUNC_DISPLAY_SEVENSEG_TEXTNC, FUNC_DISPLAY_SCROLLDELAY, FUNC_DISPLAY_CLOCK, FUNC_DISPLAY_SETLEDS, FUNC_DISPLAY_SETLED, - FUNC_DISPLAY_BUTTONS, FUNC_DISPLAY_SCROLLTEXT + FUNC_DISPLAY_BUTTONS, FUNC_DISPLAY_SCROLLTEXT, FUNC_DISPLAY_TYPE }; enum DisplayInitModes { DISPLAY_INIT_MODE, DISPLAY_INIT_PARTIAL, DISPLAY_INIT_FULL }; @@ -114,7 +115,7 @@ const char kDisplayCommands[] PROGMEM = D_PRFX_DISPLAY "|" // Prefix "|" D_CMND_DISP_CLEAR "|" D_CMND_DISP_NUMBER "|" D_CMND_DISP_FLOAT "|" D_CMND_DISP_NUMBERNC "|" D_CMND_DISP_FLOATNC "|" D_CMND_DISP_BRIGHTNESS "|" D_CMND_DISP_RAW "|" D_CMND_DISP_LEVEL "|" D_CMND_DISP_SEVENSEG_TEXT "|" D_CMND_DISP_SEVENSEG_TEXTNC "|" D_CMND_DISP_SCROLLDELAY "|" D_CMND_DISP_CLOCK "|" D_CMND_DISP_TEXTNC "|" D_CMND_DISP_SETLEDS "|" D_CMND_DISP_SETLED "|" - D_CMND_DISP_BUTTONS "|" D_CMND_DISP_SCROLLTEXT + D_CMND_DISP_BUTTONS "|" D_CMND_DISP_SCROLLTEXT "|" D_CMND_DISP_TYPE ; void (* const DisplayCommand[])(void) PROGMEM = { @@ -127,7 +128,7 @@ void (* const DisplayCommand[])(void) PROGMEM = { , &CmndDisplayClear, &CmndDisplayNumber, &CmndDisplayFloat, &CmndDisplayNumberNC, &CmndDisplayFloatNC, &CmndDisplayBrightness, &CmndDisplayRaw, &CmndDisplayLevel, &CmndDisplaySevensegText, &CmndDisplaySevensegTextNC, &CmndDisplayScrollDelay, &CmndDisplayClock, &CmndDisplayTextNC, &CmndDisplaySetLEDs, &CmndDisplaySetLED, - &CmndDisplayButtons, &CmndDisplayScrollText + &CmndDisplayButtons, &CmndDisplayScrollText, &CmndDisplayType }; char *dsp_str; @@ -1875,32 +1876,50 @@ void CmndDisplaySetLEDs(void) void CmndDisplaySetLED(void) -{ - if (!renderer) { - XdspCall(FUNC_DISPLAY_SETLED); - } - ResponseCmndChar(XdrvMailbox.data); -} - -void CmndDisplayButtons(void) -{ - if (!renderer) { - XdspCall(FUNC_DISPLAY_BUTTONS); - } - ResponseCmndNumber(XdrvMailbox.payload); -} - - -void CmndDisplayScrollText(void) { bool result = false; if (!renderer) { - result = XdspCall(FUNC_DISPLAY_SCROLLTEXT); + result = XdspCall(FUNC_DISPLAY_SETLED); } if(result) ResponseCmndNumber(XdrvMailbox.payload); else ResponseCmndChar(XdrvMailbox.data); } +void CmndDisplayButtons(void) +{ + bool result = false; + if (!renderer) { + result = XdspCall(FUNC_DISPLAY_BUTTONS); + } + if(result) ResponseCmndNumber(XdrvMailbox.payload); + else ResponseCmndChar(XdrvMailbox.data); +} + + +void CmndDisplayScrollText(void) +{ + if (!renderer) { + XdspCall(FUNC_DISPLAY_SCROLLTEXT); + } + ResponseCmndChar(XdrvMailbox.data); +} + + +void CmndDisplayType(void) +{ + if(ArgC() == 0) { + XdrvMailbox.payload = Settings.display_type; + } else { + uint8_t prev_type = Settings.display_type; + if(prev_type != XdrvMailbox.payload) { + if (!renderer) { + XdspCall(FUNC_DISPLAY_TYPE); + Settings.display_type = XdrvMailbox.payload; + } + } + } + ResponseCmndNumber(XdrvMailbox.payload); +} void CmndDisplaySize(void) { diff --git a/tasmota/xdsp_15_tm1637.ino b/tasmota/xdsp_15_tm1637.ino index 79bf3ab93..13260f4a7 100644 --- a/tasmota/xdsp_15_tm1637.ino +++ b/tasmota/xdsp_15_tm1637.ino @@ -1,5 +1,5 @@ /* - xdsp_15_tm1637.ino - Support for TM1637 seven-segment display (upto 6 digits) for Tasmota + xdsp_15_tm1637.ino - Support for TM1637- and TM1638-based seven-segment displays for Tasmota Copyright (C) 2021 Ajith Vasudevan @@ -21,29 +21,36 @@ #ifdef USE_DISPLAY_TM1637 /*********************************************************************************************\ This driver enables the display of numbers (both integers and floats) and basic text - on the inexpensive TM1637-based seven-segment modules (tested on both 4- and 6-digit variants). + on the inexpensive TM1637- and TM1638-based seven-segment modules. + Raw segments can also be displayed. - In addition, it is also possible to set brightness (8 levels), clear the display, scroll text, display - a rudimentary bar graph, and a Clock (12 hr and 24 hr). + + In addition, it is also possible to set brightness (8 levels), clear the display, scroll text, + display a rudimentary bar graph, and a Clock (12 hr and 24 hr). To use, compile Tasmota with USE_DISPLAY and USE_DISPLAY_TM1637, or build the tasmota-display env. - The pins to use are "SSPI MOSI" and "SSPI SCLK". - - Connect the TM1637 display module's DIO and CLK pins to any free GPIOs of the ESP8266 module + Connect the TM1637 or TM1638 display module's pins to any free GPIOs of the ESP8266 module and assign the pins as follows from Tasmota's GUI: DIO hardware pin --> "SSPI MOSI" CLK hardware pin --> "SSPI SCLK" - - Once the device restarts the following "Display" commands become available: + STB hardware pin --> "SSPI MISO" (Only for TM1638) + Once the device restarts the following "Display" commands should become available: + + In case you get a stat//RESULT = {"Command":"Unknown"} result for any of these commands, + please ensure that your DisplayModel is set to 15 using the command "DisplayModel 15" - DisplaySize size {1-6} - Sets the number of digits to use. This is typically set to the actual number of digits available - in the display module. command e.g., "DisplaySize 6" + DisplayType type {0|1|2} + + Sets the display type. 0 => TM1637, 4 digit + 1 => TM1637, 6 digit + 2 => TM1638, 8 digit + Command e.g., "DisplayType 1" // to enable TM1637 6-digit variant + DisplayClear @@ -51,6 +58,7 @@ Clears the display, command: "DisplayClear" + DisplayNumber num [,position {0-(NUM_DIGITS-1))} [,leading_zeros {0|1} [,length {1 to NUM_DIGITS}]]] Clears and then displays number without decimal. command e.g., "DisplayNumber 1234" @@ -58,6 +66,8 @@ 'leading zeros' can be 1 or 0 (default), 'length' can be 1 to NUM_DIGITS, 'position' can be 0 (left-most) to NUM_DIGITS (right-most). See function description below for more details. + + DisplayNumberNC num [,position {0-(NUM_DIGITS-1))} [,leading_zeros {0|1} [,length {1 to NUM_DIGITS}]]] Display integer number as above, but without clearing first. e.g., "DisplayNumberNC 1234". Usage is same as above. @@ -97,10 +107,12 @@ Clears and then displays basic text. command e.g., "DisplayText ajith vasudevan" Control 'length' and 'position' with "DisplayText , , " 'length' can be 1 to NUM_DIGITS, 'position' can be 0 (left-most) to NUM_DIGITS-1 (right-most) + A caret(^) symbol in the text input is dispayed as the degrees(°) symbol. This is useful for displaying Temperature! For example, the command "DisplayText 22.5^" will display "22.5°". + DisplayTextNC text [, position {0-NUM_DIGITS-1} [,length {1 to NUM_DIGITS}]] Clears first, then displays text. Usage is same as above. @@ -132,16 +144,63 @@ "DisplayClock 2" // 24 hr format "DisplayClock 0" // turn off clock + + +Commands specific to TM1638 +==================================== + + DisplaySetLEDs bit_array {0-255} + + Sets the 8 LEDs (not the digits!) on the TM1638 module to the binary number represented by the input bit_array. + For example, "DisplaySetLEDs 3" would light up the first and second LED (from left), because 3 => 00000011 + + + + DisplaySetLED position {0-7}, value {0|1} + + Sets a specified LED to either ON or OFF. e.g., "DisplaySetLED 2, 1" would light up the 3rd LED (2 => 3rd position) + + + + DisplayButtons + + Causes the current state of the buttons to be returned as a "STAT" message of the form stat/TM1638/RESULT = {"DisplayButtons": } + The button value is the decimal representation of the bit-array that constitutes the button states. For example, if the 5th button is pressed and the + DisplayButtons command is issued, the response will be stat/TM1638/RESULT = {"DisplayButtons": 16} because 16 => 2^(5-1) + if the 2nd and 3rd buttons are pressed together and the DisplayButtons command is issued, the response will be + stat/TM1638/RESULT = {"DisplayButtons": 6} because 6 => 2^(2-1) + 2^(3-1) + + + + Button Functionality (TM1638 only): +====================================== + When this driver is initialized with "DisplayType 2" (TM1638), the buttons on the TM1638 module can be used + to toggle the corresponding LEDs. + + In addition, if SwitchTopic is set to some value, then for each button press, a TOGGLE for that switch number is sent. + + For example, if Topic = "TM1638" and SwitchTopic = "TEST_TM1638", and if S3 is pressed, then, + + 1) a STAT message is sent : stat/TM1638/RESULT = {"TM1638_BUTTONS":4} // (4 = 2^(3-1)) + and 2) a TOGGLE command is sent: cmnd/TEST/POWER3 = TOGGLE + + \*********************************************************************************************/ #define XDSP_15 15 -#include "SevenSegmentTM1637.h" -SevenSegmentTM1637 *display; +#include "SevenSegmentTM1637.h" +#include + +SevenSegmentTM1637 *disp37; +TM1638plus *disp38; +bool driverinited = false; bool showClock = false; bool clock24 = false; char tm[5]; char msg[60]; +uint8_t buttons; +uint8_t prevbuttons; uint32_t NUM_DIGITS = 4; uint32_t prev_num_digits = 4; bool scroll = false; @@ -149,7 +208,10 @@ uint32_t scrolldelay = 4; uint32_t scrollindex = 0; uint32_t iteration = 0; uint32_t brightness = 5; - +char modelname[8]; +enum displaytypes { TM1637, TM1638 }; +uint8_t displaytype = TM1637; +bool modechanged = false; #define BRIGHTNESS_MIN 0 // Display OFF #define BRIGHTNESS_MAX 8 @@ -157,21 +219,42 @@ uint32_t brightness = 5; #define LEVEL_MIN 0 #define LEVEL_MAX 100 #define SCROLL_MAX_LEN 50 - +#define POSITION_MIN 0 +#define POSITION_MAX 8 +#define LED_MIN 0 +#define LED_MAX 255 char scrolltext[CMD_MAX_LEN]; /*********************************************************************************************\ * Init function \*********************************************************************************************/ -bool TM1637Init(void) { - display = new SevenSegmentTM1637(Pin(GPIO_SSPI_SCLK), Pin(GPIO_SSPI_MOSI) ); - NUM_DIGITS = Settings.display_size > 3 ? Settings.display_size : 4; - Settings.display_size = NUM_DIGITS; - display->begin(NUM_DIGITS, 1); - display->setBacklight(brightness * 10); - clearDisplay(); - Settings.display_model = XDSP_15; - AddLog(LOG_LEVEL_INFO, PSTR("DSP: TM1637 display driver initialized")); +bool DriverInit(void) { + if(Settings.display_model == XDSP_15) { + if(driverinited) return true; + + if(Settings.display_type == 2) { NUM_DIGITS = 8; displaytype = TM1638; } + else if(Settings.display_type == 1) { NUM_DIGITS = 6; displaytype = TM1637; } + else { Settings.display_type = 0; NUM_DIGITS = 4; displaytype = TM1637; } + + if(displaytype == TM1637) { + strcpy(modelname, "TM1637"); + disp37 = new SevenSegmentTM1637(Pin(GPIO_SSPI_SCLK), Pin(GPIO_SSPI_MOSI) ); + disp37->begin(NUM_DIGITS, 1); + } else if(displaytype == TM1638) { + strcpy(modelname, "TM1638"); + disp38 = new TM1638plus(Pin(GPIO_SSPI_MISO), Pin(GPIO_SSPI_SCLK), Pin(GPIO_SSPI_MOSI), true ); + NUM_DIGITS = 8; + disp38->displayBegin(); + } + Settings.display_size = NUM_DIGITS; // Can use to check current display size + clearDisplay(); + brightness = (Settings.display_dimmer ? Settings.display_dimmer : brightness); + setBrightness(brightness); + driverinited = true; + modechanged = false; + AddLog(LOG_LEVEL_INFO, PSTR("DSP: %s display driver initialized with %d digits (DisplayType %d)"), modelname, NUM_DIGITS, Settings.display_type); + } + return true; } @@ -182,7 +265,7 @@ bool TM1637Init(void) { * commands: DisplayNumber num [,position {0-(NUM_DIGITS-1)} [,leading_zeros {0|1} [,length {1 to NUM_DIGITS}]]] * DisplayNumberNC num [,position {0-(NUM_DIGITS-1)} [,leading_zeros {0|1} [,length {1 to NUM_DIGITS}]]] // "NC" --> "No Clear" \*********************************************************************************************/ -bool CmndTM1637Number(bool clear) { +bool CmndNumber(bool clear) { char sNum[CMD_MAX_LEN]; char sLeadingzeros[CMD_MAX_LEN]; char sPosition[CMD_MAX_LEN]; @@ -212,10 +295,10 @@ bool CmndTM1637Number(bool clear) { if((position < 0) || (position > (NUM_DIGITS-1))) position = 0; - AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: num=%d"), num); - AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: position=%d"), position); - AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: leadingzeros=%d"), leadingzeros); - AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: length=%d"), length); + AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: num=%d"), modelname, num); + AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: position=%d"), modelname, position); + AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: leadingzeros=%d"), modelname, leadingzeros); + AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: length=%d"), modelname, length); if(clear) clearDisplay(); @@ -227,17 +310,18 @@ bool CmndTM1637Number(bool clear) { char pad = (leadingzeros ? '0': ' '); uint32_t i = position; uint8_t rawBytes[1]; - rawBytes[0] = display->encode(pad); + for(; iNUM_DIGITS) break; - display->printRaw(rawBytes, 1, i); + if(displaytype == TM1637) { rawBytes[0] = disp37->encode(pad); disp37->printRaw(rawBytes, 1, i); } + else if(displaytype == TM1638) disp38->displayASCII(i, pad); } for(uint32_t j = 0; i< position + length; i++, j++) { - if(txt[j] == 0) break; - rawBytes[0] = display->encode(txt[j]); if(i>NUM_DIGITS) break; - display->printRaw(rawBytes, 1, i); + if(txt[j] == 0) break; + if(displaytype == TM1637) { rawBytes[0] = disp37->encode(txt[j]); disp37->printRaw(rawBytes, 1, i); } + else if(displaytype == TM1638) disp38->displayASCII(i, txt[j]); } return true; @@ -251,7 +335,7 @@ bool CmndTM1637Number(bool clear) { * commands: DisplayFloat num [,position {0-(NUM_DIGITS-1)} [,precision {0-NUM_DIGITS} [,length {1 to NUM_DIGITS}]]] * DisplayFloatNC num [,position {0-(NUM_DIGITS-1)} [,precision {0-NUM_DIGITS} [,length {1 to NUM_DIGITS}]]] // "NC" --> "No Clear" \*********************************************************************************************/ -bool CmndTM1637Float(bool clear) { +bool CmndFloat(bool clear) { char sNum[CMD_MAX_LEN]; char sPrecision[CMD_MAX_LEN]; @@ -292,22 +376,36 @@ bool CmndTM1637Float(bool clear) { if((length <= 0) || (length > NUM_DIGITS)) length = NUM_DIGITS; char s[30]; - ext_snprintf_P(s, sizeof(s), PSTR("LOG: TM1637: num=%*_f"), 4, &fnum); + ext_snprintf_P(s, sizeof(s), PSTR("LOG: %s: num=%4_f"), modelname, &fnum); AddLog(LOG_LEVEL_DEBUG, PSTR("%s"), s); - AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: precision=%d"), precision); - AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: length=%d"), length); - uint8_t rawBytes[1]; - for(uint32_t i=0, j=0; iencode(txt[i]); - if(txt[i+1] == '.') { - rawBytes[0] = rawBytes[0] | 128; - i++; - length++; + AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: precision=%d"), modelname, precision); + AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: length=%d"), modelname, length); + + if(displaytype == TM1637) { + uint8_t rawBytes[1]; + for(uint32_t i=0, j=0; iencode(txt[i]); + if(txt[i+1] == '.') { + rawBytes[0] = rawBytes[0] | 128; + i++; + length++; + } + if((j+position) > NUM_DIGITS) break; + disp37->printRaw(rawBytes, 1, j+position); } - if((j+position) > NUM_DIGITS) break; - display->printRaw(rawBytes, 1, j+position); - } + } else if(displaytype == TM1638) { + for(uint32_t i=0, j=0; i 7) break; + if(txt[i] == 0) break; + if(txt[i+1] == '.') { + disp38->displayASCIIwDot(j+position, txt[i]); + i++; + length++; + } + else disp38->displayASCII(j+position, txt[i]); + } + } return true; } @@ -317,7 +415,7 @@ bool CmndTM1637Float(bool clear) { // * Clears the display // * Command: DisplayClear // \*********************************************************************************************/ -bool CmndTM1637Clear(void) { +bool CmndClear(void) { clearDisplay(); sprintf(msg, PSTR("Cleared")); XdrvMailbox.data = msg; @@ -325,10 +423,16 @@ bool CmndTM1637Clear(void) { } +// /*********************************************************************************************\ +// * Clears the display +// \*********************************************************************************************/ void clearDisplay (void) { - unsigned char arr[] = {0}; - AddLog(LOG_LEVEL_DEBUG, PSTR("Clearing digit %d"), NUM_DIGITS); - for(int i=0; iprintRaw(arr, 1, i); + if(displaytype == TM1637) { + unsigned char arr[] = {0}; + for(int i=0; iprintRaw(arr, 1, i); + } else if(displaytype == TM1638) { + for(int i=0; idisplay7Seg(i, 0); + } } @@ -336,9 +440,9 @@ void clearDisplay (void) { * Display scrolling text * Command: DisplayScrollText text \*********************************************************************************************/ -bool CmndTM1637ScrollText(void) { +bool CmndScrollText(void) { - AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: text=%s"), XdrvMailbox.data); + AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: text=%s"), modelname, XdrvMailbox.data); if(XdrvMailbox.data_len > SCROLL_MAX_LEN) { snprintf(msg, sizeof(msg), PSTR("Text too long. Length should be less than %d"), SCROLL_MAX_LEN); @@ -360,7 +464,7 @@ bool CmndTM1637ScrollText(void) { * Sets the scroll delay for scrolling text. * Command: DisplayScrollDelay delay {0-15} // default = 4 \*********************************************************************************************/ -bool CmndTM1637ScrollDelay(void) { +bool CmndScrollDelay(void) { if(scrolldelay<0) scrolldelay=0; scrolldelay = XdrvMailbox.payload; return true; @@ -372,28 +476,31 @@ bool CmndTM1637ScrollDelay(void) { * Scrolls a given string. Called every 50ms \*********************************************************************************************/ void scrollText(void) { - if(scroll) { - iteration++; - if(scrolldelay) iteration = iteration % scrolldelay; - else iteration = 0; - if(iteration) return; + iteration++; + if(scrolldelay) iteration = iteration % scrolldelay; + else iteration = 0; + if(iteration) return; - if(scrollindex > strlen(scrolltext)) { - scroll = false; - scrollindex = 0; - return; - } - bool clr = false; - uint8_t rawBytes[1]; - for(uint32_t i=0, j=scrollindex; i< strlen(scrolltext); i++, j++) { - if(i > (NUM_DIGITS-1)) break; - if(scrolltext[j] == 0) {clr = true;}; - char charToDisp = (clr ? ' ' : scrolltext[j]); - rawBytes[0] = display->encode(charToDisp); - display->printRaw(rawBytes, 1, i); - } - scrollindex++; + if(scrollindex > strlen(scrolltext)) { + scroll = false; + scrollindex = 0; + return; } + bool clr = false; + uint8_t rawBytes[1]; + for(uint32_t i=0, j=scrollindex; i< strlen(scrolltext); i++, j++) { + if(i > (NUM_DIGITS-1)) break; + if(scrolltext[j] == 0) {clr = true;}; + if(displaytype == TM1637) { + char charToDisp = (clr ? ' ' : scrolltext[j]); + rawBytes[0] = disp37->encode(charToDisp); + disp37->printRaw(rawBytes, 1, i); + } else if(displaytype == TM1638) { + disp38->displayASCII(i, (clr ? ' ' : scrolltext[j])); + } + + } + scrollindex++; } @@ -405,7 +512,7 @@ void scrollText(void) { * Displays a horizontal bar graph. Takes a percentage number (0-100) as input * Command: DisplayLevel level {0-100} \*********************************************************************************************/ -bool CmndTM1637Level(void) { +bool CmndLevel(void) { uint16_t val = XdrvMailbox.payload; if((val < LEVEL_MIN) || (val > LEVEL_MAX)) { sprintf(msg, PSTR("Level should be a number in the range [%d, %d]"), LEVEL_MIN, LEVEL_MAX); @@ -414,25 +521,31 @@ bool CmndTM1637Level(void) { } uint8_t totalBars = 2*NUM_DIGITS; - AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: CmndTM1637Level totalBars=%d"), totalBars); + AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: CmndLevel totalBars=%d"), modelname, totalBars); float barsToDisplay = totalBars * val / 100.0f; char txt[5]; ext_snprintf_P(txt, sizeof(txt), PSTR("%*_f"), 1, &barsToDisplay); - AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: CmndTM1637Level barsToDisplay=%s"), txt); + AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: CmndLevel barsToDisplay=%s"), modelname, txt); char s[4]; ext_snprintf_P(s, sizeof(s), PSTR("%*_f"), 0, &barsToDisplay); uint8_t numBars = atoi(s); - AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: CmndTM1637Level numBars=%d"), numBars); + AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: CmndLevel numBars=%d"), modelname, numBars); clearDisplay(); uint8_t rawBytes[1]; for(int i=1; i<=numBars; i++) { uint8_t digit = (i-1) / 2; - AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: CmndTM1637Level digit=%d"), digit); + AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: CmndLevel digit=%d"), modelname, digit); uint8_t value = (((i%2) == 0) ? 54 : 48); - AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: CmndTM1637Level value=%d"), value); - rawBytes[0] = value; - display->printRaw(rawBytes, 1, digit); + AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: CmndLevel value=%d"), modelname, value); + + if(displaytype == TM1637) { + rawBytes[0] = value; + disp37->printRaw(rawBytes, 1, digit); + } else if(displaytype == TM1638) { + disp38->display7Seg(digit, value); + } + } return true; } @@ -446,7 +559,7 @@ bool CmndTM1637Level(void) { * bit 1 is segment B etc. The function may either set the entire display * or any desired part using the length and position parameters. \*********************************************************************************************/ -bool CmndTM1637Raw(void) { +bool CmndRaw(void) { uint8_t DATA[6] = { 0, 0, 0, 0, 0, 0 }; char as[CMD_MAX_LEN]; @@ -496,23 +609,32 @@ bool CmndTM1637Raw(void) { if(position < 0 || position > (NUM_DIGITS-1)) position = 0; - AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: a=%d"), DATA[0]); - AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: b=%d"), DATA[1]); - AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: c=%d"), DATA[2]); - AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: d=%d"), DATA[3]); - AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: e=%d"), DATA[4]); - AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: f=%d"), DATA[5]); + AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: a=%d"), modelname, DATA[0]); + AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: b=%d"), modelname, DATA[1]); + AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: c=%d"), modelname, DATA[2]); + AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: d=%d"), modelname, DATA[3]); + AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: e=%d"), modelname, DATA[4]); + AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: f=%d"), modelname, DATA[5]); - AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: length=%d"), length); - AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: position=%d"), position); + AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: length=%d"), modelname, length); + AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: position=%d"), modelname, position); - uint8_t rawBytes[1]; - for(uint32_t i=position; i(NUM_DIGITS-1)) break; - rawBytes[0] = DATA[i-position]; - display->printRaw(rawBytes, 1, i); + + if(displaytype == TM1637) { + uint8_t rawBytes[1]; + for(uint32_t i=position; i(NUM_DIGITS-1)) break; + rawBytes[0] = DATA[i-position]; + disp37->printRaw(rawBytes, 1, i); + } + } else if(displaytype == TM1638) { + for(uint32_t i=position; i7) break; + disp38->display7Seg(i, DATA[i-position]); + } } + return true; } @@ -524,7 +646,7 @@ bool CmndTM1637Raw(void) { * position parameters without affecting the rest of the display. * Command: DisplayText text [, position {0-(NUM_DIGITS-1)} [,length {1 to NUM_DIGITS}]] \*********************************************************************************************/ -bool CmndTM1637Text(bool clear) { +bool CmndText(bool clear) { char sString[CMD_MAX_LEN + 1]; char sPosition[CMD_MAX_LEN]; char sLength[CMD_MAX_LEN]; @@ -546,9 +668,9 @@ bool CmndTM1637Text(bool clear) { if((position < 0) || (position > (NUM_DIGITS-1))) position = 0; - AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: sString=%s"), sString); - AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: position=%d"), position); - AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: length=%d"), length); + AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: sString=%s"), modelname, sString); + AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: position=%d"), modelname, position); + AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: length=%d"), modelname, length); if(clear) clearDisplay(); @@ -556,18 +678,31 @@ bool CmndTM1637Text(bool clear) { if((length < 0) || (length > NUM_DIGITS)) length = NUM_DIGITS; uint32_t i = position; - uint8_t rawBytes[1]; - for(uint32_t j = 0; i< position + length; i++, j++) { - if(i > (NUM_DIGITS-1)) break; - if(sString[j] == 0) break; - rawBytes[0] = display->encode(sString[j]); - if(sString[j+1] == '.') { - rawBytes[0] = rawBytes[0] | 128; - j++; - } else if(sString[j] == '^') { - rawBytes[0] = 1 | 2 | 32 | 64; + if(displaytype == TM1637) { + uint8_t rawBytes[1]; + for(uint32_t j = 0; i< position + length; i++, j++) { + if(i > (NUM_DIGITS-1)) break; + if(sString[j] == 0) break; + rawBytes[0] = disp37->encode(sString[j]); + if(sString[j+1] == '.') { + rawBytes[0] = rawBytes[0] | 128; + j++; + } else if(sString[j] == '^') { + rawBytes[0] = 1 | 2 | 32 | 64; + } + disp37->printRaw(rawBytes, 1, i); } - display->printRaw(rawBytes, 1, i); + } else if(displaytype == TM1638) { + for(uint32_t j = 0; i< position + length; i++, j++) { + if(i > 7) break; + if(sString[j] == 0) break; + if(sString[j+1] == '.') { + disp38->displayASCIIwDot(i, sString[j]); + j++; + } else if(sString[j] == '^') { + disp38->display7Seg(i, (1 | 2 | 32 | 64)); + } else disp38->displayASCII(i, sString[j]); + } } return true; @@ -578,7 +713,7 @@ bool CmndTM1637Text(bool clear) { * Sets brightness of the display. * Command: DisplayBrightness {0-8} // 0 => off \*********************************************************************************************/ -bool CmndTM1637Brightness(void) { +bool CmndBrightness(void) { uint16_t val = XdrvMailbox.payload; if(ArgC() == 0) { @@ -592,20 +727,30 @@ bool CmndTM1637Brightness(void) { return false; } brightness = val; - - display->setBacklight(brightness*10); + setBrightness(brightness); return true; } +void setBrightness(uint8_t val) { + if((val < BRIGHTNESS_MIN) || (val > BRIGHTNESS_MAX)) val = 5; + Settings.display_dimmer = val; + if(displaytype == TM1637) disp37->setBacklight(val*10); + else if(displaytype == TM1638) disp38->brightness(val); +} + + + + + /*********************************************************************************************\ * Displays a clock. * Command: DisplayClock 1 // 12-hour format * DisplayClock 2 // 24-hour format * DisplayClock 0 // turn off clock and clear \*********************************************************************************************/ -bool CmndTM1637Clock(void) { +bool CmndClock(void) { showClock = XdrvMailbox.payload; @@ -613,8 +758,8 @@ bool CmndTM1637Clock(void) { if(XdrvMailbox.payload > 1) clock24 = true; else if(XdrvMailbox.payload == 1) clock24 = false; - AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: showClock=%d"), showClock); - AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: clock24=%d"), clock24); + AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: showClock=%d"), modelname, showClock); + AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: clock24=%d"), modelname, clock24); if(!showClock) { clearDisplay(); @@ -646,29 +791,144 @@ void showTime() { if(mn < 10) snprintf(tm, sizeof(tm), PSTR("%d0%d"), hr, mn); else snprintf(tm, sizeof(tm), PSTR("%d%d"), hr, mn); } - uint8_t rawBytes[1]; - for(uint32_t i = 0; i< 4; i++) { - rawBytes[0] = display->encode(tm[i]); - if((millis() % 1000) > 500 && (i == 1)) rawBytes[0] = rawBytes[0] | 128; - display->printRaw(rawBytes, 1, i); + + if(displaytype == TM1637) { + uint8_t rawBytes[1]; + for(uint32_t i = 0; i< 4; i++) { + rawBytes[0] = disp37->encode(tm[i]); + if((millis() % 1000) > 500 && (i == 1)) rawBytes[0] = rawBytes[0] | 128; + disp37->printRaw(rawBytes, 1, i); + } + } else if(displaytype == TM1638) { + for(uint32_t i = 0; i< 4; i++) { + if((millis() % 1000) > 500 && (i == 1)) disp38->displayASCIIwDot(i, tm[i]); + else disp38->displayASCII(i, tm[i]); + } } + +} + + + + +/*********************************************************************************************\ +* Sets all LEDs of the display. +* Command: DisplaySetLEDs {0-255} +\*********************************************************************************************/ +bool CmndSetLEDs(void) { + if(displaytype != TM1638) { + sprintf(msg, PSTR("Command not valid for DisplayType %d"), displaytype); + XdrvMailbox.data = msg; + return false; + } + if(ArgC() == 0) XdrvMailbox.payload = 0; + uint16_t val = XdrvMailbox.payload; + if((val < LED_MIN) || (val > LED_MAX)) { + sprintf(msg, PSTR("Set LEDs value should be a number in the range [%d, %d]"), LED_MIN, LED_MAX); + XdrvMailbox.data = msg; + return false; + } + disp38->setLEDs(val << 8); + return true; +} + + +/*********************************************************************************************\ +* Sets an LED at specified position. +* Command: DisplaySetLED position {0-7}, value {0|1} +\*********************************************************************************************/ +bool CmndSetLED(void) { + if(displaytype != TM1638) { + sprintf(msg, PSTR("Command not valid for DisplayType %d"), displaytype); + XdrvMailbox.data = msg; + return false; + } + if(ArgC() < 2) { + sprintf(msg, PSTR("Set LED requires two comma-separated numbers as arguments")); + XdrvMailbox.data = msg; + return false; + } + + char sVal[CMD_MAX_LEN]; + char sPos[CMD_MAX_LEN]; + uint32_t position = 0; + uint32_t value = 0; + + switch (ArgC()) + { + case 2 : + subStr(sVal, XdrvMailbox.data, ",", 2); + value = atoi(sVal); + case 1 : + subStr(sPos, XdrvMailbox.data, ",", 1); + position = atoi(sPos); + } + + + if((position < POSITION_MIN) || (position > POSITION_MAX)) { + sprintf(msg, PSTR("First argument, position should be in the range [%d, %d]"), POSITION_MIN, POSITION_MAX); + XdrvMailbox.data = msg; + return false; + } + + AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1638: position=%d"), position); + AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1638: value=%d"), value); + + disp38->setLED(position, value); + return true; +} + + +/*********************************************************************************************\ +* Reads the button states. Called every 50ms +\*********************************************************************************************/ +bool readButtons(void) { + buttons = disp38->readButtons(); + if(prevbuttons != buttons) { + prevbuttons = buttons; + if(!buttons) return true; + if(buttons) { + Response_P(PSTR("{\"TM1638_BUTTONS\":%d}"), buttons); + MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR("BUTTONS")); + AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1638: buttons changed: %d"), buttons); + for(int i=0; i<8; i++) { + if(buttons & (1<setLED(i, (1 + SwitchGetVirtual(i)) % 2 ); + } + } + + SwitchHandler(1); + } + } + return true; } /*********************************************************************************************\ -* This function is called for all TM1637 Display functions. +* Returns the current state of the buttons as a decimal representation of the button states +* Command: DisplayButtons \*********************************************************************************************/ -bool TM1637Cmd(uint8_t fn) { +bool CmndButtons(void) { + if(displaytype != TM1638) { + sprintf(msg, PSTR("Command not valid for DisplayType %d"), displaytype); + XdrvMailbox.data = msg; + return false; + } + AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1638: buttons=%d"), buttons); + XdrvMailbox.payload = buttons; + return true; +} + + + + + +/*********************************************************************************************\ +* This function is called for all Display functions. +\*********************************************************************************************/ +bool MainFunc(uint8_t fn) { bool result = false; - NUM_DIGITS = Settings.display_size; - if(prev_num_digits != NUM_DIGITS) { // Cleck for change of display size, and re-init the library - AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: Size changed. Re-initializing library...")); - display = new SevenSegmentTM1637(Pin(GPIO_SSPI_SCLK), Pin(GPIO_SSPI_MOSI) ); - display->begin(NUM_DIGITS, 1); - display->setBacklight(40); - clearDisplay(); - prev_num_digits = NUM_DIGITS; - AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: Re-initialized library")); - } if(XdrvMailbox.data_len > CMD_MAX_LEN) { sprintf(msg, PSTR("Command text too long. Please limit it to %d characters"), CMD_MAX_LEN); @@ -678,43 +938,52 @@ bool TM1637Cmd(uint8_t fn) { switch (fn) { case FUNC_DISPLAY_CLEAR: - result = CmndTM1637Clear(); + result = CmndClear(); break; case FUNC_DISPLAY_NUMBER : - result = CmndTM1637Number(true); + result = CmndNumber(true); break; case FUNC_DISPLAY_NUMBERNC : - result = CmndTM1637Number(false); + result = CmndNumber(false); break; case FUNC_DISPLAY_FLOAT : - result = CmndTM1637Float(true); + result = CmndFloat(true); break; case FUNC_DISPLAY_FLOATNC : - result = CmndTM1637Float(false); + result = CmndFloat(false); break; case FUNC_DISPLAY_BRIGHTNESS: - result = CmndTM1637Brightness(); + result = CmndBrightness(); break; case FUNC_DISPLAY_RAW: - result = CmndTM1637Raw(); + result = CmndRaw(); break; case FUNC_DISPLAY_SEVENSEG_TEXT: - result = CmndTM1637Text(true); + result = CmndText(true); break; case FUNC_DISPLAY_SEVENSEG_TEXTNC: - result = CmndTM1637Text(false); + result = CmndText(false); break; case FUNC_DISPLAY_LEVEL: - result = CmndTM1637Level(); + result = CmndLevel(); break; case FUNC_DISPLAY_SCROLLTEXT: - result = CmndTM1637ScrollText(); + result = CmndScrollText(); break; case FUNC_DISPLAY_SCROLLDELAY: - result = CmndTM1637ScrollDelay(); + result = CmndScrollDelay(); break; + case FUNC_DISPLAY_SETLEDS: + result = CmndSetLEDs(); + break; + case FUNC_DISPLAY_SETLED: + result = CmndSetLED(); + break; + case FUNC_DISPLAY_BUTTONS: + result = CmndButtons(); + break; case FUNC_DISPLAY_CLOCK: - result = CmndTM1637Clock(); + result = CmndClock(); break; } @@ -725,23 +994,26 @@ bool TM1637Cmd(uint8_t fn) { /*********************************************************************************************\ * Interface \*********************************************************************************************/ - bool Xdsp15(uint8_t function) { bool result = false; - if (FUNC_DISPLAY_INIT_DRIVER == function) { - result = TM1637Init(); // init + if(function == FUNC_DISPLAY_MODEL) { + return true; } - else if (XDSP_15 == Settings.display_model) { + + if (Settings.display_model == XDSP_15) { switch (function) { - case FUNC_DISPLAY_MODEL: - AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: FUNC_DISPLAY_MODEL")); - result = true; + case FUNC_DISPLAY_INIT_DRIVER: + result = DriverInit(); // init break; case FUNC_DISPLAY_INIT: - CmndTM1637Clear(); - AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: FUNC_DISPLAY_INIT")); + AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: FUNC_DISPLAY_INIT: Display depends on DisplayType, currently %d"), modelname, Settings.display_type); + result = true; + break; + case FUNC_DISPLAY_TYPE: + AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: FUNC_DISPLAY_TYPE: DisplayType set to %d, restarting to take effect ..."), modelname, Settings.display_type); + TasmotaGlobal.restart_flag = 2; break; case FUNC_DISPLAY_SEVENSEG_TEXT: case FUNC_DISPLAY_CLEAR: @@ -755,14 +1027,16 @@ bool Xdsp15(uint8_t function) case FUNC_DISPLAY_SEVENSEG_TEXTNC: case FUNC_DISPLAY_SCROLLTEXT: case FUNC_DISPLAY_SCROLLDELAY: + case FUNC_DISPLAY_SETLEDS: + case FUNC_DISPLAY_SETLED: + case FUNC_DISPLAY_BUTTONS: case FUNC_DISPLAY_CLOCK: - result = TM1637Cmd(function); + result = MainFunc(function); break; case FUNC_DISPLAY_EVERY_50_MSECOND: - scrollText(); - if(showClock) { - showTime(); - } + if(scroll) scrollText(); + if(showClock) showTime(); + if(displaytype == TM1638) readButtons(); break; } } From ac14dab680903851abb7917693cb5757f2eecca9 Mon Sep 17 00:00:00 2001 From: Ajith Vasudevan Date: Fri, 19 Feb 2021 15:28:16 +0530 Subject: [PATCH 02/13] Better input validation error messages --- tasmota/xdrv_13_display.ino | 13 ++--- tasmota/xdsp_15_tm1637.ino | 97 +++++++++++++++++++------------------ 2 files changed, 54 insertions(+), 56 deletions(-) diff --git a/tasmota/xdrv_13_display.ino b/tasmota/xdrv_13_display.ino index fcecc087c..54aaca31c 100755 --- a/tasmota/xdrv_13_display.ino +++ b/tasmota/xdrv_13_display.ino @@ -1803,7 +1803,6 @@ void CmndDisplayBrightness(void) result = XdspCall(FUNC_DISPLAY_BRIGHTNESS); } if(result) ResponseCmndNumber(XdrvMailbox.payload); - else ResponseCmndChar(XdrvMailbox.data); } void CmndDisplayRaw(void) @@ -1821,7 +1820,6 @@ void CmndDisplayLevel(void) result = XdspCall(FUNC_DISPLAY_LEVEL); } if(result) ResponseCmndNumber(XdrvMailbox.payload); - else ResponseCmndChar(XdrvMailbox.data); } void CmndDisplaySevensegText(void) @@ -1871,7 +1869,6 @@ void CmndDisplaySetLEDs(void) result = XdspCall(FUNC_DISPLAY_SETLEDS); } if(result) ResponseCmndNumber(XdrvMailbox.payload); - else ResponseCmndChar(XdrvMailbox.data); } @@ -1882,26 +1879,24 @@ void CmndDisplaySetLED(void) result = XdspCall(FUNC_DISPLAY_SETLED); } if(result) ResponseCmndNumber(XdrvMailbox.payload); - else ResponseCmndChar(XdrvMailbox.data); } void CmndDisplayButtons(void) { bool result = false; if (!renderer) { - result = XdspCall(FUNC_DISPLAY_BUTTONS); + XdspCall(FUNC_DISPLAY_BUTTONS); } - if(result) ResponseCmndNumber(XdrvMailbox.payload); - else ResponseCmndChar(XdrvMailbox.data); } void CmndDisplayScrollText(void) { + bool result = false; if (!renderer) { - XdspCall(FUNC_DISPLAY_SCROLLTEXT); + result = XdspCall(FUNC_DISPLAY_SCROLLTEXT); } - ResponseCmndChar(XdrvMailbox.data); + if(result) ResponseCmndChar(XdrvMailbox.data); } diff --git a/tasmota/xdsp_15_tm1637.ino b/tasmota/xdsp_15_tm1637.ino index 13260f4a7..a97aa2d4c 100644 --- a/tasmota/xdsp_15_tm1637.ino +++ b/tasmota/xdsp_15_tm1637.ino @@ -21,7 +21,9 @@ #ifdef USE_DISPLAY_TM1637 /*********************************************************************************************\ This driver enables the display of numbers (both integers and floats) and basic text - on the inexpensive TM1637- and TM1638-based seven-segment modules. + on the inexpensive TM1637- and TM1638-based seven-segment modules. Additionally, for the TM1638, + it allows the TM1638 LEDs to be toggled using its buttons. + Useful STAT messages are also sent when the TM1638 buttons are pressed. Raw segments can also be displayed. @@ -164,11 +166,15 @@ Commands specific to TM1638 DisplayButtons - Causes the current state of the buttons to be returned as a "STAT" message of the form stat/TM1638/RESULT = {"DisplayButtons": } - The button value is the decimal representation of the bit-array that constitutes the button states. For example, if the 5th button is pressed and the - DisplayButtons command is issued, the response will be stat/TM1638/RESULT = {"DisplayButtons": 16} because 16 => 2^(5-1) - if the 2nd and 3rd buttons are pressed together and the DisplayButtons command is issued, the response will be - stat/TM1638/RESULT = {"DisplayButtons": 6} because 6 => 2^(2-1) + 2^(3-1) + Causes the current state of the buttons/LEDs to be returned as a "STAT" message of the following form: + stat/TM1638/RESULT = {"DisplayButtons": {"S1":, "S2":, "S3":, "S4":, "S5":, "S6":, "S7":, "S8":, "Array": [,,,,,,,], "Byte": }} + where , , ... are the states of each of the buttons/LEDs, and is the decimal representation + of the bit-array that constitutes these states. + + For example, if the 5th button is pressed to turn ON LED5, and the "DisplayButtons" command is issued, + the response STAT message will be of the form: + stat/TM1638/RESULT = {"DisplayButtons": {"S1":0, "S2":0, "S3":0, "S4":0, "S5":1, "S6":0, "S7":0, "S8":0, "Array": [0,0,0,0,1,0,0,0], "Byte": 16}} + because 16 => 2^(5-1) @@ -177,12 +183,20 @@ Commands specific to TM1638 When this driver is initialized with "DisplayType 2" (TM1638), the buttons on the TM1638 module can be used to toggle the corresponding LEDs. - In addition, if SwitchTopic is set to some value, then for each button press, a TOGGLE for that switch number is sent. + In addition, for each button press, a STAT message of the following form is sent: - For example, if Topic = "TM1638" and SwitchTopic = "TEST_TM1638", and if S3 is pressed, then, + stat//RESULT = {"TM1638_BUTTON":} - 1) a STAT message is sent : stat/TM1638/RESULT = {"TM1638_BUTTONS":4} // (4 = 2^(3-1)) - and 2) a TOGGLE command is sent: cmnd/TEST/POWER3 = TOGGLE + where = button index (starting at 1) + = state of the corresponding LED. It can be "ON" or "OFF" + + For example, if Button3 is pressed, LED3 would light up and a STAT message is sent as follows: + + stat/TM1638/RESULT = {"TM1638_BUTTON3":"ON"} + + Pressing Button3 again would turn OFF LED3 and a STAT message is sent as follows: + + stat/TM1638/RESULT = {"TM1638_BUTTON3":"OFF"} \*********************************************************************************************/ @@ -200,6 +214,7 @@ bool clock24 = false; char tm[5]; char msg[60]; uint8_t buttons; +bool LED[8] = {false, false, false, false, false, false, false, false}; uint8_t prevbuttons; uint32_t NUM_DIGITS = 4; uint32_t prev_num_digits = 4; @@ -445,8 +460,7 @@ bool CmndScrollText(void) { AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: text=%s"), modelname, XdrvMailbox.data); if(XdrvMailbox.data_len > SCROLL_MAX_LEN) { - snprintf(msg, sizeof(msg), PSTR("Text too long. Length should be less than %d"), SCROLL_MAX_LEN); - XdrvMailbox.data = msg; + Response_P(PSTR("{\"Error\":\"Text too long. Length should be less than %d\"}"), SCROLL_MAX_LEN); return false; } else { snprintf(scrolltext, sizeof(scrolltext), PSTR("%s"), XdrvMailbox.data); @@ -515,8 +529,7 @@ void scrollText(void) { bool CmndLevel(void) { uint16_t val = XdrvMailbox.payload; if((val < LEVEL_MIN) || (val > LEVEL_MAX)) { - sprintf(msg, PSTR("Level should be a number in the range [%d, %d]"), LEVEL_MIN, LEVEL_MAX); - XdrvMailbox.data = msg; + Response_P(PSTR("{\"Error\":\"Level should be a number in the range [%d, %d]\"}"), LEVEL_MIN, LEVEL_MAX); return false; } @@ -535,10 +548,7 @@ bool CmndLevel(void) { uint8_t rawBytes[1]; for(int i=1; i<=numBars; i++) { uint8_t digit = (i-1) / 2; - AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: CmndLevel digit=%d"), modelname, digit); uint8_t value = (((i%2) == 0) ? 54 : 48); - AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: CmndLevel value=%d"), modelname, value); - if(displaytype == TM1637) { rawBytes[0] = value; disp37->printRaw(rawBytes, 1, digit); @@ -722,8 +732,7 @@ bool CmndBrightness(void) { } if((val < BRIGHTNESS_MIN) || (val > BRIGHTNESS_MAX)) { - sprintf(msg, PSTR("Brightness should be a number in the range [%d, %d]"), BRIGHTNESS_MIN, BRIGHTNESS_MAX); - XdrvMailbox.data = msg; + Response_P(PSTR("{\"Error\":\"Brightness should be a number in the range [%d, %d]\"}"), BRIGHTNESS_MIN, BRIGHTNESS_MAX); return false; } brightness = val; @@ -817,17 +826,16 @@ void showTime() { \*********************************************************************************************/ bool CmndSetLEDs(void) { if(displaytype != TM1638) { - sprintf(msg, PSTR("Command not valid for DisplayType %d"), displaytype); - XdrvMailbox.data = msg; + Response_P(PSTR("{\"Error\":\"Command not valid for DisplayType %d\"}"), displaytype); return false; } if(ArgC() == 0) XdrvMailbox.payload = 0; uint16_t val = XdrvMailbox.payload; if((val < LED_MIN) || (val > LED_MAX)) { - sprintf(msg, PSTR("Set LEDs value should be a number in the range [%d, %d]"), LED_MIN, LED_MAX); - XdrvMailbox.data = msg; - return false; - } + Response_P(PSTR("{\"Error\":\"Set LEDs value should be a number in the range [%d, %d]\"}"), LED_MIN, LED_MAX); + return false; + } + for(uint8_t i=0; i<8; i++) LED[i] = ((val & 2^i) >> i); disp38->setLEDs(val << 8); return true; } @@ -839,13 +847,11 @@ bool CmndSetLEDs(void) { \*********************************************************************************************/ bool CmndSetLED(void) { if(displaytype != TM1638) { - sprintf(msg, PSTR("Command not valid for DisplayType %d"), displaytype); - XdrvMailbox.data = msg; + Response_P(PSTR("{\"Error\":\"Command not valid for DisplayType %d\"}"), displaytype); return false; } if(ArgC() < 2) { - sprintf(msg, PSTR("Set LED requires two comma-separated numbers as arguments")); - XdrvMailbox.data = msg; + Response_P(PSTR("{\"Error\":\"Set LED requires two comma-separated numbers as arguments\"}")); return false; } @@ -866,14 +872,14 @@ bool CmndSetLED(void) { if((position < POSITION_MIN) || (position > POSITION_MAX)) { - sprintf(msg, PSTR("First argument, position should be in the range [%d, %d]"), POSITION_MIN, POSITION_MAX); - XdrvMailbox.data = msg; - return false; + Response_P(PSTR("{\"Error\":\"First argument, position should be in the range [%d, %d]\"}"), POSITION_MIN, POSITION_MAX); + return false; } AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1638: position=%d"), position); AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1638: value=%d"), value); + LED[position] = value; disp38->setLED(position, value); return true; } @@ -888,18 +894,15 @@ bool readButtons(void) { prevbuttons = buttons; if(!buttons) return true; if(buttons) { - Response_P(PSTR("{\"TM1638_BUTTONS\":%d}"), buttons); - MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR("BUTTONS")); - AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1638: buttons changed: %d"), buttons); for(int i=0; i<8; i++) { - if(buttons & (1<setLED(i, (1 + SwitchGetVirtual(i)) % 2 ); + if(buttons & (1<setLED(i, LED[i]); + Response_P(PSTR("{\"TM1638_BUTTON%d\":\"%s\"}"), i+1, (LED[i]?PSTR("ON"):PSTR("OFF"))); + MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR("BUTTONS")); } } - - SwitchHandler(1); } } return true; @@ -911,12 +914,13 @@ bool readButtons(void) { \*********************************************************************************************/ bool CmndButtons(void) { if(displaytype != TM1638) { - sprintf(msg, PSTR("Command not valid for DisplayType %d"), displaytype); - XdrvMailbox.data = msg; + Response_P(PSTR("{\"Error\":\"Command not valid for DisplayType %d\"}"), displaytype); return false; } AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1638: buttons=%d"), buttons); - XdrvMailbox.payload = buttons; + uint8_t byte = LED[0]<<0 | LED[1]<<1 | LED[2]<<2 | LED[3]<<3 | LED[4]<<4 | LED[5]<<5 | LED[6]<<6 | LED[7]<<7; + Response_P(PSTR("{\"DisplayButtons\": {\"S1\":%d, \"S2\":%d, \"S3\":%d, \"S4\":%d, \"S5\":%d, \"S6\":%d, \"S7\":%d, \"S8\":%d, \"Array\": [%d,%d,%d,%d,%d,%d,%d,%d], \"Byte\": %d}}"), + LED[0], LED[1], LED[2], LED[3], LED[4], LED[5], LED[6], LED[7], LED[0], LED[1], LED[2], LED[3], LED[4], LED[5], LED[6], LED[7], byte); return true; } @@ -931,9 +935,8 @@ bool MainFunc(uint8_t fn) { bool result = false; if(XdrvMailbox.data_len > CMD_MAX_LEN) { - sprintf(msg, PSTR("Command text too long. Please limit it to %d characters"), CMD_MAX_LEN); - XdrvMailbox.data = msg; - return result; + Response_P(PSTR("{\"Error\":\"Command text too long. Please limit it to %d characters\"}"), CMD_MAX_LEN); + return false; } switch (fn) { From 2f6cacc69bb2c0f2347f1a4d7e8f348822ee4df3 Mon Sep 17 00:00:00 2001 From: Ajith Vasudevan Date: Fri, 19 Feb 2021 18:39:42 +0530 Subject: [PATCH 03/13] Disabled Clock display automatically when a new command is issued --- tasmota/xdsp_15_tm1637.ino | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/tasmota/xdsp_15_tm1637.ino b/tasmota/xdsp_15_tm1637.ino index a97aa2d4c..11d52640f 100644 --- a/tasmota/xdsp_15_tm1637.ino +++ b/tasmota/xdsp_15_tm1637.ino @@ -39,12 +39,17 @@ CLK hardware pin --> "SSPI SCLK" STB hardware pin --> "SSPI MISO" (Only for TM1638) - - Once the device restarts the following "Display" commands should become available: - In case you get a stat//RESULT = {"Command":"Unknown"} result for any of these commands, - please ensure that your DisplayModel is set to 15 using the command "DisplayModel 15" - + Once the GPIO configuration is saved and the ESP8266/ESP32 module restarts, set the Display Model to 15 + using the command "DisplayModel 15" + + After this, depending upon your display variant, set your Display Type to 0, 1 or 2 using the command + "DisplayType 0" // for the 4-digit TM1637 + or "DisplayType 1" // for the 6-digit TM1637 + or "DisplayType 2" // for the 8-digit TM1638 + + After the ESP8266/ESP32 module restarts again, the following "Display" commands can be used: + DisplayType type {0|1|2} @@ -1032,8 +1037,9 @@ bool Xdsp15(uint8_t function) case FUNC_DISPLAY_SCROLLDELAY: case FUNC_DISPLAY_SETLEDS: case FUNC_DISPLAY_SETLED: - case FUNC_DISPLAY_BUTTONS: + case FUNC_DISPLAY_BUTTONS: case FUNC_DISPLAY_CLOCK: + showClock = false; result = MainFunc(function); break; case FUNC_DISPLAY_EVERY_50_MSECOND: From e2ea80ad8dc9b1b227387e24813c28a58a5ee8a7 Mon Sep 17 00:00:00 2001 From: Ajith Vasudevan Date: Sun, 21 Feb 2021 10:34:40 +0530 Subject: [PATCH 04/13] made brightness range consistent across display types --- tasmota/xdsp_15_tm1637.ino | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/tasmota/xdsp_15_tm1637.ino b/tasmota/xdsp_15_tm1637.ino index 11d52640f..57e087935 100644 --- a/tasmota/xdsp_15_tm1637.ino +++ b/tasmota/xdsp_15_tm1637.ino @@ -95,9 +95,9 @@ - DisplayBrightness num {0-8} + DisplayBrightness num {1-8} - Set brightness (0 (off) to 8) command e.g., "DisplayBrightness 2" + Set brightness (1 to 8) command e.g., "DisplayBrightness 2" @@ -231,9 +231,8 @@ uint32_t brightness = 5; char modelname[8]; enum displaytypes { TM1637, TM1638 }; uint8_t displaytype = TM1637; -bool modechanged = false; -#define BRIGHTNESS_MIN 0 // Display OFF +#define BRIGHTNESS_MIN 1 #define BRIGHTNESS_MAX 8 #define CMD_MAX_LEN 55 #define LEVEL_MIN 0 @@ -271,7 +270,6 @@ bool DriverInit(void) { brightness = (Settings.display_dimmer ? Settings.display_dimmer : brightness); setBrightness(brightness); driverinited = true; - modechanged = false; AddLog(LOG_LEVEL_INFO, PSTR("DSP: %s display driver initialized with %d digits (DisplayType %d)"), modelname, NUM_DIGITS, Settings.display_type); } @@ -726,7 +724,7 @@ bool CmndText(bool clear) { /*********************************************************************************************\ * Sets brightness of the display. -* Command: DisplayBrightness {0-8} // 0 => off +* Command: DisplayBrightness {1-8} \*********************************************************************************************/ bool CmndBrightness(void) { @@ -751,7 +749,7 @@ void setBrightness(uint8_t val) { if((val < BRIGHTNESS_MIN) || (val > BRIGHTNESS_MAX)) val = 5; Settings.display_dimmer = val; if(displaytype == TM1637) disp37->setBacklight(val*10); - else if(displaytype == TM1638) disp38->brightness(val); + else if(displaytype == TM1638) disp38->brightness(val-1); } From 5009a3fae9e23cb9e9935d91b78e97d9c8d5659b Mon Sep 17 00:00:00 2001 From: Ajith Vasudevan Date: Sun, 21 Feb 2021 11:07:12 +0530 Subject: [PATCH 05/13] Fixed bug where clock is disabled after a brightness change --- tasmota/xdsp_15_tm1637.ino | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tasmota/xdsp_15_tm1637.ino b/tasmota/xdsp_15_tm1637.ino index 57e087935..da64edb1a 100644 --- a/tasmota/xdsp_15_tm1637.ino +++ b/tasmota/xdsp_15_tm1637.ino @@ -784,6 +784,7 @@ bool CmndClock(void) { * refreshes the time if clock is displayed \*********************************************************************************************/ void showTime() { + AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: showTime()"), modelname); uint8_t hr = RtcTime.hour; uint8_t mn = RtcTime.minute; // uint8_t hr = 1; @@ -1027,17 +1028,17 @@ bool Xdsp15(uint8_t function) case FUNC_DISPLAY_FLOAT: case FUNC_DISPLAY_NUMBERNC: case FUNC_DISPLAY_FLOATNC: - case FUNC_DISPLAY_BRIGHTNESS: case FUNC_DISPLAY_RAW: case FUNC_DISPLAY_LEVEL: case FUNC_DISPLAY_SEVENSEG_TEXTNC: case FUNC_DISPLAY_SCROLLTEXT: case FUNC_DISPLAY_SCROLLDELAY: + case FUNC_DISPLAY_CLOCK: + showClock = false; + case FUNC_DISPLAY_BRIGHTNESS: case FUNC_DISPLAY_SETLEDS: case FUNC_DISPLAY_SETLED: case FUNC_DISPLAY_BUTTONS: - case FUNC_DISPLAY_CLOCK: - showClock = false; result = MainFunc(function); break; case FUNC_DISPLAY_EVERY_50_MSECOND: From db17863828de0f47b99bca825210bb33cb2a6149 Mon Sep 17 00:00:00 2001 From: Ajith Vasudevan Date: Sun, 21 Feb 2021 14:42:12 +0530 Subject: [PATCH 06/13] Removed unwanted log --- tasmota/xdsp_15_tm1637.ino | 1 - 1 file changed, 1 deletion(-) diff --git a/tasmota/xdsp_15_tm1637.ino b/tasmota/xdsp_15_tm1637.ino index da64edb1a..eec946083 100644 --- a/tasmota/xdsp_15_tm1637.ino +++ b/tasmota/xdsp_15_tm1637.ino @@ -784,7 +784,6 @@ bool CmndClock(void) { * refreshes the time if clock is displayed \*********************************************************************************************/ void showTime() { - AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: showTime()"), modelname); uint8_t hr = RtcTime.hour; uint8_t mn = RtcTime.minute; // uint8_t hr = 1; From c5f79aa532bcfeacdef07569cb44febc98bc2afb Mon Sep 17 00:00:00 2001 From: Ajith Vasudevan Date: Mon, 22 Feb 2021 12:04:30 +0530 Subject: [PATCH 07/13] Fixed some logs --- tasmota/xdsp_15_tm1637.ino | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/tasmota/xdsp_15_tm1637.ino b/tasmota/xdsp_15_tm1637.ino index 8f417ce1a..58b376271 100644 --- a/tasmota/xdsp_15_tm1637.ino +++ b/tasmota/xdsp_15_tm1637.ino @@ -751,9 +751,7 @@ bool CmndClock(void) { AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: TM1637Data.show_clock %d, TM1637Data.clock_24 %d"), TM1637Data.show_clock, TM1637Data.clock_24); - if(!TM1637Data.show_clock) { - clearDisplay(); - } + clearDisplay(); return true; } @@ -877,7 +875,7 @@ bool readButtons(void) { if(TM1637Data.buttons) { for(int i=0; i<8; i++) { if(TM1637Data.buttons & (1<setLED(i, TM1637Data.LED[i]); Response_P(PSTR("{\"TM1638_BUTTON%d\":\"%s\"}"), i+1, (TM1637Data.LED[i]?PSTR("ON"):PSTR("OFF"))); @@ -898,7 +896,7 @@ bool CmndButtons(void) { Response_P(PSTR("{\"Error\":\"Command not valid for TM1637Data.display_type %d\"}"), TM1637Data.display_type); return false; } - AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1638: buttons=%d"), TM1637Data.buttons); + AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: TM1638: buttons=%d"), TM1637Data.buttons); uint8_t byte = TM1637Data.LED[0]<<0 | TM1637Data.LED[1]<<1 | TM1637Data.LED[2]<<2 | TM1637Data.LED[3]<<3 | TM1637Data.LED[4]<<4 | TM1637Data.LED[5]<<5 | TM1637Data.LED[6]<<6 | TM1637Data.LED[7]<<7; Response_P(PSTR("{\"DisplayButtons\": {\"S1\":%d, \"S2\":%d, \"S3\":%d, \"S4\":%d, \"S5\":%d, \"S6\":%d, \"S7\":%d, \"S8\":%d, \"Array\": [%d,%d,%d,%d,%d,%d,%d,%d], \"Byte\": %d}}"), TM1637Data.LED[0], TM1637Data.LED[1], TM1637Data.LED[2], TM1637Data.LED[3], TM1637Data.LED[4], TM1637Data.LED[5], TM1637Data.LED[6], TM1637Data.LED[7], TM1637Data.LED[0], @@ -993,11 +991,11 @@ bool Xdsp15(uint8_t function) result = DriverInit(); // init break; case FUNC_DISPLAY_INIT: - AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: FUNC_DISPLAY_INIT: Display depends on TM1637Data.display_type, currently %d"), TM1637Data.model_name, Settings.display_type); + AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: %s: FUNC_DISPLAY_INIT: Display depends on TM1637Data.display_type, currently %d"), TM1637Data.model_name, Settings.display_type); result = true; break; case FUNC_DISPLAY_TYPE: - AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: FUNC_DISPLAY_TYPE: TM1637Data.display_type set to %d, restarting to take effect ..."), TM1637Data.model_name, Settings.display_type); + AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: %s: FUNC_DISPLAY_TYPE: TM1637Data.display_type set to %d, restarting to take effect ..."), TM1637Data.model_name, Settings.display_type); TasmotaGlobal.restart_flag = 2; break; case FUNC_DISPLAY_SEVENSEG_TEXT: From 75699fe203202a2832fbc81d73862828a8cbbc2b Mon Sep 17 00:00:00 2001 From: Ajith Vasudevan Date: Mon, 22 Feb 2021 15:12:48 +0530 Subject: [PATCH 08/13] Removed the need for SPI for TM1637 to work --- tasmota/support_tasmota.ino | 4 +--- tasmota/tasmota.ino | 5 ++++- tasmota/xdrv_13_display.ino | 2 +- tasmota/xdsp_interface.ino | 15 ++++++++++++++- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/tasmota/support_tasmota.ino b/tasmota/support_tasmota.ino index 4742537a2..af9aca1e2 100644 --- a/tasmota/support_tasmota.ino +++ b/tasmota/support_tasmota.ino @@ -1678,9 +1678,7 @@ void GpioInit(void) ValidSpiPinUsed(GPIO_ST7789_DC) || // ST7789 CS may be omitted so chk DC too ValidSpiPinUsed(GPIO_ST7789_CS) || (ValidSpiPinUsed(GPIO_SSD1331_CS) && ValidSpiPinUsed(GPIO_SSD1331_DC)) || - ValidSpiPinUsed(GPIO_SDCARD_CS) || - (ValidSpiPinUsed(GPIO_TM1637CLK) && ValidSpiPinUsed(GPIO_TM1637DIO)) || - (ValidSpiPinUsed(GPIO_TM1638CLK) && ValidSpiPinUsed(GPIO_TM1638DIO) && ValidSpiPinUsed(GPIO_TM1638STB)) + ValidSpiPinUsed(GPIO_SDCARD_CS) ); // If SPI_CS and/or SPI_DC is used they must be valid TasmotaGlobal.spi_enabled = (valid_cs) ? SPI_MOSI_MISO : SPI_NONE; diff --git a/tasmota/tasmota.ino b/tasmota/tasmota.ino index c0b7b4669..7d52e5a44 100644 --- a/tasmota/tasmota.ino +++ b/tasmota/tasmota.ino @@ -147,6 +147,7 @@ struct { bool module_changed; // Indicate module changed since last restart bool wifi_stay_asleep; // Allow sleep only incase of ESP32 BLE bool no_autoexec; // Disable autoexec + bool tm1637_enabled; // TM1637 driver enabled StateBitfield global_state; // Global states (currently Wifi and Mqtt) (8 bits) uint8_t spi_enabled; // SPI configured @@ -227,7 +228,9 @@ void setup(void) { TasmotaGlobal.tele_period = 9999; TasmotaGlobal.active_device = 1; TasmotaGlobal.global_state.data = 0xF; // Init global state (wifi_down, mqtt_down) to solve possible network issues - +#if defined(USE_DISPLAY) && defined(USE_DISPLAY_TM1637) + TasmotaGlobal.tm1637_enabled = true; +#endif RtcRebootLoad(); if (!RtcRebootValid()) { RtcReboot.fast_reboot_count = 0; diff --git a/tasmota/xdrv_13_display.ino b/tasmota/xdrv_13_display.ino index 54aaca31c..fafeb0452 100755 --- a/tasmota/xdrv_13_display.ino +++ b/tasmota/xdrv_13_display.ino @@ -2779,7 +2779,7 @@ bool Xdrv13(uint8_t function) { bool result = false; - if ((TasmotaGlobal.i2c_enabled || TasmotaGlobal.spi_enabled || TasmotaGlobal.soft_spi_enabled) && XdspPresent()) { + if ((TasmotaGlobal.i2c_enabled || TasmotaGlobal.spi_enabled || TasmotaGlobal.soft_spi_enabled || TasmotaGlobal.tm1637_enabled) && XdspPresent()) { switch (function) { case FUNC_PRE_INIT: DisplayInitDriver(); diff --git a/tasmota/xdsp_interface.ino b/tasmota/xdsp_interface.ino index 3ca49f3d6..42907ae15 100644 --- a/tasmota/xdsp_interface.ino +++ b/tasmota/xdsp_interface.ino @@ -17,7 +17,7 @@ along with this program. If not, see . */ -#if defined(USE_I2C) || defined(USE_SPI) +#if defined(USE_I2C) || defined(USE_SPI) || defined(USE_DISPLAY_TM1637) #ifdef USE_DISPLAY #ifdef XFUNC_PTR_IN_ROM @@ -26,6 +26,8 @@ bool (* const xdsp_func_ptr[])(uint8_t) PROGMEM = { // Display Function Pointe bool (* const xdsp_func_ptr[])(uint8_t) = { // Display Function Pointers #endif +#if defined(USE_I2C) || defined(USE_SPI) + #ifdef XDSP_01 &Xdsp01, #endif @@ -82,10 +84,18 @@ bool (* const xdsp_func_ptr[])(uint8_t) = { // Display Function Pointers &Xdsp14, #endif +#endif // #if defined(USE_I2C) || defined(USE_SPI) + +#ifdef USE_DISPLAY_TM1637 + #ifdef XDSP_15 &Xdsp15, #endif +#endif // USE_DISPLAY_TM1637 + +#if defined(USE_I2C) || defined(USE_SPI) + #ifdef XDSP_16 &Xdsp16, #endif @@ -153,6 +163,9 @@ bool (* const xdsp_func_ptr[])(uint8_t) = { // Display Function Pointers #ifdef XDSP_32 &Xdsp32 #endif + +#endif // #if defined(USE_I2C) || defined(USE_SPI) + }; const uint8_t xdsp_present = sizeof(xdsp_func_ptr) / sizeof(xdsp_func_ptr[0]); // Number of drivers found From f16f2c187936f2f0fa5dcbcfa6c44256a1397726 Mon Sep 17 00:00:00 2001 From: Ajith Vasudevan Date: Tue, 23 Feb 2021 12:52:05 +0530 Subject: [PATCH 09/13] Fixed minor bug in DisplayScrollText --- tasmota/xdsp_15_tm1637.ino | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/tasmota/xdsp_15_tm1637.ino b/tasmota/xdsp_15_tm1637.ino index 58b376271..bba883711 100644 --- a/tasmota/xdsp_15_tm1637.ino +++ b/tasmota/xdsp_15_tm1637.ino @@ -464,6 +464,7 @@ bool CmndScrollText(void) { XdrvMailbox.data = TM1637Data.msg; return false; } else { + snprintf(TM1637Data.scroll_text, sizeof(TM1637Data.scroll_text), PSTR(" ")); snprintf(TM1637Data.scroll_text, sizeof(TM1637Data.scroll_text), PSTR("%s"), XdrvMailbox.data); TM1637Data.scroll_text[XdrvMailbox.data_len] = 0; TM1637Data.scroll_index = 0; @@ -480,6 +481,10 @@ bool CmndScrollText(void) { * Command: DisplayTM1637Data.scroll_delay delay {0-15} // default = 4 \*********************************************************************************************/ bool CmndScrollDelay(void) { + if(ArgC() == 0) { + XdrvMailbox.payload = TM1637Data.scroll_delay; + return true; + } if(TM1637Data.scroll_delay<0) TM1637Data.scroll_delay=0; TM1637Data.scroll_delay = XdrvMailbox.payload; return true; @@ -501,17 +506,28 @@ void scrollText(void) { TM1637Data.scroll_index = 0; return; } - bool clr = false; uint8_t rawBytes[1]; - for(uint32_t i=0, j=TM1637Data.scroll_index; i< strlen(TM1637Data.scroll_text); i++, j++) { - if(i > (TM1637Data.num_digits-1)) break; - if(TM1637Data.scroll_text[j] == 0) {clr = true;}; + for(uint32_t i=0, j=TM1637Data.scroll_index; i< 1 + strlen(TM1637Data.scroll_text); i++, j++) { + if(i > (TM1637Data.num_digits-1)) { break; } + rawBytes[0] = tm1637display->encode(TM1637Data.scroll_text[j]); + bool dotSkipped = false; + if(TM1637Data.scroll_text[j+1] == '.') { + dotSkipped = true; + rawBytes[0] = rawBytes[0] | 128; + j++; + } else if(TM1637Data.scroll_text[j] == '^') { + rawBytes[0] = 1 | 2 | 32 | 64; + } + if(!dotSkipped && TM1637Data.scroll_text[j] == '.') { + j++; + TM1637Data.scroll_index++; + rawBytes[0] = tm1637display->encode(TM1637Data.scroll_text[j]); + } + if(TM1637Data.scroll_text[j+1] == '.') { rawBytes[0] = rawBytes[0] | 128; } if(TM1637Data.display_type == TM1637) { - char charToDisp = (clr ? ' ' : TM1637Data.scroll_text[j]); - rawBytes[0] = tm1637display->encode(charToDisp); tm1637display->printRaw(rawBytes, 1, i); } else if(TM1637Data.display_type == TM1638) { - tm1638display->displayASCII(i, (clr ? ' ' : TM1637Data.scroll_text[j])); + tm1638display->display7Seg(i, rawBytes[0]); } } @@ -676,12 +692,15 @@ bool CmndText(bool clear) { if(i > (TM1637Data.num_digits-1)) break; if(sString[j] == 0) break; rawBytes[0] = tm1637display->encode(sString[j]); + bool dotSkipped = false; if(sString[j+1] == '.') { + dotSkipped = true; rawBytes[0] = rawBytes[0] | 128; j++; } else if(sString[j] == '^') { rawBytes[0] = 1 | 2 | 32 | 64; } + if(!dotSkipped && sString[j] == '.') rawBytes[0] = 128; tm1637display->printRaw(rawBytes, 1, i); } } else if(TM1637Data.display_type == TM1638) { From 7a85a0e88e52f3a76d779322a36dcfb37c156622 Mon Sep 17 00:00:00 2001 From: Ajith Vasudevan Date: Wed, 3 Mar 2021 18:15:27 +0530 Subject: [PATCH 10/13] Now using Settings.display_options instead of display_type --- tasmota/xdsp_15_tm1637.ino | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tasmota/xdsp_15_tm1637.ino b/tasmota/xdsp_15_tm1637.ino index bba883711..614bc8c96 100644 --- a/tasmota/xdsp_15_tm1637.ino +++ b/tasmota/xdsp_15_tm1637.ino @@ -258,9 +258,9 @@ bool DriverInit(void) { if(Settings.display_model == XDSP_15) { if(TM1637Data.driver_inited) return true; - if(Settings.display_type == 2) { TM1637Data.num_digits = 8; TM1637Data.display_type = TM1638; } - else if(Settings.display_type == 1) { TM1637Data.num_digits = 6; TM1637Data.display_type = TM1637; } - else { Settings.display_type = 0; TM1637Data.num_digits = 4; TM1637Data.display_type = TM1637; } + if(Settings.display_options.data == 2) { TM1637Data.num_digits = 8; TM1637Data.display_type = TM1638; } + else if(Settings.display_options.data == 1) { TM1637Data.num_digits = 6; TM1637Data.display_type = TM1637; } + else { Settings.display_options.data = 0; TM1637Data.num_digits = 4; TM1637Data.display_type = TM1637; } if(TM1637Data.display_type == TM1637) { strcpy(TM1637Data.model_name, "TM1637"); @@ -277,7 +277,7 @@ bool DriverInit(void) { TM1637Data.brightness = (Settings.display_dimmer ? Settings.display_dimmer : TM1637Data.brightness); setBrightness(TM1637Data.brightness); TM1637Data.driver_inited = true; - AddLog(LOG_LEVEL_INFO, PSTR("DSP: %s display driver initialized with %d digits (DisplayType %d)"), TM1637Data.model_name, TM1637Data.num_digits, Settings.display_type); + AddLog(LOG_LEVEL_INFO, PSTR("DSP: %s display driver initialized with %d digits (DisplayType %d)"), TM1637Data.model_name, TM1637Data.num_digits, Settings.display_options.data); } return true; @@ -1010,11 +1010,11 @@ bool Xdsp15(uint8_t function) result = DriverInit(); // init break; case FUNC_DISPLAY_INIT: - AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: %s: FUNC_DISPLAY_INIT: Display depends on TM1637Data.display_type, currently %d"), TM1637Data.model_name, Settings.display_type); + AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: %s: FUNC_DISPLAY_INIT: Display depends on TM1637Data.display_type, currently %d"), TM1637Data.model_name, Settings.display_options.data); result = true; break; case FUNC_DISPLAY_TYPE: - AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: %s: FUNC_DISPLAY_TYPE: TM1637Data.display_type set to %d, restarting to take effect ..."), TM1637Data.model_name, Settings.display_type); + AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: %s: FUNC_DISPLAY_TYPE: TM1637Data.display_type set to %d, restarting to take effect ..."), TM1637Data.model_name, Settings.display_options.data); TasmotaGlobal.restart_flag = 2; break; case FUNC_DISPLAY_SEVENSEG_TEXT: From 7fe8f117a5505c4c61a1f3f5c943b0be17330d7b Mon Sep 17 00:00:00 2001 From: Ajith Vasudevan Date: Tue, 9 Mar 2021 00:47:19 +0530 Subject: [PATCH 11/13] Reverted changes to xdsp_interface and related changes done in 75699fe --- tasmota/tasmota.ino | 5 +---- tasmota/tasmota_template.h | 8 +++----- tasmota/xdrv_13_display.ino | 2 +- tasmota/xdsp_15_tm1637.ino | 2 +- tasmota/xdsp_interface.ino | 15 +-------------- 5 files changed, 7 insertions(+), 25 deletions(-) diff --git a/tasmota/tasmota.ino b/tasmota/tasmota.ino index 94d459d35..637d2b84b 100644 --- a/tasmota/tasmota.ino +++ b/tasmota/tasmota.ino @@ -147,7 +147,6 @@ struct { bool module_changed; // Indicate module changed since last restart bool wifi_stay_asleep; // Allow sleep only incase of ESP32 BLE bool no_autoexec; // Disable autoexec - bool tm1637_enabled; // TM1637 driver enabled StateBitfield global_state; // Global states (currently Wifi and Mqtt) (8 bits) uint8_t spi_enabled; // SPI configured @@ -228,9 +227,7 @@ void setup(void) { TasmotaGlobal.tele_period = 9999; TasmotaGlobal.active_device = 1; TasmotaGlobal.global_state.data = 0xF; // Init global state (wifi_down, mqtt_down) to solve possible network issues -#if defined(USE_DISPLAY) && defined(USE_DISPLAY_TM1637) - TasmotaGlobal.tm1637_enabled = true; -#endif + RtcRebootLoad(); if (!RtcRebootValid()) { RtcReboot.fast_reboot_count = 0; diff --git a/tasmota/tasmota_template.h b/tasmota/tasmota_template.h index 3afbf1794..a96d15830 100644 --- a/tasmota/tasmota_template.h +++ b/tasmota/tasmota_template.h @@ -150,7 +150,6 @@ enum UserSelectablePins { GPIO_NEOPOOL_TX, GPIO_NEOPOOL_RX, // Sugar Valley RS485 interface GPIO_SDM72_TX, GPIO_SDM72_RX, // SDM72 Serial interface GPIO_TM1637CLK, GPIO_TM1637DIO, // TM1637 interface - GPIO_TM1638CLK, GPIO_TM1638DIO, GPIO_TM1638STB, // TM1638 interface GPIO_PROJECTOR_CTRL_TX, GPIO_PROJECTOR_CTRL_RX, // LCD/DLP Projector Serial Control GPIO_SSD1351_DC, GPIO_XPT2046_CS, // XPT2046 SPI Chip Select @@ -325,7 +324,6 @@ const char kSensorNames[] PROGMEM = D_SENSOR_NEOPOOL_TX "|" D_SENSOR_NEOPOOL_RX "|" D_SENSOR_SDM72_TX "|" D_SENSOR_SDM72_RX "|" D_SENSOR_TM1637_CLK "|" D_SENSOR_TM1637_DIO "|" - D_SENSOR_TM1638_CLK "|" D_SENSOR_TM1638_DIO "|" D_SENSOR_TM1638_STB "|" D_SENSOR_PROJECTOR_CTRL_TX "|" D_SENSOR_PROJECTOR_CTRL_RX "|" D_SENSOR_SSD1351_DC "|" D_SENSOR_XPT2046_CS "|" @@ -451,9 +449,9 @@ const uint16_t kGpioNiceList[] PROGMEM = { #ifdef USE_DISPLAY_TM1637 AGPIO(GPIO_TM1637CLK), AGPIO(GPIO_TM1637DIO), - AGPIO(GPIO_TM1638CLK), - AGPIO(GPIO_TM1638DIO), - AGPIO(GPIO_TM1638STB), + AGPIO(GPIO_TM16CLK), + AGPIO(GPIO_TM16DIO), + AGPIO(GPIO_TM16STB), #endif // USE_DISPLAY_TM1637 AGPIO(GPIO_BACKLIGHT), // Display backlight control AGPIO(GPIO_OLED_RESET), // OLED Display Reset diff --git a/tasmota/xdrv_13_display.ino b/tasmota/xdrv_13_display.ino index bd1955a7b..2bb77a03a 100755 --- a/tasmota/xdrv_13_display.ino +++ b/tasmota/xdrv_13_display.ino @@ -2842,7 +2842,7 @@ bool Xdrv13(uint8_t function) { bool result = false; - if ((TasmotaGlobal.i2c_enabled || TasmotaGlobal.spi_enabled || TasmotaGlobal.soft_spi_enabled || TasmotaGlobal.tm1637_enabled) && XdspPresent()) { + if ((TasmotaGlobal.i2c_enabled || TasmotaGlobal.spi_enabled || TasmotaGlobal.soft_spi_enabled) && XdspPresent()) { switch (function) { case FUNC_PRE_INIT: DisplayInitDriver(); diff --git a/tasmota/xdsp_15_tm1637.ino b/tasmota/xdsp_15_tm1637.ino index 614bc8c96..d551582b0 100644 --- a/tasmota/xdsp_15_tm1637.ino +++ b/tasmota/xdsp_15_tm1637.ino @@ -268,7 +268,7 @@ bool DriverInit(void) { tm1637display->begin(TM1637Data.num_digits, 1); } else if(TM1637Data.display_type == TM1638) { strcpy(TM1637Data.model_name, "TM1638"); - tm1638display = new TM1638plus(Pin(GPIO_TM1638STB), Pin(GPIO_TM1638CLK), Pin(GPIO_TM1638DIO), true ); + tm1638display = new TM1638plus(Pin(GPIO_TM16STB), Pin(GPIO_TM16CLK), Pin(GPIO_TM16DIO), true ); TM1637Data.num_digits = 8; tm1638display->displayBegin(); } diff --git a/tasmota/xdsp_interface.ino b/tasmota/xdsp_interface.ino index 42907ae15..3ca49f3d6 100644 --- a/tasmota/xdsp_interface.ino +++ b/tasmota/xdsp_interface.ino @@ -17,7 +17,7 @@ along with this program. If not, see . */ -#if defined(USE_I2C) || defined(USE_SPI) || defined(USE_DISPLAY_TM1637) +#if defined(USE_I2C) || defined(USE_SPI) #ifdef USE_DISPLAY #ifdef XFUNC_PTR_IN_ROM @@ -26,8 +26,6 @@ bool (* const xdsp_func_ptr[])(uint8_t) PROGMEM = { // Display Function Pointe bool (* const xdsp_func_ptr[])(uint8_t) = { // Display Function Pointers #endif -#if defined(USE_I2C) || defined(USE_SPI) - #ifdef XDSP_01 &Xdsp01, #endif @@ -84,18 +82,10 @@ bool (* const xdsp_func_ptr[])(uint8_t) = { // Display Function Pointers &Xdsp14, #endif -#endif // #if defined(USE_I2C) || defined(USE_SPI) - -#ifdef USE_DISPLAY_TM1637 - #ifdef XDSP_15 &Xdsp15, #endif -#endif // USE_DISPLAY_TM1637 - -#if defined(USE_I2C) || defined(USE_SPI) - #ifdef XDSP_16 &Xdsp16, #endif @@ -163,9 +153,6 @@ bool (* const xdsp_func_ptr[])(uint8_t) = { // Display Function Pointers #ifdef XDSP_32 &Xdsp32 #endif - -#endif // #if defined(USE_I2C) || defined(USE_SPI) - }; const uint8_t xdsp_present = sizeof(xdsp_func_ptr) / sizeof(xdsp_func_ptr[0]); // Number of drivers found From acf65d7a68926a0a1176f5f1e1a7738c4091d8a4 Mon Sep 17 00:00:00 2001 From: Ajith Vasudevan Date: Tue, 9 Mar 2021 01:12:42 +0530 Subject: [PATCH 12/13] Removed unwanted lines --- tasmota/tasmota_configurations.h | 1 - tasmota/xdrv_13_display.ino | 1 - 2 files changed, 2 deletions(-) diff --git a/tasmota/tasmota_configurations.h b/tasmota/tasmota_configurations.h index 73b55c9f2..c4956bdbd 100644 --- a/tasmota/tasmota_configurations.h +++ b/tasmota/tasmota_configurations.h @@ -324,7 +324,6 @@ #define USE_DISPLAY_RA8876 // [DisplayModel 10] #define USE_DISPLAY_ST7789 // [DisplayModel 12] Enable ST7789 module #define USE_DISPLAY_SSD1331 // [DisplayModel 14] Enable SSD1331 module - #define USE_DISPLAY_TM1637 // [DisplayModel 15] Enable TM1637, TM1638 modules #undef DEBUG_THEO // Disable debug code #undef USE_DEBUG_DRIVER // Disable debug code diff --git a/tasmota/xdrv_13_display.ino b/tasmota/xdrv_13_display.ino index 2bb77a03a..ee53bdef8 100755 --- a/tasmota/xdrv_13_display.ino +++ b/tasmota/xdrv_13_display.ino @@ -83,7 +83,6 @@ const uint8_t DISPLAY_LOG_ROWS = 32; // Number of lines in display log #define D_CMND_DISP_BUTTONS "Buttons" #define D_CMND_DISP_SCROLLTEXT "ScrollText" #define D_CMND_DISP_TYPE "Type" - #define D_CMND_DISP_ILIMODE "ILIMode" #define D_CMND_DISP_ILIINVERT "Invert" From ba77e6d1c0d5632133e80d14bf66c38e45912cad Mon Sep 17 00:00:00 2001 From: Ajith Vasudevan Date: Thu, 18 Mar 2021 19:30:50 +0530 Subject: [PATCH 13/13] Removed DisplayType and TM1638 Buttons and LEDs support --- tasmota/xdrv_13_display.ino | 58 +------ tasmota/xdsp_15_tm1637.ino | 330 ++++++++---------------------------- 2 files changed, 78 insertions(+), 310 deletions(-) diff --git a/tasmota/xdrv_13_display.ino b/tasmota/xdrv_13_display.ino index 4524858ac..35e4e05ee 100755 --- a/tasmota/xdrv_13_display.ino +++ b/tasmota/xdrv_13_display.ino @@ -77,11 +77,7 @@ const uint8_t DISPLAY_LOG_ROWS = 32; // Number of lines in display log #define D_CMND_DISP_SCROLLDELAY "ScrollDelay" #define D_CMND_DISP_CLOCK "Clock" #define D_CMND_DISP_TEXTNC "TextNC" // NC - "No Clear" -#define D_CMND_DISP_SETLEDS "SetLEDs" -#define D_CMND_DISP_SETLED "SetLED" -#define D_CMND_DISP_BUTTONS "Buttons" #define D_CMND_DISP_SCROLLTEXT "ScrollText" -#define D_CMND_DISP_TYPE "Type" #define D_CMND_DISP_ILIMODE "ILIMode" #define D_CMND_DISP_ILIINVERT "Invert" @@ -99,8 +95,7 @@ enum XdspFunctions { FUNC_DISPLAY_INIT_DRIVER, FUNC_DISPLAY_INIT, FUNC_DISPLAY_E #endif , FUNC_DISPLAY_NUMBER, FUNC_DISPLAY_FLOAT, FUNC_DISPLAY_NUMBERNC, FUNC_DISPLAY_FLOATNC, FUNC_DISPLAY_BRIGHTNESS, FUNC_DISPLAY_RAW, FUNC_DISPLAY_LEVEL, FUNC_DISPLAY_SEVENSEG_TEXT, FUNC_DISPLAY_SEVENSEG_TEXTNC, - FUNC_DISPLAY_SCROLLDELAY, FUNC_DISPLAY_CLOCK, FUNC_DISPLAY_SETLEDS, FUNC_DISPLAY_SETLED, - FUNC_DISPLAY_BUTTONS, FUNC_DISPLAY_SCROLLTEXT, FUNC_DISPLAY_TYPE + FUNC_DISPLAY_SCROLLDELAY, FUNC_DISPLAY_CLOCK, FUNC_DISPLAY_SCROLLTEXT }; enum DisplayInitModes { DISPLAY_INIT_MODE, DISPLAY_INIT_PARTIAL, DISPLAY_INIT_FULL }; @@ -114,8 +109,8 @@ const char kDisplayCommands[] PROGMEM = D_PRFX_DISPLAY "|" // Prefix #endif "|" D_CMND_DISP_CLEAR "|" D_CMND_DISP_NUMBER "|" D_CMND_DISP_FLOAT "|" D_CMND_DISP_NUMBERNC "|" D_CMND_DISP_FLOATNC "|" D_CMND_DISP_BRIGHTNESS "|" D_CMND_DISP_RAW "|" D_CMND_DISP_LEVEL "|" D_CMND_DISP_SEVENSEG_TEXT "|" D_CMND_DISP_SEVENSEG_TEXTNC "|" - D_CMND_DISP_SCROLLDELAY "|" D_CMND_DISP_CLOCK "|" D_CMND_DISP_TEXTNC "|" D_CMND_DISP_SETLEDS "|" D_CMND_DISP_SETLED "|" - D_CMND_DISP_BUTTONS "|" D_CMND_DISP_SCROLLTEXT "|" D_CMND_DISP_TYPE "|" D_CMND_DISP_ILIMODE "|" D_CMND_DISP_ILIINVERT + D_CMND_DISP_SCROLLDELAY "|" D_CMND_DISP_CLOCK "|" D_CMND_DISP_TEXTNC "|" + D_CMND_DISP_SCROLLTEXT "|" D_CMND_DISP_ILIMODE "|" D_CMND_DISP_ILIINVERT ; void (* const DisplayCommand[])(void) PROGMEM = { @@ -127,8 +122,8 @@ void (* const DisplayCommand[])(void) PROGMEM = { #endif , &CmndDisplayClear, &CmndDisplayNumber, &CmndDisplayFloat, &CmndDisplayNumberNC, &CmndDisplayFloatNC, &CmndDisplayBrightness, &CmndDisplayRaw, &CmndDisplayLevel, &CmndDisplaySevensegText, &CmndDisplaySevensegTextNC, - &CmndDisplayScrollDelay, &CmndDisplayClock, &CmndDisplayTextNC, &CmndDisplaySetLEDs, &CmndDisplaySetLED, - &CmndDisplayButtons, &CmndDisplayScrollText, &CmndDisplayType, &CmndDisplayILIMOde , &CmndDisplayILIInvert + &CmndDisplayScrollDelay, &CmndDisplayClock, &CmndDisplayTextNC, + &CmndDisplayScrollText, &CmndDisplayILIMOde , &CmndDisplayILIInvert }; char *dsp_str; @@ -1865,33 +1860,6 @@ void CmndDisplayClock(void) ResponseCmndNumber(XdrvMailbox.payload); } -void CmndDisplaySetLEDs(void) -{ - bool result = false; - if (!renderer) { - result = XdspCall(FUNC_DISPLAY_SETLEDS); - } - if(result) ResponseCmndNumber(XdrvMailbox.payload); -} - - -void CmndDisplaySetLED(void) -{ - bool result = false; - if (!renderer) { - result = XdspCall(FUNC_DISPLAY_SETLED); - } - if(result) ResponseCmndNumber(XdrvMailbox.payload); -} - -void CmndDisplayButtons(void) -{ - bool result = false; - if (!renderer) { - XdspCall(FUNC_DISPLAY_BUTTONS); - } -} - void CmndDisplayScrollText(void) { @@ -1903,22 +1871,6 @@ void CmndDisplayScrollText(void) } -void CmndDisplayType(void) -{ - if(ArgC() == 0) { - XdrvMailbox.payload = Settings.display_options.data; - } else { - uint8_t prev_type = Settings.display_options.data; - if(prev_type != XdrvMailbox.payload) { - if (!renderer) { - XdspCall(FUNC_DISPLAY_TYPE); - Settings.display_options.data = XdrvMailbox.payload; - } - } - } - ResponseCmndNumber(XdrvMailbox.payload); -} - void CmndDisplaySize(void) { #ifdef USE_DISPLAY_TM1637 diff --git a/tasmota/xdsp_15_tm1637.ino b/tasmota/xdsp_15_tm1637.ino index d551582b0..2d2f17bba 100644 --- a/tasmota/xdsp_15_tm1637.ino +++ b/tasmota/xdsp_15_tm1637.ino @@ -21,9 +21,7 @@ #ifdef USE_DISPLAY_TM1637 /*********************************************************************************************\ This driver enables the display of numbers (both integers and floats) and basic text - on the inexpensive TM1637- and TM1638-based seven-segment modules. Additionally, for the TM1638, - it allows the TM1638 LEDs to be toggled using its buttons. - Useful STAT messages are also sent when the TM1638 buttons are pressed. + on the inexpensive TM1637- and TM1638-based seven-segment modules. Raw segments can also be displayed. @@ -51,23 +49,12 @@ Once the GPIO configuration is saved and the ESP8266/ESP32 module restarts, set the Display Model to 15 using the command "DisplayModel 15" - After this, depending upon your display variant, set your Display Type to 0, 1 or 2 using the command - "DisplayType 0" // for the 4-digit TM1637 - or "DisplayType 1" // for the 6-digit TM1637 - or "DisplayType 2" // for the 8-digit TM1638 + If your display is a TM1637 with 6 digits, set Display Columns to the number of digits your + display has, using the command "DisplayCols 6" and restart the ESP module. After the ESP8266/ESP32 module restarts again, the following "Display" commands can be used: - DisplayType type {0|1|2} - - Sets the display type. 0 => TM1637, 4 digit - 1 => TM1637, 6 digit - 2 => TM1638, 8 digit - Command e.g., "TM1637Data.display_type 1" // to enable TM1637 6-digit variant - - - DisplayClear Clears the display, command: "DisplayClear" @@ -156,56 +143,6 @@ -Commands specific to TM1638 -==================================== - - DisplaySetLEDs bit_array {0-255} - - Sets the 8 LEDs (not the digits!) on the TM1638 module to the binary number represented by the input bit_array. - For example, "DisplaySetLEDs 3" would light up the first and second LED (from left), because 3 => 00000011 - - - - DisplaySetLED position {0-7}, value {0|1} - - Sets a specified LED to either ON or OFF. e.g., "DisplaySetLED 2, 1" would light up the 3rd LED (2 => 3rd position) - - - - DisplayButtons - - Causes the current state of the buttons/LEDs to be returned as a "STAT" message of the following form: - stat/TM1638/RESULT = {"DisplayButtons": {"S1":, "S2":, "S3":, "S4":, "S5":, "S6":, "S7":, "S8":, "Array": [,,,,,,,], "Byte": }} - where , , ... are the states of each of the buttons/LEDs, and is the decimal representation - of the bit-array that constitutes these states. - - For example, if the 5th button is pressed to turn ON LED5, and the "DisplayButtons" command is issued, - the response STAT message will be of the form: - stat/TM1638/RESULT = {"DisplayButtons": {"S1":0, "S2":0, "S3":0, "S4":0, "S5":1, "S6":0, "S7":0, "S8":0, "Array": [0,0,0,0,1,0,0,0], "Byte": 16}} - because 16 => 2^(5-1) - - - - Button Functionality (TM1638 only): -====================================== - When this driver is initialized with "DisplayType 2" (TM1638), the buttons on the TM1638 module can be used - to toggle the corresponding LEDs. - - In addition, for each button press, a STAT message of the following form is sent: - - stat//RESULT = {"TM1638_BUTTON":} - - where = button index (starting at 1) - = state of the corresponding LED. It can be "ON" or "OFF" - - For example, if Button3 is pressed, LED3 would light up and a STAT message is sent as follows: - - stat/TM1638/RESULT = {"TM1638_BUTTON3":"ON"} - - Pressing Button3 again would turn OFF LED3 and a STAT message is sent as follows: - - stat/TM1638/RESULT = {"TM1638_BUTTON3":"OFF"} - \*********************************************************************************************/ @@ -254,31 +191,37 @@ struct { /*********************************************************************************************\ * Init function \*********************************************************************************************/ -bool DriverInit(void) { - if(Settings.display_model == XDSP_15) { - if(TM1637Data.driver_inited) return true; +bool TM1637Init(void) { - if(Settings.display_options.data == 2) { TM1637Data.num_digits = 8; TM1637Data.display_type = TM1638; } - else if(Settings.display_options.data == 1) { TM1637Data.num_digits = 6; TM1637Data.display_type = TM1637; } - else { Settings.display_options.data = 0; TM1637Data.num_digits = 4; TM1637Data.display_type = TM1637; } + if(TM1637Data.driver_inited) return true; - if(TM1637Data.display_type == TM1637) { - strcpy(TM1637Data.model_name, "TM1637"); - tm1637display = new SevenSegmentTM1637(Pin(GPIO_TM1637CLK), Pin(GPIO_TM1637DIO)); - tm1637display->begin(TM1637Data.num_digits, 1); - } else if(TM1637Data.display_type == TM1638) { - strcpy(TM1637Data.model_name, "TM1638"); - tm1638display = new TM1638plus(Pin(GPIO_TM16STB), Pin(GPIO_TM16CLK), Pin(GPIO_TM16DIO), true ); - TM1637Data.num_digits = 8; - tm1638display->displayBegin(); - } - Settings.display_size = TM1637Data.num_digits; // Can use to check current display size - clearDisplay(); - TM1637Data.brightness = (Settings.display_dimmer ? Settings.display_dimmer : TM1637Data.brightness); - setBrightness(TM1637Data.brightness); - TM1637Data.driver_inited = true; - AddLog(LOG_LEVEL_INFO, PSTR("DSP: %s display driver initialized with %d digits (DisplayType %d)"), TM1637Data.model_name, TM1637Data.num_digits, Settings.display_options.data); + if(PinUsed(GPIO_TM16CLK) && PinUsed(GPIO_TM16DIO) && PinUsed(GPIO_TM16STB)) { + TM1637Data.display_type = TM1638; + TM1637Data.num_digits = 8; + } else if(PinUsed(GPIO_TM1637CLK) && PinUsed(GPIO_TM1637DIO)) { + TM1637Data.display_type = TM1637; + if(Settings.display_cols[0] <= 6) TM1637Data.num_digits = Settings.display_cols[0]; + else TM1637Data.num_digits = 4; } + else return false; + + Settings.display_model == XDSP_15; + + if(TM1637Data.display_type == TM1637) { + strcpy(TM1637Data.model_name, "TM1637"); + tm1637display = new SevenSegmentTM1637(Pin(GPIO_TM1637CLK), Pin(GPIO_TM1637DIO)); + tm1637display->begin(TM1637Data.num_digits, 1); + } else if(TM1637Data.display_type == TM1638) { + strcpy(TM1637Data.model_name, "TM1638"); + tm1638display = new TM1638plus(Pin(GPIO_TM16STB), Pin(GPIO_TM16CLK), Pin(GPIO_TM16DIO), true ); + TM1637Data.num_digits = 8; + tm1638display->displayBegin(); + } + TM1637ClearDisplay(); + TM1637Data.brightness = (Settings.display_dimmer ? Settings.display_dimmer : TM1637Data.brightness); + TM1637SetBrightness(TM1637Data.brightness); + TM1637Data.driver_inited = true; + AddLog(LOG_LEVEL_INFO, PSTR("DSP: %s display driver initialized with %d digits"), TM1637Data.model_name, TM1637Data.num_digits); return true; } @@ -289,7 +232,7 @@ bool DriverInit(void) { * commands: DisplayNumber num [,position {0-(TM1637Data.num_digits-1)} [,leading_zeros {0|1} [,length {1 to TM1637Data.num_digits}]]] * DisplayNumberNC num [,position {0-(TM1637Data.num_digits-1)} [,leading_zeros {0|1} [,length {1 to TM1637Data.num_digits}]]] // "NC" --> "No Clear" \*********************************************************************************************/ -bool CmndNumber(bool clear) { +bool CmndTM1637Number(bool clear) { char sNum[CMD_MAX_LEN]; char sLeadingzeros[CMD_MAX_LEN]; char sPosition[CMD_MAX_LEN]; @@ -321,7 +264,7 @@ bool CmndNumber(bool clear) { AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: num %d, pos %d, lead %d, len %d"), num, position, leadingzeros, length); - if(clear) clearDisplay(); + if(clear) TM1637ClearDisplay(); char txt[30]; snprintf_P(txt, sizeof(txt), PSTR("%d"), num); @@ -354,7 +297,7 @@ bool CmndNumber(bool clear) { * commands: DisplayFloat num [,position {0-(TM1637Data.num_digits-1)} [,precision {0-TM1637Data.num_digits} [,length {1 to TM1637Data.num_digits}]]] * DisplayFloatNC num [,position {0-(TM1637Data.num_digits-1)} [,precision {0-TM1637Data.num_digits} [,length {1 to TM1637Data.num_digits}]]] // "NC" --> "No Clear" \*********************************************************************************************/ -bool CmndFloat(bool clear) { +bool CmndTM1637Float(bool clear) { char sNum[CMD_MAX_LEN]; char sPrecision[CMD_MAX_LEN]; @@ -386,7 +329,7 @@ bool CmndFloat(bool clear) { if((position < 0) || (position > (TM1637Data.num_digits-1))) position = 0; if((precision < 0) || (precision > TM1637Data.num_digits)) precision = TM1637Data.num_digits; - if(clear) clearDisplay(); + if(clear) TM1637ClearDisplay(); char txt[30]; ext_snprintf_P(txt, sizeof(txt), PSTR("%*_f"), precision, &fnum); @@ -430,8 +373,8 @@ bool CmndFloat(bool clear) { // * Clears the display // * Command: DisplayClear // \*********************************************************************************************/ -bool CmndClear(void) { - clearDisplay(); +bool CmndTM1637Clear(void) { + TM1637ClearDisplay(); sprintf(TM1637Data.msg, PSTR("Cleared")); XdrvMailbox.data = TM1637Data.msg; return true; @@ -441,7 +384,7 @@ bool CmndClear(void) { // /*********************************************************************************************\ // * Clears the display // \*********************************************************************************************/ -void clearDisplay (void) { +void TM1637ClearDisplay (void) { if(TM1637Data.display_type == TM1637) { unsigned char arr[] = {0}; for(int i=0; iprintRaw(arr, 1, i); @@ -455,7 +398,7 @@ void clearDisplay (void) { * Display scrolling text * Command: DisplayTM1637Data.scroll_text text \*********************************************************************************************/ -bool CmndScrollText(void) { +bool CmndTM1637ScrollText(void) { AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: Text %s"), XdrvMailbox.data); @@ -480,7 +423,7 @@ bool CmndScrollText(void) { * Sets the scroll delay for scrolling text. * Command: DisplayTM1637Data.scroll_delay delay {0-15} // default = 4 \*********************************************************************************************/ -bool CmndScrollDelay(void) { +bool CmndTM1637ScrollDelay(void) { if(ArgC() == 0) { XdrvMailbox.payload = TM1637Data.scroll_delay; return true; @@ -495,7 +438,7 @@ bool CmndScrollDelay(void) { /*********************************************************************************************\ * Scrolls a given string. Called every 50ms \*********************************************************************************************/ -void scrollText(void) { +void TM1637ScrollText(void) { TM1637Data.iteration++; if(TM1637Data.scroll_delay) TM1637Data.iteration = TM1637Data.iteration % TM1637Data.scroll_delay; else TM1637Data.iteration = 0; @@ -538,7 +481,7 @@ void scrollText(void) { * Displays a horizontal bar graph. Takes a percentage number (0-100) as input * Command: DisplayLevel level {0-100} \*********************************************************************************************/ -bool CmndLevel(void) { +bool CmndTM1637Level(void) { uint16_t val = XdrvMailbox.payload; if((val < LEVEL_MIN) || (val > LEVEL_MAX)) { Response_P(PSTR("{\"Error\":\"Level should be a number in the range [%d, %d]\"}"), LEVEL_MIN, LEVEL_MAX); @@ -546,17 +489,17 @@ bool CmndLevel(void) { } uint8_t totalBars = 2*TM1637Data.num_digits; - AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: TM1637Data.model_name %s CmndLevel totalBars=%d"), TM1637Data.model_name, totalBars); + AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: TM1637Data.model_name %s CmndTM1637Level totalBars=%d"), TM1637Data.model_name, totalBars); float barsToDisplay = totalBars * val / 100.0f; char txt[5]; ext_snprintf_P(txt, sizeof(txt), PSTR("%*_f"), 1, &barsToDisplay); - AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: TM1637Data.model_name %s CmndLevel barsToDisplay=%s"), TM1637Data.model_name, txt); + AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: TM1637Data.model_name %s CmndTM1637Level barsToDisplay=%s"), TM1637Data.model_name, txt); char s[4]; ext_snprintf_P(s, sizeof(s), PSTR("%0_f"), &barsToDisplay); uint8_t numBars = atoi(s); AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: CmndTM1637Level numBars %d"), numBars); - clearDisplay(); + TM1637ClearDisplay(); uint8_t rawBytes[1]; for(int i=1; i<=numBars; i++) { uint8_t digit = (i-1) / 2; @@ -580,7 +523,7 @@ bool CmndLevel(void) { * bit 1 is segment B etc. The function may either set the entire display * or any desired part using the length and position parameters. \*********************************************************************************************/ -bool CmndRaw(void) { +bool CmndTM1637Raw(void) { uint8_t DATA[6] = { 0, 0, 0, 0, 0, 0 }; char as[CMD_MAX_LEN]; @@ -656,7 +599,7 @@ bool CmndRaw(void) { * position parameters without affecting the rest of the display. * Command: DisplayText text [, position {0-(TM1637Data.num_digits-1)} [,length {1 to TM1637Data.num_digits}]] \*********************************************************************************************/ -bool CmndText(bool clear) { +bool CmndTM1637Text(bool clear) { char sString[CMD_MAX_LEN + 1]; char sPosition[CMD_MAX_LEN]; char sLength[CMD_MAX_LEN]; @@ -680,7 +623,7 @@ bool CmndText(bool clear) { AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: sString %s, pos %d, len %d"), sString, position, length); - if(clear) clearDisplay(); + if(clear) TM1637ClearDisplay(); if(!length) length = strlen(sString); if((length < 0) || (length > TM1637Data.num_digits)) length = TM1637Data.num_digits; @@ -724,7 +667,7 @@ bool CmndText(bool clear) { * Sets brightness of the display. * Command: DisplayBrightness {1-8} \*********************************************************************************************/ -bool CmndBrightness(void) { +bool CmndTM1637Brightness(void) { uint16_t val = XdrvMailbox.payload; if(ArgC() == 0) { @@ -737,13 +680,13 @@ bool CmndBrightness(void) { return false; } TM1637Data.brightness = val; - setBrightness(TM1637Data.brightness); + TM1637SetBrightness(TM1637Data.brightness); return true; } -void setBrightness(uint8_t val) { +void TM1637SetBrightness(uint8_t val) { if((val < BRIGHTNESS_MIN) || (val > BRIGHTNESS_MAX)) val = 5; Settings.display_dimmer = val; if(TM1637Data.display_type == TM1637) tm1637display->setBacklight(val*10); @@ -760,7 +703,7 @@ void setBrightness(uint8_t val) { * DisplayClock 2 // 24-hour format * DisplayClock 0 // turn off clock and clear \*********************************************************************************************/ -bool CmndClock(void) { +bool CmndTM1637Clock(void) { TM1637Data.show_clock = XdrvMailbox.payload; @@ -770,7 +713,7 @@ bool CmndClock(void) { AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: TM1637Data.show_clock %d, TM1637Data.clock_24 %d"), TM1637Data.show_clock, TM1637Data.clock_24); - clearDisplay(); + TM1637ClearDisplay(); return true; } @@ -778,7 +721,7 @@ bool CmndClock(void) { /*********************************************************************************************\ * refreshes the time if clock is displayed \*********************************************************************************************/ -void showTime() { +void TM1637ShowTime() { uint8_t hr = RtcTime.hour; uint8_t mn = RtcTime.minute; // uint8_t hr = 1; @@ -817,120 +760,10 @@ void showTime() { } - - -/*********************************************************************************************\ -* Sets all LEDs of the display. -* Command: DisplaySetLEDs {0-255} -\*********************************************************************************************/ -bool CmndSetLEDs(void) { - if(TM1637Data.display_type != TM1638) { - Response_P(PSTR("{\"Error\":\"Command not valid for TM1637Data.display_type %d\"}"), TM1637Data.display_type); - return false; - } - if(ArgC() == 0) XdrvMailbox.payload = 0; - uint16_t val = XdrvMailbox.payload; - if((val < LED_MIN) || (val > LED_MAX)) { - Response_P(PSTR("{\"Error\":\"Set LEDs value should be a number in the range [%d, %d]\"}"), LED_MIN, LED_MAX); - return false; - } - for(uint8_t i=0; i<8; i++) TM1637Data.LED[i] = ((val & 2^i) >> i); - tm1638display->setLEDs(val << 8); - return true; -} - - -/*********************************************************************************************\ -* Sets an TM1637Data.LED at specified position. -* Command: DisplaySetLED position {0-7}, value {0|1} -\*********************************************************************************************/ -bool CmndSetLED(void) { - if(TM1637Data.display_type != TM1638) { - Response_P(PSTR("{\"Error\":\"Command not valid for TM1637Data.display_type %d\"}"), TM1637Data.display_type); - return false; - } - if(ArgC() < 2) { - Response_P(PSTR("{\"Error\":\"Set LED requires two comma-separated numbers as arguments\"}")); - return false; - } - - char sVal[CMD_MAX_LEN]; - char sPos[CMD_MAX_LEN]; - uint32_t position = 0; - uint32_t value = 0; - - switch (ArgC()) - { - case 2 : - subStr(sVal, XdrvMailbox.data, ",", 2); - value = atoi(sVal); - case 1 : - subStr(sPos, XdrvMailbox.data, ",", 1); - position = atoi(sPos); - } - - - if((position < POSITION_MIN) || (position > POSITION_MAX)) { - Response_P(PSTR("{\"Error\":\"First argument, position should be in the range [%d, %d]\"}"), POSITION_MIN, POSITION_MAX); - return false; - } - - AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: TM1637Data.model_name TM1638, position=%d, value %d"), position, value); - - TM1637Data.LED[position] = value; - tm1638display->setLED(position, value); - return true; -} - - -/*********************************************************************************************\ -* Reads the button states. Called every 50ms -\*********************************************************************************************/ -bool readButtons(void) { - TM1637Data.buttons = tm1638display->readButtons(); - if(TM1637Data.prev_buttons != TM1637Data.buttons) { - TM1637Data.prev_buttons = TM1637Data.buttons; - if(!TM1637Data.buttons) return true; - if(TM1637Data.buttons) { - for(int i=0; i<8; i++) { - if(TM1637Data.buttons & (1<setLED(i, TM1637Data.LED[i]); - Response_P(PSTR("{\"TM1638_BUTTON%d\":\"%s\"}"), i+1, (TM1637Data.LED[i]?PSTR("ON"):PSTR("OFF"))); - MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR("BUTTONS")); - } - } - } - } - return true; -} - -/*********************************************************************************************\ -* Returns the current state of the buttons as a decimal representation of the button states -* Command: DisplayButtons -\*********************************************************************************************/ -bool CmndButtons(void) { - if(TM1637Data.display_type != TM1638) { - Response_P(PSTR("{\"Error\":\"Command not valid for TM1637Data.display_type %d\"}"), TM1637Data.display_type); - return false; - } - AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: TM1638: buttons=%d"), TM1637Data.buttons); - uint8_t byte = TM1637Data.LED[0]<<0 | TM1637Data.LED[1]<<1 | TM1637Data.LED[2]<<2 | TM1637Data.LED[3]<<3 | TM1637Data.LED[4]<<4 | TM1637Data.LED[5]<<5 | TM1637Data.LED[6]<<6 | TM1637Data.LED[7]<<7; - Response_P(PSTR("{\"DisplayButtons\": {\"S1\":%d, \"S2\":%d, \"S3\":%d, \"S4\":%d, \"S5\":%d, \"S6\":%d, \"S7\":%d, \"S8\":%d, \"Array\": [%d,%d,%d,%d,%d,%d,%d,%d], \"Byte\": %d}}"), - TM1637Data.LED[0], TM1637Data.LED[1], TM1637Data.LED[2], TM1637Data.LED[3], TM1637Data.LED[4], TM1637Data.LED[5], TM1637Data.LED[6], TM1637Data.LED[7], TM1637Data.LED[0], - TM1637Data.LED[1], TM1637Data.LED[2], TM1637Data.LED[3], TM1637Data.LED[4], TM1637Data.LED[5], TM1637Data.LED[6], TM1637Data.LED[7], byte); - return true; -} - - - - - /*********************************************************************************************\ * This function is called for all Display functions. \*********************************************************************************************/ -bool MainFunc(uint8_t fn) { +bool TM1637MainFunc(uint8_t fn) { bool result = false; if(XdrvMailbox.data_len > CMD_MAX_LEN) { @@ -940,52 +773,43 @@ bool MainFunc(uint8_t fn) { switch (fn) { case FUNC_DISPLAY_CLEAR: - result = CmndClear(); + result = CmndTM1637Clear(); break; case FUNC_DISPLAY_NUMBER : - result = CmndNumber(true); + result = CmndTM1637Number(true); break; case FUNC_DISPLAY_NUMBERNC : - result = CmndNumber(false); + result = CmndTM1637Number(false); break; case FUNC_DISPLAY_FLOAT : - result = CmndFloat(true); + result = CmndTM1637Float(true); break; case FUNC_DISPLAY_FLOATNC : - result = CmndFloat(false); + result = CmndTM1637Float(false); break; case FUNC_DISPLAY_BRIGHTNESS: - result = CmndBrightness(); + result = CmndTM1637Brightness(); break; case FUNC_DISPLAY_RAW: - result = CmndRaw(); + result = CmndTM1637Raw(); break; case FUNC_DISPLAY_SEVENSEG_TEXT: - result = CmndText(true); + result = CmndTM1637Text(true); break; case FUNC_DISPLAY_SEVENSEG_TEXTNC: - result = CmndText(false); + result = CmndTM1637Text(false); break; case FUNC_DISPLAY_LEVEL: - result = CmndLevel(); + result = CmndTM1637Level(); break; case FUNC_DISPLAY_SCROLLTEXT: - result = CmndScrollText(); + result = CmndTM1637ScrollText(); break; case FUNC_DISPLAY_SCROLLDELAY: - result = CmndScrollDelay(); + result = CmndTM1637ScrollDelay(); break; - case FUNC_DISPLAY_SETLEDS: - result = CmndSetLEDs(); - break; - case FUNC_DISPLAY_SETLED: - result = CmndSetLED(); - break; - case FUNC_DISPLAY_BUTTONS: - result = CmndButtons(); - break; - case FUNC_DISPLAY_CLOCK: - result = CmndClock(); + case FUNC_DISPLAY_CLOCK: + result = CmndTM1637Clock(); break; } @@ -1007,16 +831,12 @@ bool Xdsp15(uint8_t function) if (Settings.display_model == XDSP_15) { switch (function) { case FUNC_DISPLAY_INIT_DRIVER: - result = DriverInit(); // init + result = TM1637Init(); // init break; case FUNC_DISPLAY_INIT: AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: %s: FUNC_DISPLAY_INIT: Display depends on TM1637Data.display_type, currently %d"), TM1637Data.model_name, Settings.display_options.data); result = true; break; - case FUNC_DISPLAY_TYPE: - AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: %s: FUNC_DISPLAY_TYPE: TM1637Data.display_type set to %d, restarting to take effect ..."), TM1637Data.model_name, Settings.display_options.data); - TasmotaGlobal.restart_flag = 2; - break; case FUNC_DISPLAY_SEVENSEG_TEXT: case FUNC_DISPLAY_CLEAR: case FUNC_DISPLAY_NUMBER: @@ -1031,15 +851,11 @@ bool Xdsp15(uint8_t function) case FUNC_DISPLAY_CLOCK: TM1637Data.show_clock = false; case FUNC_DISPLAY_BRIGHTNESS: - case FUNC_DISPLAY_SETLEDS: - case FUNC_DISPLAY_SETLED: - case FUNC_DISPLAY_BUTTONS: - result = MainFunc(function); + result = TM1637MainFunc(function); break; case FUNC_DISPLAY_EVERY_50_MSECOND: - if(TM1637Data.scroll) scrollText(); - if(TM1637Data.show_clock) showTime(); - if(TM1637Data.display_type == TM1638) readButtons(); + if(TM1637Data.scroll) TM1637ScrollText(); + if(TM1637Data.show_clock) TM1637ShowTime(); break; } }