2022-12-31 08:19:53 +00:00
/*
xdsp_20_tm1650 . ino - TM1650 four - digit seven - segment LED display controller support for Tasmota
Copyright ( C ) 2021 Stefan Oskamp , Theo Arends , Anatoli Arkhipenko
2023-03-12 08:22:40 +00:00
Copyright ( C ) 2023 Gabriele Lauricella
2022-12-31 08:19:53 +00:00
This program is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
/*
The TM1650 chip is a controller for a four digit seven - segment ( plus dot ) LED display .
It uses eight I2C addresses ; four to control the digits and four to display content .
The addresses are not configurable : 0x24 . . .0 x27 , 0x34 . . .0 x37
There is a Chinese datasheet on the Internet and a machine translation to English .
The Controller also supports reading a keyboard matrix of 4 x 8 keys . This is not
supported by this driver .
The TM1650 is found in clocks with seven - segment LED displays , e . g . , the " XY-Clock " .
In this clock , the dots of the display are connected to the controller in an unintuitive
way . While digits are counted from left to right , the associated dots on the display
are : 0 = rightmost dot , 1 = dot after third digit , 2 = upper half of the colon
3 = lower half of the column . The dots after the first and second digits are not
connected . This wiring of the XY - Clock has been reflected in the time format . Other
clocks using a TM1650 might be wired differently .
*/
2023-03-12 08:22:40 +00:00
2022-12-31 08:19:53 +00:00
# ifdef USE_I2C
# ifdef USE_DISPLAY
# ifdef USE_DISPLAY_TM1650
2023-03-12 08:22:40 +00:00
/*********************************************************************************************\
This driver enables the display of numbers ( both integers and floats ) and basic text
on the inexpensive TM1650 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 ) .
To use , compile Tasmota with USE_I2C , USE_DISPLAY and USE_DISPLAY_TM1650 , or build the tasmota - display env .
For TM1650 :
Connect the TM1650 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 - - > " I2C SCA "
CLK hardware pin - - > " I2C SCL "
Once the GPIO configuration is saved and the ESP8266 / ESP32 module restarts ,
set the Display Model to 20 and Display Mode to 0
using the command " Backlog DisplayModel 20 ; DisplayMode 0; "
Before using it set the Display Type , if you have an XY - Clock set it to 0 otherwise if you
have a 303 WifiL01 set it to 2 using the " DisplayType 0 " command .
After the ESP8266 / ESP32 module restarts again , turn ON the display with the command " Power 1 "
Now , the following " Display " commands can be used :
DisplayClear
Clears the display , command : " DisplayClear "
DisplayNumber num [ , position { 0 - ( Settings - > display_width - 1 ) ) } [ , leading_zeros { 0 | 1 } [ , length { 1 to Settings - > display_width } ] ] ]
Clears and then displays number without decimal . command e . g . , " DisplayNumber 1234 "
Control ' leading zeros ' , ' length ' and ' position ' with " DisplayNumber 1234, <position>, <leadingZeros>, <length> "
' leading zeros ' can be 1 or 0 ( default ) , ' length ' can be 1 to Settings - > display_width , ' position ' can be 0 ( left - most ) to Settings - > display_width ( right - most ) .
See function description below for more details .
DisplayNumberNC num [ , position { 0 - ( Settings - > display_width - 1 ) ) } [ , leading_zeros { 0 | 1 } [ , length { 1 to Settings - > display_width } ] ] ]
Display integer number as above , but without clearing first . e . g . , " DisplayNumberNC 1234 " . Usage is same as above .
DisplayFloat num [ , position { 0 - ( Settings - > display_width - 1 ) } [ , precision { 0 - Settings - > display_width } [ , length { 1 to Settings - > display_width } ] ] ]
Clears and then displays float ( with decimal point ) command e . g . , " DisplayFloat 12.34 "
See function description below for more details .
DisplayFloatNC num [ , position { 0 - ( Settings - > display_width - 1 ) } [ , precision { 0 - Settings - > display_width } [ , length { 1 to Settings - > display_width } ] ] ]
Displays float ( with decimal point ) as above , but without clearing first . command e . g . , " DisplayFloatNC 12.34 "
See function description below for more details .
DisplayRaw position { 0 - ( Settings - > display_width - 1 ) } , length { 1 to Settings - > display_width } , num1 [ , num2 [ , num3 [ , num4 [ , . . . upto Settings - > display_width numbers ] ] ] ] ]
Takes upto Settings - > display_width comma - separated integers ( 0 - 255 ) and displays raw segments . Each number represents a
7 - segment digit . Each 8 - bit number represents individual segments of a digit .
For example , the command " DisplayRaw 0, 4, 255, 255, 255, 255 " would display " [8.8.8.8.] "
DisplayText text [ , position { 0 - ( Settings - > display_width - 1 ) } [ , length { 1 to Settings - > display_width } ] ]
Clears and then displays basic text . command e . g . , " DisplayText ajith vasudevan "
Control ' length ' and ' position ' with " DisplayText <text>, <position>, <length> "
' length ' can be 1 to Settings - > display_width , ' position ' can be 0 ( left - most ) to Settings - > display_width - 1 ( right - most )
A caret ( ^ ) or backtick ( ` ) 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 - Settings - > display_width - 1 } [ , length { 1 to Settings - > display_width } ] ]
Clears first , then displays text . Usage is same as above .
DisplayScrollText text [ , num_loops ]
Displays scrolling text indefinitely , until another Display - command ( other than DisplayScrollText
or DisplayScrollDelay is issued ) . Optionally , stop scrolling after num_loops iterations .
DisplayScrollDelay delay { 0 - 15 } // default = 4
Sets the speed of text scroll . Smaller delay = faster scrolling .
DisplayLevel num { 0 - 100 }
Display a horizontal bar graph ( 0 - 100 ) command e . g . , " DisplayLevel 50 " will display [ | | | | ]
DisplayClock 1 | 2 | 0
Displays a clock .
Commands " DisplayClock 1 " // 12 hr format
" DisplayClock 2 " // 24 hr format
" DisplayClock 0 " // turn off clock
In addition , if you compile using USE_DISPLAY_MODES1TO5 , setting DisplayMode to 1 shows the time ,
setting it to 2 shows the date and setting it to 3 alternates between time and date ( using " DisplayRefresh [1..7] "
for the time and seconds you want to show the time before displaying the date )
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2022-12-31 08:19:53 +00:00
# define XDSP_20 20
# define XI2C_74 74 // See I2CDEVICES.md
2023-03-12 08:22:40 +00:00
# define CMD_MAX_LEN 55
# define LEVEL_MIN 0
# define LEVEL_MAX 100
# define SCROLL_MAX_LEN 50
2022-12-31 08:19:53 +00:00
# define TM1650_CONTROL_BASE 0x24 // I2C address to control left-most digit.
# define TM1650_DISPLAY_BASE 0x34 // I2C address to display something in the left-most digit.
# define TM1650_DIGITS 4 // One TM1650 can only control modules with up to four digits.
// TM1650 Display bits:
# define TM1650_DISPLAY_DOT 7
// TM1650 Control bits:
# define TM1650_CONTROL_ON 0
# define TM1650_CONTROL_RESERVED1 1
# define TM1650_CONTROL_RESERVED2 2
# define TM1650_CONTROL_DOT 3 // Dots can be switched on/off with both control and display.
# define TM1650_CONTROL_BRIGHTNESS 4 // Bits 4...6
# define TM1650_CONTROL_RESERVED3 7
2023-03-12 08:22:40 +00:00
# include <Wire.h>
2022-12-31 08:19:53 +00:00
static unsigned char TM1650Control [ TM1650_DIGITS ] = { 0 , 0 , 0 , 0 } ;
static unsigned char TM1650Display [ TM1650_DIGITS ] = { 0 , 0 , 0 , 0 } ;
static const byte TM1650Font [ 128 ] {
//0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , // 0x00
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , // 0x10
2023-03-12 08:22:40 +00:00
// ! " ' ( ) -
2022-12-31 08:19:53 +00:00
0x00 , 0x82 , 0x21 , 0x00 , 0x00 , 0x00 , 0x00 , 0x02 , 0x39 , 0x0F , 0x00 , 0x00 , 0x00 , 0x40 , 0x80 , 0x00 , // 0x20
2023-03-12 08:22:40 +00:00
//0 1 2 3 4 5 6 7 8 9 = ?
2022-12-31 08:19:53 +00:00
0x3F , 0x06 , 0x5B , 0x4F , 0x66 , 0x6D , 0x7D , 0x07 , 0x7f , 0x6f , 0x00 , 0x00 , 0x00 , 0x48 , 0x00 , 0x53 , // 0x30
2023-03-12 08:22:40 +00:00
// A B C D E F G H I J L N O
2022-12-31 08:19:53 +00:00
0x00 , 0x77 , 0x7C , 0x39 , 0x5E , 0x79 , 0x71 , 0x6F , 0x76 , 0x06 , 0x1E , 0x00 , 0x38 , 0x00 , 0x54 , 0x3F , // 0x40
2023-03-12 08:22:40 +00:00
//P Q R S T U Y [ ] ^=° _
0x73 , 0x67 , 0x50 , 0x6D , 0x78 , 0x3E , 0x00 , 0x00 , 0x00 , 0x6E , 0x00 , 0x39 , 0x00 , 0x0F , 0x63 , 0x08 , // 0x50
//`=° a b c d e f g h i j l n o
2022-12-31 08:19:53 +00:00
0x63 , 0x5F , 0x7C , 0x58 , 0x5E , 0x7B , 0x71 , 0x6F , 0x74 , 0x02 , 0x1E , 0x00 , 0x06 , 0x00 , 0x54 , 0x5C , // 0x60
2023-03-12 08:22:40 +00:00
//p q r s t u y { | }
2022-12-31 08:19:53 +00:00
0x73 , 0x67 , 0x50 , 0x6D , 0x78 , 0x1C , 0x00 , 0x00 , 0x00 , 0x6E , 0x00 , 0x39 , 0x30 , 0x0F , 0x00 , 0x00 // 0x70
} ;
2023-03-12 08:22:40 +00:00
enum display_options_types
{
T_XY_CLOCK , // XY-Clock - white PCB with a perpendicular small daughter board
NOTUSED ,
T_303WIFILC01 // 303WifiLC01 - green clock
2022-12-31 11:45:59 +00:00
} ;
2022-12-31 08:19:53 +00:00
2023-03-12 08:22:40 +00:00
struct
2022-12-31 08:19:53 +00:00
{
2023-03-12 08:22:40 +00:00
char scroll_text [ CMD_MAX_LEN ] ;
char msg [ 60 ] ;
char model_name [ 8 ] ;
uint8_t scroll_delay = 4 ;
uint8_t scroll_index = 0 ;
uint8_t iteration = 0 ;
uint8_t scroll_counter = 0 ;
uint8_t scroll_counter_max = 3 ;
uint8_t display_type = XDSP_20 ;
bool init_driver_done = false ;
bool scroll = false ;
bool show_clock = false ;
bool clock_24 = false ;
bool clock_blynk_dots = true ;
} TM1650Data ;
2022-12-31 08:19:53 +00:00
2023-03-12 08:22:40 +00:00
/*********************************************************************************************\
* Init function
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2022-12-31 08:19:53 +00:00
void TM1650Init ( uint8_t mode )
{
switch ( mode ) {
case DISPLAY_INIT_MODE :
2023-03-12 08:22:40 +00:00
TM1650Dim ( ) ;
TM1650ClearDisplay ( ) ;
2022-12-31 08:19:53 +00:00
break ;
case DISPLAY_INIT_PARTIAL :
case DISPLAY_INIT_FULL :
2023-03-12 08:22:40 +00:00
TM1650Dim ( ) ;
TM1650ClearDisplay ( ) ;
2022-12-31 08:19:53 +00:00
break ;
}
2023-03-12 08:22:40 +00:00
}
2022-12-31 08:19:53 +00:00
2023-03-12 08:22:40 +00:00
/*********************************************************************************************\
* Init Drive function
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2022-12-31 08:19:53 +00:00
void TM1650InitDriver ( void )
{
if ( ! TasmotaGlobal . i2c_enabled ) {
return ;
}
if ( ! Settings - > display_model ) {
if ( I2cSetDevice ( TM1650_CONTROL_BASE ) ) {
Settings - > display_address [ 0 ] = TM1650_CONTROL_BASE ;
Settings - > display_model = XDSP_20 ;
}
}
if ( XDSP_20 = = Settings - > display_model ) {
I2cSetActiveFound ( Settings - > display_address [ 0 ] , " TM1650 " ) ;
Settings - > display_cols [ 0 ] = 4 ;
2023-03-12 08:22:40 +00:00
Settings - > display_rows = 1 ;
2022-12-31 08:19:53 +00:00
Settings - > display_width = Settings - > display_cols [ 0 ] ;
Settings - > display_height = Settings - > display_rows ;
2023-03-12 08:22:40 +00:00
if ( T_XY_CLOCK = = Settings - > display_options . type )
{
strcpy_P ( TM1650Data . model_name , PSTR ( " XY-Clock " ) ) ;
}
else if ( NOTUSED = = Settings - > display_options . type )
{
strcpy_P ( TM1650Data . model_name , PSTR ( " NOTUSED " ) ) ;
}
else if ( T_303WIFILC01 = = Settings - > display_options . type )
{
strcpy_P ( TM1650Data . model_name , PSTR ( " 303WiFiLC01 " ) ) ;
}
TM1650Dim ( ) ;
TM1650ClearDisplay ( ) ;
2022-12-31 08:19:53 +00:00
2023-03-12 08:22:40 +00:00
AddLog ( LOG_LEVEL_INFO , PSTR ( " DSP: TM1650 \" %s \" with %d digits (type %d) " ) , TM1650Data . model_name , Settings - > display_width , Settings - > display_options . type ) ;
TM1650Data . init_driver_done = true ;
2022-12-31 08:19:53 +00:00
}
2023-03-12 08:22:40 +00:00
}
2022-12-31 08:19:53 +00:00
void TM1650DisplayOn ( )
{
for ( int i = 0 ; i < TM1650_DIGITS ; i + + ) {
TM1650Control [ i ] | = _BV ( TM1650_CONTROL_ON ) ;
Wire . beginTransmission ( TM1650_CONTROL_BASE + i ) ;
Wire . write ( TM1650Control [ i ] ) ;
Wire . endTransmission ( ) ;
}
2023-03-12 08:22:40 +00:00
}
2022-12-31 08:19:53 +00:00
void TM1650DisplayOff ( )
{
for ( int i = 0 ; i < TM1650_DIGITS ; i + + ) {
TM1650Control [ i ] & = ~ _BV ( TM1650_CONTROL_ON ) ;
Wire . beginTransmission ( TM1650_CONTROL_BASE + i ) ;
Wire . write ( TM1650Control [ i ] ) ;
Wire . endTransmission ( ) ;
}
2023-03-12 08:22:40 +00:00
}
2022-12-31 08:19:53 +00:00
void TM1650DisplayOnOff ( )
{
if ( disp_power ) {
TM1650DisplayOn ( ) ;
}
else {
TM1650DisplayOff ( ) ;
}
2023-03-12 08:22:40 +00:00
}
2022-12-31 08:19:53 +00:00
void TM1650SetBrightness ( unsigned int level )
{
if ( level > 0 b111 ) level = 0 b111 ;
for ( int i = 0 ; i < TM1650_DIGITS ; i + + ) {
TM1650Control [ i ] = TM1650Control [ i ] & ~ ( 0 b111 < < TM1650_CONTROL_BRIGHTNESS ) | level < < TM1650_CONTROL_BRIGHTNESS ;
Wire . beginTransmission ( TM1650_CONTROL_BASE + i ) ;
Wire . write ( TM1650Control [ i ] ) ;
Wire . endTransmission ( ) ;
}
2023-03-12 08:22:40 +00:00
}
2022-12-31 08:19:53 +00:00
2023-03-12 08:22:40 +00:00
void TM1650DisplayText ( char * text ) / / Text shall match regex ( ( [ ^ . ] ? \ . ? ) { 0 , 4 } \ 0 ) , e . g . , 123.4 or 8.8 .8 .8 for full digit
2022-12-31 08:19:53 +00:00
{
2023-03-12 08:22:40 +00:00
//AddLog(LOG_LEVEL_DEBUG, PSTR("TM1650DisplayText(\"%s\")"), text);
2022-12-31 08:19:53 +00:00
for ( int i = 0 ; i < TM1650_DIGITS ; i + + ) {
2023-03-12 08:22:40 +00:00
2022-12-31 08:19:53 +00:00
if ( * text ! = 0 ) {
if ( * text = = ' . ' ) {
TM1650Display [ i ] = 0 ; // Blank this digit, set the dot below.
}
else { // Something to display.
char c = * text + + ;
TM1650Display [ i ] = TM1650Font [ c & ~ _BV ( TM1650_DISPLAY_DOT ) ] ;
}
if ( * text = = ' . ' ) {
char c = * text + + ;
TM1650Display [ i ] | = _BV ( TM1650_DISPLAY_DOT ) ;
}
2022-12-31 11:45:59 +00:00
2023-03-12 08:22:40 +00:00
if ( T_303WIFILC01 = = Settings - > display_options . type ) {
TM1650Display [ i ] = swapbits ( TM1650Display [ i ] ) ; // 303WIFILC01 board has special wiring
2022-12-31 11:45:59 +00:00
}
2023-03-12 08:22:40 +00:00
}
else {
2022-12-31 08:19:53 +00:00
TM1650Display [ i ] = 0 ; // Clear digits after the text.
}
Wire . beginTransmission ( TM1650_DISPLAY_BASE + i ) ;
Wire . write ( TM1650Display [ i ] ) ;
Wire . endTransmission ( ) ;
2023-03-12 08:22:40 +00:00
}
}
uint8_t swapbits ( uint8_t n )
{
// For model 303WiFiLC01 board has different segments wiring
// PGFEDCBA -> BFAEDCGP
//seg EDC //seg A //seg B
return ( n & 0x1C ) | ( ( n & 0x01 ) < < 5 ) | ( ( n & 0x02 ) < < 6 )
| ( ( n & 0x20 ) < < 1 ) | ( ( n & 0x40 ) > > 5 ) | ( ( n & 0x80 ) > > 7 ) ;
//seg F //seg G //seg P
}
void TM1650DisplayRaw ( char * text ) / / Text shall match regex ( ( [ ^ . ] ? \ . ? ) { 0 , 4 } \ 0 ) , e . g . , 123.4
{
for ( int i = 0 ; i < TM1650_DIGITS ; i + + ) {
char c = * text + + ;
TM1650Display [ i ] = c ;
//AddLog(LOG_LEVEL_DEBUG, PSTR("Raw Digit(%d - %d - %c)"), i, TM1650Display[i], TM1650Display[i]);
Wire . beginTransmission ( TM1650_DISPLAY_BASE + i ) ;
Wire . write ( TM1650Display [ i ] ) ;
Wire . endTransmission ( ) ;
}
}
/*********************************************************************************************\
* Displays number without decimal , with / without leading zeros , specifying start - position
* and length , optionally skipping clearing display before displaying the number .
* commands : DisplayNumber num [ , position { 0 - ( Settings - > display_width - 1 ) } [ , leading_zeros { 0 | 1 } [ , length { 1 to Settings - > display_width } ] ] ]
* DisplayNumberNC num [ , position { 0 - ( Settings - > display_width - 1 ) } [ , leading_zeros { 0 | 1 } [ , length { 1 to Settings - > display_width } ] ] ] // "NC" --> "No Clear"
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool CmndTM1650Number ( bool clear )
{
char sNum [ CMD_MAX_LEN ] ;
char sLeadingzeros [ CMD_MAX_LEN ] ;
char sPosition [ CMD_MAX_LEN ] ;
char sLength [ CMD_MAX_LEN ] ;
uint8_t length = 0 ;
bool leadingzeros = false ;
uint8_t position = 0 ;
uint32_t num = 0 ;
switch ( ArgC ( ) )
{
case 4 :
subStr ( sLength , XdrvMailbox . data , " , " , 4 ) ;
length = atoi ( sLength ) ;
case 3 :
subStr ( sLeadingzeros , XdrvMailbox . data , " , " , 3 ) ;
leadingzeros = atoi ( sLeadingzeros ) ;
case 2 :
subStr ( sPosition , XdrvMailbox . data , " , " , 2 ) ;
position = atoi ( sPosition ) ;
case 1 :
subStr ( sNum , XdrvMailbox . data , " , " , 1 ) ;
num = TextToInt ( sNum ) ;
}
if ( ( position < 0 ) | | ( position > ( Settings - > display_width - 1 ) ) )
position = 0 ;
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " TM5: num %d, pos %d, lead %d, len %d " ) , num , position , leadingzeros , length ) ;
if ( clear )
TM1650ClearDisplay ( ) ;
char txt [ 30 ] ;
snprintf_P ( txt , sizeof ( txt ) , PSTR ( " %d " ) , num ) ;
if ( ! length )
length = strlen ( txt ) ;
if ( ( length < 0 ) | | ( length > Settings - > display_width ) )
length = Settings - > display_width ;
char pad = ( leadingzeros ? ' 0 ' : ' ' ) ;
uint32_t i = position ;
char text [ TM1650_DIGITS + 1 ] ;
//write empty pos
for ( uint32_t j = 0 ; j < position ; j + + )
{
if ( j > = Settings - > display_width )
break ;
text [ j ] = ' ' ;
}
//write pads
for ( ; i < position + ( length - strlen ( txt ) ) ; i + + )
{
if ( i > = Settings - > display_width )
break ;
text [ i ] = pad ;
}
//write digits
for ( uint32_t j = 0 ; i < position + length ; i + + , j + + )
{
if ( i > = Settings - > display_width )
break ;
if ( txt [ j ] = = 0 )
break ;
if ( txt [ j ] = = ' . ' ) {
i - - ;
continue ;
}
text [ i ] = txt [ j ] ;
}
text [ i ] = 0 ; //string termination
TM1650DisplayText ( text ) ;
return true ;
}
/*********************************************************************************************\
* Displays number with decimal , specifying position , precision and length ,
* optionally skipping clearing display before displaying the number .
* commands : DisplayFloat num [ , position { 0 - ( Settings - > display_width - 1 ) } [ , precision { 0 - Settings - > display_width } [ , length { 1 to Settings - > display_width } ] ] ]
* DisplayFloatNC num [ , position { 0 - ( Settings - > display_width - 1 ) } [ , precision { 0 - Settings - > display_width } [ , length { 1 to Settings - > display_width } ] ] ] // "NC" --> "No Clear"
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool CmndTM1650Float ( bool clear )
{
char sNum [ CMD_MAX_LEN ] ;
char sPrecision [ CMD_MAX_LEN ] ;
char sPosition [ CMD_MAX_LEN ] ;
char sLength [ CMD_MAX_LEN ] ;
uint8_t length = 0 ;
uint8_t precision = Settings - > display_width - 1 ;
uint8_t position = 0 ;
float fnum = 0.0f ;
switch ( ArgC ( ) )
{
case 4 :
subStr ( sLength , XdrvMailbox . data , " , " , 4 ) ;
length = atoi ( sLength ) ;
case 3 :
subStr ( sPrecision , XdrvMailbox . data , " , " , 3 ) ;
precision = atoi ( sPrecision ) ;
case 2 :
subStr ( sPosition , XdrvMailbox . data , " , " , 2 ) ;
position = atoi ( sPosition ) ;
case 1 :
subStr ( sNum , XdrvMailbox . data , " , " , 1 ) ;
fnum = CharToFloat ( sNum ) ;
}
if ( ( position < 0 ) | | ( position > ( Settings - > display_width ) ) )
position = 0 ;
if ( ( precision < 0 ) | | ( precision > = Settings - > display_width ) )
precision = Settings - > display_width - 1 ;
if ( clear )
TM1650ClearDisplay ( ) ;
char txt [ 30 ] ;
ext_snprintf_P ( txt , sizeof ( txt ) , PSTR ( " %*_f " ) , precision , & fnum ) ;
if ( ! length )
length = strlen ( txt ) ;
if ( ( length < = 0 ) | | ( length > Settings - > display_width ) )
length = Settings - > display_width ;
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " TM5: num %4_f, pos %d, prec %d, len %d, txt %s " ) , & fnum , position , precision , length , txt ) ;
uint32_t i = position ;
uint32_t dots = 0 ;
char text [ TM1650_DIGITS + 1 + 1 ] ;
//write empty pos
for ( uint32_t j = 0 ; j < position ; j + + )
{
if ( j > = Settings - > display_width )
break ;
text [ j ] = ' ' ;
}
if ( T_XY_CLOCK = = Settings - > display_options . type ) {
for ( uint32_t j = 0 ; i < position + length + dots ; i + + , j + + )
{
if ( txt [ j ] = = ' . ' ) dots + + ;
if ( i > = Settings - > display_width + dots )
break ;
if ( txt [ j ] = = 0 )
break ;
if ( txt [ j ] = = ' . ' ) {
if ( i = = 2 ) {
//2nd dot ok
}
else if ( i = = 3 ) {
//3rd dot but move do 1st
text [ i ] = text [ i - 1 ] ;
text [ i - 1 ] = text [ i - 2 ] ;
text [ i - 2 ] = txt [ j ] ;
continue ;
}
else {
//dot on 1st or 4th
AddLog ( LOG_LEVEL_INFO , PSTR ( " TM5: Can't display this float " ) ) ;
return false ;
}
}
text [ i ] = txt [ j ] ;
}
}
else if ( T_303WIFILC01 = = Settings - > display_options . type ) {
//todo
AddLog ( LOG_LEVEL_INFO , PSTR ( " TM5: DisplayFloat not implemented yet for display type: 303WifiClock " ) ) ;
return false ;
}
text [ i ] = 0 ; //string termination
TM1650DisplayText ( text ) ;
return true ;
}
/ / /*********************************************************************************************\
// * Clears the display
// * Command: DisplayClear
// \*********************************************************************************************/
bool CmndTM1650Clear ( void )
{
TM1650ClearDisplay ( ) ;
sprintf ( TM1650Data . msg , PSTR ( " Cleared " ) ) ;
XdrvMailbox . data = TM1650Data . msg ;
return true ;
}
/ / /*********************************************************************************************\
// * Clears the display
// \*********************************************************************************************/
void TM1650ClearDisplay ( void )
{
for ( int i = 0 ; i < TM1650_DIGITS ; i + + ) {
TM1650Display [ i ] = 0 ;
Wire . beginTransmission ( TM1650_DISPLAY_BASE + i ) ;
Wire . write ( TM1650Display [ i ] ) ;
Wire . endTransmission ( ) ;
}
}
/*********************************************************************************************\
* Display scrolling text
* Command : DisplayScrollText text
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool CmndTM1650ScrollText ( void )
{
char sString [ SCROLL_MAX_LEN + 1 ] ;
char sMaxLoopCount [ CMD_MAX_LEN ] ;
uint8_t maxLoopCount = 0 ;
switch ( ArgC ( ) )
{
case 2 :
subStr ( sMaxLoopCount , XdrvMailbox . data , " , " , 2 ) ;
maxLoopCount = atoi ( sMaxLoopCount ) ;
case 1 :
subStr ( sString , XdrvMailbox . data , " , " , 1 ) ;
}
if ( maxLoopCount < 0 )
maxLoopCount = 0 ;
//AddLog(LOG_LEVEL_DEBUG, PSTR("TM5: sString %s, maxLoopCount %d"), sString, maxLoopCount);
TM1650Data . scroll_counter_max = maxLoopCount ;
if ( strlen ( sString ) > SCROLL_MAX_LEN )
{
snprintf ( TM1650Data . msg , sizeof ( TM1650Data . msg ) , PSTR ( " Text too long. Length should be less than %d " ) , SCROLL_MAX_LEN ) ;
XdrvMailbox . data = TM1650Data . msg ;
return false ;
}
else
{
snprintf ( TM1650Data . scroll_text , sizeof ( TM1650Data . scroll_text ) , PSTR ( " " ) ) ;
snprintf ( TM1650Data . scroll_text , Settings - > display_width + sizeof ( TM1650Data . scroll_text ) , PSTR ( " %s " ) , & sString ) ;
TM1650Data . scroll_text [ strlen ( sString ) + Settings - > display_width ] = 0 ;
TM1650Data . scroll_index = 0 ;
TM1650Data . scroll = true ;
TM1650Data . scroll_counter = 0 ;
return true ;
}
}
/*********************************************************************************************\
* Sets the scroll delay for scrolling text .
* Command : DisplayScrollDelay delay { 0 - 15 } // default = 4
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool CmndTM1650ScrollDelay ( void )
{
if ( ArgC ( ) = = 0 )
{
XdrvMailbox . payload = TM1650Data . scroll_delay ;
return true ;
}
if ( TM1650Data . scroll_delay < 0 )
TM1650Data . scroll_delay = 0 ;
TM1650Data . scroll_delay = XdrvMailbox . payload ;
return true ;
}
/*********************************************************************************************\
* Scrolls a given string . Called every 50 ms
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void TM1650ScrollText ( void )
{
if ( ! TM1650Data . scroll ) return ;
TM1650Data . iteration + + ;
if ( TM1650Data . scroll_delay )
TM1650Data . iteration = TM1650Data . iteration % TM1650Data . scroll_delay ;
else
TM1650Data . iteration = 0 ;
if ( TM1650Data . iteration )
return ;
if ( TM1650Data . scroll_index > strlen ( TM1650Data . scroll_text ) )
{
TM1650Data . scroll_index = 0 ;
TM1650Data . scroll_counter + + ;
if ( TM1650Data . scroll_counter_max ! = 0 & & ( TM1650Data . scroll_counter > = TM1650Data . scroll_counter_max ) ) {
TM1650Data . scroll = false ;
return ;
}
}
char text [ CMD_MAX_LEN + 2 + 1 ] ;
uint32_t i ;
uint32_t j ;
for ( i = 0 , j = TM1650Data . scroll_index ; i < 1 + strlen ( TM1650Data . scroll_text ) ; i + + , j + + )
{
if ( i > ( Settings - > display_width - 1 ) )
{
break ;
}
text [ i ] = TM1650Data . scroll_text [ j ] ;
}
text [ i ] = 0 ; //string termination
TM1650DisplayText ( text ) ;
TM1650Data . scroll_index + + ;
}
/*********************************************************************************************\
* Displays a horizontal bar graph . Takes a percentage number ( 0 - 100 ) as input
* Command : DisplayLevel level { 0 - 100 }
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool CmndTM1650Level ( 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 ) ;
return false ;
}
char text [ TM1650_DIGITS + 1 ] ;
for ( uint32_t i = 0 ; i < TM1650_DIGITS ; i + + )
{
text [ i ] = 0 ;
}
uint8_t totalBars = 2 * Settings - > display_width ;
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " TM5: CmndTM1650Level totalBars=%d " ) , 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 ( " TM5: CmndTM1650Level barsToDisplay=%s " ) , txt ) ;
char s [ 4 ] ;
ext_snprintf_P ( s , sizeof ( s ) , PSTR ( " %0_f " ) , & barsToDisplay ) ;
uint8_t numBars = atoi ( s ) ;
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " TM5: CmndTM1650Level numBars %d " ) , numBars ) ;
TM1650ClearDisplay ( ) ;
uint8_t digit = numBars / 2 ;
uint8_t remainder = numBars % 2 ;
for ( uint32_t i = 0 ; i < TM1650_DIGITS ; i + + )
{
if ( i > = Settings - > display_width )
break ;
if ( i < digit ) {
text [ i ] = 0x36 ;
}
else if ( i = = digit & & remainder = = 1 ) {
text [ i ] = 0x30 ;
}
else {
text [ i ] = 0 ;
}
}
TM1650DisplayRaw ( text ) ;
return true ;
}
/*********************************************************************************************\
* Display arbitrary data on the display module
* Command : DisplayRaw position { 0 - ( Settings - > display_width - 1 ) } , length { 1 to Settings - > display_width } , a [ , b [ , c [ , d [ . . . upto Settings - > display_width ] ] ] ]
* where a , b , c , d . . . are upto Settings - > display_width numbers in the range 0 - 255 , each number ( byte )
* corresponding to a single 7 - segment digit . Within each byte , bit 0 is segment A ,
* 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 CmndTM1650Raw ( void )
{
char text [ TM1650_DIGITS + 1 ] ;
for ( uint32_t i = 0 ; i < TM1650_DIGITS ; i + + )
{
text [ i ] = 0 ;
}
uint8_t DATA [ 4 ] = { 0 , 0 , 0 , 0 } ;
char as [ CMD_MAX_LEN ] ;
char bs [ CMD_MAX_LEN ] ;
char cs [ CMD_MAX_LEN ] ;
char ds [ CMD_MAX_LEN ] ;
char sLength [ CMD_MAX_LEN ] ;
char sPos [ CMD_MAX_LEN ] ;
uint32_t position = 0 ;
uint32_t length = 0 ;
switch ( ArgC ( ) )
{
case 6 :
subStr ( ds , XdrvMailbox . data , " , " , 6 ) ;
DATA [ 3 ] = atoi ( ds ) ;
case 5 :
subStr ( cs , XdrvMailbox . data , " , " , 5 ) ;
DATA [ 2 ] = atoi ( cs ) ;
case 4 :
subStr ( bs , XdrvMailbox . data , " , " , 4 ) ;
DATA [ 1 ] = atoi ( bs ) ;
case 3 :
subStr ( as , XdrvMailbox . data , " , " , 3 ) ;
DATA [ 0 ] = atoi ( as ) ;
case 2 :
subStr ( sLength , XdrvMailbox . data , " , " , 2 ) ;
length = atoi ( sLength ) ;
case 1 :
subStr ( sPos , XdrvMailbox . data , " , " , 1 ) ;
position = atoi ( sPos ) ;
}
if ( ! length )
length = ArgC ( ) - 2 ;
if ( length < 0 | | length > Settings - > display_width )
length = Settings - > display_width ;
if ( position < 0 | | position > ( Settings - > display_width - 1 ) )
position = 0 ;
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " TM5: a %d, b %d, c %d, d %d, len %d, pos %d " ) ,
DATA [ 0 ] , DATA [ 1 ] , DATA [ 2 ] , DATA [ 3 ] , length , position ) ;
for ( uint32_t i = position ; i < position + length ; i + + )
{
if ( i > = Settings - > display_width )
break ;
text [ i ] = DATA [ i - position ] ;
}
TM1650DisplayRaw ( text ) ;
return true ;
}
/*********************************************************************************************\
* Display a given string .
* Text can be placed at arbitrary location on the display using the length and
* position parameters without affecting the rest of the display .
* Command : DisplayText text [ , position { 0 - ( Settings - > display_width - 1 ) } [ , length { 1 to Settings - > display_width } ] ]
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool CmndTM1650Text ( bool clear )
{
char text [ CMD_MAX_LEN + 2 + 1 ] ;
char sString [ CMD_MAX_LEN + 2 + 1 ] ;
char sPosition [ CMD_MAX_LEN ] ;
char sLength [ CMD_MAX_LEN ] ;
uint8_t length = 0 ;
uint8_t position = 0 ;
uint8_t dots = 0 ;
uint8_t strLen = 0 ;
switch ( ArgC ( ) )
{
case 3 :
subStr ( sLength , XdrvMailbox . data , " , " , 3 ) ;
length = atoi ( sLength ) ;
case 2 :
subStr ( sPosition , XdrvMailbox . data , " , " , 2 ) ;
position = atoi ( sPosition ) ;
case 1 :
subStr ( sString , XdrvMailbox . data , " , " , 1 ) ;
}
if ( ( position < 0 ) | | ( position > ( Settings - > display_width - 1 ) ) )
position = 0 ;
strLen = strlen ( sString ) ;
if ( ! length )
length = Settings - > display_width ;
if ( ( length < 0 ) | | ( length > Settings - > display_width ) )
length = Settings - > display_width ;
if ( clear )
TM1650ClearDisplay ( ) ;
uint32_t s = 0 ;
uint32_t i = 0 ;
for ( i = 0 ; i < ( strLen + position ) ; i + + )
{
if ( ( i > = ( length + dots + position ) ) | | dots > 4 ) {
break ;
}
if ( i < position ) {
text [ i ] = ' ' ;
continue ;
}
if ( sString [ s ] = = ' . ' & & dots < = 4 ) {
dots + + ;
}
text [ i ] = sString [ s ] ;
s + + ;
}
if ( i < strLen & & sString [ s ] = = ' . ' ) {
text [ i ] = ' . ' ;
i + + ;
}
text [ i ] = 0 ; //terminate string
TM1650DisplayText ( text ) ;
return true ;
}
/*********************************************************************************************\
* Displays a clock .
* Command : DisplayClock 1 // 12-hour format
* DisplayClock 2 // 24-hour format
* DisplayClock 0 // turn off clock and clear
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool CmndTM1650Clock ( void )
{
uint16_t val = XdrvMailbox . payload ;
if ( ArgC ( ) = = 0 )
val = 0 ;
if ( ( val < 0 ) | | ( val > 2 ) )
return false ;
if ( val = = 1 ) {
TM1650Data . show_clock = true ;
TM1650Data . clock_24 = false ;
}
else if ( val = = 2 ) {
TM1650Data . show_clock = true ;
TM1650Data . clock_24 = true ;
} else {
TM1650Data . show_clock = false ;
TM1650Data . clock_24 = false ;
}
TM1650ClearDisplay ( ) ;
return true ;
}
/*********************************************************************************************\
* refreshes the time if clock is displayed
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void TM1650ShowTime ( )
{
TM1650Data . iteration + + ;
if ( 20 ! = TM1650Data . iteration ) {
// every 20*50ms = 1000 ms should be enough
return ;
}
TM1650Data . iteration = 0 ;
char text [ TM1650_DIGITS + 2 + 1 ] ;
int i = 0 ;
uint8_t hour = RtcTime . hour ;
uint8_t min = RtcTime . minute ;
if ( ! TM1650Data . clock_24 )
{
if ( hour > 12 )
hour - = 12 ;
if ( hour = = 0 )
hour = 12 ;
}
text [ i + + ] = ' 0 ' + hour / 10 ;
text [ i + + ] = ' 0 ' + hour % 10 ;
if ( T_XY_CLOCK = = Settings - > display_options . type ) {
text [ i + + ] = ' 0 ' + min / 10 ;
if ( TM1650Data . clock_blynk_dots ) text [ i + + ] = ' . ' ; // Lower half of the colon, depending on how the LEDs are connected to the TM1650 in the XY-Clock.
text [ i + + ] = ' 0 ' + min % 10 ;
if ( TM1650Data . clock_blynk_dots ) text [ i + + ] = ' . ' ; // Upper half of the colon.
}
else if ( T_303WIFILC01 = = Settings - > display_options . type ) {
if ( TM1650Data . clock_blynk_dots ) text [ i + + ] = ' . ' ; // Colon for 303WIFILC01
text [ i + + ] = ' 0 ' + min / 10 ;
text [ i + + ] = ' 0 ' + min % 10 ;
}
text [ i + + ] = 0 ;
if ( ! TM1650Data . clock_24 & & text [ 0 ] = = ' 0 ' )
{
text [ 0 ] = ' ' ;
}
TM1650Data . clock_blynk_dots = ! TM1650Data . clock_blynk_dots ;
TM1650DisplayText ( text ) ;
}
/*********************************************************************************************\
* This function is called for all Display functions .
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool TM1650MainFunc ( uint8_t fn )
{
bool result = false ;
if ( fn ! = FUNC_DISPLAY_SCROLLDELAY ) TM1650Data . scroll = false ;
if ( XdrvMailbox . data_len > CMD_MAX_LEN )
{
Response_P ( PSTR ( " { \" Error \" : \" Command text too long. Please limit it to %d characters \" } " ) , CMD_MAX_LEN ) ;
return false ;
}
switch ( fn )
{
case FUNC_DISPLAY_CLEAR :
result = CmndTM1650Clear ( ) ;
break ;
case FUNC_DISPLAY_NUMBER :
result = CmndTM1650Number ( true ) ;
break ;
case FUNC_DISPLAY_NUMBERNC :
result = CmndTM1650Number ( false ) ;
break ;
case FUNC_DISPLAY_FLOAT :
result = CmndTM1650Float ( true ) ;
break ;
case FUNC_DISPLAY_FLOATNC :
result = CmndTM1650Float ( false ) ;
break ;
case FUNC_DISPLAY_RAW :
result = CmndTM1650Raw ( ) ;
break ;
case FUNC_DISPLAY_SEVENSEG_TEXT :
result = CmndTM1650Text ( true ) ;
break ;
case FUNC_DISPLAY_SEVENSEG_TEXTNC :
result = CmndTM1650Text ( false ) ;
break ;
case FUNC_DISPLAY_LEVEL :
result = CmndTM1650Level ( ) ;
break ;
case FUNC_DISPLAY_SCROLLTEXT :
result = CmndTM1650ScrollText ( ) ;
break ;
case FUNC_DISPLAY_SCROLLDELAY :
result = CmndTM1650ScrollDelay ( ) ;
break ;
case FUNC_DISPLAY_CLOCK :
result = CmndTM1650Clock ( ) ;
break ;
}
return result ;
}
void TM1650Dim ( void )
{
int brightness = GetDisplayDimmer16 ( ) ;
if ( brightness < 2 ) {
TM1650DisplayOff ( ) ;
}
else if ( brightness > 14 ) {
TM1650DisplayOn ( ) ;
TM1650SetBrightness ( 0 ) ; // In TM1650, brightness 0 means max brightness (level 8).
TM1650DisplayOn ( ) ;
}
else {
// Map 2...14 to 1...7:
TM1650SetBrightness ( brightness > > 1 ) ;
TM1650DisplayOn ( ) ;
}
}
/*********************************************************************************************/
# ifdef USE_DISPLAY_MODES1TO5
2022-12-31 08:19:53 +00:00
void TM1650Time ( void )
{
char text [ TM1650_DIGITS + 2 + 1 ] ;
int i = 0 ;
text [ i + + ] = ' 0 ' + RtcTime . hour / 10 ;
text [ i + + ] = ' 0 ' + RtcTime . hour % 10 ;
2022-12-31 11:45:59 +00:00
2023-03-12 08:22:40 +00:00
if ( T_XY_CLOCK = = Settings - > display_options . type ) {
2022-12-31 11:45:59 +00:00
text [ i + + ] = ' 0 ' + RtcTime . minute / 10 ;
2023-03-12 08:22:40 +00:00
if ( TM1650Data . clock_blynk_dots ) text [ i + + ] = ' . ' ; // Lower half of the colon, depending on how the LEDs are connected to the TM1650 in the XY-Clock.
2022-12-31 11:45:59 +00:00
text [ i + + ] = ' 0 ' + RtcTime . minute % 10 ;
2023-03-12 08:22:40 +00:00
if ( TM1650Data . clock_blynk_dots ) text [ i + + ] = ' . ' ; // Upper half of the colon.
2022-12-31 11:45:59 +00:00
}
2023-03-12 08:22:40 +00:00
else if ( T_303WIFILC01 = = Settings - > display_options . type ) {
if ( TM1650Data . clock_blynk_dots ) text [ i + + ] = ' . ' ; // Colon for 303WIFILC01
2022-12-31 11:45:59 +00:00
text [ i + + ] = ' 0 ' + RtcTime . minute / 10 ;
text [ i + + ] = ' 0 ' + RtcTime . minute % 10 ;
}
2022-12-31 08:19:53 +00:00
2023-03-12 08:22:40 +00:00
text [ i + + ] = 0 ;
TM1650Data . clock_blynk_dots = ! TM1650Data . clock_blynk_dots ;
2022-12-31 08:19:53 +00:00
TM1650DisplayText ( text ) ;
2023-03-12 08:22:40 +00:00
}
void TM1650Date ( void )
{
char text [ TM1650_DIGITS + 2 + 1 ] ;
int i = 0 ;
text [ i + + ] = ' 0 ' + RtcTime . day_of_month / 10 ;
text [ i + + ] = ' 0 ' + RtcTime . day_of_month % 10 ;
if ( T_XY_CLOCK = = Settings - > display_options . type ) {
text [ i + + ] = ' 0 ' + RtcTime . month / 10 ;
text [ i + + ] = ' 0 ' + RtcTime . month % 10 ;
text [ i + + ] = ' . ' ; // Lower half of the colon, depending on how the LEDs are connected to the TM1650 in the XY-Clock.
}
else if ( T_303WIFILC01 = = Settings - > display_options . type ) {
text [ i + + ] = ' . ' ; // Colon for 303WIFILC01
text [ i + + ] = ' 0 ' + RtcTime . month / 10 ;
text [ i + + ] = ' 0 ' + RtcTime . month % 10 ;
}
text [ i + + ] = 0 ;
TM1650DisplayText ( text ) ;
}
2022-12-31 08:19:53 +00:00
void TM1650Refresh ( void ) // Every second
{
if ( Settings - > display_mode ) { // Mode 0 is User text
switch ( Settings - > display_mode ) {
case 1 : // Time
TM1650Time ( ) ;
break ;
2023-03-12 08:22:40 +00:00
case 2 : // Date
TM1650Date ( ) ;
2022-12-31 08:19:53 +00:00
break ;
2023-03-12 08:22:40 +00:00
case 3 : // Time/Date
if ( TasmotaGlobal . uptime % Settings - > display_refresh )
{
TM1650Time ( ) ;
}
else
{
TM1650Date ( ) ;
}
break ;
case 4 :
2022-12-31 08:19:53 +00:00
case 5 :
2023-03-12 08:22:40 +00:00
// not in use
2022-12-31 08:19:53 +00:00
break ;
}
}
2023-03-12 08:22:40 +00:00
}
2022-12-31 08:19:53 +00:00
2023-03-12 08:22:40 +00:00
# endif // USE_DISPLAY_MODES1TO5
2022-12-31 08:19:53 +00:00
/*********************************************************************************************\
* Interface
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool Xdsp20 ( uint32_t function )
{
if ( ! I2cEnabled ( XI2C_74 ) ) { return false ; }
bool result = false ;
2023-03-12 08:22:40 +00:00
if ( FUNC_DISPLAY_INIT_DRIVER = = function )
{
2022-12-31 08:19:53 +00:00
TM1650InitDriver ( ) ;
}
2023-03-12 08:22:40 +00:00
else if ( ( TM1650Data . init_driver_done | | FUNC_DISPLAY_MODEL = = function )
& & ( XDSP_20 = = Settings - > display_model ) ) {
2022-12-31 08:19:53 +00:00
switch ( function ) {
2023-03-12 08:22:40 +00:00
case FUNC_DISPLAY_EVERY_50_MSECOND :
if ( disp_power & & ! Settings - > display_mode )
{
if ( TM1650Data . scroll )
{
TM1650ScrollText ( ) ;
}
if ( TM1650Data . show_clock )
{
TM1650ShowTime ( ) ;
}
}
break ;
2022-12-31 08:19:53 +00:00
case FUNC_DISPLAY_INIT :
TM1650Init ( dsp_init ) ;
break ;
# ifdef USE_DISPLAY_MODES1TO5
case FUNC_DISPLAY_EVERY_SECOND :
TM1650Refresh ( ) ;
break ;
# endif // USE_DISPLAY_MODES1TO5
2023-03-12 08:22:40 +00:00
case FUNC_DISPLAY_MODEL :
result = true ;
break ;
case FUNC_DISPLAY_SEVENSEG_TEXT :
case FUNC_DISPLAY_CLEAR :
case FUNC_DISPLAY_NUMBER :
case FUNC_DISPLAY_FLOAT :
case FUNC_DISPLAY_NUMBERNC :
case FUNC_DISPLAY_FLOATNC :
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 :
result = TM1650MainFunc ( function ) ;
break ;
case FUNC_DISPLAY_DIM :
TM1650Dim ( ) ;
break ;
case FUNC_DISPLAY_POWER :
TM1650DisplayOnOff ( ) ;
break ;
}
}
2022-12-31 08:19:53 +00:00
return result ;
2023-03-12 08:22:40 +00:00
}
2022-12-31 08:19:53 +00:00
# endif // USE_DISPLAY_TM1650
# endif // USE_DISPLAY
# endif // USE_I2C