From d079bdc2fdaa29ee69210ba3b51ade11a82fc1c5 Mon Sep 17 00:00:00 2001 From: Ajith Vasudevan Date: Fri, 19 Mar 2021 22:30:06 +0530 Subject: [PATCH] Added MAX7912 to TM1637 driver --- tasmota/xdsp_15_tm1637.ino | 1036 +++++++++++++++++++++++------------ tasmota/xdsp_16_max7219.ino | 878 ----------------------------- 2 files changed, 685 insertions(+), 1229 deletions(-) delete mode 100644 tasmota/xdsp_16_max7219.ino diff --git a/tasmota/xdsp_15_tm1637.ino b/tasmota/xdsp_15_tm1637.ino index 0b507fce5..861f2111d 100644 --- a/tasmota/xdsp_15_tm1637.ino +++ b/tasmota/xdsp_15_tm1637.ino @@ -21,7 +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. + on the inexpensive TM1637-, TM1638- and MAX7219-based seven-segment modules. Raw segments can also be displayed. @@ -45,9 +45,17 @@ CLK hardware pin --> "TM1638 CLK" STB hardware pin --> "TM1638 STB" + For MAX7219: + Connect the MAX7219 display module's pins to any free GPIOs of the ESP8266 module + and assign the pins as follows from Tasmota's GUI: - Once the GPIO configuration is saved and the ESP8266/ESP32 module restarts, set the Display Model to 15 - using the command "DisplayModel 15" + DIN hardware pin --> "MAX7219 DIN" + CS hardware pin --> "MAX7219 CS" + CLK hardware pin --> "MAX7219 CLK" + + Once the GPIO configuration is saved and the ESP8266/ESP32 module restarts, + set the Display Model to 15 and Display Mode to 0 + using the command "Backlog DisplayModel 15 ; DisplayMode 0" 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. @@ -136,63 +144,83 @@ "DisplayClock 0" // turn off clock +In addition, setting DisplayMode to 1 shows the time, setting it to 2 shows the date +and setting it to 3 alternates between time and date. + \*********************************************************************************************/ -#define XDSP_15 15 +#define XDSP_15 15 + +#define CMD_MAX_LEN 55 +#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 +#define MAX7219_ADDR 0 -#define CMD_MAX_LEN 55 -#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 #include "SevenSegmentTM1637.h" #include +#include SevenSegmentTM1637 *tm1637display; TM1638plus *tm1638display; +LedControl *max7219display; -enum display_types { TM1637, TM1638 }; +enum display_types +{ + TM1637, + TM1638, + MAX7219 +}; -struct { +struct +{ 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 buttons; uint8_t display_type = TM1637; - uint8_t prev_buttons; bool init_done = false; bool scroll = false; bool show_clock = false; bool clock_24 = false; - bool LED[8] = {false, false, false, false, false, false, false, false}; } TM1637Data; /*********************************************************************************************\ * Init function \*********************************************************************************************/ -void TM1637Init(void) { - if (PinUsed(GPIO_TM1638CLK) && PinUsed(GPIO_TM1638DIO) && PinUsed(GPIO_TM1638STB)) { +void TM1637Init(void) +{ + if (PinUsed(GPIO_TM1638CLK) && PinUsed(GPIO_TM1638DIO) && PinUsed(GPIO_TM1638STB)) + { TM1637Data.display_type = TM1638; Settings.display_width = 8; } - else if (PinUsed(GPIO_TM1637CLK) && PinUsed(GPIO_TM1637DIO)) { + else if (PinUsed(GPIO_TM1637CLK) && PinUsed(GPIO_TM1637DIO)) + { TM1637Data.display_type = TM1637; - if ((!Settings.display_width || Settings.display_width > 6)) { + if ((!Settings.display_width || Settings.display_width > 6)) + { Settings.display_width = 4; } } - else { + else if (PinUsed(GPIO_MAX7219DIN) && PinUsed(GPIO_MAX7219CLK) && PinUsed(GPIO_MAX7219CS)) + { + TM1637Data.display_type = MAX7219; + Settings.display_width = 8; + } + else + { return; } @@ -200,30 +228,73 @@ void TM1637Init(void) { Settings.display_cols[0] = Settings.display_width; Settings.display_height = 1; Settings.display_rows = Settings.display_height; + if(!Settings.display_dimmer || Settings.display_dimmer < 2 || Settings.display_dimmer > 15) Settings.display_dimmer = 8; - if (TM1637 == TM1637Data.display_type) { + if (TM1637 == TM1637Data.display_type) + { strcpy_P(TM1637Data.model_name, PSTR("TM1637")); tm1637display = new SevenSegmentTM1637(Pin(GPIO_TM1637CLK), Pin(GPIO_TM1637DIO)); tm1637display->begin(Settings.display_width, 1); } - else if (TM1638 == TM1637Data.display_type) { + else if (TM1638 == TM1637Data.display_type) + { strcpy_P(TM1637Data.model_name, PSTR("TM1638")); - tm1638display = new TM1638plus(Pin(GPIO_TM1638STB), Pin(GPIO_TM1638CLK), Pin(GPIO_TM1638DIO), true ); + tm1638display = new TM1638plus(Pin(GPIO_TM1638STB), Pin(GPIO_TM1638CLK), Pin(GPIO_TM1638DIO), true); tm1638display->displayBegin(); } + else if (MAX7219 == TM1637Data.display_type) + { + strcpy_P(TM1637Data.model_name, PSTR("MAX7219")); + max7219display = new LedControl(Pin(GPIO_MAX7219DIN), Pin(GPIO_MAX7219CLK), Pin(GPIO_MAX7219CS), 1); + max7219display->shutdown(MAX7219_ADDR, false); + } TM1637ClearDisplay(); TM1637Dim(); TM1637Data.init_done = true; AddLog(LOG_LEVEL_INFO, PSTR("DSP: %s with %d digits"), TM1637Data.model_name, Settings.display_width); } +// Function to display specified ascii char at specified position for MAX7219 +void displayMAX7219ASCII(uint8_t pos, char c) +{ + pos = 7 - pos; + max7219display->setChar(MAX7219_ADDR, pos, c, false); +} + +// Function to display specified ascii char with dot at specified position for MAX7219 +void displayMAX7219ASCIIwDot(uint8_t pos, char c) +{ + pos = 7 - pos; + max7219display->setChar(MAX7219_ADDR, pos, c, true); +} + +// Function to display raw segments at specified position for MAX7219 +void displayMAX72197Seg(uint8_t pos, uint8_t seg) +{ + bool dec_bit = seg & 128; + seg = seg << 1; + seg = seg | dec_bit; + uint8_t NO_OF_BITS = 8; + uint8_t reverse_num = 0; + for (uint8_t i = 0; i < NO_OF_BITS; i++) + { + if ((seg & (1 << i))) + reverse_num |= 1 << ((NO_OF_BITS - 1) - i); + } + seg = reverse_num; + + pos = 7 - pos; + max7219display->setRow(MAX7219_ADDR, pos, seg); +} + /*********************************************************************************************\ * 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 CmndTM1637Number(bool clear) { +bool CmndTM1637Number(bool clear) +{ char sNum[CMD_MAX_LEN]; char sLeadingzeros[CMD_MAX_LEN]; char sPosition[CMD_MAX_LEN]; @@ -236,47 +307,79 @@ bool CmndTM1637Number(bool clear) { 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 = atof(sNum); + 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 = atof(sNum); } - - if((position < 0) || (position > (Settings.display_width-1))) position = 0; + if ((position < 0) || (position > (Settings.display_width - 1))) + position = 0; AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: num %d, pos %d, lead %d, len %d"), num, position, leadingzeros, length); - if(clear) TM1637ClearDisplay(); + if (clear) + TM1637ClearDisplay(); 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; + if (!length) + length = strlen(txt); + if ((length < 0) || (length > Settings.display_width)) + length = Settings.display_width; - char pad = (leadingzeros ? '0': ' '); + char pad = (leadingzeros ? '0' : ' '); uint32_t i = position; uint8_t rawBytes[1]; - for(; iSettings.display_width) break; - if(TM1637Data.display_type == TM1637) { rawBytes[0] = tm1637display->encode(pad); tm1637display->printRaw(rawBytes, 1, i); } - else if(TM1637Data.display_type == TM1638) tm1638display->displayASCII(i, pad); + for (; i < position + (length - strlen(txt)); i++) + { + if (i > Settings.display_width) + break; + if (TM1637 == TM1637Data.display_type) + { + rawBytes[0] = tm1637display->encode(pad); + tm1637display->printRaw(rawBytes, 1, i); + } + else if (TM1638 == TM1637Data.display_type) + tm1638display->displayASCII(i, pad); + else if (MAX7219 == TM1637Data.display_type) + { + if (i > 7) + break; + displayMAX7219ASCII(i, pad); + } } - for(uint32_t j = 0; i< position + length; i++, j++) { - if(i>Settings.display_width) break; - if(txt[j] == 0) break; - if(TM1637Data.display_type == TM1637) { rawBytes[0] = tm1637display->encode(txt[j]); tm1637display->printRaw(rawBytes, 1, i); } - else if(TM1637Data.display_type == TM1638) tm1638display->displayASCII(i, txt[j]); + for (uint32_t j = 0; i < position + length; i++, j++) + { + if (i > Settings.display_width) + break; + if (txt[j] == 0) + break; + if (TM1637 == TM1637Data.display_type) + { + rawBytes[0] = tm1637display->encode(txt[j]); + tm1637display->printRaw(rawBytes, 1, i); + } + else if (TM1638 == TM1637Data.display_type) + tm1638display->displayASCII(i, txt[j]); + else if (MAX7219 == TM1637Data.display_type) + { + if (i > 7) + break; + if (txt[j] == 0) + break; + displayMAX7219ASCII(i, txt[j]); + } } return true; @@ -288,7 +391,8 @@ bool CmndTM1637Number(bool clear) { * 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 CmndTM1637Float(bool clear) { +bool CmndTM1637Float(bool clear) +{ char sNum[CMD_MAX_LEN]; char sPrecision[CMD_MAX_LEN]; @@ -302,102 +406,148 @@ bool CmndTM1637Float(bool clear) { 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 = atof(sNum); + 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 = atof(sNum); } + if ((position < 0) || (position > (Settings.display_width - 1))) + position = 0; + if ((precision < 0) || (precision > Settings.display_width)) + precision = Settings.display_width; - if((position < 0) || (position > (Settings.display_width-1))) position = 0; - if((precision < 0) || (precision > Settings.display_width)) precision = Settings.display_width; - - if(clear) TM1637ClearDisplay(); + if (clear) + TM1637ClearDisplay(); 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; + if (!length) + length = strlen(txt); + if ((length <= 0) || (length > Settings.display_width)) + length = Settings.display_width; AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: num %4_f, prec %d, len %d"), &fnum, precision, length); - if(TM1637Data.display_type == TM1637) { + if (TM1637 == TM1637Data.display_type) + { uint8_t rawBytes[1]; - for(uint32_t i=0, j=0; iencode(txt[i]); - if(txt[i+1] == '.') { + if (txt[i + 1] == '.') + { rawBytes[0] = rawBytes[0] | 128; i++; length++; } - if((j+position) > Settings.display_width) break; - tm1637display->printRaw(rawBytes, 1, j+position); + if ((j + position) > Settings.display_width) + break; + tm1637display->printRaw(rawBytes, 1, j + position); } - } else if(TM1637Data.display_type == TM1638) { - for(uint32_t i=0, j=0; i 7) break; - if(txt[i] == 0) break; - if(txt[i+1] == '.') { - tm1638display->displayASCIIwDot(j+position, txt[i]); + } + else if (TM1638 == TM1637Data.display_type) + { + for (uint32_t i = 0, j = 0; i < length; i++, j++) + { + if ((j + position) > 7) + break; + if (txt[i] == 0) + break; + if (txt[i + 1] == '.') + { + tm1638display->displayASCIIwDot(j + position, txt[i]); i++; length++; } - else tm1638display->displayASCII(j+position, txt[i]); + else + tm1638display->displayASCII(j + position, txt[i]); + } + } + else if (MAX7219 == TM1637Data.display_type) + { + for (uint32_t i = 0, j = 0; i < length; i++, j++) + { + if ((j + position) > 7) + break; + if (txt[i] == 0) + break; + if (txt[i + 1] == '.') + { + displayMAX7219ASCIIwDot(j + position, txt[i]); + i++; + length++; + } + else + displayMAX7219ASCII(j + position, txt[i]); } } return true; } - // /*********************************************************************************************\ // * Clears the display // * Command: DisplayClear // \*********************************************************************************************/ -bool CmndTM1637Clear(void) { +bool CmndTM1637Clear(void) +{ TM1637ClearDisplay(); sprintf(TM1637Data.msg, PSTR("Cleared")); XdrvMailbox.data = TM1637Data.msg; return true; } - // /*********************************************************************************************\ // * Clears the display // \*********************************************************************************************/ -void TM1637ClearDisplay (void) { - if(TM1637Data.display_type == TM1637) { - unsigned char arr[] = {0}; - for(int i=0; iprintRaw(arr, 1, i); - } else if(TM1637Data.display_type == TM1638) { - for(int i=0; idisplay7Seg(i, 0); +void TM1637ClearDisplay(void) +{ + if (TM1637 == TM1637Data.display_type) + { + unsigned char arr[] = {0}; + for (int i = 0; i < Settings.display_width; i++) + tm1637display->printRaw(arr, 1, i); + } + else if (TM1638 == TM1637Data.display_type) + { + for (int i = 0; i < Settings.display_width; i++) + tm1638display->display7Seg(i, 0); + } + else if (MAX7219 == TM1637Data.display_type) + { + max7219display->clearDisplay(MAX7219_ADDR); } } - /*********************************************************************************************\ * Display scrolling text * Command: DisplayTM1637Data.scroll_text text \*********************************************************************************************/ -bool CmndTM1637ScrollText(void) { +bool CmndTM1637ScrollText(void) +{ AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: Text %s"), XdrvMailbox.data); - if(XdrvMailbox.data_len > SCROLL_MAX_LEN) { + if (XdrvMailbox.data_len > SCROLL_MAX_LEN) + { snprintf(TM1637Data.msg, sizeof(TM1637Data.msg), PSTR("Text too long. Length should be less than %d"), SCROLL_MAX_LEN); XdrvMailbox.data = TM1637Data.msg; return false; - } else { + } + 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; @@ -405,65 +555,85 @@ bool CmndTM1637ScrollText(void) { TM1637Data.scroll = true; return true; } - } - - /*********************************************************************************************\ * Sets the scroll delay for scrolling text. * Command: DisplayTM1637Data.scroll_delay delay {0-15} // default = 4 \*********************************************************************************************/ -bool CmndTM1637ScrollDelay(void) { - if(ArgC() == 0) { +bool CmndTM1637ScrollDelay(void) +{ + if (ArgC() == 0) + { XdrvMailbox.payload = TM1637Data.scroll_delay; return true; } - if(TM1637Data.scroll_delay<0) TM1637Data.scroll_delay=0; + if (TM1637Data.scroll_delay < 0) + TM1637Data.scroll_delay = 0; TM1637Data.scroll_delay = XdrvMailbox.payload; return true; } - - /*********************************************************************************************\ * Scrolls a given string. Called every 50ms \*********************************************************************************************/ -void TM1637ScrollText(void) { +void TM1637ScrollText(void) +{ TM1637Data.iteration++; - if(TM1637Data.scroll_delay) TM1637Data.iteration = TM1637Data.iteration % TM1637Data.scroll_delay; - else TM1637Data.iteration = 0; - if(TM1637Data.iteration) return; + if (TM1637Data.scroll_delay) + TM1637Data.iteration = TM1637Data.iteration % TM1637Data.scroll_delay; + else + TM1637Data.iteration = 0; + if (TM1637Data.iteration) + return; - if(TM1637Data.scroll_index > strlen(TM1637Data.scroll_text)) { - TM1637Data.scroll= false; + if (TM1637Data.scroll_index > strlen(TM1637Data.scroll_text)) + { + TM1637Data.scroll = false; TM1637Data.scroll_index = 0; return; } uint8_t rawBytes[1]; - for(uint32_t i=0, j=TM1637Data.scroll_index; i< 1 + strlen(TM1637Data.scroll_text); i++, j++) { - if(i > (Settings.display_width-1)) { break; } + for (uint32_t i = 0, j = TM1637Data.scroll_index; i < 1 + strlen(TM1637Data.scroll_text); i++, j++) + { + if (i > (Settings.display_width - 1)) + { + break; + } rawBytes[0] = tm1637display->encode(TM1637Data.scroll_text[j]); bool dotSkipped = false; - if(TM1637Data.scroll_text[j+1] == '.') { + if (TM1637Data.scroll_text[j + 1] == '.') + { dotSkipped = true; rawBytes[0] = rawBytes[0] | 128; j++; - } else if(TM1637Data.scroll_text[j] == '^') { + } + else if (TM1637Data.scroll_text[j] == '^') + { rawBytes[0] = 1 | 2 | 32 | 64; } - if(!dotSkipped && TM1637Data.scroll_text[j] == '.') { + 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) { + if (TM1637Data.scroll_text[j + 1] == '.') + { + rawBytes[0] = rawBytes[0] | 128; + } + if (TM1637 == TM1637Data.display_type) + { tm1637display->printRaw(rawBytes, 1, i); - } else if(TM1637Data.display_type == TM1638) { + } + else if (TM1638 == TM1637Data.display_type) + { tm1638display->display7Seg(i, rawBytes[0]); } - + else if (MAX7219 == TM1637Data.display_type) + { + displayMAX72197Seg(i, rawBytes[0]); + } } TM1637Data.scroll_index++; } @@ -472,14 +642,16 @@ void TM1637ScrollText(void) { * Displays a horizontal bar graph. Takes a percentage number (0-100) as input * Command: DisplayLevel level {0-100} \*********************************************************************************************/ -bool CmndTM1637Level(void) { +bool CmndTM1637Level(void) +{ uint16_t val = XdrvMailbox.payload; - if((val < LEVEL_MIN) || (val > LEVEL_MAX)) { + 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; } - uint8_t totalBars = 2*Settings.display_width; + uint8_t totalBars = 2 * Settings.display_width; 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]; @@ -492,16 +664,23 @@ bool CmndTM1637Level(void) { TM1637ClearDisplay(); uint8_t rawBytes[1]; - for(int i=1; i<=numBars; i++) { - uint8_t digit = (i-1) / 2; - uint8_t value = (((i%2) == 0) ? 54 : 48); - if(TM1637Data.display_type == TM1637) { + for (int i = 1; i <= numBars; i++) + { + uint8_t digit = (i - 1) / 2; + uint8_t value = (((i % 2) == 0) ? 54 : 48); + if (TM1637 == TM1637Data.display_type) + { rawBytes[0] = value; tm1637display->printRaw(rawBytes, 1, digit); - } else if(TM1637Data.display_type == TM1638) { + } + else if (TM1638 == TM1637Data.display_type) + { tm1638display->display7Seg(digit, value); } - + else if (MAX7219 == TM1637Data.display_type) + { + displayMAX72197Seg(digit, value); + } } return true; } @@ -514,8 +693,9 @@ 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) { - uint8_t DATA[6] = { 0, 0, 0, 0, 0, 0 }; +bool CmndTM1637Raw(void) +{ + uint8_t DATA[6] = {0, 0, 0, 0, 0, 0}; char as[CMD_MAX_LEN]; char bs[CMD_MAX_LEN]; @@ -527,60 +707,76 @@ bool CmndTM1637Raw(void) { char sLength[CMD_MAX_LEN]; char sPos[CMD_MAX_LEN]; - uint32_t position = 0; uint32_t length = 0; switch (ArgC()) { - case 8 : - subStr(fs, XdrvMailbox.data, ",", 8); - DATA[5] = atoi(fs); - case 7 : - subStr(es, XdrvMailbox.data, ",", 7); - DATA[4] = atoi(es); - 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); + case 8: + subStr(fs, XdrvMailbox.data, ",", 8); + DATA[5] = atoi(fs); + case 7: + subStr(es, XdrvMailbox.data, ",", 7); + DATA[4] = atoi(es); + 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; + 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("TM7: a %d, b %d, c %d, d %d, e %d, f %d, len %d, pos %d"), - DATA[0], DATA[1], DATA[2], DATA[3], DATA[4], DATA[5], length, position); + DATA[0], DATA[1], DATA[2], DATA[3], DATA[4], DATA[5], length, position); - if(TM1637Data.display_type == TM1637) { + if (TM1637 == TM1637Data.display_type) + { uint8_t rawBytes[1]; - for(uint32_t i=position; i(Settings.display_width-1)) break; - rawBytes[0] = DATA[i-position]; + for (uint32_t i = position; i < position + length; i++) + { + if (i > (Settings.display_width - 1)) + break; + rawBytes[0] = DATA[i - position]; tm1637display->printRaw(rawBytes, 1, i); } - } else if(TM1637Data.display_type == TM1638) { - for(uint32_t i=position; i7) break; - tm1638display->display7Seg(i, DATA[i-position]); + } + else if (TM1638 == TM1637Data.display_type) + { + for (uint32_t i = position; i < position + length; i++) + { + if (i > 7) + break; + tm1638display->display7Seg(i, DATA[i - position]); + } + } + else if (MAX7219 == TM1637Data.display_type) + { + for (uint32_t i = position; i < position + length; i++) + { + if (i > 7) + break; + displayMAX72197Seg(i, DATA[i - position]); } } - - return true; } @@ -590,7 +786,8 @@ bool CmndTM1637Raw(void) { * 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 CmndTM1637Text(bool clear) { +bool CmndTM1637Text(bool clear) +{ char sString[CMD_MAX_LEN + 1]; char sPosition[CMD_MAX_LEN]; char sLength[CMD_MAX_LEN]; @@ -599,74 +796,126 @@ bool CmndTM1637Text(bool clear) { 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); + 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; + if ((position < 0) || (position > (Settings.display_width - 1))) + position = 0; AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: sString %s, pos %d, len %d"), sString, position, length); - if(clear) TM1637ClearDisplay(); + if (clear) + TM1637ClearDisplay(); - if(!length) length = strlen(sString); - if((length < 0) || (length > Settings.display_width)) length = Settings.display_width; + if (!length) + length = strlen(sString); + if ((length < 0) || (length > Settings.display_width)) + length = Settings.display_width; uint32_t i = position; - if(TM1637Data.display_type == TM1637) { + if (TM1637 == TM1637Data.display_type) + { uint8_t rawBytes[1]; - for(uint32_t j = 0; i< position + length; i++, j++) { - if(i > (Settings.display_width-1)) break; - if(sString[j] == 0) break; + for (uint32_t j = 0; i < position + length; i++, j++) + { + if (i > (Settings.display_width - 1)) + break; + if (sString[j] == 0) + break; rawBytes[0] = tm1637display->encode(sString[j]); bool dotSkipped = false; - if(sString[j+1] == '.') { + if (sString[j + 1] == '.') + { dotSkipped = true; rawBytes[0] = rawBytes[0] | 128; j++; - } else if(sString[j] == '^') { + } + else if (sString[j] == '^') + { rawBytes[0] = 1 | 2 | 32 | 64; } - if(!dotSkipped && sString[j] == '.') rawBytes[0] = 128; + if (!dotSkipped && sString[j] == '.') + rawBytes[0] = 128; tm1637display->printRaw(rawBytes, 1, i); } - } else if(TM1637Data.display_type == TM1638) { - for(uint32_t j = 0; i< position + length; i++, j++) { - if(i > 7) break; - if(sString[j] == 0) break; - if(sString[j+1] == '.') { + } + else if (TM1638 == TM1637Data.display_type) + { + for (uint32_t j = 0; i < position + length; i++, j++) + { + if (i > 7) + break; + if (sString[j] == 0) + break; + if (sString[j + 1] == '.') + { tm1638display->displayASCIIwDot(i, sString[j]); j++; - } else if(sString[j] == '^') { + } + else if (sString[j] == '^') + { tm1638display->display7Seg(i, (1 | 2 | 32 | 64)); - } else tm1638display->displayASCII(i, sString[j]); + } + else + tm1638display->displayASCII(i, sString[j]); + } + } + else if (MAX7219 == TM1637Data.display_type) + { + uint8_t rawBytes[1]; + for (uint32_t j = 0; i < position + length; i++, j++) + { + if (i > 7) + 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; + displayMAX72197Seg(i, rawBytes[0]); } } - return true; } - /*********************************************************************************************\ * 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 CmndTM1637Clock(void) +{ TM1637Data.show_clock = XdrvMailbox.payload; - if(ArgC() == 0) XdrvMailbox.payload = 1; - if(XdrvMailbox.payload > 1) TM1637Data.clock_24 = true; - else if(XdrvMailbox.payload == 1) TM1637Data.clock_24 = false; + if (ArgC() == 0) + XdrvMailbox.payload = 1; + if (XdrvMailbox.payload > 1) { + TM1637Data.clock_24 = true; + XdrvMailbox.payload = 2; + } else { + TM1637Data.clock_24 = false; + XdrvMailbox.payload = 1; + } AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: TM1637Data.show_clock %d, TM1637Data.clock_24 %d"), TM1637Data.show_clock, TM1637Data.clock_24); @@ -674,110 +923,149 @@ bool CmndTM1637Clock(void) { return true; } - /*********************************************************************************************\ * refreshes the time if clock is displayed \*********************************************************************************************/ -void TM1637ShowTime() { +void TM1637ShowTime() +{ uint8_t hr = RtcTime.hour; uint8_t mn = RtcTime.minute; // uint8_t hr = 1; // uint8_t mn = 0; char z = ' '; - if(TM1637Data.clock_24) { + if (TM1637Data.clock_24) + { z = '0'; - } else { - if(hr > 12) hr -= 12; - if(hr == 0) hr = 12; + } + else + { + if (hr > 12) + hr -= 12; + if (hr == 0) + hr = 12; } char tm[5]; - if(hr < 10) { - if(mn < 10) snprintf(tm, sizeof(tm), PSTR("%c%d0%d"), z, hr, mn); - else snprintf(tm, sizeof(tm), PSTR("%c%d%d"), z, hr, mn); - } else { - if(mn < 10) snprintf(tm, sizeof(tm), PSTR("%d0%d"), hr, mn); - else snprintf(tm, sizeof(tm), PSTR("%d%d"), hr, mn); + if (hr < 10) + { + if (mn < 10) + snprintf(tm, sizeof(tm), PSTR("%c%d0%d"), z, hr, mn); + else + snprintf(tm, sizeof(tm), PSTR("%c%d%d"), z, hr, mn); + } + else + { + if (mn < 10) + snprintf(tm, sizeof(tm), PSTR("%d0%d"), hr, mn); + else + snprintf(tm, sizeof(tm), PSTR("%d%d"), hr, mn); } - if(TM1637Data.display_type == TM1637) { + if (TM1637 == TM1637Data.display_type) + { uint8_t rawBytes[1]; - for(uint32_t i = 0; i< 4; i++) { + for (uint32_t i = 0; i < 4; i++) + { rawBytes[0] = tm1637display->encode(tm[i]); - if((millis() % 1000) > 500 && (i == 1)) rawBytes[0] = rawBytes[0] | 128; + if ((millis() % 1000) > 500 && (i == 1)) + rawBytes[0] = rawBytes[0] | 128; tm1637display->printRaw(rawBytes, 1, i); } - } else if(TM1637Data.display_type == TM1638) { - for(uint32_t i = 0; i< 4; i++) { - if((millis() % 1000) > 500 && (i == 1)) tm1638display->displayASCIIwDot(i, tm[i]); - else tm1638display->displayASCII(i, tm[i]); + } + else if (TM1638 == TM1637Data.display_type) + { + for (uint32_t i = 0; i < 4; i++) + { + if ((millis() % 1000) > 500 && (i == 1)) + tm1638display->displayASCIIwDot(i, tm[i]); + else + tm1638display->displayASCII(i, tm[i]); + } + } + else if (MAX7219 == TM1637Data.display_type) + { + for (uint32_t i = 0; i < 4; i++) + { + if ((millis() % 1000) > 500 && (i == 1)) + displayMAX7219ASCIIwDot(i, tm[i]); + else + displayMAX7219ASCII(i, tm[i]); } } - } /*********************************************************************************************\ * This function is called for all Display functions. \*********************************************************************************************/ -bool TM1637MainFunc(uint8_t fn) { +bool TM1637MainFunc(uint8_t fn) +{ bool result = false; - if(XdrvMailbox.data_len > CMD_MAX_LEN) { + 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 = CmndTM1637Clear(); - break; - case FUNC_DISPLAY_NUMBER : - result = CmndTM1637Number(true); - break; - case FUNC_DISPLAY_NUMBERNC : - result = CmndTM1637Number(false); - break; - case FUNC_DISPLAY_FLOAT : - result = CmndTM1637Float(true); - break; - case FUNC_DISPLAY_FLOATNC : - result = CmndTM1637Float(false); - break; - case FUNC_DISPLAY_RAW: - result = CmndTM1637Raw(); - break; - case FUNC_DISPLAY_SEVENSEG_TEXT: - result = CmndTM1637Text(true); - break; - case FUNC_DISPLAY_SEVENSEG_TEXTNC: - result = CmndTM1637Text(false); - break; - case FUNC_DISPLAY_LEVEL: - result = CmndTM1637Level(); - break; - case FUNC_DISPLAY_SCROLLTEXT: - result = CmndTM1637ScrollText(); - break; - case FUNC_DISPLAY_SCROLLDELAY: - result = CmndTM1637ScrollDelay(); - break; - case FUNC_DISPLAY_CLOCK: - result = CmndTM1637Clock(); - break; + switch (fn) + { + case FUNC_DISPLAY_CLEAR: + result = CmndTM1637Clear(); + break; + case FUNC_DISPLAY_NUMBER: + result = CmndTM1637Number(true); + break; + case FUNC_DISPLAY_NUMBERNC: + result = CmndTM1637Number(false); + break; + case FUNC_DISPLAY_FLOAT: + result = CmndTM1637Float(true); + break; + case FUNC_DISPLAY_FLOATNC: + result = CmndTM1637Float(false); + break; + case FUNC_DISPLAY_RAW: + result = CmndTM1637Raw(); + break; + case FUNC_DISPLAY_SEVENSEG_TEXT: + result = CmndTM1637Text(true); + break; + case FUNC_DISPLAY_SEVENSEG_TEXTNC: + result = CmndTM1637Text(false); + break; + case FUNC_DISPLAY_LEVEL: + result = CmndTM1637Level(); + break; + case FUNC_DISPLAY_SCROLLTEXT: + result = CmndTM1637ScrollText(); + break; + case FUNC_DISPLAY_SCROLLDELAY: + result = CmndTM1637ScrollDelay(); + break; + case FUNC_DISPLAY_CLOCK: + result = CmndTM1637Clock(); + break; } return result; } -void TM1637Dim(void) { +void TM1637Dim(void) +{ // Settings.display_dimmer = 0 - 15 - uint8_t brightness = Settings.display_dimmer >> 1; // 0 - 7 + uint8_t brightness = Settings.display_dimmer >> 1; // 0 - 7 - if (TM1637 == TM1637Data.display_type) { - tm1637display->setBacklight(brightness * 12); // 0 - 84 + if (TM1637 == TM1637Data.display_type) + { + tm1637display->setBacklight(brightness * 12); // 0 - 84 } - else if (TM1637Data.display_type == TM1638) { - tm1638display->brightness(brightness); // 0 - 7 + else if (TM1638 == TM1637Data.display_type) + { + tm1638display->brightness(brightness); // 0 - 7 + } + else if (MAX7219 == TM1637Data.display_type) + { + max7219display->setIntensity(MAX7219_ADDR, brightness); // 0 - 7 } } @@ -785,35 +1073,50 @@ void TM1637Dim(void) { #ifdef USE_DISPLAY_MODES1TO5 -void TM1637Print(char* txt) { - for (uint32_t i = 0; i < Settings.display_cols[0]; i++) { - if (TM1637 == TM1637Data.display_type) { +void TM1637Print(char *txt) +{ + for (uint32_t i = 0; i < Settings.display_cols[0]; i++) + { + if (TM1637 == TM1637Data.display_type) + { uint8_t rawBytes[1]; rawBytes[0] = tm1637display->encode(txt[i]); -// if ((millis() % 1000) > 500 && (i == 1)) { rawBytes[0] = rawBytes[0] | 128; } + // if ((millis() % 1000) > 500 && (i == 1)) { rawBytes[0] = rawBytes[0] | 128; } tm1637display->printRaw(rawBytes, 1, i); } - else if (TM1638 == TM1637Data.display_type) { -// if ((millis() % 1000) > 500 && (i == 1)) { tm1638display->displayASCIIwDot(i, txt[i]); } + else if (TM1638 == TM1637Data.display_type) + { + // if ((millis() % 1000) > 500 && (i == 1)) { tm1638display->displayASCIIwDot(i, txt[i]); } tm1638display->displayASCII(i, txt[i]); } + else if (MAX7219 == TM1637Data.display_type) + { + // if ((millis() % 1000) > 500 && (i == 1)) { tm1638display->displayASCIIwDot(i, txt[i]); } + displayMAX7219ASCII(i, txt[i]); + } + } } -void TM1637Center(char* txt) { - char line[Settings.display_cols[0] +2]; +void TM1637Center(char *txt) +{ + char line[Settings.display_cols[0] + 2]; int len = strlen(txt); int offset = 0; - if (len >= Settings.display_cols[0]) { + if (len >= Settings.display_cols[0]) + { len = Settings.display_cols[0]; - } else { + } + else + { offset = (Settings.display_cols[0] - len) / 2; } memset(line, 0x20, Settings.display_cols[0]); line[Settings.display_cols[0]] = 0; - for (uint32_t i = 0; i < len; i++) { - line[offset +i] = txt[i]; + for (uint32_t i = 0; i < len; i++) + { + line[offset + i] = txt[i]; } TM1637Print(line); } @@ -845,54 +1148,70 @@ bool TM1637PrintLog(void) { } */ -void TM1637Time(void) { - char line[Settings.display_cols[0] +1]; +void TM1637Time(void) +{ + char line[Settings.display_cols[0] + 1]; - if (Settings.display_cols[0] >= 8) { + if (Settings.display_cols[0] >= 8) + { snprintf_P(line, sizeof(line), PSTR("%02d %02d %02d"), RtcTime.hour, RtcTime.minute, RtcTime.second); } - else if (Settings.display_cols[0] >= 6) { + else if (Settings.display_cols[0] >= 6) + { snprintf_P(line, sizeof(line), PSTR("%02d%02d%02d"), RtcTime.hour, RtcTime.minute, RtcTime.second); } - else { + else + { snprintf_P(line, sizeof(line), PSTR("%02d%02d"), RtcTime.hour, RtcTime.minute); } TM1637Center(line); } -void TM1637Date(void) { - char line[Settings.display_cols[0] +1]; +void TM1637Date(void) +{ + char line[Settings.display_cols[0] + 1]; - if (Settings.display_cols[0] >= 8) { - snprintf_P(line, sizeof(line), PSTR("%02d-%02d-%02d"), RtcTime.day_of_month, RtcTime.month, RtcTime.year -2000); + if (Settings.display_cols[0] >= 8) + { + snprintf_P(line, sizeof(line), PSTR("%02d-%02d-%02d"), RtcTime.day_of_month, RtcTime.month, RtcTime.year - 2000); } - else if (Settings.display_cols[0] >= 6) { - snprintf_P(line, sizeof(line), PSTR("%02d%02d%02d"), RtcTime.day_of_month, RtcTime.month, RtcTime.year -2000); + else if (Settings.display_cols[0] >= 6) + { + snprintf_P(line, sizeof(line), PSTR("%02d%02d%02d"), RtcTime.day_of_month, RtcTime.month, RtcTime.year - 2000); } - else { + else + { snprintf_P(line, sizeof(line), PSTR("%02d%02d"), RtcTime.day_of_month, RtcTime.month); } TM1637Center(line); } -void TM1637Refresh(void) { // Every second - if (!disp_power || !Settings.display_mode) { return; } // Mode 0 is User text +void TM1637Refresh(void) +{ // Every second + if (!disp_power || !Settings.display_mode) + { + return; + } // Mode 0 is User text - switch (Settings.display_mode) { - case 1: // Time + switch (Settings.display_mode) + { + case 1: // Time + TM1637Time(); + break; + case 2: // Date + TM1637Date(); + break; + case 3: // Time + if (TasmotaGlobal.uptime % Settings.display_refresh) + { TM1637Time(); - break; - case 2: // Date + } + else + { TM1637Date(); - break; - case 3: // Time - if (TasmotaGlobal.uptime % Settings.display_refresh) { - TM1637Time(); - } else { - TM1637Date(); - } - break; -/* + } + break; + /* case 4: // Mqtt TM1637PrintLog(); break; @@ -904,61 +1223,76 @@ void TM1637Refresh(void) { // Every second } } -#endif // USE_DISPLAY_MODES1TO5 +#endif // USE_DISPLAY_MODES1TO5 /*********************************************************************************************\ * Interface \*********************************************************************************************/ -bool Xdsp15(uint8_t function) { +bool Xdsp15(uint8_t function) +{ bool result = false; - if (FUNC_DISPLAY_INIT_DRIVER == function) { + if (FUNC_DISPLAY_INIT_DRIVER == function) + { TM1637Init(); } - else if (TM1637Data.init_done && (XDSP_15 == Settings.display_model)) { - switch (function) { - case FUNC_DISPLAY_EVERY_50_MSECOND: - if (disp_power && !Settings.display_mode) { - if (TM1637Data.scroll) { TM1637ScrollText(); } - if (TM1637Data.show_clock) { TM1637ShowTime(); } + else if (TM1637Data.init_done && (XDSP_15 == Settings.display_model)) + { + switch (function) + { + case FUNC_DISPLAY_EVERY_50_MSECOND: + if (disp_power && !Settings.display_mode) + { + if (TM1637Data.scroll) + { + TM1637ScrollText(); } - break; + if (TM1637Data.show_clock) + { + TM1637ShowTime(); + } + } + break; #ifdef USE_DISPLAY_MODES1TO5 - case FUNC_DISPLAY_EVERY_SECOND: - TM1637Refresh(); - break; -#endif // USE_DISPLAY_MODES1TO5 - 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: - if (disp_power && !Settings.display_mode) { - TM1637Data.show_clock = false; - result = TM1637MainFunc(function); - } - break; - case FUNC_DISPLAY_DIM: - TM1637Dim(); - break; - case FUNC_DISPLAY_POWER: - if (!disp_power) { TM1637ClearDisplay(); } - break; + case FUNC_DISPLAY_EVERY_SECOND: + TM1637Refresh(); + break; +#endif // USE_DISPLAY_MODES1TO5 + 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: + if (disp_power && !Settings.display_mode) + { + TM1637Data.show_clock = false; + result = TM1637MainFunc(function); + } + break; + case FUNC_DISPLAY_DIM: + TM1637Dim(); + break; + case FUNC_DISPLAY_POWER: + if (!disp_power) + { + TM1637ClearDisplay(); + } + break; } } return result; } -#endif // USE_DISPLAY_TM1637 -#endif // USE_DISPLAY +#endif // USE_DISPLAY_TM1637 +#endif // USE_DISPLAY diff --git a/tasmota/xdsp_16_max7219.ino b/tasmota/xdsp_16_max7219.ino deleted file mode 100644 index c8a39b280..000000000 --- a/tasmota/xdsp_16_max7219.ino +++ /dev/null @@ -1,878 +0,0 @@ -/* - xdsp_16_max7219.ino - Support for MAX7219- based seven-segment displays for Tasmota - - Copyright (C) 2021 Ajith Vasudevan - - 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 . -*/ - -#ifdef USE_DISPLAY -#ifdef USE_DISPLAY_MAX7219 -/*********************************************************************************************\ - This driver enables the display of numbers (both integers and floats) and basic text - on the inexpensive MAX7219-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). - - To use, compile Tasmota with USE_DISPLAY and USE_DISPLAY_MAX7219, or build the tasmota-display env. - - Connect the MAX7219 display module's pins to any free GPIOs of the ESP8266 module - and assign the pins as follows from Tasmota's GUI: - - DIN hardware pin --> "MAX7219 DIN" - CS hardware pin --> "MAX7219 CS" - CLK hardware pin --> "MAX7219 CLK" - - - Once the GPIO configuration is saved and the ESP8266/ESP32 module restarts, set the Display Model to 16 - using the command "DisplayModel 16" - - After the ESP8266/ESP32 module restarts again, the following "Display" commands can be used: - - - DisplayClear - - Clears the display, command: "DisplayClear" - - - DisplayNumber num [,position {0-(MAX7219Data.num_digits-1))} [,leading_zeros {0|1} [,length {1 to MAX7219Data.num_digits}]]] - - Clears and then displays number without decimal. command e.g., "DisplayNumber 1234" - Control 'leading zeros', 'length' and 'position' with "DisplayNumber 1234, , , " - 'leading zeros' can be 1 or 0 (default), 'length' can be 1 to MAX7219Data.num_digits, 'position' can be 0 (left-most) to MAX7219Data.num_digits (right-most). - See function description below for more details. - - DisplayNumberNC num [,position {0-(MAX7219Data.num_digits-1))} [,leading_zeros {0|1} [,length {1 to MAX7219Data.num_digits}]]] - - Display integer number as above, but without clearing first. e.g., "DisplayNumberNC 1234". Usage is same as above. - - - - DisplayFloat num [,position {0-(MAX7219Data.num_digits-1)} [,precision {0-MAX7219Data.num_digits} [,length {1 to MAX7219Data.num_digits}]]] - - 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-(MAX7219Data.num_digits-1)} [,precision {0-MAX7219Data.num_digits} [,length {1 to MAX7219Data.num_digits}]]] - - Displays float (with decimal point) as above, but without clearing first. command e.g., "DisplayFloatNC 12.34" - See function description below for more details. - - - - DisplayBrightness num {1-8} - - Set brightness (1 to 8) command e.g., "DisplayBrightness 2" - - - - DisplayRaw position {0-(MAX7219Data.num_digits-1)},length {1 to MAX7219Data.num_digits}, num1 [, num2[, num3[, num4[, ...upto MAX7219Data.num_digits numbers]]]]] - - Takes upto MAX7219Data.num_digits 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-(MAX7219Data.num_digits-1)} [,length {1 to MAX7219Data.num_digits}]] - - Clears and then displays basic text. command e.g., "DisplayText ajith vasudevan" - Control 'length' and 'position' with "DisplayText , , " - 'length' can be 1 to MAX7219Data.num_digits, 'position' can be 0 (left-most) to MAX7219Data.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-MAX7219Data.num_digits-1} [,length {1 to MAX7219Data.num_digits}]] - - Clears first, then displays text. Usage is same as above. - - - - DisplayScrollText text - - Displays scrolling text. - - - - 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 - - - -\*********************************************************************************************/ - -#define XDSP_16 16 - -#define BRIGHTNESS_MIN 1 -#define BRIGHTNESS_MAX 8 -#define CMD_MAX_LEN 55 -#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 -#define MAX7219_ADDR 0 - -#include - -LedControl *max7219display; - -struct -{ - char scroll_text[CMD_MAX_LEN]; - char msg[60]; - char model_name[8]; - uint8_t num_digits = 4; - uint8_t scroll_delay = 4; - uint8_t scroll_index = 0; - uint8_t iteration = 0; - uint8_t brightness = 5; - uint8_t prev_buttons; - - bool init_done = false; - bool scroll = false; - bool show_clock = false; - bool clock_24 = false; -} MAX7219Data; - -/*********************************************************************************************\ -* Init function -\*********************************************************************************************/ -void MAXDriverInit(void) -{ - - if (!(PinUsed(GPIO_MAX7219DIN) && PinUsed(GPIO_MAX7219CLK) && PinUsed(GPIO_MAX7219CS))) - return; - - Settings.display_model == XDSP_16; - MAX7219Data.num_digits = 8; - - strcpy(MAX7219Data.model_name, "MAX7219"); - max7219display = new LedControl(Pin(GPIO_MAX7219DIN), Pin(GPIO_MAX7219CLK), Pin(GPIO_MAX7219CS), 1); - max7219display->shutdown(MAX7219_ADDR, false); - - maxClearDisplay(); - MAX7219Data.brightness = (Settings.display_dimmer ? Settings.display_dimmer : MAX7219Data.brightness); - maxSetBrightness(MAX7219Data.brightness); - MAX7219Data.init_done = true; - AddLog(LOG_LEVEL_INFO, PSTR("DSP: %s display driver initialized with %d digits"), MAX7219Data.model_name, MAX7219Data.num_digits); -} - -// Function to display specified ascii char at specified position for MAX7219 -void displayMAX7219ASCII(uint8_t pos, char c) -{ - pos = 7 - pos; - max7219display->setChar(MAX7219_ADDR, pos, c, false); -} - -// Function to display specified ascii char with dot at specified position for MAX7219 -void displayMAX7219ASCIIwDot(uint8_t pos, char c) -{ - pos = 7 - pos; - max7219display->setChar(MAX7219_ADDR, pos, c, true); -} - -// Function to display raw segments at specified position for MAX7219 -void displayMAX72197Seg(uint8_t pos, uint8_t seg) -{ - bool dec_bit = seg & 128; - seg = seg << 1; - seg = seg | dec_bit; - uint8_t NO_OF_BITS = 8; - uint8_t reverse_num = 0; - for (uint8_t i = 0; i < NO_OF_BITS; i++) - { - if ((seg & (1 << i))) - reverse_num |= 1 << ((NO_OF_BITS - 1) - i); - } - seg = reverse_num; - - pos = 7 - pos; - max7219display->setRow(MAX7219_ADDR, pos, seg); -} - -/*********************************************************************************************\ -* 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-(MAX7219Data.num_digits-1)} [,leading_zeros {0|1} [,length {1 to MAX7219Data.num_digits}]]] -* DisplayNumberNC num [,position {0-(MAX7219Data.num_digits-1)} [,leading_zeros {0|1} [,length {1 to MAX7219Data.num_digits}]]] // "NC" --> "No Clear" -\*********************************************************************************************/ -bool MAXCmndNumber(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 = atof(sNum); - } - - if ((position < 0) || (position > (MAX7219Data.num_digits - 1))) - position = 0; - - AddLog(LOG_LEVEL_DEBUG, PSTR("MAX: num %d, pos %d, lead %d, len %d"), num, position, leadingzeros, length); - - if (clear) - maxClearDisplay(); - - char txt[30]; - snprintf_P(txt, sizeof(txt), PSTR("%d"), num); - if (!length) - length = strlen(txt); - if ((length < 0) || (length > MAX7219Data.num_digits)) - length = MAX7219Data.num_digits; - - char pad = (leadingzeros ? '0' : ' '); - uint32_t i = position; - uint8_t rawBytes[1]; - - for (; i < position + (length - strlen(txt)); i++) - { - if (i > MAX7219Data.num_digits) - break; - displayMAX7219ASCII(i, pad); - } - - for (uint32_t j = 0; i < position + length; i++, j++) - { - if (i > MAX7219Data.num_digits) - break; - if (txt[j] == 0) - break; - displayMAX7219ASCII(i, txt[j]); - } - - return true; -} - -/*********************************************************************************************\ -* Displays number with decimal, specifying position, precision and length, -* optionally skipping clearing display before displaying the number. -* commands: DisplayFloat num [,position {0-(MAX7219Data.num_digits-1)} [,precision {0-MAX7219Data.num_digits} [,length {1 to MAX7219Data.num_digits}]]] -* DisplayFloatNC num [,position {0-(MAX7219Data.num_digits-1)} [,precision {0-MAX7219Data.num_digits} [,length {1 to MAX7219Data.num_digits}]]] // "NC" --> "No Clear" -\*********************************************************************************************/ -bool MAXCmndFloat(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 = MAX7219Data.num_digits; - 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 = atof(sNum); - } - - if ((position < 0) || (position > (MAX7219Data.num_digits - 1))) - position = 0; - if ((precision < 0) || (precision > MAX7219Data.num_digits)) - precision = MAX7219Data.num_digits; - - if (clear) - maxClearDisplay(); - - char txt[30]; - ext_snprintf_P(txt, sizeof(txt), PSTR("%*_f"), precision, &fnum); - - if (!length) - length = strlen(txt); - if ((length <= 0) || (length > MAX7219Data.num_digits)) - length = MAX7219Data.num_digits; - - AddLog(LOG_LEVEL_DEBUG, PSTR("MAX: num %4_f, prec %d, len %d"), &fnum, precision, length); - - for (uint32_t i = 0, j = 0; i < length; i++, j++) - { - if ((j + position) > 7) - break; - if (txt[i] == 0) - break; - if (txt[i + 1] == '.') - { - displayMAX7219ASCIIwDot(j + position, txt[i]); - i++; - length++; - } - else - displayMAX7219ASCII(j + position, txt[i]); - } - return true; -} - -// /*********************************************************************************************\ -// * Clears the display -// * Command: DisplayClear -// \*********************************************************************************************/ -bool MAXCmndClear(void) -{ - maxClearDisplay(); - sprintf(MAX7219Data.msg, PSTR("Cleared")); - XdrvMailbox.data = MAX7219Data.msg; - return true; -} - -// /*********************************************************************************************\ -// * Clears the display -// \*********************************************************************************************/ -void maxClearDisplay(void) -{ - max7219display->clearDisplay(MAX7219_ADDR); -} - -/*********************************************************************************************\ -* Display scrolling text -* Command: DisplayMAX7219Data.scroll_text text -\*********************************************************************************************/ -bool MAXCmndScrollText(void) -{ - - AddLog(LOG_LEVEL_DEBUG, PSTR("MAX: Text %s"), XdrvMailbox.data); - - if (XdrvMailbox.data_len > SCROLL_MAX_LEN) - { - snprintf(MAX7219Data.msg, sizeof(MAX7219Data.msg), PSTR("Text too long. Length should be less than %d"), SCROLL_MAX_LEN); - XdrvMailbox.data = MAX7219Data.msg; - return false; - } - else - { - snprintf(MAX7219Data.scroll_text, sizeof(MAX7219Data.scroll_text), PSTR(" ")); - snprintf(MAX7219Data.scroll_text, sizeof(MAX7219Data.scroll_text), PSTR("%s"), XdrvMailbox.data); - MAX7219Data.scroll_text[XdrvMailbox.data_len] = 0; - MAX7219Data.scroll_index = 0; - MAX7219Data.scroll = true; - return true; - } -} - -/*********************************************************************************************\ -* Sets the scroll delay for scrolling text. -* Command: DisplayMAX7219Data.scroll_delay delay {0-15} // default = 4 -\*********************************************************************************************/ -bool MAXCmndScrollDelay(void) -{ - if (ArgC() == 0) - { - XdrvMailbox.payload = MAX7219Data.scroll_delay; - return true; - } - if (MAX7219Data.scroll_delay < 0) - MAX7219Data.scroll_delay = 0; - MAX7219Data.scroll_delay = XdrvMailbox.payload; - return true; -} - -/*********************************************************************************************\ -* Scrolls a given string. Called every 50ms -\*********************************************************************************************/ -void maxScrollText(void) -{ - MAX7219Data.iteration++; - if (MAX7219Data.scroll_delay) - MAX7219Data.iteration = MAX7219Data.iteration % MAX7219Data.scroll_delay; - else - MAX7219Data.iteration = 0; - if (MAX7219Data.iteration) - return; - - if (MAX7219Data.scroll_index > strlen(MAX7219Data.scroll_text)) - { - MAX7219Data.scroll = false; - MAX7219Data.scroll_index = 0; - return; - } - uint8_t rawBytes[1]; - for (uint32_t i = 0, j = MAX7219Data.scroll_index; i < 1 + strlen(MAX7219Data.scroll_text); i++, j++) - { - if (i > (MAX7219Data.num_digits - 1)) - { - break; - } - rawBytes[0] = tm1637display->encode(MAX7219Data.scroll_text[j]); - bool dotSkipped = false; - if (MAX7219Data.scroll_text[j + 1] == '.') - { - dotSkipped = true; - rawBytes[0] = rawBytes[0] | 128; - j++; - } - else if (MAX7219Data.scroll_text[j] == '^') - { - rawBytes[0] = 1 | 2 | 32 | 64; - } - if (!dotSkipped && MAX7219Data.scroll_text[j] == '.') - { - j++; - MAX7219Data.scroll_index++; - rawBytes[0] = tm1637display->encode(MAX7219Data.scroll_text[j]); - } - if (MAX7219Data.scroll_text[j + 1] == '.') - { - rawBytes[0] = rawBytes[0] | 128; - } - displayMAX72197Seg(i, rawBytes[0]); - } - MAX7219Data.scroll_index++; -} - -/*********************************************************************************************\ -* Displays a horizontal bar graph. Takes a percentage number (0-100) as input -* Command: DisplayLevel level {0-100} -\*********************************************************************************************/ -bool MAXCmndLevel(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; - } - - uint8_t totalBars = 2 * MAX7219Data.num_digits; - AddLog(LOG_LEVEL_DEBUG, PSTR("MAX: MAX7219Data.model_name %s MAXCmndLevel totalBars=%d"), MAX7219Data.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("MAX: MAX7219Data.model_name %s MAXCmndLevel barsToDisplay=%s"), MAX7219Data.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("MAX: CmndTM1637Level numBars %d"), numBars); - - maxClearDisplay(); - uint8_t rawBytes[1]; - for (int i = 1; i <= numBars; i++) - { - uint8_t digit = (i - 1) / 2; - uint8_t value = (((i % 2) == 0) ? 54 : 48); - displayMAX72197Seg(digit, value); - } - return true; -} - -/*********************************************************************************************\ -* Display arbitrary data on the display module -* Command: DisplayRaw position {0-(MAX7219Data.num_digits-1)},length {1 to MAX7219Data.num_digits}, a [, b[, c[, d[...upto MAX7219Data.num_digits]]]] -* where a,b,c,d... are upto MAX7219Data.num_digits 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 MAXCmndRaw(void) -{ - uint8_t DATA[8] = {0, 0, 0, 0, 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 es[CMD_MAX_LEN]; - char fs[CMD_MAX_LEN]; - char gs[CMD_MAX_LEN]; - char hs[CMD_MAX_LEN]; - - char sLength[CMD_MAX_LEN]; - char sPos[CMD_MAX_LEN]; - - uint32_t position = 0; - uint32_t length = 0; - - switch (ArgC()) - { - case 10: - subStr(hs, XdrvMailbox.data, ",", 10); - DATA[7] = atoi(hs); - case 9: - subStr(gs, XdrvMailbox.data, ",", 9); - DATA[6] = atoi(gs); - case 8: - subStr(fs, XdrvMailbox.data, ",", 8); - DATA[5] = atoi(fs); - case 7: - subStr(es, XdrvMailbox.data, ",", 7); - DATA[4] = atoi(es); - 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 > MAX7219Data.num_digits) - length = MAX7219Data.num_digits; - if (position < 0 || position > (MAX7219Data.num_digits - 1)) - position = 0; - - AddLog(LOG_LEVEL_DEBUG, PSTR("MAX: a %d, b %d, c %d, d %d, e %d, f %d, g %d, h %d, len %d, pos %d"), - DATA[0], DATA[1], DATA[2], DATA[3], DATA[4], DATA[5], DATA[6], DATA[7], length, position); - - for (uint32_t i = position; i < position + length; i++) - { - if (i > 7) - break; - displayMAX72197Seg(i, DATA[i - position]); - } - - 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-(MAX7219Data.num_digits-1)} [,length {1 to MAX7219Data.num_digits}]] -\*********************************************************************************************/ -bool MAXCmndText(bool clear) -{ - char sString[CMD_MAX_LEN + 1]; - char sPosition[CMD_MAX_LEN]; - char sLength[CMD_MAX_LEN]; - uint8_t length = 0; - uint8_t position = 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 > (MAX7219Data.num_digits - 1))) - position = 0; - - AddLog(LOG_LEVEL_DEBUG, PSTR("MAX: sString %s, pos %d, len %d"), sString, position, length); - - if (clear) - maxClearDisplay(); - - if (!length) - length = strlen(sString); - if ((length < 0) || (length > MAX7219Data.num_digits)) - length = MAX7219Data.num_digits; - - uint32_t i = position; - uint8_t rawBytes[1]; - for (uint32_t j = 0; i < position + length; i++, j++) - { - if (i > (MAX7219Data.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; - displayMAX72197Seg(i, rawBytes[0]); - } - - return true; -} - -/*********************************************************************************************\ -* Sets brightness of the display. -* Command: DisplayBrightness {1-8} -\*********************************************************************************************/ -bool MAXCmndBrightness(void) -{ - - uint16_t val = XdrvMailbox.payload; - if (ArgC() == 0) - { - XdrvMailbox.payload = MAX7219Data.brightness; - return true; - } - - if ((val < BRIGHTNESS_MIN) || (val > BRIGHTNESS_MAX)) - { - Response_P(PSTR("{\"Error\":\"Brightness should be a number in the range [%d, %d]\"}"), BRIGHTNESS_MIN, BRIGHTNESS_MAX); - return false; - } - MAX7219Data.brightness = val; - maxSetBrightness(MAX7219Data.brightness); - return true; -} - -void maxSetBrightness(uint8_t val) -{ - if ((val < BRIGHTNESS_MIN) || (val > BRIGHTNESS_MAX)) - val = 5; - Settings.display_dimmer = val; - max7219display->setIntensity(MAX7219_ADDR, val - 1); -} - -/*********************************************************************************************\ -* Displays a clock. -* Command: DisplayClock 1 // 12-hour format -* DisplayClock 2 // 24-hour format -* DisplayClock 0 // turn off clock and clear -\*********************************************************************************************/ -bool MAXCmndClock(void) -{ - - MAX7219Data.show_clock = XdrvMailbox.payload; - - if (ArgC() == 0) - XdrvMailbox.payload = 1; - if (XdrvMailbox.payload > 1) - MAX7219Data.clock_24 = true; - else if (XdrvMailbox.payload == 1) - MAX7219Data.clock_24 = false; - - AddLog(LOG_LEVEL_DEBUG, PSTR("MAX: MAX7219Data.show_clock %d, MAX7219Data.clock_24 %d"), MAX7219Data.show_clock, MAX7219Data.clock_24); - - maxClearDisplay(); - return true; -} - -/*********************************************************************************************\ -* refreshes the time if clock is displayed -\*********************************************************************************************/ -void maxShowTime() -{ - uint8_t hr = RtcTime.hour; - uint8_t mn = RtcTime.minute; - // uint8_t hr = 1; - // uint8_t mn = 0; - char z = ' '; - if (MAX7219Data.clock_24) - { - z = '0'; - } - else - { - if (hr > 12) - hr -= 12; - if (hr == 0) - hr = 12; - } - - char tm[5]; - if (hr < 10) - { - if (mn < 10) - snprintf(tm, sizeof(tm), PSTR("%c%d0%d"), z, hr, mn); - else - snprintf(tm, sizeof(tm), PSTR("%c%d%d"), z, hr, mn); - } - else - { - if (mn < 10) - snprintf(tm, sizeof(tm), PSTR("%d0%d"), hr, mn); - else - snprintf(tm, sizeof(tm), PSTR("%d%d"), hr, mn); - } - - for (uint32_t i = 0; i < 4; i++) - { - if ((millis() % 1000) > 500 && (i == 1)) - displayMAX7219ASCIIwDot(i, tm[i]); - else - displayMAX7219ASCII(i, tm[i]); - } -} - -/*********************************************************************************************\ -* This function is called for all Display functions. -\*********************************************************************************************/ -bool MAXMainFunc(uint8_t fn) -{ - bool result = 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 = MAXCmndClear(); - break; - case FUNC_DISPLAY_NUMBER: - result = MAXCmndNumber(true); - break; - case FUNC_DISPLAY_NUMBERNC: - result = MAXCmndNumber(false); - break; - case FUNC_DISPLAY_FLOAT: - result = MAXCmndFloat(true); - break; - case FUNC_DISPLAY_FLOATNC: - result = MAXCmndFloat(false); - break; - case FUNC_DISPLAY_BRIGHTNESS: - result = MAXCmndBrightness(); - break; - case FUNC_DISPLAY_RAW: - result = MAXCmndRaw(); - break; - case FUNC_DISPLAY_SEVENSEG_TEXT: - result = MAXCmndText(true); - break; - case FUNC_DISPLAY_SEVENSEG_TEXTNC: - result = MAXCmndText(false); - break; - case FUNC_DISPLAY_LEVEL: - result = MAXCmndLevel(); - break; - case FUNC_DISPLAY_SCROLLTEXT: - result = MAXCmndScrollText(); - break; - case FUNC_DISPLAY_SCROLLDELAY: - result = MAXCmndScrollDelay(); - break; - case FUNC_DISPLAY_CLOCK: - result = MAXCmndClock(); - break; - } - - return result; -} - -/*********************************************************************************************\ - * Interface -\*********************************************************************************************/ -bool Xdsp16(uint8_t function) -{ - bool result = false; - - if (Settings.display_model == XDSP_16) - { - switch (function) - { - case FUNC_DISPLAY_MODEL: - result = true; - break; - case FUNC_DISPLAY_INIT_DRIVER: - MAXDriverInit(); // init - 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: - MAX7219Data.show_clock = false; - case FUNC_DISPLAY_BRIGHTNESS: - result = MAXMainFunc(function); - break; - case FUNC_DISPLAY_EVERY_50_MSECOND: - if (MAX7219Data.scroll) - maxScrollText(); - if (MAX7219Data.show_clock) - maxShowTime(); - break; - } - } - return result; -} - -#endif // USE_DISPLAY_MAX7219 -#endif // USE_DISPLAY